From 19e59ebe9b5645c7e47b4990fad76efb91136660 Mon Sep 17 00:00:00 2001 From: Jeremy Grelle Date: Tue, 16 Jun 2026 06:34:52 -0400 Subject: [PATCH 1/8] Saving WIP - intitial skeleton of ComponentParser and supporting infra --- parser/pom.xml | 72 + .../run/endive/cm/parser/ComponentParser.java | 198 ++ .../cm/parser/ComponentParserListener.java | 9 + .../endive/cm/tools/ComponentValidate.java | 91 + .../cm/tools/ComponentValidateException.java | 13 + .../run/endive/cm/tools/JsonFromWast.java | 93 + .../cm/tools/JsonFromWastException.java | 14 + .../java/run/endive/cm/tools/WastTests.java | 356 +++ .../java/run/endive/cm/parser/SpecTests.java | 32 + .../spec-tests/async/async-calls-sync.wast | 251 +++ .../spec-tests/async/cancel-stream.wast | 202 ++ .../spec-tests/async/cancel-subtask.wast | 201 ++ .../spec-tests/async/cancellable.wast | 325 +++ .../spec-tests/async/closed-stream.wast | 102 + .../spec-tests/async/cross-abi-calls.wast | 519 +++++ .../resources/spec-tests/async/deadlock.wast | 73 + .../spec-tests/async/dont-block-start.wast | 50 + .../async/drop-cross-task-borrow.wast | 309 +++ .../spec-tests/async/drop-stream.wast | 160 ++ .../spec-tests/async/drop-subtask.wast | 140 ++ .../spec-tests/async/drop-waitable-set.wast | 84 + .../spec-tests/async/empty-wait.wast | 199 ++ .../spec-tests/async/futures-must-write.wast | 118 + .../async/partial-stream-copies.wast | 238 ++ .../spec-tests/async/passing-resources.wast | 176 ++ .../async/same-component-stream-future.wast | 259 +++ .../spec-tests/async/sync-barges-in.wast | 311 +++ .../spec-tests/async/sync-streams.wast | 178 ++ .../async/trap-if-block-and-sync.wast | 343 +++ .../spec-tests/async/trap-if-done.wast | 468 ++++ .../spec-tests/async/trap-on-reenter.wast | 110 + .../async/wait-during-callback.wast | 77 + .../spec-tests/async/zero-length.wast | 223 ++ .../resources/spec-tests/names/kebab.wast | 60 + .../resources/multiple-resources.wast | 170 ++ .../spec-tests/validation/implements.wast | 108 + .../resources/spec-tests/values/strings.wast | 136 ++ .../values/trap-in-post-return.wast | 249 +++ .../spec-tests/wasm-tools/adapt.wast | 287 +++ .../spec-tests/wasm-tools/alias.wast | 301 +++ .../resources/spec-tests/wasm-tools/big.wast | 36 + .../spec-tests/wasm-tools/definedtypes.wast | 123 ++ .../spec-tests/wasm-tools/empty.wast | 4 + .../spec-tests/wasm-tools/example.wast | 17 + .../wasm-tools/export-ascription.wast | 44 + .../wasm-tools/export-introduces-alias.wast | 48 + .../spec-tests/wasm-tools/export.wast | 63 + .../resources/spec-tests/wasm-tools/func.wast | 146 ++ .../spec-tests/wasm-tools/import.wast | 359 +++ .../wasm-tools/imports-exports.wast | 26 + .../spec-tests/wasm-tools/inline-exports.wast | 9 + .../spec-tests/wasm-tools/instance-type.wast | 234 ++ .../spec-tests/wasm-tools/instantiate.wast | 976 ++++++++ .../spec-tests/wasm-tools/invalid.wast | 34 + .../resources/spec-tests/wasm-tools/link.wast | 14 + .../wasm-tools/lots-of-aliases.wast | 179 ++ .../spec-tests/wasm-tools/lower.wast | 17 + .../spec-tests/wasm-tools/memory64.wast | 55 + .../spec-tests/wasm-tools/module-link.wast | 98 + .../spec-tests/wasm-tools/more-flags.wast | 41 + .../spec-tests/wasm-tools/naming.wast | 127 ++ .../spec-tests/wasm-tools/nested-modules.wast | 50 + .../spec-tests/wasm-tools/resources.wast | 1195 ++++++++++ .../resources/spec-tests/wasm-tools/tags.wast | 30 + .../wasm-tools/type-export-restrictions.wast | 504 +++++ .../spec-tests/wasm-tools/types.wast | 374 ++++ .../spec-tests/wasm-tools/very-nested.wast | 1954 +++++++++++++++++ .../spec-tests/wasm-tools/virtualize.wast | 119 + .../spec-tests/wasm-tools/wrong-order.wast | 11 + .../spec-tests/wasmtime/adapter.wast | 137 ++ .../spec-tests/wasmtime/aliasing.wast | 29 + .../resources/spec-tests/wasmtime/fused.wast | 1391 ++++++++++++ .../resources/spec-tests/wasmtime/import.wast | 20 + .../spec-tests/wasmtime/instance.wast | 327 +++ .../spec-tests/wasmtime/linking.wast | 18 + .../spec-tests/wasmtime/modules.wast | 479 ++++ .../resources/spec-tests/wasmtime/nested.wast | 451 ++++ .../spec-tests/wasmtime/resources.wast | 1091 +++++++++ .../spec-tests/wasmtime/restrictions.wast | 22 + .../resources/spec-tests/wasmtime/simple.wast | 42 + .../spec-tests/wasmtime/strings.wast | 110 + .../resources/spec-tests/wasmtime/tags.wast | 14 + .../resources/spec-tests/wasmtime/types.wast | 355 +++ parser/update-spec-tests.sh | 62 + pom.xml | 24 + types/pom.xml | 32 + .../java/run/endive/cm/types/Section.java | 13 + .../java/run/endive/cm/types/SectionId.java | 19 + .../run/endive/cm/types/WasmComponent.java | 18 + 89 files changed, 18846 insertions(+) create mode 100644 parser/pom.xml create mode 100644 parser/src/main/java/run/endive/cm/parser/ComponentParser.java create mode 100644 parser/src/main/java/run/endive/cm/parser/ComponentParserListener.java create mode 100644 parser/src/main/java/run/endive/cm/tools/ComponentValidate.java create mode 100644 parser/src/main/java/run/endive/cm/tools/ComponentValidateException.java create mode 100644 parser/src/main/java/run/endive/cm/tools/JsonFromWast.java create mode 100644 parser/src/main/java/run/endive/cm/tools/JsonFromWastException.java create mode 100644 parser/src/main/java/run/endive/cm/tools/WastTests.java create mode 100644 parser/src/test/java/run/endive/cm/parser/SpecTests.java create mode 100644 parser/src/test/resources/spec-tests/async/async-calls-sync.wast create mode 100644 parser/src/test/resources/spec-tests/async/cancel-stream.wast create mode 100644 parser/src/test/resources/spec-tests/async/cancel-subtask.wast create mode 100644 parser/src/test/resources/spec-tests/async/cancellable.wast create mode 100644 parser/src/test/resources/spec-tests/async/closed-stream.wast create mode 100644 parser/src/test/resources/spec-tests/async/cross-abi-calls.wast create mode 100644 parser/src/test/resources/spec-tests/async/deadlock.wast create mode 100644 parser/src/test/resources/spec-tests/async/dont-block-start.wast create mode 100644 parser/src/test/resources/spec-tests/async/drop-cross-task-borrow.wast create mode 100644 parser/src/test/resources/spec-tests/async/drop-stream.wast create mode 100644 parser/src/test/resources/spec-tests/async/drop-subtask.wast create mode 100644 parser/src/test/resources/spec-tests/async/drop-waitable-set.wast create mode 100644 parser/src/test/resources/spec-tests/async/empty-wait.wast create mode 100644 parser/src/test/resources/spec-tests/async/futures-must-write.wast create mode 100644 parser/src/test/resources/spec-tests/async/partial-stream-copies.wast create mode 100644 parser/src/test/resources/spec-tests/async/passing-resources.wast create mode 100644 parser/src/test/resources/spec-tests/async/same-component-stream-future.wast create mode 100644 parser/src/test/resources/spec-tests/async/sync-barges-in.wast create mode 100644 parser/src/test/resources/spec-tests/async/sync-streams.wast create mode 100644 parser/src/test/resources/spec-tests/async/trap-if-block-and-sync.wast create mode 100644 parser/src/test/resources/spec-tests/async/trap-if-done.wast create mode 100644 parser/src/test/resources/spec-tests/async/trap-on-reenter.wast create mode 100644 parser/src/test/resources/spec-tests/async/wait-during-callback.wast create mode 100644 parser/src/test/resources/spec-tests/async/zero-length.wast create mode 100644 parser/src/test/resources/spec-tests/names/kebab.wast create mode 100644 parser/src/test/resources/spec-tests/resources/multiple-resources.wast create mode 100644 parser/src/test/resources/spec-tests/validation/implements.wast create mode 100644 parser/src/test/resources/spec-tests/values/strings.wast create mode 100644 parser/src/test/resources/spec-tests/values/trap-in-post-return.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/adapt.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/alias.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/big.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/definedtypes.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/empty.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/example.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/export-ascription.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/export-introduces-alias.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/export.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/func.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/import.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/imports-exports.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/inline-exports.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/instance-type.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/instantiate.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/invalid.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/link.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/lower.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/memory64.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/module-link.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/more-flags.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/naming.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/nested-modules.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/resources.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/tags.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/types.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/very-nested.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/virtualize.wast create mode 100644 parser/src/test/resources/spec-tests/wasm-tools/wrong-order.wast create mode 100644 parser/src/test/resources/spec-tests/wasmtime/adapter.wast create mode 100644 parser/src/test/resources/spec-tests/wasmtime/aliasing.wast create mode 100644 parser/src/test/resources/spec-tests/wasmtime/fused.wast create mode 100644 parser/src/test/resources/spec-tests/wasmtime/import.wast create mode 100644 parser/src/test/resources/spec-tests/wasmtime/instance.wast create mode 100644 parser/src/test/resources/spec-tests/wasmtime/linking.wast create mode 100644 parser/src/test/resources/spec-tests/wasmtime/modules.wast create mode 100644 parser/src/test/resources/spec-tests/wasmtime/nested.wast create mode 100644 parser/src/test/resources/spec-tests/wasmtime/resources.wast create mode 100644 parser/src/test/resources/spec-tests/wasmtime/restrictions.wast create mode 100644 parser/src/test/resources/spec-tests/wasmtime/simple.wast create mode 100644 parser/src/test/resources/spec-tests/wasmtime/strings.wast create mode 100644 parser/src/test/resources/spec-tests/wasmtime/tags.wast create mode 100644 parser/src/test/resources/spec-tests/wasmtime/types.wast create mode 100755 parser/update-spec-tests.sh create mode 100644 types/pom.xml create mode 100644 types/src/main/java/run/endive/cm/types/Section.java create mode 100644 types/src/main/java/run/endive/cm/types/SectionId.java create mode 100644 types/src/main/java/run/endive/cm/types/WasmComponent.java diff --git a/parser/pom.xml b/parser/pom.xml new file mode 100644 index 0000000..a73c423 --- /dev/null +++ b/parser/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + + run.endive.cm + endive-cm + 999-SNAPSHOT + + parser + jar + + Endive CM - Binary Component Model Parser + Binary parser for Endive Component Model + + + + io.roastedroot + zerofs + + + run.endive + log + + + run.endive + runtime + + + run.endive + wasi + + + run.endive + wasm + + + run.endive + wasm-tools + + + run.endive.cm + types + + + com.fasterxml.jackson.core + jackson-databind + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-params + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 16 + 16 + + + + + + diff --git a/parser/src/main/java/run/endive/cm/parser/ComponentParser.java b/parser/src/main/java/run/endive/cm/parser/ComponentParser.java new file mode 100644 index 0000000..7d3b90e --- /dev/null +++ b/parser/src/main/java/run/endive/cm/parser/ComponentParser.java @@ -0,0 +1,198 @@ +package run.endive.cm.parser; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; +import java.util.function.Supplier; + +import run.endive.cm.types.SectionId; +import run.endive.cm.types.WasmComponent; +import run.endive.wasm.MalformedException; +import run.endive.wasm.io.InputStreams; +import run.endive.cm.types.Section; + +import static java.util.Objects.requireNonNull; +import static run.endive.wasm.Encoding.readVarUInt32; + +public final class ComponentParser { + + static final byte[] MAGIC_BYTES = {0x00, 0x61, 0x73, 0x6D}; + static final byte[] VERSION_BYTES = {0x0d, 0x00}; + static final byte[] LAYER_BYTES = {0x01, 0x00}; + + private ComponentParser() {} + + private static ByteBuffer readByteBuffer(InputStream is) { + try { + var buffer = ByteBuffer.wrap(InputStreams.readAllBytes(is)); + buffer.order(ByteOrder.LITTLE_ENDIAN); + return buffer; + } catch (IOException e) { + throw new IllegalArgumentException("Failed to read wasm bytes.", e); + } + } + + public static ComponentParser.Builder builder() { + return new ComponentParser.Builder(); + } + + public static final class Builder { + + private Builder() {} + + public ComponentParser build() { + return new ComponentParser(); + } + } + + public WasmComponent parse(Supplier inputStreamSupplier) { + WasmComponent.Builder componentBuilder = WasmComponent.builder(); + parse(inputStreamSupplier.get(), s -> onSection(componentBuilder, s)); + return componentBuilder.build(); + } + + private void parse(InputStream in, ComponentParserListener listener) { + requireNonNull(listener, "listener"); + + var buffer = readByteBuffer(in); + + byte[] magic = new byte[4]; + readBytes(buffer, magic); + if (!Arrays.equals(magic, MAGIC_BYTES)) { + throw new MalformedException( + "magic header not detected, found: " + + Arrays.toString(magic) + + " expected: " + + Arrays.toString(MAGIC_BYTES)); + } + + byte[] version = new byte[2]; + readBytes(buffer, version); + if (!Arrays.equals(version, VERSION_BYTES)) { + throw new MalformedException( + "unknown binary version, found: " + + Arrays.toString(version) + + " expected: " + + Arrays.toString(VERSION_BYTES)); + } + + byte[] layer = new byte[2]; + readBytes(buffer, layer); + if (!Arrays.equals(layer, LAYER_BYTES)) { + throw new MalformedException( + "unknown layer, found: " + + Arrays.toString(layer) + + " expected: " + + Arrays.toString(LAYER_BYTES)); + } + + while (buffer.hasRemaining()) { + var sectionId = readByte(buffer); + var sectionSize = readVarUInt32(buffer); + + ByteBuffer sectionByteBuffer = buffer.asReadOnlyBuffer(); + sectionByteBuffer.order(buffer.order()); + + // move buffer to next section + var sectionLimit = sectionByteBuffer.position() + (int) sectionSize; + if (buffer.capacity() < sectionLimit) { + throw new MalformedException("length out of bounds for section" + sectionId); + } + buffer.position(sectionLimit); + + sectionByteBuffer.limit(sectionLimit); + + // Process different section types based on the sectionId + switch (sectionId) { + case SectionId.CUSTOM: + { + throw new UnsupportedOperationException("Custom section is not supported yet"); + } + case SectionId.CORE_MODULE: + { + throw new UnsupportedOperationException("Core module section is not supported yet"); + } + case SectionId.CORE_INSTANCE: + { + throw new UnsupportedOperationException("Core instance section is not supported yet"); + } + case SectionId.CORE_TYPE: + { + throw new UnsupportedOperationException("Core type section is not supported yet"); + } + case SectionId.COMPONENT: + { + throw new UnsupportedOperationException("Component section is not supported yet"); + } + case SectionId.INSTANCE: + { + throw new UnsupportedOperationException("Instance section is not supported yet"); + } + case SectionId.ALIAS: + { + throw new UnsupportedOperationException("Alias section is not supported yet"); + } + case SectionId.TYPE: + { + throw new UnsupportedOperationException("Type section is not supported yet"); + } + case SectionId.CANON: + { + throw new UnsupportedOperationException("Canon section is not supported yet"); + } + case SectionId.START: + { + throw new UnsupportedOperationException("Start section is not supported yet"); + } + case SectionId.IMPORT: + { + throw new UnsupportedOperationException("Import section is not supported yet"); + } + case SectionId.EXPORT: + { + throw new UnsupportedOperationException("Export section is not supported yet"); + } + case SectionId.VALUE: + { + throw new UnsupportedOperationException("Value section is not supported yet"); + } + default: + { + throw new MalformedException( + "section size mismatch, malformed section id " + sectionId); + } + } + +// if (sectionByteBuffer.hasRemaining()) { +// throw new MalformedException("section size mismatch"); +// } + } + } + + private static void onSection(WasmComponent.Builder module, Section s) { + + } + + static int readInt(ByteBuffer buffer) { + if (buffer.remaining() < 4) { + throw new MalformedException("length out of bounds"); + } + return buffer.getInt(); + } + + static byte readByte(ByteBuffer buffer) { + if (!buffer.hasRemaining()) { + throw new MalformedException("length out of bounds"); + } + return buffer.get(); + } + + static void readBytes(ByteBuffer buffer, byte[] dest) { + if (buffer.remaining() < dest.length) { + throw new MalformedException("length out of bounds"); + } + buffer.get(dest); + } +} diff --git a/parser/src/main/java/run/endive/cm/parser/ComponentParserListener.java b/parser/src/main/java/run/endive/cm/parser/ComponentParserListener.java new file mode 100644 index 0000000..ee38fde --- /dev/null +++ b/parser/src/main/java/run/endive/cm/parser/ComponentParserListener.java @@ -0,0 +1,9 @@ +package run.endive.cm.parser; + +import run.endive.cm.types.Section; + +@FunctionalInterface +public interface ComponentParserListener { + + void onSection(Section section); +} diff --git a/parser/src/main/java/run/endive/cm/tools/ComponentValidate.java b/parser/src/main/java/run/endive/cm/tools/ComponentValidate.java new file mode 100644 index 0000000..71f4a55 --- /dev/null +++ b/parser/src/main/java/run/endive/cm/tools/ComponentValidate.java @@ -0,0 +1,91 @@ +package run.endive.cm.tools; + +import io.roastedroot.zerofs.Configuration; +import io.roastedroot.zerofs.ZeroFs; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import run.endive.log.Logger; +import run.endive.log.SystemLogger; +import run.endive.runtime.ByteArrayMemory; +import run.endive.runtime.ImportValues; +import run.endive.runtime.Instance; +import run.endive.tools.wasm.WasmToolsModule; +import run.endive.wasi.WasiExitException; +import run.endive.wasi.WasiOptions; +import run.endive.wasi.WasiPreview1; +import run.endive.wasm.WasmModule; + +public final class ComponentValidate { + + private ComponentValidate() {} + + private static final Logger logger = + new SystemLogger() { + @Override + public boolean isLoggable(Logger.Level level) { + return false; + } + }; + + private static final WasmModule MODULE = WasmToolsModule.load(); + + public static void validate(InputStream is) { + try (var stdinStream = new ByteArrayInputStream(new byte[0]); + var stdoutStream = new ByteArrayOutputStream(); + var stderrStream = new ByteArrayOutputStream(); + FileSystem fs = + ZeroFs.newFileSystem( + Configuration.unix().toBuilder() + .setAttributeViews("unix") + .build())) { + + Path inputDir = fs.getPath("input"); + Files.createDirectory(inputDir); + Path inputFile = inputDir.resolve("input.wasm"); + Files.write(inputFile, is.readAllBytes()); + + var options = + WasiOptions.builder() + .withStdin(stdinStream, false) + .withStdout(stdoutStream, false) + .withStderr(stderrStream, false) + .withDirectory(inputDir.toString(), inputDir) + .withArguments( + List.of( + "wasm-tools", + "validate", + inputFile.toString())) + .build(); + + try (var wasi = + WasiPreview1.builder().withLogger(logger).withOptions(options).build()) { + var imports = ImportValues.builder().addFunction(wasi.toHostFunctions()).build(); + + try { + Instance.builder(MODULE) + .withMachineFactory(WasmToolsModule::create) + .withMemoryFactory(ByteArrayMemory::new) + .withImportValues(imports) + .build(); + } catch (WasiExitException e) { + if (e.exitCode() != 0) { + throw new ComponentValidateException( + stdoutStream.toString(StandardCharsets.UTF_8) + + stderrStream.toString(StandardCharsets.UTF_8), + e); + } + } + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} diff --git a/parser/src/main/java/run/endive/cm/tools/ComponentValidateException.java b/parser/src/main/java/run/endive/cm/tools/ComponentValidateException.java new file mode 100644 index 0000000..a566e90 --- /dev/null +++ b/parser/src/main/java/run/endive/cm/tools/ComponentValidateException.java @@ -0,0 +1,13 @@ +package run.endive.cm.tools; + +public class ComponentValidateException extends RuntimeException { + public ComponentValidateException() {} + + public ComponentValidateException(String message) { + super(message); + } + + public ComponentValidateException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/parser/src/main/java/run/endive/cm/tools/JsonFromWast.java b/parser/src/main/java/run/endive/cm/tools/JsonFromWast.java new file mode 100644 index 0000000..b97429e --- /dev/null +++ b/parser/src/main/java/run/endive/cm/tools/JsonFromWast.java @@ -0,0 +1,93 @@ +package run.endive.cm.tools; + +import io.roastedroot.zerofs.Configuration; +import io.roastedroot.zerofs.ZeroFs; +import run.endive.log.Logger; +import run.endive.log.SystemLogger; +import run.endive.runtime.ByteArrayMemory; +import run.endive.runtime.ImportValues; +import run.endive.runtime.Instance; +import run.endive.tools.wasm.WasmToolsModule; +import run.endive.wasi.WasiExitException; +import run.endive.wasi.WasiOptions; +import run.endive.wasi.WasiPreview1; +import run.endive.wasm.WasmModule; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +public final class JsonFromWast { + + private JsonFromWast() {} + + private static final Logger logger = + new SystemLogger() { + @Override + public boolean isLoggable(Logger.Level level) { + return false; + } + }; + + private static final WasmModule MODULE = WasmToolsModule.load(); + + public static WastTests exec(InputStream is) { + try (var stdinStream = new ByteArrayInputStream(new byte[0]); + var stdoutStream = new ByteArrayOutputStream(); + var stderrStream = new ByteArrayOutputStream()) { + + FileSystem fs = + ZeroFs.newFileSystem( + Configuration.unix().toBuilder() + .setAttributeViews("unix") + .build()); + + Path wastDir = fs.getPath("wast"); + Files.createDirectory(wastDir); + Path inputFile = wastDir.resolve("input.wast"); + byte[] source = is.readAllBytes(); + Files.write(inputFile, source); + + var options = + WasiOptions.builder() + .withStdin(stdinStream, false) + .withStdout(stdoutStream, false) + .withStderr(stderrStream, false) + .withDirectory("/", fs.getPath("/work")) + .withArguments( + List.of( + "wasm-tools", + "json-from-wast", + inputFile.toString(), + "-vv", + "--pretty")) + .build(); + + try (var wasi = + WasiPreview1.builder().withLogger(logger).withOptions(options).build()) { + var imports = ImportValues.builder().addFunction(wasi.toHostFunctions()).build(); + try { + Instance.builder(MODULE) + .withMachineFactory(WasmToolsModule::create) + .withMemoryFactory(ByteArrayMemory::new) + .withImportValues(imports) + .build(); + } catch (WasiExitException e) { + if (e.exitCode() != 0) { + throw new ComponentValidateException( + stdoutStream.toString(StandardCharsets.UTF_8) + + stderrStream.toString(StandardCharsets.UTF_8), + e); + } + } + var wastJson = stdoutStream.toString(StandardCharsets.UTF_8); + return new WastTests(wastJson, fs); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} diff --git a/parser/src/main/java/run/endive/cm/tools/JsonFromWastException.java b/parser/src/main/java/run/endive/cm/tools/JsonFromWastException.java new file mode 100644 index 0000000..f686be9 --- /dev/null +++ b/parser/src/main/java/run/endive/cm/tools/JsonFromWastException.java @@ -0,0 +1,14 @@ +package run.endive.cm.tools; + +public class JsonFromWastException extends RuntimeException { + + public JsonFromWastException() {} + + public JsonFromWastException(String message) { + super(message); + } + + public JsonFromWastException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/parser/src/main/java/run/endive/cm/tools/WastTests.java b/parser/src/main/java/run/endive/cm/tools/WastTests.java new file mode 100644 index 0000000..accaed1 --- /dev/null +++ b/parser/src/main/java/run/endive/cm/tools/WastTests.java @@ -0,0 +1,356 @@ +package run.endive.cm.tools; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import run.endive.cm.parser.ComponentParser; +import run.endive.cm.types.WasmComponent; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.IntStream; + +public final class WastTests implements AutoCloseable { + + private final WastTestFile wastTestFile; + + private final FileSystem wastFS; + + public WastTests(String wastJson, FileSystem wastFS) { + var objectMapper = new ObjectMapper(); + try { + this.wastTestFile = + objectMapper.readValue(wastJson, WastTestFile.class); + this.wastFS = wastFS; + } catch (JsonProcessingException e) { + throw new JsonFromWastException("failed to deserialize wast json", e); + } + } + + public void runTests(int[] skipLines) { + var workingDir = wastFS.getPath("/work"); + for (var command : wastTestFile.commands()) { + command.execute(workingDir, skipLines); + } + } + + @Override + public void close() throws Exception { + this.wastFS.close(); + } + + static final class WastTestFile { + private final String sourceFilename; + private final List commands; + + WastTestFile( + @JsonProperty("source_filename") String sourceFilename, + @JsonProperty("commands") List commands) { + this.sourceFilename = sourceFilename; + this.commands = commands; + } + + String sourceFilename() { + return sourceFilename; + } + + List commands() { + return commands; + } + } + + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = + "type") + @JsonSubTypes({ + @JsonSubTypes.Type(value = Module.class, name = "module"), + @JsonSubTypes.Type(value = AssertMalformed.class, name = "assert_malformed"), + @JsonSubTypes.Type(value = AssertInvalid.class, name = "assert_invalid"), + }) + interface Command { + + void execute(Path location, int... skipLines) + throws CommandException; + + default WasmComponent parseComponent(Path location, String filename) + throws CommandException { + var filePath = location.resolve(filename); + try (var in = new ByteArrayInputStream(Files.readAllBytes(filePath))) { + try { + ComponentValidate.validate(in); + in.reset(); + var parser = ComponentParser.builder().build(); + return parser.parse(() -> in); + } catch (UnsupportedOperationException e) { + throw new CommandException(e); + } + } catch (IOException e) { + throw new CommandException(e); + } + } + } + + public static class CommandException extends RuntimeException { + public CommandException(Throwable cause) { + super(cause); + } + + public CommandException(String message) { + super(message); + } + + public CommandException(String message, Throwable cause) { + super(message, cause); + } + } + + static final class AssertInvalid implements Command { + private final int line; + private final String filename; + private final String moduleType; + private final String text; + + AssertInvalid( + @JsonProperty("line") int line, + @JsonProperty("filename") String filename, + @JsonProperty("module_type") String moduleType, + @JsonProperty("text") String text) { + this.line = line; + this.filename = filename; + this.moduleType = moduleType; + this.text = text; + } + + int line() { + return line; + } + + String filename() { + return filename; + } + + String moduleType() { + return moduleType; + } + + String text() { + return text; + } + + @Override + public void execute(Path location, int... skipLines) + throws CommandException { + if (skipLines.length > 0) { + if (IntStream.of(skipLines).anyMatch(i -> i == line)) { + return; + } + } + try { + parseComponent(location, filename); + } catch (Exception e) { + if (!(e instanceof ComponentValidateException)) { + throw new CommandException( + String.format( + "Expected validation of %s to fail at line %d due to '%s' but got unexpected exception of type %s", + filename, line, text, e.getClass().getSimpleName()), + e); + } + return; + } + throw new CommandException( + String.format( + "\"Expected validation of %s to fail at line %d due to '%s' ", + filename, line, text)); + } + } + + static final class AssertMalformed implements Command { + private final int line; + private final String filename; + private final String moduleType; + private final String text; + + AssertMalformed( + @JsonProperty("line") int line, + @JsonProperty("filename") String filename, + @JsonProperty("module_type") String moduleType, + @JsonProperty("text") String text) { + this.line = line; + this.filename = filename; + this.moduleType = moduleType; + this.text = text; + } + + int line() { + return line; + } + + String filename() { + return filename; + } + + String moduleType() { + return moduleType; + } + + String text() { + return text; + } + + @Override + public void execute(Path location, int... skipLines) + throws CommandException { + if (skipLines.length > 0) { + if (IntStream.of(skipLines).anyMatch(i -> i == line)) { + return; + } + } + try { + parseComponent(location, filename); + } catch (Exception e) { + if (!(e instanceof ComponentValidateException)) { + throw new CommandException( + String.format( + "Expected validation of %s to fail at line %d due to '%s' but got unexpected exception of type %s", + filename, line, text, e.getClass().getSimpleName()), + e); + } + return; + } + throw new CommandException( + String.format( + "\"Expected validation of %s to fail at line %d due to '%s' ", + filename, line, text)); + } + } + + static final class Action { + private final String type; + private final String field; + private final List args; + + Action( + @JsonProperty("type") String type, + @JsonProperty("field") String field, + @JsonProperty("args") List args) { + this.type = type; + this.field = field; + this.args = args; + } + + String type() { + return type; + } + + String field() { + return field; + } + + List args() { + return args; + } + } + + static final class TypedValue { + private final String type; + private final String value; + + TypedValue(@JsonProperty("type") String type, @JsonProperty("value") String value) { + this.type = type; + this.value = value; + } + + String type() { + return type; + } + + String value() { + return value; + } + + Object converted() { + switch (type) { + case "bool": + return Boolean.parseBoolean(value); + case "s8": + return Byte.parseByte(value); + case "u8": + case "s16": + return Short.parseShort(value); + case "u16": + case "s32": + case "i32": + return Integer.parseInt(value); + case "u32": + case "s64": + case "i64": + return Long.parseLong(value); + case "u64": + return BigInteger.valueOf(Long.parseLong(value)); + case "f32": + return Float.parseFloat(value); + case "f64": + return Double.parseDouble(value); + default: + return value; + } + } + } + + static final class Module implements Command { + private final int line; + private final String name; + private final String filename; + private final String moduleType; + + Module( + @JsonProperty("line") int line, + @JsonProperty("name") String name, + @JsonProperty("filename") String filename, + @JsonProperty("module_type") String moduleType) { + this.line = line; + this.name = name; + this.filename = filename; + this.moduleType = moduleType; + } + + int line() { + return line; + } + + String name() { + return name; + } + + String filename() { + return filename; + } + + String moduleType() { + return moduleType; + } + + @Override + public void execute(Path location, int... skipLines) + throws CommandException { + if (skipLines.length > 0) { + if (IntStream.of(skipLines).anyMatch(i -> i == line)) { + return; + } + } + try { + parseComponent(location, filename); + } catch (Exception e) { + throw new CommandException( + String.format("Failed to load module %s due to error at line %d", filename, line), + e); + } + } + } +} diff --git a/parser/src/test/java/run/endive/cm/parser/SpecTests.java b/parser/src/test/java/run/endive/cm/parser/SpecTests.java new file mode 100644 index 0000000..1fc7d09 --- /dev/null +++ b/parser/src/test/java/run/endive/cm/parser/SpecTests.java @@ -0,0 +1,32 @@ + package run.endive.cm.parser; + + import java.nio.file.Files; + import java.nio.file.Path; + + import org.junit.jupiter.params.ParameterizedTest; + import org.junit.jupiter.params.provider.Arguments; + import org.junit.jupiter.params.provider.MethodSource; + import run.endive.cm.tools.JsonFromWast; + + import static org.junit.jupiter.api.Assertions.fail; + + public class SpecTests { + + static java.util.stream.Stream testLocations() { + return java.util.stream.Stream.of( + //Arguments.arguments("./wasmtime/types.wast", new int[] {145}), + Arguments.arguments("./wasm-tools/types.wast", new int[0])); + } + + @ParameterizedTest + @MethodSource("testLocations") + void allSpecTests(String testLocation, int[] skipLines) { + var testDir = Path.of("src/test/resources/spec-tests"); + var testFile = testDir.resolve(testLocation); + try (var wast = Files.newInputStream(testFile); var wastTests = JsonFromWast.exec(wast)){ + wastTests.runTests(skipLines); + } catch (Exception e) { + fail(e); + } + } + } diff --git a/parser/src/test/resources/spec-tests/async/async-calls-sync.wast b/parser/src/test/resources/spec-tests/async/async-calls-sync.wast new file mode 100644 index 0000000..5172bb4 --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/async-calls-sync.wast @@ -0,0 +1,251 @@ +;; This test contains 3 components, $AsyncInner, $SyncMiddle and $AsyncOuter, +;; where there are two instances of $SyncMiddle that import a single instance +;; of $AsyncInner, and $AsyncOuter imports all 3 preceding instances. +;; +;; $AsyncOuter.run asynchronously calls $SyncMiddle.sync-func twice concurrently +;; in each instance (4 total calls), hitting the synchronous backpressure case +;; in 2 of the 4 calls. +;; +;; $SyncMiddle.sync-func makes a blocking call to $AsyncInner.blocking-call +;; which is used to emulate a host call that blocks until $AsyncOuter.run +;; calls $AsyncInner.unblock to unblock all the 'blocking-call' calls. +(component + (component $AsyncInner + (core module $CoreAsyncInner + (import "" "context.set" (func $context.set (param i32))) + (import "" "context.get" (func $context.get (result i32))) + (import "" "task.return0" (func $task.return0)) + (import "" "task.return1" (func $task.return1 (param i32))) + + (memory 1) + (global $blocked (mut i32) (i32.const 1)) + (global $counter (mut i32) (i32.const 2)) + + ;; 'blocking-call' cooperatively "spin-waits" until $blocked is 0. + (func $blocking-call (export "blocking-call") (result i32) + (call $context.set (global.get $counter)) + (global.set $counter (i32.add (i32.const 1) (global.get $counter))) + (i32.const 1 (; YIELD ;)) + ) + (func $blocking-call-cb (export "blocking-call-cb") (param i32 i32 i32) (result i32) + (if (i32.eqz (global.get $blocked)) (then + (call $task.return1 (call $context.get)) + (return (i32.const 0 (; EXIT ;))) + )) + (i32.const 1 (; YIELD ;)) + ) + (func $unblock (export "unblock") (result i32) + (global.set $blocked (i32.const 0)) + (call $task.return0) + (i32.const 0 (; EXIT ;)) + ) + (func $unblock-cb (export "unblock-cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (canon task.return (core func $task.return0)) + (canon task.return (result u32) (core func $task.return1)) + (canon context.set i32 0 (core func $context.set)) + (canon context.get i32 0 (core func $context.get)) + (core instance $core_async_inner (instantiate $CoreAsyncInner (with "" (instance + (export "task.return0" (func $task.return0)) + (export "task.return1" (func $task.return1)) + (export "context.set" (func $context.set)) + (export "context.get" (func $context.get)) + )))) + (func (export "blocking-call") async (result u32) (canon lift + (core func $core_async_inner "blocking-call") + async (callback (func $core_async_inner "blocking-call-cb")) + )) + (func (export "unblock") async (canon lift + (core func $core_async_inner "unblock") + async (callback (func $core_async_inner "unblock-cb")) + )) + ) + + (component $SyncMiddle + (import "blocking-call" (func $blocking-call async (result u32))) + (core module $CoreSyncMiddle + (import "" "blocking-call" (func $blocking-call (result i32))) + (func $sync-func (export "sync-func") (result i32) + (call $blocking-call) + ) + ) + (canon lower (func $blocking-call) (core func $blocking-call')) + (core instance $core_sync_middle (instantiate $CoreSyncMiddle (with "" (instance + (export "blocking-call" (func $blocking-call')) + )))) + (func (export "sync-func") async (result u32) (canon lift + (core func $core_sync_middle "sync-func") + )) + ) + + (component $AsyncMiddle + (import "blocking-call" (func $blocking-call async (result u32))) + (core module $CoreSyncMiddle + (import "" "task.return" (func $task.return (param i32))) + (import "" "blocking-call" (func $blocking-call (result i32))) + (func $sync-func (export "sync-func") (result i32) + (call $task.return (call $blocking-call)) + (i32.const 0 (; EXIT ;)) + ) + (func $sync-func-cb (export "sync-func-cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (canon task.return (result u32) (core func $task.return)) + (canon lower (func $blocking-call) (core func $blocking-call')) + (core instance $core_sync_middle (instantiate $CoreSyncMiddle (with "" (instance + (export "task.return" (func $task.return)) + (export "blocking-call" (func $blocking-call')) + )))) + (func (export "sync-func") async (result u32) (canon lift + (core func $core_sync_middle "sync-func") + async (callback (func $core_sync_middle "sync-func-cb")) + )) + ) + + (component $AsyncOuter + (import "unblock" (func $unblock async)) + (import "sync-func1" (func $sync-func1 async (result u32))) + (import "sync-func2" (func $sync-func2 async (result u32))) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CoreAsyncOuter + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "subtask.drop" (func $subtask.drop (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "unblock" (func $unblock)) + (import "" "sync-func1" (func $sync-func1 (param i32) (result i32))) + (import "" "sync-func2" (func $sync-func2 (param i32) (result i32))) + + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + ;; set $remain to the number of tasks to wait to complete + (global $remain (mut i32) (i32.const 4)) + + (func $run (export "run") (result i32) + (local $ret i32) + + ;; call 'sync-func1' and 'sync-func2' asynchronously, both of which will block + ;; (on $AsyncInner.blocking-call). because 'sync-func1/2' are in different instances, + ;; both calls will reach the STARTED state. + (local.set $ret (call $sync-func1 (i32.const 8))) + (if (i32.ne (i32.const 0x21 (; STARTED=1 | (subtask=2 << 4) ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (i32.const 2) (global.get $ws)) + (local.set $ret (call $sync-func2 (i32.const 12))) + (if (i32.ne (i32.const 0x31 (; STARTED=1 | (subtask=3 << 4) ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (i32.const 3) (global.get $ws)) + + ;; now start another pair of 'sync-func1/2' calls, both of which should see auto + ;; backpressure and get stuck in the STARTING state. + (local.set $ret (call $sync-func1 (i32.const 16))) + (if (i32.ne (i32.const 0x40 (; STARTING=0 | (subtask=4 << 4) ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (i32.const 4) (global.get $ws)) + (local.set $ret (call $sync-func2 (i32.const 20))) + (if (i32.ne (i32.const 0x50 (; STARTING=0 | (subtask=5 << 4) ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (i32.const 5) (global.get $ws)) + + ;; unblock all the tasks and start waiting to complete + (call $unblock) + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) + ) + (func $run-cb (export "run-cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + (local $ret i32) + + ;; confirm we only receive SUBTASK events. + (if (i32.ne (local.get $event_code) (i32.const 1 (; SUBTASK ;))) + (then unreachable)) + + ;; if we receive a SUBTASK STARTED event, it should only be for the 3rd or + ;; 4th subtask (at indices 4/5, resp), so keep waiting for completion + (if (i32.eq (local.get $payload) (i32.const 1 (; STARTED ;))) (then + (if (i32.and + (i32.ne (local.get $index) (i32.const 4)) + (i32.ne (local.get $index) (i32.const 5))) + (then unreachable)) + (return (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4)))) + )) + + ;; when we receive a SUBTASK RETURNED event, check the return value is equal to the + ;; subtask index (which we've ensured by having $AsyncInner.$counter start at 2, the + ;; first subtask index. The address of the return buffer is the index*4. + (if (i32.ne (local.get $payload) (i32.const 2 (; RETURNED ;))) + (then unreachable)) + (if (i32.ne (local.get $index) (i32.load (i32.mul (local.get $index) (i32.const 4)))) + (then unreachable)) + + ;; decrement $remain and exit if 0 + (call $subtask.drop (local.get $index)) + (global.set $remain (i32.sub (global.get $remain) (i32.const 1))) + (if (i32.gt_u (global.get $remain) (i32.const 0)) (then + (return (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4)))) + )) + (call $task.return (i32.const 42)) + (i32.const 0 (; EXIT ;)) + ) + ) + (canon task.return (result u32) (core func $task.return)) + (canon subtask.drop (core func $subtask.drop)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon lower (func $unblock) (core func $unblock)) + (canon lower (func $sync-func1) async (memory $memory "mem") (core func $sync-func1')) + (canon lower (func $sync-func2) async (memory $memory "mem") (core func $sync-func2')) + (core instance $em (instantiate $CoreAsyncOuter (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "subtask.drop" (func $subtask.drop)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "unblock" (func $unblock)) + (export "sync-func1" (func $sync-func1')) + (export "sync-func2" (func $sync-func2')) + )))) + (func (export "run") async (result u32) (canon lift + (core func $em "run") + async (callback (func $em "run-cb")) + )) + ) + + ;; run1 uses $SyncMiddle + (instance $async_inner1 (instantiate $AsyncInner)) + (instance $sync_middle11 (instantiate $SyncMiddle + (with "blocking-call" (func $async_inner1 "blocking-call")) + )) + (instance $sync_middle12 (instantiate $SyncMiddle + (with "blocking-call" (func $async_inner1 "blocking-call")) + )) + (instance $async_outer1 (instantiate $AsyncOuter + (with "unblock" (func $async_inner1 "unblock")) + (with "sync-func1" (func $sync_middle11 "sync-func")) + (with "sync-func2" (func $sync_middle12 "sync-func")) + )) + (func (export "run1") (alias export $async_outer1 "run")) + + ;; run2 uses $AsyncMiddle + (instance $async_inner2 (instantiate $AsyncInner)) + (instance $sync_middle21 (instantiate $SyncMiddle + (with "blocking-call" (func $async_inner2 "blocking-call")) + )) + (instance $sync_middle22 (instantiate $AsyncMiddle + (with "blocking-call" (func $async_inner2 "blocking-call")) + )) + (instance $async_outer2 (instantiate $AsyncOuter + (with "unblock" (func $async_inner2 "unblock")) + (with "sync-func1" (func $sync_middle21 "sync-func")) + (with "sync-func2" (func $sync_middle22 "sync-func")) + )) + (func (export "run2") (alias export $async_outer2 "run")) +) +(assert_return (invoke "run1") (u32.const 42)) +(assert_return (invoke "run2") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/async/cancel-stream.wast b/parser/src/test/resources/spec-tests/async/cancel-stream.wast new file mode 100644 index 0000000..336b5ac --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/cancel-stream.wast @@ -0,0 +1,202 @@ +;; This test contains two components $C and $D that test cancelling reads +;; and writes in the presence and absence of partial reads/writes. +;; +;; $C exports a function 'start-stream' that creates and holds onto a writable +;; stream in the global $sw as well as various operations that operate on $sw. +;; $D calls $C.start-stream to get the readable end and then drives the test. +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + (global $sw (mut i32) (i32.const 0)) + + (func $start-stream (export "start-stream") (result i32) + ;; create a new stream, return the readable end to the caller + (local $ret64 i64) + (local.set $ret64 (call $stream.new)) + (global.set $sw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (i32.wrap_i64 (local.get $ret64)) + ) + + (func $write4 (export "write4") + ;; write 6 bytes into the stream, expecting to rendezvous with a stream.read + (local $ret i32) + (i32.store (i32.const 8) (i32.const 0xabcd)) + (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 4))) + (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + ) + + (func $write4-and-drop (export "write4-and-drop") + (call $write4) + (call $stream.drop-writable (global.get $sw)) + ) + + (func $start-blocking-write (export "start-blocking-write") + (local $ret i32) + + ;; prepare the write buffer + (i64.store (i32.const 8) (i64.const 0x123456789abcdef)) + + ;; start one blocking write and immediately cancel it + (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 8))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $stream.cancel-write (global.get $sw))) + (if (i32.ne (i32.const 0x2 (; CANCELLED ;)) (local.get $ret)) + (then unreachable)) + + ;; start a second blockign write and leave it pending + (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 8))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + ) + + (func $cancel-after-read4 (export "cancel-after-read4") + (local $ret i32) + (local.set $ret (call $stream.cancel-write (global.get $sw))) + (if (i32.ne (i32.const 0x42 (; CANCELLED=2 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + ) + ) + (type $ST (stream u8)) + (canon task.return (result u32) (core func $task.return)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.cancel-write $ST (core func $stream.cancel-write)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "stream.new" (func $stream.new)) + (export "stream.write" (func $stream.write)) + (export "stream.cancel-write" (func $stream.cancel-write)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (func (export "start-stream") async (result (stream u8)) (canon lift (core func $cm "start-stream"))) + (func (export "write4") async (canon lift (core func $cm "write4"))) + (func (export "write4-and-drop") async (canon lift (core func $cm "write4-and-drop"))) + (func (export "start-blocking-write") async (canon lift (core func $cm "start-blocking-write"))) + (func (export "cancel-after-read4") async (canon lift (core func $cm "cancel-after-read4"))) + ) + + (component $D + (import "c" (instance $c + (export "start-stream" (func async (result (stream u8)))) + (export "write4" (func async)) + (export "write4-and-drop" (func async)) + (export "start-blocking-write" (func async)) + (export "cancel-after-read4" (func async)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.cancel-read" (func $stream.cancel-read (param i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "start-stream" (func $start-stream (result i32))) + (import "" "write4" (func $write4)) + (import "" "write4-and-drop" (func $write4-and-drop)) + (import "" "start-blocking-write" (func $start-blocking-write)) + (import "" "cancel-after-read4" (func $cancel-after-read4)) + + (func $run (export "run") (result i32) + (local $ret i32) + (local $sr i32) + + ;; call 'start-stream' to get the stream we'll be working with + (local.set $sr (call $start-stream)) + (if (i32.ne (i32.const 1) (local.get $sr)) + (then unreachable)) + + ;; start read that will block + (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) + (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) + (then unreachable)) + + ;; cancelling it will finish without anything having been written + (local.set $ret (call $stream.cancel-read (local.get $sr))) + (if (i32.ne (i32.const 0x2 (; CANCELLED ;)) (local.get $ret)) + (then unreachable)) + + ;; read, block, call $C to write 4 bytes into the buffer, + ;; then cancel, which should show "4+cancelled" + (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) + (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) + (then unreachable)) + (call $write4) + (local.set $ret (call $stream.cancel-read (local.get $sr))) + (if (i32.ne (i32.const 0x42 (; CANCELLED=2 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0xabcd) (i32.load (i32.const 8))) + (then unreachable)) + + ;; read, block, call $C to write 4 bytes into the buffer and drop, then cancel + (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) + (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) + (then unreachable)) + (call $write4-and-drop) + (local.set $ret (call $stream.cancel-read (local.get $sr))) + (if (i32.ne (i32.const 0x41 (; DROPPED=1 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0xabcd) (i32.load (i32.const 8))) + (then unreachable)) + (call $stream.drop-readable (local.get $sr)) + + ;; get a new $sr + (local.set $sr (call $start-stream)) + (if (i32.ne (i32.const 1) (local.get $sr)) + (then unreachable)) + + ;; start outstanding write in $C, read 4 of it, then call back into $C + ;; which will cancel and see 4 written. + (call $start-blocking-write) + (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 4))) + (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0x89abcdef) (i32.load (i32.const 8))) + (then unreachable)) + (call $cancel-after-read4) + + ;; return 42 to the top-level assert_return + (i32.const 42) + ) + ) + (type $ST (stream u8)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.cancel-read $ST (core func $stream.cancel-read)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon lower (func $c "start-stream") (core func $start-stream')) + (canon lower (func $c "write4") (core func $write4')) + (canon lower (func $c "write4-and-drop") (core func $write4-and-drop')) + (canon lower (func $c "start-blocking-write") (core func $start-blocking-write')) + (canon lower (func $c "cancel-after-read4") (core func $cancel-after-read4')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "stream.read" (func $stream.read)) + (export "stream.cancel-read" (func $stream.cancel-read)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "start-stream" (func $start-stream')) + (export "write4" (func $write4')) + (export "write4-and-drop" (func $write4-and-drop')) + (export "start-blocking-write" (func $start-blocking-write')) + (export "cancel-after-read4" (func $cancel-after-read4')) + )))) + (func (export "run") async (result u32) (canon lift (core func $dm "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "run") (alias export $d "run")) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/async/cancel-subtask.wast b/parser/src/test/resources/spec-tests/async/cancel-subtask.wast new file mode 100644 index 0000000..57a0f33 --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/cancel-subtask.wast @@ -0,0 +1,201 @@ +;; This test contains two components $C and $D where $D imports and calls $C. +;; $D.run calls $C.f, which blocks on an empty waitable set +;; $D.run then subtask.cancels $C.f, which resumes $C.f which promptly resolves +;; without returning a value. +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.cancel" (func $task.cancel)) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + + ;; $ws is waited on by 'f' + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + (func $f (export "f") (result i32) + ;; wait on $ws which is currently empty, expected to get cancelled + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) + ) + (func $f_cb (export "f_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + ;; confirm that we've received a cancellation request + (if (i32.ne (local.get $event_code) (i32.const 6 (; TASK_CANCELLED ;))) + (then unreachable)) + (if (i32.ne (local.get $index) (i32.const 0)) + (then unreachable)) + (if (i32.ne (local.get $payload) (i32.const 0)) + (then unreachable)) + + ;; finish without returning a value + (call $task.cancel) + (i32.const 0 (; EXIT ;)) + ) + + (func $g (export "g") (param $futr i32) (result i32) + (local $ret i32) + (local $event_code i32) + + ;; perform a future.read which will block, waiting for the caller to write + (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (local.get $futr) (global.get $ws)) + + ;; wait on $ws synchronously, don't expect cancellation + (local.set $event_code (call $waitable-set.wait (global.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) + (then unreachable)) + + ;; finish returning a value + (i32.const 42) + ) + ) + (type $FT (future)) + (canon task.cancel (core func $task.cancel)) + (canon future.read $FT async (memory $memory "mem") (core func $future.read)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.cancel" (func $task.cancel)) + (export "future.read" (func $future.read)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + )))) + (func (export "f") async (result u32) (canon lift + (core func $cm "f") + async (callback (func $cm "f_cb")) + )) + (func (export "g") async (param "fut" $FT) (result u32) (canon lift + (core func $cm "g") + )) + ) + + (component $D + (type $FT (future)) + (import "f" (func $f async (result u32))) + (import "g" (func $g async (param "fut" $FT) (result u32))) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) + (import "" "subtask.drop" (func $subtask.drop (param i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "f" (func $f (param i32) (result i32))) + (import "" "g" (func $g (param i32 i32) (result i32))) + + (func $run (export "run") (result i32) + (local $ret i32) (local $ret64 i64) + (local $retp i32) (local $retp1 i32) (local $retp2 i32) + (local $subtask i32) + (local $event_code i32) + (local $futr i32) (local $futw i32) + (local $ws i32) + + ;; call 'f'; it should block + (local.set $retp (i32.const 4)) + (i32.store (local.get $retp) (i32.const 0xbad0bad0)) + (local.set $ret (call $f (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; cancel 'f'; it should complete without blocking + (local.set $ret (call $subtask.cancel (local.get $subtask))) + (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (local.get $ret)) + (then unreachable)) + + ;; The $retp memory shouldn't have changed + (if (i32.ne (i32.load (local.get $retp)) (i32.const 0xbad0bad0)) + (then unreachable)) + + (call $subtask.drop (local.get $subtask)) + + ;; create future that g will wait on + (local.set $ret64 (call $future.new)) + (local.set $futr (i32.wrap_i64 (local.get $ret64))) + (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + + ;; call 'g'; it should block + (local.set $retp1 (i32.const 4)) + (local.set $retp2 (i32.const 8)) + (i32.store (local.get $retp1) (i32.const 0xbad0bad0)) + (i32.store (local.get $retp2) (i32.const 0xbad0bad0)) + (local.set $ret (call $g (local.get $futr) (local.get $retp1))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; cancel 'g'; it should block + (local.set $ret (call $subtask.cancel (local.get $subtask))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; future.write, unblocking 'g' + (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + ;; wait to see 'g' finish and check its return value + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtask) (local.get $ws)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load (local.get $retp1))) + (then unreachable)) + + ;; return to the top-level assert_return + (i32.const 42) + ) + ) + (canon subtask.cancel async (core func $subtask.cancel)) + (canon subtask.drop (core func $subtask.drop)) + (canon future.new $FT (core func $future.new)) + (canon future.write $FT async (memory $memory "mem") (core func $future.write)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon lower (func $f) async (memory $memory "mem") (core func $f')) + (canon lower (func $g) async (memory $memory "mem") (core func $g')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "subtask.cancel" (func $subtask.cancel)) + (export "subtask.drop" (func $subtask.drop)) + (export "future.new" (func $future.new)) + (export "future.write" (func $future.write)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "f" (func $f')) + (export "g" (func $g')) + )))) + (func (export "run") async (result u32) (canon lift (core func $dm "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D + (with "f" (func $c "f")) + (with "g" (func $c "g")) + )) + (func (export "run") (alias export $d "run")) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/async/cancellable.wast b/parser/src/test/resources/spec-tests/async/cancellable.wast new file mode 100644 index 0000000..2c5614c --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/cancellable.wast @@ -0,0 +1,325 @@ +;; This test exercises the 'cancellable' immediate on waitable-set.wait, +;; waitable-set.poll, and thread.yield. +;; +;; Component $C exports five async callback-lifted functions that block in +;; their initial core function (the callbacks are never invoked): +;; wait-cancel: blocks on cancellable waitable-set.wait, expects TASK_CANCELLED +;; yield-cancel: yields with cancellable, caller cancels during yield +;; poll-cancel-pending: blocks on non-cancellable wait, then polls with cancellable +;; yield-cancel-pending: blocks on non-cancellable wait, then yields with cancellable +;; +;; Component $D calls each function and cancels it, verifying the cancel is +;; delivered correctly through the cancellable built-in in each case. +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.cancel" (func $task.cancel)) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait-cancellable" (func $waitable-set.wait-cancellable (param i32 i32) (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "waitable-set.poll-cancellable" (func $waitable-set.poll-cancellable (param i32 i32) (result i32))) + (import "" "thread.yield-cancellable" (func $thread.yield-cancellable (result i32))) + + ;; Test 1: direct cancel delivery through cancellable waitable-set.wait + (func $wait-cancel (export "wait-cancel") (result i32) + (local $event_code i32) + (local $ws i32) + (local.set $ws (call $waitable-set.new)) + ;; wait on empty waitable set with cancellable; blocks until cancelled + (local.set $event_code (call $waitable-set.wait-cancellable (local.get $ws) (i32.const 0))) + (if (i32.ne (local.get $event_code) (i32.const 6 (; TASK_CANCELLED ;))) + (then unreachable)) + (call $task.cancel) + (i32.const 0 (; EXIT ;)) + ) + + ;; Test 2: direct cancel delivery through cancellable thread.yield + (func $yield-cancel (export "yield-cancel") (result i32) + (local $ret i32) + ;; yield with cancellable; suspends with cancellable=true, caller cancels + (local.set $ret (call $thread.yield-cancellable)) + (if (i32.ne (i32.const 1 (; CANCELLED ;)) (local.get $ret)) + (then unreachable)) + (call $task.cancel) + (i32.const 0 (; EXIT ;)) + ) + + ;; Test 3: deferred cancel delivered through cancellable waitable-set.poll + (func $poll-cancel-pending (export "poll-cancel-pending") (param $futr i32) (result i32) + (local $ws i32) + (local $ret i32) + (local $event_code i32) + (local.set $ws (call $waitable-set.new)) + ;; read future - blocks (caller hasn't written yet) + (local.set $ret (call $future.read (local.get $futr) (i32.const 0))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (local.get $futr) (local.get $ws)) + ;; wait WITHOUT cancellable - cancel will be deferred as PENDING_CANCEL + (local.set $event_code (call $waitable-set.wait (local.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) + (then unreachable)) + ;; poll WITH cancellable - delivers the pending cancel + (local.set $event_code (call $waitable-set.poll-cancellable (local.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 6 (; TASK_CANCELLED ;)) (local.get $event_code)) + (then unreachable)) + (call $task.cancel) + (i32.const 0 (; EXIT ;)) + ) + + ;; Test 4: deferred cancel delivered through cancellable thread.yield + (func $yield-cancel-pending (export "yield-cancel-pending") (param $futr i32) (result i32) + (local $ws i32) + (local $ret i32) + (local $event_code i32) + (local.set $ws (call $waitable-set.new)) + ;; read future - blocks (caller hasn't written yet) + (local.set $ret (call $future.read (local.get $futr) (i32.const 0))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (local.get $futr) (local.get $ws)) + ;; wait WITHOUT cancellable - cancel will be deferred as PENDING_CANCEL + (local.set $event_code (call $waitable-set.wait (local.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) + (then unreachable)) + ;; yield WITH cancellable - delivers the pending cancel + (local.set $ret (call $thread.yield-cancellable)) + (if (i32.ne (i32.const 1 (; CANCELLED ;)) (local.get $ret)) + (then unreachable)) + (call $task.cancel) + (i32.const 0 (; EXIT ;)) + ) + + ;; callback that should never be called + (func (export "unreachable-cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (type $FT (future)) + (canon task.cancel (core func $task.cancel)) + (canon future.read $FT async (memory $memory "mem") (core func $future.read)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait cancellable (memory $memory "mem") (core func $waitable-set.wait-cancellable)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon waitable-set.poll cancellable (memory $memory "mem") (core func $waitable-set.poll-cancellable)) + (canon thread.yield cancellable (core func $thread.yield-cancellable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.cancel" (func $task.cancel)) + (export "future.read" (func $future.read)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait-cancellable" (func $waitable-set.wait-cancellable)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "waitable-set.poll-cancellable" (func $waitable-set.poll-cancellable)) + (export "thread.yield-cancellable" (func $thread.yield-cancellable)) + )))) + (func (export "wait-cancel") async (result u32) (canon lift + (core func $cm "wait-cancel") + async (callback (func $cm "unreachable-cb")) + )) + (func (export "yield-cancel") async (result u32) (canon lift + (core func $cm "yield-cancel") + async (callback (func $cm "unreachable-cb")) + )) + (func (export "poll-cancel-pending") async (param "fut" $FT) (result u32) (canon lift + (core func $cm "poll-cancel-pending") + async (callback (func $cm "unreachable-cb")) + )) + (func (export "yield-cancel-pending") async (param "fut" $FT) (result u32) (canon lift + (core func $cm "yield-cancel-pending") + async (callback (func $cm "unreachable-cb")) + )) + ) + + (component $D + (type $FT (future)) + (import "wait-cancel" (func $wait-cancel async (result u32))) + (import "yield-cancel" (func $yield-cancel async (result u32))) + (import "poll-cancel-pending" (func $poll-cancel-pending async (param "fut" $FT) (result u32))) + (import "yield-cancel-pending" (func $yield-cancel-pending async (param "fut" $FT) (result u32))) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) + (import "" "subtask.drop" (func $subtask.drop (param i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "wait-cancel" (func $wait-cancel (param i32) (result i32))) + (import "" "yield-cancel" (func $yield-cancel (param i32) (result i32))) + (import "" "poll-cancel-pending" (func $poll-cancel-pending (param i32 i32) (result i32))) + (import "" "yield-cancel-pending" (func $yield-cancel-pending (param i32 i32) (result i32))) + + (func $run (export "run") (result i32) + (local $ret i32) (local $ret64 i64) + (local $retp i32) (local $retp2 i32) + (local $subtask i32) + (local $event_code i32) + (local $futr i32) (local $futw i32) + (local $ws i32) + + ;; ========================================== + ;; Test 1: waitable-set.wait cancellable + ;; ========================================== + + ;; call wait-cancel; it should block in cancellable wait + (local.set $retp (i32.const 4)) + (local.set $ret (call $wait-cancel (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; cancel; completes immediately (C is in cancellable wait) + (local.set $ret (call $subtask.cancel (local.get $subtask))) + (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (local.get $ret)) + (then unreachable)) + (call $subtask.drop (local.get $subtask)) + + ;; ========================================== + ;; Test 2: thread.yield cancellable + ;; ========================================== + + ;; call yield-cancel; it should suspend in cancellable yield + (local.set $ret (call $yield-cancel (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; cancel; completes immediately (C is in cancellable yield) + (local.set $ret (call $subtask.cancel (local.get $subtask))) + (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (local.get $ret)) + ;; TODO: this currently fails in Wasmtime due to cancellable + ;; thread.yield not being directly resumed by subtask.cancel, but it + ;; seems like it should pass: + (then unreachable)) + (call $subtask.drop (local.get $subtask)) + + ;; ========================================== + ;; Test 3: waitable-set.poll cancellable (pending) + ;; ========================================== + + ;; create future for poll-cancel-pending to read + (local.set $ret64 (call $future.new)) + (local.set $futr (i32.wrap_i64 (local.get $ret64))) + (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + + ;; call poll-cancel-pending; it should block in non-cancellable wait + (local.set $retp (i32.const 4)) + (local.set $retp2 (i32.const 8)) + (local.set $ret (call $poll-cancel-pending (local.get $futr) (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; cancel; blocks because C's wait is not cancellable + (local.set $ret (call $subtask.cancel (local.get $subtask))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; write to future; unblocks C's non-cancellable wait + (local.set $ret (call $future.write (local.get $futw) (i32.const 0))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + ;; wait for subtask to complete + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtask) (local.get $ws)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (i32.load offset=4 (local.get $retp2))) + (then unreachable)) + (call $subtask.drop (local.get $subtask)) + + ;; ========================================== + ;; Test 4: thread.yield cancellable (pending) + ;; ========================================== + + ;; create future for yield-cancel-pending to read + (local.set $ret64 (call $future.new)) + (local.set $futr (i32.wrap_i64 (local.get $ret64))) + (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + + ;; call yield-cancel-pending; it should block in non-cancellable wait + (local.set $ret (call $yield-cancel-pending (local.get $futr) (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; cancel; blocks because C's wait is not cancellable + (local.set $ret (call $subtask.cancel (local.get $subtask))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; write to future; unblocks C's non-cancellable wait + (local.set $ret (call $future.write (local.get $futw) (i32.const 0))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + ;; wait for subtask to complete + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtask) (local.get $ws)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (i32.load offset=4 (local.get $retp2))) + (then unreachable)) + (call $subtask.drop (local.get $subtask)) + + ;; all tests passed + (i32.const 42) + ) + ) + (canon subtask.cancel async (core func $subtask.cancel)) + (canon subtask.drop (core func $subtask.drop)) + (canon future.new $FT (core func $future.new)) + (canon future.write $FT async (memory $memory "mem") (core func $future.write)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon lower (func $wait-cancel) async (memory $memory "mem") (core func $wait-cancel')) + (canon lower (func $yield-cancel) async (memory $memory "mem") (core func $yield-cancel')) + (canon lower (func $poll-cancel-pending) async (memory $memory "mem") (core func $poll-cancel-pending')) + (canon lower (func $yield-cancel-pending) async (memory $memory "mem") (core func $yield-cancel-pending')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "subtask.cancel" (func $subtask.cancel)) + (export "subtask.drop" (func $subtask.drop)) + (export "future.new" (func $future.new)) + (export "future.write" (func $future.write)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "wait-cancel" (func $wait-cancel')) + (export "yield-cancel" (func $yield-cancel')) + (export "poll-cancel-pending" (func $poll-cancel-pending')) + (export "yield-cancel-pending" (func $yield-cancel-pending')) + )))) + (func (export "run") async (result u32) (canon lift (core func $dm "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D + (with "wait-cancel" (func $c "wait-cancel")) + (with "yield-cancel" (func $c "yield-cancel")) + (with "poll-cancel-pending" (func $c "poll-cancel-pending")) + (with "yield-cancel-pending" (func $c "yield-cancel-pending")) + )) + (func (export "run") (alias export $d "run")) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/async/closed-stream.wast b/parser/src/test/resources/spec-tests/async/closed-stream.wast new file mode 100644 index 0000000..eb462c8 --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/closed-stream.wast @@ -0,0 +1,102 @@ +;; This test contains two components $C and $D that test that if the writable side +;; of a stream is dropped, the other side registers a STREAM DROPPED status +;; when attempting to read from the stream. +(component definition $Tester + ;; Creates a stream and keeps a handle to the writable end of it. + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + ;; Store the writable end of a stream + (global $sw (mut i32) (i32.const 0)) + + ;; Create a new stream, return the readable end to the caller + (func $start-stream (export "start-stream") (result i32) + (local $ret64 i64) + (local.set $ret64 (call $stream.new)) + (global.set $sw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (i32.wrap_i64 (local.get $ret64)) + ) + + ;; Drop the writable end of a stream + (func $drop-writable (export "drop-writable") + (call $stream.drop-writable (global.get $sw)) + ) + ) + (type $ST (stream u8)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "stream.new" (func $stream.new)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (func (export "start-stream") (result (stream u8)) (canon lift (core func $cm "start-stream"))) + (func (export "drop-writable") (canon lift (core func $cm "drop-writable"))) + ) + + ;; Gets a readable stream from component $C and calls operations on it. + (component $D + (import "c" (instance $c + (export "start-stream" (func (result (stream u8)))) + (export "drop-writable" (func)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + (import "" "start-stream" (func $start-stream (result i32))) + (import "" "drop-writable" (func $drop-writable)) + + (func (export "read-from-closed-stream") + (local $ret i32) (local $sr i32) + + ;; call 'start-stream' to get the stream we'll be working with + (local.set $sr (call $start-stream)) + (if (i32.ne (i32.const 1) (local.get $sr)) + (then unreachable)) + + ;; drop the writable end and then attempt to read from it + (call $drop-writable) + (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 4))) + (if (i32.ne (i32.const 1 (; DROPPED ;)) (local.get $ret)) + (then unreachable)) + ) + ) + (type $ST (stream u8)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (canon lower (func $c "start-stream") (core func $start-stream')) + (canon lower (func $c "drop-writable") (core func $drop-writable')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-writable" (func $stream.drop-writable)) + (export "start-stream" (func $start-stream')) + (export "drop-writable" (func $drop-writable')) + )))) + (func (export "read-from-closed-stream") (canon lift (core func $core "read-from-closed-stream"))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "read-from-closed-stream") (alias export $d "read-from-closed-stream")) +) + +(component instance $new-tester-instance $Tester) +(invoke "read-from-closed-stream") diff --git a/parser/src/test/resources/spec-tests/async/cross-abi-calls.wast b/parser/src/test/resources/spec-tests/async/cross-abi-calls.wast new file mode 100644 index 0000000..8f1370b --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/cross-abi-calls.wast @@ -0,0 +1,519 @@ +;; This test pairs sync and async-callback calls from $Bottom into $Top, +;; testing different numbers of parameters and results that hit the various +;; flat-vs-heap cases in the spec. +(component definition $C + (component $Top + (core module $Memory + (memory (export "mem") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + i32.const 0 ;; cheat -- there's never more than 1 allocation alive + ) + ) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 0)) + (import "" "task.return0" (func $task.return0)) + (import "" "task.return1" (func $task.return1 (param f64))) + (import "" "task.return16" (func $task.return16 (param i32 i64 f32 f64 i32 i64 f32 f64 i32 i64 f32 f64 i32 i64 f32 f64))) + (import "" "task.return17" (func $task.return17 (param i32))) + (func (export "sync-4-param") (param i32 i64 f32 f64) + (if (i32.ne (i32.const 42) (local.get 0)) + (then unreachable)) + (if (i64.ne (i64.const 43) (local.get 1)) + (then unreachable)) + (if (f32.ne (f32.const 44.4) (local.get 2)) + (then unreachable)) + (if (f64.ne (f64.const 45.5) (local.get 3)) + (then unreachable)) + ) + (func (export "sync-5-param") (param i32 i64 f32 f64 i32) + (if (i32.ne (i32.const -1) (local.get 0)) + (then unreachable)) + (if (i64.ne (i64.const -2) (local.get 1)) + (then unreachable)) + (if (f32.ne (f32.const -3.3) (local.get 2)) + (then unreachable)) + (if (f64.ne (f64.const -4.4) (local.get 3)) + (then unreachable)) + (if (i32.ne (i32.const -5) (local.get 4)) + (then unreachable)) + ) + (func $check-17 (param $ptr i32) + (if (i32.ne (i32.const -1) (i32.load (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -2) (i64.load offset=8 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -3.3) (f32.load offset=16 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -4.4) (f64.load offset=24 (local.get $ptr))) + (then unreachable)) + (if (i32.ne (i32.const -5) (i32.load offset=32 (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -6) (i64.load offset=40 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -7.7) (f32.load offset=48 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -8.8) (f64.load offset=56 (local.get $ptr))) + (then unreachable)) + (if (i32.ne (i32.const -9) (i32.load offset=64 (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -10) (i64.load offset=72 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -11.11) (f32.load offset=80 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -12.12) (f64.load offset=88 (local.get $ptr))) + (then unreachable)) + (if (i32.ne (i32.const -13) (i32.load offset=96 (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -14) (i64.load offset=104 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -15.15) (f32.load offset=112 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -16.16) (f64.load offset=120 (local.get $ptr))) + (then unreachable)) + (if (i32.ne (i32.const -17) (i32.load offset=128 (local.get $ptr))) + (then unreachable)) + ) + (func (export "sync-17-param") (param $ptr i32) + (call $check-17 (local.get $ptr)) + ) + (func (export "sync-1-result") (result f64) + (f64.const -1.1) + ) + (func $setup-16 (param $ptr i32) + (i32.store (local.get $ptr) (i32.const -1)) + (i64.store offset=8 (local.get $ptr) (i64.const -2)) + (f32.store offset=16 (local.get $ptr) (f32.const -3.3)) + (f64.store offset=24 (local.get $ptr) (f64.const -4.4)) + (i32.store offset=32 (local.get $ptr) (i32.const -5)) + (i64.store offset=40 (local.get $ptr) (i64.const -6)) + (f32.store offset=48 (local.get $ptr) (f32.const -7.7)) + (f64.store offset=56 (local.get $ptr) (f64.const -8.8)) + (i32.store offset=64 (local.get $ptr) (i32.const -9)) + (i64.store offset=72 (local.get $ptr) (i64.const -10)) + (f32.store offset=80 (local.get $ptr) (f32.const -11.11)) + (f64.store offset=88 (local.get $ptr) (f64.const -12.12)) + (i32.store offset=96 (local.get $ptr) (i32.const -13)) + (i64.store offset=104 (local.get $ptr) (i64.const -14)) + (f32.store offset=112 (local.get $ptr) (f32.const -15.15)) + (f64.store offset=120 (local.get $ptr) (f64.const -16.16)) + ) + (func $setup-17 (param $ptr i32) + (call $setup-16 (local.get $ptr)) + (i32.store offset=128 (local.get $ptr) (i32.const -17)) + ) + (func (export "sync-16-result") (result i32) + (local $ptr i32) + (call $setup-16 (local.get $ptr)) + (local.get $ptr) + ) + (func (export "sync-17-result") (result i32) + (local $ptr i32) + (call $setup-17 (local.get $ptr)) + (local.get $ptr) + ) + (func (export "async-4-param") (param i32 i64 f32 f64) (result i32) + (if (i32.ne (i32.const 42) (local.get 0)) + (then unreachable)) + (if (i64.ne (i64.const 43) (local.get 1)) + (then unreachable)) + (if (f32.ne (f32.const 44.4) (local.get 2)) + (then unreachable)) + (if (f64.ne (f64.const 45.5) (local.get 3)) + (then unreachable)) + (call $task.return0) + (i32.const 0 (; EXIT ;)) + ) + (func (export "async-5-param") (param i32 i64 f32 f64 i32) (result i32) + (if (i32.ne (i32.const -1) (local.get 0)) + (then unreachable)) + (if (i64.ne (i64.const -2) (local.get 1)) + (then unreachable)) + (if (f32.ne (f32.const -3.3) (local.get 2)) + (then unreachable)) + (if (f64.ne (f64.const -4.4) (local.get 3)) + (then unreachable)) + (if (i32.ne (i32.const -5) (local.get 4)) + (then unreachable)) + (call $task.return0) + (i32.const 0 (; EXIT ;)) + ) + (func (export "async-17-param") (param $ptr i32) (result i32) + (call $check-17 (local.get $ptr)) + (call $task.return0) + (i32.const 0 (; EXIT ;)) + ) + (func (export "async-1-result") (result i32) + (call $task.return1 (f64.const -1.1)) + (i32.const 0 (; EXIT ;)) + ) + (func (export "async-16-result") (result i32) + (call $task.return16 (i32.const -1) (i64.const -2) (f32.const -3.3) (f64.const -4.4) + (i32.const -5) (i64.const -6) (f32.const -7.7) (f64.const -8.8) + (i32.const -9) (i64.const -10) (f32.const -11.11) (f64.const -12.12) + (i32.const -13) (i64.const -14) (f32.const -15.15) (f64.const -16.16)) + (i32.const 0 (; EXIT ;)) + ) + (func (export "async-17-result") (result i32) + (local $ptr i32) + (call $setup-17 (local.get $ptr)) + (call $task.return17 (local.get $ptr)) + (i32.const 0 (; EXIT ;)) + ) + (func (export "unreachable-cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (canon task.return (core func $task.return0)) + (canon task.return (result f64) (core func $task.return1)) + (canon task.return (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)) (core func $task.return16)) + (canon task.return (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)) (memory $memory "mem") (core func $task.return17)) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return0" (func $task.return0)) + (export "task.return1" (func $task.return1)) + (export "task.return16" (func $task.return16)) + (export "task.return17" (func $task.return17)) + )))) + (func (export "sync-4-param") async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) + (canon lift (core func $core "sync-4-param")) + ) + (func (export "sync-5-param") async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) (param "e" u32) + (canon lift (core func $core "sync-5-param")) + ) + (func (export "sync-17-param") async + (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) + (param "e" u32) (param "f" u64) (param "g" f32) (param "h" f64) + (param "i" u32) (param "j" u64) (param "k" f32) (param "l" f64) + (param "m" u32) (param "n" u64) (param "o" f32) (param "p" f64) + (param "q" u32) + (canon lift (core func $core "sync-17-param") (memory $memory "mem") (realloc (func $memory "realloc"))) + ) + (func (export "sync-1-result") async (result f64) + (canon lift (core func $core "sync-1-result")) + ) + (func (export "sync-16-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)) + (canon lift (core func $core "sync-16-result") (memory $memory "mem")) + ) + (func (export "sync-17-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)) + (canon lift (core func $core "sync-17-result") (memory $memory "mem")) + ) + (func (export "async-4-param") async + (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) + (canon lift (core func $core "async-4-param") async (callback (func $core "unreachable-cb"))) + ) + (func (export "async-5-param") async + (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) (param "e" u32) + (canon lift (core func $core "async-5-param") async (callback (func $core "unreachable-cb"))) + ) + (func (export "async-17-param") async + (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) + (param "e" u32) (param "f" u64) (param "g" f32) (param "h" f64) + (param "i" u32) (param "j" u64) (param "k" f32) (param "l" f64) + (param "m" u32) (param "n" u64) (param "o" f32) (param "p" f64) + (param "q" u32) + (canon lift (core func $core "async-17-param") async (callback (func $core "unreachable-cb")) (memory $memory "mem") (realloc (func $memory "realloc"))) + ) + (func (export "async-1-result") async (result f64) + (canon lift (core func $core "async-1-result") async (callback (func $core "unreachable-cb"))) + ) + (func (export "async-16-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)) + (canon lift (core func $core "async-16-result") async (callback (func $core "unreachable-cb"))) + ) + (func (export "async-17-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)) + (canon lift (core func $core "async-17-result") async (callback (func $core "unreachable-cb")) (memory $memory "mem") (realloc (func $memory "realloc"))) + ) + ) + (component $Bottom + (import "func-4-param" (func $func-4-param async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64))) + (import "func-5-param" (func $func-5-param async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) (param "e" u32))) + (import "func-17-param" (func $func-17-param async + (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) + (param "e" u32) (param "f" u64) (param "g" f32) (param "h" f64) + (param "i" u32) (param "j" u64) (param "k" f32) (param "l" f64) + (param "m" u32) (param "n" u64) (param "o" f32) (param "p" f64) + (param "q" u32))) + (import "func-1-result" (func $func-1-result async (result f64))) + (import "func-16-result" (func $func-16-result async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)))) + (import "func-17-result" (func $func-17-result async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)))) + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "sync-4-param" (func $sync-4-param (param i32 i64 f32 f64))) + (import "" "async-4-param" (func $async-4-param (param i32 i64 f32 f64) (result i32))) + (import "" "sync-5-param" (func $sync-5-param (param i32 i64 f32 f64 i32))) + (import "" "async-5-param" (func $async-5-param (param i32) (result i32))) + (import "" "sync-17-param" (func $sync-17-param (param i32))) + (import "" "async-17-param" (func $async-17-param (param i32) (result i32))) + (import "" "sync-1-result" (func $sync-1-result (result f64))) + (import "" "async-1-result" (func $async-1-result (param i32) (result i32))) + (import "" "sync-16-result" (func $sync-16-result (param i32))) + (import "" "async-16-result" (func $async-16-result (param i32) (result i32))) + (import "" "sync-17-result" (func $sync-17-result (param i32))) + (import "" "async-17-result" (func $async-17-result (param i32) (result i32))) + (func (export "call-sync-4-param") (result i32) + (call $sync-4-param (i32.const 42) (i64.const 43) (f32.const 44.4) (f64.const 45.5)) + (i32.const 83) + ) + (func (export "call-async-4-param") (result i32) + (if (i32.ne (call $async-4-param (i32.const 42) (i64.const 43) (f32.const 44.4) (f64.const 45.5)) + (i32.const 2 (; RETURNED ;))) + (then unreachable)) + (i32.const 84) + ) + (func (export "call-sync-5-param") (result i32) + (call $sync-5-param (i32.const -1) (i64.const -2) (f32.const -3.3) (f64.const -4.4) (i32.const -5)) + (i32.const 85) + ) + (func (export "call-async-5-param") (result i32) + (local $ptr i32) + (i32.store (local.get $ptr) (i32.const -1)) + (i64.store offset=8 (local.get $ptr) (i64.const -2)) + (f32.store offset=16 (local.get $ptr) (f32.const -3.3)) + (f64.store offset=24 (local.get $ptr) (f64.const -4.4)) + (i32.store offset=32 (local.get $ptr) (i32.const -5)) + (if (i32.ne (call $async-5-param (local.get $ptr)) (i32.const 2 (; RETURNED ;))) + (then unreachable)) + (i32.const 86) + ) + (func $setup-17 (param $ptr i32) + (i32.store (local.get $ptr) (i32.const -1)) + (i64.store offset=8 (local.get $ptr) (i64.const -2)) + (f32.store offset=16 (local.get $ptr) (f32.const -3.3)) + (f64.store offset=24 (local.get $ptr) (f64.const -4.4)) + (i32.store offset=32 (local.get $ptr) (i32.const -5)) + (i64.store offset=40 (local.get $ptr) (i64.const -6)) + (f32.store offset=48 (local.get $ptr) (f32.const -7.7)) + (f64.store offset=56 (local.get $ptr) (f64.const -8.8)) + (i32.store offset=64 (local.get $ptr) (i32.const -9)) + (i64.store offset=72(local.get $ptr) (i64.const -10)) + (f32.store offset=80 (local.get $ptr) (f32.const -11.11)) + (f64.store offset=88 (local.get $ptr) (f64.const -12.12)) + (i32.store offset=96 (local.get $ptr) (i32.const -13)) + (i64.store offset=104 (local.get $ptr) (i64.const -14)) + (f32.store offset=112 (local.get $ptr) (f32.const -15.15)) + (f64.store offset=120 (local.get $ptr) (f64.const -16.16)) + (i32.store offset=128 (local.get $ptr) (i32.const -17)) + ) + (func (export "call-sync-17-param") (result i32) + (call $setup-17 (i32.const 0)) + (call $sync-17-param (i32.const 0)) + (i32.const 87) + ) + (func (export "call-async-17-param") (result i32) + (call $setup-17 (i32.const 0)) + (if (i32.ne (call $async-17-param (i32.const 0)) (i32.const 2 (; RETURNED ;))) + (then unreachable)) + (i32.const 88) + ) + (func (export "call-sync-1-result") (result i32) + (if (f64.ne (call $sync-1-result) (f64.const -1.1)) + (then unreachable)) + (i32.const 89) + ) + (func (export "call-async-1-result") (result i32) + (local $ptr i32) + (if (i32.ne (call $async-1-result (local.get $ptr)) (i32.const 2 (; RETURNED ;))) + (then unreachable)) + (if (f64.ne (f64.load (local.get $ptr)) (f64.const -1.1)) + (then unreachable)) + (i32.const 90) + ) + (func $check-16 (param $ptr i32) + (if (i32.ne (i32.const -1) (i32.load (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -2) (i64.load offset=8 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -3.3) (f32.load offset=16 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -4.4) (f64.load offset=24 (local.get $ptr))) + (then unreachable)) + (if (i32.ne (i32.const -5) (i32.load offset=32 (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -6) (i64.load offset=40 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -7.7) (f32.load offset=48 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -8.8) (f64.load offset=56 (local.get $ptr))) + (then unreachable)) + (if (i32.ne (i32.const -9) (i32.load offset=64 (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -10) (i64.load offset=72 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -11.11) (f32.load offset=80 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -12.12) (f64.load offset=88 (local.get $ptr))) + (then unreachable)) + (if (i32.ne (i32.const -13) (i32.load offset=96 (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -14) (i64.load offset=104 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -15.15) (f32.load offset=112 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -16.16) (f64.load offset=120 (local.get $ptr))) + (then unreachable)) + ) + (func $check-17 (param $ptr i32) + (call $check-16 (local.get $ptr)) + (if (i32.ne (i32.const -17) (i32.load offset=128 (local.get $ptr))) + (then unreachable)) + ) + (func (export "call-sync-16-result") (result i32) + (local $ptr i32) + (call $sync-16-result (local.get $ptr)) + (call $check-16 (local.get $ptr)) + (i32.const 91) + ) + (func (export "call-async-16-result") (result i32) + (local $ptr i32) + (if (i32.ne (call $async-16-result (local.get $ptr)) (i32.const 2 (; RETURNED ;))) + (then unreachable)) + (call $check-16 (local.get $ptr)) + (i32.const 92) + ) + (func (export "call-sync-17-result") (result i32) + (local $ptr i32) + (call $sync-17-result (local.get $ptr)) + (call $check-17 (local.get $ptr)) + (i32.const 93) + ) + (func (export "call-async-17-result") (result i32) + (local $ptr i32) + (if (i32.ne (call $async-17-result (local.get $ptr)) (i32.const 2 (; RETURNED ;))) + (then unreachable)) + (call $check-17 (local.get $ptr)) + (i32.const 94) + ) + ) + (canon lower (func $func-4-param) (core func $sync-4-param)) + (canon lower (func $func-4-param) async (memory $memory "mem") (core func $async-4-param)) + (canon lower (func $func-5-param) (core func $sync-5-param)) + (canon lower (func $func-5-param) async (memory $memory "mem") (core func $async-5-param)) + (canon lower (func $func-17-param) (memory $memory "mem") (core func $sync-17-param)) + (canon lower (func $func-17-param) async (memory $memory "mem") (core func $async-17-param)) + (canon lower (func $func-1-result) (core func $sync-1-result)) + (canon lower (func $func-1-result) async (memory $memory "mem") (core func $async-1-result)) + (canon lower (func $func-16-result) (memory $memory "mem") (core func $sync-16-result)) + (canon lower (func $func-16-result) async (memory $memory "mem") (core func $async-16-result)) + (canon lower (func $func-17-result) (memory $memory "mem") (core func $sync-17-result)) + (canon lower (func $func-17-result) async (memory $memory "mem") (core func $async-17-result)) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "sync-4-param" (func $sync-4-param)) + (export "async-4-param" (func $async-4-param)) + (export "sync-5-param" (func $sync-5-param)) + (export "async-5-param" (func $async-5-param)) + (export "sync-17-param" (func $sync-17-param)) + (export "async-17-param" (func $async-17-param)) + (export "sync-1-result" (func $sync-1-result)) + (export "async-1-result" (func $async-1-result)) + (export "sync-16-result" (func $sync-16-result)) + (export "async-16-result" (func $async-16-result)) + (export "sync-17-result" (func $sync-17-result)) + (export "async-17-result" (func $async-17-result)) + )))) + (func (export "call-sync-4-param") async (result u32) (canon lift (core func $core "call-sync-4-param"))) + (func (export "call-async-4-param") async (result u32) (canon lift (core func $core "call-async-4-param"))) + (func (export "call-sync-5-param") async (result u32) (canon lift (core func $core "call-sync-5-param"))) + (func (export "call-async-5-param") async (result u32) (canon lift (core func $core "call-async-5-param"))) + (func (export "call-sync-17-param") async (result u32) (canon lift (core func $core "call-sync-17-param"))) + (func (export "call-async-17-param") async (result u32) (canon lift (core func $core "call-async-17-param"))) + (func (export "call-sync-1-result") async (result u32) (canon lift (core func $core "call-sync-1-result"))) + (func (export "call-async-1-result") async (result u32) (canon lift (core func $core "call-async-1-result"))) + (func (export "call-sync-16-result") async (result u32) (canon lift (core func $core "call-sync-16-result"))) + (func (export "call-async-16-result") async (result u32) (canon lift (core func $core "call-async-16-result"))) + (func (export "call-sync-17-result") async (result u32) (canon lift (core func $core "call-sync-17-result"))) + (func (export "call-async-17-result") async (result u32) (canon lift (core func $core "call-async-17-result"))) + ) + (instance $top (instantiate $Top)) + (instance $bottom-to-sync (instantiate $Bottom + (with "func-4-param" (func $top "sync-4-param")) + (with "func-5-param" (func $top "sync-5-param")) + (with "func-17-param" (func $top "sync-17-param")) + (with "func-1-result" (func $top "sync-1-result")) + (with "func-16-result" (func $top "sync-16-result")) + (with "func-17-result" (func $top "sync-17-result")) + )) + (instance $bottom-to-async (instantiate $Bottom + (with "func-4-param" (func $top "async-4-param")) + (with "func-5-param" (func $top "async-5-param")) + (with "func-17-param" (func $top "async-17-param")) + (with "func-1-result" (func $top "async-1-result")) + (with "func-16-result" (func $top "async-16-result")) + (with "func-17-result" (func $top "async-17-result")) + )) + (func (export "sync-calls-sync-4-param") (alias export $bottom-to-sync "call-sync-4-param")) + (func (export "sync-calls-async-4-param") (alias export $bottom-to-async "call-sync-4-param")) + (func (export "async-calls-sync-4-param") (alias export $bottom-to-sync "call-async-4-param")) + (func (export "async-calls-async-4-param") (alias export $bottom-to-async "call-async-4-param")) + (func (export "sync-calls-sync-5-param") (alias export $bottom-to-sync "call-sync-5-param")) + (func (export "sync-calls-async-5-param") (alias export $bottom-to-async "call-sync-5-param")) + (func (export "async-calls-sync-5-param") (alias export $bottom-to-sync "call-async-5-param")) + (func (export "async-calls-async-5-param") (alias export $bottom-to-async "call-async-5-param")) + (func (export "sync-calls-sync-17-param") (alias export $bottom-to-sync "call-sync-17-param")) + (func (export "sync-calls-async-17-param") (alias export $bottom-to-async "call-sync-17-param")) + (func (export "async-calls-sync-17-param") (alias export $bottom-to-sync "call-async-17-param")) + (func (export "async-calls-async-17-param") (alias export $bottom-to-async "call-async-17-param")) + (func (export "sync-calls-sync-1-result") (alias export $bottom-to-sync "call-sync-1-result")) + (func (export "sync-calls-async-1-result") (alias export $bottom-to-async "call-sync-1-result")) + (func (export "async-calls-sync-1-result") (alias export $bottom-to-sync "call-async-1-result")) + (func (export "async-calls-async-1-result") (alias export $bottom-to-async "call-async-1-result")) + (func (export "sync-calls-sync-16-result") (alias export $bottom-to-sync "call-sync-16-result")) + (func (export "sync-calls-async-16-result") (alias export $bottom-to-async "call-sync-16-result")) + (func (export "async-calls-sync-16-result") (alias export $bottom-to-sync "call-async-16-result")) + (func (export "async-calls-async-16-result") (alias export $bottom-to-async "call-async-16-result")) + (func (export "sync-calls-sync-17-result") (alias export $bottom-to-sync "call-sync-17-result")) + (func (export "sync-calls-async-17-result") (alias export $bottom-to-async "call-sync-17-result")) + (func (export "async-calls-sync-17-result") (alias export $bottom-to-sync "call-async-17-result")) + (func (export "async-calls-async-17-result") (alias export $bottom-to-async "call-async-17-result")) +) + +(component instance $i $C) +(assert_return (invoke "sync-calls-sync-4-param") (u32.const 83)) +(component instance $i $C) +(assert_return (invoke "sync-calls-async-4-param") (u32.const 83)) +(component instance $i $C) +(assert_return (invoke "async-calls-sync-4-param") (u32.const 84)) +(component instance $i $C) +(assert_return (invoke "async-calls-async-4-param") (u32.const 84)) +(component instance $i $C) +(assert_return (invoke "sync-calls-sync-5-param") (u32.const 85)) +(component instance $i $C) +(assert_return (invoke "sync-calls-async-5-param") (u32.const 85)) +(component instance $i $C) +(assert_return (invoke "async-calls-sync-5-param") (u32.const 86)) +(component instance $i $C) +(assert_return (invoke "async-calls-async-5-param") (u32.const 86)) +(component instance $i $C) +(assert_return (invoke "sync-calls-sync-17-param") (u32.const 87)) +(component instance $i $C) +(assert_return (invoke "sync-calls-async-17-param") (u32.const 87)) +(component instance $i $C) +(assert_return (invoke "async-calls-sync-17-param") (u32.const 88)) +(component instance $i $C) +(assert_return (invoke "async-calls-async-17-param") (u32.const 88)) +(component instance $i $C) +(assert_return (invoke "sync-calls-sync-1-result") (u32.const 89)) +(component instance $i $C) +(assert_return (invoke "sync-calls-async-1-result") (u32.const 89)) +(component instance $i $C) +(assert_return (invoke "async-calls-sync-1-result") (u32.const 90)) +(component instance $i $C) +(assert_return (invoke "async-calls-async-1-result") (u32.const 90)) +(component instance $i $C) +(assert_return (invoke "sync-calls-sync-16-result") (u32.const 91)) +(component instance $i $C) +(assert_return (invoke "sync-calls-async-16-result") (u32.const 91)) +(component instance $i $C) +(assert_return (invoke "async-calls-sync-16-result") (u32.const 92)) +(component instance $i $C) +(assert_return (invoke "async-calls-async-16-result") (u32.const 92)) +(component instance $i $C) +(assert_return (invoke "sync-calls-sync-17-result") (u32.const 93)) +(component instance $i $C) +(assert_return (invoke "sync-calls-async-17-result") (u32.const 93)) +(component instance $i $C) +(assert_return (invoke "async-calls-sync-17-result") (u32.const 94)) +(component instance $i $C) +(assert_return (invoke "async-calls-async-17-result") (u32.const 94)) diff --git a/parser/src/test/resources/spec-tests/async/deadlock.wast b/parser/src/test/resources/spec-tests/async/deadlock.wast new file mode 100644 index 0000000..6d50c9f --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/deadlock.wast @@ -0,0 +1,73 @@ +;; This test defines components $C and $D where $D imports and calls $C +;; $C.f waits on an empty waitable set +;; $D.g calls $C.f and then waits for it to finish, which fails due to deadlock +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + + (func (export "f") (result i32) + ;; wait on a new empty waitable set + (local $ws i32) + (local.set $ws (call $waitable-set.new)) + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (local.get $ws) (i32.const 4))) + ) + (func (export "cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + unreachable + ) + ) + (canon waitable-set.new (core func $waitable-set.new)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable-set.new" (func $waitable-set.new)) + )))) + (func (export "f") async (result u32) (canon lift + (core func $cm "f") + async (memory $memory "mem") (callback (func $cm "cb")) + )) + ) + + (component $D + (import "f" (func $f async (result u32))) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "f" (func $f (param i32) (result i32))) + + (func (export "g") (result i32) + (local $ws i32) (local $ret i32) (local $subtaski i32) + (local.set $ret (call $f (i32.const 0))) + (local.set $subtaski (i32.shr_u (local.get $ret) (i32.const 4))) + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtaski) (local.get $ws)) + (call $waitable-set.wait (local.get $ws) (i32.const 0)) + unreachable + ) + ) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon lower (func $f) async (memory $memory "mem") (core func $f')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "f" (func $f')) + )))) + (func (export "f") async (result u32) (canon lift (core func $dm "g"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "f" (func $c "f")))) + (func (export "f") (alias export $d "f")) +) +(assert_trap (invoke "f") "wasm trap: deadlock detected: event loop cannot make further progress") diff --git a/parser/src/test/resources/spec-tests/async/dont-block-start.wast b/parser/src/test/resources/spec-tests/async/dont-block-start.wast new file mode 100644 index 0000000..5fab77f --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/dont-block-start.wast @@ -0,0 +1,50 @@ +;; test a few cases where components trap during core module instantiation +;; due to blocking during the (implicitly sync) start function +(assert_trap + (component + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $M + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (func $start + (drop (call $waitable-set.wait (call $waitable-set.new) (i32.const 0))) + ) + (start $start) + ) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (core instance $m (instantiate $M (with "" (instance + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + )))) + ) + "cannot block a synchronous task before returning" +) +(assert_trap + (component + (component $C + (core module $M + (func (export "f") (result i32) unreachable) + (func (export "f_cb") (param i32 i32 i32) (result i32) unreachable) + ) + (core instance $i (instantiate $M)) + (func (export "f") async (canon lift (core func $i "f") async (callback (func $i "f_cb")))) + ) + (component $D + (import "f" (func $f async)) + (core module $M + (import "" "f" (func $f)) + (func $start (call $f)) + (start $start) + ) + (canon lower (func $f) (core func $f')) + (core instance $m (instantiate $M (with "" (instance + (export "f" (func $f')) + )))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "f" (func $c "f")))) + ) + "cannot block a synchronous task before returning" +) diff --git a/parser/src/test/resources/spec-tests/async/drop-cross-task-borrow.wast b/parser/src/test/resources/spec-tests/async/drop-cross-task-borrow.wast new file mode 100644 index 0000000..139981c --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/drop-cross-task-borrow.wast @@ -0,0 +1,309 @@ +;; This test has 3 components $C, $D and $E +;; $C just implements a resource type that's used by $D and $E +;; $E calls async function $D.dont-drop, lending it a handle. +;; $D.dont-drop blocks, waiting on an empty waitable-set +;; $E then calls $D.drop-handle which drops the handle that $D.dont-drop +;; was lent, albeit from the "wrong" task ($D.drop-handle). +;; Then $E calls $D.resume-dont-drop to unblock $D.dont-drop, which +;; will call task.return which should not trap. +(component definition $Test + (component $C + (type $R' (resource (rep i32))) + (canon resource.new $R' (core func $resource.new)) + (core module $CM (func (export "id") (param i32) (result i32) (local.get 0))) + (core instance $cm (instantiate $CM)) + (alias core export $cm "id" (core func $resource.rep)) + (export $R "R" (type $R')) + (func (export "R-new") (param "rep" u32) (result (own $R)) (canon lift (core func $resource.new))) + (func (export "R-rep") (param "self" (borrow $R)) (result u32) (canon lift (core func $resource.rep))) + ) + + (component $D + (import "c" (instance $d + (export "R" (type $R (sub resource))) + (export "R-new" (func (param "rep" u32) (result (own $R)))) + (export "R-rep" (func (param "self" (borrow $R)) (result u32))) + )) + (core module $DM + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "task.return0" (func $task.return0)) + (import "" "task.return1" (func $task.return1 (param i32))) + (import "" "R-rep" (func $R-rep (param i32) (result i32))) + (import "" "R-drop" (func $R-drop (param i32))) + + (global $handle (mut i32) (i32.const 0)) + (global $dont-drop-result (mut i32) (i32.const 0)) + (global $dont-drop-ws (mut i32) (i32.const 0)) + + (func (export "dont-drop") (param $h i32) (result i32) + ;; Stash the given (borrow $R) handle in a global. + (global.set $handle (local.get $h)) + ;; Stash the result of $R-rep in a global for later task.return + (global.set $dont-drop-result (call $R-rep (local.get $h))) + ;; Stash the waitable-set we're waiting on in a global for resume-dont-drop to use + (global.set $dont-drop-ws (call $waitable-set.new)) + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $dont-drop-ws) (i32.const 4))) + ) + (func (export "dont-drop-cb") (param i32 i32 i32) (result i32) + ;; We were resumed by resume-dont-drop + (call $task.return1 (global.get $dont-drop-result)) + (i32.const 0 (; EXIT ;)) + ) + (func (export "drop-handle") (result i32) + ;; Drops the borrowed handle passed to dont-drop + (local $result i32) + (local.set $result (call $R-rep (global.get $handle))) + (call $R-drop (global.get $handle)) + (local.get $result) + ) + (func (export "resume-dont-drop") + ;; Add a waitable with a pending event to dont-drop's waitable-set to + ;; wake it up. + (local $ret i32) (local $ret64 i64) + (local $futw i32) (local $futr i32) + (local.set $ret64 (call $future.new)) + (local.set $futr (i32.wrap_i64 (local.get $ret64))) + (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (local.get $futr) (global.get $dont-drop-ws)) + ) + (func (export "drop-other-and-self") (param $h i32) (result i32) + (local $result i32) + (local.set $result (call $R-rep (global.get $handle))) + (call $R-drop (global.get $handle)) + (call $R-drop (local.get $h)) + (call $task.return1 (local.get $result)) + (i32.const 0 (; EXIT ;)) + ) + (func (export "drop-wrong-one") (param $h i32) (result i32) + (call $R-drop (global.get $handle)) + ;; trap b/c $h wasn't dropped + (call $task.return0) + (i32.const 0 (; EXIT ;)) + ) + (func (export "unreachable-cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (type $FT (future)) + (alias export $d "R" (type $R)) + (canon task.return (core func $task.return0)) + (canon task.return (result u32) (core func $task.return1)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon future.new $FT (core func $future.new)) + (canon future.read $FT async (core func $future.read)) + (canon future.write $FT async (core func $future.write)) + (canon lower (func $d "R-rep") (core func $R-rep)) + (canon resource.drop $R (core func $R-drop)) + (core instance $dm (instantiate $DM (with "" (instance + (export "task.return0" (func $task.return0)) + (export "task.return1" (func $task.return1)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "future.new" (func $future.new)) + (export "future.read" (func $future.read)) + (export "future.write" (func $future.write)) + (export "R-rep" (func $R-rep)) + (export "R-drop" (func $R-drop)) + )))) + (func (export "dont-drop") async (param "self" (borrow $R)) (result u32) + (canon lift (core func $dm "dont-drop") async (callback (func $dm "dont-drop-cb"))) + ) + (func (export "drop-handle") (result u32) + (canon lift (core func $dm "drop-handle")) + ) + (func (export "resume-dont-drop") + (canon lift (core func $dm "resume-dont-drop")) + ) + (func (export "drop-other-and-self") async (param "self" (borrow $R)) (result u32) + (canon lift (core func $dm "drop-other-and-self") async (callback (func $dm "unreachable-cb"))) + ) + (func (export "drop-wrong-one") async (param "self" (borrow $R)) + (canon lift (core func $dm "drop-wrong-one") async (callback (func $dm "unreachable-cb"))) + ) + ) + + (component $E + (import "c" (instance $c + (export "R" (type $R (sub resource))) + (export "R-new" (func (param "rep" u32) (result (own $R)))) + )) + (alias export $c "R" (type $R)) + (import "d" (instance $d + (export "dont-drop" (func async (param "self" (borrow $R)) (result u32))) + (export "drop-handle" (func (result u32))) + (export "resume-dont-drop" (func)) + (export "drop-other-and-self" (func async (param "self" (borrow $R)) (result u32))) + (export "drop-wrong-one" (func async (param "self" (borrow $R)))) + )) + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $EM + (import "" "mem" (memory 1)) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "R-new" (func $R-new (param i32) (result i32))) + (import "" "dont-drop" (func $dont-drop (param i32 i32) (result i32))) + (import "" "drop-handle" (func $drop-handle (result i32))) + (import "" "resume-dont-drop" (func $resume-dont-drop)) + (import "" "drop-other-and-self" (func $drop-other-and-self (param i32) (result i32))) + (import "" "drop-wrong-one" (func $drop-wrong-one (param i32))) + (func (export "drop-other-no-self") (result i32) + (local $ret i32) + (local $retp i32) (local $retp2 i32) + (local $handle i32) + (local $subtask i32) + (local $magic i32) + (local $ws i32) (local $event_code i32) + + ;; Create a resource storing $magic as it's rep + (local.set $magic (i32.const 10)) + (local.set $handle (call $R-new (local.get $magic))) + + ;; Kick off a call to dont-drop that will block + (local.set $retp (i32.const 16)) + (local.set $ret (call $dont-drop (local.get $handle) (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; drop-handle should return the rep of the handle passed to dont-drop + (local.set $ret (call $drop-handle)) + (if (i32.ne (local.get $magic) (local.get $ret)) + (then unreachable)) + + ;; this unblocks $subtask + (call $resume-dont-drop) + + ;; now wait for $subtask to return, so that it can run before the test is over + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtask) (local.get $ws)) + (local.set $retp2 (i32.const 32)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) + (then unreachable)) + + ;; $subtask should return the rep passed to $R-new. + (if (i32.ne (local.get $magic) (i32.load (local.get $retp))) + (then unreachable)) + + i32.const 42 + ) + (func (export "drop-other-and-self") (result i32) + (local $ret i32) + (local $retp i32) (local $retp2 i32) + (local $handle i32) + (local $subtask i32) + (local $magic i32) + (local $ws i32) (local $event_code i32) + + ;; Create a resource storing $magic as it's rep + (local.set $magic (i32.const 11)) + (local.set $handle (call $R-new (local.get $magic))) + + ;; Kick off a call to dont-drop that will block + (local.set $retp (i32.const 16)) + (local.set $ret (call $dont-drop (local.get $handle) (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; This will drop dont-drop's *and* its own borrowed handle + (local.set $ret (call $drop-other-and-self (local.get $handle))) + (if (i32.ne (local.get $magic) (local.get $ret)) + (then unreachable)) + + ;; this unblocks $subtask + (call $resume-dont-drop) + + ;; now wait for $subtask to return, so that it can run before the test is over + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtask) (local.get $ws)) + (local.set $retp2 (i32.const 32)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) + (then unreachable)) + + ;; $subtask should return the rep passed to $R-new. + (if (i32.ne (local.get $magic) (i32.load (local.get $retp))) + (then unreachable)) + + i32.const 43 + ) + (func (export "drop-other-miss-self") + (local $ret i32) + (local $retp i32) + (local $handle i32) + (local $subtask i32) + + (local.set $handle (call $R-new (i32.const 42))) + + ;; Kick off a call to dont-drop that will block + (local.set $retp (i32.const 16)) + (local.set $ret (call $dont-drop (local.get $handle) (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; Call drop-wrong-one which will drop the above call's borrow, but not its own and trap + (call $drop-wrong-one (local.get $handle)) + ) + ) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon lower (func $c "R-new") (core func $R-new)) + (canon lower (func $d "dont-drop") async (memory $memory "mem") (core func $dont-drop)) + (canon lower (func $d "drop-handle") (core func $drop-handle)) + (canon lower (func $d "resume-dont-drop") (core func $resume-dont-drop)) + (canon lower (func $d "drop-other-and-self") (core func $drop-other-and-self)) + (canon lower (func $d "drop-wrong-one") (core func $drop-wrong-one)) + (core instance $em (instantiate $EM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "R-new" (func $R-new)) + (export "dont-drop" (func $dont-drop)) + (export "drop-handle" (func $drop-handle)) + (export "resume-dont-drop" (func $resume-dont-drop)) + (export "drop-other-and-self" (func $drop-other-and-self)) + (export "drop-wrong-one" (func $drop-wrong-one)) + )))) + (func (export "drop-other-no-self") async (result u32) (canon lift (core func $em "drop-other-no-self"))) + (func (export "drop-other-and-self") async (result u32) (canon lift (core func $em "drop-other-and-self"))) + (func (export "drop-other-miss-self") async (canon lift (core func $em "drop-other-miss-self"))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (instance $e (instantiate $E (with "c" (instance $c)) (with "d" (instance $d)))) + (func (export "drop-other-no-self") (alias export $e "drop-other-no-self")) + (func (export "drop-other-and-self") (alias export $e "drop-other-and-self")) + (func (export "drop-other-miss-self") (alias export $e "drop-other-miss-self")) +) + +(component instance $i $Test) +(assert_return (invoke "drop-other-no-self") (u32.const 42)) +(component instance $i $Test) +(assert_return (invoke "drop-other-and-self") (u32.const 43)) +(component instance $i $Test) +(assert_trap (invoke "drop-other-miss-self") "borrow handles still remain at the end of the call") diff --git a/parser/src/test/resources/spec-tests/async/drop-stream.wast b/parser/src/test/resources/spec-tests/async/drop-stream.wast new file mode 100644 index 0000000..bf7212f --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/drop-stream.wast @@ -0,0 +1,160 @@ +;; This test contains two components $C and $D that test that traps occur +;; when closing the readable or writable end of stream while a read or write +;; is pending. In particular, even if a partial copy has happened into the +;; buffer such that waiting/polling for an event *would* produce a STREAM +;; READ/WRITE event, if the event has not been delivered, the operation is +;; still considered pending. +(component definition $Tester + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + (global $sw (mut i32) (i32.const 0)) + + (func $start-stream (export "start-stream") (result i32) + ;; create a new stream, return the readable end to the caller + (local $ret64 i64) + (local.set $ret64 (call $stream.new)) + (global.set $sw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (i32.wrap_i64 (local.get $ret64)) + ) + (func $write4 (export "write4") + ;; write 6 bytes into the stream, expecting to rendezvous with a stream.read + (local $ret i32) + (i32.store (i32.const 8) (i32.const 0x12345678)) + (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 4))) + (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + ) + (func $start-blocking-write (export "start-blocking-write") + (local $ret i32) + + ;; prepare the write buffer + (i64.store (i32.const 8) (i64.const 0x123456789abcdef)) + + ;; start a blocking write + (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 8))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + ) + (func $drop-writable (export "drop-writable") + ;; boom + (call $stream.drop-writable (global.get $sw)) + ) + ) + (type $ST (stream u8)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "stream.new" (func $stream.new)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (func (export "start-stream") (result (stream u8)) (canon lift (core func $cm "start-stream"))) + (func (export "write4") (canon lift (core func $cm "write4"))) + (func (export "start-blocking-write") (canon lift (core func $cm "start-blocking-write"))) + (func (export "drop-writable") (canon lift (core func $cm "drop-writable"))) + ) + (component $D + (import "c" (instance $c + (export "start-stream" (func (result (stream u8)))) + (export "write4" (func)) + (export "start-blocking-write" (func)) + (export "drop-writable" (func)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + (import "" "start-stream" (func $start-stream (result i32))) + (import "" "write4" (func $write4)) + (import "" "start-blocking-write" (func $start-blocking-write)) + (import "" "drop-writable" (func $drop-writable)) + + (func (export "drop-while-reading") + (local $ret i32) (local $sr i32) + + ;; call 'start-stream' to get the stream we'll be working with + (local.set $sr (call $start-stream)) + (if (i32.ne (i32.const 1) (local.get $sr)) + (then unreachable)) + + ;; start a blocking read + (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) + (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) + (then unreachable)) + + ;; write into the buffer, but the read is still in progress since we + ;; haven't received notification yet. + (call $write4) + (if (i32.ne (i32.const 0x12345678) (i32.load (i32.const 8))) + (then unreachable)) + + ;; boom + (call $stream.drop-readable (local.get $sr)) + ) + (func (export "drop-while-writing") + (local $ret i32) (local $sr i32) + + ;; call 'start-stream' to get the stream we'll be working with + (local.set $sr (call $start-stream)) + (if (i32.ne (i32.const 1) (local.get $sr)) + (then unreachable)) + + ;; start a blocking write and partially read from it + (call $start-blocking-write) + (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 4))) + (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0x89abcdef) (i32.load (i32.const 8))) + (then unreachable)) + (call $drop-writable) + ) + ) + (type $ST (stream u8)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (canon lower (func $c "start-stream") (core func $start-stream')) + (canon lower (func $c "write4") (core func $write4')) + (canon lower (func $c "start-blocking-write") (core func $start-blocking-write')) + (canon lower (func $c "drop-writable") (core func $drop-writable')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "stream.drop-writable" (func $stream.drop-writable)) + (export "start-stream" (func $start-stream')) + (export "write4" (func $write4')) + (export "start-blocking-write" (func $start-blocking-write')) + (export "drop-writable" (func $drop-writable')) + )))) + (func (export "drop-while-reading") (canon lift (core func $core "drop-while-reading"))) + (func (export "drop-while-writing") (canon lift (core func $core "drop-while-writing"))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "drop-while-reading") (alias export $d "drop-while-reading")) + (func (export "drop-while-writing") (alias export $d "drop-while-writing")) +) +(component instance $new-tester-instance $Tester) +(assert_trap (invoke "drop-while-reading") "cannot remove busy stream") +(component instance $new-tester-instance $Tester) +(assert_trap (invoke "drop-while-writing") "cannot drop busy stream") diff --git a/parser/src/test/resources/spec-tests/async/drop-subtask.wast b/parser/src/test/resources/spec-tests/async/drop-subtask.wast new file mode 100644 index 0000000..21eb9fc --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/drop-subtask.wast @@ -0,0 +1,140 @@ +;; This test contains two components: $Looper and $Caller. +;; $Caller starts an async subtask for $Looper.loop and then drops these +;; subtasks in both allowed and disallowed cases, testing for success and +;; traps. +(component + (component $Looper + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CoreLooper + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return)) + + (global $done (mut i32) (i32.const 0)) + + (func $loop (export "loop") (result i32) + (i32.const 1 (; YIELD ;)) + ) + (func $loop_cb (export "loop_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + ;; confirm that we've received a cancellation request + (if (i32.ne (local.get $event_code) (i32.const 0 (; NONE ;))) + (then unreachable)) + (if (i32.ne (local.get $index) (i32.const 0)) + (then unreachable)) + (if (i32.ne (local.get $payload) (i32.const 0)) + (then unreachable)) + + (if (i32.eqz (global.get $done)) + (then (return (i32.const 1 (; YIELD ;))))) + (call $task.return) + (i32.const 0 (; EXIT ;)) + ) + + (func $return (export "return") + (global.set $done (i32.const 1)) + ) + ) + (canon task.return (core func $task.return)) + (core instance $core_looper (instantiate $CoreLooper (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + )))) + (func (export "loop") async (canon lift + (core func $core_looper "loop") + async (callback (func $core_looper "loop_cb")) + )) + (func (export "return") async (canon lift + (core func $core_looper "return") + )) + ) + + (component $Caller + (import "looper" (instance $looper + (export "loop" (func async)) + (export "return" (func async)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CoreCaller + (import "" "mem" (memory 1)) + (import "" "subtask.drop" (func $subtask.drop (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "loop" (func $loop (result i32))) + (import "" "return" (func $return)) + + (func $drop-after-return (export "drop-after-return") (result i32) + (local $ret i32) (local $ws i32) (local $subtask i32) + + ;; start 'loop' + (local.set $ret (call $loop)) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; tell 'loop' to stop + (call $return) + + ;; wait for 'loop' to run and return + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtask) (local.get $ws)) + (local.set $ret (call $waitable-set.wait (local.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (i32.const 0))) + (then unreachable)) + (if (i32.ne (i32.const 2 (; RETURNED ;)) (i32.load (i32.const 4))) + (then unreachable)) + + ;; ok to drop + (call $subtask.drop (local.get $subtask)) + (i32.const 42) + ) + + (func $drop-before-return (export "drop-before-return") (result i32) + (local $ret i32) (local $subtask i32) + + ;; start 'loop' + (local.set $ret (call $loop (i32.const 0xdead) (i32.const 0xbeef))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; this should trap + (call $subtask.drop (local.get $subtask)) + unreachable + ) + ) + (canon subtask.drop (core func $subtask.drop)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon lower (func $looper "loop") async (memory $memory "mem") (core func $loop')) + (canon lower (func $looper "return") (memory $memory "mem") (core func $return')) + (core instance $core_caller (instantiate $CoreCaller (with "" (instance + (export "mem" (memory $memory "mem")) + (export "subtask.drop" (func $subtask.drop)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "loop" (func $loop')) + (export "return" (func $return')) + )))) + (func (export "drop-after-return") async (result u32) (canon lift + (core func $core_caller "drop-after-return") + )) + (func (export "drop-before-return") async (result u32) (canon lift + (core func $core_caller "drop-before-return") + )) + ) + + (instance $looper (instantiate $Looper)) + (instance $caller1 (instantiate $Caller (with "looper" (instance $looper)))) + (instance $caller2 (instantiate $Caller (with "looper" (instance $looper)))) + (func (export "drop-after-return") (alias export $caller1 "drop-after-return")) + (func (export "drop-before-return") (alias export $caller2 "drop-before-return")) +) +(assert_return (invoke "drop-after-return") (u32.const 42)) +(assert_trap (invoke "drop-before-return") "cannot drop a subtask which has not yet resolved") diff --git a/parser/src/test/resources/spec-tests/async/drop-waitable-set.wast b/parser/src/test/resources/spec-tests/async/drop-waitable-set.wast new file mode 100644 index 0000000..23fff15 --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/drop-waitable-set.wast @@ -0,0 +1,84 @@ +;; This test contains two components $C and $D +;; $D.run drives the test and first calls $C.wait-on-set, which waits on +;; a waitable-set. Then $D.run calls $C.drop-while-waiting which attempts +;; to drop the same waitable-set, which should trap. +(component + (component $C + (core module $Core + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.drop" (func $waitable-set.drop (param i32))) + + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + (func $wait-on-set (export "wait-on-set") (result i32) + ;; wait on $ws + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) + ) + (func $drop-while-waiting (export "drop-while-waiting") (result i32) + ;; boom + (call $waitable-set.drop (global.get $ws)) + unreachable + ) + (func $unreachable-cb (export "unreachable-cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.drop (core func $waitable-set.drop)) + (core instance $core (instantiate $Core (with "" (instance + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.drop" (func $waitable-set.drop)) + )))) + (func (export "wait-on-set") async (canon lift + (core func $core "wait-on-set") + async (callback (func $core "unreachable-cb")) + )) + (func (export "drop-while-waiting") async (canon lift + (core func $core "drop-while-waiting") + async (callback (func $core "unreachable-cb")) + )) + ) + + (component $D + (import "c" (instance $c + (export "wait-on-set" (func async)) + (export "drop-while-waiting" (func async)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "wait-on-set" (func $wait-on-set (result i32))) + (import "" "drop-while-waiting" (func $drop-while-waiting)) + (func $run (export "run") (result i32) + (local $ret i32) + + ;; start an async call to 'wait-on-set' which blocks, waiting on a + ;; waitable-set. + (local.set $ret (call $wait-on-set)) + (if (i32.ne (i32.const 0x11) (local.get $ret)) + (then unreachable)) + + ;; this call will try to drop the same waitable-set, which should trap. + (call $drop-while-waiting) + unreachable + ) + ) + (canon lower (func $c "wait-on-set") async (memory $memory "mem") (core func $wait-on-set')) + (canon lower (func $c "drop-while-waiting") (core func $drop-while-waiting')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "wait-on-set" (func $wait-on-set')) + (export "drop-while-waiting" (func $drop-while-waiting')) + )))) + (func (export "run") async (result u32) (canon lift (core func $core "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "run") (alias export $d "run")) +) +(assert_trap (invoke "run") "cannot drop waitable set with waiters") diff --git a/parser/src/test/resources/spec-tests/async/empty-wait.wast b/parser/src/test/resources/spec-tests/async/empty-wait.wast new file mode 100644 index 0000000..8b4d789 --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/empty-wait.wast @@ -0,0 +1,199 @@ +;; This test has two components $C and $D, where $D imports and calls $C +;; $C exports two functions: 'blocker' and 'unblocker' +;; 'blocker' blocks on an empty waitable set +;; 'unblocker' wakes blocker by adding a resolved future to blocker's waitable set +;; $D calls 'blocker' then 'unblocker', then waits for 'blocker' to finish +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "future.drop-readable" (func $future.drop-readable (param i32))) + (import "" "future.drop-writable" (func $future.drop-writable (param i32))) + + ;; $ws is waited on by 'blocker' and added to by 'unblocker' + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + ;; 'unblocker' initializes $futr with the readable end of a resolved future + (global $futr (mut i32) (i32.const 0)) + + (func $blocker (export "blocker") (result i32) + ;; wait on $ws which is currently empty; 'unblocker' will wake us up + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) + ) + (func $blocker_cb (export "blocker_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + ;; assert that we were in fact woken by 'unblocker' adding $futr to $ws + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (global.get $futr) (local.get $index)) + (then unreachable)) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $payload)) + (then unreachable)) + + (call $future.drop-readable (global.get $futr)) + + ;; return 42 to $D.run + (call $task.return (i32.const 42)) + (i32.const 0) + ) + + (func $unblocker (export "unblocker") (result i32) + (local $ret i32) (local $ret64 i64) + (local $futw i32) + + ;; create a future that will be used to unblock 'blocker', storing r/w ends in $futr/$futw + (local.set $ret64 (call $future.new)) + (global.set $futr (i32.wrap_i64 (local.get $ret64))) + (if (i32.ne (i32.const 2) (global.get $futr)) + (then unreachable)) + (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (if (i32.ne (i32.const 3) (local.get $futw)) + (then unreachable)) + + ;; perform a future.read which will block, and add this future to the waitable-set + ;; being waited on by 'blocker' + (local.set $ret (call $future.read (global.get $futr) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (global.get $futr) (global.get $ws)) + + ;; perform a future.write which will rendezvous with the write and complete + (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + (call $future.drop-writable (local.get $futw)) + + ;; return 43 to $D.run + (call $task.return (i32.const 43)) + (i32.const 0) + ) + (func $unblocker_cb (export "unblocker_cb") (param i32 i32 i32) (result i32) + ;; 'unblocker' doesn't block + unreachable + ) + ) + (type $FT (future)) + (canon task.return (result u32) (core func $task.return)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon future.new $FT (core func $future.new)) + (canon future.read $FT async (core func $future.read)) + (canon future.write $FT async (core func $future.write)) + (canon future.drop-readable $FT (core func $future.drop-readable)) + (canon future.drop-writable $FT (core func $future.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "future.new" (func $future.new)) + (export "future.read" (func $future.read)) + (export "future.write" (func $future.write)) + (export "future.drop-readable" (func $future.drop-readable)) + (export "future.drop-writable" (func $future.drop-writable)) + )))) + (func (export "blocker") async (result u32) (canon lift + (core func $cm "blocker") + async (callback (func $cm "blocker_cb")) + )) + (func (export "unblocker") async (result u32) (canon lift + (core func $cm "unblocker") + async (callback (func $cm "unblocker_cb")) + )) + ) + + (component $D + (import "c" (instance $c + (export "blocker" (func async (result u32))) + (export "unblocker" (func async (result u32))) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "subtask.drop" (func $subtask.drop (param i32))) + (import "" "blocker" (func $blocker (param i32) (result i32))) + (import "" "unblocker" (func $unblocker (param i32) (result i32))) + + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + (func $run (export "run") (result i32) + (local $ret i32) (local $retp1 i32) (local $retp2 i32) + (local $subtask i32) + (local $event_code i32) + + ;; call 'blocker'; it should block + (local.set $retp1 (i32.const 4)) + (local.set $ret (call $blocker (local.get $retp1))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (if (i32.ne (i32.const 2) (local.get $subtask)) + (then unreachable)) + + ;; call 'unblocker' to unblock 'blocker'; it should complete eagerly + (local.set $retp2 (i32.const 8)) + (local.set $ret (call $unblocker (local.get $retp2))) + (if (i32.ne (i32.const 2 (; RETURNED ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 43) (i32.load (local.get $retp2))) + (then unreachable)) + + ;; wait for 'blocker' to be scheduled, run, and return + (call $waitable.join (local.get $subtask) (global.get $ws)) + (local.set $retp2 (i32.const 8)) + (local.set $event_code (call $waitable-set.wait (global.get $ws) (local.get $retp2))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load (local.get $retp1))) + (then unreachable)) + + (call $subtask.drop (local.get $subtask)) + + ;; return 44 to the top-level test harness + (i32.const 44) + ) + ) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon subtask.drop (core func $subtask.drop)) + (canon lower (func $c "blocker") async (memory $memory "mem") (core func $blocker')) + (canon lower (func $c "unblocker") async (memory $memory "mem") (core func $unblocker')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "subtask.drop" (func $subtask.drop)) + (export "blocker" (func $blocker')) + (export "unblocker" (func $unblocker')) + )))) + (func (export "run") async (result u32) (canon lift (core func $dm "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "run") (alias export $d "run")) +) +(assert_return (invoke "run") (u32.const 44)) diff --git a/parser/src/test/resources/spec-tests/async/futures-must-write.wast b/parser/src/test/resources/spec-tests/async/futures-must-write.wast new file mode 100644 index 0000000..ce2446b --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/futures-must-write.wast @@ -0,0 +1,118 @@ +;; This test contains two components $C and $D that test that a trap occurs +;; when closing the writable end of a future (in $C) before having written +;; a value while closing the readable end of a future (in $D) before reading +;; a value is fine. +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "future.drop-writable" (func $future.drop-writable (param i32))) + + (global $fw (mut i32) (i32.const 0)) + + (func $start-future (export "start-future") (result i32) + ;; create a new future, return the readable end to the caller + (local $ret64 i64) + (local.set $ret64 (call $future.new)) + (global.set $fw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (i32.wrap_i64 (local.get $ret64)) + ) + (func $attempt-write (export "attempt-write") (result i32) + ;; because the caller already dropped the readable end, this write will eagerly + ;; return DROPPED having written no values. + (local $ret i32) + (local.set $ret (call $future.write (global.get $fw) (i32.const 42))) + (if (i32.ne (i32.const 0x01 (; DROPPED ;)) (local.get $ret)) + (then unreachable)) + + ;; return without trapping + (i32.const 42) + ) + (func $drop-writable (export "drop-writable") + ;; maybe boom + (call $future.drop-writable (global.get $fw)) + ) + ) + (type $FT (future u8)) + (canon future.new $FT (core func $future.new)) + (canon future.write $FT async (memory $memory "mem") (core func $future.write)) + (canon future.drop-writable $FT (core func $future.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "future.new" (func $future.new)) + (export "future.write" (func $future.write)) + (export "future.drop-writable" (func $future.drop-writable)) + )))) + (func (export "start-future") (result (future u8)) (canon lift (core func $cm "start-future"))) + (func (export "attempt-write") (result u32) (canon lift (core func $cm "attempt-write"))) + (func (export "drop-writable") (canon lift (core func $cm "drop-writable"))) + ) + (component $D + (import "c" (instance $c + (export "start-future" (func (result (future u8)))) + (export "attempt-write" (func (result u32))) + (export "drop-writable" (func)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "future.drop-readable" (func $future.drop-readable (param i32))) + (import "" "start-future" (func $start-future (result i32))) + (import "" "attempt-write" (func $attempt-write (result i32))) + (import "" "drop-writable" (func $drop-writable)) + + (func $drop-readable-future-before-read (export "drop-readable-future-before-read") (result i32) + ;; call 'start-future' to get the future we'll be working with + (local $fr i32) + (local.set $fr (call $start-future)) + (if (i32.ne (i32.const 1) (local.get $fr)) + (then unreachable)) + + ;; ok to immediately drop the readable end + (call $future.drop-readable (local.get $fr)) + + ;; the callee will see that we dropped the readable end when it tries to write + (call $attempt-write) + ) + (func $drop-writable-future-before-write (export "drop-writable-future-before-write") + ;; call 'start-future' to get the future we'll be working with + (local $fr i32) + (local.set $fr (call $start-future)) + (if (i32.ne (i32.const 1) (local.get $fr)) + (then unreachable)) + + ;; boom + (call $drop-writable) + ) + ) + (type $FT (future u8)) + (canon future.new $FT (core func $future.new)) + (canon future.drop-readable $FT (core func $future.drop-readable)) + (canon lower (func $c "start-future") (core func $start-future')) + (canon lower (func $c "attempt-write") (core func $attempt-write')) + (canon lower (func $c "drop-writable") (core func $drop-writable')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "future.new" (func $future.new)) + (export "future.drop-readable" (func $future.drop-readable)) + (export "start-future" (func $start-future')) + (export "attempt-write" (func $attempt-write')) + (export "drop-writable" (func $drop-writable')) + )))) + (func (export "drop-readable-future-before-read") (result u32) (canon lift (core func $core "drop-readable-future-before-read"))) + (func (export "drop-writable-future-before-write") (canon lift (core func $core "drop-writable-future-before-write"))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "drop-writable-future-before-write") (alias export $d "drop-writable-future-before-write")) + (func (export "drop-readable-future-before-read") (alias export $d "drop-readable-future-before-read")) +) + +(assert_return (invoke "drop-readable-future-before-read") (u32.const 42)) +(assert_trap (invoke "drop-writable-future-before-write") "cannot drop future write end without first writing a value") diff --git a/parser/src/test/resources/spec-tests/async/partial-stream-copies.wast b/parser/src/test/resources/spec-tests/async/partial-stream-copies.wast new file mode 100644 index 0000000..d70ece2 --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/partial-stream-copies.wast @@ -0,0 +1,238 @@ +;; This test has two components $C and $D, where $D imports and calls $C.transform +;; $C.transform takes and returns a stream +;; Before $C.transform blocks the first time, it supplies a 12-byte read buffer +;; When $D.run regains control after $C.transform blocks, it can perform multiple +;; successful writes until it fully uses up the 12-byte buffer. +;; ... and that's where I am so far ... +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + ;; $ws is waited on by 'transform' + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + ;; $insr/$outsw are read/written by 'transform' + (global $insr (mut i32) (i32.const 0)) + (global $inbufp (mut i32) (i32.const 0x10)) + (global $outsw (mut i32) (i32.const 0)) + (global $outbufp (mut i32) (i32.const 0x20)) + + (func $transform (export "transform") (param i32) (result i32) + (local $ret i32) (local $ret64 i64) (local $outsr i32) + + ;; check the incoming readable stream end + (global.set $insr (local.get 0)) + (if (i32.ne (i32.const 2) (global.get $insr)) + (then unreachable)) + + ;; create a new stream r/w pair $outsr/$outsw + (local.set $ret64 (call $stream.new)) + (local.set $outsr (i32.wrap_i64 (local.get $ret64))) + (if (i32.ne (i32.const 3) (local.get $outsr)) + (then unreachable)) + (global.set $outsw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (if (i32.ne (i32.const 4) (global.get $outsw)) + (then unreachable)) + + ;; start async read on $insr which will block + (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 12))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; return the readable end of the outgoing stream to the caller + (call $task.return (local.get $outsr)) + + ;; wait for the stream.read/write to complete + (call $waitable.join (global.get $insr) (global.get $ws)) + (call $waitable.join (global.get $outsw) (global.get $ws)) + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) + ) + (func $transform_cb (export "transform_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + (local $ret i32) (local $ret64 i64) + + ;; confirm the read succeeded fully + (if (i32.ne (local.get $event_code) (i32.const 2 (; STREAM_READ ;))) + (then unreachable)) + (if (i32.ne (local.get $index) (global.get $insr)) + (then unreachable)) + (if (i32.ne (local.get $payload) (i32.const 0xc0 (; COMPLETED=0 | (12 << 4) ;))) + (then unreachable)) + (if (i32.ne (i32.const 0x89abcdef) (i32.load offset=0 (global.get $inbufp))) + (then unreachable)) + (if (i32.ne (i32.const 0x01234567) (i32.load offset=4 (global.get $inbufp))) + (then unreachable)) + (if (i32.ne (i32.const 0x89abcdef) (i32.load offset=8 (global.get $inbufp))) + (then unreachable)) + + ;; multiple read calls succeed until 12-byte buffer is consumed + (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 4))) + (if (i32.ne (i32.const 0x40) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0x76543210) (i32.load (global.get $inbufp))) + (then unreachable)) + (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 2))) + (if (i32.ne (i32.const 0x20) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0xba98) (i32.load16_u (global.get $inbufp))) + (then unreachable)) + (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 8))) + (if (i32.ne (i32.const 0x60) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0x3210fedc) (i32.load (global.get $inbufp))) + (then unreachable)) + (if (i32.ne (i32.const 0x7654) (i32.load16_u offset=4 (global.get $inbufp))) + (then unreachable)) + + (call $stream.drop-readable (global.get $insr)) + (call $stream.drop-writable (global.get $outsw)) + (return (i32.const 0 (; EXIT ;))) + ) + ) + (type $ST (stream u8)) + (canon task.return (result $ST) (memory $memory "mem") (core func $task.return)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (func (export "transform") async (param "in" (stream u8)) (result (stream u8)) (canon lift + (core func $cm "transform") + async (memory $memory "mem") (callback (func $cm "transform_cb")) + )) + ) + + (component $D + (import "transform" (func $transform async (param "in" (stream u8)) (result (stream u8)))) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + (import "" "transform" (func $transform (param i32 i32) (result i32))) + + (func $run (export "run") (result i32) + (local $ret i32) (local $ret64 i64) (local $retp i32) + (local $insr i32) (local $insw i32) (local $outsr i32) + (local $subtask i32) (local $event_code i32) (local $index i32) (local $payload i32) + (local $ws i32) + + ;; create a new stream r/w pair $insr/$insw + (local.set $ret64 (call $stream.new)) + (local.set $insr (i32.wrap_i64 (local.get $ret64))) + (if (i32.ne (i32.const 1) (local.get $insr)) + (then unreachable)) + (local.set $insw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (if (i32.ne (i32.const 2) (local.get $insw)) + (then unreachable)) + + ;; call 'transform' which will return a readable stream $outsr eagerly + (local.set $retp (i32.const 8)) + (local.set $ret (call $transform (local.get $insr) (local.get $retp))) + (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (local.get $ret)) + (then unreachable)) + (local.set $outsr (i32.load (local.get $retp))) + (if (i32.ne (i32.const 1) (local.get $outsr)) + (then unreachable)) + + ;; multiple write calls succeed until 12-byte buffer is filled + (i64.store (i32.const 16) (i64.const 0x0123456789abcdef)) + (local.set $ret (call $stream.write (local.get $insw) (i32.const 16) (i32.const 8))) + (if (i32.ne (i32.const 0x80) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $stream.write (local.get $insw) (i32.const 16) (i32.const 8))) + (if (i32.ne (i32.const 0x40) (local.get $ret)) + (then unreachable)) + + ;; start a blocking write with a 12-byte buffer + (i64.store (i32.const 16) (i64.const 0xfedcba9876543210)) + (i32.store (i32.const 24) (i32.const 0x76543210)) + (local.set $ret (call $stream.write (local.get $insw) (i32.const 16) (i32.const 12))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; wait for transform to read our write and drop all the streams + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $insw) (local.get $ws)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (i32.const 0))) + (local.set $index (i32.load (i32.const 0))) + (local.set $payload (i32.load (i32.const 4))) + + ;; confirm the write and the dropped stream + (if (i32.ne (local.get $event_code) (i32.const 3 (; STREAM_WRITE ;))) + (then unreachable)) + (if (i32.ne (local.get $index) (local.get $insw)) + (then unreachable)) + (if (i32.ne (local.get $payload) (i32.const 0xc1 (; DROPPED=1 | (12 << 4) ;))) + (then unreachable)) + + (call $stream.drop-writable (local.get $insw)) + (call $stream.drop-readable (local.get $outsr)) + + ;; return 42 to the top-level test harness + (i32.const 42) + ) + ) + (type $ST (stream u8)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (canon lower (func $transform) async (memory $memory "mem") (core func $transform')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "stream.drop-writable" (func $stream.drop-writable)) + (export "transform" (func $transform')) + )))) + (func (export "run") async (result u32) (canon lift (core func $dm "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "transform" (func $c "transform")))) + (func (export "run") (alias export $d "run")) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/async/passing-resources.wast b/parser/src/test/resources/spec-tests/async/passing-resources.wast new file mode 100644 index 0000000..d8a7c50 --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/passing-resources.wast @@ -0,0 +1,176 @@ +;; This test contains two components, $Producer and $Consumer. +;; $Producer.run drives the test and calls $Producer.start-stream to create +;; a stream and attempt to write 2 owned handles. $Producer.run then reads +;; just 1 element. The test finishes by confirming that $Consumer owns the +;; first resource, $Producer (still) owns the second resource, and $Producer +;; traps if it attempts to access the index of the first resource. +(component + (component $Producer + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "resource.new" (func $resource.new (param i32) (result i32))) + (import "" "resource.rep" (func $resource.rep (param i32) (result i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + (global $ws (mut i32) (i32.const 0)) + (global $res1 (mut i32) (i32.const 0)) + (global $res2 (mut i32) (i32.const 0)) + + (func $start-stream (export "start-stream") (result i32) + (local $ret i32) (local $ret64 i64) + (local $rs i32) + + ;; create a new stream, return the readable end to the caller + (local.set $ret64 (call $stream.new)) + (global.set $ws (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $rs (i32.wrap_i64 (local.get $ret64))) + + ;; create two resources and write them into a buffer to pass to stream.write + (global.set $res1 (call $resource.new (i32.const 50))) + (global.set $res2 (call $resource.new (i32.const 51))) + (i32.store (i32.const 8) (global.get $res1)) + (i32.store (i32.const 12) (global.get $res2)) + + ;; start a write which will block + (local.set $ret (call $stream.write (global.get $ws) (i32.const 8) (i32.const 2))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; check that this instance still owns both resources (ownership has not + ;; yet been transferred). + (if (i32.ne (i32.const 50) (call $resource.rep (global.get $res1))) + (then unreachable)) + (if (i32.ne (i32.const 51) (call $resource.rep (global.get $res2))) + (then unreachable)) + + (local.get $rs) + ) + (func $cancel-write (export "cancel-write") + (local $ret i32) + + ;; cancel the write, confirming that the first element was transferred + (local.set $ret (call $stream.cancel-write (global.get $ws))) + (if (i32.ne (i32.const 0x11 (; DROPPED=1 | (1 << 4) ;)) (local.get $ret)) + (then unreachable)) + + ;; we still own $res2 + (if (i32.ne (i32.const 51) (call $resource.rep (global.get $res2))) + (then unreachable)) + + (call $stream.drop-writable (global.get $ws)) + ) + (func $R.foo (export "R.foo") (param $rep i32) (result i32) + (i32.add (local.get $rep) (i32.const 50)) + ) + (func $fail-accessing-res1 (export "fail-accessing-res1") + ;; boom + (call $resource.rep (global.get $res1)) + unreachable + ) + ) + (type $R (resource (rep i32))) + (type $ST (stream (own $R))) + (canon resource.new $R (core func $resource.new)) + (canon resource.rep $R (core func $resource.rep)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.cancel-write $ST (core func $stream.cancel-write)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "resource.new" (func $resource.new)) + (export "resource.rep" (func $resource.rep)) + (export "stream.new" (func $stream.new)) + (export "stream.write" (func $stream.write)) + (export "stream.cancel-write" (func $stream.cancel-write)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (export $R' "R" (type $R)) + (func (export "[method]R.foo") async (param "self" (borrow $R')) (result u32) (canon lift (core func $core "R.foo"))) + (func (export "start-stream") async (result (stream (own $R'))) (canon lift (core func $core "start-stream"))) + (func (export "cancel-write") async (canon lift (core func $core "cancel-write"))) + (func (export "fail-accessing-res1") async (canon lift (core func $core "fail-accessing-res1"))) + ) + + (component $Consumer + (import "producer" (instance $producer + (export "R" (type $R (sub resource))) + (export "[method]R.foo" (func async (param "self" (borrow $R)) (result u32))) + (export "start-stream" (func async (result (stream (own $R))))) + (export "cancel-write" (func async)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "R.foo" (func $R.foo (param i32) (result i32))) + (import "" "start-stream" (func $start-stream (result i32))) + (import "" "cancel-write" (func $cancel-write)) + + (func $run (export "run") (result i32) + (local $ret i32) (local $rs i32) + (local $res1 i32) + + ;; get the readable end of a stream which has a pending write + (local.set $rs (call $start-stream)) + (if (i32.ne (local.get $rs) (i32.const 1)) + (then unreachable)) + + ;; read only 1 (of the 2 pending) elements, which won't block + (i64.store (i32.const 8) (i64.const 0xdeadbeefdeadbeef)) + (local.set $ret (call $stream.read (local.get $rs) (i32.const 8) (i32.const 1))) + (if (i32.ne (i32.const 0x10) (local.get $ret)) + (then unreachable)) + + ;; only 1 handle should have been transferred + (local.set $res1 (i32.load (i32.const 8))) + (if (i32.ne (i32.load (i32.const 12)) (i32.const 0xdeadbeef)) + (then unreachable)) + + ;; check that we got the first resource and it works + (local.set $ret (call $R.foo (local.get $res1))) + (if (i32.ne (i32.const 100) (local.get $ret)) + (then unreachable)) + + ;; drop the stream and then let $C run and assert stuff + (call $stream.drop-readable (local.get $rs)) + (call $cancel-write) + + (i32.const 42) + ) + ) + (alias export $producer "R" (type $R)) + (type $ST (stream (own $R))) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon lower (func $producer "[method]R.foo") (core func $R.foo')) + (canon lower (func $producer "start-stream") (core func $start-stream')) + (canon lower (func $producer "cancel-write") (core func $cancel-write')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "stream.read" (func $stream.read)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "R.foo" (func $R.foo')) + (export "start-stream" (func $start-stream')) + (export "cancel-write" (func $cancel-write')) + )))) + (func (export "run") async (result u32) (canon lift + (core func $core "run") + )) + ) + + (instance $producer (instantiate $Producer)) + (instance $consumer (instantiate $Consumer (with "producer" (instance $producer)))) + (func (export "run") (alias export $consumer "run")) + (func (export "fail-accessing-res1") (alias export $producer "fail-accessing-res1")) +) +(assert_return (invoke "run") (u32.const 42)) +(assert_trap (invoke "fail-accessing-res1") "unknown handle index 3") diff --git a/parser/src/test/resources/spec-tests/async/same-component-stream-future.wast b/parser/src/test/resources/spec-tests/async/same-component-stream-future.wast new file mode 100644 index 0000000..18d4a14 --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/same-component-stream-future.wast @@ -0,0 +1,259 @@ +;; This test tests same-component reading/writing of a stream and future +;; from the same component instance (which either traps or succeeds), +;; depending on the element type. + +(component definition $Tester + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $M + (import "" "mem" (memory 1)) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "future.newb" (func $future.newb (result i64))) + (import "" "future.readb" (func $future.readb (param i32 i32) (result i32))) + (import "" "future.writeb" (func $future.writeb (param i32 i32) (result i32))) + (import "" "stream.newb" (func $stream.newb (result i64))) + (import "" "stream.readb" (func $stream.readb (param i32 i32 i32) (result i32))) + (import "" "stream.writeb" (func $stream.writeb (param i32 i32 i32) (result i32))) + (import "" "future.newc" (func $future.newc (result i64))) + (import "" "future.readc" (func $future.readc (param i32 i32) (result i32))) + (import "" "future.writec" (func $future.writec (param i32 i32) (result i32))) + + (func (export "test-empty") (result i32) + (local $ret i32) (local $ret64 i64) + (local $rx i32) (local $tx i32) + + ;; test future reader then writer + (local.set $ret64 (call $future.new)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $future.read (local.get $rx) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $future.write (local.get $tx) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + ;; test future writer than reader + (local.set $ret64 (call $future.new)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $future.write (local.get $tx) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $future.read (local.get $rx) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + ;; test stream reader then writer + (local.set $ret64 (call $stream.new)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $stream.read (local.get $rx) (i32.const 0xdeadbeef) (i32.const 1))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $stream.write (local.get $tx) (i32.const 0xdeadbeef) (i32.const 1))) + (if (i32.ne (i32.const 0x10 (; COMPLETED=0 | (1<<4) ;)) (local.get $ret)) + (then unreachable)) + + ;; test stream writer than reader + (local.set $ret64 (call $stream.new)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $stream.write (local.get $tx) (i32.const 0xdeadbeef) (i32.const 1))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $stream.read (local.get $rx) (i32.const 0xdeadbeef) (i32.const 1))) + (if (i32.ne (i32.const 0x10 (; COMPLETED=0 | (1<<4) ;)) (local.get $ret)) + (then unreachable)) + + (i32.const 42) + ) + + (func $test-stream (param $srcp i32) (param $dstp i32) + (local $ret i32) (local $ret64 i64) + (local $rx i32) (local $tx i32) + + ;; test stream reader then writer + (i64.store (local.get $dstp) (i64.const 0)) + (i64.store (local.get $srcp) (i64.const 0x0123456789abcdef)) + (local.set $ret64 (call $stream.newb)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $stream.readb (local.get $rx) (local.get $dstp) (i32.const 8))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $stream.writeb (local.get $tx) (local.get $srcp) (i32.const 8))) + (if (i32.ne (i32.const 0x80 (; COMPLETED=0 | (8<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i64.ne (i64.load (local.get $dstp)) (i64.const 0x0123456789abcdef)) + (then unreachable)) + + ;; test stream writer than reader + (i64.store (local.get $dstp) (i64.const 0)) + (i64.store (local.get $srcp) (i64.const 0x0123456789abcdef)) + (local.set $ret64 (call $stream.newb)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $stream.writeb (local.get $tx) (local.get $srcp) (i32.const 8))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $stream.readb (local.get $rx) (local.get $dstp) (i32.const 8))) + (if (i32.ne (i32.const 0x80 (; COMPLETED=0 | (8<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i64.ne (i64.load (local.get $dstp)) (i64.const 0x0123456789abcdef)) + (then unreachable)) + ) + + (func (export "test-bytes") (result i32) + (local $ret i32) (local $ret64 i64) + (local $rx i32) (local $tx i32) + (local $dstp i32) (local $srcp i32) + + ;; because pointers must be aligned and futures are single-element, + ;; it's not possible to test the interesting overlap case + (local.set $srcp (i32.const 16)) + (local.set $dstp (i32.const 17)) + (i32.store8 (local.get $dstp) (i32.const 0)) + (i32.store8 (local.get $srcp) (i32.const 42)) + + ;; test future reader then writer + (local.set $ret64 (call $future.newb)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $future.readb (local.get $rx) (local.get $dstp))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $future.writeb (local.get $tx) (local.get $srcp))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.load8_u (local.get $dstp)) (i32.const 42)) + (then unreachable)) + + ;; reset memory and then test future writer than reader + (i32.store8 (local.get $dstp) (i32.const 0)) + (i32.store8 (local.get $srcp) (i32.const 42)) + (local.set $ret64 (call $future.newb)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $future.writeb (local.get $tx) (local.get $srcp))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $future.readb (local.get $rx) (local.get $dstp))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.load8_u (local.get $dstp)) (i32.const 42)) + (then unreachable)) + + ;; test a bunch of different overlapping cases + (call $test-stream (i32.const 16) (i32.const 8)) + (call $test-stream (i32.const 16) (i32.const 9)) + (call $test-stream (i32.const 16) (i32.const 10)) + (call $test-stream (i32.const 16) (i32.const 11)) + (call $test-stream (i32.const 16) (i32.const 12)) + (call $test-stream (i32.const 16) (i32.const 13)) + (call $test-stream (i32.const 16) (i32.const 14)) + (call $test-stream (i32.const 16) (i32.const 15)) + (call $test-stream (i32.const 16) (i32.const 16)) + (call $test-stream (i32.const 16) (i32.const 17)) + (call $test-stream (i32.const 16) (i32.const 18)) + (call $test-stream (i32.const 16) (i32.const 19)) + (call $test-stream (i32.const 16) (i32.const 20)) + (call $test-stream (i32.const 16) (i32.const 21)) + (call $test-stream (i32.const 16) (i32.const 22)) + (call $test-stream (i32.const 16) (i32.const 23)) + (call $test-stream (i32.const 16) (i32.const 24)) + + (i32.const 43) + ) + + (func (export "test-no-read-char") + (local $ret i32) (local $ret64 i64) + (local $rx i32) (local $tx i32) + (local.set $ret64 (call $future.newc)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $future.readc (local.get $rx) (i32.const 0))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (call $future.writec (local.get $tx) (i32.const 0)) + unreachable + ) + + (func (export "test-no-write-char") + (local $ret i32) (local $ret64 i64) + (local $rx i32) (local $tx i32) + (local.set $ret64 (call $future.newc)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $future.writec (local.get $tx) (i32.const 0))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (call $future.readc (local.get $rx) (i32.const 0)) + unreachable + ) + ) + (type $FT (future)) + (type $ST (stream)) + (type $FTB (future u8)) + (type $STB (stream u8)) + (type $FTC (future char)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon future.new $FT (core func $future.new)) + (canon future.read $FT async (core func $future.read)) + (canon future.write $FT async (core func $future.write)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST async (core func $stream.read)) + (canon stream.write $ST async (core func $stream.write)) + (canon future.new $FTB (core func $future.newb)) + (canon future.read $FTB async (memory $memory "mem") (core func $future.readb)) + (canon future.write $FTB async (memory $memory "mem") (core func $future.writeb)) + (canon stream.new $STB (core func $stream.newb)) + (canon stream.read $STB async (memory $memory "mem") (core func $stream.readb)) + (canon stream.write $STB async (memory $memory "mem") (core func $stream.writeb)) + (canon future.new $FTC (core func $future.newc)) + (canon future.read $FTC async (memory $memory "mem") (core func $future.readc)) + (canon future.write $FTC async (memory $memory "mem") (core func $future.writec)) + (core instance $m (instantiate $M (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "future.new" (func $future.new)) + (export "future.read" (func $future.read)) + (export "future.write" (func $future.write)) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "future.newb" (func $future.newb)) + (export "future.readb" (func $future.readb)) + (export "future.writeb" (func $future.writeb)) + (export "stream.newb" (func $stream.newb)) + (export "stream.readb" (func $stream.readb)) + (export "stream.writeb" (func $stream.writeb)) + (export "future.newc" (func $future.newc)) + (export "future.readc" (func $future.readc)) + (export "future.writec" (func $future.writec)) + )))) + (func (export "test-empty") (result u32) (canon lift (core func $m "test-empty"))) + (func (export "test-bytes") (result u32) (canon lift (core func $m "test-bytes"))) + (func (export "test-no-read-char") (canon lift (core func $m "test-no-read-char"))) + (func (export "test-no-write-char") (canon lift (core func $m "test-no-write-char"))) +) +(component instance $i $Tester) +(assert_return (invoke "test-empty") (u32.const 42)) +(component instance $i $Tester) +(assert_return (invoke "test-bytes") (u32.const 43)) +(component instance $i $Tester) +(assert_trap (invoke "test-no-read-char") "cannot read from and write to intra-component future") +(component instance $i $Tester) +(assert_trap (invoke "test-no-write-char") "cannot read from and write to intra-component future") diff --git a/parser/src/test/resources/spec-tests/async/sync-barges-in.wast b/parser/src/test/resources/spec-tests/async/sync-barges-in.wast new file mode 100644 index 0000000..3161f93 --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/sync-barges-in.wast @@ -0,0 +1,311 @@ +;; This test tests that a blocked previous sync- or async-lifted callee +;; can be synchronously reentered by a sync-typed function without the +;; usual backpressure triggering. The $Tester component has two nested +;; components $C and $D, where $D imports and calls $C. $C contains utilities +;; used by $D to perform all the tests. +(component definition $Tester + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "thread.yield" (func $thread.yield (result i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + + (global $unblock-value (mut i32) (i32.const 0)) + + ;; $ws is waited on by 'blocker' and added to by 'unblocker' + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + (func (export "blocker") + ;; wait on $ws, which is initially empty, but will be populated with + ;; a completed future when "unblocker" synchronously barges in. + (local $ret i32) + (local.set $ret (call $waitable-set.wait (global.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (i32.load (i32.const 4))) + (then unreachable)) + + (call $task.return (global.get $unblock-value)) + ) + + (func (export "blocker-cb") (result i32) + ;; wait on $ws, which is initially empty, but will be populated with + ;; a completed future when "unblocker" synchronously barges in. + (i32.or + (i32.const 2 (; WAIT ;)) + (i32.shl (global.get $ws) (i32.const 4))) + ) + (func (export "blocker-cb-cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $payload)) + (then unreachable)) + + (call $task.return (global.get $unblock-value)) + (i32.const 0 (; EXIT ;)) + ) + + (func $unblocker (export "unblocker") (param $val i32) + (local $ret i32) (local $ret64 i64) + (local $futr i32) (local $futw i32) + + ;; create read/write futures that will be used to unblock 'blocker' + (local.set $ret64 (call $future.new)) + (local.set $futr (i32.wrap_i64 (local.get $ret64))) + (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + + ;; perform a future.read which will block, and add this future to the waitable-set + ;; being waited on by 'blocker' + (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (local.get $futr) (global.get $ws)) + + ;; perform a future.write which will rendezvous with the write and complete + (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + (global.set $unblock-value (local.get $val)) + ) + + (func (export "yielder") + (drop (call $thread.yield)) + (call $task.return (global.get $unblock-value)) + ) + (func (export "yielder-cb") (result i32) + (i32.const 1 (; YIELD ;)) + ) + (func (export "yielder-cb-cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + (if (i32.ne (i32.const 0 (; EVENT_NONE ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (i32.const 0) (local.get $index)) + (then unreachable)) + (if (i32.ne (i32.const 0) (local.get $payload)) + (then unreachable)) + (call $task.return (global.get $unblock-value)) + (i32.const 0 (; EXIT ;)) + ) + (func (export "poker") (param $val i32) + (global.set $unblock-value (local.get $val)) + ) + ) + (type $FT (future)) + (canon task.return (result u32) (core func $task.return)) + (canon thread.yield (core func $thread.yield)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon future.new $FT (core func $future.new)) + (canon future.read $FT async (core func $future.read)) + (canon future.write $FT async (core func $future.write)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "thread.yield" (func $thread.yield)) + (export "task.return" (func $task.return)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "future.new" (func $future.new)) + (export "future.read" (func $future.read)) + (export "future.write" (func $future.write)) + )))) + (type $R (resource (rep i32) (dtor (func $cm "unblocker")))) + (type $S (resource (rep i32) (dtor (func $cm "poker")))) + (canon resource.new $R (core func $new-R)) + (canon resource.new $S (core func $new-S)) + (export $R' "R" (type $R)) + (export $S' "S" (type $S)) + (func (export "new-R") (param "rep" u32) (result (own $R')) (canon lift (core func $new-R))) + (func (export "blocker") async (result u32) (canon lift (core func $cm "blocker") async)) + (func (export "blocker-cb") async (result u32) (canon lift (core func $cm "blocker-cb") async (callback (func $cm "blocker-cb-cb")))) + (func (export "unblocker") (param "val" u32) (canon lift (core func $cm "unblocker"))) + (func (export "new-S") (param "rep" u32) (result (own $S')) (canon lift (core func $new-S))) + (func (export "yielder") async (result u32) (canon lift (core func $cm "yielder") async)) + (func (export "yielder-cb") async (result u32) (canon lift (core func $cm "yielder-cb") async (callback (func $cm "yielder-cb-cb")))) + (func (export "poker") (param "val" u32) (canon lift (core func $cm "poker"))) + ) + (component $D + (import "c" (instance $c + (export "R" (type $R (sub resource))) + (export "new-R" (func (param "rep" u32) (result (own $R)))) + (export "blocker" (func async (result u32))) + (export "blocker-cb" (func async (result u32))) + (export "unblocker" (func (param "val" u32))) + (export "S" (type $S (sub resource))) + (export "new-S" (func (param "rep" u32) (result (own $S)))) + (export "yielder" (func async (result u32))) + (export "yielder-cb" (func async (result u32))) + (export "poker" (func (param "val" u32))) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "subtask.drop" (func $subtask.drop (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.drop" (func $waitable-set.drop (param i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "waitable-set.poll" (func $waitable-set.poll (param i32 i32) (result i32))) + (import "" "new-R" (func $new-R (param i32) (result i32))) + (import "" "drop-R" (func $drop-R (param i32))) + (import "" "blocker" (func $blocker (param i32) (result i32))) + (import "" "blocker-cb" (func $blocker-cb (param i32) (result i32))) + (import "" "unblocker" (func $unblocker (param i32))) + (import "" "new-S" (func $new-S (param i32) (result i32))) + (import "" "drop-S" (func $drop-S (param i32))) + (import "" "yielder" (func $yielder (param i32) (result i32))) + (import "" "yielder-cb" (func $yielder-cb (param i32) (result i32))) + (import "" "poker" (func $poker (param i32))) + + (func $wait-for-return (param $subtask i32) (param $retp i32) (param $expect i32) + (local $outp i32) + (local $ws i32) (local $event_code i32) + + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtask) (local.get $ws)) + (local.set $outp (i32.const 32)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $outp))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (local.get $outp))) + (then unreachable)) + (if (i32.ne (i32.const 2 (; RETURNED=2 ;)) (i32.load offset=4 (local.get $outp))) + (then unreachable)) + (if (i32.ne (local.get $expect) (i32.load (local.get $retp))) + (then unreachable)) + (call $subtask.drop (local.get $subtask)) + (call $waitable-set.drop (local.get $ws)) + ) + + (func (export "run") (result i32) + (local $ret i32) (local $retp i32) + (local $subtask i32) (local $handle i32) + + (local.set $retp (i32.const 8)) + + ;; call $blocker which will block during a synchronous function. + ;; normally calling another function would hit backpressure until + ;; $blocker was done, but calling the sync-typed function $unblocker + ;; barges in synchronously. + (local.set $ret (call $blocker (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $unblocker (i32.const 90)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 90)) + + ;; do it all again, but this time unblock via resource.drop: + (local.set $handle (call $new-R (i32.const 91))) + (local.set $ret (call $blocker (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $drop-R (local.get $handle)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 91)) + + ;; do both of the above again, but for $blocker-cb instead of $blocker + (local.set $ret (call $blocker-cb (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $unblocker (i32.const 92)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 92)) + (local.set $handle (call $new-R (i32.const 93))) + (local.set $ret (call $blocker-cb (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $drop-R (local.get $handle)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 93)) + + ;; now do all the above again, but for 'yielder'/'yielder-cb', which + ;; yield, instead of waiting, using 'poker' to deliver a specific value + (local.set $ret (call $yielder (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $poker (i32.const 94)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 94)) + (local.set $handle (call $new-S (i32.const 95))) + (local.set $ret (call $yielder (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $drop-S (local.get $handle)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 95)) + (local.set $ret (call $yielder-cb (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $poker (i32.const 96)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 96)) + (local.set $handle (call $new-S (i32.const 97))) + (local.set $ret (call $yielder-cb (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $drop-S (local.get $handle)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 97)) + + (i32.const 100) + ) + ) + (alias export $c "R" (type $R)) + (alias export $c "S" (type $S)) + (canon resource.drop $R (core func $drop-R')) + (canon resource.drop $S (core func $drop-S')) + (canon subtask.drop (core func $subtask.drop)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.drop (core func $waitable-set.drop)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon waitable-set.poll (memory $memory "mem") (core func $waitable-set.poll)) + (canon lower (func $c "new-R") (core func $new-R')) + (canon lower (func $c "blocker") (memory $memory "mem") async (core func $blocker')) + (canon lower (func $c "blocker-cb") (memory $memory "mem") async (core func $blocker-cb')) + (canon lower (func $c "unblocker") (core func $unblocker')) + (canon lower (func $c "new-S") (core func $new-S')) + (canon lower (func $c "yielder") (memory $memory "mem") async (core func $yielder')) + (canon lower (func $c "yielder-cb") (memory $memory "mem") async (core func $yielder-cb')) + (canon lower (func $c "poker") (core func $poker')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "subtask.drop" (func $subtask.drop)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.drop" (func $waitable-set.drop)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "waitable-set.poll" (func $waitable-set.poll)) + (export "new-R" (func $new-R')) + (export "drop-R" (func $drop-R')) + (export "blocker" (func $blocker')) + (export "blocker-cb" (func $blocker-cb')) + (export "unblocker" (func $unblocker')) + (export "new-S" (func $new-S')) + (export "drop-S" (func $drop-S')) + (export "yielder" (func $yielder')) + (export "yielder-cb" (func $yielder-cb')) + (export "poker" (func $poker')) + )))) + (func (export "run") async (result u32) (canon lift (core func $core "run"))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "run") (alias export $d "run")) +) + +(component instance $i $Tester) +(assert_return (invoke "run") (u32.const 100)) diff --git a/parser/src/test/resources/spec-tests/async/sync-streams.wast b/parser/src/test/resources/spec-tests/async/sync-streams.wast new file mode 100644 index 0000000..364ba9c --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/sync-streams.wast @@ -0,0 +1,178 @@ +;; This test calls sync stream.write in $C.get and sync stream.read in $C.set. +;; Both of these calls block because $C is first to the rendezvous. But since +;; they are synchronous, control flow switches to $D.run which will do +;; a complementary read/write that rendezvous, and then control flow will +;; switch back to $C.get/set where the synchronous read/write will return +;; without blocking. +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.return0" (func $task.return0)) + (import "" "task.return1" (func $task.return1 (param i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + (func (export "get") (result i32) + (local $ret i32) (local $ret64 i64) + (local $tx i32) (local $rx i32) + (local $bufp i32) + + ;; ($rx, $tx) = stream.new + (local.set $ret64 (call $stream.new)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + + ;; return $rx + (call $task.return1 (local.get $rx)) + + ;; (stream.write $tx $bufp 4) will block and, because called + ;; synchronously, switch to the caller who will read and rendezvous + (local.set $bufp (i32.const 16)) + (i32.store (local.get $bufp) (i32.const 0x01234567)) + (local.set $ret (call $stream.write (local.get $tx) (local.get $bufp) (i32.const 4))) + (if (i32.ne (i32.const 0x41 (; DROPPED=1 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + + (call $stream.drop-writable (local.get $tx)) + (return (i32.const 0 (; EXIT ;))) + ) + (func (export "get_cb") (param i32 i32 i32) (result i32) + unreachable + ) + + (func (export "set") (param $rx i32) (result i32) + (local $ret i32) (local $ret64 i64) + (local $bufp i32) + + ;; return immediately so that the caller can just call synchronously + (call $task.return0) + + ;; (stream.read $rx $bufp 4) will block and, because called + ;; synchronously, switch to the caller who will write and rendezvous + (local.set $bufp (i32.const 16)) + (local.set $ret (call $stream.read (local.get $rx) (local.get $bufp) (i32.const 4))) + (if (i32.ne (i32.const 0x41 (; DROPPED=1 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0x89abcdef) (i32.load (local.get $bufp))) + (then unreachable)) + + (call $stream.drop-readable (local.get $rx)) + (return (i32.const 0 (; EXIT ;))) + ) + (func (export "set_cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (type $ST (stream u8)) + (canon task.return (memory $memory "mem") (core func $task.return0)) + (canon task.return (result $ST) (memory $memory "mem") (core func $task.return1)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return0" (func $task.return0)) + (export "task.return1" (func $task.return1)) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (func (export "get") async (result (stream u8)) (canon lift + (core func $cm "get") + async (memory $memory "mem") (callback (func $cm "get_cb")) + )) + (func (export "set") async (param "in" (stream u8)) (canon lift + (core func $cm "set") + async (memory $memory "mem") (callback (func $cm "set_cb")) + )) + ) + (component $D + (import "get" (func $get async (result (stream u8)))) + (import "set" (func $set async (param "in" (stream u8)))) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + (import "" "get" (func $get (result i32))) + (import "" "set" (func $set (param i32))) + + (func (export "run") (result i32) + (local $ret i32) (local $ret64 i64) + (local $rx i32) (local $tx i32) + (local $bufp i32) + + ;; $rx = $C.get() + (local.set $rx (call $get)) + + ;; (stream.read $rx $bufp 4) will succeed without blocking + (local.set $bufp (i32.const 20)) + (local.set $ret (call $stream.read (local.get $rx) (local.get $bufp) (i32.const 4))) + (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0x01234567) (i32.load (local.get $bufp))) + (then unreachable)) + + (call $stream.drop-readable (local.get $rx)) + + ;; ($rx, $tx) = stream.new + ;; $C.set($rx) + (local.set $ret64 (call $stream.new)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (call $set (local.get $rx)) + + ;; (stream.write $tx $bufp 4) will succeed without blocking + (local.set $bufp (i32.const 16)) + (local.set $ret (call $stream.write (local.get $tx) (local.get $bufp) (i32.const 4))) + (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + + (call $stream.drop-writable (local.get $tx)) + (i32.const 42) + ) + ) + (type $ST (stream u8)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (canon lower (func $get) (core func $get')) + (canon lower (func $set) (core func $set')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "stream.drop-writable" (func $stream.drop-writable)) + (export "get" (func $get')) + (export "set" (func $set')) + )))) + (func (export "run") async (result u32) (canon lift (core func $dm "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D + (with "get" (func $c "get")) + (with "set" (func $c "set")) + )) + (func (export "run") (alias export $d "run")) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/async/trap-if-block-and-sync.wast b/parser/src/test/resources/spec-tests/async/trap-if-block-and-sync.wast new file mode 100644 index 0000000..e2dc06b --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/trap-if-block-and-sync.wast @@ -0,0 +1,343 @@ +;; The $Tester component has two nested components $C and $D, where $D imports +;; and calls $C. $C contains utilities used by $D to perform all the tests. +;; Most of the tests trap, $Tester exports 1 function per test and a fresh +;; $Tester is created to run each test. +(component definition $Tester + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (func (export "sync-async-func") + unreachable + ) + (func (export "async-async-func") (result i32) + unreachable + ) + (func (export "async-async-func-cb") (param i32 i32 i32) (result i32) + unreachable + ) + (func (export "sync-blocks-and-traps") + (call $waitable-set.wait (call $waitable-set.new) (i32.const 0xdeadbeef)) + unreachable + ) + ) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (core instance $cm (instantiate $CM (with "" (instance + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + )))) + (func (export "sync-async-func") async (canon lift (core func $cm "sync-async-func"))) + (func (export "async-async-func") async (canon lift (core func $cm "async-async-func") async (callback (func $cm "async-async-func-cb")))) + (func (export "sync-blocks-and-traps") (canon lift (core func $cm "sync-blocks-and-traps"))) + ) + (component $D + (import "c" (instance $c + (export "sync-async-func" (func async)) + (export "async-async-func" (func async)) + (export "sync-blocks-and-traps" (func)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core module $Table + (table (export "__indirect_function_table") 2 funcref)) + (core instance $memory (instantiate $Memory)) + (core instance $table (instantiate $Table)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) + (import "" "thread.yield" (func $thread.yield (result i32))) + ;;(import "" "thread.yield-to" (func $thread.yield-to (param i32) (result i32))) + ;;(import "" "thread.switch-to" (func $thread.switch-to (param i32) (result i32))) + ;;(import "" "thread.resume-later" (func $thread.resume-later (param i32))) + (import "" "thread.index" (func $thread-index (result i32))) + (import "" "thread.suspend" (func $thread.suspend (result i32))) + (import "" "thread.new-indirect" (func $thread.new-indirect (param i32 i32) (result i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "waitable-set.poll" (func $waitable-set.poll (param i32 i32) (result i32))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "stream.cancel-read" (func $stream.cancel-read (param i32) (result i32))) + (import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32))) + (import "" "future.cancel-read" (func $future.cancel-read (param i32) (result i32))) + (import "" "future.cancel-write" (func $future.cancel-write (param i32) (result i32))) + (import "" "await-sync-async-func" (func $await-sync-async-func)) + (import "" "await-async-async-func" (func $await-async-async-func)) + (import "" "sync-blocks-and-traps" (func $sync-blocks-and-traps)) + (import "" "__indirect_function_table" (table $indirect-function-table 2 funcref)) + + (func (export "unreachable-cb") (param i32 i32 i32) (result i32) + unreachable + ) + (func (export "return-42-cb") (param i32 i32 i32) (result i32) + (call $task.return (i32.const 42)) + (i32.const 0 (; EXIT ;)) + ) + + (func (export "trap-if-sync-call-async1") + (call $await-sync-async-func) + ) + (func (export "trap-if-sync-call-async2") + (call $await-async-async-func) + ) + (func (export "trap-if-async-calls-sync-and-blocks") (result i32) + (call $sync-blocks-and-traps) + unreachable + ) + (func (export "trap-if-suspend") + (call $thread.suspend) + unreachable + ) + (func (export "trap-if-wait") + (call $waitable-set.wait (call $waitable-set.new) (i32.const 0xdeadbeef)) + unreachable + ) + (func (export "trap-if-wait-cb") (result i32) + (i32.or + (i32.const 2 (; WAIT ;)) + (i32.shl (call $waitable-set.new) (i32.const 4))) + ) + (func (export "poll-is-fine") (result i32) + (local $ret i32) + (local.set $ret (call $waitable-set.poll (call $waitable-set.new) (i32.const 0))) + (if (i32.ne (i32.const 0 (; NONE ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0) (i32.load (i32.const 0))) + (then unreachable)) + (if (i32.ne (i32.const 0) (i32.load (i32.const 4))) + (then unreachable)) + (i32.const 42) + ) + (func (export "trap-if-invalid-callback-code") (param $invalid-code i32) (result i32) + (i32.or + (local.get $invalid-code) + (i32.shl (call $waitable-set.new) (i32.const 4))) + ) + (func (export "yield-is-fine") (result i32) + (drop (call $thread.yield)) + (i32.const 42) + ) + (func (export "yield-is-fine-cb") (result i32) + (i32.or + (i32.const 1 (; YIELD ;)) + (i32.shl (i32.const 0xdead) (i32.const 4))) + ) + (func $thread-start-noop (param i32)) + (elem (table $indirect-function-table) (i32.const 0) func $thread-start-noop) + (func (export "yield-to-is-fine") (result i32) + ;; TODO: rename and reenable + ;;(drop (call $thread.yield-to (call $thread.new-indirect (i32.const 0) (i32.const 0)))) + (i32.const 42) + ) + (func $thread-start-switch-back (param i32) + ;;(drop (call $thread.switch-to (local.get 0))) + ) + (elem (table $indirect-function-table) (i32.const 1) func $thread-start-switch-back) + (func (export "switch-to-is-fine") (result i32) + ;; TODO: rename and reenable + ;;(drop (call $thread.switch-to (call $thread.new-indirect (i32.const 1) (call $thread-index)))) + (i32.const 42) + ) + (func (export "resume-later-is-fine") (result i32) + ;; TODO: rename and reenable + ;;(call $thread.resume-later (call $thread.new-indirect (i32.const 0) (i32.const 0))) + (i32.const 42) + ) + (func (export "trap-if-sync-cancel") + (call $subtask.cancel (i32.const 0xdeadbeef)) + unreachable + ) + (func (export "trap-if-sync-stream-read") + (call $stream.read (i32.const 0xdead) (i32.const 0xbeef) (i32.const 0xdead)) + unreachable + ) + (func (export "trap-if-sync-stream-write") + (call $stream.write (i32.const 0xdead) (i32.const 0xbeef) (i32.const 0xdead)) + unreachable + ) + (func (export "trap-if-sync-future-read") + (call $future.read (i32.const 0xdead) (i32.const 0xdeadbeef)) + unreachable + ) + (func (export "trap-if-sync-future-write") + (call $future.write (i32.const 0xdead) (i32.const 0xdeadbeef)) + unreachable + ) + (func (export "trap-if-sync-stream-cancel-read") + (call $stream.cancel-read (i32.const 0xdead)) + unreachable + ) + (func (export "trap-if-sync-stream-cancel-write") + (call $stream.cancel-write (i32.const 0xdead)) + unreachable + ) + (func (export "trap-if-sync-future-cancel-read") + (call $future.cancel-read (i32.const 0xdead) (i32.const 0xdeadbeef)) + unreachable + ) + (func (export "trap-if-sync-future-cancel-write") + (call $future.cancel-write (i32.const 0xdead) (i32.const 0xdeadbeef)) + unreachable + ) + ) + (type $FT (future u8)) + (type $ST (stream u8)) + (core type $start-func-ty (func (param i32))) + (alias core export $table "__indirect_function_table" (core table $indirect-function-table)) + (core func $thread.new-indirect + (canon thread.new-indirect $start-func-ty (table $indirect-function-table))) + (canon task.return (result u32) (core func $task.return)) + (canon subtask.cancel (core func $subtask.cancel)) + (canon thread.yield (core func $thread.yield)) + (canon thread.suspend (core func $thread.suspend)) + ;;(canon thread.yield-to (core func $thread.yield-to)) + ;;(canon thread.switch-to (core func $thread.switch-to)) + ;;(canon thread.resume-later (core func $thread.resume-later)) + (canon thread.index (core func $thread.index)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon waitable-set.poll (memory $memory "mem") (core func $waitable-set.poll)) + (canon stream.read $ST (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST (memory $memory "mem") (core func $stream.write)) + (canon future.read $FT (memory $memory "mem") (core func $future.read)) + (canon future.write $FT (memory $memory "mem") (core func $future.write)) + (canon stream.cancel-read $ST (core func $stream.cancel-read)) + (canon stream.cancel-write $ST (core func $stream.cancel-write)) + (canon future.cancel-read $FT (core func $future.cancel-read)) + (canon future.cancel-write $FT (core func $future.cancel-write)) + (canon lower (func $c "sync-async-func") (core func $await-sync-async-func')) + (canon lower (func $c "async-async-func") (core func $await-async-async-func')) + (canon lower (func $c "sync-blocks-and-traps") (core func $sync-blocks-and-traps')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "subtask.cancel" (func $subtask.cancel)) + (export "thread.yield" (func $thread.yield)) + (export "thread.suspend" (func $thread.suspend)) + ;;(export "thread.yield-to" (func $thread.yield-to)) + ;;(export "thread.switch-to" (func $thread.switch-to)) + ;;(export "thread.resume-later" (func $thread.resume-later)) + (export "thread.index" (func $thread.index)) + (export "thread.new-indirect" (func $thread.new-indirect)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "waitable-set.poll" (func $waitable-set.poll)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "future.read" (func $future.read)) + (export "future.write" (func $future.write)) + (export "stream.cancel-read" (func $stream.cancel-read)) + (export "stream.cancel-write" (func $stream.cancel-write)) + (export "future.cancel-read" (func $future.cancel-read)) + (export "future.cancel-write" (func $future.cancel-write)) + (export "await-sync-async-func" (func $await-sync-async-func')) + (export "await-async-async-func" (func $await-async-async-func')) + (export "sync-blocks-and-traps" (func $sync-blocks-and-traps')) + (export "__indirect_function_table" (table $indirect-function-table)) + )))) + (func (export "trap-if-suspend") (canon lift (core func $core "trap-if-suspend"))) + (func (export "trap-if-wait") (canon lift (core func $core "trap-if-wait"))) + (func (export "trap-if-wait-cb") async (canon lift (core func $core "trap-if-wait-cb") async (callback (func $core "unreachable-cb")))) + (func (export "poll-is-fine") (result u32) (canon lift (core func $core "poll-is-fine"))) + (func (export "trap-if-invalid-callback-code") async (param "invalid-code" u32) (canon lift (core func $core "trap-if-invalid-callback-code") async (callback (func $core "unreachable-cb")))) + (func (export "yield-is-fine") (result u32) (canon lift (core func $core "yield-is-fine"))) + (func (export "yield-is-fine-cb") async (result u32) (canon lift (core func $core "yield-is-fine-cb") async (callback (func $core "return-42-cb")))) + (func (export "yield-to-is-fine") (result u32) (canon lift (core func $core "yield-to-is-fine"))) + (func (export "switch-to-is-fine") (result u32) (canon lift (core func $core "switch-to-is-fine"))) + (func (export "resume-later-is-fine") (result u32) (canon lift (core func $core "resume-later-is-fine"))) + (func (export "trap-if-sync-call-async1") (canon lift (core func $core "trap-if-sync-call-async1"))) + (func (export "trap-if-sync-call-async2") (canon lift (core func $core "trap-if-sync-call-async2"))) + (func (export "trap-if-async-calls-sync-and-blocks") async (canon lift (core func $core "trap-if-async-calls-sync-and-blocks") async (callback (func $core "unreachable-cb")))) + (func (export "trap-if-sync-cancel") (canon lift (core func $core "trap-if-sync-cancel"))) + (func (export "trap-if-sync-stream-read") (canon lift (core func $core "trap-if-sync-stream-read"))) + (func (export "trap-if-sync-stream-write") (canon lift (core func $core "trap-if-sync-stream-write"))) + (func (export "trap-if-sync-future-read") (canon lift (core func $core "trap-if-sync-future-read"))) + (func (export "trap-if-sync-future-write") (canon lift (core func $core "trap-if-sync-future-write"))) + (func (export "trap-if-sync-stream-cancel-read") (canon lift (core func $core "trap-if-sync-stream-cancel-read"))) + (func (export "trap-if-sync-stream-cancel-write") (canon lift (core func $core "trap-if-sync-stream-cancel-write"))) + (func (export "trap-if-sync-future-cancel-read") (canon lift (core func $core "trap-if-sync-future-cancel-read"))) + (func (export "trap-if-sync-future-cancel-write") (canon lift (core func $core "trap-if-sync-future-cancel-write"))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "trap-if-sync-call-async1") (alias export $d "trap-if-sync-call-async1")) + (func (export "trap-if-sync-call-async2") (alias export $d "trap-if-sync-call-async2")) + (func (export "trap-if-async-calls-sync-and-blocks") (alias export $d "trap-if-async-calls-sync-and-blocks")) + (func (export "trap-if-suspend") (alias export $d "trap-if-suspend")) + (func (export "trap-if-wait") (alias export $d "trap-if-wait")) + (func (export "trap-if-wait-cb") (alias export $d "trap-if-wait-cb")) + (func (export "poll-is-fine") (alias export $d "poll-is-fine")) + (func (export "trap-if-invalid-callback-code") (alias export $d "trap-if-invalid-callback-code")) + (func (export "yield-is-fine") (alias export $d "yield-is-fine")) + (func (export "yield-is-fine-cb") (alias export $d "yield-is-fine-cb")) + (func (export "yield-to-is-fine") (alias export $d "yield-to-is-fine")) + (func (export "switch-to-is-fine") (alias export $d "switch-to-is-fine")) + (func (export "resume-later-is-fine") (alias export $d "resume-later-is-fine")) + (func (export "trap-if-sync-cancel") (alias export $d "trap-if-sync-cancel")) + (func (export "trap-if-sync-stream-read") (alias export $d "trap-if-sync-stream-read")) + (func (export "trap-if-sync-stream-write") (alias export $d "trap-if-sync-stream-write")) + (func (export "trap-if-sync-future-read") (alias export $d "trap-if-sync-future-read")) + (func (export "trap-if-sync-future-write") (alias export $d "trap-if-sync-future-write")) + (func (export "trap-if-sync-stream-cancel-read") (alias export $d "trap-if-sync-stream-cancel-read")) + (func (export "trap-if-sync-stream-cancel-write") (alias export $d "trap-if-sync-stream-cancel-write")) + (func (export "trap-if-sync-future-cancel-read") (alias export $d "trap-if-sync-future-cancel-read")) + (func (export "trap-if-sync-future-cancel-write") (alias export $d "trap-if-sync-future-cancel-write")) +) + +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-call-async1") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-call-async2") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-async-calls-sync-and-blocks") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-suspend") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-wait") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-wait-cb") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_return (invoke "poll-is-fine") (u32.const 42)) +(component instance $i $Tester) +(assert_trap (invoke "trap-if-invalid-callback-code" (u32.const 3)) "unsupported callback code") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-invalid-callback-code" (u32.const 4)) "unsupported callback code") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-invalid-callback-code" (u32.const 15)) "unsupported callback code") +(component instance $i $Tester) +(assert_return (invoke "yield-is-fine") (u32.const 42)) +(component instance $i $Tester) +(assert_return (invoke "yield-is-fine-cb") (u32.const 42)) +(component instance $i $Tester) +(assert_return (invoke "yield-to-is-fine") (u32.const 42)) +(component instance $i $Tester) +(assert_return (invoke "switch-to-is-fine") (u32.const 42)) +(component instance $i $Tester) +(assert_return (invoke "resume-later-is-fine") (u32.const 42)) +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-cancel") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-stream-read") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-stream-write") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-future-read") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-future-write") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-stream-cancel-read") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-stream-cancel-write") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-future-cancel-read") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-future-cancel-write") "cannot block a synchronous task before returning") diff --git a/parser/src/test/resources/spec-tests/async/trap-if-done.wast b/parser/src/test/resources/spec-tests/async/trap-if-done.wast new file mode 100644 index 0000000..5d7d9aa --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/trap-if-done.wast @@ -0,0 +1,468 @@ +;; This test has two components $C and $D, where $D imports and calls $C. +;; $C contains utility functions used by $D to create futures/streams, +;; write to them and close them. $D uses these utility functions to test for +;; all the cases where, once a future/stream is "done", further uses of the +;; future/stream trap. +;; +;; $D exports a list of functions, one for each case of trapping. Since traps +;; take out their containing instance, a fresh instance of $Tester is created +;; for each call to a $D export. +;; +;; When testing traps involving the readable end, the exports of $D take a +;; "bool" parameter that toggles whether the trap is triggered by +;; {stream,future}.{read,write} or by lifting, and the top-level commands +;; pass 'false' and 'true'. +(component definition $Tester + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "future.drop-writable" (func $future.drop-writable (param i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + (global $writable-end (mut i32) (i32.const 0)) + (global $ws (mut i32) (i32.const 0)) + + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + (func $start-future (export "start-future") (result i32) + ;; create a new future, return the readable end to the caller + (local $ret64 i64) + (local.set $ret64 (call $future.new)) + (global.set $writable-end (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (call $waitable.join (global.get $writable-end) (global.get $ws) ) + (i32.wrap_i64 (local.get $ret64)) + ) + (func $future-write (export "future-write") (result i32) + ;; the caller will assert what they expect the return value to be + (i32.store (i32.const 16) (i32.const 42)) + (call $future.write (global.get $writable-end) (i32.const 16)) + ) + (func $acknowledge-future-write (export "acknowledge-future-write") + ;; confirm we got a FUTURE_WRITE $writable-end COMPLETED event + (local $ret i32) + (local.set $ret (call $waitable-set.wait (global.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 5 (; FUTURE_WRITE ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (global.get $writable-end) (i32.load (i32.const 0))) + (then unreachable)) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (i32.load (i32.const 4))) + (then unreachable)) + ) + (func $future-drop-writable (export "future-drop-writable") + ;; maybe boom + (call $future.drop-writable (global.get $writable-end)) + ) + + (func $start-stream (export "start-stream") (result i32) + ;; create a new stream, return the readable end to the caller + (local $ret64 i64) + (local.set $ret64 (call $stream.new)) + (global.set $writable-end (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (call $waitable.join (global.get $writable-end) (global.get $ws) ) + (i32.wrap_i64 (local.get $ret64)) + ) + (func $stream-write (export "stream-write") (result i32) + ;; the caller will assert what they expect the return value to be + (i32.store (i32.const 16) (i32.const 42)) + (call $stream.write (global.get $writable-end) (i32.const 16) (i32.const 1)) + ) + (func $acknowledge-stream-write (export "acknowledge-stream-write") + ;; confirm we got a STREAM_WRITE $writable-end COMPLETED event + (local $ret i32) + (local.set $ret (call $waitable-set.wait (global.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 3 (; STREAM_WRITE ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (global.get $writable-end) (i32.load (i32.const 0))) + (then unreachable)) + (if (i32.ne (i32.const 0x11 (; DROPPED=1 | (1<<4) ;)) (i32.load (i32.const 4))) + (then unreachable)) + ) + (func $stream-drop-writable (export "stream-drop-writable") + ;; maybe boom + (call $stream.drop-writable (global.get $writable-end)) + ) + ) + (type $FT (future u8)) + (type $ST (stream u8)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon future.new $FT (core func $future.new)) + (canon future.write $FT async (memory $memory "mem") (core func $future.write)) + (canon future.drop-writable $FT (core func $future.drop-writable)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "future.new" (func $future.new)) + (export "future.write" (func $future.write)) + (export "future.drop-writable" (func $future.drop-writable)) + (export "stream.new" (func $stream.new)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (func (export "start-future") async (result (future u8)) (canon lift (core func $cm "start-future"))) + (func (export "future-write") async (result u32) (canon lift (core func $cm "future-write"))) + (func (export "acknowledge-future-write") async (canon lift (core func $cm "acknowledge-future-write"))) + (func (export "future-drop-writable") async (canon lift (core func $cm "future-drop-writable"))) + (func (export "start-stream") async (result (stream u8)) (canon lift (core func $cm "start-stream"))) + (func (export "stream-write") async (result u32) (canon lift (core func $cm "stream-write"))) + (func (export "acknowledge-stream-write") async (canon lift (core func $cm "acknowledge-stream-write"))) + (func (export "stream-drop-writable") async (canon lift (core func $cm "stream-drop-writable"))) + ) + (component $D + (import "c" (instance $c + (export "start-future" (func async (result (future u8)))) + (export "future-write" (func async (result u32))) + (export "acknowledge-future-write" (func async)) + (export "future-drop-writable" (func async)) + (export "start-stream" (func async (result (stream u8)))) + (export "stream-write" (func async (result u32))) + (export "acknowledge-stream-write" (func async)) + (export "stream-drop-writable" (func async)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.drop-readable" (func $future.drop-readable (param i32))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "start-future" (func $start-future (result i32))) + (import "" "future-write" (func $future-write (result i32))) + (import "" "acknowledge-future-write" (func $acknowledge-future-write)) + (import "" "future-drop-writable" (func $future-drop-writable)) + (import "" "start-stream" (func $start-stream (result i32))) + (import "" "stream-write" (func $stream-write (result i32))) + (import "" "acknowledge-stream-write" (func $acknowledge-stream-write)) + (import "" "stream-drop-writable" (func $stream-drop-writable)) + + (func $trap-after-future-eager-write (export "trap-after-future-eager-write") + (local $ret i32) + (local $fr i32) + (local.set $fr (call $start-future)) + + ;; start a read on our end so the next write will succeed + (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; calling future.write in $C should succeed eagerly + (local.set $ret (call $future-write)) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) + (then unreachable)) + + ;; calling future.write in $C now should trap + (drop (call $future-write)) + ) + (func $trap-after-future-async-write (export "trap-after-future-async-write") + (local $ret i32) + (local $fr i32) + (local.set $fr (call $start-future)) + + ;; calling future.write in $C should block + (local.set $ret (call $future-write)) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; our future.read should then succeed eagerly + (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) + (then unreachable)) + + ;; let $C see the write completed so the future is 'done' + (call $acknowledge-future-write) + + ;; trying to call future.write again in $C should trap + (drop (call $future-write)) + ) + (func $trap-after-future-reader-dropped (export "trap-after-future-reader-dropped") + (local $ret i32) + (local $fr i32) + (local.set $fr (call $start-future)) + + ;; drop our readable end before writer can write + (call $future.drop-readable (local.get $fr)) + + ;; let $C try to future.write and find out we DROPPED + (local.set $ret (call $future-write)) + (if (i32.ne (i32.const 1 (; DROPPED ;)) (local.get $ret)) + (then unreachable)) + + ;; trying to call future.write again in $C should trap + (drop (call $future-write)) + ) + (func $trap-after-future-eager-read (export "trap-after-future-eager-read") (param $bool i32) (result i32) + (local $ret i32) + (local $fr i32) + (local.set $fr (call $start-future)) + + ;; calling future.write in $C should block + (local.set $ret (call $future-write)) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; our future.read should then succeed eagerly + (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) + (then unreachable)) + + (if (i32.eqz (local.get $bool)) (then + ;; calling future.read again should then trap + (drop (call $future.read (local.get $fr) (i32.const 16))) + ) (else + ;; lifting the future by returning it should also trap + (return (local.get $fr)) + )) + unreachable + ) + (func $trap-after-future-async-read (export "trap-after-future-async-read") (param $bool i32) (result i32) + (local $ret i32) (local $ws i32) + (local $fr i32) + (local.set $fr (call $start-future)) + + ;; read first, so it blocks + (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; calling future.write in $C should then succeed eagerly + (local.set $ret (call $future-write)) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) + (then unreachable)) + + ;; wait to see that our blocked future.read COMPLETED, producing '42' + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $fr) (local.get $ws)) + (local.set $ret (call $waitable-set.wait (local.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (local.get $fr) (i32.load (i32.const 0))) + (then unreachable)) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (i32.load (i32.const 4))) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load (i32.const 16))) + (then unreachable)) + + (if (i32.eqz (local.get $bool)) (then + ;; calling future.read again should then trap + (drop (call $future.read (local.get $fr) (i32.const 16))) + ) (else + ;; lifting the future by returning it should also trap + (return (local.get $fr)) + )) + unreachable + ) + (func $trap-after-stream-reader-eager-dropped (export "trap-after-stream-reader-eager-dropped") + (local $ret i32) + (local $sr i32) + (local.set $sr (call $start-stream)) + + ;; drop our readable end before writer can write + (call $stream.drop-readable (local.get $sr)) + + ;; let $C try to stream.write and find out we DROPPED + (local.set $ret (call $stream-write)) + (if (i32.ne (i32.const 1 (; DROPPED ;)) (local.get $ret)) + (then unreachable)) + + ;; trying to call stream.write again in $C should trap + (drop (call $stream-write)) + ) + (func $trap-after-stream-reader-async-dropped (export "trap-after-stream-reader-async-dropped") + (local $ret i32) + (local $sr i32) + (local.set $sr (call $start-stream)) + + ;; calling stream.write in $C should block + (local.set $ret (call $stream-write)) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; our stream.read should then succeed eagerly + (local.set $ret (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) + (if (i32.ne (i32.const 0x10 (; COMPLETED=0 | (1<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) + (then unreachable)) + + ;; then drop our readable end + (call $stream.drop-readable (local.get $sr)) + + ;; let $C see that it's stream.write COMPLETED and wrote 1 elem + (call $acknowledge-stream-write) + + ;; now calling stream.write again in $C will trap + (drop (call $stream-write)) + ) + (func $trap-after-stream-writer-eager-dropped (export "trap-after-stream-writer-eager-dropped") (param $bool i32) (result i32) + (local $ret i32) + (local $sr i32) + (local.set $sr (call $start-stream)) + + ;; immediately drop the writable end + (call $stream-drop-writable) + + ;; calling stream.read will see that the writer dropped + (local.set $ret (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) + (if (i32.ne (i32.const 0x01 (; DROPPED=1 | (0<<4) ;)) (local.get $ret)) + (then unreachable)) + + (if (i32.eqz (local.get $bool)) (then + ;; calling stream.read again should then trap + (drop (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) + ) (else + ;; lifting the stream by returning it should also trap + (return (local.get $sr)) + )) + unreachable + ) + (func $trap-after-stream-writer-async-dropped (export "trap-after-stream-writer-async-dropped") (param $bool i32) (result i32) + (local $ret i32) (local $ws i32) + (local $sr i32) + (local.set $sr (call $start-stream)) + + ;; start a read on our end first which will block + (local.set $ret (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; drop the writable end before writing anything + (call $stream-drop-writable) + + ;; wait to see that our blocked stream.read was DROPPED + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $sr) (local.get $ws)) + (local.set $ret (call $waitable-set.wait (local.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 2 (; STREAM_READ ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (local.get $sr) (i32.load (i32.const 0))) + (then unreachable)) + (if (i32.ne (i32.const 0x01 (; DROPPED=1 | (0<<4) ;)) (i32.load (i32.const 4))) + (then unreachable)) + + (if (i32.eqz (local.get $bool)) (then + ;; calling stream.read again should then trap + (drop (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) + ) (else + ;; lifting the stream by returning it should also trap + (return (local.get $sr)) + )) + unreachable + ) + ) + (type $FT (future u8)) + (type $ST (stream u8)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon future.new $FT (core func $future.new)) + (canon future.read $FT async (memory $memory "mem") (core func $future.read)) + (canon future.drop-readable $FT (core func $future.drop-readable)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon lower (func $c "start-future") (core func $start-future')) + (canon lower (func $c "future-write") (core func $future-write')) + (canon lower (func $c "acknowledge-future-write") (core func $acknowledge-future-write')) + (canon lower (func $c "future-drop-writable") (core func $future-drop-writable')) + (canon lower (func $c "start-stream") (core func $start-stream')) + (canon lower (func $c "stream-write") (core func $stream-write')) + (canon lower (func $c "acknowledge-stream-write") (core func $acknowledge-stream-write')) + (canon lower (func $c "stream-drop-writable") (core func $stream-drop-writable')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "future.new" (func $future.new)) + (export "future.read" (func $future.read)) + (export "future.drop-readable" (func $future.drop-readable)) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "start-future" (func $start-future')) + (export "future-write" (func $future-write')) + (export "acknowledge-future-write" (func $acknowledge-future-write')) + (export "future-drop-writable" (func $future-drop-writable')) + (export "start-stream" (func $start-stream')) + (export "stream-write" (func $stream-write')) + (export "acknowledge-stream-write" (func $acknowledge-stream-write')) + (export "stream-drop-writable" (func $stream-drop-writable')) + )))) + (func (export "trap-after-future-eager-write") async (canon lift (core func $core "trap-after-future-eager-write"))) + (func (export "trap-after-future-async-write") async (canon lift (core func $core "trap-after-future-async-write"))) + (func (export "trap-after-future-reader-dropped") async (canon lift (core func $core "trap-after-future-reader-dropped"))) + (func (export "trap-after-future-eager-read") async (param "bool" bool) (result $FT) (canon lift (core func $core "trap-after-future-eager-read"))) + (func (export "trap-after-future-async-read") async (param "bool" bool) (result $FT) (canon lift (core func $core "trap-after-future-async-read"))) + (func (export "trap-after-stream-reader-eager-dropped") async (canon lift (core func $core "trap-after-stream-reader-eager-dropped"))) + (func (export "trap-after-stream-reader-async-dropped") async (canon lift (core func $core "trap-after-stream-reader-async-dropped"))) + (func (export "trap-after-stream-writer-eager-dropped") async (param "bool" bool) (result $ST) (canon lift (core func $core "trap-after-stream-writer-eager-dropped"))) + (func (export "trap-after-stream-writer-async-dropped") async (param "bool" bool) (result $ST) (canon lift (core func $core "trap-after-stream-writer-async-dropped"))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "trap-after-future-eager-write") (alias export $d "trap-after-future-eager-write")) + (func (export "trap-after-future-async-write") (alias export $d "trap-after-future-async-write")) + (func (export "trap-after-future-reader-dropped") (alias export $d "trap-after-future-reader-dropped")) + (func (export "trap-after-future-eager-read") (alias export $d "trap-after-future-eager-read")) + (func (export "trap-after-future-async-read") (alias export $d "trap-after-future-async-read")) + (func (export "trap-after-stream-reader-eager-dropped") (alias export $d "trap-after-stream-reader-eager-dropped")) + (func (export "trap-after-stream-reader-async-dropped") (alias export $d "trap-after-stream-reader-async-dropped")) + (func (export "trap-after-stream-writer-eager-dropped") (alias export $d "trap-after-stream-writer-eager-dropped")) + (func (export "trap-after-stream-writer-async-dropped") (alias export $d "trap-after-stream-writer-async-dropped")) +) + +(component instance $i1 $Tester) +(assert_trap (invoke "trap-after-future-eager-write") "cannot write to future after previous write succeeded") +(component instance $i2 $Tester) +(assert_trap (invoke "trap-after-future-async-write") "cannot write to future after previous write succeeded") +(component instance $i3 $Tester) +(assert_trap (invoke "trap-after-future-reader-dropped") "cannot write to future after previous write succeeded or readable end dropped") +(component instance $i4.1 $Tester) +(assert_trap (invoke "trap-after-future-eager-read" (bool.const false)) "cannot read from future after previous read succeeded") +(component instance $i4.2 $Tester) +(assert_trap (invoke "trap-after-future-eager-read" (bool.const true)) "cannot lift future after previous read succeeded") +(component instance $i5.1 $Tester) +(assert_trap (invoke "trap-after-future-async-read" (bool.const false)) "cannot read from future after previous read succeeded") +(component instance $i5.2 $Tester) +(assert_trap (invoke "trap-after-future-async-read" (bool.const true)) "cannot lift future after previous read succeeded") +(component instance $i6 $Tester) +(assert_trap (invoke "trap-after-stream-reader-eager-dropped") "cannot write to stream after being notified that the readable end dropped") +(component instance $i7 $Tester) +(assert_trap (invoke "trap-after-stream-reader-async-dropped") "cannot write to stream after being notified that the readable end dropped") +(component instance $i8.1 $Tester) +(assert_trap (invoke "trap-after-stream-writer-eager-dropped" (bool.const false)) "cannot read from stream after being notified that the writable end dropped") +(component instance $i8.2 $Tester) +(assert_trap (invoke "trap-after-stream-writer-eager-dropped" (bool.const true)) "cannot lift stream after being notified that the writable end dropped") +(component instance $i9.1 $Tester) +(assert_trap (invoke "trap-after-stream-writer-async-dropped" (bool.const false)) "cannot read from stream after being notified that the writable end dropped") +(component instance $i9.2 $Tester) +(assert_trap (invoke "trap-after-stream-writer-async-dropped" (bool.const true)) "cannot lift stream after being notified that the writable end dropped") diff --git a/parser/src/test/resources/spec-tests/async/trap-on-reenter.wast b/parser/src/test/resources/spec-tests/async/trap-on-reenter.wast new file mode 100644 index 0000000..f363f6d --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/trap-on-reenter.wast @@ -0,0 +1,110 @@ +;; This test creates an asynchronous recursive call stack: +;; $Parent --> $Child --> $Parent +;; That should trap when $Child tries to call $Parent. +(component $Parent + (core module $CoreInner + (memory (export "mem") 1) + (func (export "a") (result i32) + unreachable + ) + (func (export "a-cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (core instance $core_inner (instantiate $CoreInner)) + (func $a async (canon lift + (core func $core_inner "a") + async (callback (func $core_inner "a-cb")) + )) + + (component $Child + (import "a" (func $a async)) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + + (core module $CoreChild + (import "" "a" (func $a (result i32))) + (func (export "b") (result i32) + (i32.const 1 (; YIELD ;)) + ) + (func (export "b-cb") (param i32 i32 i32) (result i32) + (call $a) + unreachable + ) + ) + (canon lower (func $a) async (memory $memory "mem") (core func $a')) + (core instance $core_child (instantiate $CoreChild (with "" (instance + (export "a" (func $a')) + )))) + (func (export "b") async (canon lift + (core func $core_child "b") + async (callback (func $core_child "b-cb")) + )) + ) + (instance $child (instantiate $Child (with "a" (func $a)))) + + (core module $CoreOuter + (import "" "b" (func $b (result i32))) + (func $c (export "c") (result i32) + (i32.const 1 (; YIELD ;)) + ) + (func $c-cb (export "c-cb") (param i32 i32 i32) (result i32) + (call $b) + ) + ) + (canon lower (func $child "b") async (memory $core_inner "mem") (core func $b)) + (core instance $core_outer (instantiate $CoreOuter (with "" (instance + (export "b" (func $b)) + )))) + (func $c (export "c") async (canon lift + (core func $core_outer "c") + async (callback (func $core_outer "c-cb")) + )) +) +(assert_trap (invoke "c") "wasm trap: cannot enter component instance") + +;; also, for now, trap on parent-to-child +(component $Parent + (component $Child + (core module $CoreChild + (func (export "f")) + ) + (core instance $core_child (instantiate $CoreChild)) + (func (export "f") (canon lift (core func $core_child "f"))) + ) + (instance $child (instantiate $Child)) + (canon lower (func $child "f") (core func $f)) + + (core module $CoreOuter + (import "" "f" (func $f)) + (func (export "g") (call $f)) + ) + (core instance $core_outer (instantiate $CoreOuter (with "" (instance (export "f" (func $f)))))) + (func $g (export "g") (canon lift (core func $core_outer "g"))) +) +(assert_trap (invoke "g") "wasm trap: cannot enter component instance") + +;; also, for now, trap on child-to-parent +(component $Parent + (core module $CoreInner + (func (export "f")) + ) + (core instance $core_inner (instantiate $CoreInner)) + (func $f (canon lift (core func $core_inner "f"))) + + (component $Child + (import "f" (func $f)) + (canon lower (func $f) (core func $f')) + (core module $CoreChild + (import "" "f" (func $f)) + (func (export "g") (call $f)) + ) + (core instance $core_child (instantiate $CoreChild (with "" (instance (export "f" (func $f')))))) + (func (export "g") (canon lift (core func $core_child "g"))) + ) + (instance $child (instantiate $Child (with "f" (func $f)))) + (alias export $child "g" (func $g)) + (export "g" (func $g)) +) +(assert_trap (invoke "g") "wasm trap: cannot enter component instance") diff --git a/parser/src/test/resources/spec-tests/async/wait-during-callback.wast b/parser/src/test/resources/spec-tests/async/wait-during-callback.wast new file mode 100644 index 0000000..3f95d5b --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/wait-during-callback.wast @@ -0,0 +1,77 @@ +;; This test calls waitable-set.wait from under an async-callback-lifted export. +(component + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + + (func $run (export "run") (result i32) + (local $ret i32) (local $ret64 i64) + (local $futr i32) (local $futw i32) (local $ws i32) + (local $event_code i32) (local $retp i32) + + ;; create a future pair + (local.set $ret64 (call $future.new)) + (local.set $futr (i32.wrap_i64 (local.get $ret64))) + (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + + ;; start a pending read that will block + (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; perform a write to make the above read ready + (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + ;; wait on a waitable set containing our now-ready future.read which + ;; should then immediately resolve + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $futr) (local.get $ws)) + (local.set $retp (i32.const 0)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp))) + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $futr) (i32.load (local.get $retp))) + (then unreachable)) + + ;; return 42 + (call $task.return (i32.const 42)) + (i32.const 0 (; EXIT ;)) + ) + (func (export "run_cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (type $FT (future)) + (canon task.return (result u32) (core func $task.return)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon future.new $FT (core func $future.new)) + (canon future.read $FT async (core func $future.read)) + (canon future.write $FT async (core func $future.write)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "future.new" (func $future.new)) + (export "future.read" (func $future.read)) + (export "future.write" (func $future.write)) + )))) + (func (export "run") async (result u32) (canon lift + (core func $cm "run") + async (callback (func $cm "run_cb")) + )) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/async/zero-length.wast b/parser/src/test/resources/spec-tests/async/zero-length.wast new file mode 100644 index 0000000..fab7765 --- /dev/null +++ b/parser/src/test/resources/spec-tests/async/zero-length.wast @@ -0,0 +1,223 @@ +;; This example defines 3 nested components $Producer, $Consumer and $Parent +;; $Parent imports $Consumer and $Producer, calling $Producer.produce, which +;; returns a stream that $Parent passes to $Consumer.consume. +;; $Producer and $Consumer both start by performing 0-length reads/writes to +;; detect when the other side is ready. Once signalled ready, a 4-byte +;; payload is written/read. +(component + (component $Producer + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CoreProducer + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + ;; $ws is waited on by 'produce' + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + ;; $outsw is written by 'produce' + (global $outsw (mut i32) (i32.const 0)) + (global $outbufp (mut i32) (i32.const 0x20)) + + (global $state (mut i32) (i32.const 0)) + + (func $produce (export "produce") (result i32) + (local $ret i32) (local $ret64 i64) (local $outsr i32) + + ;; create a new stream r/w pair $outsr/$outsw + (local.set $ret64 (call $stream.new)) + (local.set $outsr (i32.wrap_i64 (local.get $ret64))) + (global.set $outsw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + + ;; return the readable end of the stream to the caller + (call $task.return (local.get $outsr)) + + ;; initiate a zero-length write + (local.set $ret (call $stream.write (global.get $outsw) (i32.const 0xdeadbeef) (i32.const 0))) + (if (i32.ne (i32.const -1) (local.get $ret)) + (then unreachable)) + + ;; wait for the stream.write to complete + (call $waitable.join (global.get $outsw) (global.get $ws)) + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) + ) + (func $produce_cb (export "produce_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + (local $ret i32) + + ;; confirm we're getting a write for the stream $outsw + (if (i32.ne (local.get $event_code) (i32.const 3 (; STREAM_WRITE ;))) + (then unreachable)) + (if (i32.ne (local.get $index) (global.get $outsw)) + (then unreachable)) + + ;; the first call to produce_cb: + (if (i32.eq (global.get $state) (i32.const 0)) (then + ;; confirm we're seeing the zero-length write complete + (if (i32.ne (local.get $payload) (i32.const 0 (; COMPLETED=0 | (0 << 4) ;))) + (then unreachable)) + + ;; issue an async non-zero-length write which should block per spec + (i32.store (i32.const 0) (i32.const 0x12345678)) + (local.set $ret (call $stream.write (global.get $outsw) (i32.const 0) (i32.const 4))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + (global.set $state (i32.const 1)) + + ;; wait on $ws + (return (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4)))) + )) + + ;; the second call to produce_cb: + (if (i32.eq (global.get $state) (i32.const 1)) (then + ;; confirm we're seeing the non-zero-length write complete + (if (i32.ne (local.get $payload) (i32.const 0x41 (; DROPPED=1 | (4 << 4) ;))) + (then unreachable)) + + (call $stream.drop-writable (global.get $outsw)) + (return (i32.const 0 (; EXIT ;))) + )) + + unreachable + ) + ) + (type $ST (stream u8)) + (canon task.return (result $ST) (core func $task.return)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $core_producer (instantiate $CoreProducer (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "stream.new" (func $stream.new)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (func (export "produce") async (result (stream u8)) (canon lift + (core func $core_producer "produce") + async (callback (func $core_producer "produce_cb")) + )) + ) + + (component $Consumer + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CoreConsumer + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + + ;; $ws is waited on by 'consume' + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + ;; $insr is read by 'consume' + (global $insr (mut i32) (i32.const 0)) + (global $inbufp (mut i32) (i32.const 0x20)) + + (func $consume (export "consume") (param $insr i32) (result i32) + (local $ret i32) + (global.set $insr (local.get $insr)) + + ;; initiate a zero-length read which will also block (even though there is + ;; a pending write, b/c the pending write is 0-length, per spec) + (local.set $ret (call $stream.read (global.get $insr) (i32.const 0xdeadbeef) (i32.const 0))) + (if (i32.ne (i32.const -1) (local.get $ret)) + (then unreachable)) + + ;; wait for the stream.read to complete + (call $waitable.join (global.get $insr) (global.get $ws)) + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) + ) + (func $consume_cb (export "consume_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + (local $ret i32) + + ;; confirm we're seeing the zero-length read complete + (if (i32.ne (local.get $event_code) (i32.const 2 (; STREAM_READ ;))) + (then unreachable)) + (if (i32.ne (local.get $index) (global.get $insr)) + (then unreachable)) + (if (i32.ne (local.get $payload) (i32.const 0 (; COMPLETED=0 | (0 << 4) ;))) + (then unreachable)) + + ;; perform a non-zero-length read which should succeed without blocking + (local.set $ret (call $stream.read (global.get $insr) (i32.const 0) (i32.const 100))) + (if (i32.ne (i32.const 0x40 (; (4 << 4) | COMPLETED=0 ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (i32.load (i32.const 0))) + (if (i32.ne (i32.const 0x12345678) (local.get $ret)) + (then unreachable)) + + (call $stream.drop-readable (global.get $insr)) + + ;; return 42 to the top-level assert_return + (call $task.return (i32.const 42)) + (i32.const 0 (; EXIT ;)) + ) + ) + (type $ST (stream u8)) + (canon task.return (result u32) (core func $task.return)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (core instance $core_consumer (instantiate $CoreConsumer (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "stream.read" (func $stream.read)) + (export "stream.drop-readable" (func $stream.drop-readable)) + )))) + (func (export "consume") async (param "in" (stream u8)) (result u32) (canon lift + (core func $core_consumer "consume") + async (callback (func $core_consumer "consume_cb")) + )) + ) + + (component $Parent + (import "produce" (func $produce async (result (stream u8)))) + (import "consume" (func $consume async (param "in" (stream u8)) (result u32))) + + (core module $CoreParent + (import "" "produce" (func $produce (result i32))) + (import "" "consume" (func $consume (param i32) (result i32))) + (memory 1) + (func $run (export "run") (result i32) + (call $consume (call $produce)) + ) + ) + + (canon lower (func $produce) (core func $produce')) + (canon lower (func $consume) (core func $consume')) + (core instance $core_parent (instantiate $CoreParent (with "" (instance + (export "produce" (func $produce')) + (export "consume" (func $consume')) + )))) + (func (export "run") async (result u32) (canon lift (core func $core_parent "run"))) + ) + + (instance $producer (instantiate $Producer)) + (instance $consumer (instantiate $Consumer)) + (instance $parent (instantiate $Parent + (with "produce" (func $producer "produce")) + (with "consume" (func $consumer "consume")) + )) + (func (export "run") (alias export $parent "run")) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/names/kebab.wast b/parser/src/test/resources/spec-tests/names/kebab.wast new file mode 100644 index 0000000..df135f8 --- /dev/null +++ b/parser/src/test/resources/spec-tests/names/kebab.wast @@ -0,0 +1,60 @@ +(component (component + (import "a" (func)) + (import "a1" (func)) + (import "a-1" (func)) + (import "a-1-b-2-c-3" (func)) + (import "B" (func)) + (import "B1" (func)) + (import "B-1" (func)) + (import "B-1-C-2-D-3" (func)) + (import "a11-B11-123-ABC-abc" (func)) + (import "ns-1-a:b-1-c/D-2" (func)) +)) +(assert_invalid + (component + (import "1" (func))) + "is not in kebab case") +(assert_invalid + (component + (import "1-a" (func))) + "is not in kebab case") +(assert_invalid + (component + (import "" (func))) + "is not in kebab case") +(assert_invalid + (component + (import "a-" (func))) + "is not in kebab case") +(assert_invalid + (component + (import "a--" (func))) + "is not in kebab case") +(assert_invalid + (component + (import "1:a/b" (func))) + "is not in kebab case") +(assert_invalid + (component + (import "A:b/c" (func))) + "is not a valid extern name") +(assert_invalid + (component + (import "1:b/c" (func))) + "is not a valid extern name") +(assert_invalid + (component + (import "ns-A:b/c" (func))) + "is not a valid extern name") +(assert_invalid + (component + (import "ns:A/b" (func))) + "is not a valid extern name") +(assert_invalid + (component + (import "ns:1/a" (func))) + "is not a valid extern name") +(assert_invalid + (component + (import "ns:pkg-A/b" (func))) + "is not a valid extern name") diff --git a/parser/src/test/resources/spec-tests/resources/multiple-resources.wast b/parser/src/test/resources/spec-tests/resources/multiple-resources.wast new file mode 100644 index 0000000..77549ad --- /dev/null +++ b/parser/src/test/resources/spec-tests/resources/multiple-resources.wast @@ -0,0 +1,170 @@ +;; This test has two components $C and $D where $D imports and calls $C +;; $C implements two resource types imported and used by $D +;; $D creates instances of both resource types, uses them and destroys them +(component + (component $C + (core module $Indirect + (table (export "ftbl") 2 funcref) + (type $FT (func (param i32))) + (func (export "R1-dtor") (param i32) + (call_indirect (type $FT) (local.get 0) (i32.const 0)) + ) + (func (export "R2-dtor") (param i32) + (call_indirect (type $FT) (local.get 0) (i32.const 1)) + ) + ) + (core instance $indirect (instantiate $Indirect)) + (type $R1' (resource (rep i32) (dtor (func $indirect "R1-dtor")))) + (type $R2' (resource (rep i32) (dtor (func $indirect "R2-dtor")))) + (export $R1 "R1" (type $R1')) + (export $R2 "R2" (type $R2')) + (canon resource.new $R1' (core func $R1.resource.new)) + (canon resource.new $R2' (core func $R2.resource.new)) + + (core module $CM + (import "" "ftbl" (table 1 funcref)) + (import "" "R1.resource.new" (func $R1.resource.new (param i32) (result i32))) + (import "" "R2.resource.new" (func $R2.resource.new (param i32) (result i32))) + (memory 1) + (global $num-live-R1 (mut i32) (i32.const 0)) + (global $num-live-R2 (mut i32) (i32.const 0)) + + ;; constructors + (func $make-R1 (export "make-R1") (result i32) + (local $h i32) + (global.set $num-live-R1 (i32.add (global.get $num-live-R1) (i32.const 1))) + (call $R1.resource.new (i32.add (i32.const 0x40) (global.get $num-live-R1))) + ) + (func $make-R2 (export "make-R2") (result i32) + (local $h i32) + (global.set $num-live-R2 (i32.add (global.get $num-live-R2) (i32.const 1))) + (call $R2.resource.new (i32.add (i32.const 0x80) (global.get $num-live-R2))) + ) + + ;; accessors + (func $get-rep-R1 (export "get-rep-R1") (param $rep i32) (result i32) + (local.get $rep) + ) + (func $get-rep-R2 (export "get-rep-R2") (param $rep i32) (result i32) + (local.get $rep) + ) + + ;; destructors + (func $R1-dtor (param $rep i32) + (if (i32.or (i32.lt_u (local.get $rep) (i32.const 0x41)) (i32.gt_u (local.get $rep) (i32.const 0x42))) + (then unreachable)) + (if (i32.eqz (global.get $num-live-R1)) + (then unreachable)) + (global.set $num-live-R1 (i32.sub (global.get $num-live-R1) (i32.const 1))) + ) + (func $R2-dtor (param $rep i32) + (if (i32.or (i32.lt_u (local.get $rep) (i32.const 0x81)) (i32.gt_u (local.get $rep) (i32.const 0x82))) + (then unreachable)) + (if (i32.eqz (global.get $num-live-R2)) + (then unreachable)) + (global.set $num-live-R2 (i32.sub (global.get $num-live-R2) (i32.const 1))) + ) + (func $num-live (export "num-live") (result i32) + (i32.add (global.get $num-live-R1) (global.get $num-live-R2)) + ) + (elem (i32.const 0) $R1-dtor $R2-dtor) + ) + (core instance $cm (instantiate $CM (with "" (instance + (export "ftbl" (table $indirect "ftbl")) + (export "R1.resource.new" (func $R1.resource.new)) + (export "R2.resource.new" (func $R2.resource.new)) + )))) + (func $make-R1 (export "make-R1") (result (own $R1)) (canon lift (core func $cm "make-R1"))) + (func $make-R2 (export "make-R2") (result (own $R2)) (canon lift (core func $cm "make-R2"))) + (func $get-rep-R1 (export "get-rep-R1") (param "r" (borrow $R1)) (result u32) (canon lift (core func $cm "get-rep-R1"))) + (func $get-rep-R2 (export "get-rep-R2") (param "r" (borrow $R2)) (result u32) (canon lift (core func $cm "get-rep-R2"))) + (func (export "num-live") (result u32) (canon lift (core func $cm "num-live"))) + ) + + (component $D + (import "c" (instance $c + (export "R1" (type $R1 (sub resource))) + (export "R2" (type $R2 (sub resource))) + (export "make-R1" (func (result (own $R1)))) + (export "make-R2" (func (result (own $R2)))) + (export "get-rep-R1" (func (param "r" (borrow $R1)) (result u32))) + (export "get-rep-R2" (func (param "r" (borrow $R2)) (result u32))) + (export "num-live" (func (result u32))) + )) + (core module $DM + (import "" "R1.resource.drop" (func $R1.resource.drop (param i32))) + (import "" "R2.resource.drop" (func $R2.resource.drop (param i32))) + (import "" "make-R1" (func $make-R1 (result i32))) + (import "" "make-R2" (func $make-R2 (result i32))) + (import "" "get-rep-R1" (func $get-rep-R1 (param i32) (result i32))) + (import "" "get-rep-R2" (func $get-rep-R2 (param i32) (result i32))) + (import "" "num-live" (func $num-live (result i32))) + (memory 1) + + (func $run (export "run") (result i32) + (local $ret i32) + (local $h1 i32) (local $h2 i32) (local $h3 i32) (local $h4 i32) + + ;; create 4 resources + (local.set $h1 (call $make-R1)) + (if (i32.ne (i32.const 1) (local.get $h1)) + (then unreachable)) + (local.set $h2 (call $make-R2)) + (if (i32.ne (i32.const 2) (local.get $h2)) + (then unreachable)) + (local.set $h3 (call $make-R1)) + (if (i32.ne (i32.const 3) (local.get $h3)) + (then unreachable)) + (local.set $h4 (call $make-R2)) + (if (i32.ne (i32.const 4) (local.get $h4)) + (then unreachable)) + (if (i32.ne (i32.const 4) (call $num-live)) + (then unreachable)) + + ;; use and destroy resources + (if (i32.ne (i32.const 0x81) (call $get-rep-R2 (local.get $h2))) + (then unreachable)) + (call $R2.resource.drop (local.get $h2)) + (if (i32.ne (i32.const 0x41) (call $get-rep-R1 (local.get $h1))) + (then unreachable)) + (call $R1.resource.drop (local.get $h1)) + (if (i32.ne (i32.const 0x82) (call $get-rep-R2 (local.get $h4))) + (then unreachable)) + (call $R2.resource.drop (local.get $h4)) + (if (i32.ne (i32.const 0x42) (call $get-rep-R1 (local.get $h3))) + (then unreachable)) + (call $R1.resource.drop (local.get $h3)) + + ;; everything should be destroyed + (if (i32.ne (i32.const 0) (call $num-live)) + (then unreachable)) + + (i32.const 42) + ) + ) + (alias export $c "R1" (type $R1)) + (alias export $c "R2" (type $R2)) + (canon resource.drop $R1 (core func $R1.resource.drop)) + (canon resource.drop $R2 (core func $R2.resource.drop)) + (canon lower (func $c "make-R1") (core func $make-R1')) + (canon lower (func $c "make-R2") (core func $make-R2')) + (canon lower (func $c "get-rep-R1") (core func $get-rep-R1')) + (canon lower (func $c "get-rep-R2") (core func $get-rep-R2')) + (canon lower (func $c "num-live") (core func $num-live')) + (core instance $dm (instantiate $DM (with "" (instance + (export "R1.resource.drop" (func $R1.resource.drop)) + (export "R2.resource.drop" (func $R2.resource.drop)) + (export "make-R1" (func $make-R1')) + (export "make-R2" (func $make-R2')) + (export "get-rep-R1" (func $get-rep-R1')) + (export "get-rep-R2" (func $get-rep-R2')) + (export "num-live" (func $num-live')) + )))) + (func (export "run") (result u32) (canon lift (core func $dm "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "run") (alias export $d "run")) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/validation/implements.wast b/parser/src/test/resources/spec-tests/validation/implements.wast new file mode 100644 index 0000000..7df0024 --- /dev/null +++ b/parser/src/test/resources/spec-tests/validation/implements.wast @@ -0,0 +1,108 @@ +;; valid usages of `implements` +(component + (component + (import "a" (implements "a:b/c") (instance)) + (import "b" (implements "a:b/c") (instance)) + (import "c" (implements "a:b/c@1.0.0") (instance)) + (import "my-label" (implements "ns:pkg/iface") (instance)) + (import "a:b/c" (instance)) + (import "a:b/c@1.0.0" (instance)) + + (instance $a) + + (export "a" (implements "a:b/c") (instance $a)) + (export "b" (implements "a:b/c") (instance $a)) + (export "c" (implements "a:b/c@1.0.0") (instance $a)) + (export "my-label" (implements "ns:pkg/iface") (instance $a)) + (export "a:b/c" (instance $a)) + (export "a:b/c@1.0.0" (instance $a)) + ) + + (type (instance + (export "a" (implements "a:b/c") (instance)) + )) + (type (component + (import "a" (implements "a:b/c") (instance)) + (export "a" (implements "a:b/c") (instance)) + )) + + (instance $a) + (instance + (export "a" (implements "a:b/c") (instance $a)) + ) +) + +;; invalid, `not-valid` should be something like `a:b/c` +(assert_invalid + (component (import "a" (implements "not-valid") (instance))) + "must be an interface") + +;; invalid, `""` must be a valid kebab-name. +(assert_invalid + (component (import "a" (implements "") (instance))) + "not a valid name") + +;; invalid, can't import the same plain-name twice. +(assert_invalid + (component + (import "a" (implements "a:b/c") (instance)) + (import "a" (implements "a:b/c") (instance)) + ) + "conflicts with previous name") + +;; invalid, can't import the same plain-name twice. +(assert_invalid + (component + (import "a" (implements "a1:b/c") (instance)) + (import "a" (implements "a2:b/c") (instance)) + ) + "conflicts with previous name") + +;; invalid, can't import the same plain-name twice. +(assert_invalid + (component + (import "a" (implements "a:b/c") (instance)) + (import "a" (implements "a:b/c@1.0.0") (instance)) + ) + "conflicts with previous name") + +;; invalid, can't import the same plain-name twice. +(assert_invalid + (component + (import "a" (instance)) + (import "a" (implements "a:b/c") (instance)) + ) + "conflicts with previous name") + +;; invalid, `implements` can only be used by imports/exports typed as `instance` +(assert_invalid + (component + (import "a" (implements "a:b/c") (func)) + ) + "only instance names can have an `implements`") + +;; invalid, `implements` can only be used by imports/exports named with a +;; plainname. +(assert_invalid + (component + (import "a1:b/c" (implements "a2:b/c") (instance)) + ) + "name `a1:b/c` is not valid with `implements`") + +;; validity checks apply to other locations of `implements`, such as +;; component/instance types and bag-of-exports. +(assert_invalid + (component (type (component (import "a" (implements "not-valid") (instance))))) + "must be an interface") +(assert_invalid + (component (type (component (export "a" (implements "") (instance))))) + "not a valid name") +(assert_invalid + (component (type (instance (export "a" (implements "a:b/c") (func))))) + "only instance names") +(assert_invalid + (component + (instance) + (instance (export "x" (implements "a") (instance 0))) + ) + "must be an interface") diff --git a/parser/src/test/resources/spec-tests/values/strings.wast b/parser/src/test/resources/spec-tests/values/strings.wast new file mode 100644 index 0000000..e838ccd --- /dev/null +++ b/parser/src/test/resources/spec-tests/values/strings.wast @@ -0,0 +1,136 @@ +(component + (core module $M + (memory (export "mem") 1) + (func (export "f1") (result i32) + (i32.store (i32.const 0) (i32.const 8)) + (i32.store (i32.const 4) (i32.const 1)) + (i32.store8 (i32.const 8) (i32.const 97)) + (i32.const 0) + ) + (func (export "f2") (result i32) + (i32.store (i32.const 0) (i32.const 8)) + (i32.store (i32.const 4) (i32.const 14)) + (i64.store (i32.const 8) (i64.const 0xb8_ef_ba_98_e2_83_98_e2)) + (i32.store (i32.const 16) (i32.const 0xe3_b6_c3_8f)) + (i32.store16 (i32.const 20) (i32.const 0x84_83)) + (i32.const 0) + ) + ;; TODO: so many cases left to test, everyone feel free to fill in... + ) + (core instance $m (instantiate $M)) + (func (export "f1") (result string) (canon lift (core func $m "f1") (memory $m "mem"))) + (func (export "f2") (result string) (canon lift (core func $m "f2") (memory $m "mem"))) +) +(assert_return (invoke "f1") (str.const "a")) +(assert_return (invoke "f2") (str.const "☃☺️öツ")) + +;; empty string with ptr=0, len=0 +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 0)) + (i32.store (i32.const 4) (i32.const 0)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_return (invoke "f") (str.const "")) + +;; empty string with non-zero in-bounds ptr, len=0 +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 100)) + (i32.store (i32.const 4) (i32.const 0)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_return (invoke "f") (str.const "")) + +;; out-of-bounds pointer traps even with len=0 +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 0xdeadbeef)) + (i32.store (i32.const 4) (i32.const 0)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_trap (invoke "f") "string pointer/length out of bounds of memory") + +;; invalid UTF-8: 0xFF is never valid +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 8)) + (i32.store (i32.const 4) (i32.const 1)) + (i32.store8 (i32.const 8) (i32.const 0xff)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_trap (invoke "f") "invalid utf-8") + +;; truncated multibyte UTF-8: leading byte 0xC3 expects a continuation byte +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 8)) + (i32.store (i32.const 4) (i32.const 1)) + (i32.store8 (i32.const 8) (i32.const 0xc3)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_trap (invoke "f") "incomplete utf-8 byte sequence") + +;; string at end of memory page boundary +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + ;; place "ok" at the very end of the first page (65536 - 2 = 65534) + (i32.store (i32.const 0) (i32.const 65534)) + (i32.store (i32.const 4) (i32.const 2)) + (i32.store8 (i32.const 65534) (i32.const 111)) ;; 'o' + (i32.store8 (i32.const 65535) (i32.const 107)) ;; 'k' + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_return (invoke "f") (str.const "ok")) + +;; string one byte past end of memory traps +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 65535)) + (i32.store (i32.const 4) (i32.const 2)) + (i32.store8 (i32.const 65535) (i32.const 111)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_trap (invoke "f") "string pointer/length out of bounds of memory") diff --git a/parser/src/test/resources/spec-tests/values/trap-in-post-return.wast b/parser/src/test/resources/spec-tests/values/trap-in-post-return.wast new file mode 100644 index 0000000..9ed38e2 --- /dev/null +++ b/parser/src/test/resources/spec-tests/values/trap-in-post-return.wast @@ -0,0 +1,249 @@ +;; $D exports one function for each place in the spec where may_leave is +;; guarded to be true and ensures that the call traps before any other guard. +;; Since each trap tears down the instance, a fresh instance of $Tester is +;; created for each export call. +(component definition $Tester + (component $C + (core module $CM + (func (export "import")) + ) + (core instance $cm (instantiate $CM)) + (func (export "import") (canon lift (core func $cm "import"))) + ) + (component $D + (import "import" (func $import)) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (type $R (resource (rep i32))) + (type $ST (stream u32)) + (type $FT (future u32)) + (canon resource.new $R (core func $resource.new)) + (canon resource.drop $R (core func $resource.drop)) + (canon task.return (core func $task.return)) + (canon task.cancel (core func $task.cancel)) + (canon thread.yield (core func $yield)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon waitable-set.poll (memory $memory "mem") (core func $waitable-set.poll)) + (canon waitable-set.drop (core func $waitable-set.drop)) + (canon waitable.join (core func $waitable.join)) + (canon subtask.cancel (core func $subtask.cancel)) + (canon subtask.drop (core func $subtask.drop)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST (memory $memory "mem") (core func $stream.write)) + (canon stream.cancel-read $ST (core func $stream.cancel-read)) + (canon stream.cancel-write $ST (core func $stream.cancel-write)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (canon future.new $FT (core func $future.new)) + (canon future.read $FT (memory $memory "mem") (core func $future.read)) + (canon future.write $FT (memory $memory "mem") (core func $future.write)) + (canon future.cancel-read $FT (core func $future.cancel-read)) + (canon future.cancel-write $FT (core func $future.cancel-write)) + (canon future.drop-readable $FT (core func $future.drop-readable)) + (canon future.drop-writable $FT (core func $future.drop-writable)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "import" (func $import)) + (import "" "resource.new" (func $resource.new (param i32) (result i32))) + (import "" "resource.drop" (func $resource.drop (param i32))) + (import "" "task.return" (func $task.return)) + (import "" "task.cancel" (func $task.cancel)) + (import "" "yield" (func $yield (result i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "waitable-set.poll" (func $waitable-set.poll (param i32 i32) (result i32))) + (import "" "waitable-set.drop" (func $waitable-set.drop (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) + (import "" "subtask.drop" (func $subtask.drop (param i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.cancel-read" (func $stream.cancel-read (param i32) (result i32))) + (import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "future.cancel-read" (func $future.cancel-read (param i32) (result i32))) + (import "" "future.cancel-write" (func $future.cancel-write (param i32) (result i32))) + (import "" "future.drop-readable" (func $future.drop-readable (param i32))) + (import "" "future.drop-writable" (func $future.drop-writable (param i32))) + + (func (export "noop")) + (func (export "trap-calling-import") (call $import)) + (func (export "trap-calling-resource-new") (drop (call $resource.new (i32.const 0)))) + (func (export "trap-calling-resource-drop") (call $resource.drop (i32.const 0))) + (func (export "trap-calling-task-return") (call $task.return)) + (func (export "trap-calling-task-cancel") (call $task.cancel)) + (func (export "trap-calling-yield") (drop (call $yield))) + (func (export "trap-calling-waitable-set-new") (drop (call $waitable-set.new))) + (func (export "trap-calling-waitable-set-wait") (drop (call $waitable-set.wait (i32.const 0) (i32.const 0)))) + (func (export "trap-calling-waitable-set-poll") (drop (call $waitable-set.poll (i32.const 0) (i32.const 0)))) + (func (export "trap-calling-waitable-set-drop") (call $waitable-set.drop (i32.const 0))) + (func (export "trap-calling-waitable-join") (call $waitable.join (i32.const 0) (i32.const 0))) + (func (export "trap-calling-subtask-cancel") (drop (call $subtask.cancel (i32.const 0)))) + (func (export "trap-calling-subtask-drop") (call $subtask.drop (i32.const 0))) + (func (export "trap-calling-stream-new") (drop (call $stream.new))) + (func (export "trap-calling-stream-read") (drop (call $stream.read (i32.const 0) (i32.const 0) (i32.const 0)))) + (func (export "trap-calling-stream-write") (drop (call $stream.write (i32.const 0) (i32.const 0) (i32.const 0)))) + (func (export "trap-calling-stream-cancel-read") (drop (call $stream.cancel-read (i32.const 0)))) + (func (export "trap-calling-stream-cancel-write") (drop (call $stream.cancel-write (i32.const 0)))) + (func (export "trap-calling-stream-drop-readable") (call $stream.drop-readable (i32.const 0))) + (func (export "trap-calling-stream-drop-writable") (call $stream.drop-writable (i32.const 0))) + (func (export "trap-calling-future-new") (drop (call $future.new))) + (func (export "trap-calling-future-read") (drop (call $future.read (i32.const 0) (i32.const 0)))) + (func (export "trap-calling-future-write") (drop (call $future.write (i32.const 0) (i32.const 0)))) + (func (export "trap-calling-future-cancel-read") (drop (call $future.cancel-read (i32.const 0)))) + (func (export "trap-calling-future-cancel-write") (drop (call $future.cancel-write (i32.const 0)))) + (func (export "trap-calling-future-drop-readable") (call $future.drop-readable (i32.const 0))) + (func (export "trap-calling-future-drop-writable") (call $future.drop-writable (i32.const 0))) + ) + (canon lower (func $import) (core func $import')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "import" (func $import')) + (export "resource.new" (func $resource.new)) + (export "resource.drop" (func $resource.drop)) + (export "task.return" (func $task.return)) + (export "task.cancel" (func $task.cancel)) + (export "yield" (func $yield)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "waitable-set.poll" (func $waitable-set.poll)) + (export "waitable-set.drop" (func $waitable-set.drop)) + (export "waitable.join" (func $waitable.join)) + (export "subtask.cancel" (func $subtask.cancel)) + (export "subtask.drop" (func $subtask.drop)) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "stream.cancel-read" (func $stream.cancel-read)) + (export "stream.cancel-write" (func $stream.cancel-write)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "stream.drop-writable" (func $stream.drop-writable)) + (export "future.new" (func $future.new)) + (export "future.read" (func $future.read)) + (export "future.write" (func $future.write)) + (export "future.cancel-read" (func $future.cancel-read)) + (export "future.cancel-write" (func $future.cancel-write)) + (export "future.drop-readable" (func $future.drop-readable)) + (export "future.drop-writable" (func $future.drop-writable)) + )))) + (func (export "trap-calling-import") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-import")))) + (func (export "trap-calling-resource-new") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-resource-new")))) + (func (export "trap-calling-resource-drop") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-resource-drop")))) + (func (export "trap-calling-task-return") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-task-return")))) + (func (export "trap-calling-task-cancel") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-task-cancel")))) + (func (export "trap-calling-yield") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-yield")))) + (func (export "trap-calling-waitable-set-new") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-waitable-set-new")))) + (func (export "trap-calling-waitable-set-wait") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-waitable-set-wait")))) + (func (export "trap-calling-waitable-set-poll") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-waitable-set-poll")))) + (func (export "trap-calling-waitable-set-drop") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-waitable-set-drop")))) + (func (export "trap-calling-waitable-join") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-waitable-join")))) + (func (export "trap-calling-subtask-cancel") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-subtask-cancel")))) + (func (export "trap-calling-subtask-drop") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-subtask-drop")))) + (func (export "trap-calling-stream-new") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-new")))) + (func (export "trap-calling-stream-read") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-read")))) + (func (export "trap-calling-stream-write") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-write")))) + (func (export "trap-calling-stream-cancel-read") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-cancel-read")))) + (func (export "trap-calling-stream-cancel-write") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-cancel-write")))) + (func (export "trap-calling-stream-drop-readable") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-drop-readable")))) + (func (export "trap-calling-stream-drop-writable") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-drop-writable")))) + (func (export "trap-calling-future-new") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-new")))) + (func (export "trap-calling-future-read") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-read")))) + (func (export "trap-calling-future-write") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-write")))) + (func (export "trap-calling-future-cancel-read") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-cancel-read")))) + (func (export "trap-calling-future-cancel-write") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-cancel-write")))) + (func (export "trap-calling-future-drop-readable") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-drop-readable")))) + (func (export "trap-calling-future-drop-writable") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-drop-writable")))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "import" (func $c "import")))) + (func (export "trap-calling-import") (alias export $d "trap-calling-import")) + (func (export "trap-calling-resource-new") (alias export $d "trap-calling-resource-new")) + (func (export "trap-calling-resource-drop") (alias export $d "trap-calling-resource-drop")) + (func (export "trap-calling-task-return") (alias export $d "trap-calling-task-return")) + (func (export "trap-calling-task-cancel") (alias export $d "trap-calling-task-cancel")) + (func (export "trap-calling-yield") (alias export $d "trap-calling-yield")) + (func (export "trap-calling-waitable-set-new") (alias export $d "trap-calling-waitable-set-new")) + (func (export "trap-calling-waitable-set-wait") (alias export $d "trap-calling-waitable-set-wait")) + (func (export "trap-calling-waitable-set-poll") (alias export $d "trap-calling-waitable-set-poll")) + (func (export "trap-calling-waitable-set-drop") (alias export $d "trap-calling-waitable-set-drop")) + (func (export "trap-calling-waitable-join") (alias export $d "trap-calling-waitable-join")) + (func (export "trap-calling-subtask-cancel") (alias export $d "trap-calling-subtask-cancel")) + (func (export "trap-calling-subtask-drop") (alias export $d "trap-calling-subtask-drop")) + (func (export "trap-calling-stream-new") (alias export $d "trap-calling-stream-new")) + (func (export "trap-calling-stream-read") (alias export $d "trap-calling-stream-read")) + (func (export "trap-calling-stream-write") (alias export $d "trap-calling-stream-write")) + (func (export "trap-calling-stream-cancel-read") (alias export $d "trap-calling-stream-cancel-read")) + (func (export "trap-calling-stream-cancel-write") (alias export $d "trap-calling-stream-cancel-write")) + (func (export "trap-calling-stream-drop-readable") (alias export $d "trap-calling-stream-drop-readable")) + (func (export "trap-calling-stream-drop-writable") (alias export $d "trap-calling-stream-drop-writable")) + (func (export "trap-calling-future-new") (alias export $d "trap-calling-future-new")) + (func (export "trap-calling-future-read") (alias export $d "trap-calling-future-read")) + (func (export "trap-calling-future-write") (alias export $d "trap-calling-future-write")) + (func (export "trap-calling-future-cancel-read") (alias export $d "trap-calling-future-cancel-read")) + (func (export "trap-calling-future-cancel-write") (alias export $d "trap-calling-future-cancel-write")) + (func (export "trap-calling-future-drop-readable") (alias export $d "trap-calling-future-drop-readable")) + (func (export "trap-calling-future-drop-writable") (alias export $d "trap-calling-future-drop-writable")) +) + +(component instance $i1 $Tester) +(assert_trap (invoke "trap-calling-import") "cannot leave component instance") +(component instance $i2 $Tester) +(assert_trap (invoke "trap-calling-resource-new") "cannot leave component instance") +(component instance $i3 $Tester) +(assert_trap (invoke "trap-calling-resource-drop") "cannot leave component instance") +(component instance $i4 $Tester) +(assert_trap (invoke "trap-calling-task-return") "cannot leave component instance") +(component instance $i5 $Tester) +(assert_trap (invoke "trap-calling-task-cancel") "cannot leave component instance") +(component instance $i6 $Tester) +(assert_trap (invoke "trap-calling-yield") "cannot leave component instance") +(component instance $i7 $Tester) +(assert_trap (invoke "trap-calling-waitable-set-new") "cannot leave component instance") +(component instance $i8 $Tester) +(assert_trap (invoke "trap-calling-waitable-set-wait") "cannot leave component instance") +(component instance $i9 $Tester) +(assert_trap (invoke "trap-calling-waitable-set-poll") "cannot leave component instance") +(component instance $i10 $Tester) +(assert_trap (invoke "trap-calling-waitable-set-drop") "cannot leave component instance") +(component instance $i11 $Tester) +(assert_trap (invoke "trap-calling-waitable-join") "cannot leave component instance") +(component instance $i12 $Tester) +(assert_trap (invoke "trap-calling-subtask-cancel") "cannot leave component instance") +(component instance $i13 $Tester) +(assert_trap (invoke "trap-calling-subtask-drop") "cannot leave component instance") +(component instance $i14 $Tester) +(assert_trap (invoke "trap-calling-stream-new") "cannot leave component instance") +(component instance $i15 $Tester) +(assert_trap (invoke "trap-calling-stream-read") "cannot leave component instance") +(component instance $i16 $Tester) +(assert_trap (invoke "trap-calling-stream-write") "cannot leave component instance") +(component instance $i17 $Tester) +(assert_trap (invoke "trap-calling-stream-cancel-read") "cannot leave component instance") +(component instance $i18 $Tester) +(assert_trap (invoke "trap-calling-stream-cancel-write") "cannot leave component instance") +(component instance $i19 $Tester) +(assert_trap (invoke "trap-calling-stream-drop-readable") "cannot leave component instance") +(component instance $i20 $Tester) +(assert_trap (invoke "trap-calling-stream-drop-writable") "cannot leave component instance") +(component instance $i21 $Tester) +(assert_trap (invoke "trap-calling-future-new") "cannot leave component instance") +(component instance $i22 $Tester) +(assert_trap (invoke "trap-calling-future-read") "cannot leave component instance") +(component instance $i23 $Tester) +(assert_trap (invoke "trap-calling-future-write") "cannot leave component instance") +(component instance $i24 $Tester) +(assert_trap (invoke "trap-calling-future-cancel-read") "cannot leave component instance") +(component instance $i25 $Tester) +(assert_trap (invoke "trap-calling-future-cancel-write") "cannot leave component instance") +(component instance $i26 $Tester) +(assert_trap (invoke "trap-calling-future-drop-readable") "cannot leave component instance") +(component instance $i27 $Tester) +(assert_trap (invoke "trap-calling-future-drop-writable") "cannot leave component instance") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/adapt.wast b/parser/src/test/resources/spec-tests/wasm-tools/adapt.wast new file mode 100644 index 0000000..8cc76f8 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/adapt.wast @@ -0,0 +1,287 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (import "log" (func $log (param "msg" string))) + (core module $libc + (memory (export "memory") 1) + (func (export "canonical_abi_realloc") (param i32 i32 i32 i32) (result i32) + unreachable) + ) + + (core module $my_module + (import "env" "log-utf8" (func $log_utf8 (param i32 i32))) + (import "env" "log-utf16" (func $log_utf16 (param i32 i32))) + (import "env" "log-compact-utf16" (func $log_compact_utf16 (param i32 i32))) + + (func (export "log-utf8") (param i32 i32) + local.get 0 + local.get 1 + call $log_utf8 + ) + (func (export "log-utf16") (param i32 i32) + local.get 0 + local.get 1 + call $log_utf16 + ) + (func (export "log-compact-utf16") (param i32 i32) + local.get 0 + local.get 1 + call $log_compact_utf16 + ) + ) + + (core instance $libc (instantiate $libc)) + + (alias core export $libc "canonical_abi_realloc" (core func $realloc)) + (alias core export $libc "memory" (core memory $memory)) + (core func $log_lower_utf8 (canon lower (func $log) string-encoding=utf8 (memory $memory) (realloc $realloc))) + (core func $log_lower_utf16 (canon lower (func $log) string-encoding=utf16 (memory $memory) (realloc $realloc))) + (core func $log_lower_compact_utf16 (canon lower (func $log) string-encoding=latin1+utf16 (memory $memory) (realloc $realloc))) + + (core instance $my_instance (instantiate $my_module + (with "libc" (instance $libc)) + (with "env" (instance + (export "log-utf8" (func $log_lower_utf8)) + (export "log-utf16" (func $log_lower_utf16)) + (export "log-compact-utf16" (func $log_lower_compact_utf16)) + )) + )) + + (func (export "log1") (param "msg" string) + (canon lift + (core func $my_instance "log-utf8") + string-encoding=utf8 + (memory $memory) + (realloc $realloc) + ) + ) + (func (export "log2") (param "msg" string) + (canon lift + (core func $my_instance "log-utf16") + string-encoding=utf16 + (memory $memory) + (realloc $realloc) + ) + ) + (func (export "log3") (param "msg" string) + (canon lift + (core func $my_instance "log-compact-utf16") + string-encoding=latin1+utf16 + (memory $memory) + (realloc $realloc) + ) + ) +) + +(assert_invalid + (component + (import "i" (func $f)) + (core func (canon lower (func $f) string-encoding=utf8 string-encoding=utf16)) + ) + "canonical encoding option `utf8` conflicts with option `utf16`") + +(assert_invalid + (component + (import "i" (func $f)) + (core func (canon lower (func $f) string-encoding=utf8 string-encoding=latin1+utf16)) + ) + "canonical encoding option `utf8` conflicts with option `latin1-utf16`") + +(assert_invalid + (component + (import "i" (func $f)) + (core func (canon lower (func $f) string-encoding=utf16 string-encoding=latin1+utf16)) + ) + "canonical encoding option `utf16` conflicts with option `latin1-utf16`") + +(assert_invalid + (component + (import "i" (func $f)) + (core func (canon lower (func $f) (memory 0))) + ) + "memory index out of bounds") + +(assert_invalid + (component + (import "i" (func $f)) + (core module $m (memory (export "memory") 1)) + (core instance $i (instantiate $m)) + (core func (canon lower (func $f) (memory $i "memory") (memory $i "memory"))) + ) + "`memory` is specified more than once") + +(assert_invalid + (component + (core module $m + (func (export "f") (param i32 i32)) + ) + (core instance $i (instantiate $m)) + (func (param "p1" (list u8)) (canon lift (core func $i "f"))) + ) + "canonical option `memory` is required") + +(assert_invalid + (component + (core module $m + (memory (export "m") 1) + (func (export "f") (param i32 i32)) + ) + (core instance $i (instantiate $m)) + (func (param "p1" (list u8)) + (canon lift (core func $i "f") + (memory $i "m") + ) + ) + ) + "canonical option `realloc` is required") + +(assert_invalid + (component + (core module $m + (memory (export "m") 1) + (func (export "f") (param i32 i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + ) + (core instance $i (instantiate $m)) + (func (param "p1" (list u8)) + (canon lift (core func $i "f") + (memory $i "m") + (realloc (func $i "r")) + (realloc (func $i "r")) + ) + ) + ) + "canonical option `realloc` is specified more than once") + +(assert_invalid + (component + (core module $m + (memory (export "m") 1) + (func (export "f") (param i32 i32)) + (func (export "r")) + ) + (core instance $i (instantiate $m)) + (func (param "p1" (list u8)) + (canon lift (core func $i "f") + (memory $i "m") + (realloc (func $i "r")) + ) + ) + ) + "canonical option `realloc` uses a core function with an incorrect signature") + +(assert_invalid + (component + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + (func (export "p")) + ) + (core instance $i (instantiate $m)) + (func (result string) + (canon lift (core func $i "f") + (memory $i "m") + (realloc (func $i "r")) + (post-return (func $i "p")) + ) + ) + ) + "canonical option `post-return` uses a core function with an incorrect signature") + +(assert_invalid + (component + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + (func (export "p") (param i32)) + ) + (core instance $i (instantiate $m)) + (func (result string) + (canon lift (core func $i "f") + (memory $i "m") + (realloc (func $i "r")) + (post-return (func $i "p")) + (post-return (func $i "p")) + ) + ) + ) + "canonical option `post-return` is specified more than once") + +(assert_invalid + (component + (import "i" (func $f (param "p1" string))) + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + (func (export "p") (param i32)) + ) + (core instance $i (instantiate $m)) + (core func + (canon lower (func $f) + (memory $i "m") + (realloc (func $i "r")) + (post-return (func $i "p")) + ) + ) + ) + "canonical option `post-return` cannot be specified for lowerings") + +(component + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32) unreachable) + (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable) + (func (export "p") (param i32)) + ) + (core instance $i (instantiate $m)) + (func (result string) + (canon lift (core func $i "f") + (memory $i "m") + (realloc (func $i "r")) + (post-return (func $i "p")) + ) + ) +) + +(assert_malformed + (component quote + "(core module $m (func (export \"\")))" + "(core instance $i (instantiate $m))" + "(core func (canon lower (func $i \"\")))" + ) + "unknown instance: failed to find name `$i`") + +(assert_invalid + (component + (core module $m (func (export "foo") (param i32))) + (core instance $i (instantiate $m)) + (func (export "foo") (canon lift (core func $i "foo"))) + ) + "lowered parameter types `[]` do not match parameter types `[I32]`") + +(assert_invalid + (component + (core module $m (func (export "foo") (result i32))) + (core instance $i (instantiate $m)) + (func (export "foo") (canon lift (core func $i "foo"))) + ) + "lowered result types `[]` do not match result types `[I32]`") + +(assert_invalid + (component + (type $f string) + (core module $m (func (export "foo"))) + (core instance $i (instantiate $m)) + (func (export "foo") (type $f) (canon lift (core func $i "foo"))) + ) + "not a function type") + +(assert_malformed + (component quote + "(import \"a\" (func $f))" + "(func (export \"foo\") (canon lift (core func $f)))" + ) + "unknown core func: failed to find name `$f`") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/alias.wast b/parser/src/test/resources/spec-tests/wasm-tools/alias.wast new file mode 100644 index 0000000..dd9d1b3 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/alias.wast @@ -0,0 +1,301 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (component + (import "i" (instance $i + (export "f1" (func)) + (export "f2" (func (param "p1" string))) + )) + (export "run" (func $i "f1")) + ) +) + +(component + (component + (import "i" (component $c + (export "f1" (func)) + (export "f2" (func (param "p1" string))) + )) + (instance $i (instantiate $c)) + (export "run" (func $i "f1")) + ) +) + +(component definition + (import "i" (core module $m + (export "f1" (func $f1)) + (export "f2" (func $f2 (param i32))) + )) + (core instance $i (instantiate $m)) + + (core module $m2 (import "" "" (func))) + + (core instance (instantiate $m2 (with "" (instance (export "" (func $i "f1")))))) +) + +(component definition + (import "a" (core module $libc + (export "memory" (memory 1)) + (export "table" (table 0 funcref)) + (export "func" (func)) + (export "global" (global i32)) + (export "global mut" (global (mut i64))) + )) + (core instance $libc (instantiate $libc)) + (alias core export $libc "memory" (core memory $mem)) + (alias core export $libc "table" (core table $tbl)) + (alias core export $libc "func" (core func $func)) + (alias core export $libc "global" (core global $global)) + (alias core export $libc "global mut" (core global $global_mut)) + + (import "x" (core module $needs_libc + (import "" "memory" (memory 1)) + (import "" "table" (table 0 funcref)) + (import "" "func" (func)) + (import "" "global" (global i32)) + (import "" "global mut" (global (mut i64))) + )) + + (core instance (instantiate $needs_libc (with "" (instance + (export "memory" (memory $mem)) + (export "table" (table $tbl)) + (export "func" (func $func)) + (export "global" (global $global)) + (export "global mut" (global $global_mut)) + )))) +) + +(component + (component + (import "a" (instance $i + (export "a" (func)) + (export "b" (core module)) + (export "c" (instance)) + )) + (export "b" (func $i "a")) + (export "c" (core module $i "b")) + (export "d" (instance $i "c")) + ) +) + + +(component definition + (import "a" (core module $libc + (export "memory" (memory 1)) + (export "table" (table 0 funcref)) + (export "func" (func)) + (export "global" (global i32)) + (export "global mut" (global (mut i64))) + )) + + (import "b" (core module $needs_libc + (import "" "memory" (memory 1)) + (import "" "table" (table 0 funcref)) + (import "" "func" (func)) + (import "" "global" (global i32)) + (import "" "global mut" (global (mut i64))) + )) + + (core instance $libc (instantiate $libc)) + (core instance (instantiate $needs_libc (with "" (instance + (export "memory" (memory $libc "memory")) + (export "table" (table $libc "table")) + (export "func" (func $libc "func")) + (export "global" (global $libc "global")) + (export "global mut" (global $libc "global mut")) + )))) +) + +(assert_invalid + (component + (import "a" (instance (export "a" (func)))) + (export "a" (core module 0 "a")) + ) + "export `a` for instance 0 is not a module") + +(assert_invalid + (component + (component + (component (export "a")) + ) + (instance (instantiate 0)) + (export "a" (core module 0 "a")) + ) + "export `a` for instance 0 is not a module") + +(assert_invalid + (component + (import "a" (core module)) + (core instance (instantiate 0)) + (alias core export 0 "a" (core func)) + ) + "core instance 0 has no export named `a`") + +(assert_invalid + (component + (core module) + (core instance (instantiate 0)) + (alias core export 0 "a" (core func)) + ) + "core instance 0 has no export named `a`") + +(assert_invalid + (component + (import "a" (component)) + (instance (instantiate 0)) + (alias export 0 "a" (func)) + ) + "instance 0 has no export named `a`") + +(assert_invalid + (component + (import "a" (core module $a (export "" (func)))) + (import "b" (core module $b (import "" "" (func (param i32))))) + + (core instance $a (instantiate $a)) + (core instance $b (instantiate $b (with "" (instance $a)))) + ) + "type mismatch") + +;; aliasing various items works + +(component $PARENT + (type $t (func (result string))) + (component + (import "a" (func (type $t))) + ) + (component + (alias outer $PARENT $t (type $my_type)) + (alias outer 0 $my_type (type $my_type_again)) + (import "a" (func (type $my_type_again))) + ) +) + +(component + (type $a (func (result string))) + (component + (type $b (func (result u32))) + (component + (type $c (func (result s32))) + + (component + (import "a" (func $a (type $a))) + (import "b" (func $b (type $b))) + (import "c" (func $c (type $c))) + + (import "d" (component $C + (import "a" (func (result string))) + (import "b" (func (result u32))) + (import "c" (func (result s32))) + )) + + (instance (instantiate $C + (with "a" (func $a)) + (with "b" (func $b)) + (with "c" (func $c)) + )) + ) + ) + ) +) + +;; multiple projections in alias sugar +(component + (component $a + (import "a" (instance $a + (export "a" (instance + (export "a" (instance + (export "a" (instance + (export "a" (func)) + )) + )) + )) + )) + + (import "b" (component $b (import "a" (func)))) + + (instance (instantiate $b + (with "a" (func $a "a" "a" "a" "a")) + )) + ) +) + +;; alias some constructs +(component + (component + (import "a" (instance $foo (export "v" (component)))) + (export "v" (component $foo "v")) + ) +) + +(component definition + (import "a" (instance $foo (export "v" (core module)))) + (export "v" (core module $foo "v")) +) + +(component $C + (core type $t (func)) + (component $C2 + (alias outer $C $t (core type $t2)) + (component + (alias outer $C $t (core type)) + (alias outer $C2 $t2 (core type)) + ) + ) +) + +(component $C + (core module $m) + (alias outer $C $m (core module $target)) + (export "v" (core module $target)) +) + +(component + (component $C + (component $m) + (alias outer $C $m (component $target)) + (export "v" (component $target)) + ) +) + +(assert_invalid + (component (alias outer 100 0 (core type))) + "invalid outer alias count of 100") + +(assert_invalid + (component (alias outer 0 0 (core type))) + "index out of bounds") + +(assert_invalid + (component (alias outer 100 0 (core module))) + "invalid outer alias count of 100") + +(assert_invalid + (component (alias outer 0 0 (core module))) + "index out of bounds") + +(assert_invalid + (component (alias outer 100 0 (component))) + "invalid outer alias count of 100") + +(assert_invalid + (component (alias outer 0 0 (component))) + "index out of bounds") + +(component definition + (import "a" (instance $i + (export "x" (core module)) + )) + ;; inline alias injection sugar works for module references + (core instance (instantiate (module $i "x"))) +) + +(component + (component + (import "a" (instance $i + (export "x" (component)) + )) + ;; inline alias injection sugar works for component references + (instance (instantiate (component $i "x"))) + ) +) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/big.wast b/parser/src/test/resources/spec-tests/wasm-tools/big.wast new file mode 100644 index 0000000..770df0a --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/big.wast @@ -0,0 +1,36 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (import "wasi-logging" (instance $logging + (export "log" (func (param "msg" string))) + )) + (import "libc" (core module $Libc + (export "memory" (memory 1)) + (export "realloc" (func (param i32 i32 i32 i32) (result i32))) + )) + (core instance $libc (instantiate $Libc)) + (core func $log (canon lower + (func $logging "log") + (memory $libc "memory") (realloc (func $libc "realloc")) + )) + (core module $Main + (import "libc" "memory" (memory 1)) + (import "libc" "realloc" (func (param i32 i32 i32 i32) (result i32))) + (import "wasi-logging" "log" (func $log (param i32 i32))) + (func (export "run") (param i32 i32) (result i32) + (local.get 0) + (local.get 1) + (call $log) + (unreachable) + ) + ) + (core instance $main (instantiate $Main + (with "libc" (instance $libc)) + (with "wasi-logging" (instance (export "log" (func $log)))) + )) + (func $run (param "in" string) (result string) (canon lift + (core func $main "run") + (memory $libc "memory") (realloc (func $libc "realloc")) + )) + (export "run" (func $run)) +) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/definedtypes.wast b/parser/src/test/resources/spec-tests/wasm-tools/definedtypes.wast new file mode 100644 index 0000000..ca24c12 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/definedtypes.wast @@ -0,0 +1,123 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component $C + (type $A1 bool) + (type $A2 u8) + (type $A3 s8) + (type $A4 u16) + (type $A5 s16) + (type $A6 u32) + (type $A7 s32) + (type $A8 u64) + (type $A9 s64) + (type $A10a f32) + (type $A11a f64) + (type $A10b float32) + (type $A11b float64) + (type $A12 char) + (type $A13 string) + + (type $A14b (record (field "x" (tuple char)))) + (type $A14c (record (field "x" $A1))) + + (type $A15a (variant (case "x"))) + (type $A15b (variant (case "x" $A1))) + (type $A15c (variant (case $x "x") (case $y "y" string) (case "z" string))) + (type $A15d (variant (case "x") (case "y" string) (case "z" string))) + + (type $A16a (list (tuple u8))) + (type $A16b (list $A3)) + + (type $A17a (tuple u8)) + (type $A17b (tuple $A4)) + + (type $A18b (flags "x")) + + (type $A19b (enum "x")) + + (type $A21a (option (tuple u32))) + (type $A21b (option $A6)) + + (type $A22a (result)) + (type $A22b (result $A7)) + (type $A22c (result (error $A8))) + (type $A22d (result $A9 (error $A10a))) +) + +(assert_malformed + (component quote + "(type $t string)" + "(type $v (variant (case $x \"x\" $t) (case $x \"y\" $t)))" + ) + "duplicate variant case identifier" +) + +(assert_invalid + (component + (type $t (func)) + (type (func (param "t" $t))) + ) + "type index 0 is not a defined type") + +(assert_invalid + (component + (type $t (instance)) + (type (func (result $t))) + ) + "type index 0 is not a defined type") + +(assert_invalid + (component + (type $t (component)) + (type (option $t)) + ) + "type index 0 is not a defined type") + +(assert_invalid + (component (type (option 0))) + "index out of bounds") +(assert_invalid + (component (type (list 0))) + "index out of bounds") +(assert_invalid + (component (type (record (field "x" 0)))) + "index out of bounds") +(assert_invalid + (component (type (variant (case "x" 0)))) + "index out of bounds") +(assert_invalid + (component (type (result 0 (error 1)))) + "index out of bounds") +(assert_invalid + (component (type (tuple 0))) + "index out of bounds") + +(assert_invalid + (component (type (record (field "a-B-c-D" string) (field "A-b-C-d" u8)))) + "record field name `A-b-C-d` conflicts with previous field name `a-B-c-D`") +(assert_invalid + (component (type (variant (case "x" s64) (case "x" s64)))) + "variant case name `x` conflicts with previous case name `x`") +(assert_invalid + (component (type (flags "x" "y" "X"))) + "flag name `X` conflicts with previous flag name `x`") +(assert_invalid + (component (type (enum "x" "y" "X"))) + "enum tag name `X` conflicts with previous tag name `x`") + +(assert_invalid + (component (type (record (field "" s32)))) + "name cannot be empty") +(assert_invalid + (component (type (variant (case "" s32)))) + "name cannot be empty") +(assert_invalid + (component (type (flags ""))) + "name cannot be empty") +(assert_invalid + (component (type (enum ""))) + "name cannot be empty") + +(assert_invalid + (component (type (variant))) + "variant type must have at least one case") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/empty.wast b/parser/src/test/resources/spec-tests/wasm-tools/empty.wast new file mode 100644 index 0000000..7f22181 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/empty.wast @@ -0,0 +1,4 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; The most minimal component. +(component) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/example.wast b/parser/src/test/resources/spec-tests/wasm-tools/example.wast new file mode 100644 index 0000000..9ba429f --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/example.wast @@ -0,0 +1,17 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; With what's defined so far, we can define the following component: + +(component + (component + (core module (func (export "one") (result i32) (i32.const 1))) + (core module (func (export "two") (result f32) (f32.const 2))) + ) + (core module (func (export "three") (result i64) (i64.const 3))) + (component + (component + (core module (func (export "four") (result f64) (f64.const 4))) + ) + ) + (component) +) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/export-ascription.wast b/parser/src/test/resources/spec-tests/wasm-tools/export-ascription.wast new file mode 100644 index 0000000..ca70736 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/export-ascription.wast @@ -0,0 +1,44 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (component + (import "f" (func $f)) + (export "f2" (func $f) (func)) + ) +) + +;; subtyping works +(component + (component + (import "f" (instance $i (export "f" (func)))) + (export "f2" (instance $i) (instance)) + ) +) + +;; make sure subtyping works in the right direction +(assert_invalid + (component + (import "f" (instance $i)) + (export "f2" (instance $i) (instance (export "f" (func)))) + ) + "ascribed type of export is not compatible") + +;; make sure the type is actually changed +(assert_invalid + (component + (import "f" (func $f)) + + (component $c + (import "f" (instance $i (export "f" (func)))) + (export "f2" (instance $i) (instance)) + ) + + (instance $c (instantiate $c (with "f" (instance (export "f" (func $f)))))) + + (component $consume + (import "arg" (instance $i (export "f" (func)))) + ) + + (instance (instantiate $consume (with "arg" (instance $c "f2")))) + ) + "missing expected export `f`") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/export-introduces-alias.wast b/parser/src/test/resources/spec-tests/wasm-tools/export-introduces-alias.wast new file mode 100644 index 0000000..40d33ef --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/export-introduces-alias.wast @@ -0,0 +1,48 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (component + (import "x" (func $f)) + + (export $g "g" (func $f)) + (export $g2 "g2" (func $g)) + ) +) + +(component + (type (component + (type $t u8) + (import "x" (instance $i (export "t" (type (eq $t))))) + (alias export $i "t" (type $my-t)) + )) +) + +(component + (type (component + (type $t u8) + (import "x" (instance $i + (export "i" (instance + (export "t" (type (eq $t))) + )) + )) + (alias export $i "i" (instance $my-i)) + (alias export $my-i "t" (type $my-t)) + )) +) + +(assert_malformed + (component quote + "(type (instance" + "(type $t u8)" + "(export \"t\" (type $t (eq $t)))" + "))" + ) + "duplicate type identifier") + +(component + (type (instance + (type $t u8) + (export "t" (type $t2 (eq $t))) + (export "t2" (type $t3 (eq $t2))) + )) +) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/export.wast b/parser/src/test/resources/spec-tests/wasm-tools/export.wast new file mode 100644 index 0000000..73d094c --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/export.wast @@ -0,0 +1,63 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component (export "" (instance 0))) + "index out of bounds") + +(assert_invalid + (component (export "" (component 0))) + "index out of bounds") + +(assert_invalid + (component (export "" (core module 0))) + "index out of bounds") + +(assert_invalid + (component (export "" (func 0))) + "index out of bounds") + +(component + (component + (import "a" (instance $i)) + (import "b" (core module $m)) + (import "c" (component $c)) + (import "e" (func $f)) + + (export "f" (instance $i)) + (export "g" (core module $m)) + (export "h" (component $c)) + (export "j" (func $f)) + ) +) + +(component + (component + (import "a" (func)) + (export (interface "wasi:http/types@2.0.0") (func 0)) + ) +) + +;; import/exports can overlap on ids +(component + (component + (import (interface "wasi:http/types@2.0.0") (func)) + (export (interface "wasi:http/types@2.0.0") (func 0)) + ) +) + +;; cannot export some types of strings +(assert_invalid + (component (type (component (export "integrity=" (func))))) + "not a valid export name") +(assert_invalid + (component (type (component (export "url=" (func))))) + "not a valid export name") +(assert_invalid + (component (type (component (export "relative-url=" (func))))) + "not a valid extern name") +(assert_invalid + (component (type (component (export "locked-dep=" (func))))) + "not a valid export name") +(assert_invalid + (component (type (component (export "unlocked-dep=" (func))))) + "not a valid export name") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/func.wast b/parser/src/test/resources/spec-tests/wasm-tools/func.wast new file mode 100644 index 0000000..4a207f9 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/func.wast @@ -0,0 +1,146 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (import "a" (func (param "foo" string))) + (import "b" (func (param "foo" string) (param "bar" s32) (param "baz" u32))) + (import "c" (func (result (tuple u8)))) +) + +(component definition + (import "a" (func)) + (import "b" (func (param "p1" string))) + (import "c" (func (result u32))) + (import "d" (func (param "p1" bool) (result string))) +) + + +(assert_invalid + (component + (type (func (param "foo" string) (param "FOO" u32))) + ) + "function parameter name `FOO` conflicts with previous parameter name `foo`" +) + +(assert_invalid + (component + (core module $m + (memory (export "memory") 1) + (func (export "foo") (result i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "tuple") (result (tuple s8 u8)) + (canon lift (core func $i "foo")) + ) + ) + "canonical option `memory` is required" +) + +(component definition + (import "a" (func $log (param "msg" string))) + (core module $libc + (memory (export "memory") 1) + ) + (core instance $libc (instantiate $libc)) + (core func (canon lower (func $log) (memory $libc "memory"))) +) + +(component + (core module $m + (memory (export "memory") 1) + (func (export "ret-list") (result i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "ret-list") (result (list u8)) + (canon lift (core func $i "ret-list") (memory $i "memory")) + ) +) + +(component + (type $big (func + (param "p1" u32) (param "p2" u32) (param "p3" u32) (param "p4" u32) (param "p5" u32) + (param "p6" u32) (param "p7" u32) (param "p8" u32) (param "p9" u32) (param "p10" u32) + (param "p11" u32) (param "p12" u32) (param "p13" u32) (param "p14" u32) (param "p15" u32) + (param "p16" u32) (param "p17" u32) (param "p18" u32) (param "p19" u32) (param "p20" u32) + )) + + (component $c + (import "big" (func $big (type $big))) + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func $big (canon lower (func $big) (memory $libc "memory"))) + ) +) + +(assert_invalid + (component + (core module $m + (memory (export "memory") 1) + (func (export "roundtrip") (param i32)) + ) + (core instance $m (instantiate $m)) + + (type $roundtrip (func + (param "p1" u32) (param "p2" u32) (param "p3" u32) (param "p4" u32) (param "p5" u32) + (param "p6" u32) (param "p7" u32) (param "p8" u32) (param "p9" u32) (param "p10" u32) + (param "p11" u32) (param "p12" u32) (param "p13" u32) (param "p14" u32) (param "p15" u32) + (param "p16" u32) (param "p17" u32) (param "p18" u32) (param "p19" u32) (param "p20" u32) + )) + + (func $roundtrip (type $roundtrip) + (canon lift (core func $m "roundtrip") (memory $m "memory")) + ) + (export "roundtrip" (func $roundtrip)) + ) + "canonical option `realloc` is required" +) + +(assert_invalid + (component + (import "a" (func $log (result string))) + (core module $libc + (memory (export "memory") 1) + ) + (core instance $libc (instantiate $libc)) + (core func (canon lower (func $log) (memory $libc "memory"))) + ) + "canonical option `realloc` is required" +) + +(assert_invalid + (component + (core module $m + (memory (export "memory") 1) + (func (export "param-list") (param i32 i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "param-list") (param "bytes" (list u8)) + (canon lift (core func $i "param-list") (memory $i "memory")) + ) + ) + "canonical option `realloc` is required" +) + +(assert_malformed + (component binary + "\00asm" "\0d\00\01\00" ;; component header + "\07\05" ;; component type section, 5 bytes + "\01" ;; 1 count + "\40" ;; component function type + "\00" ;; 0 parameters + "\01\01" ;; invalid result encoding + ) + "invalid leading byte (0x1) for number of results") + +(assert_malformed + (component binary + "\00asm" "\0d\00\01\00" ;; component header + "\07\05" ;; component type section, 5 bytes + "\01" ;; 1 count + "\40" ;; component function type + "\00" ;; 0 parameters + "\02\00" ;; invalid result encoding + ) + "invalid leading byte (0x2) for component function results") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/import.wast b/parser/src/test/resources/spec-tests/wasm-tools/import.wast new file mode 100644 index 0000000..b226157 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/import.wast @@ -0,0 +1,359 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (component + (import "a" (func)) + (import "b" (instance)) + (import "c" (instance + (export "a" (func)) + )) + (import "d" (component + (import "a" (core module)) + (export "b" (func)) + )) + (type $t (func)) + (import "e" (type (eq $t))) + ) +) + +(assert_invalid + (component + (type $f (func)) + (import "a" (instance (type $f))) + ) + "type index 0 is not an instance type") + +(assert_invalid + (component + (core type $f (func)) + (import "a" (core module (type $f))) + ) + "core type index 0 is not a module type") + +(assert_invalid + (component + (type $f string) + (import "a" (func (type $f))) + ) + "type index 0 is not a function type") + +;; Disallow duplicate imports for core wasm modules +(assert_invalid + (component + (core type (module + (import "" "" (func)) + (import "" "" (func)) + )) + ) + "duplicate import name `:`") +(assert_invalid + (component + (core module + (import "" "" (func)) + (import "" "" (func)) + ) + ) + "duplicate import name `:`") +(assert_invalid + (component + (core type (module + (import "" "a" (func)) + (import "" "a" (func)) + )) + ) + "duplicate import name `:a`") +(assert_invalid + (component + (core module + (import "" "a" (func)) + (import "" "a" (func)) + ) + ) + "duplicate import name `:a`") + +(assert_invalid + (component + (import "a" (func)) + (import "a" (func)) + ) + "import name `a` conflicts with previous name `a`") + +(assert_invalid + (component + (type (component + (import "a" (func)) + (import "a" (func)) + )) + ) + "import name `a` conflicts with previous name `a`") + +(assert_invalid + (component + (import "a" (func (type 100))) + ) + "type index out of bounds") + +(assert_invalid + (component + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (func (type 100) (canon lift (core func $i ""))) + ) + "type index out of bounds") + +(component definition + (import "wasi:http/types" (func)) + (import "wasi:http/types@1.0.0" (func)) + (import "wasi:http/types@2.0.0" (func)) + (import "a-b:c-d/e-f@123456.7890.488" (func)) + (import "a:b/c@1.2.3" (func)) + (import "a:b/c@0.0.0" (func)) + (import "a:b/c@0.0.0+abcd" (func)) + (import "a:b/c@0.0.0+abcd-efg" (func)) + (import "a:b/c@0.0.0-abcd+efg" (func)) + (import "a:b/c@0.0.0-abcd.1.2+efg.4.ee.5" (func)) +) + +(assert_invalid + (component + (import "wasi:http/types" (func)) + (import "wasi:http/types" (func)) + ) + "conflicts with previous name") + +(assert_invalid + (component (import "" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "wasi:" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "wasi:/" (func))) + "not in kebab case") +(assert_invalid + (component (import ":/" (func))) + "not in kebab case") +(assert_invalid + (component (import "wasi/http" (func))) + "`wasi/http` is not in kebab case") +(assert_invalid + (component (import "wasi:http/TyPeS" (func))) + "`TyPeS` is not in kebab case") +(assert_invalid + (component (import "WaSi:http/types" (func))) + "`WaSi` is not in kebab case") +(assert_invalid + (component (import "wasi:HtTp/types" (func))) + "`HtTp` is not in kebab case") +(assert_invalid + (component (import "wasi:http/types@" (func))) + "empty string") +(assert_invalid + (component (import "wasi:http/types@." (func))) + "unexpected character '.'") +(assert_invalid + (component (import "wasi:http/types@1." (func))) + "unexpected end of input") +(assert_invalid + (component (import "wasi:http/types@a.2" (func))) + "unexpected character 'a'") +(assert_invalid + (component (import "wasi:http/types@2.b" (func))) + "unexpected character 'b'") +(assert_invalid + (component (import "wasi:http/types@2.0x0" (func))) + "unexpected character 'x'") +(assert_invalid + (component (import "wasi:http/types@2.0.0+" (func))) + "empty identifier segment") +(assert_invalid + (component (import "wasi:http/types@2.0.0-" (func))) + "empty identifier segment") +(assert_invalid + (component (import "foo:bar:baz/qux" (func))) + "expected `/` after package name") +(assert_invalid + (component (import "foo:bar/baz/qux" (func))) + "trailing characters found: `/qux`") + +(component + (component + (import "a" (func $a)) + (export "a" (func $a)) + ) +) + +(component definition + (import "unlocked-dep=" (func)) + (import "unlocked-dep=" (func)) + (import "unlocked-dep==1.2.3}>" (func)) + (import "unlocked-dep==1.2.3-rc}>" (func)) + (import "unlocked-dep=" (func)) + (import "unlocked-dep=" (func)) + (import "unlocked-dep==1.2.3 <1.2.3}>" (func)) + (import "unlocked-dep==1.2.3-rc <1.2.3}>" (func)) +) + +(assert_invalid + (component (import "unlocked-dep=" (func))) + "expected `<` at ``") +(assert_invalid + (component (import "unlocked-dep=<" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "unlocked-dep=<>" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "unlocked-dep=<:>" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "unlocked-dep=" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "unlocked-dep=<:a>" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "unlocked-dep=" (func))) + "expected `{` at `>`") +(assert_invalid + (component (import "unlocked-dep=" (func))) + "expected `>=` or `<` at start of version range") +(assert_invalid + (component (import "unlocked-dep=" (func))) + "`xyz` is not a valid semver") +(assert_invalid + (component (import "unlocked-dep==2.3.4}>" (func))) + "`1.2.3 >=2.3.4` is not a valid semver") + +(component definition + (import "locked-dep=" (func)) + (import "locked-dep=" (func)) + (import "locked-dep=,integrity=" (func)) + (import "locked-dep=,integrity=" (func)) +) + +(assert_invalid + (component (import "locked-dep=" (func))) + "expected `<` at ``") +(assert_invalid + (component (import "locked-dep=<" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "locked-dep=<:" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "locked-dep=<:>" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "locked-dep=" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "locked-dep=<:a>" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "locked-dep=` at ``") +(assert_invalid + (component (import "locked-dep=" (func))) + "is not a valid semver") +(assert_invalid + (component (import "locked-dep=` at ``") +(assert_invalid + (component (import "locked-dep=," (func))) + "expected `integrity=<`") +(assert_invalid + (component (import "locked-dep=x" (func))) + "trailing characters found: `x`") + +(component definition + (import "url=<>" (func)) + (import "url=" (func)) + (import "url=,integrity=" (func)) +) + +(assert_invalid + (component (import "url=" (func))) + "expected `<` at ``") +(assert_invalid + (component (import "url=<" (func))) + "failed to find `>`") +(assert_invalid + (component (import "url=<<>" (func))) + "url cannot contain `<`") + +(assert_invalid + (component + (import "relative-url=<>" (func)) + (import "relative-url=" (func)) + (import "relative-url=,integrity=" (func)) + ) + "not a valid extern name") + +(assert_invalid + (component (import "relative-url=" (func))) + "not a valid extern name") +(assert_invalid + (component (import "relative-url=<" (func))) + "not a valid extern name") +(assert_invalid + (component (import "relative-url=<<>" (func))) + "not a valid extern name") + +(component definition + (import "integrity=" (func)) + (import "integrity=" (func)) + (import "integrity=" (func)) + (import "integrity=" (func)) + (import "integrity=< sha512-a sha256-b >" (func)) + (import "integrity=< sha512-a?abcd >" (func)) + (import "integrity=" (func)) + (import "integrity=" (func)) + (import "integrity=" (func)) + (import "integrity=" (func)) +) +(assert_invalid + (component (import "integrity=<>" (func))) + "integrity hash cannot be empty") +(assert_invalid + (component (import "integrity=" (func))) + "expected `-` after hash algorithm") +(assert_invalid + (component (import "integrity=" (func))) + "not valid base64") +(assert_invalid + (component (import "integrity=" (func))) + "not valid base64") +(assert_invalid + (component (import "integrity=" (func))) + "not valid base64") +(assert_invalid + (component (import "integrity=" (func))) + "not valid base64") +(assert_invalid + (component (import "integrity=" (func))) + "not valid base64") +(assert_invalid + (component (import "integrity=" (func))) + "unrecognized hash algorithm") + +;; Prior to WebAssembly/component-model#263 this was a valid component. +;; Specifically the 0x01 prefix byte on the import was valid. Nowadays that's +;; not valid in the spec but it's accepted for backwards compatibility. This +;; tests is here to ensure such compatibility. In the future this test should +;; be changed to `(assert_invalid ...)` +(component definition binary + "\00asm" "\0d\00\01\00" ;; component header + + "\07\05" ;; type section, 5 bytes large + "\01" ;; 1 count + "\40" ;; function + "\00" ;; parameters, 0 count + "\01\00" ;; results, named, 0 count + + "\0a\06" ;; import section, 6 bytes large + "\01" ;; 1 count + "\01" ;; prefix byte of 0x01 (invalid by the spec nowadays) + "\01a" ;; name = "a" + "\01\00" ;; type = func ($type 0) +) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/imports-exports.wast b/parser/src/test/resources/spec-tests/wasm-tools/imports-exports.wast new file mode 100644 index 0000000..e650c8c --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/imports-exports.wast @@ -0,0 +1,26 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; With what's defined so far, we can define a component that imports, links and exports other components: + +(component + (component + (import "c" (instance $c + (export "f" (func (result string))) + )) + (import "d" (component $D + (import "c" (instance $c + (export "f" (func (result string))) + )) + (export "g" (func (result string))) + )) + (instance $d1 (instantiate $D + (with "c" (instance $c)) + )) + (instance $d2 (instantiate $D + (with "c" (instance + (export "f" (func $d1 "g")) + )) + )) + (export "d2" (instance $d2)) + ) +) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/inline-exports.wast b/parser/src/test/resources/spec-tests/wasm-tools/inline-exports.wast new file mode 100644 index 0000000..2c3ff56 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/inline-exports.wast @@ -0,0 +1,9 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (type (export "foo") u8) +) + +(assert_malformed + (component quote "(type (component (type (export \"\") (func))))") + "unexpected token") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/instance-type.wast b/parser/src/test/resources/spec-tests/wasm-tools/instance-type.wast new file mode 100644 index 0000000..2f4b140 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/instance-type.wast @@ -0,0 +1,234 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; instances +(component + (type (instance)) + + (type $foo (func)) + + (type $t (func (result string))) + + (core type (module + (type $local_type (func)) + ;; functions + (export "a" (func)) + (export "b" (func $foo)) + (export "c" (func)) + (export "d" (func $foo)) + (export "e" (func (type $local_type))) + (export "f" (func (param i32))) + (export "g" (func (param i32) (result i32 i64))) + (export "h" (func (type $local_type) (result i32))) + + ;; globals + (export "i" (global i32)) + (export "j" (global $foo i32)) + (export "k" (global (mut i32))) + + ;; tables + (export "l" (table 1 funcref)) + (export "m" (table $foo 1 funcref)) + + ;; memory + (export "n" (memory 1)) + (export "o" (memory $foo 1)) + (export "p" (memory 1 2)) + (export "q" (memory 1 2 shared)) + )) + + (type $outer (instance + (type $local_type (func)) + ;; functions + (export "a" (func)) + (export "a2" (func (type $local_type))) + (export "b" (func)) + (export "c" (func)) + (export "d" (func)) + (export "e" (func (type $t))) + (export "f" (func (param "f" string))) + (export "g" (func (param "g" s32) (result u32))) + (export "h" (func (type $t))) + + ;; components + (type $component_type (component)) + (export "c1" (component)) + (export "c2" (component (import "i1" (func)))) + (export "c3" (component (export "e1" (func)))) + (export "c4" (component (type $component_type))) + (export "c5" (component + (type $nested_func_type (func)) + (alias outer $outer $local_type (type $my_type)) + (import "i1" (func (type $nested_func_type))) + (import "i2" (component)) + (export "e1" (func (type $my_type))) + (export "e2" (component)) + )) + )) +) + +;; expand inline types +(component + (type (instance (export "a" (instance)))) +) + +;; reference outer types +(component + (type (instance + (type $t (instance)) + (export "a" (instance (type $t))) + )) + (type $x (instance)) + (type (instance (export "a" (instance (type $x))))) +) + +;; recursive +(component + (type (instance (export "a" (core module + (type $functype (func)) + + (export "a" (func)) + (export "b" (func (type 0))) + (export "c" (func (param i32))) + (export "d" (func (type $functype))) + + ;; globals + (export "e" (global i32)) + (export "f" (global (mut i32))) + + ;; tables + (export "g" (table 1 funcref)) + + ;; memory + (export "h" (memory 1)) + (export "i" (memory 1 2)) + (export "j" (memory 1 2 shared)) + )))) +) + +;; modules +(component + (core type (module)) + + (core type $foo (module)) + + (type $empty (func)) + (type $i (instance)) + + (core type (module + (type $empty (func)) + (import "" "a" (func)) + (import "" "b" (func (type $empty))) + (import "" "c" (func (param i32))) + (import "" "d" (func (param i32) (result i32))) + + (import "" "e" (global i32)) + (import "" "f" (memory 1)) + (import "" "g" (table 1 funcref)) + + (export "a" (func)) + (export "b" (global i32)) + (export "c" (memory 1)) + (export "d" (table 1 funcref)) + + (export "e" (func (type $empty))) + (export "f" (func (param i32))) + )) + + (type (component + (import "a" (func)) + (import "b" (func (type $empty))) + (import "c" (func (param "c" s32))) + (import "d" (func (param "d" s32) (result s32))) + + (import "h" (instance)) + (import "i" (instance (type $i))) + (import "j" (instance + (export "a" (func)) + (export "b" (func (type $empty))) + (export "c" (func (param "c" s32))) + )) + + (import "k" (core module)) + (import "l" (core module + (type $empty (func)) + (import "" "a" (func (type $empty))) + (import "" "b" (func (param i32))) + (export "a" (func (type $empty))) + (export "b" (func (param i32))) + )) + + (export "m" (func)) + (export "n" (func (type $empty))) + (export "o" (func (param "f" s32))) + + (export "p" (instance + (export "a" (func)) + (export "b" (func (type $empty))) + (export "c" (func (param "c" s32))) + )) + + (export "q" (core module + (type $empty (func)) + (import "" "a" (func (type $empty))) + (import "" "b" (func (param i32))) + (export "a" (func (type $empty))) + (export "b" (func (param i32))) + )) + )) +) + +(assert_invalid + (component + (type (instance + (export "a" (func)) + (export "a" (func))))) + "export name `a` conflicts with previous name `a`") + +(assert_invalid + (component + (type $t (func)) + (type (instance + (export "a" (instance (type $t))) + ))) + "type index 0 is not an instance type") + +(assert_invalid + (component + (core type $t (func)) + (type (instance + (export "a" (core module (type $t))) + ))) + "core type index 0 is not a module type") + +(assert_malformed + (component quote + "(type $t (func))" + "(type (instance (export \"a\" (core module (type $t)))))" + ) + "unknown core type") + +(assert_invalid + (component + (type $t (record (field "a" string))) + (type (instance + (export "a" (func (type $t))) + ))) + "type index 0 is not a function type") + +(assert_invalid + (component + (type $t (instance)) + (type (instance + (export "a" (func (type $t))) + ))) + "type index 0 is not a function type") + +(assert_invalid + (component + (type $t (instance)) + (type (instance + (export "a" (instance + (export "a" (func (type $t))) + )) + ))) + "type index 0 is not a function type") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/instantiate.wast b/parser/src/test/resources/spec-tests/wasm-tools/instantiate.wast new file mode 100644 index 0000000..cb99239 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/instantiate.wast @@ -0,0 +1,976 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (import "a" (core module $m)) + (core instance $a (instantiate $m)) +) + +(component + (component + (import "a" (func $i)) + (import "b" (component $c (import "a" (func)))) + (instance (instantiate $c (with "a" (func $i)))) + ) +) + +(component + (component + (import "a" (component $i)) + (import "b" (component $c (import "a" (component)))) + (instance (instantiate $c (with "a" (component $i)))) + ) +) + +(component + (component + (import "a" (core module $i)) + (import "b" (component $c (import "a" (core module)))) + (instance (instantiate $c (with "a" (core module $i)))) + ) +) + +(component + (component + (import "a" (instance $i)) + (import "b" (component $c (import "a" (instance)))) + (instance (instantiate $c (with "a" (instance $i)))) + ) +) + +(component definition + (import "a" (core module $m + (import "" "a" (func)) + (import "" "b" (global i32)) + (import "" "c" (table 1 funcref)) + (import "" "d" (memory 1)) + )) + (import "b" (core module $m2 + (export "a" (func)) + (export "b" (global i32)) + (export "c" (table 1 funcref)) + (export "d" (memory 1)) + )) + (core instance $x (instantiate $m2)) + (core instance (instantiate $m (with "" (instance $x)))) +) + +(component definition + (import "a" (core module $m + (import "" "d" (func)) + (import "" "c" (global i32)) + (import "" "b" (table 1 funcref)) + (import "" "a" (memory 1)) + )) + (import "b" (core module $m2 + (export "a" (func)) + (export "b" (global i32)) + (export "c" (table 1 funcref)) + (export "d" (memory 1)) + )) + (core instance $x (instantiate $m2)) + + (core instance (instantiate $m (with "" (instance + (export "d" (func $x "a")) + (export "c" (global $x "b")) + (export "b" (table $x "c")) + (export "a" (memory $x "d")) + )))) +) + +(component + (component + (import "a" (component $m + (import "a" (instance + (export "a" (core module)) + )) + )) + (import "b" (component $m2 + (export "b" (core module)) + )) + (instance $x (instantiate $m2)) + + (instance (instantiate $m (with "a" (instance + (export "a" (core module $x "b")) + )))) + ) +) + +(component + (component + (import "a" (component $c + (import "a" (core module)) + (import "b" (func)) + (import "c" (component)) + (import "d" (instance)) + )) + (core module $m (import "b")) + (func $f (import "c")) + (component $c2 (import "d")) + (instance $i (import "e")) + + (instance + (instantiate $c + (with "a" (core module $m)) + (with "b" (func $f)) + (with "c" (component $c2)) + (with "d" (instance $i)) + ) + ) + + (core instance $c (instantiate $m)) + (core instance (instantiate $m)) + + ;; inline exports/imports + (type $empty (instance)) + (instance $d (import "g") (type $empty)) + (instance (import "h")) + (instance (import "i") + (export "x" (func))) + (instance (export "j") (export "k") (import "x")) + ) +) + +(assert_invalid + (component + (core instance (instantiate 0)) + ) + "unknown module") +(assert_invalid + (component + (instance (instantiate 0)) + ) + "unknown component") +(assert_invalid + (component + (import "a" (core module)) + (core instance (instantiate 1)) + ) + "unknown module") + +(component + (component + (import "a" (func $f)) + (import "b" (component $c)) + (instance (instantiate $c (with "a" (func $f)))) + ) +) +(assert_invalid + (component + (import "a" (core module $m (import "" "" (func)))) + (core instance (instantiate $m)) + ) + "missing module instantiation argument") +(assert_invalid + (component + (import "a" (component $m (import "a" (func)))) + (instance (instantiate $m)) + ) + "missing import named `a`") + +(assert_invalid + (component + (import "a" (component $m + (import "a" (func)) + )) + (import "b" (component $c)) + (instance $i (instantiate $m (with "a" (component $c)))) + ) + "expected func, found component") + +(assert_invalid + (component + (import "a" (component $m + (import "a" (func)) + )) + (import "b" (func $f (result string))) + (instance $i (instantiate $m (with "a" (func $f)))) + ) + "expected a result, found none") + +(assert_invalid + (component + (import "a" (component $m + (import "a" (func)) + )) + (import "b" (func (param "i" string))) + (instance $i (instantiate $m (with "a" (func 0)))) + ) + "expected 0 parameters, found 1") + +(assert_invalid + (component + (import "a" (component $m + (import "a" (core module + (import "" "" (func)) + )) + )) + (import "b" (core module $i + (import "" "" (global i32)) + )) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) + "type mismatch in import `::`") + +(assert_invalid + (component + (import "a" (component $m + (import "a" (core module)) + )) + (import "b" (core module $i + (import "" "foobar" (global i32)) + )) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) + "missing expected import `::foobar`") +(assert_invalid + (component + (import "a" (component $m + (import "a" (core module (export "x" (func)))) + )) + (import "b" (core module $i)) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) + "missing expected export `x`") + +;; it's ok to give a module with fewer imports +(component + (component + (import "a" (component $m + (import "a" (core module + (import "" "" (global i32)) + (import "" "f" (func)) + )) + )) + (import "b" (core module $i + (import "" "" (global i32)) + )) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) +) + +;; export subsets +(component + (component + (import "a" (component $m + (import "a" (core module + (export "" (func)) + )) + )) + (import "b" (core module $i + (export "" (func)) + (export "a" (func)) + )) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) +) +(component + (component + (import "a" (component $m + (import "a" (instance + (export "a" (func)) + )) + )) + (import "b" (instance $i + (export "a" (func)) + (export "b" (func)) + )) + (instance (instantiate $m (with "a" (instance $i)))) + ) +) + + +;; ============================================================================ +;; core wasm type checking + +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (func)))) + (import "m2" (core module $m2 (export "" (func (param i32))))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "expected: (func)") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (func)))) + (import "m2" (core module $m2 (export "" (func (result i32))))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "expected: (func)") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (global i32)))) + (import "m2" (core module $m2 (export "" (global i64)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "expected global type i32, found i64") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (table 1 funcref)))) + (import "m2" (core module $m2 (export "" (table 2 externref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "expected table element type funcref, found externref") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (table 1 2 funcref)))) + (import "m2" (core module $m2 (export "" (table 2 funcref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "mismatch in table limits") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (table 2 2 funcref)))) + (import "m2" (core module $m2 (export "" (table 1 funcref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "mismatch in table limits") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (table 2 2 funcref)))) + (import "m2" (core module $m2 (export "" (table 2 3 funcref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "mismatch in table limits") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (memory 1 2 shared)))) + (import "m2" (core module $m2 (export "" (memory 1)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "mismatch in the shared flag for memories") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (memory 1)))) + (import "m2" (core module $m2 (export "" (memory 0)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "mismatch in memory limits") +(assert_invalid + (component + (import "m1" (core module $m1 (export "g" (func)))) + (component $c + (import "m" (core module (export "g" (global i32)))) + ) + (instance (instantiate $c (with "m" (core module $m1)))) + ) + "type mismatch in export `g`") + +(assert_invalid + (component + (core instance (instantiate 0)) + ) + "unknown module") + +(component + (component $m + (core module $sub (export "module") + (func $f (export "") (result i32) + i32.const 5)) + ) + (instance $a (instantiate $m)) + (alias export $a "module" (core module $sub)) + (core instance $b (instantiate $sub)) + + (core module $final + (import "" "" (func $b (result i32))) + (func (export "get") (result i32) + call $b)) + + (core instance (instantiate $final (with "" (instance $b)))) +) + +(assert_invalid + (component (instance $i (export "" (func 0)))) + "function index out of bounds") + +(assert_invalid + (component (instance (export "" (instance 0)))) + "index out of bounds") + +(assert_invalid + (component (instance $i (export "" (component 0)))) + "index out of bounds") + +(assert_invalid + (component (instance (export "" (instance 0)))) + "index out of bounds") + +(assert_invalid + (component (instance $i (export "" (core module 0)))) + "index out of bounds") + +(assert_invalid + (component (core instance (export "" (func 0)))) + "index out of bounds") + +(assert_invalid + (component (core instance (export "" (table 0)))) + "index out of bounds") + +(assert_invalid + (component (core instance (export "" (global 0)))) + "index out of bounds") + +(assert_invalid + (component (core instance (export "" (memory 0)))) + "index out of bounds") + +(assert_invalid + (component + (core module $m) + (core instance $i (instantiate $m)) + (core instance (instantiate $m + (with "" (instance $i)) + (with "" (instance $i)) + )) + ) + "duplicate module instantiation argument named ``" +) + +(assert_invalid + (component + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (core instance (instantiate $m + (with "" (instance $i)) + (with "" (instance $i)) + )) + ) + "duplicate module instantiation argument named ``") + +(assert_invalid + (component + (core module $m1 (func (export ""))) + (core module $m2 (import "" "" (global i32))) + (core instance $i (instantiate $m1)) + (core instance (instantiate $m2 + (with "" (instance $i)) + )) + ) + "expected global, found func") + +(assert_invalid + (component + (component $m) + (instance $i (instantiate $m)) + (instance (instantiate $m + (with "a" (instance $i)) + (with "a" (instance $i)) + )) + ) + "instantiation argument `a` conflicts with previous argument `a`") + +(assert_invalid + (component + (component $c (import "a" (func))) + (instance (instantiate $c + (with "a" (component $c)) + )) + ) + "expected func, found component") + +(assert_invalid + (component + (component $c) + (instance (instantiate $c + (with "" (core module 0)) + )) + ) + "index out of bounds") + +(assert_invalid + (component + (component $c) + (instance (instantiate $c + (with "" (instance 0)) + )) + ) + "index out of bounds") + +(assert_invalid + (component + (component $c) + (instance (instantiate $c + (with "" (func 0)) + )) + ) + "index out of bounds") + +(assert_invalid + (component + (component $c) + (instance (instantiate $c + (with "" (component 100)) + )) + ) + "index out of bounds") + +(assert_invalid + (component + (component $c) + (instance + (export "a" (component $c)) + (export "a" (component $c)) + ) + ) + "export name `a` conflicts with previous name `a`") + +(component + (component + (import "a" (instance $i)) + (import "b" (func $f)) + (import "c" (component $c)) + (import "d" (core module $m)) + (instance + (export "a" (instance $i)) + (export "b" (func $f)) + (export "c" (component $c)) + (export "d" (core module $m)) + ) + ) +) + +(component + (core module $m + (func (export "1")) + (memory (export "2") 1) + (table (export "3") 1 funcref) + (global (export "4") i32 i32.const 0) + ) + (core instance $i (instantiate $m)) + (core instance + (export "a" (func $i "1")) + (export "b" (memory $i "2")) + (export "c" (table $i "3")) + (export "d" (global $i "4")) + ) +) + +(assert_invalid + (component + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (core instance + (export "" (func $i "")) + (export "" (func $i "")) + ) + ) + "export name `` already defined") + +(assert_invalid + (component + (component $c) + (instance $i (instantiate $c)) + (export "a" (instance $i "a")) + ) + "no export named `a`") + +(assert_invalid + (component + (export "a" (instance 100 "a")) + ) + "index out of bounds") + +(assert_invalid + (component + (import "a" (core module $libc + (export "memory" (memory 1)) + (export "table" (table 0 funcref)) + (export "func" (func)) + (export "global" (global i32)) + (export "global mut" (global (mut i64))) + )) + (core instance $libc (instantiate $libc)) + (alias core export $libc "memory" (core memory $mem)) + (alias core export $libc "table" (core table $tbl)) + (alias core export $libc "func" (core func $func)) + (alias core export $libc "global" (core global $global)) + (alias core export $libc "global mut" (core global $global_mut)) + + (import "x" (core module $needs_libc + (import "" "memory" (memory 1)) + (import "" "table" (table 0 funcref)) + (import "" "func" (func)) + (import "" "global" (global i32)) + (import "" "global mut" (global (mut i64))) + )) + + (core instance + (instantiate $needs_libc + (with "" (instance (export "memory" (memory $mem)))) + ) + ) + ) + "module instantiation argument `` does not export an item named `table`") + +;; Ensure a type can be an instantiation argument +(component + (type (tuple u32 u32)) + (import "a" (type (eq 0))) + (component + (type (tuple u32 u32)) + (import "a" (type (eq 0))) + ) + (instance (instantiate 0 + (with "a" (type 1)) + ) + ) +) + +(assert_invalid + (component + (type $t (tuple string string)) + (import "a" (type $a (eq $t))) + (component $c + (type $t (tuple u32 u32)) + (import "a" (type (eq $t))) + ) + (instance (instantiate $c + (with "a" (type $a)) + ) + ) + ) + "expected primitive `u32` found primitive `string`") + + +;; subtyping for module imports reverses order of imports/exports for the +;; subtyping check +;; +;; Here `C` imports a module, and the module itself imports a table of min size +;; 1. A module import which imports a min-size table of 0, however, is valid to +;; supply for this since it'll already be given at least 1 anyway. +;; +;; Similarly for exports `C` imports a module that exports a table of at least +;; size 1. If it's given a module that exports a larger table that's ok too. +(component + (core module $a + (import "" "" (table 0 funcref)) + (table (export "x") 2 funcref) + ) + (component $C + (import "a" (core module + (import "" "" (table 1 funcref)) + (export "x" (table 1 funcref)) + )) + ) + (instance (instantiate $C (with "a" (core module $a)))) +) + +;; same as above but for memories +(component + (core module $a1 (import "" "" (memory 0))) + (core module $a2 (memory (export "x") 2)) + (component $C + (import "a1" (core module (import "" "" (memory 1)))) + (import "a2" (core module (export "x" (memory 1)))) + ) + (instance (instantiate $C + (with "a1" (core module $a1)) + (with "a2" (core module $a2)) + )) +) + +(assert_invalid + (component + (import "x" (func $x (param "x" u32))) + (import "y" (component $c + (import "x" (func (param "y" u32))) + )) + + (instance (instantiate $c (with "x" (func $x)))) + ) + "expected parameter named `y`, found `x`") +(assert_invalid + (component + (import "x" (func $x (param "x" u32))) + (import "y" (component $c + (import "x" (func (param "x" s32))) + )) + + (instance (instantiate $c (with "x" (func $x)))) + ) + "type mismatch in function parameter `x`") +(assert_invalid + (component + (import "x" (func $x (result u32))) + (import "y" (component $c + (import "x" (func (result s32))) + )) + + (instance (instantiate $c (with "x" (func $x)))) + ) + "type mismatch with result type") + +(assert_invalid + (component + (import "x" (instance $x (export "a" (func)))) + (import "y" (component $c + (import "x" (instance $x (export "a" (component)))) + )) + + (instance (instantiate $c (with "x" (instance $x)))) + ) + "type mismatch in instance export `a`") + +(assert_invalid + (component + (import "y" (component $c + (type $t u32) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "f" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected primitive, found record") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "f" u32))) + (import "x" (type (eq $t))) + )) + + (type $x u32) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected record, found u32") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $f (tuple u8)) + (type $x (record (field "x" $f))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected u32, found tuple") + +(assert_invalid + (component + (import "y" (component $c + (type $f (option s32)) + (type $t (record (field "x" $f))) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "x" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in record field `x`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "y" u32) (field "z" u64))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected 1 fields, found 2") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "a" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "b" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected field name `a`, found `b`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x" u32) (case "y" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected 1 cases, found 2") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "y" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected case named `x`, found `y`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x"))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected case `x` to have a type, found none") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x"))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected case `x` to have no type") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x" s32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in variant case `x`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (tuple u8)) + (import "x" (type (eq $t))) + )) + + (type $x (tuple u32 u32)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected 1 types, found 2") + +(assert_invalid + (component + (import "y" (component $c + (type $t (tuple u8)) + (import "x" (type (eq $t))) + )) + + (type $x (tuple u16)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in tuple field 0") + +(assert_invalid + (component + (import "y" (component $c + (type $t (flags "a")) + (import "x" (type (eq $t))) + )) + + (type $x (flags "x")) + (instance (instantiate $c (with "x" (type $x)))) + ) + "mismatch in flags elements") + +(assert_invalid + (component + (import "y" (component $c + (type $t (enum "a")) + (import "x" (type (eq $t))) + )) + + (type $x (enum "x")) + (instance (instantiate $c (with "x" (type $x)))) + ) + "mismatch in enum elements") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result s32)) + (import "x" (type (eq $t))) + )) + + (type $x (result u32)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in ok variant") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result (error s32))) + (import "x" (type (eq $t))) + )) + + (type $x (result (error u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in err variant") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result)) + (import "x" (type (eq $t))) + )) + + (type $x (result u32)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected ok type to not be present") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result u32)) + (import "x" (type (eq $t))) + )) + + (type $x (result)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected ok type, but found none") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result)) + (import "x" (type (eq $t))) + )) + + (type $x (result (error u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected err type to not be present") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result (error u32))) + (import "x" (type (eq $t))) + )) + + (type $x (result)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected err type, but found none") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/invalid.wast b/parser/src/test/resources/spec-tests/wasm-tools/invalid.wast new file mode 100644 index 0000000..267b31f --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/invalid.wast @@ -0,0 +1,34 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (core type (module + (import "" "" (func (type 1))) + )) + (type (func)) + ) + "type index out of bounds") + +(assert_malformed + (component quote + "(export \"\" (func $foo))" + ) + "unknown func") + +(assert_malformed + (component quote + "(alias outer 100 $foo (type $foo))" + ) + "outer count of `100` is too large") + +(assert_malformed + (component quote + "(alias outer $nonexistent $foo (type $foo))" + ) + "outer component `nonexistent` not found") + +(assert_malformed + (component quote + "(import \"x\" (func $x))" + "(component (export \"x\" (func $x)))") + "outer item `x` is not a module, type, or component") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/link.wast b/parser/src/test/resources/spec-tests/wasm-tools/link.wast new file mode 100644 index 0000000..7202365 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/link.wast @@ -0,0 +1,14 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; Based on this, we can link two modules $A and $B together with the following component: + +(component + (core module $A + (func (export "one") (result i32) (i32.const 1)) + ) + (core module $B + (func (import "a" "one") (result i32)) + ) + (core instance $a (instantiate $A)) + (core instance $b (instantiate $B (with "a" (instance $a)))) +) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast b/parser/src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast new file mode 100644 index 0000000..32e1a27 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast @@ -0,0 +1,179 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (core module $m + (memory (export "m") 1) + (table (export "t") 1 funcref) + (global (export "g") i32 i32.const 0) + (func (export "f")) + ) + (core instance $i (instantiate $m)) + + ;; 160 memories (4 per row 40 rows) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + + ;; 160 tables (4 per row 40 rows) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + + ;; 160 globals (4 per row 40 rows) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + + ;; 160 functions (4 per row 40 rows) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) +) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/lower.wast b/parser/src/test/resources/spec-tests/wasm-tools/lower.wast new file mode 100644 index 0000000..5b9e13b --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/lower.wast @@ -0,0 +1,17 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (import "f" (func $f (param "x" (list u8)))) + (core func $f (canon lower (func $f) + )) + ) + "canonical option `memory` is required") + +(assert_invalid + (component + (import "f" (func $f (result (list u8)))) + (core func $f (canon lower (func $f) + )) + ) + "canonical option `memory` is required") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/memory64.wast b/parser/src/test/resources/spec-tests/wasm-tools/memory64.wast new file mode 100644 index 0000000..a72eb3b --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/memory64.wast @@ -0,0 +1,55 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (core module $A + (import "" "" (memory 1))) + (core module $B + (memory (export "") i64 1)) + (core instance $b (instantiate $B)) + (core instance $a (instantiate $A (with "" (instance $b)))) + ) + "mismatch in index type used for memories") + +(assert_invalid + (component + (core module $A + (import "" "" (memory i64 1))) + (core module $B + (memory (export "") 1)) + (core instance $b (instantiate $B)) + (core instance $a (instantiate $A (with "" (instance $b)))) + ) + "mismatch in index type used for memories") + +(component + (core module $A + (memory (export "m") i64 1)) + (core instance $A (instantiate $A)) + (alias core export $A "m" (core memory $m)) + + (core module $B (import "" "" (memory i64 1))) + (core instance (instantiate $B (with "" (instance (export "" (memory $m)))))) +) + +(component + (core module $A + (table (export "m") i64 1 funcref)) + (core instance $A (instantiate $A)) + (alias core export $A "m" (core table $m)) + + (core module $B (import "" "" (table i64 1 funcref))) + (core instance (instantiate $B (with "" (instance (export "" (table $m)))))) +) + +(component + (import "x" (func $x (param "x" string))) + (core module $A + (memory (export "m") i64 1) + (func (export "realloc") (param i64 i64 i64 i64) (result i64) unreachable) + ) + (core instance $A (instantiate $A)) + (alias core export $A "m" (core memory $m)) + (core func $realloc (alias core export $A "realloc")) + (core func (canon lower (func $x) (memory $m) (realloc (func $realloc)))) +) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/module-link.wast b/parser/src/test/resources/spec-tests/wasm-tools/module-link.wast new file mode 100644 index 0000000..119da23 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/module-link.wast @@ -0,0 +1,98 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (type $Wasi (instance)) + (component $B) + (component $B_wrap + (import "wasi" (instance $wasi (type $Wasi))) + (instance $b (instantiate $B)) + ) +) + +(component + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + + (component $A + (type $Wasi (instance)) + (import "wasi" (instance (type $Wasi))) + + (core module $m + (func (export "a")) + ) + + (core instance $i (instantiate $m)) + (func (export "a") + (canon lift (core func $i "a")) + ) + ) + + (component $B + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (import "a1-x" (component $A + (import "wasi" (instance (type $Wasi))) + (export "a" (func)) + )) + (instance $a (instantiate $A (with "wasi" (instance $wasi)))) + + (core func $lower (canon lower (func $a "a"))) + (core module $b + (import "a" "a" (func)) + (func (export "b")) + ) + (core instance $b (instantiate $b + (with "a" (instance (export "a" (func $lower)))) + )) + (func (export "b") + (canon lift (core func $b "b")) + ) + ) + (component $B_wrap + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (instance $b (instantiate $B + (with "wasi" (instance $wasi)) + (with "a1-x" (component $A))) + ) + (export "b" (func $b "b")) + ) + + (component $C + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (import "b1-x" (component $B + (import "wasi" (instance $wasi (type $Wasi))) + (export "b" (func)) + )) + (instance $b (instantiate $B (with "wasi" (instance $wasi)))) + (export "c" (func $b "b")) + ) + (component $C_wrap + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (instance $c (instantiate $C + (with "wasi" (instance $wasi)) + (with "b1-x" (component $B_wrap)) + )) + (export "c" (func $c "c")) + ) + + (component $D + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (import "c1-x" (component $C + (import "wasi" (instance $wasi (type $Wasi))) + (export "c" (func)) + )) + (instance $c (instantiate $C (with "wasi" (instance $wasi)))) + (export "d" (func $c "c")) + ) + + (instance $d (instantiate $D + (with "wasi" (instance $wasi)) + (with "c1-x" (component $C_wrap)) + )) + + (export "d" (func $d "d")) +) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/more-flags.wast b/parser/src/test/resources/spec-tests/wasm-tools/more-flags.wast new file mode 100644 index 0000000..ebcced0 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/more-flags.wast @@ -0,0 +1,41 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (type (flags + "f1" + "f2" + "f3" + "f4" + "f5" + "f6" + "f7" + "f8" + "f9" + "f10" + "f11" + "f12" + "f13" + "f14" + "f15" + "f16" + "f17" + "f18" + "f19" + "f20" + "f21" + "f22" + "f23" + "f24" + "f25" + "f26" + "f27" + "f28" + "f29" + "f30" + "f31" + "f32" + "f33" + )) + ) + "cannot have more than 32 flags") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/naming.wast b/parser/src/test/resources/spec-tests/wasm-tools/naming.wast new file mode 100644 index 0000000..5decf55 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/naming.wast @@ -0,0 +1,127 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (func (import "a")) + (component) + (instance (instantiate 0 (with "NotKebab-Case" (func 0)))) +) + +(assert_invalid + (component + (import "f" (func)) + (instance (export "1" (func 0))) + ) + "`1` is not in kebab case" +) + +(assert_invalid + (component + (instance) + (alias export 0 "Xml" (func)) + ) + "instance 0 has no export named `Xml`" +) + +(component definition + (type (flags "a-1-c")) +) + +(assert_invalid + (component + (type (enum "NevEr")) + ) + "enum tag name `NevEr` is not in kebab case" +) + +(assert_invalid + (component + (type (record (field "GoNnA" string))) + ) + "record field name `GoNnA` is not in kebab case" +) + +(assert_invalid + (component + (type (variant (case "GIVe" string))) + ) + "variant case name `GIVe` is not in kebab case" +) + + +(assert_invalid + (component + (type (func (param "yOu" string))) + ) + "function parameter name `yOu` is not in kebab case" +) + +(assert_invalid + (component + (type (component (export "NevEr" (func)))) + ) + "`NevEr` is not in kebab case" +) + +(assert_invalid + (component + (type (component (import "GonnA" (func)))) + ) + "`GonnA` is not in kebab case" +) + +(assert_invalid + (component + (type (instance (export "lET" (func)))) + ) + "`lET` is not in kebab case" +) + +(assert_invalid + (component + (instance (export "YoU")) + ) + "`YoU` is not in kebab case" +) + +(assert_invalid + (component + (instance (import "DOWn")) + ) + "`DOWn` is not in kebab case" +) + +(assert_invalid + (component + (instance (import "A:b/c")) + ) + "character `A` is not lowercase in package name/namespace" +) +(assert_invalid + (component + (instance (import "a:B/c")) + ) + "character `B` is not lowercase in package name/namespace" +) +(component + (instance (import "a:b/c")) + (instance (import "a1:b1/c")) +) + +(component definition + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (own $a)))) +) + +(assert_invalid + (component + (import "a" (type $a (sub resource))) + (import "[method]a.a" (func (param "self" (borrow $a)))) + ) + "import name `[method]a.a` conflicts with previous name `a`") + +(assert_invalid + (component + (import "a" (type $a (sub resource))) + (import "[static]a.a" (func)) + ) + "import name `[static]a.a` conflicts with previous name `a`") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/nested-modules.wast b/parser/src/test/resources/spec-tests/wasm-tools/nested-modules.wast new file mode 100644 index 0000000..5e629ea --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/nested-modules.wast @@ -0,0 +1,50 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (import "i1" (core module)) + + (core module) + (core module) + + (core module (export "x")) + + (component + (core module) + ) + + (component + (core module $m) + (import "a" (func (param "p" string))) + (export "b" (core module $m)) + ) +) + +;; does the `import` use the type annotation specified later? +(component definition + (import "a" (core module)) + (core type (module)) +) + +;; be sure to typecheck nested modules +(assert_invalid + (component + (core module + (func + i32.add) + ) + ) + "type mismatch") + +;; interleave module definitions with imports/aliases and ensure that we +;; typecheck the module code section correctly +(component definition + (core module + (func (export "")) + ) + (import "a" (core module)) + (core module + (func (export "") (result i32) i32.const 5) + ) + (import "b" (instance (export "a" (core module)))) + (alias export 0 "a" (core module)) +) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/resources.wast b/parser/src/test/resources/spec-tests/wasm-tools/resources.wast new file mode 100644 index 0000000..14509c5 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/resources.wast @@ -0,0 +1,1195 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (type $x (resource (rep i32))) +) + +(component + (type $x (resource (rep i32))) + + (core func (canon resource.new $x)) + (core func (canon resource.rep $x)) + (core func (canon resource.drop $x)) +) + +(component definition + (import "x" (type $x (sub resource))) + + (core func (canon resource.drop $x)) +) + +(component + (core module $m + (func (export "dtor") (param i32)) + ) + (core instance $m (instantiate $m)) + (type $x (resource (rep i32) (dtor (func $m "dtor")))) + (core func (canon resource.new $x)) +) + +(component + (type $x (resource (rep i32))) + (core func $f1 (canon resource.new $x)) + (core func $f2 (canon resource.rep $x)) + (core func $f3 (canon resource.drop $x)) + + (core module $m + (import "" "f1" (func (param i32) (result i32))) + (import "" "f2" (func (param i32) (result i32))) + (import "" "f3" (func (param i32))) + ) + + (core instance (instantiate $m + (with "" (instance + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + )) + )) +) + +(assert_invalid + (component + (type $x (resource (rep i64))) + ) + "resources can only be represented by `i32`") + +(assert_invalid + (component + (type $x (own 100)) + ) + "type index out of bounds") + +(assert_invalid + (component + (type $x (borrow 100)) + ) + "type index out of bounds") + +(assert_invalid + (component + (type $t u8) + (type $x (borrow $t)) + ) + "not a resource type") + +(assert_invalid + (component + (type $t u8) + (type $x (own $t)) + ) + "not a resource type") + +(assert_invalid + (component + (import "x" (type $x (sub resource))) + (core func (canon resource.new $x)) + ) + "not a local resource") + +(assert_invalid + (component + (import "x" (type $x (sub resource))) + (core func (canon resource.rep $x)) + ) + "not a local resource") + +(assert_invalid + (component + (type $t (tuple u32)) + (core func (canon resource.drop $t)) + ) + "not a resource type") + +(assert_invalid + (component + (core func (canon resource.drop 100)) + ) + "type index out of bounds") + +(assert_invalid + (component + (type (component)) + (core func (canon resource.drop 0)) + ) + "not a resource type") + +(assert_invalid + (component + (type (component)) + (core func (canon resource.new 0)) + ) + "not a resource type") + +(assert_invalid + (component + (core module $m + (func (export "dtor")) + ) + (core instance $m (instantiate $m)) + (type $x (resource (rep i32) (dtor (func $m "dtor")))) + (core func (canon resource.new $x)) + ) + "wrong signature for a destructor") + +(assert_invalid + (component + (type (resource (rep i32) (dtor (func 100)))) + ) + "function index out of bounds") + +(assert_invalid + (component + (import "x" (type $x (sub resource))) + (import "y" (type $y (sub resource))) + (import "z" (func $z (param "x" (own $x)) (param "y" (own $y)))) + + (component $c + (import "x" (type $x (sub resource))) + (import "z" (func (param "x" (own $x)) (param "y" (own $x)))) + ) + + (instance (instantiate $c (with "x" (type $x)) (with "z" (func $z)))) + ) + "resource types are not the same") + +(component + (type (component + (import "x" (type $x (sub resource))) + (export "y" (type (eq $x))) + (export "z" (type (sub resource))) + )) +) + +(assert_invalid + (component + (type (component + (type $x (resource (rep i32))) + )) + ) + "resources can only be defined within a concrete component") + +(assert_invalid + (component + (type (instance + (type $x (resource (rep i32))) + )) + ) + "resources can only be defined within a concrete component") + +(component + (type (component + (import "x" (instance $i + (export "t" (type $t (sub resource))) + (export "f" (func (result (own $t)))) + )) + (alias export $i "t" (type $t)) + (export "f" (func (result (own $t)))) + )) +) + +(component definition + (import "fancy-fs" (instance $fancy-fs + (export "fs" (instance $fs + (export "file" (type (sub resource))) + )) + (alias export $fs "file" (type $file)) + (export "fancy-op" (func (param "f" (borrow $file)))) + )) +) + +(component $C + (type $T (list (tuple string bool))) + (type $U (option $T)) + (type $G (func (param "x" (list $T)) (result $U))) + (type $D (component + (alias outer $C $T (type $C_T)) + (type $L (list $C_T)) + (import "f" (func (param "x" $L) (result (list u8)))) + (import "g" (func (type $G))) + (export "g2" (func (type $G))) + (export "h" (func (result $U))) + (import "T" (type $T (sub resource))) + (import "i" (func (param "x" (list (own $T))))) + (export "T2" (type $T' (eq $T))) + (export "U" (type $U' (sub resource))) + (export "j" (func (param "x" (borrow $T')) (result (own $U')))) + )) +) + +(component definition + (import "T1" (type $T1 (sub resource))) + (import "T2" (type $T2 (sub resource))) +) + +(component definition $C + (import "T1" (type $T1 (sub resource))) + (import "T2" (type $T2 (sub resource))) + (import "T3" (type $T3 (eq $T2))) + (type $ListT1 (list (own $T1))) + (type $ListT2 (list (own $T2))) + (type $ListT3 (list (own $T3))) +) + +(component definition + (import "T" (type $T (sub resource))) + (import "U" (type $U (sub resource))) + (type $Own1 (own $T)) + (type $Own2 (own $T)) + (type $Own3 (own $U)) + (type $ListOwn1 (list $Own1)) + (type $ListOwn2 (list $Own2)) + (type $ListOwn3 (list $Own3)) + (type $Borrow1 (borrow $T)) + (type $Borrow2 (borrow $T)) + (type $Borrow3 (borrow $U)) + (type $ListBorrow1 (list $Borrow1)) + (type $ListBorrow2 (list $Borrow2)) + (type $ListBorrow3 (list $Borrow3)) +) + +(component + (component + (import "C" (component $C + (export "T1" (type (sub resource))) + (export "T2" (type $T2 (sub resource))) + (export "T3" (type (eq $T2))) + )) + (instance $c (instantiate $C)) + (alias export $c "T1" (type $T1)) + (alias export $c "T2" (type $T2)) + (alias export $c "T3" (type $T3)) + ) +) + +(component + (component $C + (type $r1 (export "r1") (resource (rep i32))) + (type $r2 (export "r2") (resource (rep i32))) + ) + (instance $c1 (instantiate $C)) + (instance $c2 (instantiate $C)) + (alias export $c1 "r1" (type $c1r1)) + (alias export $c1 "r2" (type $c1r2)) + (alias export $c2 "r1" (type $c2r1)) + (alias export $c2 "r2" (type $c2r2)) +) + +(component + (type $r (resource (rep i32))) + (export "r1" (type $r)) + (export "r2" (type $r)) +) + +(component + (type (component + (export "r1" (type (sub resource))) + (export "r2" (type (sub resource))) + )) +) + +(component + (type $r (resource (rep i32))) + (export $r1 "r1" (type $r)) + (export "r2" (type $r1)) +) + +(component + (type (component + (export "r1" (type $r1 (sub resource))) + (export "r2" (type (eq $r1))) + )) +) + +(component + (component $P + (import "C1" (component $C1 + (import "T" (type $T (sub resource))) + (export "foo" (func (param "t" (own $T)))) + )) + (import "C2" (component $C2 + (import "T" (type $T (sub resource))) + (import "foo" (func (param "t" (own $T)))) + )) + (type $R (resource (rep i32))) + (instance $c1 (instantiate $C1 (with "T" (type $R)))) + (instance $c2 (instantiate $C2 + (with "T" (type $R)) + (with "foo" (func $c1 "foo")) + )) + ) +) + +(component + (component + (import "C1" (component $C1 + (import "T1" (type $T1 (sub resource))) + (import "T2" (type $T2 (sub resource))) + (export "foo" (func (param "t" (tuple (own $T1) (own $T2))))) + )) + (import "C2" (component $C2 + (import "T" (type $T (sub resource))) + (export "foo" (func (param "t" (tuple (own $T) (own $T))))) + )) + (type $R (resource (rep i32))) + (instance $c1 (instantiate $C1 + (with "T1" (type $R)) + (with "T2" (type $R)) + )) + (instance $c2 (instantiate $C2 + (with "T" (type $R)) + (with "foo" (func $c1 "foo")) + )) + ) +) + +(assert_invalid + (component + (component $C + (type $R (resource (rep i32))) + (export "R" (type $R)) + ) + (instance $c (instantiate $C)) + (alias export $c "R" (type $R)) + (core func (canon resource.rep $R)) + ) + "not a local resource") + +(component + (component $C + (type $R (resource (rep i32))) + (export "R" (type $R)) + ) + (instance $c (instantiate $C)) + (alias export $c "R" (type $R)) + (core func (canon resource.drop $R)) +) + +(component + (component $C1 + (import "X" (type (sub resource))) + ) + (component $C2 + (import "C1" (component + (import "X" (type (sub resource))) + )) + ) + (instance $c (instantiate $C2 (with "C1" (component $C1)))) +) + +(component + (component $C1 + (import "X" (type $X (sub resource))) + (import "f" (func $f (result (own $X)))) + (export "g" (func $f)) + ) + (component $C2 + (import "C1" (component + (import "X" (type $X (sub resource))) + (import "f" (func (result (own $X)))) + (export "g" (func (result (own $X)))) + )) + ) + (instance $c (instantiate $C2 (with "C1" (component $C1)))) +) + +(component + (component $C1 + (type $X' (resource (rep i32))) + (export $X "X" (type $X')) + + (core func $f (canon resource.drop $X)) + (func (export "f") (param "X" (own $X)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c2 (instantiate $C2 + (with "X" (type $c1 "X")) + (with "f" (func $c1 "f")) + )) +) + +(assert_invalid + (component + (component $C1 + (type $X' (resource (rep i32))) + (export $X "X" (type $X')) + + (core func $f (canon resource.drop $X)) + (func (export "f") (param "X" (own $X)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + (instance $c2 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c3 (instantiate $C2 + (with "X" (type $c1 "X")) + (with "f" (func $c2 "f")) + )) + ) + "resource types are not the same") + +(component + (component $C1 + (type $X (resource (rep i32))) + (export $X1 "X1" (type $X)) + (export $X2 "X2" (type $X)) + + (core func $f (canon resource.drop $X)) + (func (export "f1") (param "X" (own $X1)) (canon lift (core func $f))) + (func (export "f2") (param "X" (own $X2)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c2 (instantiate $C2 + (with "X" (type $c1 "X1")) + (with "f" (func $c1 "f1")) + )) + (instance $c3 (instantiate $C2 + (with "X" (type $c1 "X2")) + (with "f" (func $c1 "f2")) + )) +) + +(component + (component $C1 + (type $X (resource (rep i32))) + (export $X1 "X1" (type $X)) + (export $X2 "X2" (type $X)) + + (core func $f (canon resource.drop $X)) + (func (export "f1") (param "X" (own $X1)) (canon lift (core func $f))) + (func (export "f2") (param "X" (own $X2)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c2 (instantiate $C2 + (with "X" (type $c1 "X1")) + (with "f" (func $c1 "f2")) + )) + (instance $c3 (instantiate $C2 + (with "X" (type $c1 "X2")) + (with "f" (func $c1 "f1")) + )) +) + +(assert_invalid + (component + (component $c + (import "x" (type (sub resource))) + ) + (type $x u32) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected resource, found defined type") + +(assert_invalid + (component + (component $c + (type $t u32) + (import "x" (type (eq $t))) + ) + (type $x (resource (rep i32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected defined type, found resource") + +(assert_invalid + (component + (component $c + (import "x1" (type $x1 (sub resource))) + (import "x2" (type $x2 (eq $x1))) + ) + (type $x1 (resource (rep i32))) + (type $x2 (resource (rep i32))) + (instance (instantiate $c + (with "x1" (type $x1)) + (with "x2" (type $x2)) + )) + ) + "resource types are not the same") + +(component + (type $x (resource (rep i32))) + (component $c + (import "x" (type $t (sub resource))) + (export "y" (type $t)) + ) + (instance $c (instantiate $c (with "x" (type $x)))) + + (alias export $c "y" (type $x2)) + (core func (canon resource.rep $x2)) + +) + +(assert_invalid + (component + (type $r (resource (rep i32))) + (import "x" (func (result (own $r)))) + ) + "func not valid to be used as import") + +(assert_invalid + (component + (type (component + (export "x" (type $x (sub resource))) + (import "f" (func (result (own $x)))) + )) + ) + "func not valid to be used as import") + +(assert_invalid + (component + (type $r (resource (rep i32))) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) + ) + "func not valid to be used as export") + +;; direct exports count as "explicit in" for resources +(component + (type $r' (resource (rep i32))) + (export $r "r" (type $r')) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; instances-as-a-bundle count as "explicit in" for resources +(component + (type $r' (resource (rep i32))) + (instance $i' + (export "r" (type $r')) + ) + (export $i "i" (instance $i')) + (alias export $i "r" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Transitive bundles count for "explicit in" +(component + (type $r' (resource (rep i32))) + (instance $i' + (export "r" (type $r')) + ) + (instance $i2' + (export "i" (instance $i')) + ) + (export $i2 "i2" (instance $i2')) + (alias export $i2 "i" (instance $i)) + (alias export $i "r" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Component instantiations count for "explicit in" +(component + (type $r' (resource (rep i32))) + (component $C + (import "x" (type $x (sub resource))) + (export "y" (type $x)) + ) + (instance $c' (instantiate $C (with "x" (type $r')))) + (export $c "c" (instance $c')) + (alias export $c "y" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Make sure threading things around is valid for "explicit in" +(component + (type $r' (resource (rep i32))) + (component $C + (import "x" (type $x (sub resource))) + (export "y" (type $x)) + ) + (instance $c (instantiate $C (with "x" (type $r')))) + (instance $i (export "x" (type $c "y"))) + + (component $C2 + (import "x" (instance $i + (export "i1" (instance + (export "i2" (type (sub resource))) + )) + )) + (export "y" (type $i "i1" "i2")) + ) + + (instance $i2 (export "i2" (type $i "x"))) + (instance $i1 (export "i1" (instance $i2))) + (instance $c2 (instantiate $C2 + (with "x" (instance $i1)) + )) + (export $r "x" (type $c2 "y")) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Importing-and-exporting instances through instantiation counts for "explicit +;; in" +(component + (type $r' (resource (rep i32))) + (component $C + (import "x" (instance $x (export "t" (type (sub resource))))) + (export "y" (instance $x)) + ) + (instance $c' (instantiate $C + (with "x" (instance + (export "t" (type $r')) + )) + )) + (export $c "c" (instance $c')) + (alias export $c "y" (instance $y)) + (alias export $y "t" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +(component definition + (type $i (instance + (export "r" (type $r (sub resource))) + (export "f" (func (result (own $r)))) + )) + (import "i1" (instance $i1 (type $i))) + (import "i2" (instance $i2 (type $i))) + + (component $c + (import "r" (type $t (sub resource))) + (import "f" (func (result (own $t)))) + ) + (instance (instantiate $c + (with "r" (type $i1 "r")) + (with "f" (func $i1 "f")) + )) + (instance (instantiate $c + (with "r" (type $i2 "r")) + (with "f" (func $i2 "f")) + )) +) + + +(assert_invalid + (component + (type $i (instance + (export "r" (type $r (sub resource))) + (export "f" (func (result (own $r)))) + )) + (import "i1" (instance $i1 (type $i))) + (import "i2" (instance $i2 (type $i))) + + (component $c + (import "r" (type $t (sub resource))) + (import "f" (func (result (own $t)))) + ) + (instance (instantiate $c + (with "r" (type $i1 "r")) + (with "f" (func $i2 "f")) + )) + ) + "resource types are not the same") + +;; substitution works +(component + (type $t (resource (rep i32))) + (component $c + (import "x" (type $t (sub resource))) + (export "y" (type $t)) + ) + (instance $c1 (instantiate $c (with "x" (type $t)))) + (instance $c2 (instantiate $c (with "x" (type $t)))) + + (component $c2 + (import "x1" (type $t (sub resource))) + (import "x2" (type (eq $t))) + (import "x3" (type (eq $t))) + ) + (instance (instantiate $c2 + (with "x1" (type $t)) + (with "x2" (type $c1 "y")) + (with "x3" (type $c2 "y")) + )) +) + +;; must supply a resource to instantiation +(assert_invalid + (component + (component $c + (import "x" (type (sub resource))) + ) + (instance (instantiate $c)) + ) + "missing import named `x`") +(assert_invalid + (component + (type $x (resource (rep i32))) + (component $c + (import "x" (type (sub resource))) + (import "y" (type (sub resource))) + ) + (instance (instantiate $c (with "x" (type $x)))) + ) + "missing import named `y`") + +;; supply the wrong resource +(assert_invalid + (component + (type $x (resource (rep i32))) + (type $y (resource (rep i32))) + (component $c + (import "x" (type $t (sub resource))) + (import "y" (type (eq $t))) + ) + (instance (instantiate $c + (with "x" (type $x)) + (with "y" (type $y)) + )) + ) + "resource types are not the same") + +;; aliasing outer resources is ok +(component $A + (type $C (component + (import "x" (type $x (sub resource))) + + (type $y (component + (alias outer $C $x (type $my-x)) + (import "x" (type (eq $my-x))) + )) + + (import "y" (component (type $y))) + (export "z" (component (type $y))) + )) + + (type $t (resource (rep i32))) + + (alias outer $A $t (type $other-t)) + + (type (instance (export "t" (type (eq $t))))) + (type (component (export "t" (type (eq $t))))) + (type (component (import "t" (type (eq $t))))) +) + +;; aliasing beyond components, however, is not ok +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (component (alias outer $A $t (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (record (field "x" (own $t)))) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (borrow $t)) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (component (export "a" (type (eq $t))))) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (component (import "a" (type (eq $t))))) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") + +(assert_invalid + (component + (component $X + (type $t (resource (rep i32))) + (export "t" (type $t)) + ) + (component $F + (import "x" (component (export "t" (type $t (sub resource))))) + ) + (instance $x1 (instantiate $X)) + (instance $f1 (instantiate $F (with "x" (instance $x1)))) + ) + "expected component, found instance") + +;; Show that two instantiations of the same component produce unique exported +;; resource types. +(assert_invalid + (component + (component $F + (type $t1 (resource (rep i32))) + (export "t1" (type $t1)) + ) + (instance $f1 (instantiate $F)) + (instance $f2 (instantiate $F)) + (alias export $f1 "t1" (type $t1)) + (alias export $f2 "t1" (type $t2)) + (component $T + (import "x" (type $x (sub resource))) + (import "y" (type (eq $x))) + ) + (instance $test + (instantiate $T (with "x" (type $t1)) (with "y" (type $t2)))) + ) + "type mismatch for import `y`") + +;; Show that re-exporting imported resources from an imported component doesn't +;; change the identity of that resource. +(component + (component $X + (type $t (resource (rep i32))) + (export "t" (type $t)) + ) + (component $F + (import "x" (instance $i (export "t" (type $t (sub resource))))) + (alias export $i "t" (type $t)) + (export "t" (type $t)) + ) + (instance $x1 (instantiate $X)) + (instance $f1 (instantiate $F (with "x" (instance $x1)))) + (instance $f2 (instantiate $F (with "x" (instance $x1)))) + (alias export $f1 "t" (type $t1)) + (alias export $f2 "t" (type $t2)) + (component $T + (import "x" (type $x (sub resource))) + (import "y" (type (eq $x))) + ) + (instance $test + (instantiate $T (with "x" (type $t1)) (with "y" (type $t2)))) +) + +(assert_invalid + (component (import "[static]" (func))) + "failed to find `.` character") + +;; validation of `[constructor]foo` +(assert_invalid + (component (import "[constructor]" (func))) + "not in kebab case") +(assert_invalid + (component (import "[constructor]a" (func))) + "should return one value") +(assert_invalid + (component (import "[constructor]a" (func (result u32)))) + "should return `(own $T)`") +(assert_invalid + (component + (import "b" (type $a (sub resource))) + (import "[constructor]a" (func (result (own $a))))) + "import name `[constructor]a` is not valid") +(assert_invalid + (component + (import "b" (type $a (sub resource))) + (import "[constructor]a" (func (result (own $a))))) + "function does not match expected resource name `b`") +(assert_invalid + (component + (import "b" (type $a (sub resource))) + (import "[constructor]a" (func (result (result(own $a)))))) + "function does not match expected resource name `b`") +(component definition + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (own $a))))) +(component definition + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (result (own $a)))))) +(component definition + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (result (own $a) (error string)))))) +(component definition + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (param "x" u32) (result (own $a))))) +(assert_invalid + (component + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result string)))) + "function should return `(own $T)` or `(result (own $T))`") +(assert_invalid + (component + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (result string))))) + "function should return `(own $T)` or `(result (own $T))`") + +;; validation of `[method]a.b` +(assert_invalid + (component (import "[method]" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[method]a" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[method]a." (func))) + "not in kebab case") +(assert_invalid + (component (import "[method].a" (func))) + "not in kebab case") +(assert_invalid + (component (import "[method]a.b.c" (func))) + "not in kebab case") +(assert_invalid + (component (import "[method]a.b" (instance))) + "is not a func") +(assert_invalid + (component (import "[method]a.b" (func))) + "should have at least one argument") +(assert_invalid + (component (import "[method]a.b" (func (param "x" u32)))) + "should have a first argument called `self`") +(assert_invalid + (component (import "[method]a.b" (func (param "self" u32)))) + "should take a first argument of `(borrow $T)`") +(assert_invalid + (component + (import "b" (type $T (sub resource))) + (import "[method]a.b" (func (param "self" (borrow $T))))) + "does not match expected resource name") +(component definition + (import "a" (type $T (sub resource))) + (import "[method]a.b" (func (param "self" (borrow $T))))) + +;; validation of `[static]a.b` +(assert_invalid + (component (import "[static]" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[static]a" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[static]a." (func))) + "not in kebab case") +(assert_invalid + (component (import "[static].a" (func))) + "not in kebab case") +(assert_invalid + (component (import "[static]a.b.c" (func))) + "not in kebab case") +(assert_invalid + (component (import "[static]a.b" (instance))) + "is not a func") +(assert_invalid + (component (import "[static]a.b" (func))) + "static resource name is not known in this context") + +(component definition + (import "a" (type (sub resource))) + (import "[static]a.b" (func))) + +;; exports/imports are disjoint +(assert_invalid + (component + (import "b" (type $T (sub resource))) + (import "f" (func $f (param "self" (borrow $T)))) + (export "[method]b.foo" (func $f)) + ) + "resource used in function does not have a name in this context") + +(component + (component + (import "b" (type $T (sub resource))) + (import "f" (func $f (param "self" (borrow $T)))) + (export $c "c" (type $T)) + (export "[method]c.foo" (func $f) (func (param "self" (borrow $c)))) + ) +) + +;; imports aren't transitive +(assert_invalid + (component + (import "i" (instance $i + (export "t" (type (sub resource))) + )) + (alias export $i "t" (type $t)) + (import "[method]t.foo" (func (param "self" (borrow $t)))) + ) + "resource used in function does not have a name in this context") + +;; validation happens in a type context +(assert_invalid + (component + (type (component + (import "b" (type $T (sub resource))) + (import "[constructor]a" (func (result (own $T)))) + )) + ) + "function does not match expected resource name `b`") + +;; bag-of-exports validation +(assert_invalid + (component + (type $T (resource (rep i32))) + (core module $m (func (export "a") (result i32) unreachable)) + (core instance $i (instantiate $m)) + (func $f (result (own $T)) (canon lift (core func $i "a"))) + (instance + (export "a" (type $T)) + (export "[constructor]a" (func $f)) + ) + ) + "resource used in function does not have a name in this context") + +(component + (component $C) + (instance (instantiate $C (with "this is not kebab case" (component $C)))) +) + +;; Test that unused arguments to instantiation are not validated to have +;; appropriate types with respect to kebab naming conventions which require +;; functions/interfaces/etc. +(component + (component $C) + (instance (instantiate $C (with "[method]foo.bar" (component $C)))) +) + +;; thread a resource through a few layers +(component + (component $C + (import "in" (type $r (sub resource))) + (export "out" (type $r)) + ) + + (type $r (resource (rep i32))) + + (instance $c1 (instantiate $C (with "in" (type $r)))) + (instance $c2 (instantiate $C (with "in" (type $c1 "out")))) + (instance $c3 (instantiate $C (with "in" (type $c2 "out")))) + (instance $c4 (instantiate $C (with "in" (type $c3 "out")))) + (instance $c5 (instantiate $C (with "in" (type $c4 "out")))) + + (component $C2 + (import "in1" (type $r (sub resource))) + (import "in2" (type (eq $r))) + (import "in3" (type (eq $r))) + (import "in4" (type (eq $r))) + (import "in5" (type (eq $r))) + (import "in6" (type (eq $r))) + ) + + (instance (instantiate $C2 + (with "in1" (type $r)) + (with "in2" (type $c1 "out")) + (with "in3" (type $c2 "out")) + (with "in4" (type $c3 "out")) + (with "in5" (type $c4 "out")) + (with "in6" (type $c5 "out")) + )) +) + +;; exporting an instance type "freshens" resources +(assert_invalid + (component + (import "x" (instance $i + (type $i (instance + (export "r" (type (sub resource))) + )) + (export "a" (instance (type $i))) + (export "b" (instance (type $i))) + )) + + (component $C + (import "x" (type $x (sub resource))) + (import "y" (type (eq $x))) + ) + (instance (instantiate $C + (with "x" (type $i "a" "r")) + (with "y" (type $i "b" "r")) + )) + ) + "resource types are not the same") + +(component + (type (export "x") (component + (type $t' (instance + (export "r" (type (sub resource))) + )) + (export "t" (instance $t (type $t'))) + (alias export $t "r" (type $r)) + (type $t2' (instance + (export "r2" (type (eq $r))) + (export "r" (type (sub resource))) + )) + (export "t2" (instance (type $t2'))) + )) +) + +(component + (type (component + (type (instance + (export "bar" (type (sub resource))) + (export "[static]bar.a" (func)) + )) + (export "x" (instance (type 0))) + )) +) + +(assert_invalid + (component + (type $r (resource (rep i32))) + (type (func (result (borrow $r)))) + ) + "function result cannot contain a `borrow` type") +(assert_invalid + (component + (type $r (resource (rep i32))) + (type (func (result (list (borrow $r))))) + ) + "function result cannot contain a `borrow` type") +(assert_invalid + (component + (type $r (resource (rep i32))) + (type (func (result (option (borrow $r))))) + ) + "function result cannot contain a `borrow` type") +(assert_invalid + (component + (type $r (resource (rep i32))) + (type $t (record (field "f" (borrow $r)))) + (type (func (result (option (list $t))))) + ) + "function result cannot contain a `borrow` type") + +;; forms of canon builtins +(component + (type $r (resource (rep i32))) + (core func (canon resource.new $r)) + (canon resource.new $r (core func)) + (core func (canon resource.drop $r)) + (canon resource.drop $r (core func)) + (core func (canon resource.rep $r)) + (canon resource.rep $r (core func)) +) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/tags.wast b/parser/src/test/resources/spec-tests/wasm-tools/tags.wast new file mode 100644 index 0000000..5c70d3a --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/tags.wast @@ -0,0 +1,30 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (alias core export $i "" (core tag $t)) + ) + "export `` for core instance 0 is not a tag") + +(component + (core module $m (tag (export ""))) + (core instance $i (instantiate $m)) + (alias core export $i "" (core tag $t)) +) + +(component + (core module $m (tag (export ""))) + (core instance $i (instantiate $m)) + (core instance + (export "" (tag $i "")))) + +(assert_invalid + (component + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (core instance + (export "" (tag 0))) + ) + "unknown tag 0") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast b/parser/src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast new file mode 100644 index 0000000..d2971f8 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast @@ -0,0 +1,504 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; Test that unnamed types in various types are all detected + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (record (field "f" $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (tuple $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (variant (case "c" $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (option $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (result $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +;; Test that various types are all flagged as "requires a name" + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (enum "a")) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (flags "a")) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (variant (case "a"))) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (resource (rep i32))) + (type $f (list (own $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +;; Some types don't need names +(component + (type $t1 (tuple (tuple u32))) + (export "t1" (type $t1)) + + (type $t2 (option (tuple (list u8) (result (list u32) (error (option string)))))) + (export "t2" (type $t2)) + + (type $t3 u32) + (export "t3" (type $t3)) +) + +(component + (type $t' (record (field "f" u32))) + (export $t "t" (type $t')) + (type $t2 (record (field "x" $t))) + (export "t2" (type $t2)) +) + +;; imports are validated as well +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $t2 (record (field "f" $t))) + (import "x" (type (eq $t2))) + ) + "type not valid to be used as import") +(component + (type $t (record (field "f" u32))) + (import "t" (type $t' (eq $t))) + (type $t2 (record (field "f" $t'))) + (import "x" (type (eq $t2))) +) +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $t2 (record (field "f" $t))) + (import "x" (func (param "x" $t2))) + ) + "func not valid to be used as import") + +(assert_invalid + (component + (type $t (resource (rep i32))) + (export "t" (type $t)) + (type $f (list (own $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +;; validate within the type context +(assert_invalid + (component + (type (component + (type $t (record (field "f" u32))) + (export "f" (func (param "x" $t))) + )) + ) + "func not valid to be used as export") +(assert_invalid + (component + (type (component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + ) + "type not valid to be used as export") + +;; instances of unexported types is ok +(component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (instance + (export "f" (type $f)) + ) +) +;; .. but exporting them is not +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (instance $i + (export "f" (type $f)) + ) + (export "i" (instance $i)) + ) + "instance not valid to be used as export") + +;; Can't export a lifted function with unexported types +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $f) (canon lift (core func $i "f"))) + (export "f" (func $f)) + ) + "func not valid to be used as export") + +;; Unexported instances don't work +(assert_invalid + (component + (type $t' (record (field "f" u32))) + (instance $i + (export "t" (type $t')) + ) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) + ) + "func not valid to be used as export") + +;; Even through a component it doesn't work +(assert_invalid + (component + (component $C + (type $t (record (field "f" u32))) + (export "t" (type $t)) + ) + (instance $i (instantiate $C)) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) + ) + "func not valid to be used as export") + +;; through exported instances is ok though +(component + (type $t' (record (field "f" u32))) + (instance $i' + (export "t" (type $t')) + ) + (export $i "i" (instance $i')) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) +) +(component + (component $C + (type $t (record (field "f" u32))) + (export "t" (type $t)) + ) + (instance $i' (instantiate $C)) + (export $i "i" (instance $i')) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) +) + +;; a type-ascribed export which is otherwise invalid can become valid +(component + (type $t (record (field "f" u32))) + + (core module $m (func (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "x" $t) (canon lift (core func $i "f"))) + + (export $t' "t" (type $t)) + (export "f" (func $f) (func (param "x" $t'))) +) + +;; imports can't reference exports +(assert_invalid + (component + (type $t1 (record (field "f" u32))) + (export $t2 "t1" (type $t1)) + (import "i" (func (result $t2))) + ) + "func not valid to be used as import") + +;; exports can reference imports +(component + (type $t1 (record (field "f" u32))) + (import "t1" (type $t2 (eq $t1))) + (export "e-t1" (type $t2)) +) +(component + (component + (type $t1 (record (field "f" u32))) + (import "t1" (type $t2 (eq $t1))) + (import "i" (func $f (result $t2))) + + (export "e-i" (func $f)) + ) +) + +;; outer aliases don't work for imports/exports +(assert_invalid + (component + (type $t1 (record (field "f" u32))) + (import "t1" (type $t2 (eq $t1))) + (component + (import "i" (func $f (result $t2))) + ) + ) + "func not valid to be used as import") +(assert_invalid + (component + (type $t1 (record (field "f" u32))) + (export $t2 "t1" (type $t1)) + (component + (core module $m (func (export "f") (result i32) unreachable)) + (core instance $i (instantiate $m)) + (func $f (export "i") (result $t2) (canon lift (core func $i "f"))) + ) + ) + "func not valid to be used as export") + +;; outer aliases work for components, modules, and resources +(component + (type $c (component)) + (type (component + (import "c" (component (type $c))) + )) + (component + (import "c" (component (type $c))) + ) + (type $i (instance)) + (type (component + (import "c" (instance (type $i))) + )) + + (type $r (resource (rep i32))) + (type (component + (import "r" (type (eq $r))) + )) +) + +;; reexport of an import is fine +(component + (component + (import "r" (func $r)) + (export "r2" (func $r)) + ) +) +(component + (type $t (record (field "f" u32))) + (import "r" (type $r (eq $t))) + (export "r2" (type $r)) +) +(component + (import "r" (instance $r)) + (export "r2" (instance $r)) +) +(component definition + (import "r" (type $r (sub resource))) + (export "r2" (type $r)) +) + +;; bag of exports cannot be exported by carrying through context that's not +;; otherwise exported +(assert_invalid + (component + (component $A + (type $t (record (field "f" u32))) + (export $t2 "t" (type $t)) + (core module $m (func (export "f") (result i32) unreachable)) + (core instance $i (instantiate $m)) + (func $f (result $t2) (canon lift (core func $i "f"))) + + (instance (export "i") + (export "f" (func $f)) + ) + ) + + (instance $a (instantiate $A)) + ;; this component only exports `f`, not the record type that is the result + ;; of `f`, so it should be invalid. + (export "a" (instance $a "i")) + ) + "instance not valid to be used as export") + +;; instance types can be "temporarily invalid", but not if they're attached +;; to a concrete component +(component + (type (instance + (type $t (record (field "f" u32))) + (export "f" (func (param "x" $t))) + )) +) +(assert_invalid + (component + (type $i (instance + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + (import "f" (instance (type $i))) + ) + "instance not valid to be used as import") + +;; allow for one import to refer to another +(component definition $C + (import "foo" (instance $i + (type $baz' (record (field "f" u32))) + (export "baz" (type $baz (eq $baz'))) + (type $bar' (record (field "baz" $baz))) + (export "bar" (type $bar (eq $bar'))) + )) + (alias export $i "bar" (type $bar)) + (import "bar" (instance + (alias outer $C $bar (type $bar')) + (export "bar" (type $bar (eq $bar'))) + (export "a" (func $f (result $bar))) + )) +) + +;; allow for one import to refer to another +(component + (type $r' (record (field "f" u32))) + (import "r" (type $r (eq $r'))) + (component $C + (type $r' (record (field "f" u32))) + (import "r" (type $r (eq $r'))) + (type $r2' (record (field "r" $r))) + (export "r2" (type $r2')) + ) + (instance $c (instantiate $C (with "r" (type $r)))) + (export "r2" (type $c "r2")) +) + +;; types are validated when they are exported +(assert_invalid + (component + (type $i (instance + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + (import "f" (type (eq $i))) + ) + "type not valid to be used as import") +(assert_invalid + (component + (type $i (instance + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + (export "f" (type $i)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (func (result $t))) + (import "f" (type (eq $f))) + ) + "type not valid to be used as import") +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (func (result $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(component + (type (;0;) + (instance + (type (;0;) (enum "qux")) + (export (;1;) "baz" (type (eq 0))) + (type (;2;) (record (field "bar" 1) )) + (export (;3;) "foo" (type (eq 2))) + ) + ) + (import (interface "demo:component/types") (instance (;0;) (type 0))) + (component + (type (;0;) + (instance + (type (;0;) (enum "qux")) + (export (;1;) "baz" (type (eq 0))) + (type (;2;) (record (field "bar" 1) )) + (export (;3;) "foo" (type (eq 2))) + ) + ) + (import (interface "demo:component/types") (instance (;0;) (type 0))) + (component (;0;) + (type (;0;) (enum "qux")) + (import "import-type-baz" (type (;1;) (eq 0))) + (type (;2;) (record (field "bar" 1) )) + (import "import-type-bar" (type (;3;) (eq 2))) + (export (;4;) "foo" (type 3)) + ) + (instance (;1;) (instantiate 0 + (with "import-type-baz" (type 0 "baz")) + (with "import-type-bar" (type 0 "foo")) + ) + ) + (export (;0;) (interface "demo:component/types") (instance 1)) + ) + (instance (instantiate 0 (with "demo:component/types" (instance 0)))) + (export (interface "demo:component/types") (instance 1 "demo:component/types")) +) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/types.wast b/parser/src/test/resources/spec-tests/wasm-tools/types.wast new file mode 100644 index 0000000..5df1ec9 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/types.wast @@ -0,0 +1,374 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (type $t (instance)) + (import "a" (func (type $t))) + ) + "type index 0 is not a function type") + +(assert_invalid + (component + (core type $t (func)) + (import "a" (core module (type $t))) + ) + "core type index 0 is not a module type") + +(assert_invalid + (component + (type $t (func)) + (import "a" (instance (type $t))) + ) + "type index 0 is not an instance type") + +(assert_invalid + (component + (type $t (func)) + (type (component + (import "a" (instance (type $t))) + )) + ) + "type index 0 is not an instance type") + +(assert_invalid + (component + (core type $t (func)) + (type (component + (import "a" (core module (type $t))) + )) + ) + "core type index 0 is not a module type") + +(assert_invalid + (component + (type $t (instance)) + (type (component + (import "a" (func (type $t))) + )) + ) + "type index 0 is not a function type") + +(assert_invalid + (component + (export "a" (core module 0)) + ) + "module index out of bounds") + +(assert_invalid + (component + (export "a" (instance 0)) + ) + "instance index out of bounds") + +(assert_invalid + (component + (core type (module + (export "a" (func (type 0))) + )) + ) + "type index out of bounds") + +(assert_invalid + (component + (core type (module + (export "a" (func)) + (export "a" (func)) + )) + ) + "export name `a` already defined") + +(assert_invalid + (component + (core type (module + (import "" "" (func)) + (import "" "" (func)) + )) + ) + "duplicate import name") + +(assert_invalid + (component + (core type (module + (import "" "" (memory 70000)) + )) + ) + "memory size must be at most") + +(assert_invalid + (component + (type (component + (export "a" (func (type 0))) + )) + ) + "type index out of bounds") + +(assert_invalid + (component + (type (component + (export "a" (func)) + (export "A" (func)) + )) + ) + "export name `A` conflicts with previous name `a`") + +(assert_invalid + (component + (type (component + (import "A" (func)) + (import "a" (func)) + )) + ) + "import name `a` conflicts with previous name `A`") + +(assert_malformed + (component quote + "(component $c (core type $t (module (alias outer $c $t (type)))))" + ) + "unknown core type") + +(assert_invalid + (component + (core type (module + (alias outer 1 0 (type)) + )) + ) + "type index out of bounds") + +(component $c + (core type $f (func)) + (core type $t (module + (alias outer $c $f (type)) + )) +) + +(assert_malformed + (component quote + "(component $c (type $t (component (alias outer $c $t (type)))))" + ) + "unknown type") + +(assert_invalid + (component + (type (component + (alias outer 1 0 (type)) + )) + ) + "type index out of bounds") + +(assert_invalid + (component $c + (type $f (func)) + (type $t (component + (alias outer 100 0 (type)) + )) + ) + "invalid outer alias count of 100") + +(assert_invalid + (component $c + (type $f (func)) + (type $t (component + (core type (module + (export "" (func)) + (export "" (func)) + )) + )) + ) + "name `` already defined") + +(assert_invalid + (component + (type (instance + (export "" (func (type 0))) + )) + ) + "type index out of bounds") + +(assert_invalid + (component + (type (instance + (export "foo-BAR-baz" (func)) + (export "FOO-bar-BAZ" (func)) + )) + ) + "export name `FOO-bar-BAZ` conflicts with previous name `foo-BAR-baz`") + +(assert_malformed + (component quote + "(component $c (type $t (instance (alias outer $c $t (type)))))" + ) + "unknown type") + +(assert_invalid + (component + (type (instance + (alias outer 1 0 (type)) + )) + ) + "type index out of bounds") + +(assert_invalid + (component $c + (type $f (func)) + (type $t (instance + (alias outer 100 0 (type)) + )) + ) + "invalid outer alias count of 100") + +(assert_invalid + (component $c + (type $f (func)) + (type $t (instance + (core type (module + (export "" (func)) + (export "" (func)) + )) + )) + ) + "name `` already defined") + +(assert_invalid + (component $c + (type $f (func (param "" string))) + ) + "function parameter name cannot be empty") + +(component + (type $t (func (result (tuple (list u8) u32)))) +) + +(component $C + (core type $t (func)) + (core type (module + (alias outer $C $t (type $a)) + (import "" "" (func (type $a))) + )) +) + +(component $C + (component $C2 + (core type $t (func)) + (core type (module + (alias outer $C2 $t (type $a)) + (import "" "" (func (type $a))) + )) + ) +) + +(component $C + (core type $t (func)) + (component $C2 + (core type (module + (alias outer $C $t (type $a)) + (import "" "" (func (type $a))) + )) + ) +) + +(component + (type (instance + (type string) + (export "a" (type (eq 0))) + )) +) + +(component + (type (component + (type string) + (import "a" (type (eq 0))) + (export "b" (type (eq 0))) + )) +) + +(assert_invalid + (component + (type (variant)) + ) + "variant type must have at least one case") + +(assert_invalid + (component + (type (enum)) + ) + "enum type must have at least one variant") + +(assert_invalid + (component + (type (record)) + ) + "record type must have at least one field") + +(assert_invalid + (component + (type (flags)) + ) + "flags must have at least one entry") + +(assert_invalid + (component + (type (tuple)) + ) + "tuple type must have at least one type") + +(component $c + (core type $f (func)) + (component $c2 + (core type $t (module + (alias outer $c $f (type)) + )) + ) +) + +(assert_invalid + (component + (type (flags + "f1" + "f2" + "f3" + "f4" + "f5" + "f6" + "f7" + "f8" + "f9" + "f10" + "f11" + "f12" + "f13" + "f14" + "f15" + "f16" + "f17" + "f18" + "f19" + "f20" + "f21" + "f22" + "f23" + "f24" + "f25" + "f26" + "f27" + "f28" + "f29" + "f30" + "f31" + "f32" + "f33" + )) + ) + "cannot have more than 32 flags") + +(assert_invalid + (component + (core type $t (module)) + (core type (func (param (ref $t)))) + ) + "type index 0 is a module type") + +(assert_invalid + (component + (core type (func (param (ref 100)))) + ) + "type index out of bounds") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/very-nested.wast b/parser/src/test/resources/spec-tests/wasm-tools/very-nested.wast new file mode 100644 index 0000000..42c5aed --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/very-nested.wast @@ -0,0 +1,1954 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component $$esl + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "00AGG554M******+*****e 4$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "anonmm-x23foinas-ASDOJASD") + ) + (component + (export "c t.****0*********") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "0+AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00A$qq") + ) + (component + (export "c t.*************") + (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "15AG:GG!le*$$qq") + ) + (component + (export "c t.*") + (component + (export "c 3@EGGGG$qq**") + (export "bsdew2-sdbsdb") + ) + (component + (export "c t.********)*eleo &m Nx2GGGGle*$$qq") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "0*************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "00AGG554M******+*****e 4$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "anonmm-x23foinas-ASDOJASD") + ) + (component + (export "c t.****0*********") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "0+AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00A$qq") + ) + (component + (export "c t.*************") + (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "15AG:GG!le*$$qq") + ) + (component + (export "c .t*") + (component + (export "c 3@EGGGG$qq**") + (export "bsdew2-sdbsdb") + ) + (component + (export "c t.********)*eleo &m Nx2GGGGle*$$qq") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle '$$qq") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c *****") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "00AGG554M******+*****e 4$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "anonmm-x23foinas-ASDOJASD") + ) + (component + (export "c t.****0*********") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "0+AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00A$qq") + ) + (component + (export "c t.*************") + (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "15AG:GG!le*$$qq") + ) + (component + (export "c t.*") + (component + (export "c 3@EGGGG$qq**") + (export "bsdew2-sdbsdb") + ) + (component + (export "c t.********)*eleo &m Nx2GGGGle*$$qq") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "0*************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "00AGG554M******+*****e 4$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "anonmm-x23foinas-ASDOJASD") + ) + (component + (export "c t.****0*********") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "0+AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00A$qq") + ) + (component + (export "c t.*************") + (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "15AG:GG!le*$$qq") + ) + (component + (export "c .t*") + (component + (export "c 3@EGGGG$qq**") + (export "bsdew2-sdbsdb") + ) + (component + (export "c t.********)*eleo &m Nx2GGGGle*$$qq") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle '$$qq") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E***0AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle '$$qq") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E**************777777777777777777777777777777777777777777777777777777777777771.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E***0AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle '$$qq") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + ) + "conflicts with previous name") + +(assert_invalid + (component + (type $m0 (component)) + (type $m1 (component + (import "i1" (component (type $m0))) + (import "i2" (component (type $m0))) + (import "i3" (component (type $m0))) + (import "i4" (component (type $m0))) + (import "i5" (component (type $m0))) + (import "i6" (component (type $m0))) + (import "i7" (component (type $m0))) + (import "i8" (component (type $m0))) + (import "i9" (component (type $m0))) + (import "i10" (component (type $m0))) + )) + (type $m2 (component + (import "i1" (component (type $m1))) + (import "i2" (component (type $m1))) + (import "i3" (component (type $m1))) + (import "i4" (component (type $m1))) + (import "i5" (component (type $m1))) + (import "i6" (component (type $m1))) + (import "i7" (component (type $m1))) + (import "i8" (component (type $m1))) + (import "i9" (component (type $m1))) + (import "i10" (component (type $m1))) + )) + (type $m3 (component + (import "i1" (component (type $m2))) + (import "i2" (component (type $m2))) + (import "i3" (component (type $m2))) + (import "i4" (component (type $m2))) + (import "i5" (component (type $m2))) + (import "i6" (component (type $m2))) + (import "i7" (component (type $m2))) + (import "i8" (component (type $m2))) + (import "i9" (component (type $m2))) + (import "i10" (component (type $m2))) + )) + (type $m4 (component + (import "i1" (component (type $m3))) + (import "i2" (component (type $m3))) + (import "i3" (component (type $m3))) + (import "i4" (component (type $m3))) + (import "i5" (component (type $m3))) + (import "i6" (component (type $m3))) + (import "i7" (component (type $m3))) + (import "i8" (component (type $m3))) + (import "i9" (component (type $m3))) + (import "i10" (component (type $m3))) + )) + (type $m5 (component + (import "i1" (component (type $m4))) + (import "i2" (component (type $m4))) + (import "i3" (component (type $m4))) + (import "i4" (component (type $m4))) + (import "i5" (component (type $m4))) + (import "i6" (component (type $m4))) + (import "i7" (component (type $m4))) + (import "i8" (component (type $m4))) + (import "i9" (component (type $m4))) + (import "i10" (component (type $m4))) + )) + (type $m6 (component + (import "i1" (component (type $m5))) + (import "i2" (component (type $m5))) + (import "i3" (component (type $m5))) + (import "i4" (component (type $m5))) + (import "i5" (component (type $m5))) + (import "i6" (component (type $m5))) + (import "i7" (component (type $m5))) + (import "i8" (component (type $m5))) + (import "i9" (component (type $m5))) + (import "i10" (component (type $m5))) + )) + (type $m7 (component + (import "i1" (component (type $m6))) + (import "i2" (component (type $m6))) + (import "i3" (component (type $m6))) + (import "i4" (component (type $m6))) + (import "i5" (component (type $m6))) + (import "i6" (component (type $m6))) + (import "i7" (component (type $m6))) + (import "i8" (component (type $m6))) + (import "i9" (component (type $m6))) + (import "i10" (component (type $m6))) + )) + (type $m8 (component + (import "i1" (component (type $m7))) + (import "i2" (component (type $m7))) + (import "i3" (component (type $m7))) + (import "i4" (component (type $m7))) + (import "i5" (component (type $m7))) + (import "i6" (component (type $m7))) + (import "i7" (component (type $m7))) + (import "i8" (component (type $m7))) + (import "i9" (component (type $m7))) + (import "i10" (component (type $m7))) + )) + (type $m9 (component + (import "i1" (component (type $m8))) + (import "i2" (component (type $m8))) + (import "i3" (component (type $m8))) + (import "i4" (component (type $m8))) + (import "i5" (component (type $m8))) + (import "i6" (component (type $m8))) + (import "i7" (component (type $m8))) + (import "i8" (component (type $m8))) + (import "i9" (component (type $m8))) + (import "i10" (component (type $m8))) + )) + + (type $m (component + (import "a" (component (type $m9))) + )) + (import "a" (component $a (type $m9))) + (import "b" (component $b (type $m))) + (instance (instantiate $b (with "a" (component $a)))) + ) + "effective type size exceeds the limit") + +(assert_invalid + (component + (component $m0) + (component $m1 + (instance (export "e0") (instantiate $m0)) + (instance (export "e1") (instantiate $m0)) + (instance (export "e2") (instantiate $m0)) + (instance (export "e3") (instantiate $m0)) + (instance (export "e4") (instantiate $m0)) + (instance (export "e5") (instantiate $m0)) + (instance (export "e6") (instantiate $m0)) + (instance (export "e7") (instantiate $m0)) + (instance (export "e8") (instantiate $m0)) + (instance (export "e9") (instantiate $m0)) + ) + (component $m2 + (instance (export "e0") (instantiate $m1)) + (instance (export "e1") (instantiate $m1)) + (instance (export "e2") (instantiate $m1)) + (instance (export "e3") (instantiate $m1)) + (instance (export "e4") (instantiate $m1)) + (instance (export "e5") (instantiate $m1)) + (instance (export "e6") (instantiate $m1)) + (instance (export "e7") (instantiate $m1)) + (instance (export "e8") (instantiate $m1)) + (instance (export "e9") (instantiate $m1)) + ) + (component $m3 + (instance (export "e0") (instantiate $m2)) + (instance (export "e1") (instantiate $m2)) + (instance (export "e2") (instantiate $m2)) + (instance (export "e3") (instantiate $m2)) + (instance (export "e4") (instantiate $m2)) + (instance (export "e5") (instantiate $m2)) + (instance (export "e6") (instantiate $m2)) + (instance (export "e7") (instantiate $m2)) + (instance (export "e8") (instantiate $m2)) + (instance (export "e9") (instantiate $m2)) + ) + (component $m4 + (instance (export "e0") (instantiate $m3)) + (instance (export "e1") (instantiate $m3)) + (instance (export "e2") (instantiate $m3)) + (instance (export "e3") (instantiate $m3)) + (instance (export "e4") (instantiate $m3)) + (instance (export "e5") (instantiate $m3)) + (instance (export "e6") (instantiate $m3)) + (instance (export "e7") (instantiate $m3)) + (instance (export "e8") (instantiate $m3)) + (instance (export "e9") (instantiate $m3)) + ) + (component $m5 + (instance (export "e0") (instantiate $m4)) + (instance (export "e1") (instantiate $m4)) + (instance (export "e2") (instantiate $m4)) + (instance (export "e3") (instantiate $m4)) + (instance (export "e4") (instantiate $m4)) + (instance (export "e5") (instantiate $m4)) + (instance (export "e6") (instantiate $m4)) + (instance (export "e7") (instantiate $m4)) + (instance (export "e8") (instantiate $m4)) + (instance (export "e9") (instantiate $m4)) + ) + (component $m6 + (instance (export "e0") (instantiate $m5)) + (instance (export "e1") (instantiate $m5)) + (instance (export "e2") (instantiate $m5)) + (instance (export "e3") (instantiate $m5)) + (instance (export "e4") (instantiate $m5)) + (instance (export "e5") (instantiate $m5)) + (instance (export "e6") (instantiate $m5)) + (instance (export "e7") (instantiate $m5)) + (instance (export "e8") (instantiate $m5)) + (instance (export "e9") (instantiate $m5)) + ) + (component $m7 + (instance (export "e0") (instantiate $m6)) + (instance (export "e1") (instantiate $m6)) + (instance (export "e2") (instantiate $m6)) + (instance (export "e3") (instantiate $m6)) + (instance (export "e4") (instantiate $m6)) + (instance (export "e5") (instantiate $m6)) + (instance (export "e6") (instantiate $m6)) + (instance (export "e7") (instantiate $m6)) + (instance (export "e8") (instantiate $m6)) + (instance (export "e9") (instantiate $m6)) + ) + ) + "effective type size exceeds the limit") + +(assert_invalid + (component + ;; size(t0) == 1 + (type $t0 (flags "x")) + + ;; size(t1) == 10 + (type $t1 (record + (field "f0" $t0) + (field "f1" $t0) + (field "f2" $t0) + (field "f3" $t0) + (field "f4" $t0) + (field "f5" $t0) + (field "f6" $t0) + (field "f7" $t0) + (field "f8" $t0) + (field "f9" $t0) + )) + + ;; size(t2) == 100 + (type $t2 (record + (field "f0" $t1) + (field "f1" $t1) + (field "f2" $t1) + (field "f3" $t1) + (field "f4" $t1) + (field "f5" $t1) + (field "f6" $t1) + (field "f7" $t1) + (field "f8" $t1) + (field "f9" $t1) + )) + + ;; size(t3) == 1000 + (type $t3 (record + (field "f0" $t2) + (field "f1" $t2) + (field "f2" $t2) + (field "f3" $t2) + (field "f4" $t2) + (field "f5" $t2) + (field "f6" $t2) + (field "f7" $t2) + (field "f8" $t2) + (field "f9" $t2) + )) + + ;; size(t4) == 10000 + (type $t4 (record + (field "f0" $t3) + (field "f1" $t3) + (field "f2" $t3) + (field "f3" $t3) + (field "f4" $t3) + (field "f5" $t3) + (field "f6" $t3) + (field "f7" $t3) + (field "f8" $t3) + (field "f9" $t3) + )) + + ;; size(t5) == 100000 + (type $t5 (record + (field "f0" $t4) + (field "f1" $t4) + (field "f2" $t4) + (field "f3" $t4) + (field "f4" $t4) + (field "f5" $t4) + (field "f6" $t4) + (field "f7" $t4) + (field "f8" $t4) + (field "f9" $t4) + )) + + (type $f (func + (param "a" $t5) + (param "b" $t5) + (param "c" $t5) + (param "d" $t5) + (param "e" $t5) + (param "f" $t5) + (param "g" $t5) + (param "h" $t5) + (param "i" $t5) + (param "j" $t5) + )) + ) + "effective type size exceeds the limit") + +(assert_malformed + (component quote + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + ) + "nesting too deep") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/virtualize.wast b/parser/src/test/resources/spec-tests/wasm-tools/virtualize.wast new file mode 100644 index 0000000..d60b73b --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/virtualize.wast @@ -0,0 +1,119 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (core module $libc + (memory (export "mem") 0) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable + ) + ) + (core instance $libc (instantiate $libc)) + + (component $child + (import "wasi-file" (instance $wasi-file + (export "read" (func (param "count" u32) (result (list u8)))) + (export "write" (func (param "bytes" (list u8)) (result u32))) + )) + + (core instance $libc (instantiate $libc)) + + (core module $m + (import "wasi-file" "read" (func $read (param i32 i32))) + (func $play (export "play") + unreachable + ) + ) + + (core func $wasi_file_read + (canon lower (func $wasi-file "read") + (memory $libc "mem") + (realloc (func $libc "realloc")) + ) + ) + + (core instance $i (instantiate $m + (with "wasi-file" (instance + (export "read" (func $wasi_file_read)) + )) + )) + + (func (export "play") + (canon lift (core func $i "play")) + ) + ) + + (component $virtualize + (import "wasi-file" (instance $wasi-file + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) + )) + (export "read" (func $wasi-file "read")) + (export "write" (func $wasi-file "write")) + ) + + (component + (type $WasiFile (instance + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) + )) + (import "wasi-file" (instance $real-wasi (type $WasiFile))) + (import "virtualize" (component $VIRTUALIZE + (import "wasi-file" (instance (type $WasiFile))) + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) + )) + (import "child" (component $CHILD + (import "wasi-file" (instance (type $WasiFile))) + (export "play" (func)) + ) + ) + + (instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi-file" (instance $real-wasi)))) + (instance $child (instantiate $CHILD (with "wasi-file" (instance $virt-wasi)))) + + (export "work" (func $child "play")) + ) + + (component + (type $WasiFile (instance + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) + )) + (import "wasi-file" (instance $real-wasi (type $WasiFile))) + + (core instance $libc (instantiate $libc)) + + (core module $CHILD + (import "wasi-file" "read" (func $wasi-file (param i32 i32))) + (func $play (export "play") + unreachable + ) + ) + + (core module $VIRTUALIZE + (import "wasi-file" "read" (func (param i32 i32))) + (func (export "read") (param i32 i32) + unreachable + ) + (func (export "write") (param i32 i32 i32) + unreachable + ) + ) + + (core func $real-wasi-read + (canon lower (func $real-wasi "read") + (memory $libc "mem") + (realloc (func $libc "realloc")) + ) + ) + + (core instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi-file" (instance (export "read" (func $real-wasi-read)))))) + (core instance $child (instantiate $CHILD (with "wasi-file" (instance $virt-wasi)))) + (func (export "work") + (canon lift (core func $child "play") + (memory $libc "mem") + (realloc (func $libc "realloc")) + ) + ) + ) +) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/wrong-order.wast b/parser/src/test/resources/spec-tests/wasm-tools/wrong-order.wast new file mode 100644 index 0000000..098fc41 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasm-tools/wrong-order.wast @@ -0,0 +1,11 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_malformed + (module binary + "\00asm\01\00\00\00" + + "\01\01\00" ;; type section, 1 byte, 0 entries + "\0b\01\00" ;; data section, 1 byte, 0 entries + "\01\01\00" ;; type section, 1 byte, 0 entries + ) + "section out of order") diff --git a/parser/src/test/resources/spec-tests/wasmtime/adapter.wast b/parser/src/test/resources/spec-tests/wasmtime/adapter.wast new file mode 100644 index 0000000..8432d58 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasmtime/adapter.wast @@ -0,0 +1,137 @@ +;;! multi_memory = true + +;; basic function lifting +(component + (core module $m + (func (export "")) + ) + (core instance $i (instantiate $m)) + + (func (export "thunk") + (canon lift (core func $i "")) + ) +) + +;; use an aliased type +(component $c + (core module $m + (func (export "")) + ) + (core instance $i (instantiate $m)) + + (type $to_alias (func)) + (alias outer $c $to_alias (type $alias)) + + (func (export "thunk") (type $alias) + (canon lift (core func $i "")) + ) +) + +;; test out some various canonical abi +(component $c + (core module $m + (func (export "") (param i32 i32)) + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "thunk") (param "a" string) + (canon lift + (core func $i "") + (memory $i "memory") + (realloc (func $i "realloc")) + ) + ) + + (func (export "thunk8") (param "a" string) + (canon lift + (core func $i "") + string-encoding=utf8 + (memory $i "memory") + (realloc (func $i "realloc")) + ) + ) + + (func (export "thunk16") (param "a" string) + (canon lift + (core func $i "") + string-encoding=utf16 + (memory $i "memory") + (realloc (func $i "realloc")) + ) + ) + + (func (export "thunklatin16") (param "a" string) + (canon lift + (core func $i "") + string-encoding=latin1+utf16 + (memory $i "memory") + (realloc (func $i "realloc")) + ) + ) +) + +;; lower something then immediately lift it +(component $c + (import "host-return-two" (func $f (result u32))) + + (core func $f_lower + (canon lower (func $f)) + ) + (func $f2 (result s32) + (canon lift (core func $f_lower)) + ) + (export "f" (func $f2)) +) + +;; valid, but odd +(component + (core module $m (func (export ""))) + (core instance $m (instantiate $m)) + + (func $f1 (canon lift (core func $m ""))) + (core func $f2 (canon lower (func $f1))) +) +(assert_trap + (component + (core module $m (func (export ""))) + (core instance $m (instantiate $m)) + + (func $f1 (canon lift (core func $m ""))) + (core func $f2 (canon lower (func $f1))) + + (core module $m2 + (import "" "" (func $f)) + (func $start + call $f) + (start $start) + ) + (core instance (instantiate $m2 + (with "" (instance (export "" (func $f2)))) + )) + ) + "cannot enter component instance") + +;; fiddling with 0-sized lists +(component $c + (core module $m + (func (export "x") (param i32 i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + i32.const -1) + (memory (export "memory") 0) + ) + (core instance $m (instantiate $m)) + (type $t' (result)) + (export $t "t" (type $t')) + (func $f (param "a" (list $t)) + (canon lift + (core func $m "x") + (realloc (func $m "realloc")) + (memory $m "memory") + ) + ) + (export "empty-list" (func $f)) +) +(assert_trap (invoke "empty-list" (list.const)) "realloc return: beyond end of memory") diff --git a/parser/src/test/resources/spec-tests/wasmtime/aliasing.wast b/parser/src/test/resources/spec-tests/wasmtime/aliasing.wast new file mode 100644 index 0000000..ad18f93 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasmtime/aliasing.wast @@ -0,0 +1,29 @@ +(component + (component + (component + (component) + (instance (instantiate 0)) + (export "a" (instance 0)) + ) + (instance (instantiate 0)) + (export "a" (instance 0)) + ) + + (instance (instantiate 0)) ;; instance 0 + (alias export 0 "a" (instance)) ;; instance 1 + (export "a" (instance 1)) ;; instance 2 + (alias export 2 "a" (instance)) ;; instance 3 + (export "inner-a" (instance 3)) ;; instance 4 +) + +(component + (component + (core module) + (export "a" (core module 0)) + ) + + (instance (instantiate 0)) + (alias export 0 "a" (core module)) ;; module 0 + (export "a" (core module 0)) ;; module 1 + (core instance (instantiate 1)) +) diff --git a/parser/src/test/resources/spec-tests/wasmtime/fused.wast b/parser/src/test/resources/spec-tests/wasmtime/fused.wast new file mode 100644 index 0000000..87fe846 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasmtime/fused.wast @@ -0,0 +1,1391 @@ +;;! multi_memory = true + +;; smoke test with no arguments and no results +(component + (component $a + (core module $m + (func (export "")) + ) + (core instance $m (instantiate $m)) + (func (export "foo") (canon lift (core func $m ""))) + ) + (instance $a (instantiate $a)) + + (component $c + (import "a" (instance $a + (export "foo" (func)) + )) + + (core func $foo (canon lower (func $a "foo"))) + (core module $m2 + (import "" "" (func)) + (start 0) + ) + (core instance $m2 (instantiate $m2 (with "" (instance (export "" (func $foo)))))) + ) + + (instance $c (instantiate $c (with "a" (instance $a)))) +) + +;; boolean parameters +(component + (component $a + (core module $m + (func (export "assert_true") (param i32) + local.get 0 + i32.const 1 + i32.eq + i32.eqz + if unreachable end + ) + (func (export "assert_false") (param i32) + local.get 0 + if unreachable end + ) + (func (export "ret-bool") (param i32) (result i32) + local.get 0 + ) + ) + (core instance $m (instantiate $m)) + (func (export "assert-true") (param "a" bool) (canon lift (core func $m "assert_true"))) + (func (export "assert-false") (param "a" bool) (canon lift (core func $m "assert_false"))) + (func (export "ret-bool") (param "a" u32) (result bool) (canon lift (core func $m "ret-bool"))) + ) + (instance $a (instantiate $a)) + + (component $c + (import "a" (instance $a + (export "assert-true" (func (param "a" bool))) + (export "assert-false" (func (param "a" bool))) + (export "ret-bool" (func (param "a" u32) (result bool))) + )) + + (core func $assert_true (canon lower (func $a "assert-true"))) + (core func $assert_false (canon lower (func $a "assert-false"))) + (core func $ret_bool (canon lower (func $a "ret-bool"))) + + (core module $m2 + (import "" "assert-true" (func $assert_true (param i32))) + (import "" "assert-false" (func $assert_false (param i32))) + (import "" "ret-bool" (func $ret_bool (param i32) (result i32))) + + (func $start + (call $assert_true (i32.const 1)) + (call $assert_true (i32.const 2)) + (call $assert_true (i32.const -1)) + (call $assert_false (i32.const 0)) + + (if (i32.ne (call $ret_bool (i32.const 1)) (i32.const 1)) + (then (unreachable))) + (if (i32.ne (call $ret_bool (i32.const 2)) (i32.const 1)) + (then (unreachable))) + (if (i32.ne (call $ret_bool (i32.const -1)) (i32.const 1)) + (then (unreachable))) + (if (i32.ne (call $ret_bool (i32.const 0)) (i32.const 0)) + (then (unreachable))) + ) + (start $start) + ) + (core instance $m2 (instantiate $m2 + (with "" (instance + (export "assert-true" (func $assert_true)) + (export "assert-false" (func $assert_false)) + (export "ret-bool" (func $ret_bool)) + )) + )) + ) + + (instance $c (instantiate $c (with "a" (instance $a)))) +) + +;; lots of parameters and results +(component + (component $a + (type $roundtrip (func + ;; 20 u32 params + (param "a1" u32) (param "a2" u32) (param "a3" u32) (param "a4" u32) (param "a5" u32) + (param "a6" u32) (param "a7" u32) (param "a8" u32) (param "a9" u32) (param "a10" u32) + (param "a11" u32) (param "a12" u32) (param "a13" u32) (param "a14" u32) (param "a15" u32) + (param "a16" u32) (param "a17" u32) (param "a18" u32) (param "a19" u32) (param "a20" u32) + + ;; 10 u32 results + (result (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) + )) + + (core module $m + (memory (export "memory") 1) + (func (export "roundtrip") (param $src i32) (result i32) + (local $dst i32) + (if (i32.ne (local.get $src) (i32.const 16)) + (then (unreachable))) + + (if (i32.ne (i32.load offset=0 (local.get $src)) (i32.const 1)) (then (unreachable))) + (if (i32.ne (i32.load offset=4 (local.get $src)) (i32.const 2)) (then (unreachable))) + (if (i32.ne (i32.load offset=8 (local.get $src)) (i32.const 3)) (then (unreachable))) + (if (i32.ne (i32.load offset=12 (local.get $src)) (i32.const 4)) (then (unreachable))) + (if (i32.ne (i32.load offset=16 (local.get $src)) (i32.const 5)) (then (unreachable))) + (if (i32.ne (i32.load offset=20 (local.get $src)) (i32.const 6)) (then (unreachable))) + (if (i32.ne (i32.load offset=24 (local.get $src)) (i32.const 7)) (then (unreachable))) + (if (i32.ne (i32.load offset=28 (local.get $src)) (i32.const 8)) (then (unreachable))) + (if (i32.ne (i32.load offset=32 (local.get $src)) (i32.const 9)) (then (unreachable))) + (if (i32.ne (i32.load offset=36 (local.get $src)) (i32.const 10)) (then (unreachable))) + (if (i32.ne (i32.load offset=40 (local.get $src)) (i32.const 11)) (then (unreachable))) + (if (i32.ne (i32.load offset=44 (local.get $src)) (i32.const 12)) (then (unreachable))) + (if (i32.ne (i32.load offset=48 (local.get $src)) (i32.const 13)) (then (unreachable))) + (if (i32.ne (i32.load offset=52 (local.get $src)) (i32.const 14)) (then (unreachable))) + (if (i32.ne (i32.load offset=56 (local.get $src)) (i32.const 15)) (then (unreachable))) + (if (i32.ne (i32.load offset=60 (local.get $src)) (i32.const 16)) (then (unreachable))) + (if (i32.ne (i32.load offset=64 (local.get $src)) (i32.const 17)) (then (unreachable))) + (if (i32.ne (i32.load offset=68 (local.get $src)) (i32.const 18)) (then (unreachable))) + (if (i32.ne (i32.load offset=72 (local.get $src)) (i32.const 19)) (then (unreachable))) + (if (i32.ne (i32.load offset=76 (local.get $src)) (i32.const 20)) (then (unreachable))) + + (local.set $dst (i32.const 500)) + + (i32.store offset=0 (local.get $dst) (i32.const 21)) + (i32.store offset=4 (local.get $dst) (i32.const 22)) + (i32.store offset=8 (local.get $dst) (i32.const 23)) + (i32.store offset=12 (local.get $dst) (i32.const 24)) + (i32.store offset=16 (local.get $dst) (i32.const 25)) + (i32.store offset=20 (local.get $dst) (i32.const 26)) + (i32.store offset=24 (local.get $dst) (i32.const 27)) + (i32.store offset=28 (local.get $dst) (i32.const 28)) + (i32.store offset=32 (local.get $dst) (i32.const 29)) + (i32.store offset=36 (local.get $dst) (i32.const 30)) + + local.get $dst + ) + + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + i32.const 16) + ) + (core instance $m (instantiate $m)) + + (func (export "roundtrip") (type $roundtrip) + (canon lift (core func $m "roundtrip") (memory $m "memory") + (realloc (func $m "realloc"))) + ) + ) + (instance $a (instantiate $a)) + + (component $c + (type $roundtrip (func + ;; 20 u32 params + (param "a1" u32) (param "a2" u32) (param "a3" u32) (param "a4" u32) (param "a5" u32) + (param "a6" u32) (param "a7" u32) (param "a8" u32) (param "a9" u32) (param "a10" u32) + (param "a11" u32) (param "a12" u32) (param "a13" u32) (param "a14" u32) (param "a15" u32) + (param "a16" u32) (param "a17" u32) (param "a18" u32) (param "a19" u32) (param "a20" u32) + + ;; 10 u32 results + (result (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) + )) + + (import "a" (instance $a + (export "roundtrip" (func (type $roundtrip))) + )) + + (core module $libc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) + ) + (core instance $libc (instantiate $libc)) + (core func $roundtrip + (canon lower (func $a "roundtrip") + (memory $libc "memory") + (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary + ) + ) + + (core module $m2 + (import "libc" "memory" (memory 1)) + (import "" "roundtrip" (func $roundtrip (param i32 i32))) + + (func $start + (local $addr i32) + (local $retaddr i32) + + (local.set $addr (i32.const 100)) + (call $store_many (i32.const 20) (local.get $addr)) + + (local.set $retaddr (i32.const 200)) + (call $roundtrip (local.get $addr) (local.get $retaddr)) + + (if (i32.ne (i32.load offset=0 (local.get $retaddr)) (i32.const 21)) (then (unreachable))) + (if (i32.ne (i32.load offset=4 (local.get $retaddr)) (i32.const 22)) (then (unreachable))) + (if (i32.ne (i32.load offset=8 (local.get $retaddr)) (i32.const 23)) (then (unreachable))) + (if (i32.ne (i32.load offset=12 (local.get $retaddr)) (i32.const 24)) (then (unreachable))) + (if (i32.ne (i32.load offset=16 (local.get $retaddr)) (i32.const 25)) (then (unreachable))) + (if (i32.ne (i32.load offset=20 (local.get $retaddr)) (i32.const 26)) (then (unreachable))) + (if (i32.ne (i32.load offset=24 (local.get $retaddr)) (i32.const 27)) (then (unreachable))) + (if (i32.ne (i32.load offset=28 (local.get $retaddr)) (i32.const 28)) (then (unreachable))) + (if (i32.ne (i32.load offset=32 (local.get $retaddr)) (i32.const 29)) (then (unreachable))) + (if (i32.ne (i32.load offset=36 (local.get $retaddr)) (i32.const 30)) (then (unreachable))) + ) + + (func $store_many (param $amt i32) (param $addr i32) + (local $c i32) + (loop $loop + (local.set $c (i32.add (local.get $c) (i32.const 1))) + (i32.store (local.get $addr) (local.get $c)) + (local.set $addr (i32.add (local.get $addr) (i32.const 4))) + + (if (i32.ne (local.get $amt) (local.get $c)) (then (br $loop))) + ) + ) + (start $start) + ) + (core instance $m2 (instantiate $m2 + (with "libc" (instance $libc)) + (with "" (instance (export "roundtrip" (func $roundtrip)))) + )) + ) + + (instance $c (instantiate $c (with "a" (instance $a)))) +) + +;; this will require multiple adapter modules to get generated +(component + (component $c0 + (core module $root (func (export "") (result i32) + i32.const 0 + )) + (core instance $root (instantiate $root)) + (func (export "thunk") (result u32) (canon lift (core func $root ""))) + ) + (instance $c0 (instantiate $c0)) + + (component $c + (import "thunk" (instance $thunk + (export "thunk" (func (result u32))) + )) + (core func $import (canon lower (func $thunk "thunk"))) + (core module $reexport + (import "" "" (func $thunk (result i32))) + (func (export "thunk") (result i32) + call $thunk + i32.const 1 + i32.add) + ) + (core instance $reexport (instantiate $reexport + (with "" (instance + (export "" (func $import)) + )) + )) + (func $export (export "thunk") (result u32) + (canon lift (core func $reexport "thunk")) + ) + ) + + (instance $c1 (instantiate $c (with "thunk" (instance $c0)))) + (instance $c2 (instantiate $c (with "thunk" (instance $c1)))) + (instance $c3 (instantiate $c (with "thunk" (instance $c2)))) + (instance $c4 (instantiate $c (with "thunk" (instance $c3)))) + (instance $c5 (instantiate $c (with "thunk" (instance $c4)))) + (instance $c6 (instantiate $c (with "thunk" (instance $c5)))) + + (component $verify + (import "thunk" (instance $thunk + (export "thunk" (func (result u32))) + )) + (core func $thunk (canon lower (func $thunk "thunk"))) + (core module $verify + (import "" "" (func $thunk (result i32))) + + (func $start + call $thunk + i32.const 6 + i32.ne + if unreachable end + ) + (start $start) + ) + (core instance (instantiate $verify + (with "" (instance + (export "" (func $thunk)) + )) + )) + ) + (instance (instantiate $verify (with "thunk" (instance $c6)))) +) + +;; Fancy case of an adapter using an adapter. Note that this is silly and +;; doesn't actually make any sense at runtime, we just shouldn't panic on a +;; valid component. +(component + (type $tuple20 (tuple + u32 u32 u32 u32 u32 + u32 u32 u32 u32 u32 + u32 u32 u32 u32 u32 + u32 u32 u32 u32 u32)) + + (component $realloc + (core module $realloc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable) + ) + (core instance $realloc (instantiate $realloc)) + (func $realloc (param "a" (tuple u32 u32 u32 u32)) (result u32) + (canon lift (core func $realloc "realloc")) + ) + (export "realloc" (func $realloc)) + ) + (instance $realloc (instantiate $realloc)) + (core func $realloc (canon lower (func $realloc "realloc"))) + + (core module $m + (memory (export "memory") 1) + (func (export "foo") (param i32)) + ) + (core instance $m (instantiate $m)) + (func $foo (param "a" $tuple20) + (canon lift + (core func $m "foo") + (memory $m "memory") + (realloc (func $realloc)) + ) + ) + + (component $c + (import "foo" (func $foo (param "a" $tuple20))) + + (core module $libc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable) + ) + (core instance $libc (instantiate $libc)) + (core func $foo + (canon lower (func $foo) + (memory $libc "memory") + (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary + ) + ) + (core module $something + (import "" "foo" (func (param i32))) + ) + (core instance (instantiate $something + (with "" (instance + (export "foo" (func $foo)) + )) + )) + ) + (instance (instantiate $c + (with "foo" (func $foo)) + )) +) + +;; Don't panic or otherwise create extraneous adapter modules when the same +;; adapter is used twice for a module's argument. +(component + (core module $m + (func (export "foo") (param)) + ) + (core instance $m (instantiate $m)) + (func $foo (canon lift (core func $m "foo"))) + + (component $c + (import "foo" (func $foo)) + (core func $foo (canon lower (func $foo))) + + (core module $something + (import "" "a" (func)) + (import "" "b" (func)) + ) + (core instance (instantiate $something + (with "" (instance + (export "a" (func $foo)) + (export "b" (func $foo)) + )) + )) + ) + (instance (instantiate $c (with "foo" (func $foo)))) +) + +;; post-return should get invoked by the generated adapter, if specified +(component + (component $a + (core module $m + (global $post_called (mut i32) (i32.const 0)) + (func (export "foo") + ;; assert `foo-post` not called yet + global.get $post_called + i32.const 1 + i32.eq + if unreachable end + ) + (func (export "foo-post") + ;; assert `foo-post` not called before + global.get $post_called + i32.const 1 + i32.eq + if unreachable end + ;; ... then flag as called + i32.const 1 + global.set $post_called + ) + (func (export "assert-post") + global.get $post_called + i32.const 1 + i32.ne + if unreachable end + ) + ) + (core instance $m (instantiate $m)) + (func (export "foo") (canon lift (core func $m "foo") (post-return (func $m "foo-post")))) + (func (export "assert-post") (canon lift (core func $m "assert-post"))) + ) + (instance $a (instantiate $a)) + + (component $c + (import "a" (instance $a + (export "foo" (func)) + (export "assert-post" (func)) + )) + (core func $foo (canon lower (func $a "foo"))) + (core func $assert_post (canon lower (func $a "assert-post"))) + + (core module $something + (import "" "foo" (func $foo)) + (import "" "assert-post" (func $assert_post)) + + (func $start + call $foo + call $assert_post + ) + (start $start) + ) + (core instance (instantiate $something + (with "" (instance + (export "foo" (func $foo)) + (export "assert-post" (func $assert_post)) + )) + )) + ) + (instance (instantiate $c (with "a" (instance $a)))) +) + +;; post-return passes the results +(component + (component $a + (core module $m + (func (export "foo") (result i32) i32.const 100) + (func (export "foo-post") (param i32) + (if (i32.ne (local.get 0) (i32.const 100)) (then (unreachable)))) + ) + (core instance $m (instantiate $m)) + (func (export "foo") (result u32) + (canon lift (core func $m "foo") (post-return (func $m "foo-post")))) + ) + (instance $a (instantiate $a)) + + (component $c + (import "a" (instance $a + (export "foo" (func (result u32))) + )) + (core func $foo (canon lower (func $a "foo"))) + + (core module $something + (import "" "foo" (func $foo (result i32))) + (func $start + (if (i32.ne (call $foo) (i32.const 100)) (then (unreachable)))) + (start $start) + ) + (core instance (instantiate $something + (with "" (instance + (export "foo" (func $foo)) + )) + )) + ) + (instance (instantiate $c (with "a" (instance $a)))) +) + +;; callee retptr misaligned +(assert_trap + (component + (component $c1 + (core module $m + (memory (export "memory") 1) + (func (export "r") (result i32) i32.const 1) + ) + (core instance $m (instantiate $m)) + (func (export "r") (result (tuple u32 u32)) + (canon lift (core func $m "r") (memory $m "memory")) + ) + ) + (component $c2 + (import "r" (func $r (result (tuple u32 u32)))) + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func $r (canon lower (func $r) (memory $libc "memory"))) + + (core module $m + (import "" "r" (func $r (param i32))) + (func $start + i32.const 4 + call $r + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) + ) + "unaligned pointer") + +;; caller retptr misaligned +(assert_trap + (component + (component $c1 + (core module $m + (memory (export "memory") 1) + (func (export "r") (result i32) i32.const 0) + ) + (core instance $m (instantiate $m)) + (func (export "r") (result (tuple u32 u32)) + (canon lift (core func $m "r") (memory $m "memory")) + ) + ) + (component $c2 + (import "r" (func $r (result (tuple u32 u32)))) + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func $r (canon lower (func $r) (memory $libc "memory"))) + + (core module $m + (import "" "r" (func $r (param i32))) + (func $start + i32.const 1 + call $r + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) + ) + "unaligned pointer") + +;; callee argptr misaligned +(assert_trap + (component + (type $big (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) + + (component $c1 + (core module $m + (memory (export "memory") 1) + (func (export "r") (param i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + i32.const 1) + ) + (core instance $m (instantiate $m)) + (func (export "r") (param "a" $big) + (canon lift (core func $m "r") (memory $m "memory") (realloc (func $m "realloc"))) + ) + ) + (component $c2 + (import "r" (func $r (param "a" $big))) + (core module $libc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) + ) + (core instance $libc (instantiate $libc)) + (core func $r + (canon lower (func $r) + (memory $libc "memory") + (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary + ) + ) + + (core module $m + (import "" "r" (func $r (param i32))) + (func $start + i32.const 4 + call $r + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) + ) + "unaligned pointer") + +;; caller argptr misaligned +(assert_trap + (component + (type $big (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) + + (component $c1 + (core module $m + (memory (export "memory") 1) + (func (export "r") (param i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + i32.const 4) + ) + (core instance $m (instantiate $m)) + (func (export "r") (param "a" $big) + (canon lift (core func $m "r") (memory $m "memory") (realloc (func $m "realloc"))) + ) + ) + (component $c2 + (import "r" (func $r (param "a" $big))) + (core module $libc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) + ) + (core instance $libc (instantiate $libc)) + (core func $r + (canon lower (func $r) + (memory $libc "memory") + (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary + ) + ) + + + (core module $m + (import "" "r" (func $r (param i32))) + (func $start + i32.const 1 + call $r + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) + ) + "unaligned pointer") + +;; simple variant translation +(component + (component $c1 + (type $a' (variant (case "x"))) + (export $a "a" (type $a')) + (type $b' (variant (case "y"))) + (export $b "b" (type $b')) + + (core module $m + (func (export "r") (param i32) (result i32) + (if (i32.ne (local.get 0) (i32.const 0)) (then (unreachable))) + i32.const 0 + ) + ) + (core instance $m (instantiate $m)) + (func (export "r") (param "a" $a) (result $b) (canon lift (core func $m "r"))) + ) + (component $c2 + (type $a' (variant (case "x"))) + (import "a" (type $a (eq $a'))) + (type $b' (variant (case "y"))) + (import "b" (type $b (eq $b'))) + + (import "r" (func $r (param "a" $a) (result $b))) + (core func $r (canon lower (func $r))) + + (core module $m + (import "" "r" (func $r (param i32) (result i32))) + (func $start + i32.const 0 + call $r + i32.const 0 + i32.ne + if unreachable end + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 + (with "a" (type $c1 "a")) + (with "b" (type $c1 "b")) + (with "r" (func $c1 "r")) + )) +) + +;; invalid variant discriminant in a parameter +(assert_trap + (component + (component $c1 + (type $a' (variant (case "x"))) + (export $a "a" (type $a')) + (core module $m + (func (export "r") (param i32)) + ) + (core instance $m (instantiate $m)) + (func (export "r") (param "a" $a) (canon lift (core func $m "r"))) + ) + (component $c2 + (type $a' (variant (case "x"))) + (import "a" (type $a (eq $a'))) + (import "r" (func $r (param "a" $a))) + (core func $r (canon lower (func $r))) + + (core module $m + (import "" "r" (func $r (param i32))) + (func $start + i32.const 1 + call $r + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 + (with "a" (type $c1 "a")) + (with "r" (func $c1 "r")) + )) + ) + "invalid variant discriminant") + +;; invalid variant discriminant in a result +(assert_trap + (component + (component $c1 + (type $a' (variant (case "x"))) + (export $a "a" (type $a')) + (core module $m + (func (export "r") (result i32) i32.const 1) + ) + (core instance $m (instantiate $m)) + (func (export "r") (result $a) (canon lift (core func $m "r"))) + ) + (component $c2 + (type $a' (variant (case "x"))) + (import "a" (type $a (eq $a'))) + (import "r" (func $r (result $a))) + (core func $r (canon lower (func $r))) + + (core module $m + (import "" "r" (func $r (result i32))) + (func $start call $r drop) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 + (with "a" (type $c1 "a")) + (with "r" (func $c1 "r")) + )) + ) + "invalid variant discriminant") + + +;; extra bits are chopped off +(component + (component $c1 + (core module $m + (func (export "u") (param i32) + (if (i32.ne (local.get 0) (i32.const 0)) (then (unreachable))) + ) + (func (export "s") (param i32) + (if (i32.ne (local.get 0) (i32.const -1)) (then (unreachable))) + ) + ) + (core instance $m (instantiate $m)) + (func (export "u8") (param "a" u8) (canon lift (core func $m "u"))) + (func (export "u16") (param "a" u16) (canon lift (core func $m "u"))) + (func (export "s8") (param "a" s8) (canon lift (core func $m "s"))) + (func (export "s16") (param "a" s16) (canon lift (core func $m "s"))) + ) + (component $c2 + (import "a" (instance $i + (export "u8" (func (param "a" u8))) + (export "s8" (func (param "a" s8))) + (export "u16" (func (param "a" u16))) + (export "s16" (func (param "a" s16))) + )) + + (core func $u8 (canon lower (func $i "u8"))) + (core func $s8 (canon lower (func $i "s8"))) + (core func $u16 (canon lower (func $i "u16"))) + (core func $s16 (canon lower (func $i "s16"))) + + (core module $m + (import "" "u8" (func $u8 (param i32))) + (import "" "s8" (func $s8 (param i32))) + (import "" "u16" (func $u16 (param i32))) + (import "" "s16" (func $s16 (param i32))) + + (func $start + (call $u8 (i32.const 0)) + (call $u8 (i32.const 0xff00)) + (call $s8 (i32.const -1)) + (call $s8 (i32.const 0xff)) + (call $s8 (i32.const 0xffff)) + + (call $u16 (i32.const 0)) + (call $u16 (i32.const 0xff0000)) + (call $s16 (i32.const -1)) + (call $s16 (i32.const 0xffff)) + (call $s16 (i32.const 0xffffff)) + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "u8" (func $u8)) + (export "s8" (func $s8)) + (export "u16" (func $u16)) + (export "s16" (func $s16)) + )) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) +) + +;; translation of locals between different types +(component + (component $c1 + (type $a' (variant (case "a" u8) (case "b" float32))) + (type $b' (variant (case "a" u16) (case "b" s64))) + (type $c' (variant (case "a" u64) (case "b" float64))) + (type $d' (variant (case "a" float32) (case "b" float64))) + (type $e' (variant (case "a" float32) (case "b" s64))) + (export $a "t-a" (type $a')) + (export $b "t-b" (type $b')) + (export $c "t-c" (type $c')) + (export $d "t-d" (type $d')) + (export $e "t-e" (type $e')) + + (type $func_a (func (param "x" bool) (param "a" $a))) + (type $func_b (func (param "x" bool) (param "b" $b))) + (type $func_c (func (param "x" bool) (param "c" $c))) + (type $func_d (func (param "x" bool) (param "d" $d))) + (type $func_e (func (param "x" bool) (param "e" $d))) + + (core module $m + (func (export "a") (param i32 i32 i32) + (i32.eqz (local.get 0)) + if + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (i32.ne (local.get 2) (i32.const 2)) (then (unreachable))) + else + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (f32.ne (f32.reinterpret_i32 (local.get 2)) (f32.const 3)) (then (unreachable))) + end + ) + (func (export "b") (param i32 i32 i64) + (i32.eqz (local.get 0)) + if + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (i64.ne (local.get 2) (i64.const 4)) (then (unreachable))) + else + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (i64.ne (local.get 2) (i64.const 5)) (then (unreachable))) + end + ) + (func (export "c") (param i32 i32 i64) + (i32.eqz (local.get 0)) + if + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (i64.ne (local.get 2) (i64.const 6)) (then (unreachable))) + else + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (f64.ne (f64.reinterpret_i64 (local.get 2)) (f64.const 7)) (then (unreachable))) + end + ) + (func (export "d") (param i32 i32 i64) + (i32.eqz (local.get 0)) + if + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (f32.ne (f32.reinterpret_i32 (i32.wrap_i64 (local.get 2))) (f32.const 8)) (then (unreachable))) + else + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (f64.ne (f64.reinterpret_i64 (local.get 2)) (f64.const 9)) (then (unreachable))) + end + ) + (func (export "e") (param i32 i32 i64) + (i32.eqz (local.get 0)) + if + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (f32.ne (f32.reinterpret_i32 (i32.wrap_i64 (local.get 2))) (f32.const 10)) (then (unreachable))) + else + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (i64.ne (local.get 2) (i64.const 11)) (then (unreachable))) + end + ) + ) + (core instance $m (instantiate $m)) + (func (export "a") (type $func_a) (canon lift (core func $m "a"))) + (func (export "b") (type $func_b) (canon lift (core func $m "b"))) + (func (export "c") (type $func_c) (canon lift (core func $m "c"))) + (func (export "d") (type $func_d) (canon lift (core func $m "d"))) + (func (export "e") (type $func_e) (canon lift (core func $m "e"))) + ) + (component $c2 + (import "a" (instance $i + (type $a' (variant (case "a" u8) (case "b" float32))) + (type $b' (variant (case "a" u16) (case "b" s64))) + (type $c' (variant (case "a" u64) (case "b" float64))) + (type $d' (variant (case "a" float32) (case "b" float64))) + (type $e' (variant (case "a" float32) (case "b" s64))) + (export "t-a" (type $a (eq $a'))) + (export "t-b" (type $b (eq $b'))) + (export "t-c" (type $c (eq $c'))) + (export "t-d" (type $d (eq $d'))) + (export "t-e" (type $e (eq $e'))) + (type $func_a (func (param "x" bool) (param "a" $a))) + (type $func_b (func (param "x" bool) (param "b" $b))) + (type $func_c (func (param "x" bool) (param "c" $c))) + (type $func_d (func (param "x" bool) (param "d" $d))) + (type $func_e (func (param "x" bool) (param "e" $d))) + + (export "a" (func (type $func_a))) + (export "b" (func (type $func_b))) + (export "c" (func (type $func_c))) + (export "d" (func (type $func_d))) + (export "e" (func (type $func_e))) + )) + + (core func $a (canon lower (func $i "a"))) + (core func $b (canon lower (func $i "b"))) + (core func $c (canon lower (func $i "c"))) + (core func $d (canon lower (func $i "d"))) + (core func $e (canon lower (func $i "e"))) + + (core module $m + (import "" "a" (func $a (param i32 i32 i32))) + (import "" "b" (func $b (param i32 i32 i64))) + (import "" "c" (func $c (param i32 i32 i64))) + (import "" "d" (func $d (param i32 i32 i64))) + (import "" "e" (func $e (param i32 i32 i64))) + + (func $start + ;; upper bits should get masked + (call $a (i32.const 0) (i32.const 0) (i32.const 0xff_02)) + (call $a (i32.const 1) (i32.const 1) (i32.reinterpret_f32 (f32.const 3))) + + ;; upper bits should get masked + (call $b (i32.const 0) (i32.const 0) (i64.const 0xff_00_04)) + (call $b (i32.const 1) (i32.const 1) (i64.const 5)) + + (call $c (i32.const 0) (i32.const 0) (i64.const 6)) + (call $c (i32.const 1) (i32.const 1) (i64.reinterpret_f64 (f64.const 7))) + + (call $d (i32.const 0) (i32.const 0) (i64.extend_i32_u (i32.reinterpret_f32 (f32.const 8)))) + (call $d (i32.const 1) (i32.const 1) (i64.reinterpret_f64 (f64.const 9))) + + (call $e (i32.const 0) (i32.const 0) (i64.extend_i32_u (i32.reinterpret_f32 (f32.const 10)))) + (call $e (i32.const 1) (i32.const 1) (i64.const 11)) + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "a" (func $a)) + (export "b" (func $b)) + (export "c" (func $c)) + (export "d" (func $d)) + (export "e" (func $e)) + )) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) +) + +;; different size variants +(component + (component $c1 + (type $a' (variant + (case "a") + (case "b" float32) + (case "c" (tuple float32 u32)) + (case "d" (tuple float32 u64 u8)) + )) + (export $a "t-a" (type $a')) + + (core module $m + (func (export "a") (param i32 i32 f32 i64 i32) + (if (i32.eq (local.get 0) (i32.const 0)) + (then (block + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (f32.ne (local.get 2) (f32.const 0)) (then (unreachable))) + (if (i64.ne (local.get 3) (i64.const 0)) (then (unreachable))) + (if (i32.ne (local.get 4) (i32.const 0)) (then (unreachable))) + )) + ) + (if (i32.eq (local.get 0) (i32.const 1)) + (then (block + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (f32.ne (local.get 2) (f32.const 1)) (then (unreachable))) + (if (i64.ne (local.get 3) (i64.const 0)) (then (unreachable))) + (if (i32.ne (local.get 4) (i32.const 0)) (then (unreachable))) + )) + ) + (if (i32.eq (local.get 0) (i32.const 2)) + (then (block + (if (i32.ne (local.get 1) (i32.const 2)) (then (unreachable))) + (if (f32.ne (local.get 2) (f32.const 2)) (then (unreachable))) + (if (i64.ne (local.get 3) (i64.const 2)) (then (unreachable))) + (if (i32.ne (local.get 4) (i32.const 0)) (then (unreachable))) + )) + ) + (if (i32.eq (local.get 0) (i32.const 3)) + (then (block + (if (i32.ne (local.get 1) (i32.const 3)) (then (unreachable))) + (if (f32.ne (local.get 2) (f32.const 3)) (then (unreachable))) + (if (i64.ne (local.get 3) (i64.const 3)) (then (unreachable))) + (if (i32.ne (local.get 4) (i32.const 3)) (then (unreachable))) + )) + ) + (if (i32.gt_u (local.get 0) (i32.const 3)) + (then (unreachable))) + ) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "x" u8) (param "a" $a) (canon lift (core func $m "a"))) + ) + (component $c2 + (import "a" (instance $i + (type $a' (variant + (case "a") + (case "b" float32) + (case "c" (tuple float32 u32)) + (case "d" (tuple float32 u64 u8)) + )) + (export "t-a" (type $a (eq $a'))) + (export "a" (func (param "x" u8) (param "a" $a))) + )) + + (core func $a (canon lower (func $i "a"))) + + (core module $m + (import "" "a" (func $a (param i32 i32 f32 i64 i32))) + + (func $start + ;; variant a + (call $a + (i32.const 0) + (i32.const 0) + (f32.const 0) + (i64.const 0) + (i32.const 0)) + ;; variant b + (call $a + (i32.const 1) + (i32.const 1) + (f32.const 1) + (i64.const 0) + (i32.const 0)) + ;; variant c + (call $a + (i32.const 2) + (i32.const 2) + (f32.const 2) + (i64.const 2) + (i32.const 0)) + ;; variant d + (call $a + (i32.const 3) + (i32.const 3) + (f32.const 3) + (i64.const 3) + (i32.const 3)) + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "a" (func $a)) + )) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) +) + +;; roundtrip some valid chars +(component + (component $c1 + (core module $m + (func (export "a") (param i32) (result i32) local.get 0) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" char) (result char) (canon lift (core func $m "a"))) + ) + (component $c2 + (import "a" (instance $i + (export "a" (func (param "a" char) (result char))) + )) + + (core func $a (canon lower (func $i "a"))) + + (core module $m + (import "" "a" (func $a (param i32) (result i32))) + + (func $start + (call $roundtrip (i32.const 0)) + (call $roundtrip (i32.const 0xab)) + (call $roundtrip (i32.const 0xd7ff)) + (call $roundtrip (i32.const 0xe000)) + (call $roundtrip (i32.const 0x10ffff)) + ) + (func $roundtrip (export "roundtrip") (param i32) + local.get 0 + call $a + local.get 0 + i32.ne + if unreachable end + ) + (start $start) + ) + (core instance $m (instantiate $m + (with "" (instance + (export "a" (func $a)) + )) + )) + + (func (export "roundtrip") (param "a" char) (canon lift (core func $m "roundtrip"))) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) + + (export "roundtrip" (func $c2 "roundtrip")) +) + +(assert_return (invoke "roundtrip" (char.const "x"))) +(assert_return (invoke "roundtrip" (char.const "⛳"))) +(assert_return (invoke "roundtrip" (char.const "🍰"))) + +;; invalid chars +(assert_trap + (component + (component $c1 + (core module $m (func (export "a") (param i32))) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" char) (canon lift (core func $m "a"))) + ) + (component $c2 + (import "a" (instance $i (export "a" (func (param "a" char))))) + (core func $a (canon lower (func $i "a"))) + (core module $m + (import "" "a" (func $a (param i32))) + (func $start (call $a (i32.const 0xd800))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "a" (func $a)))))) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) + ) + "invalid `char` bit pattern") +(assert_trap + (component + (component $c1 + (core module $m (func (export "a") (param i32))) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" char) (canon lift (core func $m "a"))) + ) + (component $c2 + (import "a" (instance $i (export "a" (func (param "a" char))))) + (core func $a (canon lower (func $i "a"))) + (core module $m + (import "" "a" (func $a (param i32))) + (func $start (call $a (i32.const 0xdfff))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "a" (func $a)))))) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) + ) + "invalid `char` bit pattern") +(assert_trap + (component + (component $c1 + (core module $m (func (export "a") (param i32))) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" char) (canon lift (core func $m "a"))) + ) + (component $c2 + (import "a" (instance $i (export "a" (func (param "a" char))))) + (core func $a (canon lower (func $i "a"))) + (core module $m + (import "" "a" (func $a (param i32))) + (func $start (call $a (i32.const 0x110000))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "a" (func $a)))))) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) + ) + "invalid `char` bit pattern") + +;; test that flags get their upper bits all masked off +(component + (type $f1' (flags "f1")) + (type $f8' (flags "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8")) + (type $f9' (flags "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" "f9")) + (type $f16' (flags + "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" + "g1" "g2" "g3" "g4" "g5" "g6" "g7" "g8" + )) + (type $f17' (flags + "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" + "g1" "g2" "g3" "g4" "g5" "g6" "g7" "g8" + "g9" + )) + (type $f32' (flags + "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" + "g1" "g2" "g3" "g4" "g5" "g6" "g7" "g8" + "h1" "h2" "h3" "h4" "h5" "h6" "h7" "h8" + "i1" "i2" "i3" "i4" "i5" "i6" "i7" "i8" + )) + + (component $c1 + (export $f1 "t-f1" (type $f1')) + (export $f8 "t-f8" (type $f8')) + (export $f9 "t-f9" (type $f9')) + (export $f16 "t-f16" (type $f16')) + (export $f17 "t-f17" (type $f17')) + (export $f32 "t-f32" (type $f32')) + (core module $m + (func (export "f1") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x1)) (then (unreachable))) + ) + (func (export "f8") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x11)) (then (unreachable))) + ) + (func (export "f9") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x111)) (then (unreachable))) + ) + (func (export "f16") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x1111)) (then (unreachable))) + ) + (func (export "f17") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x11111)) (then (unreachable))) + ) + (func (export "f32") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x11111111)) (then (unreachable))) + ) + ) + (core instance $m (instantiate $m)) + (func (export "f1") (param "a" $f1) (canon lift (core func $m "f1"))) + (func (export "f8") (param "a" $f8) (canon lift (core func $m "f8"))) + (func (export "f9") (param "a" $f9) (canon lift (core func $m "f9"))) + (func (export "f16") (param "a" $f16) (canon lift (core func $m "f16"))) + (func (export "f17") (param "a" $f17) (canon lift (core func $m "f17"))) + (func (export "f32") (param "a" $f32) (canon lift (core func $m "f32"))) + ) + (instance $c1 (instantiate $c1)) + + (component $c2 + (import "a" (instance $i + (export "t-f1" (type $f1 (eq $f1'))) + (export "t-f8" (type $f8 (eq $f8'))) + (export "t-f9" (type $f9 (eq $f9'))) + (export "t-f16" (type $f16 (eq $f16'))) + (export "t-f17" (type $f17 (eq $f17'))) + (export "t-f32" (type $f32 (eq $f32'))) + (export "f1" (func (param "a" $f1))) + (export "f8" (func (param "a" $f8))) + (export "f9" (func (param "a" $f9))) + (export "f16" (func (param "a" $f16))) + (export "f17" (func (param "a" $f17))) + (export "f32" (func (param "a" $f32))) + )) + (core func $f1 (canon lower (func $i "f1"))) + (core func $f8 (canon lower (func $i "f8"))) + (core func $f9 (canon lower (func $i "f9"))) + (core func $f16 (canon lower (func $i "f16"))) + (core func $f17 (canon lower (func $i "f17"))) + (core func $f32 (canon lower (func $i "f32"))) + + (core module $m + (import "" "f1" (func $f1 (param i32))) + (import "" "f8" (func $f8 (param i32))) + (import "" "f9" (func $f9 (param i32))) + (import "" "f16" (func $f16 (param i32))) + (import "" "f17" (func $f17 (param i32))) + (import "" "f32" (func $f32 (param i32))) + + (func $start + (call $f1 (i32.const 0xffffff01)) + (call $f8 (i32.const 0xffffff11)) + (call $f9 (i32.const 0xffffff11)) + (call $f16 (i32.const 0xffff1111)) + (call $f17 (i32.const 0xffff1111)) + (call $f32 (i32.const 0x11111111)) + ) + + (start $start) + ) + (core instance $m (instantiate $m + (with "" (instance + (export "f1" (func $f1)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f16" (func $f16)) + (export "f17" (func $f17)) + (export "f32" (func $f32)) + )) + )) + ) + (instance (instantiate $c2 (with "a" (instance $c1)))) +) + +;; Adapters are used slightly out-of-order here to stress the internals of +;; dependencies between adapters. +(component + (core module $m + (func (export "execute")) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) + (memory (export "memory") 1) + ) + + (component $root + (core instance $m (instantiate $m)) + (func (export "execute") + (canon lift (core func $m "execute")) + ) + ) + (component $c + (import "backend" (instance $i + (export "execute" (func)) + )) + (core module $shim2 (import "" "0" (func))) + (core instance $m (instantiate $m)) + + ;; This adapter, when fused with itself on the second instantiation of this + ;; component, will depended on the prior instance `$m` so it which means + ;; that the adapter module containing this must be placed in the right + ;; location. + (core func $execute + (canon lower (func $i "execute") (memory $m "memory") (realloc (func $m "realloc"))) + ) + (core instance (instantiate $shim2 + (with "" (instance + (export "0" (func $execute)) + )) + )) + (func (export "execute") (canon lift (core func $m "execute"))) + ) + (instance $root (instantiate $root)) + (instance $c1 (instantiate $c (with "backend" (instance $root)))) + (instance $c2 (instantiate $c (with "backend" (instance $c1)))) +) diff --git a/parser/src/test/resources/spec-tests/wasmtime/import.wast b/parser/src/test/resources/spec-tests/wasmtime/import.wast new file mode 100644 index 0000000..20688ef --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasmtime/import.wast @@ -0,0 +1,20 @@ +(assert_invalid + (component + (import "host-return-two" (func $f (result u32))) + (export "x" (func $f))) + "component export `x` is a reexport of an imported function which is not implemented") + +(assert_unlinkable + (component + (import "host-return-two" (instance)) + ) + "expected instance found func") + +;; empty instances don't need to be supplied by the host, even recursively +;; empty instances. +(component + (import "not-provided-by-the-host" (instance)) + (import "not-provided-by-the-host2" (instance + (export "x" (instance)) + )) +) diff --git a/parser/src/test/resources/spec-tests/wasmtime/instance.wast b/parser/src/test/resources/spec-tests/wasmtime/instance.wast new file mode 100644 index 0000000..4216cdc --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasmtime/instance.wast @@ -0,0 +1,327 @@ +(component + (core module $m) + (core instance (instantiate $m)) +) + +(component + (core module $m + (func (export "")) + ) + (core instance $i (instantiate $m)) + + (core module $m2 + (func (import "" "")) + ) + (core instance (instantiate $m2 (with "" (instance $i)))) +) + +(component + (core module $m + (func (export "a")) + ) + (core instance $i (instantiate $m)) + + (core module $m2 + (func (import "" "b")) + ) + (core instance (instantiate $m2 + (with "" (instance (export "b" (func $i "a")))) + )) +) + +;; all kinds of imports for core wasm modules, and register a start function on +;; one module to ensure that everything is correct +(component + (core module $m + (func (export "a")) + (table (export "b") 1 funcref) + (memory (export "c") 1) + (global (export "d") i32 i32.const 1) + ) + (core instance $i (instantiate $m)) + + (core module $m2 + (import "" "a" (func $f)) + (import "" "b" (table 1 funcref)) + (import "" "c" (memory 1)) + (import "" "d" (global $g i32)) + + (func $start + global.get $g + i32.const 1 + i32.ne + if + unreachable + end + + call $f + ) + + (start $start) + + (data (i32.const 0) "hello") + (elem (i32.const 0) $start) + ) + (core instance (instantiate $m2 + (with "" (instance $i)) + )) +) + +;; Test to see if a component with a type export can be instantiated. +(component + (type string) + (export "a" (type 0)) +) + +;; double-check the start function runs by ensuring that a trap shows up and it +;; sees the wrong value for the global import +(assert_trap + (component + (core module $m + (global (export "g") i32 i32.const 1) + ) + (core instance $i (instantiate $m)) + + (core module $m2 + (import "" "g" (global $g i32)) + + (func $start + global.get $g + i32.const 0 + i32.ne + if + unreachable + end + ) + + (start $start) + ) + (core instance (instantiate $m2 (with "" (instance $i)))) + ) + "unreachable") + +;; shuffle around imports to get to what the target core wasm module needs +(component + (core module $m + (func (export "1")) + (table (export "2") 1 funcref) + (memory (export "3") 1) + (global (export "4") i32 i32.const 1) + ) + (core instance $i (instantiate $m)) + + (core module $m2 + (import "" "a" (func $f)) + (import "" "b" (table 1 funcref)) + (import "" "c" (memory 1)) + (import "" "d" (global $g i32)) + ) + (core instance (instantiate $m2 + (with "" (instance + (export "a" (func $i "1")) + (export "b" (table $i "2")) + (export "c" (memory $i "3")) + (export "d" (global $i "4")) + )) + )) +) + +;; indirect references through a synthetic instance +(component + (core module $m + (func (export "a")) + (table (export "b") 1 funcref) + (memory (export "c") 1) + (global (export "d") i32 i32.const 1) + ) + (core instance $i (instantiate $m)) + (core instance $i2 + (export "a1" (func $i "a")) + (export "a2" (table $i "b")) + (export "a3" (memory $i "c")) + (export "a4" (global $i "d")) + ) + + (core module $m2 + (import "" "1" (func $f)) + (import "" "2" (table 1 funcref)) + (import "" "3" (memory 1)) + (import "" "4" (global $g i32)) + ) + (core instance (instantiate $m2 + (with "" (instance + (export "1" (func $i2 "a1")) + (export "2" (table $i2 "a2")) + (export "3" (memory $i2 "a3")) + (export "4" (global $i2 "a4")) + )) + )) +) + +(component + (import "host" (instance $i (export "return-three" (func (result u32))))) + + (core module $m + (import "host" "return-three" (func $three (result i32))) + (func $start + call $three + i32.const 3 + i32.ne + if unreachable end + ) + (start $start) + ) + (core func $three_lower + (canon lower (func $i "return-three")) + ) + (core instance (instantiate $m + (with "host" (instance (export "return-three" (func $three_lower)))) + )) +) + +(component + (import "host" (instance $i + (type $x' (record (field "x" u32))) + (export "x" (type $x (eq $x'))) + (type $rec' (record (field "x" $x) (field "y" string))) + (export "rec" (type $rec (eq $rec'))) + (export "some-record" (type (eq $rec))))) +) + +(component + (import "host" (instance $i + (export "nested" (instance + (export "return-four" (func (result u32))) + )) + )) + + (core module $m + (import "host" "return-three" (func $three (result i32))) + (func $start + call $three + i32.const 4 + i32.ne + if unreachable end + ) + (start $start) + ) + (core func $three_lower + (canon lower (func $i "nested" "return-four")) + ) + (core instance (instantiate $m + (with "host" (instance (export "return-three" (func $three_lower)))) + )) +) + +(component + (import "host" (instance $i + (export "simple-module" (core module)) + )) + + (core instance (instantiate (module $i "simple-module"))) +) + +(component + (import "host" (instance $i + (export "simple-module" (core module + (export "f" (func (result i32))) + (export "g" (global i32)) + )) + )) + + (core instance $i (instantiate (module $i "simple-module"))) + (core module $verify + (import "host" "f" (func $f (result i32))) + (import "host" "g" (global $g i32)) + + (func $start + call $f + i32.const 101 + i32.ne + if unreachable end + + global.get $g + i32.const 100 + i32.ne + if unreachable end + ) + (start $start) + ) + + (core instance (instantiate $verify (with "host" (instance $i)))) +) + +;; export an instance +(component + (core module $m) + (instance $i (export "m" (core module $m))) + (export "i" (instance $i)) +) +(component + (component $c) + (instance $i (instantiate $c)) + (export "i" (instance $i)) +) +(component + (import "host" (instance $i)) + (export "i" (instance $i)) +) + + +(component definition $C1 + (type $r1 (resource (rep i32))) + (export "r" (type $r1)) +) +(component definition $C2 + (type $r1 (resource (rep i32))) + (export "r" (type $r1)) +) + +(component instance $I1 $C1) +(component instance $I2 $C1) +(component instance $I3 $C2) +(component instance $I4 $C2) + +;; all instances have different resource types +(assert_unlinkable + (component + (import "I1" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I2" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") +(assert_unlinkable + (component + (import "I1" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I3" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") +(assert_unlinkable + (component + (import "I1" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I4" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") +(assert_unlinkable + (component + (import "I2" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I3" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") +(assert_unlinkable + (component + (import "I2" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I4" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") +(assert_unlinkable + (component + (import "I3" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I4" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") diff --git a/parser/src/test/resources/spec-tests/wasmtime/linking.wast b/parser/src/test/resources/spec-tests/wasmtime/linking.wast new file mode 100644 index 0000000..966926f --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasmtime/linking.wast @@ -0,0 +1,18 @@ +(assert_unlinkable + (component + (import "undefined-name" (core module)) + ) + "was not found") +(component $i) +(component + (import "i" (instance)) +) +(assert_unlinkable + (component (import "i" (core module))) + "expected module found instance") +(assert_unlinkable + (component (import "i" (func))) + "expected function found instance") +(assert_unlinkable + (component (import "i" (instance (export "x" (func))))) + "was not found") diff --git a/parser/src/test/resources/spec-tests/wasmtime/modules.wast b/parser/src/test/resources/spec-tests/wasmtime/modules.wast new file mode 100644 index 0000000..6014f94 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasmtime/modules.wast @@ -0,0 +1,479 @@ +;;! reference_types = true + +(component $foo + (core module (export "a-module")) +) + +;; the above instance can be imported into this component +(component + (import "foo" (instance + (export "a-module" (core module)) + )) +) + +;; specifying extra imports is ok +(component + (import "foo" (instance + (export "a-module" (core module + (import "foo" "bar" (func)) + )) + )) +) + +;; specifying extra exports is not ok +(assert_unlinkable + (component + (import "foo" (instance + (export "a-module" (core module + (export "the-export" (func)) + )) + )) + ) + "module export `the-export` not defined") + +(component $foo + (core module (export "a-module") + (import "env" "something" (func)) + ) +) + +;; imports must be specified +(assert_unlinkable + (component + (import "foo" (instance + (export "a-module" (core module)) + )) + ) + "module import `env::something` not defined") + +(component + (import "foo" (instance + (export "a-module" (core module + (import "env" "something" (func)) + )) + )) +) + +;; extra imports still ok +(component + (import "foo" (instance + (export "a-module" (core module + (import "env" "something" (func)) + (import "env" "other" (global i32)) + )) + )) +) + +(component $foo + (core module (export "a-module") + (func (export "f")) + ) +) + +;; dropping exports is ok +(component + (import "foo" (instance + (export "a-module" (core module)) + )) +) + +(component + (import "foo" (instance + (export "a-module" (core module + (export "f" (func)) + )) + )) +) + +(assert_unlinkable + (component + (import "foo" (instance + (export "a-module" (core module + (export "f" (func (param i32))) + )) + )) + ) + "expected type `(func (param i32))`, found type `(func)`") + +(assert_unlinkable + (component + (import "foo" (instance + (export "a-module" (core module + (export "f" (global i32)) + )) + )) + ) + "expected global found func") + +(component $foo + (core module (export "m") + (func (export "f")) + (table (export "t") 1 funcref) + (memory (export "m") 1) + (global (export "g") i32 i32.const 0) + ) +) + +;; wrong class of item +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "f" (global i32)))) + )) + ) + "expected global found func") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "t" (func)))) + )) + ) + "expected func found table") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "m" (func)))) + )) + ) + "expected func found memory") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "g" (func)))) + )) + ) + "expected func found global") + +;; wrong item type +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "f" (func (param i32))))) + )) + ) + "export `f` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "t" (table 1 externref)))) + )) + ) + "export `t` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "t" (table 2 funcref)))) + )) + ) + "export `t` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "m" (memory 2)))) + )) + ) + "export `m` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "g" (global f32)))) + )) + ) + "export `g` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "g" (global (mut i32))))) + )) + ) + "export `g` has the wrong type") + +;; subtyping ok +(component + (import "foo" (instance + (export "m" (core module + (export "t" (table 0 funcref)) + (export "m" (memory 0)) + )) + )) +) + +(component $foo + (core module (export "f") (func (import "" ""))) + (core module (export "t") (table (import "" "") 1 funcref)) + (core module (export "m") (memory (import "" "") 1)) + (core module (export "g") (global (import "" "") i32)) +) + +;; wrong class of item +(assert_unlinkable + (component + (import "foo" (instance + (export "f" (core module (import "" "" (global i32)))) + )) + ) + "expected func found global") +(assert_unlinkable + (component + (import "foo" (instance + (export "t" (core module (import "" "" (func)))) + )) + ) + "expected table found func") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (import "" "" (func)))) + )) + ) + "expected memory found func") +(assert_unlinkable + (component + (import "foo" (instance + (export "g" (core module (import "" "" (func)))) + )) + ) + "expected global found func") + +;; wrong item type +(assert_unlinkable + (component + (import "foo" (instance + (export "f" (core module (import "" "" (func (param i32))))) + )) + ) + "module import `::` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "t" (core module (import "" "" (table 1 externref)))) + )) + ) + "module import `::` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "t" (core module (import "" "" (table 0 funcref)))) + )) + ) + "module import `::` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (import "" "" (memory 0)))) + )) + ) + "module import `::` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "g" (core module (import "" "" (global f32)))) + )) + ) + "module import `::` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "g" (core module (import "" "" (global (mut i32))))) + )) + ) + "module import `::` has the wrong type") + +;; subtyping ok, but in the opposite direction of imports +(component + (import "foo" (instance + (export "t" (core module (import "" "" (table 2 funcref)))) + (export "m" (core module (import "" "" (memory 2)))) + )) +) + +;; An instance can reexport a module, define a module, and everything can be +;; used by something else +(component $src + (core module (export "m") + (global (export "g") i32 i32.const 2) + ) +) + +(component $reexport + (core module $m1 + (global (export "g") i32 i32.const 1) + ) + (import "src" (instance $src + (export "m" (core module (export "g" (global i32)))) + )) + + (core module $m3 + (global (export "g") i32 i32.const 3) + ) + + (export "m1" (core module $m1)) + (export "m2" (core module $src "m")) + (export "m3" (core module $m3)) +) + +(component + (core type $modulety (module (export "g" (global i32)))) + (import "reexport" (instance $reexport + (export "m1" (core module (type $modulety))) + (export "m2" (core module (type $modulety))) + (export "m3" (core module (type $modulety))) + )) + + (core module $assert_ok + (import "m1" "g" (global $m1 i32)) + (import "m2" "g" (global $m2 i32)) + (import "m3" "g" (global $m3 i32)) + + (func $assert_ok + block + global.get $m1 + i32.const 1 + i32.eq + br_if 0 + unreachable + end + block + global.get $m2 + i32.const 2 + i32.eq + br_if 0 + unreachable + end + block + global.get $m3 + i32.const 3 + i32.eq + br_if 0 + unreachable + end + ) + + (start $assert_ok) + ) + + (core instance $m1 (instantiate (module $reexport "m1"))) + (core instance $m2 (instantiate (module $reexport "m2"))) + (core instance $m3 (instantiate (module $reexport "m3"))) + + (core instance (instantiate $assert_ok + (with "m1" (instance $m1)) + (with "m2" (instance $m2)) + (with "m3" (instance $m3)) + )) +) + +;; order of imports and exports can be shuffled between definition site and +;; use-site +(component $provider + (core module (export "m") + (import "" "1" (global $i1 i32)) + (import "" "2" (global $i2 i32)) + (import "" "3" (global $i3 i32)) + (import "" "4" (global $i4 i32)) + + (global $g1 i32 i32.const 100) + (global $g2 i32 i32.const 101) + (global $g3 i32 i32.const 102) + (global $g4 i32 i32.const 103) + + (func $assert_imports + (block + global.get $i1 + i32.const 1 + i32.eq + br_if 0 + unreachable) + (block + global.get $i2 + i32.const 2 + i32.eq + br_if 0 + unreachable) + (block + global.get $i3 + i32.const 3 + i32.eq + br_if 0 + unreachable) + (block + global.get $i4 + i32.const 4 + i32.eq + br_if 0 + unreachable) + ) + + (start $assert_imports) + + (export "g1" (global $g1)) + (export "g2" (global $g2)) + (export "g3" (global $g3)) + (export "g4" (global $g4)) + ) +) + +(component + (import "provider" (instance $provider + (export "m" (core module + (import "" "4" (global i32)) + (import "" "3" (global i32)) + (import "" "2" (global i32)) + (import "" "1" (global i32)) + + (export "g4" (global i32)) + (export "g3" (global i32)) + (export "g2" (global i32)) + (export "g1" (global i32)) + )) + )) + + (core module $imports + (global (export "1") i32 (i32.const 1)) + (global (export "3") i32 (i32.const 3)) + (global (export "2") i32 (i32.const 2)) + (global (export "4") i32 (i32.const 4)) + ) + (core instance $imports (instantiate $imports)) + (core instance $m (instantiate (module $provider "m") + (with "" (instance $imports)) + )) + + (core module $import_globals + (import "" "g4" (global $g4 i32)) + (import "" "g3" (global $g3 i32)) + (import "" "g2" (global $g2 i32)) + (import "" "g1" (global $g1 i32)) + + (func $assert_imports + (block + global.get $g1 + i32.const 100 + i32.eq + br_if 0 + unreachable) + (block + global.get $g2 + i32.const 101 + i32.eq + br_if 0 + unreachable) + (block + global.get $g3 + i32.const 102 + i32.eq + br_if 0 + unreachable) + (block + global.get $g4 + i32.const 103 + i32.eq + br_if 0 + unreachable) + ) + + (start $assert_imports) + ) + + (core instance (instantiate $import_globals (with "" (instance $m)))) +) diff --git a/parser/src/test/resources/spec-tests/wasmtime/nested.wast b/parser/src/test/resources/spec-tests/wasmtime/nested.wast new file mode 100644 index 0000000..8cb4c38 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasmtime/nested.wast @@ -0,0 +1,451 @@ +;; simple nested component +(component + (component) +) + +;; simple nested component with a nested module +(component + (component + (core module) + ) +) + +;; simple instantiation of a nested component +(component + (component $c) + (instance (instantiate $c)) + (instance (instantiate $c + (with "x" (component $c)) + )) +) + +;; instantiate a module during a nested component, and also instantiate it +;; as an export of the nested component +(component + (component $c + (core module $m) + (core instance (instantiate $m)) + (export "m" (core module $m)) + ) + (instance $i (instantiate $c)) + (core instance $i (instantiate (module $i "m"))) +) + +;; instantiate an inner exported module with two different modules and +;; verify imports match +(component + (component $c + (core module $m + (import "" "g" (global $g i32)) + (import "" "f" (func $f (result i32))) + + (func $start + call $f + global.get $g + i32.ne + if unreachable end) + + (start $start) + ) + + (core module $m2 + (global (export "g") i32 i32.const 1) + (func (export "f") (result i32) i32.const 1) + ) + (core instance $i2 (instantiate $m2)) + (core instance (instantiate $m (with "" (instance $i2)))) + + (export "m" (core module $m)) + ) + (instance $i (instantiate $c)) + (core module $m2 + (global (export "g") i32 i32.const 5) + (func (export "f") (result i32) i32.const 5) + ) + (core instance $i2 (instantiate $m2)) + (core instance (instantiate (module $i "m") (with "" (instance $i2)))) +) + +;; instantiate an inner component with a module import +(component + (component $c + (import "m" (core module $m + (export "g" (global i32)) + )) + + (core instance $i (instantiate $m)) + + (core module $verify + (import "" "g" (global $g i32)) + + (func $start + global.get $g + i32.const 2 + i32.ne + if unreachable end + ) + + (start $start) + ) + (core instance (instantiate $verify (with "" (instance $i)))) + ) + + (core module $m + (global (export "g") i32 (i32.const 2)) + ) + (instance (instantiate $c (with "m" (core module $m)))) +) + +;; instantiate an inner component with a module import that itself has imports +(component + (component $c + (import "m" (core module $m + (import "" "g" (global i32)) + )) + (core module $m2 + (global (export "g") i32 i32.const 2100) + ) + (core instance $m2 (instantiate $m2)) + (core instance (instantiate $m (with "" (instance $m2)))) + ) + + (core module $verify + (import "" "g" (global $g i32)) + + (func $start + global.get $g + i32.const 2100 + i32.ne + if unreachable end + ) + + (start $start) + ) + (instance (instantiate $c (with "m" (core module $verify)))) +) + +;; instantiate an inner component with an export from the outer component +(component $c + (core module (export "m") + (import "" "g1" (global $g1 i32)) + (import "" "g2" (global $g2 i32)) + + (func $start + global.get $g1 + i32.const 10000 + i32.ne + if unreachable end + + global.get $g2 + i32.const 20000 + i32.ne + if unreachable end + ) + + (start $start) + ) +) + +(component + (import "c" (instance $i + (export "m" (core module + (import "" "g2" (global i32)) + (import "" "g1" (global i32)) + )) + )) + + (component $c + (import "m" (core module $verify + (import "" "g2" (global i32)) + (import "" "g1" (global i32)) + )) + + (core module $m + (global (export "g1") i32 i32.const 10000) + (global (export "g2") i32 i32.const 20000) + ) + (core instance $m (instantiate $m)) + (core instance (instantiate $verify (with "" (instance $m)))) + ) + + (instance (instantiate $c (with "m" (core module $i "m")))) +) + +;; instantiate a reexported module +(component + (core module $m + (global (export "g") i32 i32.const 7) + ) + (component $c + (import "i" (instance $i + (export "m" (core module + (import "" "" (func)) + (export "g" (global i32)) + )) + )) + + (export "m" (core module $i "m")) + ) + + (instance $c (instantiate $c (with "i" (instance (export "m" (core module $m)))))) + (core module $dummy + (func (export "")) + ) + (core instance $dummy (instantiate $dummy)) + + (core instance $m (instantiate (module $c "m") (with "" (instance $dummy)))) + + (core module $verify + (import "" "g" (global i32)) + (func $start + global.get 0 + i32.const 7 + i32.ne + if unreachable end + ) + + (start $start) + ) + (core instance (instantiate $verify (with "" (instance $m)))) +) + +;; module must be found through a few layers of imports +(component $c + (core module (export "m") + (global (export "g") i32 i32.const 101) + ) +) + +(component + (import "c" (instance $i + (export "m" (core module + (export "g" (global i32)) + )) + )) + (component $c1 + (import "c" (instance $i + (export "m" (core module + (export "g" (global i32)) + )) + )) + (core module $verify + (import "" "g" (global i32)) + (func $start + global.get 0 + i32.const 101 + i32.ne + if unreachable end + ) + + (start $start) + ) + (core instance $m (instantiate (module $i "m"))) + (core instance (instantiate $verify (with "" (instance $m)))) + ) + (instance (instantiate $c1 (with "c" (instance $i)))) +) + +;; instantiate outer alias to self +(component $C + (core module $m) + (alias outer $C $m (core module $other_m)) + (core instance (instantiate $other_m)) +) + +(component $C + (component $m) + (alias outer $C $m (component $other_m)) + (instance (instantiate $other_m)) +) + + +;; closing over an outer alias which is actually an argument to some +;; instantiation +(component + (component $c + (import "c" (core module $c + (export "a" (global i32)) + )) + + (component (export "c2") + (export "m" (core module $c)) + ) + ) + + (core module $m1 (global (export "a") i32 i32.const 1)) + (core module $m2 (global (export "a") i32 i32.const 2)) + + (instance $c1 (instantiate $c (with "c" (core module $m1)))) + (instance $c2 (instantiate $c (with "c" (core module $m2)))) + + (instance $m1_container (instantiate (component $c1 "c2"))) + (instance $m2_container (instantiate (component $c2 "c2"))) + + (core instance $core1 (instantiate (module $m1_container "m"))) + (core instance $core2 (instantiate (module $m2_container "m"))) + + (core module $verify + (import "core1" "a" (global $a i32)) + (import "core2" "a" (global $b i32)) + + (func $start + global.get $a + i32.const 1 + i32.ne + if unreachable end + + global.get $b + i32.const 2 + i32.ne + if unreachable end + ) + + (start $start) + ) + (core instance (instantiate $verify + (with "core1" (instance $core1)) + (with "core2" (instance $core2)) + )) +) + +;; simple importing of a component +(component + (component $C) + (component $other + (import "x" (component $c)) + (instance (instantiate $c)) + ) + (instance (instantiate $other (with "x" (component $C)))) +) + +;; deep nesting +(component $C + (core module $m + (global (export "g") i32 (i32.const 1)) + ) + (component $c + (core module (export "m") + (global (export "g") i32 (i32.const 2)) + ) + ) + + (component $c1 + (component $c2 (export "a") + (component $c3 (export "a") + (alias outer $C $m (core module $my_module)) + (alias outer $C $c (component $my_component)) + + (export "m" (core module $my_module)) + (export "c" (component $my_component)) + ) + ) + ) + + (instance $i1 (instantiate $c1)) + (instance $i2 (instantiate (component $i1 "a"))) + (instance $i3 (instantiate (component $i2 "a"))) + + (core instance $m1 (instantiate (module $i3 "m"))) + (instance $c (instantiate (component $i3 "c"))) + (core instance $m2 (instantiate (module $c "m"))) + + (core module $verify + (import "m1" "g" (global $m1 i32)) + (import "m2" "g" (global $m2 i32)) + + (func $start + global.get $m1 + i32.const 1 + i32.ne + if unreachable end + + global.get $m2 + i32.const 2 + i32.ne + if unreachable end + ) + (start $start) + ) + (core instance (instantiate $verify (with "m1" (instance $m1)) (with "m2" (instance $m2)))) +) + +;; Try threading through component instantiation arguments as various forms of +;; instances. +(component + (component $c + (core module $m (export "m")) + (component $c (export "c") + (core module (export "m")) + ) + (instance $i (instantiate $c)) + (instance $i2 + (export "m" (core module $m)) + (export "c" (component $c)) + (export "i" (instance $i)) + ) + (export "i" (instance $i)) + (export "i2" (instance $i2)) + ) + (instance $i (instantiate $c)) + + (component $another + (import "host" (instance + (export "m" (core module)) + (export "c" (component)) + (export "i" (instance)) + )) + ) + (instance (instantiate $another (with "host" (instance $i)))) + (instance (instantiate $another (with "host" (instance $i "i2")))) + + (instance $reexport + (export "c" (component $i "c")) + (export "m" (core module $i "m")) + (export "i" (instance $i "i")) + ) + (instance (instantiate $another (with "host" (instance $reexport)))) +) + +;; thread host functions around +(component + (import "host-return-two" (func $import (result u32))) + + ;; thread the host function through an instance + (component $c + (import "a" (func $f (result u32))) + (export "f" (func $f)) + ) + (instance $c (instantiate $c (with "a" (func $import)))) + (alias export $c "f" (func $import2)) + + ;; thread the host function into a nested component + (component $c2 + (import "host" (instance $i (export "return-two" (func (result u32))))) + + (core module $m + (import "host" "return-two" (func $host (result i32))) + (func $start + call $host + i32.const 2 + i32.ne + if unreachable end + ) + (start $start) + ) + + (core func $return_two + (canon lower (func $i "return-two")) + ) + (core instance (instantiate $m + (with "host" (instance + (export "return-two" (func $return_two)) + )) + )) + ) + + (instance (instantiate $c2 + (with "host" (instance + (export "return-two" (func $import2)) + )) + )) +) diff --git a/parser/src/test/resources/spec-tests/wasmtime/resources.wast b/parser/src/test/resources/spec-tests/wasmtime/resources.wast new file mode 100644 index 0000000..28e68ad --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasmtime/resources.wast @@ -0,0 +1,1091 @@ +;; bare bones "intrinsics work" +(component + (type $r (resource (rep i32))) + (core func $rep (canon resource.rep $r)) + (core func $new (canon resource.new $r)) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "rep" (func $rep (param i32) (result i32))) + (import "" "new" (func $new (param i32) (result i32))) + (import "" "drop" (func $drop (param i32))) + + (func $start + (local $r i32) + (local.set $r (call $new (i32.const 100))) + + (if (i32.ne (local.get $r) (i32.const 1)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r)) (i32.const 100)) (then (unreachable))) + + (call $drop (local.get $r)) + ) + + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "rep" (func $rep)) + (export "new" (func $new)) + (export "drop" (func $drop)) + )) + )) +) + +;; cannot call `resource.drop` on a nonexistent resource +(component + (type $r (resource (rep i32))) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "drop" (func $drop (param i32))) + + (func (export "r") + (call $drop (i32.const 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + )) + )) + + (func (export "r") (canon lift (core func $i "r"))) +) +(assert_trap (invoke "r") "unknown handle index 0") + +;; cannot call `resource.rep` on a nonexistent resource +(component + (type $r (resource (rep i32))) + (core func $rep (canon resource.rep $r)) + + (core module $m + (import "" "rep" (func $rep (param i32) (result i32))) + + (func (export "r") + (drop (call $rep (i32.const 0))) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "rep" (func $rep)) + )) + )) + + (func (export "r") (canon lift (core func $i "r"))) +) +(assert_trap (invoke "r") "unknown handle index 0") + +;; index reuse behavior of handles +(component + (type $r (resource (rep i32))) + (core func $rep (canon resource.rep $r)) + (core func $new (canon resource.new $r)) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "rep" (func $rep (param i32) (result i32))) + (import "" "new" (func $new (param i32) (result i32))) + (import "" "drop" (func $drop (param i32))) + + (func $start + (local $r1 i32) + (local $r2 i32) + (local $r3 i32) + (local $r4 i32) + + ;; resources assigned sequentially + (local.set $r1 (call $new (i32.const 100))) + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + + (local.set $r2 (call $new (i32.const 200))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + + (local.set $r3 (call $new (i32.const 300))) + (if (i32.ne (local.get $r3) (i32.const 3)) (then (unreachable))) + + ;; representations all look good + (if (i32.ne (call $rep (local.get $r1)) (i32.const 100)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r2)) (i32.const 200)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r3)) (i32.const 300)) (then (unreachable))) + + ;; reallocate r2 + (call $drop (local.get $r2)) + (local.set $r2 (call $new (i32.const 400))) + + ;; should have reused index 3 + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + + ;; representations all look good + (if (i32.ne (call $rep (local.get $r1)) (i32.const 100)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r2)) (i32.const 400)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r3)) (i32.const 300)) (then (unreachable))) + + ;; deallocate, then reallocate + (call $drop (local.get $r1)) + (call $drop (local.get $r2)) + (call $drop (local.get $r3)) + + (local.set $r1 (call $new (i32.const 500))) + (local.set $r2 (call $new (i32.const 600))) + (local.set $r3 (call $new (i32.const 700))) + + ;; representations all look good + (if (i32.ne (call $rep (local.get $r1)) (i32.const 500)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r2)) (i32.const 600)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r3)) (i32.const 700)) (then (unreachable))) + + ;; indices should be lifo + (if (i32.ne (local.get $r1) (i32.const 3)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + (if (i32.ne (local.get $r3) (i32.const 1)) (then (unreachable))) + + ;; bump one more time + (local.set $r4 (call $new (i32.const 800))) + (if (i32.ne (local.get $r4) (i32.const 4)) (then (unreachable))) + + ;; deallocate everything + (call $drop (local.get $r1)) + (call $drop (local.get $r2)) + (call $drop (local.get $r3)) + (call $drop (local.get $r4)) + ) + + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "rep" (func $rep)) + (export "new" (func $new)) + (export "drop" (func $drop)) + )) + )) +) + +(assert_unlinkable + (component + (import "host" (instance + (export "missing" (type (sub resource))) + )) + ) + "was not found") +(assert_unlinkable + (component + (import "host" (instance + (export "return-three" (type (sub resource))) + )) + ) + "expected resource found func") + +;; all resources can be uniquely imported +(component + (import "host" (instance + (export "resource1" (type (sub resource))) + (export "resource2" (type (sub resource))) + (export "resource1-again" (type (sub resource))) + )) +) + +;; equality constraints also work +(component + (import "host" (instance + (export "resource1" (type $r1 (sub resource))) + (export "resource2" (type (sub resource))) + (export "resource1-again" (type (eq $r1))) + )) +) + +;; equality constraints are checked if resources are supplied +(assert_unlinkable + (component + (import "host" (instance + (export "resource1" (type (sub resource))) + (export "resource2" (type $r1 (sub resource))) + (export "resource1-again" (type (eq $r1))) + )) + ) + "mismatched resource types") + +;; equality constraints mean that types don't need to be supplied +(component + (import "host" (instance + (export "resource1" (type $r1 (sub resource))) + (export "resource2" (type (sub resource))) + (export "this-name-is-not-provided-in-the-wast-harness" (type (eq $r1))) + )) +) + +;; simple properties of handles +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32))) + )) + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + (alias export $host "[static]resource1.assert" (func $assert)) + + (core func $drop (canon resource.drop $r)) + (core func $ctor (canon lower (func $ctor))) + (core func $assert (canon lower (func $assert))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "assert" (func $assert (param i32 i32))) + + (func $start + (local $r1 i32) + (local $r2 i32) + (local.set $r1 (call $ctor (i32.const 100))) + (local.set $r2 (call $ctor (i32.const 200))) + + ;; assert r1/r2 are sequential + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + + ;; reallocate r1 and it should be reassigned the same index + (call $drop (local.get $r1)) + (local.set $r1 (call $ctor (i32.const 300))) + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + + ;; internal values should match + (call $assert (local.get $r1) (i32.const 300)) + (call $assert (local.get $r2) (i32.const 200)) + ) + + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + (export "ctor" (func $ctor)) + (export "assert" (func $assert)) + )) + )) +) + +;; Using an index that has never been valid is a trap +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32))) + )) + (alias export $host "resource1" (type $r)) + (alias export $host "[static]resource1.assert" (func $assert)) + (core func $assert (canon lower (func $assert))) + + (core module $m + (import "" "assert" (func $assert (param i32 i32))) + + (func (export "f") + (call $assert (i32.const 0) (i32.const 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "assert" (func $assert)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) +) + +(assert_trap (invoke "f") "unknown handle index") + +;; Using an index which was previously valid but no longer valid is also a trap. +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32))) + )) + (alias export $host "[constructor]resource1" (func $ctor)) + (alias export $host "[static]resource1.assert" (func $assert)) + + (core func $assert (canon lower (func $assert))) + (core func $ctor (canon lower (func $ctor))) + + (core module $m + (import "" "assert" (func $assert (param i32 i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + + (global $handle (mut i32) i32.const 0) + + (func (export "f") + (global.set $handle (call $ctor (i32.const 100))) + (call $assert (global.get $handle) (i32.const 100)) + ) + + (func (export "f2") + (call $assert (global.get $handle) (i32.const 100)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "assert" (func $assert)) + (export "ctor" (func $ctor)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) + (func (export "f2") (canon lift (core func $i "f2"))) +) + +(assert_return (invoke "f")) +(assert_trap (invoke "f2") "unknown handle index") + +;; Also invalid to pass a previously valid handle to the drop intrinsic +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + )) + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + + (core func $drop (canon resource.drop $r)) + (core func $ctor (canon lower (func $ctor))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + + (global $handle (mut i32) i32.const 0) + + (func (export "f") + (global.set $handle (call $ctor (i32.const 100))) + (call $drop (global.get $handle)) + ) + + (func (export "f2") + (call $drop (global.get $handle)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "ctor" (func $ctor)) + (export "drop" (func $drop)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) + (func (export "f2") (canon lift (core func $i "f2"))) +) + +(assert_return (invoke "f")) +(assert_trap (invoke "f2") "unknown handle index") + +;; If an inner component instantiates a resource then an outer component +;; should not implicitly have access to that resource. +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + )) + + ;; an inner component which upon instantiation will invoke the constructor, + ;; assert that it's zero, and then forget about it. + (component $inner + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + )) + (alias export $host "[constructor]resource1" (func $ctor)) + + (core func $ctor (canon lower (func $ctor))) + + (core module $m + (import "" "ctor" (func $ctor (param i32) (result i32))) + + (func $start + (if (i32.ne (call $ctor (i32.const 100)) (i32.const 0)) (then (unreachable))) + ) + ) + (core instance $i (instantiate $m + (with "" (instance (export "ctor" (func $ctor)))) + )) + ) + (instance $i (instantiate $inner (with "host" (instance $host)))) + + ;; the rest of this component which is a single function that invokes `drop` + ;; for index 0. The index 0 should be valid within the above component, but + ;; it is not valid within this component + (alias export $host "resource1" (type $r)) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "drop" (func $drop (param i32))) + + (func (export "f") + (call $drop (i32.const 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) +) + +(assert_trap (invoke "f") "unknown handle index") + +;; Same as the above test, but for resources defined within a component +(component + (component $inner + (type $r (resource (rep i32))) + + (core func $ctor (canon resource.new $r)) + + (core module $m + (import "" "ctor" (func $ctor (param i32) (result i32))) + + (func $start + (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) + ) + (start $start) + ) + (core instance $i (instantiate $m + (with "" (instance (export "ctor" (func $ctor)))) + )) + (export "r" (type $r)) + ) + (instance $i (instantiate $inner)) + + ;; the rest of this component which is a single function that invokes `drop` + ;; for index 1. The index 1 should be valid within the above component, but + ;; it is not valid within this component + (alias export $i "r" (type $r)) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "drop" (func $drop (param i32))) + + (func (export "f") + (call $drop (i32.const 1)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) +) + +(assert_trap (invoke "f") "unknown handle index 1") + +;; Each instantiation of a component generates a unique resource type, so +;; allocating in one component and deallocating in another should fail. +(component + (component $inner + (type $r (resource (rep i32))) + + (core func $ctor (canon resource.new $r)) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "drop" (func $drop (param i32))) + + (func (export "alloc") + (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) + ) + (func (export "dealloc") + (call $drop (i32.const 1)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "ctor" (func $ctor)) + (export "drop" (func $drop)) + )) + )) + (func (export "alloc") (canon lift (core func $i "alloc"))) + (func (export "dealloc") (canon lift (core func $i "dealloc"))) + ) + (instance $i1 (instantiate $inner)) + (instance $i2 (instantiate $inner)) + + (alias export $i1 "alloc" (func $alloc_in_1)) + (alias export $i1 "dealloc" (func $dealloc_in_1)) + (alias export $i2 "alloc" (func $alloc_in_2)) + (alias export $i2 "dealloc" (func $dealloc_in_2)) + + (export "alloc-in1" (func $alloc_in_1)) + (export "dealloc-in1" (func $dealloc_in_1)) + (export "alloc-in2" (func $alloc_in_2)) + (export "dealloc-in2" (func $dealloc_in_2)) +) + +(assert_return (invoke "alloc-in1")) +(assert_return (invoke "dealloc-in1")) +(assert_return (invoke "alloc-in1")) +(assert_return (invoke "alloc-in2")) +(assert_return (invoke "dealloc-in2")) +(assert_trap (invoke "dealloc-in2") "unknown handle index") + +;; Same as above, but the same host resource type is imported into a +;; component that is instantiated twice. Each component instance should +;; receive different tables tracking resources so a resource allocated in one +;; should not be visible in the other. +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + )) + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + + (component $inner + (import "r" (type $r (sub resource))) + (import "[constructor]r" (func $ctor (param "r" u32) (result (own $r)))) + + (core func $ctor (canon lower (func $ctor))) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "drop" (func $drop (param i32))) + + (func (export "alloc") + (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) + ) + (func (export "dealloc") + (call $drop (i32.const 1)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "ctor" (func $ctor)) + (export "drop" (func $drop)) + )) + )) + (func (export "alloc") (canon lift (core func $i "alloc"))) + (func (export "dealloc") (canon lift (core func $i "dealloc"))) + ) + (instance $i1 (instantiate $inner + (with "r" (type $r)) + (with "[constructor]r" (func $ctor)) + )) + (instance $i2 (instantiate $inner + (with "r" (type $r)) + (with "[constructor]r" (func $ctor)) + )) + + (alias export $i1 "alloc" (func $alloc_in_1)) + (alias export $i1 "dealloc" (func $dealloc_in_1)) + (alias export $i2 "alloc" (func $alloc_in_2)) + (alias export $i2 "dealloc" (func $dealloc_in_2)) + + (export "alloc-in1" (func $alloc_in_1)) + (export "dealloc-in1" (func $dealloc_in_1)) + (export "alloc-in2" (func $alloc_in_2)) + (export "dealloc-in2" (func $dealloc_in_2)) +) + +(assert_return (invoke "alloc-in1")) +(assert_return (invoke "dealloc-in1")) +(assert_return (invoke "alloc-in1")) +(assert_return (invoke "alloc-in2")) +(assert_return (invoke "dealloc-in2")) +(assert_trap (invoke "dealloc-in2") "unknown handle index") + +;; Multiple copies of intrinsics all work +(component + (type $r (resource (rep i32))) + + (core func $new1 (canon resource.new $r)) + (core func $new2 (canon resource.new $r)) + (core func $drop1 (canon resource.drop $r)) + (core func $drop2 (canon resource.drop $r)) + + (core module $m + (import "" "new1" (func $new1 (param i32) (result i32))) + (import "" "new2" (func $new2 (param i32) (result i32))) + (import "" "drop1" (func $drop1 (param i32))) + (import "" "drop2" (func $drop2 (param i32))) + + (func $start + ;; 2x2 matrix of pairing new/drop + (call $drop1 (call $new1 (i32.const 101))) + (call $drop2 (call $new1 (i32.const 102))) + (call $drop1 (call $new2 (i32.const 103))) + (call $drop2 (call $new2 (i32.const 104))) + + ;; should be referencing the same namespace + (if (i32.ne (call $new1 (i32.const 105)) (i32.const 1)) (then (unreachable))) + (if (i32.ne (call $new2 (i32.const 105)) (i32.const 2)) (then (unreachable))) + + ;; use different drops out of order + (call $drop2 (i32.const 1)) + (call $drop1 (i32.const 2)) + ) + + (start $start) + ) + + (core instance (instantiate $m + (with "" (instance + (export "new1" (func $new1)) + (export "new2" (func $new2)) + (export "drop1" (func $drop1)) + (export "drop2" (func $drop2)) + )) + )) +) + +;; u32::MAX isn't special in some weird way, it's just probably always invalid +;; because that's a lot of handles. +(component + (type $r (resource (rep i32))) + + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "drop" (func $drop (param i32))) + + (func (export "f") + (call $drop (i32.const 0xffffffff)) + ) + ) + + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + )) + )) + (func (export "f") (canon lift (core func $i "f"))) +) +(assert_trap (invoke "f") "unknown handle index") + +;; Test behavior of running a destructor for local resources +(component + (core module $m1 + (global $drops (mut i32) i32.const 0) + (global $last_drop (mut i32) i32.const -1) + + (func (export "dtor") (param i32) + (global.set $drops (i32.add (global.get $drops) (i32.const 1))) + (global.set $last_drop (local.get 0)) + ) + (func (export "drops") (result i32) global.get $drops) + (func (export "last-drop") (result i32) global.get $last_drop) + ) + (core instance $i1 (instantiate $m1)) + + (type $r1 (resource (rep i32))) + (type $r2 (resource (rep i32) (dtor (func $i1 "dtor")))) + + (core func $drop1 (canon resource.drop $r1)) + (core func $drop2 (canon resource.drop $r2)) + (core func $new1 (canon resource.new $r1)) + (core func $new2 (canon resource.new $r2)) + + (core module $m2 + (import "" "drop1" (func $drop1 (param i32))) + (import "" "drop2" (func $drop2 (param i32))) + (import "" "new1" (func $new1 (param i32) (result i32))) + (import "" "new2" (func $new2 (param i32) (result i32))) + (import "i1" "drops" (func $drops (result i32))) + (import "i1" "last-drop" (func $last-drop (result i32))) + + (func $start + (local $r1 i32) + (local $r2 i32) + + (local.set $r1 (call $new1 (i32.const 100))) + (local.set $r2 (call $new2 (i32.const 200))) + + ;; indexes start at 2 and while they have distinct types they should be + ;; within the same table. + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + + ;; nothing should be dropped yet + (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const -1)) (then (unreachable))) + + ;; dropping a resource without a destructor is ok, but shouldn't tamper + ;; with anything. + (call $drop1 (local.get $r1)) + (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const -1)) (then (unreachable))) + + ;; drop r2 which should record a drop and additionally record the private + ;; representation value which was dropped + (call $drop2 (local.get $r2)) + (if (i32.ne (call $drops) (i32.const 1)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const 200)) (then (unreachable))) + + ;; do it all over again + (local.set $r2 (call $new2 (i32.const 300))) + (call $drop2 (local.get $r2)) + (if (i32.ne (call $drops) (i32.const 2)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const 300)) (then (unreachable))) + ) + + (start $start) + ) + + (core instance $i2 (instantiate $m2 + (with "" (instance + (export "drop1" (func $drop1)) + (export "drop2" (func $drop2)) + (export "new1" (func $new1)) + (export "new2" (func $new2)) + )) + (with "i1" (instance $i1)) + )) +) + +;; Test dropping a host resource +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + (export "[static]resource1.last-drop" (func (result u32))) + (export "[static]resource1.drops" (func (result u32))) + )) + + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + (alias export $host "[static]resource1.last-drop" (func $last-drop)) + (alias export $host "[static]resource1.drops" (func $drops)) + + (core func $drop (canon resource.drop $r)) + (core func $ctor (canon lower (func $ctor))) + (core func $last-drop (canon lower (func $last-drop))) + (core func $drops (canon lower (func $drops))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "last-drop" (func $last-drop (result i32))) + (import "" "drops" (func $raw-drops (result i32))) + + (global $init-drop-cnt (mut i32) i32.const 0) + + (func $drops (result i32) + (i32.sub (call $raw-drops) (global.get $init-drop-cnt)) + ) + + (func $start + (local $r1 i32) + (global.set $init-drop-cnt (call $raw-drops)) + + (local.set $r1 (call $ctor (i32.const 100))) + + ;; should be no drops yet + (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) + + ;; should count a drop + (call $drop (local.get $r1)) + (if (i32.ne (call $drops) (i32.const 1)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const 100)) (then (unreachable))) + + ;; do it again to be sure + (local.set $r1 (call $ctor (i32.const 200))) + (call $drop (local.get $r1)) + (if (i32.ne (call $drops) (i32.const 2)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const 200)) (then (unreachable))) + ) + + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + (export "ctor" (func $ctor)) + (export "last-drop" (func $last-drop)) + (export "drops" (func $drops)) + )) + )) +) + +;; Test some bare-bones basics of borrowed resources +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + (export "[method]resource1.simple" (func (param "self" (borrow $r)) (param "rep" u32))) + (export "[method]resource1.take-borrow" (func (param "self" (borrow $r)) (param "b" (borrow $r)))) + (export "[method]resource1.take-own" (func (param "self" (borrow $r)) (param "b" (own $r)))) + )) + + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + (alias export $host "[method]resource1.simple" (func $simple)) + (alias export $host "[method]resource1.take-borrow" (func $take-borrow)) + (alias export $host "[method]resource1.take-own" (func $take-own)) + + (core func $drop (canon resource.drop $r)) + (core func $ctor (canon lower (func $ctor))) + (core func $simple (canon lower (func $simple))) + (core func $take-own (canon lower (func $take-own))) + (core func $take-borrow (canon lower (func $take-borrow))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "simple" (func $simple (param i32 i32))) + (import "" "take-own" (func $take-own (param i32 i32))) + (import "" "take-borrow" (func $take-borrow (param i32 i32))) + + + (func $start + (local $r1 i32) + (local $r2 i32) + (local.set $r1 (call $ctor (i32.const 100))) + (local.set $r2 (call $ctor (i32.const 200))) + + (call $simple (local.get $r1) (i32.const 100)) + (call $simple (local.get $r1) (i32.const 100)) + (call $simple (local.get $r2) (i32.const 200)) + (call $simple (local.get $r1) (i32.const 100)) + (call $simple (local.get $r2) (i32.const 200)) + (call $simple (local.get $r2) (i32.const 200)) + + (call $drop (local.get $r1)) + (call $drop (local.get $r2)) + + + (local.set $r1 (call $ctor (i32.const 200))) + (local.set $r2 (call $ctor (i32.const 300))) + (call $take-borrow (local.get $r1) (local.get $r2)) + (call $take-borrow (local.get $r2) (local.get $r1)) + (call $take-borrow (local.get $r1) (local.get $r1)) + (call $take-borrow (local.get $r2) (local.get $r2)) + + (call $take-own (local.get $r1) (call $ctor (i32.const 400))) + (call $take-own (local.get $r2) (call $ctor (i32.const 500))) + (call $take-own (local.get $r2) (local.get $r1)) + (call $drop (local.get $r2)) + + ;; table should be empty at this point, so a fresh allocation should get + ;; index 2 + (if (i32.ne (call $ctor (i32.const 600)) (i32.const 1)) (then (unreachable))) + ) + + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + (export "ctor" (func $ctor)) + (export "simple" (func $simple)) + (export "take-own" (func $take-own)) + (export "take-borrow" (func $take-borrow)) + )) + )) +) + +;; Cannot pass out an owned resource when it's borrowed by the same call +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + (export "[method]resource1.take-own" (func (param "self" (borrow $r)) (param "b" (own $r)))) + )) + + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + (alias export $host "[method]resource1.take-own" (func $take-own)) + + (core func $drop (canon resource.drop $r)) + (core func $ctor (canon lower (func $ctor))) + (core func $take-own (canon lower (func $take-own))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "take-own" (func $take-own (param i32 i32))) + + + (func (export "f") + (local $r i32) + (local.set $r (call $ctor (i32.const 100))) + (call $take-own (local.get $r) (local.get $r)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + (export "ctor" (func $ctor)) + (export "take-own" (func $take-own)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) +) + +(assert_trap (invoke "f") "cannot remove owned resource while borrowed") + +;; Borrows must actually exist +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[method]resource1.simple" (func (param "self" (borrow $r)) (param "b" u32))) + )) + + (alias export $host "resource1" (type $r)) + (alias export $host "[method]resource1.simple" (func $simple)) + + (core func $drop (canon resource.drop $r)) + (core func $simple (canon lower (func $simple))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "simple" (func $simple (param i32 i32))) + + + (func (export "f") + (call $simple (i32.const 0) (i32.const 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + (export "simple" (func $simple)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) +) + +(assert_trap (invoke "f") "unknown handle index 0") + +(component + (component $A + (type $t' (resource (rep i32))) + (export $t "t" (type $t')) + + (core func $ctor (canon resource.new $t)) + (core func $dtor (canon resource.drop $t)) + (core func $rep (canon resource.rep $t)) + + (core module $m + (import "" "dtor" (func $dtor (param i32))) + (import "" "rep" (func $rep (param i32) (result i32))) + + (func (export "[method]t.assert") (param i32 i32) + (if (i32.ne (local.get 0) (local.get 1)) (then (unreachable))) + ) + (func (export "[static]t.assert-own") (param i32 i32) + (if (i32.ne (call $rep (local.get 0)) (local.get 1)) (then (unreachable))) + (call $dtor (local.get 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "dtor" (func $dtor)) + (export "rep" (func $rep)) + )) + )) + (func (export "[constructor]t") (param "x" u32) (result (own $t)) + (canon lift (core func $ctor))) + (func (export "[method]t.assert") (param "self" (borrow $t)) (param "x" u32) + (canon lift (core func $i "[method]t.assert"))) + (func (export "[static]t.assert-own") (param "self" (own $t)) (param "x" u32) + (canon lift (core func $i "[static]t.assert-own"))) + ) + (instance $a (instantiate $A)) + + (component $B + (import "a" (instance $i + (export "t" (type $t (sub resource))) + (export "[constructor]t" (func (param "x" u32) (result (own $t)))) + (export "[method]t.assert" (func (param "self" (borrow $t)) (param "x" u32))) + (export "[static]t.assert-own" (func (param "self" (own $t)) (param "x" u32))) + )) + + (alias export $i "t" (type $t)) + (alias export $i "[constructor]t" (func $ctor)) + (alias export $i "[method]t.assert" (func $assert-borrow)) + (alias export $i "[static]t.assert-own" (func $assert-own)) + + (core func $ctor (canon lower (func $ctor))) + (core func $dtor (canon resource.drop $t)) + (core func $assert-own (canon lower (func $assert-own))) + (core func $assert-borrow (canon lower (func $assert-borrow))) + + (core module $m + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "dtor" (func $dtor (param i32))) + (import "" "assert-own" (func $assert-own (param i32 i32))) + (import "" "assert-borrow" (func $assert-borrow (param i32 i32))) + + (func (export "f") + (local $r1 i32) + (local $r2 i32) + + (local.set $r1 (call $ctor (i32.const 100))) + (local.set $r2 (call $ctor (i32.const 200))) + + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + + (call $assert-borrow (local.get $r2) (i32.const 200)) + (call $assert-borrow (local.get $r1) (i32.const 100)) + + (call $assert-own (local.get $r2) (i32.const 200)) + (call $dtor (local.get $r1)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "ctor" (func $ctor)) + (export "dtor" (func $dtor)) + (export "assert-own" (func $assert-own)) + (export "assert-borrow" (func $assert-borrow)) + )) + )) + (func (export "f") (canon lift (core func $i "f"))) + ) + (instance $b (instantiate $B (with "a" (instance $a)))) + (export "f" (func $b "f")) +) + +(assert_return (invoke "f")) + +;; Test destructor behavior when using the wrong resource type +(component definition $C + (type $r1 (resource (rep i32))) + (type $r2 (resource (rep i32))) + + (core func $drop1 (canon resource.drop $r1)) + (core func $drop2 (canon resource.drop $r2)) + (core func $new1 (canon resource.new $r1)) + (core func $new2 (canon resource.new $r2)) + + (core module $m2 + (import "" "drop1" (func $drop1 (param i32))) + (import "" "drop2" (func $drop2 (param i32))) + (import "" "new1" (func $new1 (param i32) (result i32))) + (import "" "new2" (func $new2 (param i32) (result i32))) + + (func (export "drop-r1-as-r2") (call $drop2 (call $new1 (i32.const 100)))) + (func (export "return-r1-as-r2") (result i32) (call $new1 (i32.const 100))) + ) + + (core instance $i2 (instantiate $m2 + (with "" (instance + (export "drop1" (func $drop1)) + (export "drop2" (func $drop2)) + (export "new1" (func $new1)) + (export "new2" (func $new2)) + )) + )) + + (export $r2' "r2" (type $r2)) + (func (export "drop-r1-as-r2") (canon lift (core func $i2 "drop-r1-as-r2"))) + (func (export "return-r1-as-r2") (result (own $r2')) (canon lift (core func $i2 "return-r1-as-r2"))) +) + +(component instance $C1 $C) +(assert_trap (invoke "drop-r1-as-r2") "handle index 1 used with the wrong type, expected guest-defined resource but found a different guest-defined resource") +(component instance $C1 $C) +(assert_trap (invoke "return-r1-as-r2") "handle index 1 used with the wrong type, expected guest-defined resource but found a different guest-defined resource") diff --git a/parser/src/test/resources/spec-tests/wasmtime/restrictions.wast b/parser/src/test/resources/spec-tests/wasmtime/restrictions.wast new file mode 100644 index 0000000..9bd53e7 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasmtime/restrictions.wast @@ -0,0 +1,22 @@ +(assert_invalid + (component (import "x" (component))) + "root-level component imports are not supported") + +(assert_invalid + (component (component (export "x"))) + "exporting a component from the root component is not supported") + +(assert_invalid + (component + (import "f" (func $f)) + (export "f" (func $f)) + ) + "component export `f` is a reexport of an imported function which is not implemented") + +(assert_invalid + (component + (import "x" (component + (export "x" (type (sub resource))) + )) + ) + "root-level component imports are not supported") diff --git a/parser/src/test/resources/spec-tests/wasmtime/simple.wast b/parser/src/test/resources/spec-tests/wasmtime/simple.wast new file mode 100644 index 0000000..7bf2ab1 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasmtime/simple.wast @@ -0,0 +1,42 @@ +(component) + +(component + (core module) +) + +(component + (core module) + (core module) + (core module) +) + +(component + (core module + (func (export "a") (result i32) i32.const 0) + (func (export "b") (result i64) i64.const 0) + ) + (core module + (func (export "c") (result f32) f32.const 0) + (func (export "d") (result f64) f64.const 0) + ) +) + +(assert_invalid + (component + (import "a" (component)) + ) + "root-level component imports are not supported") + +(assert_invalid + (component + (component (export "a")) + ) + "exporting a component from the root component is not supported") + +(component + (core module $m (func (export ""))) + (core instance $m (instantiate $m)) + (func (export "a") (canon lift (core func $m ""))) +) + +(assert_return (invoke "a")) diff --git a/parser/src/test/resources/spec-tests/wasmtime/strings.wast b/parser/src/test/resources/spec-tests/wasmtime/strings.wast new file mode 100644 index 0000000..943fd31 --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasmtime/strings.wast @@ -0,0 +1,110 @@ +;;! multi_memory = true + +;; unaligned utf16 string +(assert_trap + (component + (component $c + (core module $m + (func (export "") (param i32 i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 0) + (memory (export "memory") 1) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" string) + (canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory")) + ) + ) + + (component $c2 + (import "a" (func $f (param "a" string))) + (core module $libc + (memory (export "memory") 1) + ) + (core instance $libc (instantiate $libc)) + (core func $f (canon lower (func $f) string-encoding=utf16 (memory $libc "memory"))) + (core module $m + (import "" "" (func $f (param i32 i32))) + + (func $start (call $f (i32.const 1) (i32.const 0))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "" (func $f)))))) + ) + + (instance $c (instantiate $c)) + (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) + ) + "unaligned pointer") + +;; unaligned latin1+utf16 string, even with the latin1 encoding +(assert_trap + (component + (component $c + (core module $m + (func (export "") (param i32 i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 0) + (memory (export "memory") 1) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" string) + (canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory")) + ) + ) + + (component $c2 + (import "a" (func $f (param "a" string))) + (core module $libc + (memory (export "memory") 1) + ) + (core instance $libc (instantiate $libc)) + (core func $f (canon lower (func $f) string-encoding=latin1+utf16 (memory $libc "memory"))) + (core module $m + (import "" "" (func $f (param i32 i32))) + + (func $start (call $f (i32.const 1) (i32.const 0))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "" (func $f)))))) + ) + + (instance $c (instantiate $c)) + (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) + ) + "unaligned pointer") + +;; out of bounds utf8->utf8 string +(assert_trap + (component + (component $c + (core module $m + (func (export "") (param i32 i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 0) + (memory (export "memory") 1) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" string) + (canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory") + string-encoding=utf8) + ) + ) + + (component $c2 + (import "a" (func $f (param "a" string))) + (core module $libc + (memory (export "memory") 1) + ) + (core instance $libc (instantiate $libc)) + (core func $f (canon lower (func $f) string-encoding=utf8 (memory $libc "memory"))) + (core module $m + (import "" "" (func $f (param i32 i32))) + + (func $start (call $f (i32.const 0x8000_0000) (i32.const 1))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "" (func $f)))))) + ) + + (instance $c (instantiate $c)) + (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) + ) + "string content out-of-bounds") diff --git a/parser/src/test/resources/spec-tests/wasmtime/tags.wast b/parser/src/test/resources/spec-tests/wasmtime/tags.wast new file mode 100644 index 0000000..cac1fde --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasmtime/tags.wast @@ -0,0 +1,14 @@ +;;! exceptions = true + +(component + (core module $a (tag (export "t"))) + (core module $b (import "a" "t" (tag))) + + (core instance $a (instantiate $a)) + (core instance (instantiate $b (with "a" (instance $a)))) + (core instance (instantiate $b + (with "a" (instance + (export "t" (tag $a "t")) + )) + )) +) diff --git a/parser/src/test/resources/spec-tests/wasmtime/types.wast b/parser/src/test/resources/spec-tests/wasmtime/types.wast new file mode 100644 index 0000000..9596ebe --- /dev/null +++ b/parser/src/test/resources/spec-tests/wasmtime/types.wast @@ -0,0 +1,355 @@ +(component + (type string) + (type (func (param "a" string))) + (type $r (record (field "x" (result)) (field "y" string))) + (type $u (variant (case "r" $r) (case "s" string))) + (type $e (result $u (error u32))) + (type (result $u)) + (type (result (error $u))) + (type (result)) + + (type (func (param "a" $e) (result (option $r)))) + + (type (variant + (case "a" string) + (case "b" u32) + (case "c" float32) + (case "d" float64) + )) + + (type $errno (enum "a" "b" "e")) + (type (list $errno)) + (type $oflags (flags "read" "write" "exclusive")) + (type (tuple $oflags $errno $r)) + + ;; primitives in functions + (type (func + (param "a" bool) + (param "b" u8) + (param "c" s8) + (param "d" u16) + (param "e" s16) + (param "f" u32) + (param "g" s32) + (param "h" u64) + (param "i" s64) + (param "j" char) + (param "k" string) + )) + + ;; primitives in types + (type bool) + (type u8) + (type s8) + (type u16) + (type s16) + (type u32) + (type s32) + (type u64) + (type s64) + (type char) + (type string) +) + +(component + (type $empty (func)) + (type (func (param "a" string) (result u32))) + (type (component)) + (core type (module)) + (core type (func)) + (type (instance)) + + (type (component + (import "x" (func (type $empty))) + (import "y" (func)) + (import "z" (component)) + + (type $t (instance)) + + (export "a" (core module)) + (export "b" (instance (type $t))) + )) + + (type (instance + (export "x" (func (type $empty))) + (export "y" (func)) + (export "z" (component)) + + (type $t (instance)) + + (export "a" (core module)) + (export "b" (instance (type $t))) + )) + + (core type (module + (import "" "" (func (param i32))) + (import "" "1" (func (result i32))) + (export "1" (global i32)) + (export "2" (memory 1)) + (export "3" (table 1 funcref)) + )) +) + +;; outer core aliases work +(component $C + (core type $f (func)) + (core type $m (module)) + + (component $C2 + (alias outer $C $f (core type $my_f)) + (import "a" (core module (type $m))) + (import "x" (core module + (alias outer $C2 $my_f (type $my_f)) + (import "" "1" (func (type $my_f))) + )) + ) +) + +;; type exports work +(component $C + (component $C2 + (type string) + (export "x" (type 0)) + ) + (instance (instantiate 0)) + (alias export 0 "x" (type)) + (export "x" (type 0)) +) + +(component + (core module $m (func (export "") (param i32) (result i32) local.get 0)) + (core instance $m (instantiate $m)) + (func (export "i-to-b") (param "a" u32) (result bool) (canon lift (core func $m ""))) + (func (export "i-to-u8") (param "a" u32) (result u8) (canon lift (core func $m ""))) + (func (export "i-to-s8") (param "a" u32) (result s8) (canon lift (core func $m ""))) + (func (export "i-to-u16") (param "a" u32) (result u16) (canon lift (core func $m ""))) + (func (export "i-to-s16") (param "a" u32) (result s16) (canon lift (core func $m ""))) +) +(assert_return (invoke "i-to-b" (u32.const 0)) (bool.const false)) +(assert_return (invoke "i-to-b" (u32.const 1)) (bool.const true)) +(assert_return (invoke "i-to-b" (u32.const 2)) (bool.const true)) +(assert_return (invoke "i-to-u8" (u32.const 0x00)) (u8.const 0)) +(assert_return (invoke "i-to-u8" (u32.const 0x01)) (u8.const 1)) +(assert_return (invoke "i-to-u8" (u32.const 0xf01)) (u8.const 1)) +(assert_return (invoke "i-to-u8" (u32.const 0xf00)) (u8.const 0)) +(assert_return (invoke "i-to-s8" (u32.const 0xffffffff)) (s8.const -1)) +(assert_return (invoke "i-to-s8" (u32.const 127)) (s8.const 127)) +(assert_return (invoke "i-to-u16" (u32.const 0)) (u16.const 0)) +(assert_return (invoke "i-to-u16" (u32.const 1)) (u16.const 1)) +(assert_return (invoke "i-to-u16" (u32.const 0xffffffff)) (u16.const 0xffff)) +(assert_return (invoke "i-to-s16" (u32.const 0)) (s16.const 0)) +(assert_return (invoke "i-to-s16" (u32.const 1)) (s16.const 1)) +(assert_return (invoke "i-to-s16" (u32.const 0xffffffff)) (s16.const -1)) + +(assert_invalid + (component + (type $t1 string) + (type $t2 (list $t1)) + (type $t3 (list $t2)) + (type $t4 (list $t3)) + (type $t5 (list $t4)) + (type $t6 (list $t5)) + (type $t7 (list $t6)) + (type $t8 (list $t7)) + (type $t9 (list $t8)) + (type $t10 (list $t9)) + (type $t11 (list $t10)) + (type $t12 (list $t11)) + (type $t13 (list $t12)) + (type $t14 (list $t13)) + (type $t15 (list $t14)) + (type $t16 (list $t15)) + (type $t17 (list $t16)) + (type $t18 (list $t17)) + (type $t19 (list $t18)) + (type $t20 (list $t19)) + (type $t21 (list $t20)) + (type $t22 (list $t21)) + (type $t23 (list $t22)) + (type $t24 (list $t23)) + (type $t25 (list $t24)) + (type $t26 (list $t25)) + (type $t27 (list $t26)) + (type $t28 (list $t27)) + (type $t29 (list $t28)) + (type $t30 (list $t29)) + (type $t31 (list $t30)) + (type $t32 (list $t31)) + (type $t33 (list $t32)) + (type $t34 (list $t33)) + (type $t35 (list $t34)) + (type $t36 (list $t35)) + (type $t37 (list $t36)) + (type $t38 (list $t37)) + (type $t39 (list $t38)) + (type $t40 (list $t39)) + (type $t41 (list $t40)) + (type $t42 (list $t41)) + (type $t43 (list $t42)) + (type $t44 (list $t43)) + (type $t45 (list $t44)) + (type $t46 (list $t45)) + (type $t47 (list $t46)) + (type $t48 (list $t47)) + (type $t49 (list $t48)) + (type $t50 (list $t49)) + (type $t51 (list $t50)) + (type $t52 (list $t51)) + (type $t53 (list $t52)) + (type $t54 (list $t53)) + (type $t55 (list $t54)) + (type $t56 (list $t55)) + (type $t57 (list $t56)) + (type $t58 (list $t57)) + (type $t59 (list $t58)) + (type $t60 (list $t59)) + (type $t61 (list $t60)) + (type $t62 (list $t61)) + (type $t63 (list $t62)) + (type $t64 (list $t63)) + (type $t65 (list $t64)) + (type $t66 (list $t65)) + (type $t67 (list $t66)) + (type $t68 (list $t67)) + (type $t69 (list $t68)) + (type $t70 (list $t69)) + (type $t71 (list $t70)) + (type $t72 (list $t71)) + (type $t73 (list $t72)) + (type $t74 (list $t73)) + (type $t75 (list $t74)) + (type $t76 (list $t75)) + (type $t77 (list $t76)) + (type $t78 (list $t77)) + (type $t79 (list $t78)) + (type $t80 (list $t79)) + (type $t81 (list $t80)) + (type $t82 (list $t81)) + (type $t83 (list $t82)) + (type $t84 (list $t83)) + (type $t85 (list $t84)) + (type $t86 (list $t85)) + (type $t87 (list $t86)) + (type $t88 (list $t87)) + (type $t89 (list $t88)) + (type $t90 (list $t89)) + (type $t91 (list $t90)) + (type $t92 (list $t91)) + (type $t93 (list $t92)) + (type $t94 (list $t93)) + (type $t95 (list $t94)) + (type $t96 (list $t95)) + (type $t97 (list $t96)) + (type $t98 (list $t97)) + (type $t99 (list $t98)) + (type $t100 (list $t99)) + (type $t101 (list $t100)) + (export "t" (type $t101)) + ) + "type nesting is too deep") + +(component + (type (instance + (export "x" (instance $x + (type $t u32) + (export "y" (type (eq $t))) + )) + (alias export $x "y" (type $t)) + (export "my-y" (type (eq $t))) + )) + + (type (component + (import "x" (instance $x + (type $t u32) + (export "y" (type (eq $t))) + )) + (alias export $x "y" (type $t)) + (export "my-y" (type (eq $t))) + )) +) + +(component + (type $t u32) + (export $t2 "t" (type $t)) + (type $r (record (field "x" $t2))) + (export "r" (type $r)) +) + +(component + (component + (import "x" (instance $i + (type $i u32) + (export "i" (type (eq $i))) + )) + (alias export $i "i" (type $i)) + (export "i" (type $i)) + ) +) + +(component + (type $u u32) + (instance $i + (export "i" (type $u)) + ) + (alias export $i "i" (type $i)) + (export "i" (type $i)) +) + +(component + (component $c + (type $t u32) + (export "t" (type $t)) + ) + (instance $c (instantiate $c)) + (export "i" (type $c "t")) +) + +(component + (component $c + (import "x" (component $c + (type $t u32) + (export "t" (type (eq $t))) + )) + (instance $c (instantiate $c)) + (export "i" (type $c "t")) + ) + + (component $x + (type $t u32) + (export "t" (type $t)) + ) + + (instance $c (instantiate $c (with "x" (component $x)))) +) + +(component + (type $t1 u64) + (import "a" (type $t2 (eq $t1))) + (import "b" (type $t3 (eq $t2))) +) + +(component + (import "a" (instance + (type $t1 u64) + (export "a" (type $t2 (eq $t1))) + (export "b" (type (eq $t2))) + )) +) + +(component + (type (export "x") (component + (type $t' (instance + (export "r" (type (sub resource))) + )) + (export "t" (instance $t (type $t'))) + )) +) + +(component + (type (export "x") (instance + (type $t' (instance + (export "r" (type (sub resource))) + )) + (export "t" (instance $t (type $t'))) + )) +) diff --git a/parser/update-spec-tests.sh b/parser/update-spec-tests.sh new file mode 100755 index 0000000..b4b0038 --- /dev/null +++ b/parser/update-spec-tests.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO="WebAssembly/component-model" +BRANCH="main" +REMOTE_TEST_DIR="test" +LOCAL_TEST_DIR="src/test/resources/spec-tests" + +API_BASE="https://api.github.com/repos/${REPO}/contents" +RAW_BASE="https://raw.githubusercontent.com/${REPO}/${BRANCH}" + +# Tracks every remote .wast path (relative to LOCAL_TEST_DIR) seen during the run +REMOTE_FILES=() + +collect_and_download() { + local api_path="$1" + local local_path="$2" + + local entries + entries=$(curl -fsSL "${API_BASE}/${api_path}") + + while IFS= read -r entry; do + local type name + type=$(printf '%s' "$entry" | grep -o '"type":"[^"]*"' | head -1 | cut -d'"' -f4) + name=$(printf '%s' "$entry" | grep -o '"name":"[^"]*"' | head -1 | cut -d'"' -f4) + + if [[ "$type" == "dir" ]]; then + collect_and_download "${api_path}/${name}" "${local_path}/${name}" + elif [[ "$type" == "file" && "$name" == *.wast ]]; then + mkdir -p "$local_path" + local dest="${local_path}/${name}" + REMOTE_FILES+=("$dest") + echo " Downloading ${api_path}/${name}" + curl -fsSL "${RAW_BASE}/${api_path}/${name}" -o "$dest" + fi + done < <(printf '%s' "$entries" | python3 -c " +import sys, json +data = json.load(sys.stdin) +for item in data: + print('{\"type\":\"' + item['type'] + '\",\"name\":\"' + item['name'] + '\"}')") +} + +mkdir -p "$LOCAL_TEST_DIR" + +echo "Fetching .wast tests from ${REPO}/${REMOTE_TEST_DIR} (branch: ${BRANCH})..." +collect_and_download "$REMOTE_TEST_DIR" "$LOCAL_TEST_DIR" + +echo "" +echo "Removing local files no longer present in remote..." +while IFS= read -r local_file; do + if [[ ! " ${REMOTE_FILES[*]} " == *" ${local_file} "* ]]; then + echo " Deleting ${local_file}" + rm -f "$local_file" + fi +done < <(find "$LOCAL_TEST_DIR" -name "*.wast" | sort) + +# Remove any directories that are now empty +find "$LOCAL_TEST_DIR" -type d -empty -delete 2>/dev/null || true + +echo "" +echo "Done. Current files:" +find "$LOCAL_TEST_DIR" -name "*.wast" | sort | sed 's|^| |' diff --git a/pom.xml b/pom.xml index b1c7b1f..c20c731 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,8 @@ + parser + types wit-parser @@ -36,11 +38,17 @@ 999-SNAPSHOT 0.1.0 + 2.18.3 5.14.4 + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + io.roastedroot zerofs @@ -71,12 +79,28 @@ wasm-tools ${endive.version} + + run.endive.cm + parser + ${project.version} + + + run.endive.cm + types + ${project.version} + org.junit.jupiter junit-jupiter-api ${junit.version} test + + org.junit.jupiter + junit-jupiter-params + ${junit.version} + test + diff --git a/types/pom.xml b/types/pom.xml new file mode 100644 index 0000000..9fd807f --- /dev/null +++ b/types/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + run.endive.cm + endive-cm + 999-SNAPSHOT + + + types + jar + + Endive CM - Component Model Types + Types for Endive Component Model + + + + run.endive + wasm + + + run.endive + wasm-tools + + + org.junit.jupiter + junit-jupiter-api + test + + + + diff --git a/types/src/main/java/run/endive/cm/types/Section.java b/types/src/main/java/run/endive/cm/types/Section.java new file mode 100644 index 0000000..ed3006b --- /dev/null +++ b/types/src/main/java/run/endive/cm/types/Section.java @@ -0,0 +1,13 @@ +package run.endive.cm.types; + +public abstract class Section { + private final int id; + + Section(long id) { + this.id = (int) id; + } + + public int sectionId() { + return id; + } +} diff --git a/types/src/main/java/run/endive/cm/types/SectionId.java b/types/src/main/java/run/endive/cm/types/SectionId.java new file mode 100644 index 0000000..e328d64 --- /dev/null +++ b/types/src/main/java/run/endive/cm/types/SectionId.java @@ -0,0 +1,19 @@ +package run.endive.cm.types; + +public final class SectionId { + public static final int CUSTOM = 0; + public static final int CORE_MODULE = 1; + public static final int CORE_INSTANCE = 2; + public static final int CORE_TYPE = 3; + public static final int COMPONENT = 4; + public static final int INSTANCE = 5; + public static final int ALIAS = 6; + public static final int TYPE = 7; + public static final int CANON = 8; + public static final int START = 9; + public static final int IMPORT = 10; + public static final int EXPORT = 11; + public static final int VALUE = 12; + + private SectionId() {} +} diff --git a/types/src/main/java/run/endive/cm/types/WasmComponent.java b/types/src/main/java/run/endive/cm/types/WasmComponent.java new file mode 100644 index 0000000..e05305c --- /dev/null +++ b/types/src/main/java/run/endive/cm/types/WasmComponent.java @@ -0,0 +1,18 @@ +package run.endive.cm.types; + +public final class WasmComponent { + + private WasmComponent() {} + + public static WasmComponent.Builder builder() { + return new WasmComponent.Builder(); + } + + public static final class Builder { + private Builder() {} + + public WasmComponent build() { + return new WasmComponent(); + } + } +} From 51e14f604b83af8d022163e7099e6d630a7b9b4c Mon Sep 17 00:00:00 2001 From: Jeremy Grelle Date: Tue, 16 Jun 2026 06:51:40 -0400 Subject: [PATCH 2/8] Move validation to parser --- .../main/java/run/endive/cm/parser/ComponentParser.java | 8 ++++++++ parser/src/main/java/run/endive/cm/tools/WastTests.java | 2 -- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/parser/src/main/java/run/endive/cm/parser/ComponentParser.java b/parser/src/main/java/run/endive/cm/parser/ComponentParser.java index 7d3b90e..a028b66 100644 --- a/parser/src/main/java/run/endive/cm/parser/ComponentParser.java +++ b/parser/src/main/java/run/endive/cm/parser/ComponentParser.java @@ -7,6 +7,7 @@ import java.util.Arrays; import java.util.function.Supplier; +import run.endive.cm.tools.ComponentValidate; import run.endive.cm.types.SectionId; import run.endive.cm.types.WasmComponent; import run.endive.wasm.MalformedException; @@ -56,6 +57,13 @@ public WasmComponent parse(Supplier inputStreamSupplier) { private void parse(InputStream in, ComponentParserListener listener) { requireNonNull(listener, "listener"); + ComponentValidate.validate(in); + try { + in.reset(); + } catch (IOException e) { + throw new RuntimeException(e); + } + var buffer = readByteBuffer(in); byte[] magic = new byte[4]; diff --git a/parser/src/main/java/run/endive/cm/tools/WastTests.java b/parser/src/main/java/run/endive/cm/tools/WastTests.java index accaed1..c8a82be 100644 --- a/parser/src/main/java/run/endive/cm/tools/WastTests.java +++ b/parser/src/main/java/run/endive/cm/tools/WastTests.java @@ -83,8 +83,6 @@ default WasmComponent parseComponent(Path location, String filename) var filePath = location.resolve(filename); try (var in = new ByteArrayInputStream(Files.readAllBytes(filePath))) { try { - ComponentValidate.validate(in); - in.reset(); var parser = ComponentParser.builder().build(); return parser.parse(() -> in); } catch (UnsupportedOperationException e) { From 5732d34d4ba98e36058629853847f439fe9bc015 Mon Sep 17 00:00:00 2001 From: Jeremy Grelle Date: Fri, 19 Jun 2026 08:32:51 -0400 Subject: [PATCH 3/8] Initial core type section parsing --- parser/pom.xml | 15 +- .../run/endive/cm/parser/ComponentParser.java | 228 +++++++++++++----- .../java/run/endive/cm/parser/CoreParser.java | 166 +++++++++++++ .../endive/cm/tools/ComponentValidate.java | 6 +- .../cm/parser/ComponentParserTests.java | 71 ++++++ .../run/endive/cm/parser}/JsonFromWast.java | 27 +-- .../cm/parser}/JsonFromWastException.java | 2 +- .../java/run/endive/cm/parser/SpecTests.java | 32 --- .../java/run/endive/cm/parser}/WastTests.java | 95 +++++--- .../src/test/resources/spec-tests/failed.wasm | Bin 0 -> 45 bytes .../java/run/endive/cm/types/CoreAlias.java | 50 ++++ .../run/endive/cm/types/CoreExportDecl.java | 3 + .../run/endive/cm/types/CoreImportDecl.java | 3 + .../endive/cm/types/CoreOuterAliasTarget.java | 46 ++++ .../java/run/endive/cm/types/CoreSort.java | 31 +++ .../java/run/endive/cm/types/CoreType.java | 105 ++++++++ .../run/endive/cm/types/CoreTypeSection.java | 62 +++++ .../run/endive/cm/types/CustomSection.java | 36 +++ .../java/run/endive/cm/types/ModuleDecl.java | 108 +++++++++ .../java/run/endive/cm/types/ModuleType.java | 54 +++++ .../run/endive/cm/types/WasmComponent.java | 58 ++++- 21 files changed, 1048 insertions(+), 150 deletions(-) create mode 100644 parser/src/main/java/run/endive/cm/parser/CoreParser.java create mode 100644 parser/src/test/java/run/endive/cm/parser/ComponentParserTests.java rename parser/src/{main/java/run/endive/cm/tools => test/java/run/endive/cm/parser}/JsonFromWast.java (88%) rename parser/src/{main/java/run/endive/cm/tools => test/java/run/endive/cm/parser}/JsonFromWastException.java (90%) delete mode 100644 parser/src/test/java/run/endive/cm/parser/SpecTests.java rename parser/src/{main/java/run/endive/cm/tools => test/java/run/endive/cm/parser}/WastTests.java (72%) create mode 100644 parser/src/test/resources/spec-tests/failed.wasm create mode 100644 types/src/main/java/run/endive/cm/types/CoreAlias.java create mode 100644 types/src/main/java/run/endive/cm/types/CoreExportDecl.java create mode 100644 types/src/main/java/run/endive/cm/types/CoreImportDecl.java create mode 100644 types/src/main/java/run/endive/cm/types/CoreOuterAliasTarget.java create mode 100644 types/src/main/java/run/endive/cm/types/CoreSort.java create mode 100644 types/src/main/java/run/endive/cm/types/CoreType.java create mode 100644 types/src/main/java/run/endive/cm/types/CoreTypeSection.java create mode 100644 types/src/main/java/run/endive/cm/types/CustomSection.java create mode 100644 types/src/main/java/run/endive/cm/types/ModuleDecl.java create mode 100644 types/src/main/java/run/endive/cm/types/ModuleType.java diff --git a/parser/pom.xml b/parser/pom.xml index a73c423..3941a7e 100644 --- a/parser/pom.xml +++ b/parser/pom.xml @@ -41,10 +41,6 @@ run.endive.cm types - - com.fasterxml.jackson.core - jackson-databind - org.junit.jupiter junit-jupiter-api @@ -55,6 +51,17 @@ junit-jupiter-params test + + com.fasterxml.jackson.core + jackson-databind + test + + + org.assertj + assertj-core + 3.27.7 + test + diff --git a/parser/src/main/java/run/endive/cm/parser/ComponentParser.java b/parser/src/main/java/run/endive/cm/parser/ComponentParser.java index a028b66..7f66bbc 100644 --- a/parser/src/main/java/run/endive/cm/parser/ComponentParser.java +++ b/parser/src/main/java/run/endive/cm/parser/ComponentParser.java @@ -1,21 +1,22 @@ package run.endive.cm.parser; +import static java.util.Objects.requireNonNull; +import static run.endive.cm.parser.CoreParser.parseCustomSection; +import static run.endive.cm.parser.CoreParser.parseRecType; +import static run.endive.wasm.Encoding.*; + import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; +import java.util.Objects; import java.util.function.Supplier; import run.endive.cm.tools.ComponentValidate; -import run.endive.cm.types.SectionId; -import run.endive.cm.types.WasmComponent; +import run.endive.cm.types.*; import run.endive.wasm.MalformedException; import run.endive.wasm.io.InputStreams; -import run.endive.cm.types.Section; - -import static java.util.Objects.requireNonNull; -import static run.endive.wasm.Encoding.readVarUInt32; public final class ComponentParser { @@ -48,6 +49,23 @@ public ComponentParser build() { } } + private static void onSection(WasmComponent.Builder module, Section s) { + switch(s.sectionId()) + { + case SectionId.CUSTOM: + var coreCustomSection = (CustomSection) s; + module.addCoreCustomSection(coreCustomSection); + break; + case SectionId.CORE_TYPE: + var coreTypeSection = (CoreTypeSection) s; + module.addCoreTypeSection(coreTypeSection); + break; + default: + throw new MalformedException( + "unsupported section id " + s.sectionId()); + } + } + public WasmComponent parse(Supplier inputStreamSupplier) { WasmComponent.Builder componentBuilder = WasmComponent.builder(); parse(inputStreamSupplier.get(), s -> onSection(componentBuilder, s)); @@ -115,88 +133,184 @@ private void parse(InputStream in, ComponentParserListener listener) { // Process different section types based on the sectionId switch (sectionId) { case SectionId.CUSTOM: - { - throw new UnsupportedOperationException("Custom section is not supported yet"); - } + { + var customSection = parseCustomSection(sectionByteBuffer, sectionSize, true); + var coreCustomSection = CustomSection.builder().withCustomSection(customSection).build(); + listener.onSection(coreCustomSection); + break; + } case SectionId.CORE_MODULE: - { - throw new UnsupportedOperationException("Core module section is not supported yet"); - } + { + throw new UnsupportedOperationException( + "Core module section is not supported yet"); + } case SectionId.CORE_INSTANCE: - { - throw new UnsupportedOperationException("Core instance section is not supported yet"); - } + { + throw new UnsupportedOperationException( + "Core instance section is not supported yet"); + } case SectionId.CORE_TYPE: - { - throw new UnsupportedOperationException("Core type section is not supported yet"); - } + { + var coreTypeSection = parseCoreTypeSection(sectionByteBuffer); + listener.onSection(coreTypeSection); + break; + } case SectionId.COMPONENT: - { - throw new UnsupportedOperationException("Component section is not supported yet"); - } + { + throw new UnsupportedOperationException( + "Component section is not supported yet"); + } case SectionId.INSTANCE: - { - throw new UnsupportedOperationException("Instance section is not supported yet"); - } + { + throw new UnsupportedOperationException( + "Instance section is not supported yet"); + } case SectionId.ALIAS: - { - throw new UnsupportedOperationException("Alias section is not supported yet"); - } + { + throw new UnsupportedOperationException( + "Alias section is not supported yet"); + } case SectionId.TYPE: - { - throw new UnsupportedOperationException("Type section is not supported yet"); - } + { + throw new UnsupportedOperationException( + "Type section is not supported yet"); + } case SectionId.CANON: - { - throw new UnsupportedOperationException("Canon section is not supported yet"); - } + { + throw new UnsupportedOperationException( + "Canon section is not supported yet"); + } case SectionId.START: - { - throw new UnsupportedOperationException("Start section is not supported yet"); - } + { + throw new UnsupportedOperationException( + "Start section is not supported yet"); + } case SectionId.IMPORT: - { - throw new UnsupportedOperationException("Import section is not supported yet"); - } + { + throw new UnsupportedOperationException( + "Import section is not supported yet"); + } case SectionId.EXPORT: - { - throw new UnsupportedOperationException("Export section is not supported yet"); - } + { + throw new UnsupportedOperationException( + "Export section is not supported yet"); + } case SectionId.VALUE: - { - throw new UnsupportedOperationException("Value section is not supported yet"); - } + { + throw new UnsupportedOperationException( + "Value section is not supported yet"); + } default: - { - throw new MalformedException( - "section size mismatch, malformed section id " + sectionId); - } + { + throw new MalformedException( + "section size mismatch, malformed section id " + sectionId); + } } -// if (sectionByteBuffer.hasRemaining()) { -// throw new MalformedException("section size mismatch"); -// } + if (sectionByteBuffer.hasRemaining()) { + throw new MalformedException("section size mismatch"); + } } } - private static void onSection(WasmComponent.Builder module, Section s) { + private static CoreTypeSection parseCoreTypeSection(ByteBuffer buffer) { + var builder = CoreTypeSection.builder(); + var numCoreTypes = readVarUInt32(buffer); + for (int i = 0; i < numCoreTypes && buffer.hasRemaining(); i++) { + builder.addCoreType(parseCoreType(buffer)); + } + return builder.build(); + } + private static CoreType parseCoreType(ByteBuffer buffer) { + var typeBuilder = CoreType.builder(); + var opcode = peekByte(buffer); + switch(opcode) { + case 0x50: + buffer.position(buffer.position() + 1); + typeBuilder.withModuleType(parseModuleType(buffer)); + break; + case 0x00: + buffer.position(buffer.position() + 1); + default: + typeBuilder.withRecType(parseRecType(buffer)); + } + return typeBuilder.build(); } - static int readInt(ByteBuffer buffer) { - if (buffer.remaining() < 4) { - throw new MalformedException("length out of bounds"); + private static ModuleType parseModuleType(ByteBuffer buffer) { + var builder = ModuleType.builder(); + var numDecls = readVarUInt32(buffer); + for (int i = 0; i < numDecls && buffer.hasRemaining(); i++) { + builder.addModuleDecl(parseModuleDecl(buffer)); } - return buffer.getInt(); + return builder.build(); + } + + private static ModuleDecl parseModuleDecl(ByteBuffer buffer) { + var builder = ModuleDecl.builder(); + var opcode = readByte(buffer); + switch (opcode) { + case 0x00: + builder.withImportDecl(parseCoreImportDecl(buffer)); + break; + case 0x01: + builder.withType(parseCoreType(buffer)); + break; + case 0x02: + builder.withAlias(parseCoreAlias(buffer)); + break; + case 0x03: + builder.withExportDecl(parseCoreExportDecl(buffer)); + break; + default: + throw new MalformedException("unknown opcode" + opcode + " in module decl"); + } + return builder.build(); + } + + private static CoreImportDecl parseCoreImportDecl(ByteBuffer buffer) { + throw new UnsupportedOperationException("import decl parsing not implemented"); + } + + private static CoreAlias parseCoreAlias(ByteBuffer buffer) { + var builder = CoreAlias.builder(); + var sortId = readByte(buffer); + var sort = CoreSort.fromId(sortId); + var targetOpcode = readByte(buffer); + if (targetOpcode != 0x01) { + throw new MalformedException("unknown target opcode " + targetOpcode + " in alias"); + } + var typeIndex = readVarUInt32(buffer); + var sortIndex = readVarUInt32(buffer); + builder.withSort(sort); + builder.withOuterTarget(CoreOuterAliasTarget.builder() + .withTypeIndex(typeIndex) + .withSortIndex(sortIndex) + .build()); + return builder.build(); + } + + private static CoreExportDecl parseCoreExportDecl(ByteBuffer buffer) { + throw new UnsupportedOperationException("export decl parsing not implemented"); } static byte readByte(ByteBuffer buffer) { if (!buffer.hasRemaining()) { throw new MalformedException("length out of bounds"); } + return buffer.get(); } + static byte peekByte(ByteBuffer buffer) { + if (!buffer.hasRemaining()) { + throw new MalformedException("length out of bounds"); + } + + return buffer.get(buffer.position()); + } + static void readBytes(ByteBuffer buffer, byte[] dest) { if (buffer.remaining() < dest.length) { throw new MalformedException("length out of bounds"); diff --git a/parser/src/main/java/run/endive/cm/parser/CoreParser.java b/parser/src/main/java/run/endive/cm/parser/CoreParser.java new file mode 100644 index 0000000..127dece --- /dev/null +++ b/parser/src/main/java/run/endive/cm/parser/CoreParser.java @@ -0,0 +1,166 @@ +package run.endive.cm.parser; + +import run.endive.wasm.MalformedException; +import run.endive.wasm.types.*; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import static run.endive.cm.parser.ComponentParser.readByte; +import static run.endive.cm.parser.ComponentParser.readBytes; +import static run.endive.wasm.Encoding.readName; +import static run.endive.wasm.Encoding.readVarSInt32; +import static run.endive.wasm.Encoding.readVarUInt32; + +public final class CoreParser { + + private CoreParser() {} + + + static CustomSection parseCustomSection( + ByteBuffer buffer, long sectionSize, boolean checkMalformed) { + var sectionPos = buffer.position(); + var name = readName(buffer, checkMalformed); + var size = (sectionSize - (buffer.position() - sectionPos)); + if (size < 0) { + throw new MalformedException("unexpected end"); + } + var bytes = new byte[(int) size]; + readBytes(buffer, bytes); + return UnknownCustomSection.builder().withName(name).withBytes(bytes).build(); + } + + static FieldType parseFieldType(ByteBuffer buffer) { + var id = (int) readVarUInt32(buffer); + + if (id == PackedType.I8.ID() || id == PackedType.I16.ID()) { + var packedType = PackedType.fromId(id); + var mut = MutabilityType.forId(readByte(buffer)); + return FieldType.builder() + .withStorageType(StorageType.builder().withPackedType(packedType).build()) + .withMutability(mut) + .build(); + } else { + var valType = readValueTypeBuilderFromOpCode(buffer, id).build(); + var mut = MutabilityType.forId(readByte(buffer)); + + return FieldType.builder() + .withStorageType(StorageType.builder().withValType(valType).build()) + .withMutability(mut) + .build(); + } + } + + static ArrayType parseArrayType(ByteBuffer buffer) { + return ArrayType.builder().withFieldType(parseFieldType(buffer)).build(); + } + + static StructType parseStructType(ByteBuffer buffer) { + var count = (int) readVarUInt32(buffer); + var builder = StructType.builder(); + for (int i = 0; i < count; i++) { + builder.addFieldType(parseFieldType(buffer)); + } + return builder.build(); + } + + static FunctionType parseFunctionType(ByteBuffer buffer) { + var paramCount = (int) readVarUInt32(buffer); + List paramsBuilder = new ArrayList<>(paramCount); + + // Parse parameter types + for (int j = 0; j < paramCount; j++) { + paramsBuilder.add(readValueTypeBuilder(buffer).build()); + } + + var returnCount = (int) readVarUInt32(buffer); + List returnsBuilder = new ArrayList<>(returnCount); + + // Parse return types + for (int j = 0; j < returnCount; j++) { + returnsBuilder.add(readValueTypeBuilder(buffer).build()); + } + + return FunctionType.of(paramsBuilder, returnsBuilder); + } + + static CompType parseCompType(int id, ByteBuffer buffer) { + if (id > Byte.MAX_VALUE) { + throw new MalformedException("integer representation too long"); + } + + switch (id) { + case 0x5E: + return CompType.builder().withArrayType(parseArrayType(buffer)).build(); + case 0x5F: + return CompType.builder().withStructType(parseStructType(buffer)).build(); + case 0x60: + return CompType.builder().withFuncType(parseFunctionType(buffer)).build(); + default: + throw new MalformedException( + "Invalid composite type. Form " + + String.format("0x%02X", id) + + " was not 0x5E, 0x5f or 0x60"); + } + } + + static SubType parseSubType(int id, ByteBuffer buffer) { + if (id == 0x50 // non final typeIdx + || id == 0x4F // final typeIdx + ) { + var count = (int) readVarUInt32(buffer); + var typeIdxs = new int[count]; + + for (int i = 0; i < count; i++) { + typeIdxs[i] = (int) readVarUInt32(buffer); + } + return SubType.builder() + .withTypeIdx(typeIdxs) + .withFinal(id == 0x4F) + .withCompType(parseCompType((int) readVarUInt32(buffer), buffer)) + .build(); + } else { + // fallback to the compressed form + return SubType.builder() + .withTypeIdx(new int[0]) + .withFinal(true) + .withCompType(parseCompType(id, buffer)) + .build(); + } + } + + static RecType parseRecType(ByteBuffer buffer) { + var discriminator = (int) readVarUInt32(buffer); + if (discriminator == 0x4E) { + var count = (int) readVarUInt32(buffer); + var subTypes = new SubType[count]; + + for (int i = 0; i < count; i++) { + subTypes[i] = parseSubType((int) readVarUInt32(buffer), buffer); + } + return RecType.builder().withSubTypes(subTypes).build(); + } else { + // fallback to the compressed form + return RecType.builder() + .withSubTypes(new SubType[] {parseSubType(discriminator, buffer)}) + .build(); + } + } + + static ValType.Builder readValueTypeBuilderFromOpCode( + ByteBuffer buffer, int valueTypeOpCode) { + var builder = ValType.builder().withOpcode(valueTypeOpCode); + if (valueTypeOpCode == ValType.ID.Ref || valueTypeOpCode == ValType.ID.RefNull) { + return builder.withTypeIdx((int) readVarSInt32(buffer)); + } else { + return builder; + } + } + + static ValType.Builder readValueTypeBuilder(ByteBuffer buffer) { + var valueTypeOpCode = (int) readVarUInt32(buffer); + + return readValueTypeBuilderFromOpCode(buffer, valueTypeOpCode); + } +} diff --git a/parser/src/main/java/run/endive/cm/tools/ComponentValidate.java b/parser/src/main/java/run/endive/cm/tools/ComponentValidate.java index 71f4a55..c24858a 100644 --- a/parser/src/main/java/run/endive/cm/tools/ComponentValidate.java +++ b/parser/src/main/java/run/endive/cm/tools/ComponentValidate.java @@ -58,11 +58,7 @@ public static void validate(InputStream is) { .withStdout(stdoutStream, false) .withStderr(stderrStream, false) .withDirectory(inputDir.toString(), inputDir) - .withArguments( - List.of( - "wasm-tools", - "validate", - inputFile.toString())) + .withArguments(List.of("wasm-tools", "validate", inputFile.toString())) .build(); try (var wasi = diff --git a/parser/src/test/java/run/endive/cm/parser/ComponentParserTests.java b/parser/src/test/java/run/endive/cm/parser/ComponentParserTests.java new file mode 100644 index 0000000..36d6e1f --- /dev/null +++ b/parser/src/test/java/run/endive/cm/parser/ComponentParserTests.java @@ -0,0 +1,71 @@ +package run.endive.cm.parser; + +import static org.junit.jupiter.api.Assertions.fail; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Map; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import run.endive.cm.types.*; +import run.endive.wasm.types.CompType; +import run.endive.wasm.types.FunctionType; +import run.endive.wasm.types.RecType; +import run.endive.wasm.types.SubType; + +public class ComponentParserTests { + + static java.util.stream.Stream testLocations() { + + return java.util.stream.Stream.of( + // Arguments.arguments("./wasmtime/types.wast", new int[] {145}), + Arguments.arguments("./wasm-tools/types.wast", WasmToolsTypesAssertions.expectedComponents, new int[0])); + } + + @ParameterizedTest + @MethodSource("testLocations") + void allSpecTests(String testLocation, Map expectedComponents, int[] skipLines) throws IOException { + var testDir = Path.of("src/test/resources/spec-tests"); + var testFile = testDir.resolve(testLocation); + try (var wast = Files.newInputStream(testFile); + var wastTests = JsonFromWast.exec(wast)) { + wastTests.runTests(expectedComponents, skipLines); + } catch (Exception e) { + if (e instanceof WastTests.CommandException) { + var ce = (WastTests.CommandException) e; + var outFile = testDir.resolve("./failed.wasm"); + Files.write(outFile, ce.testContents()); + } + fail(e); + } + } + + private static final class WasmToolsTypesAssertions { + + private final static Map expectedComponents = Map.of(17, case17()); + + private static WasmComponent case17() { + var funcType = FunctionType.of(new ArrayList<>(), new ArrayList<>()); + var compType = CompType.builder().withFuncType(funcType).build(); + var subType = SubType.builder().withTypeIdx(new int[] {}).withFinal(true).withCompType(compType).build(); + var recType = RecType.builder().withSubTypes(new SubType[] {subType}).build(); + var coreFuncType = CoreType.builder().withRecType(recType).build(); + + var alias = CoreAlias.builder().withSort(CoreSort.TYPE). + withOuterTarget(CoreOuterAliasTarget.builder() + .withTypeIndex(1) + .withSortIndex(0) + .build()).build(); + var moduleDecl = ModuleDecl.builder().withAlias(alias).build(); + var moduleType = ModuleType.builder().addModuleDecl(moduleDecl).build(); + var coreModuleType = CoreType.builder().withModuleType(moduleType).build(); + + var coreTypeSection = CoreTypeSection.builder().addCoreType(coreFuncType).addCoreType(coreModuleType).build(); + return WasmComponent.builder().addCoreTypeSection(coreTypeSection).build(); + } + } +} diff --git a/parser/src/main/java/run/endive/cm/tools/JsonFromWast.java b/parser/src/test/java/run/endive/cm/parser/JsonFromWast.java similarity index 88% rename from parser/src/main/java/run/endive/cm/tools/JsonFromWast.java rename to parser/src/test/java/run/endive/cm/parser/JsonFromWast.java index b97429e..4c49ac2 100644 --- a/parser/src/main/java/run/endive/cm/tools/JsonFromWast.java +++ b/parser/src/test/java/run/endive/cm/parser/JsonFromWast.java @@ -1,7 +1,15 @@ -package run.endive.cm.tools; +package run.endive.cm.parser; import io.roastedroot.zerofs.Configuration; import io.roastedroot.zerofs.ZeroFs; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import run.endive.cm.tools.ComponentValidateException; import run.endive.log.Logger; import run.endive.log.SystemLogger; import run.endive.runtime.ByteArrayMemory; @@ -13,13 +21,6 @@ import run.endive.wasi.WasiPreview1; import run.endive.wasm.WasmModule; -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystem; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - public final class JsonFromWast { private JsonFromWast() {} @@ -36,14 +37,12 @@ public boolean isLoggable(Logger.Level level) { public static WastTests exec(InputStream is) { try (var stdinStream = new ByteArrayInputStream(new byte[0]); - var stdoutStream = new ByteArrayOutputStream(); - var stderrStream = new ByteArrayOutputStream()) { + var stdoutStream = new ByteArrayOutputStream(); + var stderrStream = new ByteArrayOutputStream()) { FileSystem fs = ZeroFs.newFileSystem( - Configuration.unix().toBuilder() - .setAttributeViews("unix") - .build()); + Configuration.unix().toBuilder().setAttributeViews("unix").build()); Path wastDir = fs.getPath("wast"); Files.createDirectory(wastDir); @@ -67,7 +66,7 @@ public static WastTests exec(InputStream is) { .build(); try (var wasi = - WasiPreview1.builder().withLogger(logger).withOptions(options).build()) { + WasiPreview1.builder().withLogger(logger).withOptions(options).build()) { var imports = ImportValues.builder().addFunction(wasi.toHostFunctions()).build(); try { Instance.builder(MODULE) diff --git a/parser/src/main/java/run/endive/cm/tools/JsonFromWastException.java b/parser/src/test/java/run/endive/cm/parser/JsonFromWastException.java similarity index 90% rename from parser/src/main/java/run/endive/cm/tools/JsonFromWastException.java rename to parser/src/test/java/run/endive/cm/parser/JsonFromWastException.java index f686be9..2ef04ac 100644 --- a/parser/src/main/java/run/endive/cm/tools/JsonFromWastException.java +++ b/parser/src/test/java/run/endive/cm/parser/JsonFromWastException.java @@ -1,4 +1,4 @@ -package run.endive.cm.tools; +package run.endive.cm.parser; public class JsonFromWastException extends RuntimeException { diff --git a/parser/src/test/java/run/endive/cm/parser/SpecTests.java b/parser/src/test/java/run/endive/cm/parser/SpecTests.java deleted file mode 100644 index 1fc7d09..0000000 --- a/parser/src/test/java/run/endive/cm/parser/SpecTests.java +++ /dev/null @@ -1,32 +0,0 @@ - package run.endive.cm.parser; - - import java.nio.file.Files; - import java.nio.file.Path; - - import org.junit.jupiter.params.ParameterizedTest; - import org.junit.jupiter.params.provider.Arguments; - import org.junit.jupiter.params.provider.MethodSource; - import run.endive.cm.tools.JsonFromWast; - - import static org.junit.jupiter.api.Assertions.fail; - - public class SpecTests { - - static java.util.stream.Stream testLocations() { - return java.util.stream.Stream.of( - //Arguments.arguments("./wasmtime/types.wast", new int[] {145}), - Arguments.arguments("./wasm-tools/types.wast", new int[0])); - } - - @ParameterizedTest - @MethodSource("testLocations") - void allSpecTests(String testLocation, int[] skipLines) { - var testDir = Path.of("src/test/resources/spec-tests"); - var testFile = testDir.resolve(testLocation); - try (var wast = Files.newInputStream(testFile); var wastTests = JsonFromWast.exec(wast)){ - wastTests.runTests(skipLines); - } catch (Exception e) { - fail(e); - } - } - } diff --git a/parser/src/main/java/run/endive/cm/tools/WastTests.java b/parser/src/test/java/run/endive/cm/parser/WastTests.java similarity index 72% rename from parser/src/main/java/run/endive/cm/tools/WastTests.java rename to parser/src/test/java/run/endive/cm/parser/WastTests.java index c8a82be..f5a31d0 100644 --- a/parser/src/main/java/run/endive/cm/tools/WastTests.java +++ b/parser/src/test/java/run/endive/cm/parser/WastTests.java @@ -1,13 +1,10 @@ -package run.endive.cm.tools; +package run.endive.cm.parser; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import run.endive.cm.parser.ComponentParser; -import run.endive.cm.types.WasmComponent; - import java.io.ByteArrayInputStream; import java.io.IOException; import java.math.BigInteger; @@ -15,8 +12,14 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.Map; import java.util.stream.IntStream; +import run.endive.cm.tools.ComponentValidateException; +import run.endive.cm.types.WasmComponent; + +import static org.assertj.core.api.Assertions.assertThat; + public final class WastTests implements AutoCloseable { private final WastTestFile wastTestFile; @@ -26,18 +29,17 @@ public final class WastTests implements AutoCloseable { public WastTests(String wastJson, FileSystem wastFS) { var objectMapper = new ObjectMapper(); try { - this.wastTestFile = - objectMapper.readValue(wastJson, WastTestFile.class); + this.wastTestFile = objectMapper.readValue(wastJson, WastTestFile.class); this.wastFS = wastFS; } catch (JsonProcessingException e) { throw new JsonFromWastException("failed to deserialize wast json", e); } } - public void runTests(int[] skipLines) { + public void runTests(Map expectedComponents, int[] skipLines) { var workingDir = wastFS.getPath("/work"); for (var command : wastTestFile.commands()) { - command.execute(workingDir, skipLines); + command.execute(workingDir, expectedComponents, skipLines); } } @@ -66,17 +68,15 @@ List commands() { } } - @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = - "type") + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSubTypes({ - @JsonSubTypes.Type(value = Module.class, name = "module"), - @JsonSubTypes.Type(value = AssertMalformed.class, name = "assert_malformed"), - @JsonSubTypes.Type(value = AssertInvalid.class, name = "assert_invalid"), + @JsonSubTypes.Type(value = Module.class, name = "module"), + @JsonSubTypes.Type(value = AssertMalformed.class, name = "assert_malformed"), + @JsonSubTypes.Type(value = AssertInvalid.class, name = "assert_invalid"), }) interface Command { - void execute(Path location, int... skipLines) - throws CommandException; + void execute(Path location, Map expectedComponents, int... skipLines) throws CommandException; default WasmComponent parseComponent(Path location, String filename) throws CommandException { @@ -86,25 +86,43 @@ default WasmComponent parseComponent(Path location, String filename) var parser = ComponentParser.builder().build(); return parser.parse(() -> in); } catch (UnsupportedOperationException e) { - throw new CommandException(e); + throw new CommandException(filePath, e); } } catch (IOException e) { - throw new CommandException(e); + throw new CommandException(filePath, e); } } } public static class CommandException extends RuntimeException { - public CommandException(Throwable cause) { + + private final byte[] testContents; + + public CommandException(Path filePath, Throwable cause) { super(cause); + this.testContents = readFileContents(filePath); } - public CommandException(String message) { + public CommandException(Path filePath, String message) { super(message); + this.testContents = readFileContents(filePath); } - public CommandException(String message, Throwable cause) { + public CommandException(Path filePath, String message, Throwable cause) { super(message, cause); + this.testContents = readFileContents(filePath); + } + + private byte[] readFileContents(Path location) { + try { + return Files.readAllBytes(location); + } catch (IOException e) { + throw new IllegalStateException("Failed to read test contents from " + location, e); + } + } + + public byte[] testContents() { + return testContents; } } @@ -142,8 +160,7 @@ String text() { } @Override - public void execute(Path location, int... skipLines) - throws CommandException { + public void execute(Path location, Map expectedComponents, int... skipLines) throws CommandException { if (skipLines.length > 0) { if (IntStream.of(skipLines).anyMatch(i -> i == line)) { return; @@ -153,15 +170,16 @@ public void execute(Path location, int... skipLines) parseComponent(location, filename); } catch (Exception e) { if (!(e instanceof ComponentValidateException)) { - throw new CommandException( + throw new CommandException(location.resolve(filename), String.format( - "Expected validation of %s to fail at line %d due to '%s' but got unexpected exception of type %s", + "Expected validation of %s to fail at line %d due to '%s' but" + + " got unexpected exception of type %s", filename, line, text, e.getClass().getSimpleName()), e); } return; } - throw new CommandException( + throw new CommandException(location.resolve(filename), String.format( "\"Expected validation of %s to fail at line %d due to '%s' ", filename, line, text)); @@ -202,8 +220,7 @@ String text() { } @Override - public void execute(Path location, int... skipLines) - throws CommandException { + public void execute(Path location, Map expectedComponents, int... skipLines) throws CommandException { if (skipLines.length > 0) { if (IntStream.of(skipLines).anyMatch(i -> i == line)) { return; @@ -213,15 +230,16 @@ public void execute(Path location, int... skipLines) parseComponent(location, filename); } catch (Exception e) { if (!(e instanceof ComponentValidateException)) { - throw new CommandException( + throw new CommandException(location.resolve(filename), String.format( - "Expected validation of %s to fail at line %d due to '%s' but got unexpected exception of type %s", + "Expected validation of %s to fail at line %d due to '%s' but" + + " got unexpected exception of type %s", filename, line, text, e.getClass().getSimpleName()), e); } return; } - throw new CommandException( + throw new CommandException(location.resolve(filename), String.format( "\"Expected validation of %s to fail at line %d due to '%s' ", filename, line, text)); @@ -335,18 +353,25 @@ String moduleType() { } @Override - public void execute(Path location, int... skipLines) - throws CommandException { + public void execute(Path location, Map expectedComponents, int... skipLines) throws CommandException { if (skipLines.length > 0) { if (IntStream.of(skipLines).anyMatch(i -> i == line)) { return; } } try { - parseComponent(location, filename); + WasmComponent actualComponent = parseComponent(location, filename); + var testId = Integer.parseInt(filename.split("\\.")[1]); + if (expectedComponents.containsKey(testId)) { + WasmComponent expectedComponent = expectedComponents.get(testId); + assertThat(actualComponent).usingRecursiveComparison() + .ignoringFields("customSections") + .isEqualTo(expectedComponent); + } } catch (Exception e) { - throw new CommandException( - String.format("Failed to load module %s due to error at line %d", filename, line), + throw new CommandException(location.resolve(filename), + String.format( + "Failed to load module %s due to error at line %d", filename, line), e); } } diff --git a/parser/src/test/resources/spec-tests/failed.wasm b/parser/src/test/resources/spec-tests/failed.wasm new file mode 100644 index 0000000000000000000000000000000000000000..e96e6020ccfbbe58add30bddc23572ce478c78a3 GIT binary patch literal 45 ycmZQbEY9U+U}RwDW-h4BXJV*yU;y&O_>%K;3-a?)^GbB{5_3}-S(zD`7)t=td sort.id == id) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unknown ID: " + id)); + } +} diff --git a/types/src/main/java/run/endive/cm/types/CoreType.java b/types/src/main/java/run/endive/cm/types/CoreType.java new file mode 100644 index 0000000..3bdd1cf --- /dev/null +++ b/types/src/main/java/run/endive/cm/types/CoreType.java @@ -0,0 +1,105 @@ +package run.endive.cm.types; + +import run.endive.wasm.types.CompType; +import run.endive.wasm.types.RecType; +import run.endive.wasm.types.SubType; + +import java.util.Objects; + +public final class CoreType { + private final RecType recType; + private final SubType subType; + private final CompType compType; + private final ModuleType moduleType; + + private CoreType(RecType recType, SubType subType, CompType compType, ModuleType moduleType) { + requireExactlyOneNonNull(recType, subType, compType, moduleType); + this.recType = recType; + this.subType = subType; + this.compType = compType; + this.moduleType = moduleType; + } + + private static void requireExactlyOneNonNull(Object a, Object b, Object c, Object d) { + if ((a == null ? 0 : 1) + (b == null ? 0 : 1) + (c == null ? 0 : 1) + (d == null ? 0 : 1) + != 1) { + throw new IllegalArgumentException("Exactly one field must be filled"); + } + } + + public RecType recType() { + return recType; + } + + public SubType subType() { + return subType; + } + + public CompType compType() { + return compType; + } + + public ModuleType moduleType() { + return moduleType; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + + private RecType recType; + private SubType subType; + private CompType compType; + private ModuleType moduleType; + + private Builder() {} + + public Builder withRecType(RecType recType) { + this.recType = recType; + return this; + } + + public Builder withSubType(SubType subType) { + this.subType = subType; + return this; + } + + public Builder withCompType(CompType compType) { + this.compType = compType; + return this; + } + + public Builder withModuleType(ModuleType moduleType) { + this.moduleType = moduleType; + return this; + } + + public CoreType build() { + return new CoreType(recType, subType, compType, moduleType); + } + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof CoreType)) return false; + CoreType coreType = (CoreType) o; + return Objects.equals(recType, coreType.recType) && Objects.equals(subType, coreType.subType) && Objects.equals(compType, coreType.compType) && Objects.equals(moduleType, coreType.moduleType); + } + + @Override + public int hashCode() { + return Objects.hash(recType, subType, compType, moduleType); + } + + @Override + public String toString() { + return "CoreType{" + + "recType=" + recType + + ", subType=" + subType + + ", compType=" + compType + + ", moduleType=" + moduleType + + '}'; + } +} diff --git a/types/src/main/java/run/endive/cm/types/CoreTypeSection.java b/types/src/main/java/run/endive/cm/types/CoreTypeSection.java new file mode 100644 index 0000000..c5f7194 --- /dev/null +++ b/types/src/main/java/run/endive/cm/types/CoreTypeSection.java @@ -0,0 +1,62 @@ +package run.endive.cm.types; + +import static java.util.Objects.requireNonNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public final class CoreTypeSection extends Section { + private final List coreTypes; + + private CoreTypeSection(List coreTypes) { + super(SectionId.CORE_TYPE); + this.coreTypes = List.copyOf(coreTypes); + } + + public int numCoreTypes() { + return coreTypes.size(); + } + + public List coreTypes() { + return coreTypes; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private final List coreTypes = new ArrayList<>(); + + private Builder() {} + + public Builder addCoreType(CoreType coreType) { + coreTypes.add(requireNonNull(coreType, "coreType")); + return this; + } + + public CoreTypeSection build() { + return new CoreTypeSection(coreTypes); + } + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof CoreTypeSection)) return false; + CoreTypeSection that = (CoreTypeSection) o; + return Objects.equals(coreTypes, that.coreTypes); + } + + @Override + public int hashCode() { + return Objects.hashCode(coreTypes); + } + + @Override + public String toString() { + return "CoreTypeSection{" + + "coreTypes=" + coreTypes + + '}'; + } +} diff --git a/types/src/main/java/run/endive/cm/types/CustomSection.java b/types/src/main/java/run/endive/cm/types/CustomSection.java new file mode 100644 index 0000000..be7830b --- /dev/null +++ b/types/src/main/java/run/endive/cm/types/CustomSection.java @@ -0,0 +1,36 @@ +package run.endive.cm.types; + +import static java.util.Objects.requireNonNull; + +public final class CustomSection extends Section { + + private final run.endive.wasm.types.CustomSection customSection; + + private CustomSection(run.endive.wasm.types.CustomSection customSection) { + super(SectionId.CUSTOM); + this.customSection = customSection; + } + + public run.endive.wasm.types.CustomSection customSection() { + return customSection; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private run.endive.wasm.types.CustomSection customSection; + + private Builder() {} + + public CustomSection build() { + return new CustomSection(customSection); + } + + public Builder withCustomSection(run.endive.wasm.types.CustomSection customSection) { + this.customSection = requireNonNull(customSection, "customSection"); + return this; + } + } +} diff --git a/types/src/main/java/run/endive/cm/types/ModuleDecl.java b/types/src/main/java/run/endive/cm/types/ModuleDecl.java new file mode 100644 index 0000000..92b57b2 --- /dev/null +++ b/types/src/main/java/run/endive/cm/types/ModuleDecl.java @@ -0,0 +1,108 @@ +package run.endive.cm.types; + +import java.util.Objects; + +public final class ModuleDecl { + + private final CoreImportDecl importDecl; + + private final CoreAlias alias; + + private final CoreType type; + + private final CoreExportDecl exportDecl; + + private static void requireExactlyOneNonNull(Object a, Object b, Object c, Object d) { + if ((a == null ? 0 : 1) + (b == null ? 0 : 1) + (c == null ? 0 : 1) + (d == null ? 0 : 1) + != 1) { + throw new IllegalArgumentException("Exactly one field must be filled"); + } + } + + private ModuleDecl( + CoreImportDecl importDecl, CoreAlias alias, CoreType type, CoreExportDecl exportDecl) { + requireExactlyOneNonNull(importDecl, alias, type, exportDecl); + this.importDecl = importDecl; + this.alias = alias; + this.type = type; + this.exportDecl = exportDecl; + } + + public CoreImportDecl importDecl() { + return importDecl; + } + + public CoreAlias alias() { + return alias; + } + + public CoreType type() { + return type; + } + + public CoreExportDecl exportDecl() { + return exportDecl; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private CoreImportDecl importDecl; + + private CoreAlias alias; + + private CoreType type; + + private CoreExportDecl exportDecl; + + public Builder() {} + + public Builder withImportDecl(CoreImportDecl importDecl) { + this.importDecl = importDecl; + return this; + } + + public Builder withAlias(CoreAlias alias) { + this.alias = alias; + return this; + } + + public Builder withType(CoreType type) { + this.type = type; + return this; + } + + public Builder withExportDecl(CoreExportDecl exportDecl) { + this.exportDecl = exportDecl; + return this; + } + + public ModuleDecl build() { + return new ModuleDecl(importDecl, alias, type, exportDecl); + } + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof ModuleDecl)) return false; + ModuleDecl that = (ModuleDecl) o; + return Objects.equals(importDecl, that.importDecl) && Objects.equals(alias, that.alias) && Objects.equals(type, that.type) && Objects.equals(exportDecl, that.exportDecl); + } + + @Override + public int hashCode() { + return Objects.hash(importDecl, alias, type, exportDecl); + } + + @Override + public String toString() { + return "ModuleDecl{" + + "importDecl=" + importDecl + + ", alias=" + alias + + ", type=" + type + + ", exportDecl=" + exportDecl + + '}'; + } +} diff --git a/types/src/main/java/run/endive/cm/types/ModuleType.java b/types/src/main/java/run/endive/cm/types/ModuleType.java new file mode 100644 index 0000000..368e1ee --- /dev/null +++ b/types/src/main/java/run/endive/cm/types/ModuleType.java @@ -0,0 +1,54 @@ +package run.endive.cm.types; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public final class ModuleType { + + private final List moduleDecls; + + private ModuleType(List moduleDecls) { + this.moduleDecls = List.copyOf(moduleDecls); + } + + public List getModuleDecls() { + return moduleDecls; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private final List moduleDecls = new ArrayList<>(); + + public Builder addModuleDecl(ModuleDecl moduleDecl) { + moduleDecls.add(moduleDecl); + return this; + } + + public ModuleType build() { + return new ModuleType(moduleDecls); + } + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof ModuleType)) return false; + ModuleType that = (ModuleType) o; + return Objects.equals(moduleDecls, that.moduleDecls); + } + + @Override + public int hashCode() { + return Objects.hashCode(moduleDecls); + } + + @Override + public String toString() { + return "ModuleType{" + + "moduleDecls=" + moduleDecls + + '}'; + } +} diff --git a/types/src/main/java/run/endive/cm/types/WasmComponent.java b/types/src/main/java/run/endive/cm/types/WasmComponent.java index e05305c..b060f6f 100644 --- a/types/src/main/java/run/endive/cm/types/WasmComponent.java +++ b/types/src/main/java/run/endive/cm/types/WasmComponent.java @@ -1,18 +1,72 @@ package run.endive.cm.types; +import static java.util.Objects.requireNonNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + public final class WasmComponent { - private WasmComponent() {} + private final List customSections; + private final List coreTypeSections; + + private WasmComponent( + List customSections, List coreTypeSections) { + this.customSections = List.copyOf(customSections); + this.coreTypeSections = List.copyOf(coreTypeSections); + } public static WasmComponent.Builder builder() { return new WasmComponent.Builder(); } + public List coreCustomSections() { + return customSections; + } + + public List coreTypeSections() { + return coreTypeSections; + } + public static final class Builder { + + private final List customSections = new ArrayList<>(); + private final List coreTypeSections = new ArrayList<>(); + private Builder() {} + public Builder addCoreCustomSection(CustomSection customSection) { + customSections.add(requireNonNull(customSection, "coreCustomSection")); + return this; + } + + public Builder addCoreTypeSection(CoreTypeSection coreTypeSection) { + coreTypeSections.add(requireNonNull(coreTypeSection, "coreTypeSection")); + return this; + } + public WasmComponent build() { - return new WasmComponent(); + return new WasmComponent(customSections, coreTypeSections); } } + + @Override + public boolean equals(Object o) { + if (!(o instanceof WasmComponent)) return false; + WasmComponent that = (WasmComponent) o; + return Objects.equals(coreTypeSections, that.coreTypeSections); + } + + @Override + public int hashCode() { + return Objects.hashCode(coreTypeSections); + } + + @Override + public String toString() { + return "WasmComponent{" + + "coreTypeSections=" + coreTypeSections + + '}'; + } } From eb4d5994df40858115b0ab23a78bc132a98a8377 Mon Sep 17 00:00:00 2001 From: Jeremy Grelle Date: Fri, 19 Jun 2026 10:06:38 -0400 Subject: [PATCH 4/8] Remove spect-tests from repo and add to .gitignore --- .gitignore | 1 + .../spec-tests/async/async-calls-sync.wast | 251 --- .../spec-tests/async/cancel-stream.wast | 202 -- .../spec-tests/async/cancel-subtask.wast | 201 -- .../spec-tests/async/cancellable.wast | 325 --- .../spec-tests/async/closed-stream.wast | 102 - .../spec-tests/async/cross-abi-calls.wast | 519 ----- .../resources/spec-tests/async/deadlock.wast | 73 - .../spec-tests/async/dont-block-start.wast | 50 - .../async/drop-cross-task-borrow.wast | 309 --- .../spec-tests/async/drop-stream.wast | 160 -- .../spec-tests/async/drop-subtask.wast | 140 -- .../spec-tests/async/drop-waitable-set.wast | 84 - .../spec-tests/async/empty-wait.wast | 199 -- .../spec-tests/async/futures-must-write.wast | 118 - .../async/partial-stream-copies.wast | 238 -- .../spec-tests/async/passing-resources.wast | 176 -- .../async/same-component-stream-future.wast | 259 --- .../spec-tests/async/sync-barges-in.wast | 311 --- .../spec-tests/async/sync-streams.wast | 178 -- .../async/trap-if-block-and-sync.wast | 343 --- .../spec-tests/async/trap-if-done.wast | 468 ---- .../spec-tests/async/trap-on-reenter.wast | 110 - .../async/wait-during-callback.wast | 77 - .../spec-tests/async/zero-length.wast | 223 -- .../src/test/resources/spec-tests/failed.wasm | Bin 45 -> 0 bytes .../resources/spec-tests/names/kebab.wast | 60 - .../resources/multiple-resources.wast | 170 -- .../spec-tests/validation/implements.wast | 108 - .../resources/spec-tests/values/strings.wast | 136 -- .../values/trap-in-post-return.wast | 249 --- .../spec-tests/wasm-tools/adapt.wast | 287 --- .../spec-tests/wasm-tools/alias.wast | 301 --- .../resources/spec-tests/wasm-tools/big.wast | 36 - .../spec-tests/wasm-tools/definedtypes.wast | 123 -- .../spec-tests/wasm-tools/empty.wast | 4 - .../spec-tests/wasm-tools/example.wast | 17 - .../wasm-tools/export-ascription.wast | 44 - .../wasm-tools/export-introduces-alias.wast | 48 - .../spec-tests/wasm-tools/export.wast | 63 - .../resources/spec-tests/wasm-tools/func.wast | 146 -- .../spec-tests/wasm-tools/import.wast | 359 --- .../wasm-tools/imports-exports.wast | 26 - .../spec-tests/wasm-tools/inline-exports.wast | 9 - .../spec-tests/wasm-tools/instance-type.wast | 234 -- .../spec-tests/wasm-tools/instantiate.wast | 976 -------- .../spec-tests/wasm-tools/invalid.wast | 34 - .../resources/spec-tests/wasm-tools/link.wast | 14 - .../wasm-tools/lots-of-aliases.wast | 179 -- .../spec-tests/wasm-tools/lower.wast | 17 - .../spec-tests/wasm-tools/memory64.wast | 55 - .../spec-tests/wasm-tools/module-link.wast | 98 - .../spec-tests/wasm-tools/more-flags.wast | 41 - .../spec-tests/wasm-tools/naming.wast | 127 -- .../spec-tests/wasm-tools/nested-modules.wast | 50 - .../spec-tests/wasm-tools/resources.wast | 1195 ---------- .../resources/spec-tests/wasm-tools/tags.wast | 30 - .../wasm-tools/type-export-restrictions.wast | 504 ----- .../spec-tests/wasm-tools/types.wast | 374 ---- .../spec-tests/wasm-tools/very-nested.wast | 1954 ----------------- .../spec-tests/wasm-tools/virtualize.wast | 119 - .../spec-tests/wasm-tools/wrong-order.wast | 11 - .../spec-tests/wasmtime/adapter.wast | 137 -- .../spec-tests/wasmtime/aliasing.wast | 29 - .../resources/spec-tests/wasmtime/fused.wast | 1391 ------------ .../resources/spec-tests/wasmtime/import.wast | 20 - .../spec-tests/wasmtime/instance.wast | 327 --- .../spec-tests/wasmtime/linking.wast | 18 - .../spec-tests/wasmtime/modules.wast | 479 ---- .../resources/spec-tests/wasmtime/nested.wast | 451 ---- .../spec-tests/wasmtime/resources.wast | 1091 --------- .../spec-tests/wasmtime/restrictions.wast | 22 - .../resources/spec-tests/wasmtime/simple.wast | 42 - .../spec-tests/wasmtime/strings.wast | 110 - .../resources/spec-tests/wasmtime/tags.wast | 14 - .../resources/spec-tests/wasmtime/types.wast | 355 --- 76 files changed, 1 insertion(+), 17800 deletions(-) delete mode 100644 parser/src/test/resources/spec-tests/async/async-calls-sync.wast delete mode 100644 parser/src/test/resources/spec-tests/async/cancel-stream.wast delete mode 100644 parser/src/test/resources/spec-tests/async/cancel-subtask.wast delete mode 100644 parser/src/test/resources/spec-tests/async/cancellable.wast delete mode 100644 parser/src/test/resources/spec-tests/async/closed-stream.wast delete mode 100644 parser/src/test/resources/spec-tests/async/cross-abi-calls.wast delete mode 100644 parser/src/test/resources/spec-tests/async/deadlock.wast delete mode 100644 parser/src/test/resources/spec-tests/async/dont-block-start.wast delete mode 100644 parser/src/test/resources/spec-tests/async/drop-cross-task-borrow.wast delete mode 100644 parser/src/test/resources/spec-tests/async/drop-stream.wast delete mode 100644 parser/src/test/resources/spec-tests/async/drop-subtask.wast delete mode 100644 parser/src/test/resources/spec-tests/async/drop-waitable-set.wast delete mode 100644 parser/src/test/resources/spec-tests/async/empty-wait.wast delete mode 100644 parser/src/test/resources/spec-tests/async/futures-must-write.wast delete mode 100644 parser/src/test/resources/spec-tests/async/partial-stream-copies.wast delete mode 100644 parser/src/test/resources/spec-tests/async/passing-resources.wast delete mode 100644 parser/src/test/resources/spec-tests/async/same-component-stream-future.wast delete mode 100644 parser/src/test/resources/spec-tests/async/sync-barges-in.wast delete mode 100644 parser/src/test/resources/spec-tests/async/sync-streams.wast delete mode 100644 parser/src/test/resources/spec-tests/async/trap-if-block-and-sync.wast delete mode 100644 parser/src/test/resources/spec-tests/async/trap-if-done.wast delete mode 100644 parser/src/test/resources/spec-tests/async/trap-on-reenter.wast delete mode 100644 parser/src/test/resources/spec-tests/async/wait-during-callback.wast delete mode 100644 parser/src/test/resources/spec-tests/async/zero-length.wast delete mode 100644 parser/src/test/resources/spec-tests/failed.wasm delete mode 100644 parser/src/test/resources/spec-tests/names/kebab.wast delete mode 100644 parser/src/test/resources/spec-tests/resources/multiple-resources.wast delete mode 100644 parser/src/test/resources/spec-tests/validation/implements.wast delete mode 100644 parser/src/test/resources/spec-tests/values/strings.wast delete mode 100644 parser/src/test/resources/spec-tests/values/trap-in-post-return.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/adapt.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/alias.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/big.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/definedtypes.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/empty.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/example.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/export-ascription.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/export-introduces-alias.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/export.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/func.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/import.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/imports-exports.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/inline-exports.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/instance-type.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/instantiate.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/invalid.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/link.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/lower.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/memory64.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/module-link.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/more-flags.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/naming.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/nested-modules.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/resources.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/tags.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/types.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/very-nested.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/virtualize.wast delete mode 100644 parser/src/test/resources/spec-tests/wasm-tools/wrong-order.wast delete mode 100644 parser/src/test/resources/spec-tests/wasmtime/adapter.wast delete mode 100644 parser/src/test/resources/spec-tests/wasmtime/aliasing.wast delete mode 100644 parser/src/test/resources/spec-tests/wasmtime/fused.wast delete mode 100644 parser/src/test/resources/spec-tests/wasmtime/import.wast delete mode 100644 parser/src/test/resources/spec-tests/wasmtime/instance.wast delete mode 100644 parser/src/test/resources/spec-tests/wasmtime/linking.wast delete mode 100644 parser/src/test/resources/spec-tests/wasmtime/modules.wast delete mode 100644 parser/src/test/resources/spec-tests/wasmtime/nested.wast delete mode 100644 parser/src/test/resources/spec-tests/wasmtime/resources.wast delete mode 100644 parser/src/test/resources/spec-tests/wasmtime/restrictions.wast delete mode 100644 parser/src/test/resources/spec-tests/wasmtime/simple.wast delete mode 100644 parser/src/test/resources/spec-tests/wasmtime/strings.wast delete mode 100644 parser/src/test/resources/spec-tests/wasmtime/tags.wast delete mode 100644 parser/src/test/resources/spec-tests/wasmtime/types.wast diff --git a/.gitignore b/.gitignore index f924c3f..bd4c723 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ target/ .DS_Store .claude +/parser/src/test/resources/spec-tests/ diff --git a/parser/src/test/resources/spec-tests/async/async-calls-sync.wast b/parser/src/test/resources/spec-tests/async/async-calls-sync.wast deleted file mode 100644 index 5172bb4..0000000 --- a/parser/src/test/resources/spec-tests/async/async-calls-sync.wast +++ /dev/null @@ -1,251 +0,0 @@ -;; This test contains 3 components, $AsyncInner, $SyncMiddle and $AsyncOuter, -;; where there are two instances of $SyncMiddle that import a single instance -;; of $AsyncInner, and $AsyncOuter imports all 3 preceding instances. -;; -;; $AsyncOuter.run asynchronously calls $SyncMiddle.sync-func twice concurrently -;; in each instance (4 total calls), hitting the synchronous backpressure case -;; in 2 of the 4 calls. -;; -;; $SyncMiddle.sync-func makes a blocking call to $AsyncInner.blocking-call -;; which is used to emulate a host call that blocks until $AsyncOuter.run -;; calls $AsyncInner.unblock to unblock all the 'blocking-call' calls. -(component - (component $AsyncInner - (core module $CoreAsyncInner - (import "" "context.set" (func $context.set (param i32))) - (import "" "context.get" (func $context.get (result i32))) - (import "" "task.return0" (func $task.return0)) - (import "" "task.return1" (func $task.return1 (param i32))) - - (memory 1) - (global $blocked (mut i32) (i32.const 1)) - (global $counter (mut i32) (i32.const 2)) - - ;; 'blocking-call' cooperatively "spin-waits" until $blocked is 0. - (func $blocking-call (export "blocking-call") (result i32) - (call $context.set (global.get $counter)) - (global.set $counter (i32.add (i32.const 1) (global.get $counter))) - (i32.const 1 (; YIELD ;)) - ) - (func $blocking-call-cb (export "blocking-call-cb") (param i32 i32 i32) (result i32) - (if (i32.eqz (global.get $blocked)) (then - (call $task.return1 (call $context.get)) - (return (i32.const 0 (; EXIT ;))) - )) - (i32.const 1 (; YIELD ;)) - ) - (func $unblock (export "unblock") (result i32) - (global.set $blocked (i32.const 0)) - (call $task.return0) - (i32.const 0 (; EXIT ;)) - ) - (func $unblock-cb (export "unblock-cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (canon task.return (core func $task.return0)) - (canon task.return (result u32) (core func $task.return1)) - (canon context.set i32 0 (core func $context.set)) - (canon context.get i32 0 (core func $context.get)) - (core instance $core_async_inner (instantiate $CoreAsyncInner (with "" (instance - (export "task.return0" (func $task.return0)) - (export "task.return1" (func $task.return1)) - (export "context.set" (func $context.set)) - (export "context.get" (func $context.get)) - )))) - (func (export "blocking-call") async (result u32) (canon lift - (core func $core_async_inner "blocking-call") - async (callback (func $core_async_inner "blocking-call-cb")) - )) - (func (export "unblock") async (canon lift - (core func $core_async_inner "unblock") - async (callback (func $core_async_inner "unblock-cb")) - )) - ) - - (component $SyncMiddle - (import "blocking-call" (func $blocking-call async (result u32))) - (core module $CoreSyncMiddle - (import "" "blocking-call" (func $blocking-call (result i32))) - (func $sync-func (export "sync-func") (result i32) - (call $blocking-call) - ) - ) - (canon lower (func $blocking-call) (core func $blocking-call')) - (core instance $core_sync_middle (instantiate $CoreSyncMiddle (with "" (instance - (export "blocking-call" (func $blocking-call')) - )))) - (func (export "sync-func") async (result u32) (canon lift - (core func $core_sync_middle "sync-func") - )) - ) - - (component $AsyncMiddle - (import "blocking-call" (func $blocking-call async (result u32))) - (core module $CoreSyncMiddle - (import "" "task.return" (func $task.return (param i32))) - (import "" "blocking-call" (func $blocking-call (result i32))) - (func $sync-func (export "sync-func") (result i32) - (call $task.return (call $blocking-call)) - (i32.const 0 (; EXIT ;)) - ) - (func $sync-func-cb (export "sync-func-cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (canon task.return (result u32) (core func $task.return)) - (canon lower (func $blocking-call) (core func $blocking-call')) - (core instance $core_sync_middle (instantiate $CoreSyncMiddle (with "" (instance - (export "task.return" (func $task.return)) - (export "blocking-call" (func $blocking-call')) - )))) - (func (export "sync-func") async (result u32) (canon lift - (core func $core_sync_middle "sync-func") - async (callback (func $core_sync_middle "sync-func-cb")) - )) - ) - - (component $AsyncOuter - (import "unblock" (func $unblock async)) - (import "sync-func1" (func $sync-func1 async (result u32))) - (import "sync-func2" (func $sync-func2 async (result u32))) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CoreAsyncOuter - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "subtask.drop" (func $subtask.drop (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "unblock" (func $unblock)) - (import "" "sync-func1" (func $sync-func1 (param i32) (result i32))) - (import "" "sync-func2" (func $sync-func2 (param i32) (result i32))) - - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - ;; set $remain to the number of tasks to wait to complete - (global $remain (mut i32) (i32.const 4)) - - (func $run (export "run") (result i32) - (local $ret i32) - - ;; call 'sync-func1' and 'sync-func2' asynchronously, both of which will block - ;; (on $AsyncInner.blocking-call). because 'sync-func1/2' are in different instances, - ;; both calls will reach the STARTED state. - (local.set $ret (call $sync-func1 (i32.const 8))) - (if (i32.ne (i32.const 0x21 (; STARTED=1 | (subtask=2 << 4) ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (i32.const 2) (global.get $ws)) - (local.set $ret (call $sync-func2 (i32.const 12))) - (if (i32.ne (i32.const 0x31 (; STARTED=1 | (subtask=3 << 4) ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (i32.const 3) (global.get $ws)) - - ;; now start another pair of 'sync-func1/2' calls, both of which should see auto - ;; backpressure and get stuck in the STARTING state. - (local.set $ret (call $sync-func1 (i32.const 16))) - (if (i32.ne (i32.const 0x40 (; STARTING=0 | (subtask=4 << 4) ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (i32.const 4) (global.get $ws)) - (local.set $ret (call $sync-func2 (i32.const 20))) - (if (i32.ne (i32.const 0x50 (; STARTING=0 | (subtask=5 << 4) ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (i32.const 5) (global.get $ws)) - - ;; unblock all the tasks and start waiting to complete - (call $unblock) - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) - ) - (func $run-cb (export "run-cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - (local $ret i32) - - ;; confirm we only receive SUBTASK events. - (if (i32.ne (local.get $event_code) (i32.const 1 (; SUBTASK ;))) - (then unreachable)) - - ;; if we receive a SUBTASK STARTED event, it should only be for the 3rd or - ;; 4th subtask (at indices 4/5, resp), so keep waiting for completion - (if (i32.eq (local.get $payload) (i32.const 1 (; STARTED ;))) (then - (if (i32.and - (i32.ne (local.get $index) (i32.const 4)) - (i32.ne (local.get $index) (i32.const 5))) - (then unreachable)) - (return (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4)))) - )) - - ;; when we receive a SUBTASK RETURNED event, check the return value is equal to the - ;; subtask index (which we've ensured by having $AsyncInner.$counter start at 2, the - ;; first subtask index. The address of the return buffer is the index*4. - (if (i32.ne (local.get $payload) (i32.const 2 (; RETURNED ;))) - (then unreachable)) - (if (i32.ne (local.get $index) (i32.load (i32.mul (local.get $index) (i32.const 4)))) - (then unreachable)) - - ;; decrement $remain and exit if 0 - (call $subtask.drop (local.get $index)) - (global.set $remain (i32.sub (global.get $remain) (i32.const 1))) - (if (i32.gt_u (global.get $remain) (i32.const 0)) (then - (return (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4)))) - )) - (call $task.return (i32.const 42)) - (i32.const 0 (; EXIT ;)) - ) - ) - (canon task.return (result u32) (core func $task.return)) - (canon subtask.drop (core func $subtask.drop)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon lower (func $unblock) (core func $unblock)) - (canon lower (func $sync-func1) async (memory $memory "mem") (core func $sync-func1')) - (canon lower (func $sync-func2) async (memory $memory "mem") (core func $sync-func2')) - (core instance $em (instantiate $CoreAsyncOuter (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "subtask.drop" (func $subtask.drop)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "unblock" (func $unblock)) - (export "sync-func1" (func $sync-func1')) - (export "sync-func2" (func $sync-func2')) - )))) - (func (export "run") async (result u32) (canon lift - (core func $em "run") - async (callback (func $em "run-cb")) - )) - ) - - ;; run1 uses $SyncMiddle - (instance $async_inner1 (instantiate $AsyncInner)) - (instance $sync_middle11 (instantiate $SyncMiddle - (with "blocking-call" (func $async_inner1 "blocking-call")) - )) - (instance $sync_middle12 (instantiate $SyncMiddle - (with "blocking-call" (func $async_inner1 "blocking-call")) - )) - (instance $async_outer1 (instantiate $AsyncOuter - (with "unblock" (func $async_inner1 "unblock")) - (with "sync-func1" (func $sync_middle11 "sync-func")) - (with "sync-func2" (func $sync_middle12 "sync-func")) - )) - (func (export "run1") (alias export $async_outer1 "run")) - - ;; run2 uses $AsyncMiddle - (instance $async_inner2 (instantiate $AsyncInner)) - (instance $sync_middle21 (instantiate $SyncMiddle - (with "blocking-call" (func $async_inner2 "blocking-call")) - )) - (instance $sync_middle22 (instantiate $AsyncMiddle - (with "blocking-call" (func $async_inner2 "blocking-call")) - )) - (instance $async_outer2 (instantiate $AsyncOuter - (with "unblock" (func $async_inner2 "unblock")) - (with "sync-func1" (func $sync_middle21 "sync-func")) - (with "sync-func2" (func $sync_middle22 "sync-func")) - )) - (func (export "run2") (alias export $async_outer2 "run")) -) -(assert_return (invoke "run1") (u32.const 42)) -(assert_return (invoke "run2") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/async/cancel-stream.wast b/parser/src/test/resources/spec-tests/async/cancel-stream.wast deleted file mode 100644 index 336b5ac..0000000 --- a/parser/src/test/resources/spec-tests/async/cancel-stream.wast +++ /dev/null @@ -1,202 +0,0 @@ -;; This test contains two components $C and $D that test cancelling reads -;; and writes in the presence and absence of partial reads/writes. -;; -;; $C exports a function 'start-stream' that creates and holds onto a writable -;; stream in the global $sw as well as various operations that operate on $sw. -;; $D calls $C.start-stream to get the readable end and then drives the test. -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - (global $sw (mut i32) (i32.const 0)) - - (func $start-stream (export "start-stream") (result i32) - ;; create a new stream, return the readable end to the caller - (local $ret64 i64) - (local.set $ret64 (call $stream.new)) - (global.set $sw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (i32.wrap_i64 (local.get $ret64)) - ) - - (func $write4 (export "write4") - ;; write 6 bytes into the stream, expecting to rendezvous with a stream.read - (local $ret i32) - (i32.store (i32.const 8) (i32.const 0xabcd)) - (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 4))) - (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - ) - - (func $write4-and-drop (export "write4-and-drop") - (call $write4) - (call $stream.drop-writable (global.get $sw)) - ) - - (func $start-blocking-write (export "start-blocking-write") - (local $ret i32) - - ;; prepare the write buffer - (i64.store (i32.const 8) (i64.const 0x123456789abcdef)) - - ;; start one blocking write and immediately cancel it - (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 8))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $stream.cancel-write (global.get $sw))) - (if (i32.ne (i32.const 0x2 (; CANCELLED ;)) (local.get $ret)) - (then unreachable)) - - ;; start a second blockign write and leave it pending - (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 8))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - ) - - (func $cancel-after-read4 (export "cancel-after-read4") - (local $ret i32) - (local.set $ret (call $stream.cancel-write (global.get $sw))) - (if (i32.ne (i32.const 0x42 (; CANCELLED=2 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - ) - ) - (type $ST (stream u8)) - (canon task.return (result u32) (core func $task.return)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.cancel-write $ST (core func $stream.cancel-write)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "stream.new" (func $stream.new)) - (export "stream.write" (func $stream.write)) - (export "stream.cancel-write" (func $stream.cancel-write)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (func (export "start-stream") async (result (stream u8)) (canon lift (core func $cm "start-stream"))) - (func (export "write4") async (canon lift (core func $cm "write4"))) - (func (export "write4-and-drop") async (canon lift (core func $cm "write4-and-drop"))) - (func (export "start-blocking-write") async (canon lift (core func $cm "start-blocking-write"))) - (func (export "cancel-after-read4") async (canon lift (core func $cm "cancel-after-read4"))) - ) - - (component $D - (import "c" (instance $c - (export "start-stream" (func async (result (stream u8)))) - (export "write4" (func async)) - (export "write4-and-drop" (func async)) - (export "start-blocking-write" (func async)) - (export "cancel-after-read4" (func async)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.cancel-read" (func $stream.cancel-read (param i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "start-stream" (func $start-stream (result i32))) - (import "" "write4" (func $write4)) - (import "" "write4-and-drop" (func $write4-and-drop)) - (import "" "start-blocking-write" (func $start-blocking-write)) - (import "" "cancel-after-read4" (func $cancel-after-read4)) - - (func $run (export "run") (result i32) - (local $ret i32) - (local $sr i32) - - ;; call 'start-stream' to get the stream we'll be working with - (local.set $sr (call $start-stream)) - (if (i32.ne (i32.const 1) (local.get $sr)) - (then unreachable)) - - ;; start read that will block - (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) - (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) - (then unreachable)) - - ;; cancelling it will finish without anything having been written - (local.set $ret (call $stream.cancel-read (local.get $sr))) - (if (i32.ne (i32.const 0x2 (; CANCELLED ;)) (local.get $ret)) - (then unreachable)) - - ;; read, block, call $C to write 4 bytes into the buffer, - ;; then cancel, which should show "4+cancelled" - (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) - (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) - (then unreachable)) - (call $write4) - (local.set $ret (call $stream.cancel-read (local.get $sr))) - (if (i32.ne (i32.const 0x42 (; CANCELLED=2 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0xabcd) (i32.load (i32.const 8))) - (then unreachable)) - - ;; read, block, call $C to write 4 bytes into the buffer and drop, then cancel - (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) - (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) - (then unreachable)) - (call $write4-and-drop) - (local.set $ret (call $stream.cancel-read (local.get $sr))) - (if (i32.ne (i32.const 0x41 (; DROPPED=1 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0xabcd) (i32.load (i32.const 8))) - (then unreachable)) - (call $stream.drop-readable (local.get $sr)) - - ;; get a new $sr - (local.set $sr (call $start-stream)) - (if (i32.ne (i32.const 1) (local.get $sr)) - (then unreachable)) - - ;; start outstanding write in $C, read 4 of it, then call back into $C - ;; which will cancel and see 4 written. - (call $start-blocking-write) - (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 4))) - (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0x89abcdef) (i32.load (i32.const 8))) - (then unreachable)) - (call $cancel-after-read4) - - ;; return 42 to the top-level assert_return - (i32.const 42) - ) - ) - (type $ST (stream u8)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.cancel-read $ST (core func $stream.cancel-read)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon lower (func $c "start-stream") (core func $start-stream')) - (canon lower (func $c "write4") (core func $write4')) - (canon lower (func $c "write4-and-drop") (core func $write4-and-drop')) - (canon lower (func $c "start-blocking-write") (core func $start-blocking-write')) - (canon lower (func $c "cancel-after-read4") (core func $cancel-after-read4')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "stream.read" (func $stream.read)) - (export "stream.cancel-read" (func $stream.cancel-read)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "start-stream" (func $start-stream')) - (export "write4" (func $write4')) - (export "write4-and-drop" (func $write4-and-drop')) - (export "start-blocking-write" (func $start-blocking-write')) - (export "cancel-after-read4" (func $cancel-after-read4')) - )))) - (func (export "run") async (result u32) (canon lift (core func $dm "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "run") (alias export $d "run")) -) -(assert_return (invoke "run") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/async/cancel-subtask.wast b/parser/src/test/resources/spec-tests/async/cancel-subtask.wast deleted file mode 100644 index 57a0f33..0000000 --- a/parser/src/test/resources/spec-tests/async/cancel-subtask.wast +++ /dev/null @@ -1,201 +0,0 @@ -;; This test contains two components $C and $D where $D imports and calls $C. -;; $D.run calls $C.f, which blocks on an empty waitable set -;; $D.run then subtask.cancels $C.f, which resumes $C.f which promptly resolves -;; without returning a value. -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.cancel" (func $task.cancel)) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - - ;; $ws is waited on by 'f' - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - (func $f (export "f") (result i32) - ;; wait on $ws which is currently empty, expected to get cancelled - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) - ) - (func $f_cb (export "f_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - ;; confirm that we've received a cancellation request - (if (i32.ne (local.get $event_code) (i32.const 6 (; TASK_CANCELLED ;))) - (then unreachable)) - (if (i32.ne (local.get $index) (i32.const 0)) - (then unreachable)) - (if (i32.ne (local.get $payload) (i32.const 0)) - (then unreachable)) - - ;; finish without returning a value - (call $task.cancel) - (i32.const 0 (; EXIT ;)) - ) - - (func $g (export "g") (param $futr i32) (result i32) - (local $ret i32) - (local $event_code i32) - - ;; perform a future.read which will block, waiting for the caller to write - (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (local.get $futr) (global.get $ws)) - - ;; wait on $ws synchronously, don't expect cancellation - (local.set $event_code (call $waitable-set.wait (global.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) - (then unreachable)) - - ;; finish returning a value - (i32.const 42) - ) - ) - (type $FT (future)) - (canon task.cancel (core func $task.cancel)) - (canon future.read $FT async (memory $memory "mem") (core func $future.read)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.cancel" (func $task.cancel)) - (export "future.read" (func $future.read)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - )))) - (func (export "f") async (result u32) (canon lift - (core func $cm "f") - async (callback (func $cm "f_cb")) - )) - (func (export "g") async (param "fut" $FT) (result u32) (canon lift - (core func $cm "g") - )) - ) - - (component $D - (type $FT (future)) - (import "f" (func $f async (result u32))) - (import "g" (func $g async (param "fut" $FT) (result u32))) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) - (import "" "subtask.drop" (func $subtask.drop (param i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "f" (func $f (param i32) (result i32))) - (import "" "g" (func $g (param i32 i32) (result i32))) - - (func $run (export "run") (result i32) - (local $ret i32) (local $ret64 i64) - (local $retp i32) (local $retp1 i32) (local $retp2 i32) - (local $subtask i32) - (local $event_code i32) - (local $futr i32) (local $futw i32) - (local $ws i32) - - ;; call 'f'; it should block - (local.set $retp (i32.const 4)) - (i32.store (local.get $retp) (i32.const 0xbad0bad0)) - (local.set $ret (call $f (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; cancel 'f'; it should complete without blocking - (local.set $ret (call $subtask.cancel (local.get $subtask))) - (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (local.get $ret)) - (then unreachable)) - - ;; The $retp memory shouldn't have changed - (if (i32.ne (i32.load (local.get $retp)) (i32.const 0xbad0bad0)) - (then unreachable)) - - (call $subtask.drop (local.get $subtask)) - - ;; create future that g will wait on - (local.set $ret64 (call $future.new)) - (local.set $futr (i32.wrap_i64 (local.get $ret64))) - (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - - ;; call 'g'; it should block - (local.set $retp1 (i32.const 4)) - (local.set $retp2 (i32.const 8)) - (i32.store (local.get $retp1) (i32.const 0xbad0bad0)) - (i32.store (local.get $retp2) (i32.const 0xbad0bad0)) - (local.set $ret (call $g (local.get $futr) (local.get $retp1))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; cancel 'g'; it should block - (local.set $ret (call $subtask.cancel (local.get $subtask))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; future.write, unblocking 'g' - (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - ;; wait to see 'g' finish and check its return value - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtask) (local.get $ws)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load (local.get $retp1))) - (then unreachable)) - - ;; return to the top-level assert_return - (i32.const 42) - ) - ) - (canon subtask.cancel async (core func $subtask.cancel)) - (canon subtask.drop (core func $subtask.drop)) - (canon future.new $FT (core func $future.new)) - (canon future.write $FT async (memory $memory "mem") (core func $future.write)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon lower (func $f) async (memory $memory "mem") (core func $f')) - (canon lower (func $g) async (memory $memory "mem") (core func $g')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "subtask.cancel" (func $subtask.cancel)) - (export "subtask.drop" (func $subtask.drop)) - (export "future.new" (func $future.new)) - (export "future.write" (func $future.write)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "f" (func $f')) - (export "g" (func $g')) - )))) - (func (export "run") async (result u32) (canon lift (core func $dm "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D - (with "f" (func $c "f")) - (with "g" (func $c "g")) - )) - (func (export "run") (alias export $d "run")) -) -(assert_return (invoke "run") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/async/cancellable.wast b/parser/src/test/resources/spec-tests/async/cancellable.wast deleted file mode 100644 index 2c5614c..0000000 --- a/parser/src/test/resources/spec-tests/async/cancellable.wast +++ /dev/null @@ -1,325 +0,0 @@ -;; This test exercises the 'cancellable' immediate on waitable-set.wait, -;; waitable-set.poll, and thread.yield. -;; -;; Component $C exports five async callback-lifted functions that block in -;; their initial core function (the callbacks are never invoked): -;; wait-cancel: blocks on cancellable waitable-set.wait, expects TASK_CANCELLED -;; yield-cancel: yields with cancellable, caller cancels during yield -;; poll-cancel-pending: blocks on non-cancellable wait, then polls with cancellable -;; yield-cancel-pending: blocks on non-cancellable wait, then yields with cancellable -;; -;; Component $D calls each function and cancels it, verifying the cancel is -;; delivered correctly through the cancellable built-in in each case. -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.cancel" (func $task.cancel)) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait-cancellable" (func $waitable-set.wait-cancellable (param i32 i32) (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "waitable-set.poll-cancellable" (func $waitable-set.poll-cancellable (param i32 i32) (result i32))) - (import "" "thread.yield-cancellable" (func $thread.yield-cancellable (result i32))) - - ;; Test 1: direct cancel delivery through cancellable waitable-set.wait - (func $wait-cancel (export "wait-cancel") (result i32) - (local $event_code i32) - (local $ws i32) - (local.set $ws (call $waitable-set.new)) - ;; wait on empty waitable set with cancellable; blocks until cancelled - (local.set $event_code (call $waitable-set.wait-cancellable (local.get $ws) (i32.const 0))) - (if (i32.ne (local.get $event_code) (i32.const 6 (; TASK_CANCELLED ;))) - (then unreachable)) - (call $task.cancel) - (i32.const 0 (; EXIT ;)) - ) - - ;; Test 2: direct cancel delivery through cancellable thread.yield - (func $yield-cancel (export "yield-cancel") (result i32) - (local $ret i32) - ;; yield with cancellable; suspends with cancellable=true, caller cancels - (local.set $ret (call $thread.yield-cancellable)) - (if (i32.ne (i32.const 1 (; CANCELLED ;)) (local.get $ret)) - (then unreachable)) - (call $task.cancel) - (i32.const 0 (; EXIT ;)) - ) - - ;; Test 3: deferred cancel delivered through cancellable waitable-set.poll - (func $poll-cancel-pending (export "poll-cancel-pending") (param $futr i32) (result i32) - (local $ws i32) - (local $ret i32) - (local $event_code i32) - (local.set $ws (call $waitable-set.new)) - ;; read future - blocks (caller hasn't written yet) - (local.set $ret (call $future.read (local.get $futr) (i32.const 0))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (local.get $futr) (local.get $ws)) - ;; wait WITHOUT cancellable - cancel will be deferred as PENDING_CANCEL - (local.set $event_code (call $waitable-set.wait (local.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) - (then unreachable)) - ;; poll WITH cancellable - delivers the pending cancel - (local.set $event_code (call $waitable-set.poll-cancellable (local.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 6 (; TASK_CANCELLED ;)) (local.get $event_code)) - (then unreachable)) - (call $task.cancel) - (i32.const 0 (; EXIT ;)) - ) - - ;; Test 4: deferred cancel delivered through cancellable thread.yield - (func $yield-cancel-pending (export "yield-cancel-pending") (param $futr i32) (result i32) - (local $ws i32) - (local $ret i32) - (local $event_code i32) - (local.set $ws (call $waitable-set.new)) - ;; read future - blocks (caller hasn't written yet) - (local.set $ret (call $future.read (local.get $futr) (i32.const 0))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (local.get $futr) (local.get $ws)) - ;; wait WITHOUT cancellable - cancel will be deferred as PENDING_CANCEL - (local.set $event_code (call $waitable-set.wait (local.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) - (then unreachable)) - ;; yield WITH cancellable - delivers the pending cancel - (local.set $ret (call $thread.yield-cancellable)) - (if (i32.ne (i32.const 1 (; CANCELLED ;)) (local.get $ret)) - (then unreachable)) - (call $task.cancel) - (i32.const 0 (; EXIT ;)) - ) - - ;; callback that should never be called - (func (export "unreachable-cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (type $FT (future)) - (canon task.cancel (core func $task.cancel)) - (canon future.read $FT async (memory $memory "mem") (core func $future.read)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait cancellable (memory $memory "mem") (core func $waitable-set.wait-cancellable)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon waitable-set.poll cancellable (memory $memory "mem") (core func $waitable-set.poll-cancellable)) - (canon thread.yield cancellable (core func $thread.yield-cancellable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.cancel" (func $task.cancel)) - (export "future.read" (func $future.read)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait-cancellable" (func $waitable-set.wait-cancellable)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "waitable-set.poll-cancellable" (func $waitable-set.poll-cancellable)) - (export "thread.yield-cancellable" (func $thread.yield-cancellable)) - )))) - (func (export "wait-cancel") async (result u32) (canon lift - (core func $cm "wait-cancel") - async (callback (func $cm "unreachable-cb")) - )) - (func (export "yield-cancel") async (result u32) (canon lift - (core func $cm "yield-cancel") - async (callback (func $cm "unreachable-cb")) - )) - (func (export "poll-cancel-pending") async (param "fut" $FT) (result u32) (canon lift - (core func $cm "poll-cancel-pending") - async (callback (func $cm "unreachable-cb")) - )) - (func (export "yield-cancel-pending") async (param "fut" $FT) (result u32) (canon lift - (core func $cm "yield-cancel-pending") - async (callback (func $cm "unreachable-cb")) - )) - ) - - (component $D - (type $FT (future)) - (import "wait-cancel" (func $wait-cancel async (result u32))) - (import "yield-cancel" (func $yield-cancel async (result u32))) - (import "poll-cancel-pending" (func $poll-cancel-pending async (param "fut" $FT) (result u32))) - (import "yield-cancel-pending" (func $yield-cancel-pending async (param "fut" $FT) (result u32))) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) - (import "" "subtask.drop" (func $subtask.drop (param i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "wait-cancel" (func $wait-cancel (param i32) (result i32))) - (import "" "yield-cancel" (func $yield-cancel (param i32) (result i32))) - (import "" "poll-cancel-pending" (func $poll-cancel-pending (param i32 i32) (result i32))) - (import "" "yield-cancel-pending" (func $yield-cancel-pending (param i32 i32) (result i32))) - - (func $run (export "run") (result i32) - (local $ret i32) (local $ret64 i64) - (local $retp i32) (local $retp2 i32) - (local $subtask i32) - (local $event_code i32) - (local $futr i32) (local $futw i32) - (local $ws i32) - - ;; ========================================== - ;; Test 1: waitable-set.wait cancellable - ;; ========================================== - - ;; call wait-cancel; it should block in cancellable wait - (local.set $retp (i32.const 4)) - (local.set $ret (call $wait-cancel (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; cancel; completes immediately (C is in cancellable wait) - (local.set $ret (call $subtask.cancel (local.get $subtask))) - (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (local.get $ret)) - (then unreachable)) - (call $subtask.drop (local.get $subtask)) - - ;; ========================================== - ;; Test 2: thread.yield cancellable - ;; ========================================== - - ;; call yield-cancel; it should suspend in cancellable yield - (local.set $ret (call $yield-cancel (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; cancel; completes immediately (C is in cancellable yield) - (local.set $ret (call $subtask.cancel (local.get $subtask))) - (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (local.get $ret)) - ;; TODO: this currently fails in Wasmtime due to cancellable - ;; thread.yield not being directly resumed by subtask.cancel, but it - ;; seems like it should pass: - (then unreachable)) - (call $subtask.drop (local.get $subtask)) - - ;; ========================================== - ;; Test 3: waitable-set.poll cancellable (pending) - ;; ========================================== - - ;; create future for poll-cancel-pending to read - (local.set $ret64 (call $future.new)) - (local.set $futr (i32.wrap_i64 (local.get $ret64))) - (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - - ;; call poll-cancel-pending; it should block in non-cancellable wait - (local.set $retp (i32.const 4)) - (local.set $retp2 (i32.const 8)) - (local.set $ret (call $poll-cancel-pending (local.get $futr) (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; cancel; blocks because C's wait is not cancellable - (local.set $ret (call $subtask.cancel (local.get $subtask))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; write to future; unblocks C's non-cancellable wait - (local.set $ret (call $future.write (local.get $futw) (i32.const 0))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - ;; wait for subtask to complete - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtask) (local.get $ws)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (i32.load offset=4 (local.get $retp2))) - (then unreachable)) - (call $subtask.drop (local.get $subtask)) - - ;; ========================================== - ;; Test 4: thread.yield cancellable (pending) - ;; ========================================== - - ;; create future for yield-cancel-pending to read - (local.set $ret64 (call $future.new)) - (local.set $futr (i32.wrap_i64 (local.get $ret64))) - (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - - ;; call yield-cancel-pending; it should block in non-cancellable wait - (local.set $ret (call $yield-cancel-pending (local.get $futr) (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; cancel; blocks because C's wait is not cancellable - (local.set $ret (call $subtask.cancel (local.get $subtask))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; write to future; unblocks C's non-cancellable wait - (local.set $ret (call $future.write (local.get $futw) (i32.const 0))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - ;; wait for subtask to complete - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtask) (local.get $ws)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (i32.load offset=4 (local.get $retp2))) - (then unreachable)) - (call $subtask.drop (local.get $subtask)) - - ;; all tests passed - (i32.const 42) - ) - ) - (canon subtask.cancel async (core func $subtask.cancel)) - (canon subtask.drop (core func $subtask.drop)) - (canon future.new $FT (core func $future.new)) - (canon future.write $FT async (memory $memory "mem") (core func $future.write)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon lower (func $wait-cancel) async (memory $memory "mem") (core func $wait-cancel')) - (canon lower (func $yield-cancel) async (memory $memory "mem") (core func $yield-cancel')) - (canon lower (func $poll-cancel-pending) async (memory $memory "mem") (core func $poll-cancel-pending')) - (canon lower (func $yield-cancel-pending) async (memory $memory "mem") (core func $yield-cancel-pending')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "subtask.cancel" (func $subtask.cancel)) - (export "subtask.drop" (func $subtask.drop)) - (export "future.new" (func $future.new)) - (export "future.write" (func $future.write)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "wait-cancel" (func $wait-cancel')) - (export "yield-cancel" (func $yield-cancel')) - (export "poll-cancel-pending" (func $poll-cancel-pending')) - (export "yield-cancel-pending" (func $yield-cancel-pending')) - )))) - (func (export "run") async (result u32) (canon lift (core func $dm "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D - (with "wait-cancel" (func $c "wait-cancel")) - (with "yield-cancel" (func $c "yield-cancel")) - (with "poll-cancel-pending" (func $c "poll-cancel-pending")) - (with "yield-cancel-pending" (func $c "yield-cancel-pending")) - )) - (func (export "run") (alias export $d "run")) -) -(assert_return (invoke "run") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/async/closed-stream.wast b/parser/src/test/resources/spec-tests/async/closed-stream.wast deleted file mode 100644 index eb462c8..0000000 --- a/parser/src/test/resources/spec-tests/async/closed-stream.wast +++ /dev/null @@ -1,102 +0,0 @@ -;; This test contains two components $C and $D that test that if the writable side -;; of a stream is dropped, the other side registers a STREAM DROPPED status -;; when attempting to read from the stream. -(component definition $Tester - ;; Creates a stream and keeps a handle to the writable end of it. - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - ;; Store the writable end of a stream - (global $sw (mut i32) (i32.const 0)) - - ;; Create a new stream, return the readable end to the caller - (func $start-stream (export "start-stream") (result i32) - (local $ret64 i64) - (local.set $ret64 (call $stream.new)) - (global.set $sw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (i32.wrap_i64 (local.get $ret64)) - ) - - ;; Drop the writable end of a stream - (func $drop-writable (export "drop-writable") - (call $stream.drop-writable (global.get $sw)) - ) - ) - (type $ST (stream u8)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "stream.new" (func $stream.new)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (func (export "start-stream") (result (stream u8)) (canon lift (core func $cm "start-stream"))) - (func (export "drop-writable") (canon lift (core func $cm "drop-writable"))) - ) - - ;; Gets a readable stream from component $C and calls operations on it. - (component $D - (import "c" (instance $c - (export "start-stream" (func (result (stream u8)))) - (export "drop-writable" (func)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - (import "" "start-stream" (func $start-stream (result i32))) - (import "" "drop-writable" (func $drop-writable)) - - (func (export "read-from-closed-stream") - (local $ret i32) (local $sr i32) - - ;; call 'start-stream' to get the stream we'll be working with - (local.set $sr (call $start-stream)) - (if (i32.ne (i32.const 1) (local.get $sr)) - (then unreachable)) - - ;; drop the writable end and then attempt to read from it - (call $drop-writable) - (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 4))) - (if (i32.ne (i32.const 1 (; DROPPED ;)) (local.get $ret)) - (then unreachable)) - ) - ) - (type $ST (stream u8)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (canon lower (func $c "start-stream") (core func $start-stream')) - (canon lower (func $c "drop-writable") (core func $drop-writable')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-writable" (func $stream.drop-writable)) - (export "start-stream" (func $start-stream')) - (export "drop-writable" (func $drop-writable')) - )))) - (func (export "read-from-closed-stream") (canon lift (core func $core "read-from-closed-stream"))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "read-from-closed-stream") (alias export $d "read-from-closed-stream")) -) - -(component instance $new-tester-instance $Tester) -(invoke "read-from-closed-stream") diff --git a/parser/src/test/resources/spec-tests/async/cross-abi-calls.wast b/parser/src/test/resources/spec-tests/async/cross-abi-calls.wast deleted file mode 100644 index 8f1370b..0000000 --- a/parser/src/test/resources/spec-tests/async/cross-abi-calls.wast +++ /dev/null @@ -1,519 +0,0 @@ -;; This test pairs sync and async-callback calls from $Bottom into $Top, -;; testing different numbers of parameters and results that hit the various -;; flat-vs-heap cases in the spec. -(component definition $C - (component $Top - (core module $Memory - (memory (export "mem") 1) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - i32.const 0 ;; cheat -- there's never more than 1 allocation alive - ) - ) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 0)) - (import "" "task.return0" (func $task.return0)) - (import "" "task.return1" (func $task.return1 (param f64))) - (import "" "task.return16" (func $task.return16 (param i32 i64 f32 f64 i32 i64 f32 f64 i32 i64 f32 f64 i32 i64 f32 f64))) - (import "" "task.return17" (func $task.return17 (param i32))) - (func (export "sync-4-param") (param i32 i64 f32 f64) - (if (i32.ne (i32.const 42) (local.get 0)) - (then unreachable)) - (if (i64.ne (i64.const 43) (local.get 1)) - (then unreachable)) - (if (f32.ne (f32.const 44.4) (local.get 2)) - (then unreachable)) - (if (f64.ne (f64.const 45.5) (local.get 3)) - (then unreachable)) - ) - (func (export "sync-5-param") (param i32 i64 f32 f64 i32) - (if (i32.ne (i32.const -1) (local.get 0)) - (then unreachable)) - (if (i64.ne (i64.const -2) (local.get 1)) - (then unreachable)) - (if (f32.ne (f32.const -3.3) (local.get 2)) - (then unreachable)) - (if (f64.ne (f64.const -4.4) (local.get 3)) - (then unreachable)) - (if (i32.ne (i32.const -5) (local.get 4)) - (then unreachable)) - ) - (func $check-17 (param $ptr i32) - (if (i32.ne (i32.const -1) (i32.load (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -2) (i64.load offset=8 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -3.3) (f32.load offset=16 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -4.4) (f64.load offset=24 (local.get $ptr))) - (then unreachable)) - (if (i32.ne (i32.const -5) (i32.load offset=32 (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -6) (i64.load offset=40 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -7.7) (f32.load offset=48 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -8.8) (f64.load offset=56 (local.get $ptr))) - (then unreachable)) - (if (i32.ne (i32.const -9) (i32.load offset=64 (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -10) (i64.load offset=72 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -11.11) (f32.load offset=80 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -12.12) (f64.load offset=88 (local.get $ptr))) - (then unreachable)) - (if (i32.ne (i32.const -13) (i32.load offset=96 (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -14) (i64.load offset=104 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -15.15) (f32.load offset=112 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -16.16) (f64.load offset=120 (local.get $ptr))) - (then unreachable)) - (if (i32.ne (i32.const -17) (i32.load offset=128 (local.get $ptr))) - (then unreachable)) - ) - (func (export "sync-17-param") (param $ptr i32) - (call $check-17 (local.get $ptr)) - ) - (func (export "sync-1-result") (result f64) - (f64.const -1.1) - ) - (func $setup-16 (param $ptr i32) - (i32.store (local.get $ptr) (i32.const -1)) - (i64.store offset=8 (local.get $ptr) (i64.const -2)) - (f32.store offset=16 (local.get $ptr) (f32.const -3.3)) - (f64.store offset=24 (local.get $ptr) (f64.const -4.4)) - (i32.store offset=32 (local.get $ptr) (i32.const -5)) - (i64.store offset=40 (local.get $ptr) (i64.const -6)) - (f32.store offset=48 (local.get $ptr) (f32.const -7.7)) - (f64.store offset=56 (local.get $ptr) (f64.const -8.8)) - (i32.store offset=64 (local.get $ptr) (i32.const -9)) - (i64.store offset=72 (local.get $ptr) (i64.const -10)) - (f32.store offset=80 (local.get $ptr) (f32.const -11.11)) - (f64.store offset=88 (local.get $ptr) (f64.const -12.12)) - (i32.store offset=96 (local.get $ptr) (i32.const -13)) - (i64.store offset=104 (local.get $ptr) (i64.const -14)) - (f32.store offset=112 (local.get $ptr) (f32.const -15.15)) - (f64.store offset=120 (local.get $ptr) (f64.const -16.16)) - ) - (func $setup-17 (param $ptr i32) - (call $setup-16 (local.get $ptr)) - (i32.store offset=128 (local.get $ptr) (i32.const -17)) - ) - (func (export "sync-16-result") (result i32) - (local $ptr i32) - (call $setup-16 (local.get $ptr)) - (local.get $ptr) - ) - (func (export "sync-17-result") (result i32) - (local $ptr i32) - (call $setup-17 (local.get $ptr)) - (local.get $ptr) - ) - (func (export "async-4-param") (param i32 i64 f32 f64) (result i32) - (if (i32.ne (i32.const 42) (local.get 0)) - (then unreachable)) - (if (i64.ne (i64.const 43) (local.get 1)) - (then unreachable)) - (if (f32.ne (f32.const 44.4) (local.get 2)) - (then unreachable)) - (if (f64.ne (f64.const 45.5) (local.get 3)) - (then unreachable)) - (call $task.return0) - (i32.const 0 (; EXIT ;)) - ) - (func (export "async-5-param") (param i32 i64 f32 f64 i32) (result i32) - (if (i32.ne (i32.const -1) (local.get 0)) - (then unreachable)) - (if (i64.ne (i64.const -2) (local.get 1)) - (then unreachable)) - (if (f32.ne (f32.const -3.3) (local.get 2)) - (then unreachable)) - (if (f64.ne (f64.const -4.4) (local.get 3)) - (then unreachable)) - (if (i32.ne (i32.const -5) (local.get 4)) - (then unreachable)) - (call $task.return0) - (i32.const 0 (; EXIT ;)) - ) - (func (export "async-17-param") (param $ptr i32) (result i32) - (call $check-17 (local.get $ptr)) - (call $task.return0) - (i32.const 0 (; EXIT ;)) - ) - (func (export "async-1-result") (result i32) - (call $task.return1 (f64.const -1.1)) - (i32.const 0 (; EXIT ;)) - ) - (func (export "async-16-result") (result i32) - (call $task.return16 (i32.const -1) (i64.const -2) (f32.const -3.3) (f64.const -4.4) - (i32.const -5) (i64.const -6) (f32.const -7.7) (f64.const -8.8) - (i32.const -9) (i64.const -10) (f32.const -11.11) (f64.const -12.12) - (i32.const -13) (i64.const -14) (f32.const -15.15) (f64.const -16.16)) - (i32.const 0 (; EXIT ;)) - ) - (func (export "async-17-result") (result i32) - (local $ptr i32) - (call $setup-17 (local.get $ptr)) - (call $task.return17 (local.get $ptr)) - (i32.const 0 (; EXIT ;)) - ) - (func (export "unreachable-cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (canon task.return (core func $task.return0)) - (canon task.return (result f64) (core func $task.return1)) - (canon task.return (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)) (core func $task.return16)) - (canon task.return (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)) (memory $memory "mem") (core func $task.return17)) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return0" (func $task.return0)) - (export "task.return1" (func $task.return1)) - (export "task.return16" (func $task.return16)) - (export "task.return17" (func $task.return17)) - )))) - (func (export "sync-4-param") async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) - (canon lift (core func $core "sync-4-param")) - ) - (func (export "sync-5-param") async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) (param "e" u32) - (canon lift (core func $core "sync-5-param")) - ) - (func (export "sync-17-param") async - (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) - (param "e" u32) (param "f" u64) (param "g" f32) (param "h" f64) - (param "i" u32) (param "j" u64) (param "k" f32) (param "l" f64) - (param "m" u32) (param "n" u64) (param "o" f32) (param "p" f64) - (param "q" u32) - (canon lift (core func $core "sync-17-param") (memory $memory "mem") (realloc (func $memory "realloc"))) - ) - (func (export "sync-1-result") async (result f64) - (canon lift (core func $core "sync-1-result")) - ) - (func (export "sync-16-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)) - (canon lift (core func $core "sync-16-result") (memory $memory "mem")) - ) - (func (export "sync-17-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)) - (canon lift (core func $core "sync-17-result") (memory $memory "mem")) - ) - (func (export "async-4-param") async - (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) - (canon lift (core func $core "async-4-param") async (callback (func $core "unreachable-cb"))) - ) - (func (export "async-5-param") async - (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) (param "e" u32) - (canon lift (core func $core "async-5-param") async (callback (func $core "unreachable-cb"))) - ) - (func (export "async-17-param") async - (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) - (param "e" u32) (param "f" u64) (param "g" f32) (param "h" f64) - (param "i" u32) (param "j" u64) (param "k" f32) (param "l" f64) - (param "m" u32) (param "n" u64) (param "o" f32) (param "p" f64) - (param "q" u32) - (canon lift (core func $core "async-17-param") async (callback (func $core "unreachable-cb")) (memory $memory "mem") (realloc (func $memory "realloc"))) - ) - (func (export "async-1-result") async (result f64) - (canon lift (core func $core "async-1-result") async (callback (func $core "unreachable-cb"))) - ) - (func (export "async-16-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)) - (canon lift (core func $core "async-16-result") async (callback (func $core "unreachable-cb"))) - ) - (func (export "async-17-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)) - (canon lift (core func $core "async-17-result") async (callback (func $core "unreachable-cb")) (memory $memory "mem") (realloc (func $memory "realloc"))) - ) - ) - (component $Bottom - (import "func-4-param" (func $func-4-param async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64))) - (import "func-5-param" (func $func-5-param async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) (param "e" u32))) - (import "func-17-param" (func $func-17-param async - (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) - (param "e" u32) (param "f" u64) (param "g" f32) (param "h" f64) - (param "i" u32) (param "j" u64) (param "k" f32) (param "l" f64) - (param "m" u32) (param "n" u64) (param "o" f32) (param "p" f64) - (param "q" u32))) - (import "func-1-result" (func $func-1-result async (result f64))) - (import "func-16-result" (func $func-16-result async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)))) - (import "func-17-result" (func $func-17-result async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)))) - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "sync-4-param" (func $sync-4-param (param i32 i64 f32 f64))) - (import "" "async-4-param" (func $async-4-param (param i32 i64 f32 f64) (result i32))) - (import "" "sync-5-param" (func $sync-5-param (param i32 i64 f32 f64 i32))) - (import "" "async-5-param" (func $async-5-param (param i32) (result i32))) - (import "" "sync-17-param" (func $sync-17-param (param i32))) - (import "" "async-17-param" (func $async-17-param (param i32) (result i32))) - (import "" "sync-1-result" (func $sync-1-result (result f64))) - (import "" "async-1-result" (func $async-1-result (param i32) (result i32))) - (import "" "sync-16-result" (func $sync-16-result (param i32))) - (import "" "async-16-result" (func $async-16-result (param i32) (result i32))) - (import "" "sync-17-result" (func $sync-17-result (param i32))) - (import "" "async-17-result" (func $async-17-result (param i32) (result i32))) - (func (export "call-sync-4-param") (result i32) - (call $sync-4-param (i32.const 42) (i64.const 43) (f32.const 44.4) (f64.const 45.5)) - (i32.const 83) - ) - (func (export "call-async-4-param") (result i32) - (if (i32.ne (call $async-4-param (i32.const 42) (i64.const 43) (f32.const 44.4) (f64.const 45.5)) - (i32.const 2 (; RETURNED ;))) - (then unreachable)) - (i32.const 84) - ) - (func (export "call-sync-5-param") (result i32) - (call $sync-5-param (i32.const -1) (i64.const -2) (f32.const -3.3) (f64.const -4.4) (i32.const -5)) - (i32.const 85) - ) - (func (export "call-async-5-param") (result i32) - (local $ptr i32) - (i32.store (local.get $ptr) (i32.const -1)) - (i64.store offset=8 (local.get $ptr) (i64.const -2)) - (f32.store offset=16 (local.get $ptr) (f32.const -3.3)) - (f64.store offset=24 (local.get $ptr) (f64.const -4.4)) - (i32.store offset=32 (local.get $ptr) (i32.const -5)) - (if (i32.ne (call $async-5-param (local.get $ptr)) (i32.const 2 (; RETURNED ;))) - (then unreachable)) - (i32.const 86) - ) - (func $setup-17 (param $ptr i32) - (i32.store (local.get $ptr) (i32.const -1)) - (i64.store offset=8 (local.get $ptr) (i64.const -2)) - (f32.store offset=16 (local.get $ptr) (f32.const -3.3)) - (f64.store offset=24 (local.get $ptr) (f64.const -4.4)) - (i32.store offset=32 (local.get $ptr) (i32.const -5)) - (i64.store offset=40 (local.get $ptr) (i64.const -6)) - (f32.store offset=48 (local.get $ptr) (f32.const -7.7)) - (f64.store offset=56 (local.get $ptr) (f64.const -8.8)) - (i32.store offset=64 (local.get $ptr) (i32.const -9)) - (i64.store offset=72(local.get $ptr) (i64.const -10)) - (f32.store offset=80 (local.get $ptr) (f32.const -11.11)) - (f64.store offset=88 (local.get $ptr) (f64.const -12.12)) - (i32.store offset=96 (local.get $ptr) (i32.const -13)) - (i64.store offset=104 (local.get $ptr) (i64.const -14)) - (f32.store offset=112 (local.get $ptr) (f32.const -15.15)) - (f64.store offset=120 (local.get $ptr) (f64.const -16.16)) - (i32.store offset=128 (local.get $ptr) (i32.const -17)) - ) - (func (export "call-sync-17-param") (result i32) - (call $setup-17 (i32.const 0)) - (call $sync-17-param (i32.const 0)) - (i32.const 87) - ) - (func (export "call-async-17-param") (result i32) - (call $setup-17 (i32.const 0)) - (if (i32.ne (call $async-17-param (i32.const 0)) (i32.const 2 (; RETURNED ;))) - (then unreachable)) - (i32.const 88) - ) - (func (export "call-sync-1-result") (result i32) - (if (f64.ne (call $sync-1-result) (f64.const -1.1)) - (then unreachable)) - (i32.const 89) - ) - (func (export "call-async-1-result") (result i32) - (local $ptr i32) - (if (i32.ne (call $async-1-result (local.get $ptr)) (i32.const 2 (; RETURNED ;))) - (then unreachable)) - (if (f64.ne (f64.load (local.get $ptr)) (f64.const -1.1)) - (then unreachable)) - (i32.const 90) - ) - (func $check-16 (param $ptr i32) - (if (i32.ne (i32.const -1) (i32.load (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -2) (i64.load offset=8 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -3.3) (f32.load offset=16 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -4.4) (f64.load offset=24 (local.get $ptr))) - (then unreachable)) - (if (i32.ne (i32.const -5) (i32.load offset=32 (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -6) (i64.load offset=40 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -7.7) (f32.load offset=48 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -8.8) (f64.load offset=56 (local.get $ptr))) - (then unreachable)) - (if (i32.ne (i32.const -9) (i32.load offset=64 (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -10) (i64.load offset=72 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -11.11) (f32.load offset=80 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -12.12) (f64.load offset=88 (local.get $ptr))) - (then unreachable)) - (if (i32.ne (i32.const -13) (i32.load offset=96 (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -14) (i64.load offset=104 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -15.15) (f32.load offset=112 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -16.16) (f64.load offset=120 (local.get $ptr))) - (then unreachable)) - ) - (func $check-17 (param $ptr i32) - (call $check-16 (local.get $ptr)) - (if (i32.ne (i32.const -17) (i32.load offset=128 (local.get $ptr))) - (then unreachable)) - ) - (func (export "call-sync-16-result") (result i32) - (local $ptr i32) - (call $sync-16-result (local.get $ptr)) - (call $check-16 (local.get $ptr)) - (i32.const 91) - ) - (func (export "call-async-16-result") (result i32) - (local $ptr i32) - (if (i32.ne (call $async-16-result (local.get $ptr)) (i32.const 2 (; RETURNED ;))) - (then unreachable)) - (call $check-16 (local.get $ptr)) - (i32.const 92) - ) - (func (export "call-sync-17-result") (result i32) - (local $ptr i32) - (call $sync-17-result (local.get $ptr)) - (call $check-17 (local.get $ptr)) - (i32.const 93) - ) - (func (export "call-async-17-result") (result i32) - (local $ptr i32) - (if (i32.ne (call $async-17-result (local.get $ptr)) (i32.const 2 (; RETURNED ;))) - (then unreachable)) - (call $check-17 (local.get $ptr)) - (i32.const 94) - ) - ) - (canon lower (func $func-4-param) (core func $sync-4-param)) - (canon lower (func $func-4-param) async (memory $memory "mem") (core func $async-4-param)) - (canon lower (func $func-5-param) (core func $sync-5-param)) - (canon lower (func $func-5-param) async (memory $memory "mem") (core func $async-5-param)) - (canon lower (func $func-17-param) (memory $memory "mem") (core func $sync-17-param)) - (canon lower (func $func-17-param) async (memory $memory "mem") (core func $async-17-param)) - (canon lower (func $func-1-result) (core func $sync-1-result)) - (canon lower (func $func-1-result) async (memory $memory "mem") (core func $async-1-result)) - (canon lower (func $func-16-result) (memory $memory "mem") (core func $sync-16-result)) - (canon lower (func $func-16-result) async (memory $memory "mem") (core func $async-16-result)) - (canon lower (func $func-17-result) (memory $memory "mem") (core func $sync-17-result)) - (canon lower (func $func-17-result) async (memory $memory "mem") (core func $async-17-result)) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "sync-4-param" (func $sync-4-param)) - (export "async-4-param" (func $async-4-param)) - (export "sync-5-param" (func $sync-5-param)) - (export "async-5-param" (func $async-5-param)) - (export "sync-17-param" (func $sync-17-param)) - (export "async-17-param" (func $async-17-param)) - (export "sync-1-result" (func $sync-1-result)) - (export "async-1-result" (func $async-1-result)) - (export "sync-16-result" (func $sync-16-result)) - (export "async-16-result" (func $async-16-result)) - (export "sync-17-result" (func $sync-17-result)) - (export "async-17-result" (func $async-17-result)) - )))) - (func (export "call-sync-4-param") async (result u32) (canon lift (core func $core "call-sync-4-param"))) - (func (export "call-async-4-param") async (result u32) (canon lift (core func $core "call-async-4-param"))) - (func (export "call-sync-5-param") async (result u32) (canon lift (core func $core "call-sync-5-param"))) - (func (export "call-async-5-param") async (result u32) (canon lift (core func $core "call-async-5-param"))) - (func (export "call-sync-17-param") async (result u32) (canon lift (core func $core "call-sync-17-param"))) - (func (export "call-async-17-param") async (result u32) (canon lift (core func $core "call-async-17-param"))) - (func (export "call-sync-1-result") async (result u32) (canon lift (core func $core "call-sync-1-result"))) - (func (export "call-async-1-result") async (result u32) (canon lift (core func $core "call-async-1-result"))) - (func (export "call-sync-16-result") async (result u32) (canon lift (core func $core "call-sync-16-result"))) - (func (export "call-async-16-result") async (result u32) (canon lift (core func $core "call-async-16-result"))) - (func (export "call-sync-17-result") async (result u32) (canon lift (core func $core "call-sync-17-result"))) - (func (export "call-async-17-result") async (result u32) (canon lift (core func $core "call-async-17-result"))) - ) - (instance $top (instantiate $Top)) - (instance $bottom-to-sync (instantiate $Bottom - (with "func-4-param" (func $top "sync-4-param")) - (with "func-5-param" (func $top "sync-5-param")) - (with "func-17-param" (func $top "sync-17-param")) - (with "func-1-result" (func $top "sync-1-result")) - (with "func-16-result" (func $top "sync-16-result")) - (with "func-17-result" (func $top "sync-17-result")) - )) - (instance $bottom-to-async (instantiate $Bottom - (with "func-4-param" (func $top "async-4-param")) - (with "func-5-param" (func $top "async-5-param")) - (with "func-17-param" (func $top "async-17-param")) - (with "func-1-result" (func $top "async-1-result")) - (with "func-16-result" (func $top "async-16-result")) - (with "func-17-result" (func $top "async-17-result")) - )) - (func (export "sync-calls-sync-4-param") (alias export $bottom-to-sync "call-sync-4-param")) - (func (export "sync-calls-async-4-param") (alias export $bottom-to-async "call-sync-4-param")) - (func (export "async-calls-sync-4-param") (alias export $bottom-to-sync "call-async-4-param")) - (func (export "async-calls-async-4-param") (alias export $bottom-to-async "call-async-4-param")) - (func (export "sync-calls-sync-5-param") (alias export $bottom-to-sync "call-sync-5-param")) - (func (export "sync-calls-async-5-param") (alias export $bottom-to-async "call-sync-5-param")) - (func (export "async-calls-sync-5-param") (alias export $bottom-to-sync "call-async-5-param")) - (func (export "async-calls-async-5-param") (alias export $bottom-to-async "call-async-5-param")) - (func (export "sync-calls-sync-17-param") (alias export $bottom-to-sync "call-sync-17-param")) - (func (export "sync-calls-async-17-param") (alias export $bottom-to-async "call-sync-17-param")) - (func (export "async-calls-sync-17-param") (alias export $bottom-to-sync "call-async-17-param")) - (func (export "async-calls-async-17-param") (alias export $bottom-to-async "call-async-17-param")) - (func (export "sync-calls-sync-1-result") (alias export $bottom-to-sync "call-sync-1-result")) - (func (export "sync-calls-async-1-result") (alias export $bottom-to-async "call-sync-1-result")) - (func (export "async-calls-sync-1-result") (alias export $bottom-to-sync "call-async-1-result")) - (func (export "async-calls-async-1-result") (alias export $bottom-to-async "call-async-1-result")) - (func (export "sync-calls-sync-16-result") (alias export $bottom-to-sync "call-sync-16-result")) - (func (export "sync-calls-async-16-result") (alias export $bottom-to-async "call-sync-16-result")) - (func (export "async-calls-sync-16-result") (alias export $bottom-to-sync "call-async-16-result")) - (func (export "async-calls-async-16-result") (alias export $bottom-to-async "call-async-16-result")) - (func (export "sync-calls-sync-17-result") (alias export $bottom-to-sync "call-sync-17-result")) - (func (export "sync-calls-async-17-result") (alias export $bottom-to-async "call-sync-17-result")) - (func (export "async-calls-sync-17-result") (alias export $bottom-to-sync "call-async-17-result")) - (func (export "async-calls-async-17-result") (alias export $bottom-to-async "call-async-17-result")) -) - -(component instance $i $C) -(assert_return (invoke "sync-calls-sync-4-param") (u32.const 83)) -(component instance $i $C) -(assert_return (invoke "sync-calls-async-4-param") (u32.const 83)) -(component instance $i $C) -(assert_return (invoke "async-calls-sync-4-param") (u32.const 84)) -(component instance $i $C) -(assert_return (invoke "async-calls-async-4-param") (u32.const 84)) -(component instance $i $C) -(assert_return (invoke "sync-calls-sync-5-param") (u32.const 85)) -(component instance $i $C) -(assert_return (invoke "sync-calls-async-5-param") (u32.const 85)) -(component instance $i $C) -(assert_return (invoke "async-calls-sync-5-param") (u32.const 86)) -(component instance $i $C) -(assert_return (invoke "async-calls-async-5-param") (u32.const 86)) -(component instance $i $C) -(assert_return (invoke "sync-calls-sync-17-param") (u32.const 87)) -(component instance $i $C) -(assert_return (invoke "sync-calls-async-17-param") (u32.const 87)) -(component instance $i $C) -(assert_return (invoke "async-calls-sync-17-param") (u32.const 88)) -(component instance $i $C) -(assert_return (invoke "async-calls-async-17-param") (u32.const 88)) -(component instance $i $C) -(assert_return (invoke "sync-calls-sync-1-result") (u32.const 89)) -(component instance $i $C) -(assert_return (invoke "sync-calls-async-1-result") (u32.const 89)) -(component instance $i $C) -(assert_return (invoke "async-calls-sync-1-result") (u32.const 90)) -(component instance $i $C) -(assert_return (invoke "async-calls-async-1-result") (u32.const 90)) -(component instance $i $C) -(assert_return (invoke "sync-calls-sync-16-result") (u32.const 91)) -(component instance $i $C) -(assert_return (invoke "sync-calls-async-16-result") (u32.const 91)) -(component instance $i $C) -(assert_return (invoke "async-calls-sync-16-result") (u32.const 92)) -(component instance $i $C) -(assert_return (invoke "async-calls-async-16-result") (u32.const 92)) -(component instance $i $C) -(assert_return (invoke "sync-calls-sync-17-result") (u32.const 93)) -(component instance $i $C) -(assert_return (invoke "sync-calls-async-17-result") (u32.const 93)) -(component instance $i $C) -(assert_return (invoke "async-calls-sync-17-result") (u32.const 94)) -(component instance $i $C) -(assert_return (invoke "async-calls-async-17-result") (u32.const 94)) diff --git a/parser/src/test/resources/spec-tests/async/deadlock.wast b/parser/src/test/resources/spec-tests/async/deadlock.wast deleted file mode 100644 index 6d50c9f..0000000 --- a/parser/src/test/resources/spec-tests/async/deadlock.wast +++ /dev/null @@ -1,73 +0,0 @@ -;; This test defines components $C and $D where $D imports and calls $C -;; $C.f waits on an empty waitable set -;; $D.g calls $C.f and then waits for it to finish, which fails due to deadlock -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - - (func (export "f") (result i32) - ;; wait on a new empty waitable set - (local $ws i32) - (local.set $ws (call $waitable-set.new)) - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (local.get $ws) (i32.const 4))) - ) - (func (export "cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - unreachable - ) - ) - (canon waitable-set.new (core func $waitable-set.new)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable-set.new" (func $waitable-set.new)) - )))) - (func (export "f") async (result u32) (canon lift - (core func $cm "f") - async (memory $memory "mem") (callback (func $cm "cb")) - )) - ) - - (component $D - (import "f" (func $f async (result u32))) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "f" (func $f (param i32) (result i32))) - - (func (export "g") (result i32) - (local $ws i32) (local $ret i32) (local $subtaski i32) - (local.set $ret (call $f (i32.const 0))) - (local.set $subtaski (i32.shr_u (local.get $ret) (i32.const 4))) - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtaski) (local.get $ws)) - (call $waitable-set.wait (local.get $ws) (i32.const 0)) - unreachable - ) - ) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon lower (func $f) async (memory $memory "mem") (core func $f')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "f" (func $f')) - )))) - (func (export "f") async (result u32) (canon lift (core func $dm "g"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "f" (func $c "f")))) - (func (export "f") (alias export $d "f")) -) -(assert_trap (invoke "f") "wasm trap: deadlock detected: event loop cannot make further progress") diff --git a/parser/src/test/resources/spec-tests/async/dont-block-start.wast b/parser/src/test/resources/spec-tests/async/dont-block-start.wast deleted file mode 100644 index 5fab77f..0000000 --- a/parser/src/test/resources/spec-tests/async/dont-block-start.wast +++ /dev/null @@ -1,50 +0,0 @@ -;; test a few cases where components trap during core module instantiation -;; due to blocking during the (implicitly sync) start function -(assert_trap - (component - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $M - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (func $start - (drop (call $waitable-set.wait (call $waitable-set.new) (i32.const 0))) - ) - (start $start) - ) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (core instance $m (instantiate $M (with "" (instance - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - )))) - ) - "cannot block a synchronous task before returning" -) -(assert_trap - (component - (component $C - (core module $M - (func (export "f") (result i32) unreachable) - (func (export "f_cb") (param i32 i32 i32) (result i32) unreachable) - ) - (core instance $i (instantiate $M)) - (func (export "f") async (canon lift (core func $i "f") async (callback (func $i "f_cb")))) - ) - (component $D - (import "f" (func $f async)) - (core module $M - (import "" "f" (func $f)) - (func $start (call $f)) - (start $start) - ) - (canon lower (func $f) (core func $f')) - (core instance $m (instantiate $M (with "" (instance - (export "f" (func $f')) - )))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "f" (func $c "f")))) - ) - "cannot block a synchronous task before returning" -) diff --git a/parser/src/test/resources/spec-tests/async/drop-cross-task-borrow.wast b/parser/src/test/resources/spec-tests/async/drop-cross-task-borrow.wast deleted file mode 100644 index 139981c..0000000 --- a/parser/src/test/resources/spec-tests/async/drop-cross-task-borrow.wast +++ /dev/null @@ -1,309 +0,0 @@ -;; This test has 3 components $C, $D and $E -;; $C just implements a resource type that's used by $D and $E -;; $E calls async function $D.dont-drop, lending it a handle. -;; $D.dont-drop blocks, waiting on an empty waitable-set -;; $E then calls $D.drop-handle which drops the handle that $D.dont-drop -;; was lent, albeit from the "wrong" task ($D.drop-handle). -;; Then $E calls $D.resume-dont-drop to unblock $D.dont-drop, which -;; will call task.return which should not trap. -(component definition $Test - (component $C - (type $R' (resource (rep i32))) - (canon resource.new $R' (core func $resource.new)) - (core module $CM (func (export "id") (param i32) (result i32) (local.get 0))) - (core instance $cm (instantiate $CM)) - (alias core export $cm "id" (core func $resource.rep)) - (export $R "R" (type $R')) - (func (export "R-new") (param "rep" u32) (result (own $R)) (canon lift (core func $resource.new))) - (func (export "R-rep") (param "self" (borrow $R)) (result u32) (canon lift (core func $resource.rep))) - ) - - (component $D - (import "c" (instance $d - (export "R" (type $R (sub resource))) - (export "R-new" (func (param "rep" u32) (result (own $R)))) - (export "R-rep" (func (param "self" (borrow $R)) (result u32))) - )) - (core module $DM - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "task.return0" (func $task.return0)) - (import "" "task.return1" (func $task.return1 (param i32))) - (import "" "R-rep" (func $R-rep (param i32) (result i32))) - (import "" "R-drop" (func $R-drop (param i32))) - - (global $handle (mut i32) (i32.const 0)) - (global $dont-drop-result (mut i32) (i32.const 0)) - (global $dont-drop-ws (mut i32) (i32.const 0)) - - (func (export "dont-drop") (param $h i32) (result i32) - ;; Stash the given (borrow $R) handle in a global. - (global.set $handle (local.get $h)) - ;; Stash the result of $R-rep in a global for later task.return - (global.set $dont-drop-result (call $R-rep (local.get $h))) - ;; Stash the waitable-set we're waiting on in a global for resume-dont-drop to use - (global.set $dont-drop-ws (call $waitable-set.new)) - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $dont-drop-ws) (i32.const 4))) - ) - (func (export "dont-drop-cb") (param i32 i32 i32) (result i32) - ;; We were resumed by resume-dont-drop - (call $task.return1 (global.get $dont-drop-result)) - (i32.const 0 (; EXIT ;)) - ) - (func (export "drop-handle") (result i32) - ;; Drops the borrowed handle passed to dont-drop - (local $result i32) - (local.set $result (call $R-rep (global.get $handle))) - (call $R-drop (global.get $handle)) - (local.get $result) - ) - (func (export "resume-dont-drop") - ;; Add a waitable with a pending event to dont-drop's waitable-set to - ;; wake it up. - (local $ret i32) (local $ret64 i64) - (local $futw i32) (local $futr i32) - (local.set $ret64 (call $future.new)) - (local.set $futr (i32.wrap_i64 (local.get $ret64))) - (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (local.get $futr) (global.get $dont-drop-ws)) - ) - (func (export "drop-other-and-self") (param $h i32) (result i32) - (local $result i32) - (local.set $result (call $R-rep (global.get $handle))) - (call $R-drop (global.get $handle)) - (call $R-drop (local.get $h)) - (call $task.return1 (local.get $result)) - (i32.const 0 (; EXIT ;)) - ) - (func (export "drop-wrong-one") (param $h i32) (result i32) - (call $R-drop (global.get $handle)) - ;; trap b/c $h wasn't dropped - (call $task.return0) - (i32.const 0 (; EXIT ;)) - ) - (func (export "unreachable-cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (type $FT (future)) - (alias export $d "R" (type $R)) - (canon task.return (core func $task.return0)) - (canon task.return (result u32) (core func $task.return1)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon future.new $FT (core func $future.new)) - (canon future.read $FT async (core func $future.read)) - (canon future.write $FT async (core func $future.write)) - (canon lower (func $d "R-rep") (core func $R-rep)) - (canon resource.drop $R (core func $R-drop)) - (core instance $dm (instantiate $DM (with "" (instance - (export "task.return0" (func $task.return0)) - (export "task.return1" (func $task.return1)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "future.new" (func $future.new)) - (export "future.read" (func $future.read)) - (export "future.write" (func $future.write)) - (export "R-rep" (func $R-rep)) - (export "R-drop" (func $R-drop)) - )))) - (func (export "dont-drop") async (param "self" (borrow $R)) (result u32) - (canon lift (core func $dm "dont-drop") async (callback (func $dm "dont-drop-cb"))) - ) - (func (export "drop-handle") (result u32) - (canon lift (core func $dm "drop-handle")) - ) - (func (export "resume-dont-drop") - (canon lift (core func $dm "resume-dont-drop")) - ) - (func (export "drop-other-and-self") async (param "self" (borrow $R)) (result u32) - (canon lift (core func $dm "drop-other-and-self") async (callback (func $dm "unreachable-cb"))) - ) - (func (export "drop-wrong-one") async (param "self" (borrow $R)) - (canon lift (core func $dm "drop-wrong-one") async (callback (func $dm "unreachable-cb"))) - ) - ) - - (component $E - (import "c" (instance $c - (export "R" (type $R (sub resource))) - (export "R-new" (func (param "rep" u32) (result (own $R)))) - )) - (alias export $c "R" (type $R)) - (import "d" (instance $d - (export "dont-drop" (func async (param "self" (borrow $R)) (result u32))) - (export "drop-handle" (func (result u32))) - (export "resume-dont-drop" (func)) - (export "drop-other-and-self" (func async (param "self" (borrow $R)) (result u32))) - (export "drop-wrong-one" (func async (param "self" (borrow $R)))) - )) - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $EM - (import "" "mem" (memory 1)) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "R-new" (func $R-new (param i32) (result i32))) - (import "" "dont-drop" (func $dont-drop (param i32 i32) (result i32))) - (import "" "drop-handle" (func $drop-handle (result i32))) - (import "" "resume-dont-drop" (func $resume-dont-drop)) - (import "" "drop-other-and-self" (func $drop-other-and-self (param i32) (result i32))) - (import "" "drop-wrong-one" (func $drop-wrong-one (param i32))) - (func (export "drop-other-no-self") (result i32) - (local $ret i32) - (local $retp i32) (local $retp2 i32) - (local $handle i32) - (local $subtask i32) - (local $magic i32) - (local $ws i32) (local $event_code i32) - - ;; Create a resource storing $magic as it's rep - (local.set $magic (i32.const 10)) - (local.set $handle (call $R-new (local.get $magic))) - - ;; Kick off a call to dont-drop that will block - (local.set $retp (i32.const 16)) - (local.set $ret (call $dont-drop (local.get $handle) (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; drop-handle should return the rep of the handle passed to dont-drop - (local.set $ret (call $drop-handle)) - (if (i32.ne (local.get $magic) (local.get $ret)) - (then unreachable)) - - ;; this unblocks $subtask - (call $resume-dont-drop) - - ;; now wait for $subtask to return, so that it can run before the test is over - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtask) (local.get $ws)) - (local.set $retp2 (i32.const 32)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) - (then unreachable)) - - ;; $subtask should return the rep passed to $R-new. - (if (i32.ne (local.get $magic) (i32.load (local.get $retp))) - (then unreachable)) - - i32.const 42 - ) - (func (export "drop-other-and-self") (result i32) - (local $ret i32) - (local $retp i32) (local $retp2 i32) - (local $handle i32) - (local $subtask i32) - (local $magic i32) - (local $ws i32) (local $event_code i32) - - ;; Create a resource storing $magic as it's rep - (local.set $magic (i32.const 11)) - (local.set $handle (call $R-new (local.get $magic))) - - ;; Kick off a call to dont-drop that will block - (local.set $retp (i32.const 16)) - (local.set $ret (call $dont-drop (local.get $handle) (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; This will drop dont-drop's *and* its own borrowed handle - (local.set $ret (call $drop-other-and-self (local.get $handle))) - (if (i32.ne (local.get $magic) (local.get $ret)) - (then unreachable)) - - ;; this unblocks $subtask - (call $resume-dont-drop) - - ;; now wait for $subtask to return, so that it can run before the test is over - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtask) (local.get $ws)) - (local.set $retp2 (i32.const 32)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) - (then unreachable)) - - ;; $subtask should return the rep passed to $R-new. - (if (i32.ne (local.get $magic) (i32.load (local.get $retp))) - (then unreachable)) - - i32.const 43 - ) - (func (export "drop-other-miss-self") - (local $ret i32) - (local $retp i32) - (local $handle i32) - (local $subtask i32) - - (local.set $handle (call $R-new (i32.const 42))) - - ;; Kick off a call to dont-drop that will block - (local.set $retp (i32.const 16)) - (local.set $ret (call $dont-drop (local.get $handle) (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; Call drop-wrong-one which will drop the above call's borrow, but not its own and trap - (call $drop-wrong-one (local.get $handle)) - ) - ) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon lower (func $c "R-new") (core func $R-new)) - (canon lower (func $d "dont-drop") async (memory $memory "mem") (core func $dont-drop)) - (canon lower (func $d "drop-handle") (core func $drop-handle)) - (canon lower (func $d "resume-dont-drop") (core func $resume-dont-drop)) - (canon lower (func $d "drop-other-and-self") (core func $drop-other-and-self)) - (canon lower (func $d "drop-wrong-one") (core func $drop-wrong-one)) - (core instance $em (instantiate $EM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "R-new" (func $R-new)) - (export "dont-drop" (func $dont-drop)) - (export "drop-handle" (func $drop-handle)) - (export "resume-dont-drop" (func $resume-dont-drop)) - (export "drop-other-and-self" (func $drop-other-and-self)) - (export "drop-wrong-one" (func $drop-wrong-one)) - )))) - (func (export "drop-other-no-self") async (result u32) (canon lift (core func $em "drop-other-no-self"))) - (func (export "drop-other-and-self") async (result u32) (canon lift (core func $em "drop-other-and-self"))) - (func (export "drop-other-miss-self") async (canon lift (core func $em "drop-other-miss-self"))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (instance $e (instantiate $E (with "c" (instance $c)) (with "d" (instance $d)))) - (func (export "drop-other-no-self") (alias export $e "drop-other-no-self")) - (func (export "drop-other-and-self") (alias export $e "drop-other-and-self")) - (func (export "drop-other-miss-self") (alias export $e "drop-other-miss-self")) -) - -(component instance $i $Test) -(assert_return (invoke "drop-other-no-self") (u32.const 42)) -(component instance $i $Test) -(assert_return (invoke "drop-other-and-self") (u32.const 43)) -(component instance $i $Test) -(assert_trap (invoke "drop-other-miss-self") "borrow handles still remain at the end of the call") diff --git a/parser/src/test/resources/spec-tests/async/drop-stream.wast b/parser/src/test/resources/spec-tests/async/drop-stream.wast deleted file mode 100644 index bf7212f..0000000 --- a/parser/src/test/resources/spec-tests/async/drop-stream.wast +++ /dev/null @@ -1,160 +0,0 @@ -;; This test contains two components $C and $D that test that traps occur -;; when closing the readable or writable end of stream while a read or write -;; is pending. In particular, even if a partial copy has happened into the -;; buffer such that waiting/polling for an event *would* produce a STREAM -;; READ/WRITE event, if the event has not been delivered, the operation is -;; still considered pending. -(component definition $Tester - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - (global $sw (mut i32) (i32.const 0)) - - (func $start-stream (export "start-stream") (result i32) - ;; create a new stream, return the readable end to the caller - (local $ret64 i64) - (local.set $ret64 (call $stream.new)) - (global.set $sw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (i32.wrap_i64 (local.get $ret64)) - ) - (func $write4 (export "write4") - ;; write 6 bytes into the stream, expecting to rendezvous with a stream.read - (local $ret i32) - (i32.store (i32.const 8) (i32.const 0x12345678)) - (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 4))) - (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - ) - (func $start-blocking-write (export "start-blocking-write") - (local $ret i32) - - ;; prepare the write buffer - (i64.store (i32.const 8) (i64.const 0x123456789abcdef)) - - ;; start a blocking write - (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 8))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - ) - (func $drop-writable (export "drop-writable") - ;; boom - (call $stream.drop-writable (global.get $sw)) - ) - ) - (type $ST (stream u8)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "stream.new" (func $stream.new)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (func (export "start-stream") (result (stream u8)) (canon lift (core func $cm "start-stream"))) - (func (export "write4") (canon lift (core func $cm "write4"))) - (func (export "start-blocking-write") (canon lift (core func $cm "start-blocking-write"))) - (func (export "drop-writable") (canon lift (core func $cm "drop-writable"))) - ) - (component $D - (import "c" (instance $c - (export "start-stream" (func (result (stream u8)))) - (export "write4" (func)) - (export "start-blocking-write" (func)) - (export "drop-writable" (func)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - (import "" "start-stream" (func $start-stream (result i32))) - (import "" "write4" (func $write4)) - (import "" "start-blocking-write" (func $start-blocking-write)) - (import "" "drop-writable" (func $drop-writable)) - - (func (export "drop-while-reading") - (local $ret i32) (local $sr i32) - - ;; call 'start-stream' to get the stream we'll be working with - (local.set $sr (call $start-stream)) - (if (i32.ne (i32.const 1) (local.get $sr)) - (then unreachable)) - - ;; start a blocking read - (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) - (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) - (then unreachable)) - - ;; write into the buffer, but the read is still in progress since we - ;; haven't received notification yet. - (call $write4) - (if (i32.ne (i32.const 0x12345678) (i32.load (i32.const 8))) - (then unreachable)) - - ;; boom - (call $stream.drop-readable (local.get $sr)) - ) - (func (export "drop-while-writing") - (local $ret i32) (local $sr i32) - - ;; call 'start-stream' to get the stream we'll be working with - (local.set $sr (call $start-stream)) - (if (i32.ne (i32.const 1) (local.get $sr)) - (then unreachable)) - - ;; start a blocking write and partially read from it - (call $start-blocking-write) - (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 4))) - (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0x89abcdef) (i32.load (i32.const 8))) - (then unreachable)) - (call $drop-writable) - ) - ) - (type $ST (stream u8)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (canon lower (func $c "start-stream") (core func $start-stream')) - (canon lower (func $c "write4") (core func $write4')) - (canon lower (func $c "start-blocking-write") (core func $start-blocking-write')) - (canon lower (func $c "drop-writable") (core func $drop-writable')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "stream.drop-writable" (func $stream.drop-writable)) - (export "start-stream" (func $start-stream')) - (export "write4" (func $write4')) - (export "start-blocking-write" (func $start-blocking-write')) - (export "drop-writable" (func $drop-writable')) - )))) - (func (export "drop-while-reading") (canon lift (core func $core "drop-while-reading"))) - (func (export "drop-while-writing") (canon lift (core func $core "drop-while-writing"))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "drop-while-reading") (alias export $d "drop-while-reading")) - (func (export "drop-while-writing") (alias export $d "drop-while-writing")) -) -(component instance $new-tester-instance $Tester) -(assert_trap (invoke "drop-while-reading") "cannot remove busy stream") -(component instance $new-tester-instance $Tester) -(assert_trap (invoke "drop-while-writing") "cannot drop busy stream") diff --git a/parser/src/test/resources/spec-tests/async/drop-subtask.wast b/parser/src/test/resources/spec-tests/async/drop-subtask.wast deleted file mode 100644 index 21eb9fc..0000000 --- a/parser/src/test/resources/spec-tests/async/drop-subtask.wast +++ /dev/null @@ -1,140 +0,0 @@ -;; This test contains two components: $Looper and $Caller. -;; $Caller starts an async subtask for $Looper.loop and then drops these -;; subtasks in both allowed and disallowed cases, testing for success and -;; traps. -(component - (component $Looper - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CoreLooper - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return)) - - (global $done (mut i32) (i32.const 0)) - - (func $loop (export "loop") (result i32) - (i32.const 1 (; YIELD ;)) - ) - (func $loop_cb (export "loop_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - ;; confirm that we've received a cancellation request - (if (i32.ne (local.get $event_code) (i32.const 0 (; NONE ;))) - (then unreachable)) - (if (i32.ne (local.get $index) (i32.const 0)) - (then unreachable)) - (if (i32.ne (local.get $payload) (i32.const 0)) - (then unreachable)) - - (if (i32.eqz (global.get $done)) - (then (return (i32.const 1 (; YIELD ;))))) - (call $task.return) - (i32.const 0 (; EXIT ;)) - ) - - (func $return (export "return") - (global.set $done (i32.const 1)) - ) - ) - (canon task.return (core func $task.return)) - (core instance $core_looper (instantiate $CoreLooper (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - )))) - (func (export "loop") async (canon lift - (core func $core_looper "loop") - async (callback (func $core_looper "loop_cb")) - )) - (func (export "return") async (canon lift - (core func $core_looper "return") - )) - ) - - (component $Caller - (import "looper" (instance $looper - (export "loop" (func async)) - (export "return" (func async)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CoreCaller - (import "" "mem" (memory 1)) - (import "" "subtask.drop" (func $subtask.drop (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "loop" (func $loop (result i32))) - (import "" "return" (func $return)) - - (func $drop-after-return (export "drop-after-return") (result i32) - (local $ret i32) (local $ws i32) (local $subtask i32) - - ;; start 'loop' - (local.set $ret (call $loop)) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; tell 'loop' to stop - (call $return) - - ;; wait for 'loop' to run and return - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtask) (local.get $ws)) - (local.set $ret (call $waitable-set.wait (local.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (i32.const 0))) - (then unreachable)) - (if (i32.ne (i32.const 2 (; RETURNED ;)) (i32.load (i32.const 4))) - (then unreachable)) - - ;; ok to drop - (call $subtask.drop (local.get $subtask)) - (i32.const 42) - ) - - (func $drop-before-return (export "drop-before-return") (result i32) - (local $ret i32) (local $subtask i32) - - ;; start 'loop' - (local.set $ret (call $loop (i32.const 0xdead) (i32.const 0xbeef))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; this should trap - (call $subtask.drop (local.get $subtask)) - unreachable - ) - ) - (canon subtask.drop (core func $subtask.drop)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon lower (func $looper "loop") async (memory $memory "mem") (core func $loop')) - (canon lower (func $looper "return") (memory $memory "mem") (core func $return')) - (core instance $core_caller (instantiate $CoreCaller (with "" (instance - (export "mem" (memory $memory "mem")) - (export "subtask.drop" (func $subtask.drop)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "loop" (func $loop')) - (export "return" (func $return')) - )))) - (func (export "drop-after-return") async (result u32) (canon lift - (core func $core_caller "drop-after-return") - )) - (func (export "drop-before-return") async (result u32) (canon lift - (core func $core_caller "drop-before-return") - )) - ) - - (instance $looper (instantiate $Looper)) - (instance $caller1 (instantiate $Caller (with "looper" (instance $looper)))) - (instance $caller2 (instantiate $Caller (with "looper" (instance $looper)))) - (func (export "drop-after-return") (alias export $caller1 "drop-after-return")) - (func (export "drop-before-return") (alias export $caller2 "drop-before-return")) -) -(assert_return (invoke "drop-after-return") (u32.const 42)) -(assert_trap (invoke "drop-before-return") "cannot drop a subtask which has not yet resolved") diff --git a/parser/src/test/resources/spec-tests/async/drop-waitable-set.wast b/parser/src/test/resources/spec-tests/async/drop-waitable-set.wast deleted file mode 100644 index 23fff15..0000000 --- a/parser/src/test/resources/spec-tests/async/drop-waitable-set.wast +++ /dev/null @@ -1,84 +0,0 @@ -;; This test contains two components $C and $D -;; $D.run drives the test and first calls $C.wait-on-set, which waits on -;; a waitable-set. Then $D.run calls $C.drop-while-waiting which attempts -;; to drop the same waitable-set, which should trap. -(component - (component $C - (core module $Core - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.drop" (func $waitable-set.drop (param i32))) - - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - (func $wait-on-set (export "wait-on-set") (result i32) - ;; wait on $ws - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) - ) - (func $drop-while-waiting (export "drop-while-waiting") (result i32) - ;; boom - (call $waitable-set.drop (global.get $ws)) - unreachable - ) - (func $unreachable-cb (export "unreachable-cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.drop (core func $waitable-set.drop)) - (core instance $core (instantiate $Core (with "" (instance - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.drop" (func $waitable-set.drop)) - )))) - (func (export "wait-on-set") async (canon lift - (core func $core "wait-on-set") - async (callback (func $core "unreachable-cb")) - )) - (func (export "drop-while-waiting") async (canon lift - (core func $core "drop-while-waiting") - async (callback (func $core "unreachable-cb")) - )) - ) - - (component $D - (import "c" (instance $c - (export "wait-on-set" (func async)) - (export "drop-while-waiting" (func async)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "wait-on-set" (func $wait-on-set (result i32))) - (import "" "drop-while-waiting" (func $drop-while-waiting)) - (func $run (export "run") (result i32) - (local $ret i32) - - ;; start an async call to 'wait-on-set' which blocks, waiting on a - ;; waitable-set. - (local.set $ret (call $wait-on-set)) - (if (i32.ne (i32.const 0x11) (local.get $ret)) - (then unreachable)) - - ;; this call will try to drop the same waitable-set, which should trap. - (call $drop-while-waiting) - unreachable - ) - ) - (canon lower (func $c "wait-on-set") async (memory $memory "mem") (core func $wait-on-set')) - (canon lower (func $c "drop-while-waiting") (core func $drop-while-waiting')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "wait-on-set" (func $wait-on-set')) - (export "drop-while-waiting" (func $drop-while-waiting')) - )))) - (func (export "run") async (result u32) (canon lift (core func $core "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "run") (alias export $d "run")) -) -(assert_trap (invoke "run") "cannot drop waitable set with waiters") diff --git a/parser/src/test/resources/spec-tests/async/empty-wait.wast b/parser/src/test/resources/spec-tests/async/empty-wait.wast deleted file mode 100644 index 8b4d789..0000000 --- a/parser/src/test/resources/spec-tests/async/empty-wait.wast +++ /dev/null @@ -1,199 +0,0 @@ -;; This test has two components $C and $D, where $D imports and calls $C -;; $C exports two functions: 'blocker' and 'unblocker' -;; 'blocker' blocks on an empty waitable set -;; 'unblocker' wakes blocker by adding a resolved future to blocker's waitable set -;; $D calls 'blocker' then 'unblocker', then waits for 'blocker' to finish -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "future.drop-readable" (func $future.drop-readable (param i32))) - (import "" "future.drop-writable" (func $future.drop-writable (param i32))) - - ;; $ws is waited on by 'blocker' and added to by 'unblocker' - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - ;; 'unblocker' initializes $futr with the readable end of a resolved future - (global $futr (mut i32) (i32.const 0)) - - (func $blocker (export "blocker") (result i32) - ;; wait on $ws which is currently empty; 'unblocker' will wake us up - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) - ) - (func $blocker_cb (export "blocker_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - ;; assert that we were in fact woken by 'unblocker' adding $futr to $ws - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (global.get $futr) (local.get $index)) - (then unreachable)) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $payload)) - (then unreachable)) - - (call $future.drop-readable (global.get $futr)) - - ;; return 42 to $D.run - (call $task.return (i32.const 42)) - (i32.const 0) - ) - - (func $unblocker (export "unblocker") (result i32) - (local $ret i32) (local $ret64 i64) - (local $futw i32) - - ;; create a future that will be used to unblock 'blocker', storing r/w ends in $futr/$futw - (local.set $ret64 (call $future.new)) - (global.set $futr (i32.wrap_i64 (local.get $ret64))) - (if (i32.ne (i32.const 2) (global.get $futr)) - (then unreachable)) - (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (if (i32.ne (i32.const 3) (local.get $futw)) - (then unreachable)) - - ;; perform a future.read which will block, and add this future to the waitable-set - ;; being waited on by 'blocker' - (local.set $ret (call $future.read (global.get $futr) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (global.get $futr) (global.get $ws)) - - ;; perform a future.write which will rendezvous with the write and complete - (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - (call $future.drop-writable (local.get $futw)) - - ;; return 43 to $D.run - (call $task.return (i32.const 43)) - (i32.const 0) - ) - (func $unblocker_cb (export "unblocker_cb") (param i32 i32 i32) (result i32) - ;; 'unblocker' doesn't block - unreachable - ) - ) - (type $FT (future)) - (canon task.return (result u32) (core func $task.return)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon future.new $FT (core func $future.new)) - (canon future.read $FT async (core func $future.read)) - (canon future.write $FT async (core func $future.write)) - (canon future.drop-readable $FT (core func $future.drop-readable)) - (canon future.drop-writable $FT (core func $future.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "future.new" (func $future.new)) - (export "future.read" (func $future.read)) - (export "future.write" (func $future.write)) - (export "future.drop-readable" (func $future.drop-readable)) - (export "future.drop-writable" (func $future.drop-writable)) - )))) - (func (export "blocker") async (result u32) (canon lift - (core func $cm "blocker") - async (callback (func $cm "blocker_cb")) - )) - (func (export "unblocker") async (result u32) (canon lift - (core func $cm "unblocker") - async (callback (func $cm "unblocker_cb")) - )) - ) - - (component $D - (import "c" (instance $c - (export "blocker" (func async (result u32))) - (export "unblocker" (func async (result u32))) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "subtask.drop" (func $subtask.drop (param i32))) - (import "" "blocker" (func $blocker (param i32) (result i32))) - (import "" "unblocker" (func $unblocker (param i32) (result i32))) - - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - (func $run (export "run") (result i32) - (local $ret i32) (local $retp1 i32) (local $retp2 i32) - (local $subtask i32) - (local $event_code i32) - - ;; call 'blocker'; it should block - (local.set $retp1 (i32.const 4)) - (local.set $ret (call $blocker (local.get $retp1))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (if (i32.ne (i32.const 2) (local.get $subtask)) - (then unreachable)) - - ;; call 'unblocker' to unblock 'blocker'; it should complete eagerly - (local.set $retp2 (i32.const 8)) - (local.set $ret (call $unblocker (local.get $retp2))) - (if (i32.ne (i32.const 2 (; RETURNED ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 43) (i32.load (local.get $retp2))) - (then unreachable)) - - ;; wait for 'blocker' to be scheduled, run, and return - (call $waitable.join (local.get $subtask) (global.get $ws)) - (local.set $retp2 (i32.const 8)) - (local.set $event_code (call $waitable-set.wait (global.get $ws) (local.get $retp2))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load (local.get $retp1))) - (then unreachable)) - - (call $subtask.drop (local.get $subtask)) - - ;; return 44 to the top-level test harness - (i32.const 44) - ) - ) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon subtask.drop (core func $subtask.drop)) - (canon lower (func $c "blocker") async (memory $memory "mem") (core func $blocker')) - (canon lower (func $c "unblocker") async (memory $memory "mem") (core func $unblocker')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "subtask.drop" (func $subtask.drop)) - (export "blocker" (func $blocker')) - (export "unblocker" (func $unblocker')) - )))) - (func (export "run") async (result u32) (canon lift (core func $dm "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "run") (alias export $d "run")) -) -(assert_return (invoke "run") (u32.const 44)) diff --git a/parser/src/test/resources/spec-tests/async/futures-must-write.wast b/parser/src/test/resources/spec-tests/async/futures-must-write.wast deleted file mode 100644 index ce2446b..0000000 --- a/parser/src/test/resources/spec-tests/async/futures-must-write.wast +++ /dev/null @@ -1,118 +0,0 @@ -;; This test contains two components $C and $D that test that a trap occurs -;; when closing the writable end of a future (in $C) before having written -;; a value while closing the readable end of a future (in $D) before reading -;; a value is fine. -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "future.drop-writable" (func $future.drop-writable (param i32))) - - (global $fw (mut i32) (i32.const 0)) - - (func $start-future (export "start-future") (result i32) - ;; create a new future, return the readable end to the caller - (local $ret64 i64) - (local.set $ret64 (call $future.new)) - (global.set $fw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (i32.wrap_i64 (local.get $ret64)) - ) - (func $attempt-write (export "attempt-write") (result i32) - ;; because the caller already dropped the readable end, this write will eagerly - ;; return DROPPED having written no values. - (local $ret i32) - (local.set $ret (call $future.write (global.get $fw) (i32.const 42))) - (if (i32.ne (i32.const 0x01 (; DROPPED ;)) (local.get $ret)) - (then unreachable)) - - ;; return without trapping - (i32.const 42) - ) - (func $drop-writable (export "drop-writable") - ;; maybe boom - (call $future.drop-writable (global.get $fw)) - ) - ) - (type $FT (future u8)) - (canon future.new $FT (core func $future.new)) - (canon future.write $FT async (memory $memory "mem") (core func $future.write)) - (canon future.drop-writable $FT (core func $future.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "future.new" (func $future.new)) - (export "future.write" (func $future.write)) - (export "future.drop-writable" (func $future.drop-writable)) - )))) - (func (export "start-future") (result (future u8)) (canon lift (core func $cm "start-future"))) - (func (export "attempt-write") (result u32) (canon lift (core func $cm "attempt-write"))) - (func (export "drop-writable") (canon lift (core func $cm "drop-writable"))) - ) - (component $D - (import "c" (instance $c - (export "start-future" (func (result (future u8)))) - (export "attempt-write" (func (result u32))) - (export "drop-writable" (func)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "future.drop-readable" (func $future.drop-readable (param i32))) - (import "" "start-future" (func $start-future (result i32))) - (import "" "attempt-write" (func $attempt-write (result i32))) - (import "" "drop-writable" (func $drop-writable)) - - (func $drop-readable-future-before-read (export "drop-readable-future-before-read") (result i32) - ;; call 'start-future' to get the future we'll be working with - (local $fr i32) - (local.set $fr (call $start-future)) - (if (i32.ne (i32.const 1) (local.get $fr)) - (then unreachable)) - - ;; ok to immediately drop the readable end - (call $future.drop-readable (local.get $fr)) - - ;; the callee will see that we dropped the readable end when it tries to write - (call $attempt-write) - ) - (func $drop-writable-future-before-write (export "drop-writable-future-before-write") - ;; call 'start-future' to get the future we'll be working with - (local $fr i32) - (local.set $fr (call $start-future)) - (if (i32.ne (i32.const 1) (local.get $fr)) - (then unreachable)) - - ;; boom - (call $drop-writable) - ) - ) - (type $FT (future u8)) - (canon future.new $FT (core func $future.new)) - (canon future.drop-readable $FT (core func $future.drop-readable)) - (canon lower (func $c "start-future") (core func $start-future')) - (canon lower (func $c "attempt-write") (core func $attempt-write')) - (canon lower (func $c "drop-writable") (core func $drop-writable')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "future.new" (func $future.new)) - (export "future.drop-readable" (func $future.drop-readable)) - (export "start-future" (func $start-future')) - (export "attempt-write" (func $attempt-write')) - (export "drop-writable" (func $drop-writable')) - )))) - (func (export "drop-readable-future-before-read") (result u32) (canon lift (core func $core "drop-readable-future-before-read"))) - (func (export "drop-writable-future-before-write") (canon lift (core func $core "drop-writable-future-before-write"))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "drop-writable-future-before-write") (alias export $d "drop-writable-future-before-write")) - (func (export "drop-readable-future-before-read") (alias export $d "drop-readable-future-before-read")) -) - -(assert_return (invoke "drop-readable-future-before-read") (u32.const 42)) -(assert_trap (invoke "drop-writable-future-before-write") "cannot drop future write end without first writing a value") diff --git a/parser/src/test/resources/spec-tests/async/partial-stream-copies.wast b/parser/src/test/resources/spec-tests/async/partial-stream-copies.wast deleted file mode 100644 index d70ece2..0000000 --- a/parser/src/test/resources/spec-tests/async/partial-stream-copies.wast +++ /dev/null @@ -1,238 +0,0 @@ -;; This test has two components $C and $D, where $D imports and calls $C.transform -;; $C.transform takes and returns a stream -;; Before $C.transform blocks the first time, it supplies a 12-byte read buffer -;; When $D.run regains control after $C.transform blocks, it can perform multiple -;; successful writes until it fully uses up the 12-byte buffer. -;; ... and that's where I am so far ... -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - ;; $ws is waited on by 'transform' - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - ;; $insr/$outsw are read/written by 'transform' - (global $insr (mut i32) (i32.const 0)) - (global $inbufp (mut i32) (i32.const 0x10)) - (global $outsw (mut i32) (i32.const 0)) - (global $outbufp (mut i32) (i32.const 0x20)) - - (func $transform (export "transform") (param i32) (result i32) - (local $ret i32) (local $ret64 i64) (local $outsr i32) - - ;; check the incoming readable stream end - (global.set $insr (local.get 0)) - (if (i32.ne (i32.const 2) (global.get $insr)) - (then unreachable)) - - ;; create a new stream r/w pair $outsr/$outsw - (local.set $ret64 (call $stream.new)) - (local.set $outsr (i32.wrap_i64 (local.get $ret64))) - (if (i32.ne (i32.const 3) (local.get $outsr)) - (then unreachable)) - (global.set $outsw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (if (i32.ne (i32.const 4) (global.get $outsw)) - (then unreachable)) - - ;; start async read on $insr which will block - (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 12))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; return the readable end of the outgoing stream to the caller - (call $task.return (local.get $outsr)) - - ;; wait for the stream.read/write to complete - (call $waitable.join (global.get $insr) (global.get $ws)) - (call $waitable.join (global.get $outsw) (global.get $ws)) - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) - ) - (func $transform_cb (export "transform_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - (local $ret i32) (local $ret64 i64) - - ;; confirm the read succeeded fully - (if (i32.ne (local.get $event_code) (i32.const 2 (; STREAM_READ ;))) - (then unreachable)) - (if (i32.ne (local.get $index) (global.get $insr)) - (then unreachable)) - (if (i32.ne (local.get $payload) (i32.const 0xc0 (; COMPLETED=0 | (12 << 4) ;))) - (then unreachable)) - (if (i32.ne (i32.const 0x89abcdef) (i32.load offset=0 (global.get $inbufp))) - (then unreachable)) - (if (i32.ne (i32.const 0x01234567) (i32.load offset=4 (global.get $inbufp))) - (then unreachable)) - (if (i32.ne (i32.const 0x89abcdef) (i32.load offset=8 (global.get $inbufp))) - (then unreachable)) - - ;; multiple read calls succeed until 12-byte buffer is consumed - (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 4))) - (if (i32.ne (i32.const 0x40) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0x76543210) (i32.load (global.get $inbufp))) - (then unreachable)) - (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 2))) - (if (i32.ne (i32.const 0x20) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0xba98) (i32.load16_u (global.get $inbufp))) - (then unreachable)) - (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 8))) - (if (i32.ne (i32.const 0x60) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0x3210fedc) (i32.load (global.get $inbufp))) - (then unreachable)) - (if (i32.ne (i32.const 0x7654) (i32.load16_u offset=4 (global.get $inbufp))) - (then unreachable)) - - (call $stream.drop-readable (global.get $insr)) - (call $stream.drop-writable (global.get $outsw)) - (return (i32.const 0 (; EXIT ;))) - ) - ) - (type $ST (stream u8)) - (canon task.return (result $ST) (memory $memory "mem") (core func $task.return)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (func (export "transform") async (param "in" (stream u8)) (result (stream u8)) (canon lift - (core func $cm "transform") - async (memory $memory "mem") (callback (func $cm "transform_cb")) - )) - ) - - (component $D - (import "transform" (func $transform async (param "in" (stream u8)) (result (stream u8)))) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - (import "" "transform" (func $transform (param i32 i32) (result i32))) - - (func $run (export "run") (result i32) - (local $ret i32) (local $ret64 i64) (local $retp i32) - (local $insr i32) (local $insw i32) (local $outsr i32) - (local $subtask i32) (local $event_code i32) (local $index i32) (local $payload i32) - (local $ws i32) - - ;; create a new stream r/w pair $insr/$insw - (local.set $ret64 (call $stream.new)) - (local.set $insr (i32.wrap_i64 (local.get $ret64))) - (if (i32.ne (i32.const 1) (local.get $insr)) - (then unreachable)) - (local.set $insw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (if (i32.ne (i32.const 2) (local.get $insw)) - (then unreachable)) - - ;; call 'transform' which will return a readable stream $outsr eagerly - (local.set $retp (i32.const 8)) - (local.set $ret (call $transform (local.get $insr) (local.get $retp))) - (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (local.get $ret)) - (then unreachable)) - (local.set $outsr (i32.load (local.get $retp))) - (if (i32.ne (i32.const 1) (local.get $outsr)) - (then unreachable)) - - ;; multiple write calls succeed until 12-byte buffer is filled - (i64.store (i32.const 16) (i64.const 0x0123456789abcdef)) - (local.set $ret (call $stream.write (local.get $insw) (i32.const 16) (i32.const 8))) - (if (i32.ne (i32.const 0x80) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $stream.write (local.get $insw) (i32.const 16) (i32.const 8))) - (if (i32.ne (i32.const 0x40) (local.get $ret)) - (then unreachable)) - - ;; start a blocking write with a 12-byte buffer - (i64.store (i32.const 16) (i64.const 0xfedcba9876543210)) - (i32.store (i32.const 24) (i32.const 0x76543210)) - (local.set $ret (call $stream.write (local.get $insw) (i32.const 16) (i32.const 12))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; wait for transform to read our write and drop all the streams - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $insw) (local.get $ws)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (i32.const 0))) - (local.set $index (i32.load (i32.const 0))) - (local.set $payload (i32.load (i32.const 4))) - - ;; confirm the write and the dropped stream - (if (i32.ne (local.get $event_code) (i32.const 3 (; STREAM_WRITE ;))) - (then unreachable)) - (if (i32.ne (local.get $index) (local.get $insw)) - (then unreachable)) - (if (i32.ne (local.get $payload) (i32.const 0xc1 (; DROPPED=1 | (12 << 4) ;))) - (then unreachable)) - - (call $stream.drop-writable (local.get $insw)) - (call $stream.drop-readable (local.get $outsr)) - - ;; return 42 to the top-level test harness - (i32.const 42) - ) - ) - (type $ST (stream u8)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (canon lower (func $transform) async (memory $memory "mem") (core func $transform')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "stream.drop-writable" (func $stream.drop-writable)) - (export "transform" (func $transform')) - )))) - (func (export "run") async (result u32) (canon lift (core func $dm "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "transform" (func $c "transform")))) - (func (export "run") (alias export $d "run")) -) -(assert_return (invoke "run") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/async/passing-resources.wast b/parser/src/test/resources/spec-tests/async/passing-resources.wast deleted file mode 100644 index d8a7c50..0000000 --- a/parser/src/test/resources/spec-tests/async/passing-resources.wast +++ /dev/null @@ -1,176 +0,0 @@ -;; This test contains two components, $Producer and $Consumer. -;; $Producer.run drives the test and calls $Producer.start-stream to create -;; a stream and attempt to write 2 owned handles. $Producer.run then reads -;; just 1 element. The test finishes by confirming that $Consumer owns the -;; first resource, $Producer (still) owns the second resource, and $Producer -;; traps if it attempts to access the index of the first resource. -(component - (component $Producer - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "resource.new" (func $resource.new (param i32) (result i32))) - (import "" "resource.rep" (func $resource.rep (param i32) (result i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - (global $ws (mut i32) (i32.const 0)) - (global $res1 (mut i32) (i32.const 0)) - (global $res2 (mut i32) (i32.const 0)) - - (func $start-stream (export "start-stream") (result i32) - (local $ret i32) (local $ret64 i64) - (local $rs i32) - - ;; create a new stream, return the readable end to the caller - (local.set $ret64 (call $stream.new)) - (global.set $ws (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $rs (i32.wrap_i64 (local.get $ret64))) - - ;; create two resources and write them into a buffer to pass to stream.write - (global.set $res1 (call $resource.new (i32.const 50))) - (global.set $res2 (call $resource.new (i32.const 51))) - (i32.store (i32.const 8) (global.get $res1)) - (i32.store (i32.const 12) (global.get $res2)) - - ;; start a write which will block - (local.set $ret (call $stream.write (global.get $ws) (i32.const 8) (i32.const 2))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; check that this instance still owns both resources (ownership has not - ;; yet been transferred). - (if (i32.ne (i32.const 50) (call $resource.rep (global.get $res1))) - (then unreachable)) - (if (i32.ne (i32.const 51) (call $resource.rep (global.get $res2))) - (then unreachable)) - - (local.get $rs) - ) - (func $cancel-write (export "cancel-write") - (local $ret i32) - - ;; cancel the write, confirming that the first element was transferred - (local.set $ret (call $stream.cancel-write (global.get $ws))) - (if (i32.ne (i32.const 0x11 (; DROPPED=1 | (1 << 4) ;)) (local.get $ret)) - (then unreachable)) - - ;; we still own $res2 - (if (i32.ne (i32.const 51) (call $resource.rep (global.get $res2))) - (then unreachable)) - - (call $stream.drop-writable (global.get $ws)) - ) - (func $R.foo (export "R.foo") (param $rep i32) (result i32) - (i32.add (local.get $rep) (i32.const 50)) - ) - (func $fail-accessing-res1 (export "fail-accessing-res1") - ;; boom - (call $resource.rep (global.get $res1)) - unreachable - ) - ) - (type $R (resource (rep i32))) - (type $ST (stream (own $R))) - (canon resource.new $R (core func $resource.new)) - (canon resource.rep $R (core func $resource.rep)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.cancel-write $ST (core func $stream.cancel-write)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "resource.new" (func $resource.new)) - (export "resource.rep" (func $resource.rep)) - (export "stream.new" (func $stream.new)) - (export "stream.write" (func $stream.write)) - (export "stream.cancel-write" (func $stream.cancel-write)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (export $R' "R" (type $R)) - (func (export "[method]R.foo") async (param "self" (borrow $R')) (result u32) (canon lift (core func $core "R.foo"))) - (func (export "start-stream") async (result (stream (own $R'))) (canon lift (core func $core "start-stream"))) - (func (export "cancel-write") async (canon lift (core func $core "cancel-write"))) - (func (export "fail-accessing-res1") async (canon lift (core func $core "fail-accessing-res1"))) - ) - - (component $Consumer - (import "producer" (instance $producer - (export "R" (type $R (sub resource))) - (export "[method]R.foo" (func async (param "self" (borrow $R)) (result u32))) - (export "start-stream" (func async (result (stream (own $R))))) - (export "cancel-write" (func async)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "R.foo" (func $R.foo (param i32) (result i32))) - (import "" "start-stream" (func $start-stream (result i32))) - (import "" "cancel-write" (func $cancel-write)) - - (func $run (export "run") (result i32) - (local $ret i32) (local $rs i32) - (local $res1 i32) - - ;; get the readable end of a stream which has a pending write - (local.set $rs (call $start-stream)) - (if (i32.ne (local.get $rs) (i32.const 1)) - (then unreachable)) - - ;; read only 1 (of the 2 pending) elements, which won't block - (i64.store (i32.const 8) (i64.const 0xdeadbeefdeadbeef)) - (local.set $ret (call $stream.read (local.get $rs) (i32.const 8) (i32.const 1))) - (if (i32.ne (i32.const 0x10) (local.get $ret)) - (then unreachable)) - - ;; only 1 handle should have been transferred - (local.set $res1 (i32.load (i32.const 8))) - (if (i32.ne (i32.load (i32.const 12)) (i32.const 0xdeadbeef)) - (then unreachable)) - - ;; check that we got the first resource and it works - (local.set $ret (call $R.foo (local.get $res1))) - (if (i32.ne (i32.const 100) (local.get $ret)) - (then unreachable)) - - ;; drop the stream and then let $C run and assert stuff - (call $stream.drop-readable (local.get $rs)) - (call $cancel-write) - - (i32.const 42) - ) - ) - (alias export $producer "R" (type $R)) - (type $ST (stream (own $R))) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon lower (func $producer "[method]R.foo") (core func $R.foo')) - (canon lower (func $producer "start-stream") (core func $start-stream')) - (canon lower (func $producer "cancel-write") (core func $cancel-write')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "stream.read" (func $stream.read)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "R.foo" (func $R.foo')) - (export "start-stream" (func $start-stream')) - (export "cancel-write" (func $cancel-write')) - )))) - (func (export "run") async (result u32) (canon lift - (core func $core "run") - )) - ) - - (instance $producer (instantiate $Producer)) - (instance $consumer (instantiate $Consumer (with "producer" (instance $producer)))) - (func (export "run") (alias export $consumer "run")) - (func (export "fail-accessing-res1") (alias export $producer "fail-accessing-res1")) -) -(assert_return (invoke "run") (u32.const 42)) -(assert_trap (invoke "fail-accessing-res1") "unknown handle index 3") diff --git a/parser/src/test/resources/spec-tests/async/same-component-stream-future.wast b/parser/src/test/resources/spec-tests/async/same-component-stream-future.wast deleted file mode 100644 index 18d4a14..0000000 --- a/parser/src/test/resources/spec-tests/async/same-component-stream-future.wast +++ /dev/null @@ -1,259 +0,0 @@ -;; This test tests same-component reading/writing of a stream and future -;; from the same component instance (which either traps or succeeds), -;; depending on the element type. - -(component definition $Tester - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $M - (import "" "mem" (memory 1)) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "future.newb" (func $future.newb (result i64))) - (import "" "future.readb" (func $future.readb (param i32 i32) (result i32))) - (import "" "future.writeb" (func $future.writeb (param i32 i32) (result i32))) - (import "" "stream.newb" (func $stream.newb (result i64))) - (import "" "stream.readb" (func $stream.readb (param i32 i32 i32) (result i32))) - (import "" "stream.writeb" (func $stream.writeb (param i32 i32 i32) (result i32))) - (import "" "future.newc" (func $future.newc (result i64))) - (import "" "future.readc" (func $future.readc (param i32 i32) (result i32))) - (import "" "future.writec" (func $future.writec (param i32 i32) (result i32))) - - (func (export "test-empty") (result i32) - (local $ret i32) (local $ret64 i64) - (local $rx i32) (local $tx i32) - - ;; test future reader then writer - (local.set $ret64 (call $future.new)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $future.read (local.get $rx) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $future.write (local.get $tx) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - ;; test future writer than reader - (local.set $ret64 (call $future.new)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $future.write (local.get $tx) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $future.read (local.get $rx) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - ;; test stream reader then writer - (local.set $ret64 (call $stream.new)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $stream.read (local.get $rx) (i32.const 0xdeadbeef) (i32.const 1))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $stream.write (local.get $tx) (i32.const 0xdeadbeef) (i32.const 1))) - (if (i32.ne (i32.const 0x10 (; COMPLETED=0 | (1<<4) ;)) (local.get $ret)) - (then unreachable)) - - ;; test stream writer than reader - (local.set $ret64 (call $stream.new)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $stream.write (local.get $tx) (i32.const 0xdeadbeef) (i32.const 1))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $stream.read (local.get $rx) (i32.const 0xdeadbeef) (i32.const 1))) - (if (i32.ne (i32.const 0x10 (; COMPLETED=0 | (1<<4) ;)) (local.get $ret)) - (then unreachable)) - - (i32.const 42) - ) - - (func $test-stream (param $srcp i32) (param $dstp i32) - (local $ret i32) (local $ret64 i64) - (local $rx i32) (local $tx i32) - - ;; test stream reader then writer - (i64.store (local.get $dstp) (i64.const 0)) - (i64.store (local.get $srcp) (i64.const 0x0123456789abcdef)) - (local.set $ret64 (call $stream.newb)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $stream.readb (local.get $rx) (local.get $dstp) (i32.const 8))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $stream.writeb (local.get $tx) (local.get $srcp) (i32.const 8))) - (if (i32.ne (i32.const 0x80 (; COMPLETED=0 | (8<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i64.ne (i64.load (local.get $dstp)) (i64.const 0x0123456789abcdef)) - (then unreachable)) - - ;; test stream writer than reader - (i64.store (local.get $dstp) (i64.const 0)) - (i64.store (local.get $srcp) (i64.const 0x0123456789abcdef)) - (local.set $ret64 (call $stream.newb)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $stream.writeb (local.get $tx) (local.get $srcp) (i32.const 8))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $stream.readb (local.get $rx) (local.get $dstp) (i32.const 8))) - (if (i32.ne (i32.const 0x80 (; COMPLETED=0 | (8<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i64.ne (i64.load (local.get $dstp)) (i64.const 0x0123456789abcdef)) - (then unreachable)) - ) - - (func (export "test-bytes") (result i32) - (local $ret i32) (local $ret64 i64) - (local $rx i32) (local $tx i32) - (local $dstp i32) (local $srcp i32) - - ;; because pointers must be aligned and futures are single-element, - ;; it's not possible to test the interesting overlap case - (local.set $srcp (i32.const 16)) - (local.set $dstp (i32.const 17)) - (i32.store8 (local.get $dstp) (i32.const 0)) - (i32.store8 (local.get $srcp) (i32.const 42)) - - ;; test future reader then writer - (local.set $ret64 (call $future.newb)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $future.readb (local.get $rx) (local.get $dstp))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $future.writeb (local.get $tx) (local.get $srcp))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.load8_u (local.get $dstp)) (i32.const 42)) - (then unreachable)) - - ;; reset memory and then test future writer than reader - (i32.store8 (local.get $dstp) (i32.const 0)) - (i32.store8 (local.get $srcp) (i32.const 42)) - (local.set $ret64 (call $future.newb)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $future.writeb (local.get $tx) (local.get $srcp))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $future.readb (local.get $rx) (local.get $dstp))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.load8_u (local.get $dstp)) (i32.const 42)) - (then unreachable)) - - ;; test a bunch of different overlapping cases - (call $test-stream (i32.const 16) (i32.const 8)) - (call $test-stream (i32.const 16) (i32.const 9)) - (call $test-stream (i32.const 16) (i32.const 10)) - (call $test-stream (i32.const 16) (i32.const 11)) - (call $test-stream (i32.const 16) (i32.const 12)) - (call $test-stream (i32.const 16) (i32.const 13)) - (call $test-stream (i32.const 16) (i32.const 14)) - (call $test-stream (i32.const 16) (i32.const 15)) - (call $test-stream (i32.const 16) (i32.const 16)) - (call $test-stream (i32.const 16) (i32.const 17)) - (call $test-stream (i32.const 16) (i32.const 18)) - (call $test-stream (i32.const 16) (i32.const 19)) - (call $test-stream (i32.const 16) (i32.const 20)) - (call $test-stream (i32.const 16) (i32.const 21)) - (call $test-stream (i32.const 16) (i32.const 22)) - (call $test-stream (i32.const 16) (i32.const 23)) - (call $test-stream (i32.const 16) (i32.const 24)) - - (i32.const 43) - ) - - (func (export "test-no-read-char") - (local $ret i32) (local $ret64 i64) - (local $rx i32) (local $tx i32) - (local.set $ret64 (call $future.newc)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $future.readc (local.get $rx) (i32.const 0))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (call $future.writec (local.get $tx) (i32.const 0)) - unreachable - ) - - (func (export "test-no-write-char") - (local $ret i32) (local $ret64 i64) - (local $rx i32) (local $tx i32) - (local.set $ret64 (call $future.newc)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $future.writec (local.get $tx) (i32.const 0))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (call $future.readc (local.get $rx) (i32.const 0)) - unreachable - ) - ) - (type $FT (future)) - (type $ST (stream)) - (type $FTB (future u8)) - (type $STB (stream u8)) - (type $FTC (future char)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon future.new $FT (core func $future.new)) - (canon future.read $FT async (core func $future.read)) - (canon future.write $FT async (core func $future.write)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST async (core func $stream.read)) - (canon stream.write $ST async (core func $stream.write)) - (canon future.new $FTB (core func $future.newb)) - (canon future.read $FTB async (memory $memory "mem") (core func $future.readb)) - (canon future.write $FTB async (memory $memory "mem") (core func $future.writeb)) - (canon stream.new $STB (core func $stream.newb)) - (canon stream.read $STB async (memory $memory "mem") (core func $stream.readb)) - (canon stream.write $STB async (memory $memory "mem") (core func $stream.writeb)) - (canon future.new $FTC (core func $future.newc)) - (canon future.read $FTC async (memory $memory "mem") (core func $future.readc)) - (canon future.write $FTC async (memory $memory "mem") (core func $future.writec)) - (core instance $m (instantiate $M (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "future.new" (func $future.new)) - (export "future.read" (func $future.read)) - (export "future.write" (func $future.write)) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "future.newb" (func $future.newb)) - (export "future.readb" (func $future.readb)) - (export "future.writeb" (func $future.writeb)) - (export "stream.newb" (func $stream.newb)) - (export "stream.readb" (func $stream.readb)) - (export "stream.writeb" (func $stream.writeb)) - (export "future.newc" (func $future.newc)) - (export "future.readc" (func $future.readc)) - (export "future.writec" (func $future.writec)) - )))) - (func (export "test-empty") (result u32) (canon lift (core func $m "test-empty"))) - (func (export "test-bytes") (result u32) (canon lift (core func $m "test-bytes"))) - (func (export "test-no-read-char") (canon lift (core func $m "test-no-read-char"))) - (func (export "test-no-write-char") (canon lift (core func $m "test-no-write-char"))) -) -(component instance $i $Tester) -(assert_return (invoke "test-empty") (u32.const 42)) -(component instance $i $Tester) -(assert_return (invoke "test-bytes") (u32.const 43)) -(component instance $i $Tester) -(assert_trap (invoke "test-no-read-char") "cannot read from and write to intra-component future") -(component instance $i $Tester) -(assert_trap (invoke "test-no-write-char") "cannot read from and write to intra-component future") diff --git a/parser/src/test/resources/spec-tests/async/sync-barges-in.wast b/parser/src/test/resources/spec-tests/async/sync-barges-in.wast deleted file mode 100644 index 3161f93..0000000 --- a/parser/src/test/resources/spec-tests/async/sync-barges-in.wast +++ /dev/null @@ -1,311 +0,0 @@ -;; This test tests that a blocked previous sync- or async-lifted callee -;; can be synchronously reentered by a sync-typed function without the -;; usual backpressure triggering. The $Tester component has two nested -;; components $C and $D, where $D imports and calls $C. $C contains utilities -;; used by $D to perform all the tests. -(component definition $Tester - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "thread.yield" (func $thread.yield (result i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - - (global $unblock-value (mut i32) (i32.const 0)) - - ;; $ws is waited on by 'blocker' and added to by 'unblocker' - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - (func (export "blocker") - ;; wait on $ws, which is initially empty, but will be populated with - ;; a completed future when "unblocker" synchronously barges in. - (local $ret i32) - (local.set $ret (call $waitable-set.wait (global.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (i32.load (i32.const 4))) - (then unreachable)) - - (call $task.return (global.get $unblock-value)) - ) - - (func (export "blocker-cb") (result i32) - ;; wait on $ws, which is initially empty, but will be populated with - ;; a completed future when "unblocker" synchronously barges in. - (i32.or - (i32.const 2 (; WAIT ;)) - (i32.shl (global.get $ws) (i32.const 4))) - ) - (func (export "blocker-cb-cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $payload)) - (then unreachable)) - - (call $task.return (global.get $unblock-value)) - (i32.const 0 (; EXIT ;)) - ) - - (func $unblocker (export "unblocker") (param $val i32) - (local $ret i32) (local $ret64 i64) - (local $futr i32) (local $futw i32) - - ;; create read/write futures that will be used to unblock 'blocker' - (local.set $ret64 (call $future.new)) - (local.set $futr (i32.wrap_i64 (local.get $ret64))) - (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - - ;; perform a future.read which will block, and add this future to the waitable-set - ;; being waited on by 'blocker' - (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (local.get $futr) (global.get $ws)) - - ;; perform a future.write which will rendezvous with the write and complete - (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - (global.set $unblock-value (local.get $val)) - ) - - (func (export "yielder") - (drop (call $thread.yield)) - (call $task.return (global.get $unblock-value)) - ) - (func (export "yielder-cb") (result i32) - (i32.const 1 (; YIELD ;)) - ) - (func (export "yielder-cb-cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - (if (i32.ne (i32.const 0 (; EVENT_NONE ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (i32.const 0) (local.get $index)) - (then unreachable)) - (if (i32.ne (i32.const 0) (local.get $payload)) - (then unreachable)) - (call $task.return (global.get $unblock-value)) - (i32.const 0 (; EXIT ;)) - ) - (func (export "poker") (param $val i32) - (global.set $unblock-value (local.get $val)) - ) - ) - (type $FT (future)) - (canon task.return (result u32) (core func $task.return)) - (canon thread.yield (core func $thread.yield)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon future.new $FT (core func $future.new)) - (canon future.read $FT async (core func $future.read)) - (canon future.write $FT async (core func $future.write)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "thread.yield" (func $thread.yield)) - (export "task.return" (func $task.return)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "future.new" (func $future.new)) - (export "future.read" (func $future.read)) - (export "future.write" (func $future.write)) - )))) - (type $R (resource (rep i32) (dtor (func $cm "unblocker")))) - (type $S (resource (rep i32) (dtor (func $cm "poker")))) - (canon resource.new $R (core func $new-R)) - (canon resource.new $S (core func $new-S)) - (export $R' "R" (type $R)) - (export $S' "S" (type $S)) - (func (export "new-R") (param "rep" u32) (result (own $R')) (canon lift (core func $new-R))) - (func (export "blocker") async (result u32) (canon lift (core func $cm "blocker") async)) - (func (export "blocker-cb") async (result u32) (canon lift (core func $cm "blocker-cb") async (callback (func $cm "blocker-cb-cb")))) - (func (export "unblocker") (param "val" u32) (canon lift (core func $cm "unblocker"))) - (func (export "new-S") (param "rep" u32) (result (own $S')) (canon lift (core func $new-S))) - (func (export "yielder") async (result u32) (canon lift (core func $cm "yielder") async)) - (func (export "yielder-cb") async (result u32) (canon lift (core func $cm "yielder-cb") async (callback (func $cm "yielder-cb-cb")))) - (func (export "poker") (param "val" u32) (canon lift (core func $cm "poker"))) - ) - (component $D - (import "c" (instance $c - (export "R" (type $R (sub resource))) - (export "new-R" (func (param "rep" u32) (result (own $R)))) - (export "blocker" (func async (result u32))) - (export "blocker-cb" (func async (result u32))) - (export "unblocker" (func (param "val" u32))) - (export "S" (type $S (sub resource))) - (export "new-S" (func (param "rep" u32) (result (own $S)))) - (export "yielder" (func async (result u32))) - (export "yielder-cb" (func async (result u32))) - (export "poker" (func (param "val" u32))) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "subtask.drop" (func $subtask.drop (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.drop" (func $waitable-set.drop (param i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "waitable-set.poll" (func $waitable-set.poll (param i32 i32) (result i32))) - (import "" "new-R" (func $new-R (param i32) (result i32))) - (import "" "drop-R" (func $drop-R (param i32))) - (import "" "blocker" (func $blocker (param i32) (result i32))) - (import "" "blocker-cb" (func $blocker-cb (param i32) (result i32))) - (import "" "unblocker" (func $unblocker (param i32))) - (import "" "new-S" (func $new-S (param i32) (result i32))) - (import "" "drop-S" (func $drop-S (param i32))) - (import "" "yielder" (func $yielder (param i32) (result i32))) - (import "" "yielder-cb" (func $yielder-cb (param i32) (result i32))) - (import "" "poker" (func $poker (param i32))) - - (func $wait-for-return (param $subtask i32) (param $retp i32) (param $expect i32) - (local $outp i32) - (local $ws i32) (local $event_code i32) - - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtask) (local.get $ws)) - (local.set $outp (i32.const 32)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $outp))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (local.get $outp))) - (then unreachable)) - (if (i32.ne (i32.const 2 (; RETURNED=2 ;)) (i32.load offset=4 (local.get $outp))) - (then unreachable)) - (if (i32.ne (local.get $expect) (i32.load (local.get $retp))) - (then unreachable)) - (call $subtask.drop (local.get $subtask)) - (call $waitable-set.drop (local.get $ws)) - ) - - (func (export "run") (result i32) - (local $ret i32) (local $retp i32) - (local $subtask i32) (local $handle i32) - - (local.set $retp (i32.const 8)) - - ;; call $blocker which will block during a synchronous function. - ;; normally calling another function would hit backpressure until - ;; $blocker was done, but calling the sync-typed function $unblocker - ;; barges in synchronously. - (local.set $ret (call $blocker (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $unblocker (i32.const 90)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 90)) - - ;; do it all again, but this time unblock via resource.drop: - (local.set $handle (call $new-R (i32.const 91))) - (local.set $ret (call $blocker (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $drop-R (local.get $handle)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 91)) - - ;; do both of the above again, but for $blocker-cb instead of $blocker - (local.set $ret (call $blocker-cb (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $unblocker (i32.const 92)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 92)) - (local.set $handle (call $new-R (i32.const 93))) - (local.set $ret (call $blocker-cb (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $drop-R (local.get $handle)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 93)) - - ;; now do all the above again, but for 'yielder'/'yielder-cb', which - ;; yield, instead of waiting, using 'poker' to deliver a specific value - (local.set $ret (call $yielder (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $poker (i32.const 94)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 94)) - (local.set $handle (call $new-S (i32.const 95))) - (local.set $ret (call $yielder (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $drop-S (local.get $handle)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 95)) - (local.set $ret (call $yielder-cb (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $poker (i32.const 96)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 96)) - (local.set $handle (call $new-S (i32.const 97))) - (local.set $ret (call $yielder-cb (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $drop-S (local.get $handle)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 97)) - - (i32.const 100) - ) - ) - (alias export $c "R" (type $R)) - (alias export $c "S" (type $S)) - (canon resource.drop $R (core func $drop-R')) - (canon resource.drop $S (core func $drop-S')) - (canon subtask.drop (core func $subtask.drop)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.drop (core func $waitable-set.drop)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon waitable-set.poll (memory $memory "mem") (core func $waitable-set.poll)) - (canon lower (func $c "new-R") (core func $new-R')) - (canon lower (func $c "blocker") (memory $memory "mem") async (core func $blocker')) - (canon lower (func $c "blocker-cb") (memory $memory "mem") async (core func $blocker-cb')) - (canon lower (func $c "unblocker") (core func $unblocker')) - (canon lower (func $c "new-S") (core func $new-S')) - (canon lower (func $c "yielder") (memory $memory "mem") async (core func $yielder')) - (canon lower (func $c "yielder-cb") (memory $memory "mem") async (core func $yielder-cb')) - (canon lower (func $c "poker") (core func $poker')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "subtask.drop" (func $subtask.drop)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.drop" (func $waitable-set.drop)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "waitable-set.poll" (func $waitable-set.poll)) - (export "new-R" (func $new-R')) - (export "drop-R" (func $drop-R')) - (export "blocker" (func $blocker')) - (export "blocker-cb" (func $blocker-cb')) - (export "unblocker" (func $unblocker')) - (export "new-S" (func $new-S')) - (export "drop-S" (func $drop-S')) - (export "yielder" (func $yielder')) - (export "yielder-cb" (func $yielder-cb')) - (export "poker" (func $poker')) - )))) - (func (export "run") async (result u32) (canon lift (core func $core "run"))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "run") (alias export $d "run")) -) - -(component instance $i $Tester) -(assert_return (invoke "run") (u32.const 100)) diff --git a/parser/src/test/resources/spec-tests/async/sync-streams.wast b/parser/src/test/resources/spec-tests/async/sync-streams.wast deleted file mode 100644 index 364ba9c..0000000 --- a/parser/src/test/resources/spec-tests/async/sync-streams.wast +++ /dev/null @@ -1,178 +0,0 @@ -;; This test calls sync stream.write in $C.get and sync stream.read in $C.set. -;; Both of these calls block because $C is first to the rendezvous. But since -;; they are synchronous, control flow switches to $D.run which will do -;; a complementary read/write that rendezvous, and then control flow will -;; switch back to $C.get/set where the synchronous read/write will return -;; without blocking. -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.return0" (func $task.return0)) - (import "" "task.return1" (func $task.return1 (param i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - (func (export "get") (result i32) - (local $ret i32) (local $ret64 i64) - (local $tx i32) (local $rx i32) - (local $bufp i32) - - ;; ($rx, $tx) = stream.new - (local.set $ret64 (call $stream.new)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - - ;; return $rx - (call $task.return1 (local.get $rx)) - - ;; (stream.write $tx $bufp 4) will block and, because called - ;; synchronously, switch to the caller who will read and rendezvous - (local.set $bufp (i32.const 16)) - (i32.store (local.get $bufp) (i32.const 0x01234567)) - (local.set $ret (call $stream.write (local.get $tx) (local.get $bufp) (i32.const 4))) - (if (i32.ne (i32.const 0x41 (; DROPPED=1 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - - (call $stream.drop-writable (local.get $tx)) - (return (i32.const 0 (; EXIT ;))) - ) - (func (export "get_cb") (param i32 i32 i32) (result i32) - unreachable - ) - - (func (export "set") (param $rx i32) (result i32) - (local $ret i32) (local $ret64 i64) - (local $bufp i32) - - ;; return immediately so that the caller can just call synchronously - (call $task.return0) - - ;; (stream.read $rx $bufp 4) will block and, because called - ;; synchronously, switch to the caller who will write and rendezvous - (local.set $bufp (i32.const 16)) - (local.set $ret (call $stream.read (local.get $rx) (local.get $bufp) (i32.const 4))) - (if (i32.ne (i32.const 0x41 (; DROPPED=1 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0x89abcdef) (i32.load (local.get $bufp))) - (then unreachable)) - - (call $stream.drop-readable (local.get $rx)) - (return (i32.const 0 (; EXIT ;))) - ) - (func (export "set_cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (type $ST (stream u8)) - (canon task.return (memory $memory "mem") (core func $task.return0)) - (canon task.return (result $ST) (memory $memory "mem") (core func $task.return1)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST (memory $memory "mem") (core func $stream.read)) - (canon stream.write $ST (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return0" (func $task.return0)) - (export "task.return1" (func $task.return1)) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (func (export "get") async (result (stream u8)) (canon lift - (core func $cm "get") - async (memory $memory "mem") (callback (func $cm "get_cb")) - )) - (func (export "set") async (param "in" (stream u8)) (canon lift - (core func $cm "set") - async (memory $memory "mem") (callback (func $cm "set_cb")) - )) - ) - (component $D - (import "get" (func $get async (result (stream u8)))) - (import "set" (func $set async (param "in" (stream u8)))) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - (import "" "get" (func $get (result i32))) - (import "" "set" (func $set (param i32))) - - (func (export "run") (result i32) - (local $ret i32) (local $ret64 i64) - (local $rx i32) (local $tx i32) - (local $bufp i32) - - ;; $rx = $C.get() - (local.set $rx (call $get)) - - ;; (stream.read $rx $bufp 4) will succeed without blocking - (local.set $bufp (i32.const 20)) - (local.set $ret (call $stream.read (local.get $rx) (local.get $bufp) (i32.const 4))) - (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0x01234567) (i32.load (local.get $bufp))) - (then unreachable)) - - (call $stream.drop-readable (local.get $rx)) - - ;; ($rx, $tx) = stream.new - ;; $C.set($rx) - (local.set $ret64 (call $stream.new)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (call $set (local.get $rx)) - - ;; (stream.write $tx $bufp 4) will succeed without blocking - (local.set $bufp (i32.const 16)) - (local.set $ret (call $stream.write (local.get $tx) (local.get $bufp) (i32.const 4))) - (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - - (call $stream.drop-writable (local.get $tx)) - (i32.const 42) - ) - ) - (type $ST (stream u8)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (canon lower (func $get) (core func $get')) - (canon lower (func $set) (core func $set')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "stream.drop-writable" (func $stream.drop-writable)) - (export "get" (func $get')) - (export "set" (func $set')) - )))) - (func (export "run") async (result u32) (canon lift (core func $dm "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D - (with "get" (func $c "get")) - (with "set" (func $c "set")) - )) - (func (export "run") (alias export $d "run")) -) -(assert_return (invoke "run") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/async/trap-if-block-and-sync.wast b/parser/src/test/resources/spec-tests/async/trap-if-block-and-sync.wast deleted file mode 100644 index e2dc06b..0000000 --- a/parser/src/test/resources/spec-tests/async/trap-if-block-and-sync.wast +++ /dev/null @@ -1,343 +0,0 @@ -;; The $Tester component has two nested components $C and $D, where $D imports -;; and calls $C. $C contains utilities used by $D to perform all the tests. -;; Most of the tests trap, $Tester exports 1 function per test and a fresh -;; $Tester is created to run each test. -(component definition $Tester - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (func (export "sync-async-func") - unreachable - ) - (func (export "async-async-func") (result i32) - unreachable - ) - (func (export "async-async-func-cb") (param i32 i32 i32) (result i32) - unreachable - ) - (func (export "sync-blocks-and-traps") - (call $waitable-set.wait (call $waitable-set.new) (i32.const 0xdeadbeef)) - unreachable - ) - ) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (core instance $cm (instantiate $CM (with "" (instance - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - )))) - (func (export "sync-async-func") async (canon lift (core func $cm "sync-async-func"))) - (func (export "async-async-func") async (canon lift (core func $cm "async-async-func") async (callback (func $cm "async-async-func-cb")))) - (func (export "sync-blocks-and-traps") (canon lift (core func $cm "sync-blocks-and-traps"))) - ) - (component $D - (import "c" (instance $c - (export "sync-async-func" (func async)) - (export "async-async-func" (func async)) - (export "sync-blocks-and-traps" (func)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core module $Table - (table (export "__indirect_function_table") 2 funcref)) - (core instance $memory (instantiate $Memory)) - (core instance $table (instantiate $Table)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) - (import "" "thread.yield" (func $thread.yield (result i32))) - ;;(import "" "thread.yield-to" (func $thread.yield-to (param i32) (result i32))) - ;;(import "" "thread.switch-to" (func $thread.switch-to (param i32) (result i32))) - ;;(import "" "thread.resume-later" (func $thread.resume-later (param i32))) - (import "" "thread.index" (func $thread-index (result i32))) - (import "" "thread.suspend" (func $thread.suspend (result i32))) - (import "" "thread.new-indirect" (func $thread.new-indirect (param i32 i32) (result i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "waitable-set.poll" (func $waitable-set.poll (param i32 i32) (result i32))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "stream.cancel-read" (func $stream.cancel-read (param i32) (result i32))) - (import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32))) - (import "" "future.cancel-read" (func $future.cancel-read (param i32) (result i32))) - (import "" "future.cancel-write" (func $future.cancel-write (param i32) (result i32))) - (import "" "await-sync-async-func" (func $await-sync-async-func)) - (import "" "await-async-async-func" (func $await-async-async-func)) - (import "" "sync-blocks-and-traps" (func $sync-blocks-and-traps)) - (import "" "__indirect_function_table" (table $indirect-function-table 2 funcref)) - - (func (export "unreachable-cb") (param i32 i32 i32) (result i32) - unreachable - ) - (func (export "return-42-cb") (param i32 i32 i32) (result i32) - (call $task.return (i32.const 42)) - (i32.const 0 (; EXIT ;)) - ) - - (func (export "trap-if-sync-call-async1") - (call $await-sync-async-func) - ) - (func (export "trap-if-sync-call-async2") - (call $await-async-async-func) - ) - (func (export "trap-if-async-calls-sync-and-blocks") (result i32) - (call $sync-blocks-and-traps) - unreachable - ) - (func (export "trap-if-suspend") - (call $thread.suspend) - unreachable - ) - (func (export "trap-if-wait") - (call $waitable-set.wait (call $waitable-set.new) (i32.const 0xdeadbeef)) - unreachable - ) - (func (export "trap-if-wait-cb") (result i32) - (i32.or - (i32.const 2 (; WAIT ;)) - (i32.shl (call $waitable-set.new) (i32.const 4))) - ) - (func (export "poll-is-fine") (result i32) - (local $ret i32) - (local.set $ret (call $waitable-set.poll (call $waitable-set.new) (i32.const 0))) - (if (i32.ne (i32.const 0 (; NONE ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0) (i32.load (i32.const 0))) - (then unreachable)) - (if (i32.ne (i32.const 0) (i32.load (i32.const 4))) - (then unreachable)) - (i32.const 42) - ) - (func (export "trap-if-invalid-callback-code") (param $invalid-code i32) (result i32) - (i32.or - (local.get $invalid-code) - (i32.shl (call $waitable-set.new) (i32.const 4))) - ) - (func (export "yield-is-fine") (result i32) - (drop (call $thread.yield)) - (i32.const 42) - ) - (func (export "yield-is-fine-cb") (result i32) - (i32.or - (i32.const 1 (; YIELD ;)) - (i32.shl (i32.const 0xdead) (i32.const 4))) - ) - (func $thread-start-noop (param i32)) - (elem (table $indirect-function-table) (i32.const 0) func $thread-start-noop) - (func (export "yield-to-is-fine") (result i32) - ;; TODO: rename and reenable - ;;(drop (call $thread.yield-to (call $thread.new-indirect (i32.const 0) (i32.const 0)))) - (i32.const 42) - ) - (func $thread-start-switch-back (param i32) - ;;(drop (call $thread.switch-to (local.get 0))) - ) - (elem (table $indirect-function-table) (i32.const 1) func $thread-start-switch-back) - (func (export "switch-to-is-fine") (result i32) - ;; TODO: rename and reenable - ;;(drop (call $thread.switch-to (call $thread.new-indirect (i32.const 1) (call $thread-index)))) - (i32.const 42) - ) - (func (export "resume-later-is-fine") (result i32) - ;; TODO: rename and reenable - ;;(call $thread.resume-later (call $thread.new-indirect (i32.const 0) (i32.const 0))) - (i32.const 42) - ) - (func (export "trap-if-sync-cancel") - (call $subtask.cancel (i32.const 0xdeadbeef)) - unreachable - ) - (func (export "trap-if-sync-stream-read") - (call $stream.read (i32.const 0xdead) (i32.const 0xbeef) (i32.const 0xdead)) - unreachable - ) - (func (export "trap-if-sync-stream-write") - (call $stream.write (i32.const 0xdead) (i32.const 0xbeef) (i32.const 0xdead)) - unreachable - ) - (func (export "trap-if-sync-future-read") - (call $future.read (i32.const 0xdead) (i32.const 0xdeadbeef)) - unreachable - ) - (func (export "trap-if-sync-future-write") - (call $future.write (i32.const 0xdead) (i32.const 0xdeadbeef)) - unreachable - ) - (func (export "trap-if-sync-stream-cancel-read") - (call $stream.cancel-read (i32.const 0xdead)) - unreachable - ) - (func (export "trap-if-sync-stream-cancel-write") - (call $stream.cancel-write (i32.const 0xdead)) - unreachable - ) - (func (export "trap-if-sync-future-cancel-read") - (call $future.cancel-read (i32.const 0xdead) (i32.const 0xdeadbeef)) - unreachable - ) - (func (export "trap-if-sync-future-cancel-write") - (call $future.cancel-write (i32.const 0xdead) (i32.const 0xdeadbeef)) - unreachable - ) - ) - (type $FT (future u8)) - (type $ST (stream u8)) - (core type $start-func-ty (func (param i32))) - (alias core export $table "__indirect_function_table" (core table $indirect-function-table)) - (core func $thread.new-indirect - (canon thread.new-indirect $start-func-ty (table $indirect-function-table))) - (canon task.return (result u32) (core func $task.return)) - (canon subtask.cancel (core func $subtask.cancel)) - (canon thread.yield (core func $thread.yield)) - (canon thread.suspend (core func $thread.suspend)) - ;;(canon thread.yield-to (core func $thread.yield-to)) - ;;(canon thread.switch-to (core func $thread.switch-to)) - ;;(canon thread.resume-later (core func $thread.resume-later)) - (canon thread.index (core func $thread.index)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon waitable-set.poll (memory $memory "mem") (core func $waitable-set.poll)) - (canon stream.read $ST (memory $memory "mem") (core func $stream.read)) - (canon stream.write $ST (memory $memory "mem") (core func $stream.write)) - (canon future.read $FT (memory $memory "mem") (core func $future.read)) - (canon future.write $FT (memory $memory "mem") (core func $future.write)) - (canon stream.cancel-read $ST (core func $stream.cancel-read)) - (canon stream.cancel-write $ST (core func $stream.cancel-write)) - (canon future.cancel-read $FT (core func $future.cancel-read)) - (canon future.cancel-write $FT (core func $future.cancel-write)) - (canon lower (func $c "sync-async-func") (core func $await-sync-async-func')) - (canon lower (func $c "async-async-func") (core func $await-async-async-func')) - (canon lower (func $c "sync-blocks-and-traps") (core func $sync-blocks-and-traps')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "subtask.cancel" (func $subtask.cancel)) - (export "thread.yield" (func $thread.yield)) - (export "thread.suspend" (func $thread.suspend)) - ;;(export "thread.yield-to" (func $thread.yield-to)) - ;;(export "thread.switch-to" (func $thread.switch-to)) - ;;(export "thread.resume-later" (func $thread.resume-later)) - (export "thread.index" (func $thread.index)) - (export "thread.new-indirect" (func $thread.new-indirect)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "waitable-set.poll" (func $waitable-set.poll)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "future.read" (func $future.read)) - (export "future.write" (func $future.write)) - (export "stream.cancel-read" (func $stream.cancel-read)) - (export "stream.cancel-write" (func $stream.cancel-write)) - (export "future.cancel-read" (func $future.cancel-read)) - (export "future.cancel-write" (func $future.cancel-write)) - (export "await-sync-async-func" (func $await-sync-async-func')) - (export "await-async-async-func" (func $await-async-async-func')) - (export "sync-blocks-and-traps" (func $sync-blocks-and-traps')) - (export "__indirect_function_table" (table $indirect-function-table)) - )))) - (func (export "trap-if-suspend") (canon lift (core func $core "trap-if-suspend"))) - (func (export "trap-if-wait") (canon lift (core func $core "trap-if-wait"))) - (func (export "trap-if-wait-cb") async (canon lift (core func $core "trap-if-wait-cb") async (callback (func $core "unreachable-cb")))) - (func (export "poll-is-fine") (result u32) (canon lift (core func $core "poll-is-fine"))) - (func (export "trap-if-invalid-callback-code") async (param "invalid-code" u32) (canon lift (core func $core "trap-if-invalid-callback-code") async (callback (func $core "unreachable-cb")))) - (func (export "yield-is-fine") (result u32) (canon lift (core func $core "yield-is-fine"))) - (func (export "yield-is-fine-cb") async (result u32) (canon lift (core func $core "yield-is-fine-cb") async (callback (func $core "return-42-cb")))) - (func (export "yield-to-is-fine") (result u32) (canon lift (core func $core "yield-to-is-fine"))) - (func (export "switch-to-is-fine") (result u32) (canon lift (core func $core "switch-to-is-fine"))) - (func (export "resume-later-is-fine") (result u32) (canon lift (core func $core "resume-later-is-fine"))) - (func (export "trap-if-sync-call-async1") (canon lift (core func $core "trap-if-sync-call-async1"))) - (func (export "trap-if-sync-call-async2") (canon lift (core func $core "trap-if-sync-call-async2"))) - (func (export "trap-if-async-calls-sync-and-blocks") async (canon lift (core func $core "trap-if-async-calls-sync-and-blocks") async (callback (func $core "unreachable-cb")))) - (func (export "trap-if-sync-cancel") (canon lift (core func $core "trap-if-sync-cancel"))) - (func (export "trap-if-sync-stream-read") (canon lift (core func $core "trap-if-sync-stream-read"))) - (func (export "trap-if-sync-stream-write") (canon lift (core func $core "trap-if-sync-stream-write"))) - (func (export "trap-if-sync-future-read") (canon lift (core func $core "trap-if-sync-future-read"))) - (func (export "trap-if-sync-future-write") (canon lift (core func $core "trap-if-sync-future-write"))) - (func (export "trap-if-sync-stream-cancel-read") (canon lift (core func $core "trap-if-sync-stream-cancel-read"))) - (func (export "trap-if-sync-stream-cancel-write") (canon lift (core func $core "trap-if-sync-stream-cancel-write"))) - (func (export "trap-if-sync-future-cancel-read") (canon lift (core func $core "trap-if-sync-future-cancel-read"))) - (func (export "trap-if-sync-future-cancel-write") (canon lift (core func $core "trap-if-sync-future-cancel-write"))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "trap-if-sync-call-async1") (alias export $d "trap-if-sync-call-async1")) - (func (export "trap-if-sync-call-async2") (alias export $d "trap-if-sync-call-async2")) - (func (export "trap-if-async-calls-sync-and-blocks") (alias export $d "trap-if-async-calls-sync-and-blocks")) - (func (export "trap-if-suspend") (alias export $d "trap-if-suspend")) - (func (export "trap-if-wait") (alias export $d "trap-if-wait")) - (func (export "trap-if-wait-cb") (alias export $d "trap-if-wait-cb")) - (func (export "poll-is-fine") (alias export $d "poll-is-fine")) - (func (export "trap-if-invalid-callback-code") (alias export $d "trap-if-invalid-callback-code")) - (func (export "yield-is-fine") (alias export $d "yield-is-fine")) - (func (export "yield-is-fine-cb") (alias export $d "yield-is-fine-cb")) - (func (export "yield-to-is-fine") (alias export $d "yield-to-is-fine")) - (func (export "switch-to-is-fine") (alias export $d "switch-to-is-fine")) - (func (export "resume-later-is-fine") (alias export $d "resume-later-is-fine")) - (func (export "trap-if-sync-cancel") (alias export $d "trap-if-sync-cancel")) - (func (export "trap-if-sync-stream-read") (alias export $d "trap-if-sync-stream-read")) - (func (export "trap-if-sync-stream-write") (alias export $d "trap-if-sync-stream-write")) - (func (export "trap-if-sync-future-read") (alias export $d "trap-if-sync-future-read")) - (func (export "trap-if-sync-future-write") (alias export $d "trap-if-sync-future-write")) - (func (export "trap-if-sync-stream-cancel-read") (alias export $d "trap-if-sync-stream-cancel-read")) - (func (export "trap-if-sync-stream-cancel-write") (alias export $d "trap-if-sync-stream-cancel-write")) - (func (export "trap-if-sync-future-cancel-read") (alias export $d "trap-if-sync-future-cancel-read")) - (func (export "trap-if-sync-future-cancel-write") (alias export $d "trap-if-sync-future-cancel-write")) -) - -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-call-async1") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-call-async2") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-async-calls-sync-and-blocks") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-suspend") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-wait") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-wait-cb") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_return (invoke "poll-is-fine") (u32.const 42)) -(component instance $i $Tester) -(assert_trap (invoke "trap-if-invalid-callback-code" (u32.const 3)) "unsupported callback code") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-invalid-callback-code" (u32.const 4)) "unsupported callback code") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-invalid-callback-code" (u32.const 15)) "unsupported callback code") -(component instance $i $Tester) -(assert_return (invoke "yield-is-fine") (u32.const 42)) -(component instance $i $Tester) -(assert_return (invoke "yield-is-fine-cb") (u32.const 42)) -(component instance $i $Tester) -(assert_return (invoke "yield-to-is-fine") (u32.const 42)) -(component instance $i $Tester) -(assert_return (invoke "switch-to-is-fine") (u32.const 42)) -(component instance $i $Tester) -(assert_return (invoke "resume-later-is-fine") (u32.const 42)) -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-cancel") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-stream-read") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-stream-write") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-future-read") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-future-write") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-stream-cancel-read") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-stream-cancel-write") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-future-cancel-read") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-future-cancel-write") "cannot block a synchronous task before returning") diff --git a/parser/src/test/resources/spec-tests/async/trap-if-done.wast b/parser/src/test/resources/spec-tests/async/trap-if-done.wast deleted file mode 100644 index 5d7d9aa..0000000 --- a/parser/src/test/resources/spec-tests/async/trap-if-done.wast +++ /dev/null @@ -1,468 +0,0 @@ -;; This test has two components $C and $D, where $D imports and calls $C. -;; $C contains utility functions used by $D to create futures/streams, -;; write to them and close them. $D uses these utility functions to test for -;; all the cases where, once a future/stream is "done", further uses of the -;; future/stream trap. -;; -;; $D exports a list of functions, one for each case of trapping. Since traps -;; take out their containing instance, a fresh instance of $Tester is created -;; for each call to a $D export. -;; -;; When testing traps involving the readable end, the exports of $D take a -;; "bool" parameter that toggles whether the trap is triggered by -;; {stream,future}.{read,write} or by lifting, and the top-level commands -;; pass 'false' and 'true'. -(component definition $Tester - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "future.drop-writable" (func $future.drop-writable (param i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - (global $writable-end (mut i32) (i32.const 0)) - (global $ws (mut i32) (i32.const 0)) - - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - (func $start-future (export "start-future") (result i32) - ;; create a new future, return the readable end to the caller - (local $ret64 i64) - (local.set $ret64 (call $future.new)) - (global.set $writable-end (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (call $waitable.join (global.get $writable-end) (global.get $ws) ) - (i32.wrap_i64 (local.get $ret64)) - ) - (func $future-write (export "future-write") (result i32) - ;; the caller will assert what they expect the return value to be - (i32.store (i32.const 16) (i32.const 42)) - (call $future.write (global.get $writable-end) (i32.const 16)) - ) - (func $acknowledge-future-write (export "acknowledge-future-write") - ;; confirm we got a FUTURE_WRITE $writable-end COMPLETED event - (local $ret i32) - (local.set $ret (call $waitable-set.wait (global.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 5 (; FUTURE_WRITE ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (global.get $writable-end) (i32.load (i32.const 0))) - (then unreachable)) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (i32.load (i32.const 4))) - (then unreachable)) - ) - (func $future-drop-writable (export "future-drop-writable") - ;; maybe boom - (call $future.drop-writable (global.get $writable-end)) - ) - - (func $start-stream (export "start-stream") (result i32) - ;; create a new stream, return the readable end to the caller - (local $ret64 i64) - (local.set $ret64 (call $stream.new)) - (global.set $writable-end (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (call $waitable.join (global.get $writable-end) (global.get $ws) ) - (i32.wrap_i64 (local.get $ret64)) - ) - (func $stream-write (export "stream-write") (result i32) - ;; the caller will assert what they expect the return value to be - (i32.store (i32.const 16) (i32.const 42)) - (call $stream.write (global.get $writable-end) (i32.const 16) (i32.const 1)) - ) - (func $acknowledge-stream-write (export "acknowledge-stream-write") - ;; confirm we got a STREAM_WRITE $writable-end COMPLETED event - (local $ret i32) - (local.set $ret (call $waitable-set.wait (global.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 3 (; STREAM_WRITE ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (global.get $writable-end) (i32.load (i32.const 0))) - (then unreachable)) - (if (i32.ne (i32.const 0x11 (; DROPPED=1 | (1<<4) ;)) (i32.load (i32.const 4))) - (then unreachable)) - ) - (func $stream-drop-writable (export "stream-drop-writable") - ;; maybe boom - (call $stream.drop-writable (global.get $writable-end)) - ) - ) - (type $FT (future u8)) - (type $ST (stream u8)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon future.new $FT (core func $future.new)) - (canon future.write $FT async (memory $memory "mem") (core func $future.write)) - (canon future.drop-writable $FT (core func $future.drop-writable)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "future.new" (func $future.new)) - (export "future.write" (func $future.write)) - (export "future.drop-writable" (func $future.drop-writable)) - (export "stream.new" (func $stream.new)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (func (export "start-future") async (result (future u8)) (canon lift (core func $cm "start-future"))) - (func (export "future-write") async (result u32) (canon lift (core func $cm "future-write"))) - (func (export "acknowledge-future-write") async (canon lift (core func $cm "acknowledge-future-write"))) - (func (export "future-drop-writable") async (canon lift (core func $cm "future-drop-writable"))) - (func (export "start-stream") async (result (stream u8)) (canon lift (core func $cm "start-stream"))) - (func (export "stream-write") async (result u32) (canon lift (core func $cm "stream-write"))) - (func (export "acknowledge-stream-write") async (canon lift (core func $cm "acknowledge-stream-write"))) - (func (export "stream-drop-writable") async (canon lift (core func $cm "stream-drop-writable"))) - ) - (component $D - (import "c" (instance $c - (export "start-future" (func async (result (future u8)))) - (export "future-write" (func async (result u32))) - (export "acknowledge-future-write" (func async)) - (export "future-drop-writable" (func async)) - (export "start-stream" (func async (result (stream u8)))) - (export "stream-write" (func async (result u32))) - (export "acknowledge-stream-write" (func async)) - (export "stream-drop-writable" (func async)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "future.drop-readable" (func $future.drop-readable (param i32))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "start-future" (func $start-future (result i32))) - (import "" "future-write" (func $future-write (result i32))) - (import "" "acknowledge-future-write" (func $acknowledge-future-write)) - (import "" "future-drop-writable" (func $future-drop-writable)) - (import "" "start-stream" (func $start-stream (result i32))) - (import "" "stream-write" (func $stream-write (result i32))) - (import "" "acknowledge-stream-write" (func $acknowledge-stream-write)) - (import "" "stream-drop-writable" (func $stream-drop-writable)) - - (func $trap-after-future-eager-write (export "trap-after-future-eager-write") - (local $ret i32) - (local $fr i32) - (local.set $fr (call $start-future)) - - ;; start a read on our end so the next write will succeed - (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; calling future.write in $C should succeed eagerly - (local.set $ret (call $future-write)) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) - (then unreachable)) - - ;; calling future.write in $C now should trap - (drop (call $future-write)) - ) - (func $trap-after-future-async-write (export "trap-after-future-async-write") - (local $ret i32) - (local $fr i32) - (local.set $fr (call $start-future)) - - ;; calling future.write in $C should block - (local.set $ret (call $future-write)) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; our future.read should then succeed eagerly - (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) - (then unreachable)) - - ;; let $C see the write completed so the future is 'done' - (call $acknowledge-future-write) - - ;; trying to call future.write again in $C should trap - (drop (call $future-write)) - ) - (func $trap-after-future-reader-dropped (export "trap-after-future-reader-dropped") - (local $ret i32) - (local $fr i32) - (local.set $fr (call $start-future)) - - ;; drop our readable end before writer can write - (call $future.drop-readable (local.get $fr)) - - ;; let $C try to future.write and find out we DROPPED - (local.set $ret (call $future-write)) - (if (i32.ne (i32.const 1 (; DROPPED ;)) (local.get $ret)) - (then unreachable)) - - ;; trying to call future.write again in $C should trap - (drop (call $future-write)) - ) - (func $trap-after-future-eager-read (export "trap-after-future-eager-read") (param $bool i32) (result i32) - (local $ret i32) - (local $fr i32) - (local.set $fr (call $start-future)) - - ;; calling future.write in $C should block - (local.set $ret (call $future-write)) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; our future.read should then succeed eagerly - (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) - (then unreachable)) - - (if (i32.eqz (local.get $bool)) (then - ;; calling future.read again should then trap - (drop (call $future.read (local.get $fr) (i32.const 16))) - ) (else - ;; lifting the future by returning it should also trap - (return (local.get $fr)) - )) - unreachable - ) - (func $trap-after-future-async-read (export "trap-after-future-async-read") (param $bool i32) (result i32) - (local $ret i32) (local $ws i32) - (local $fr i32) - (local.set $fr (call $start-future)) - - ;; read first, so it blocks - (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; calling future.write in $C should then succeed eagerly - (local.set $ret (call $future-write)) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) - (then unreachable)) - - ;; wait to see that our blocked future.read COMPLETED, producing '42' - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $fr) (local.get $ws)) - (local.set $ret (call $waitable-set.wait (local.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (local.get $fr) (i32.load (i32.const 0))) - (then unreachable)) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (i32.load (i32.const 4))) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load (i32.const 16))) - (then unreachable)) - - (if (i32.eqz (local.get $bool)) (then - ;; calling future.read again should then trap - (drop (call $future.read (local.get $fr) (i32.const 16))) - ) (else - ;; lifting the future by returning it should also trap - (return (local.get $fr)) - )) - unreachable - ) - (func $trap-after-stream-reader-eager-dropped (export "trap-after-stream-reader-eager-dropped") - (local $ret i32) - (local $sr i32) - (local.set $sr (call $start-stream)) - - ;; drop our readable end before writer can write - (call $stream.drop-readable (local.get $sr)) - - ;; let $C try to stream.write and find out we DROPPED - (local.set $ret (call $stream-write)) - (if (i32.ne (i32.const 1 (; DROPPED ;)) (local.get $ret)) - (then unreachable)) - - ;; trying to call stream.write again in $C should trap - (drop (call $stream-write)) - ) - (func $trap-after-stream-reader-async-dropped (export "trap-after-stream-reader-async-dropped") - (local $ret i32) - (local $sr i32) - (local.set $sr (call $start-stream)) - - ;; calling stream.write in $C should block - (local.set $ret (call $stream-write)) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; our stream.read should then succeed eagerly - (local.set $ret (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) - (if (i32.ne (i32.const 0x10 (; COMPLETED=0 | (1<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) - (then unreachable)) - - ;; then drop our readable end - (call $stream.drop-readable (local.get $sr)) - - ;; let $C see that it's stream.write COMPLETED and wrote 1 elem - (call $acknowledge-stream-write) - - ;; now calling stream.write again in $C will trap - (drop (call $stream-write)) - ) - (func $trap-after-stream-writer-eager-dropped (export "trap-after-stream-writer-eager-dropped") (param $bool i32) (result i32) - (local $ret i32) - (local $sr i32) - (local.set $sr (call $start-stream)) - - ;; immediately drop the writable end - (call $stream-drop-writable) - - ;; calling stream.read will see that the writer dropped - (local.set $ret (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) - (if (i32.ne (i32.const 0x01 (; DROPPED=1 | (0<<4) ;)) (local.get $ret)) - (then unreachable)) - - (if (i32.eqz (local.get $bool)) (then - ;; calling stream.read again should then trap - (drop (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) - ) (else - ;; lifting the stream by returning it should also trap - (return (local.get $sr)) - )) - unreachable - ) - (func $trap-after-stream-writer-async-dropped (export "trap-after-stream-writer-async-dropped") (param $bool i32) (result i32) - (local $ret i32) (local $ws i32) - (local $sr i32) - (local.set $sr (call $start-stream)) - - ;; start a read on our end first which will block - (local.set $ret (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; drop the writable end before writing anything - (call $stream-drop-writable) - - ;; wait to see that our blocked stream.read was DROPPED - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $sr) (local.get $ws)) - (local.set $ret (call $waitable-set.wait (local.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 2 (; STREAM_READ ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (local.get $sr) (i32.load (i32.const 0))) - (then unreachable)) - (if (i32.ne (i32.const 0x01 (; DROPPED=1 | (0<<4) ;)) (i32.load (i32.const 4))) - (then unreachable)) - - (if (i32.eqz (local.get $bool)) (then - ;; calling stream.read again should then trap - (drop (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) - ) (else - ;; lifting the stream by returning it should also trap - (return (local.get $sr)) - )) - unreachable - ) - ) - (type $FT (future u8)) - (type $ST (stream u8)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon future.new $FT (core func $future.new)) - (canon future.read $FT async (memory $memory "mem") (core func $future.read)) - (canon future.drop-readable $FT (core func $future.drop-readable)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon lower (func $c "start-future") (core func $start-future')) - (canon lower (func $c "future-write") (core func $future-write')) - (canon lower (func $c "acknowledge-future-write") (core func $acknowledge-future-write')) - (canon lower (func $c "future-drop-writable") (core func $future-drop-writable')) - (canon lower (func $c "start-stream") (core func $start-stream')) - (canon lower (func $c "stream-write") (core func $stream-write')) - (canon lower (func $c "acknowledge-stream-write") (core func $acknowledge-stream-write')) - (canon lower (func $c "stream-drop-writable") (core func $stream-drop-writable')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "future.new" (func $future.new)) - (export "future.read" (func $future.read)) - (export "future.drop-readable" (func $future.drop-readable)) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "start-future" (func $start-future')) - (export "future-write" (func $future-write')) - (export "acknowledge-future-write" (func $acknowledge-future-write')) - (export "future-drop-writable" (func $future-drop-writable')) - (export "start-stream" (func $start-stream')) - (export "stream-write" (func $stream-write')) - (export "acknowledge-stream-write" (func $acknowledge-stream-write')) - (export "stream-drop-writable" (func $stream-drop-writable')) - )))) - (func (export "trap-after-future-eager-write") async (canon lift (core func $core "trap-after-future-eager-write"))) - (func (export "trap-after-future-async-write") async (canon lift (core func $core "trap-after-future-async-write"))) - (func (export "trap-after-future-reader-dropped") async (canon lift (core func $core "trap-after-future-reader-dropped"))) - (func (export "trap-after-future-eager-read") async (param "bool" bool) (result $FT) (canon lift (core func $core "trap-after-future-eager-read"))) - (func (export "trap-after-future-async-read") async (param "bool" bool) (result $FT) (canon lift (core func $core "trap-after-future-async-read"))) - (func (export "trap-after-stream-reader-eager-dropped") async (canon lift (core func $core "trap-after-stream-reader-eager-dropped"))) - (func (export "trap-after-stream-reader-async-dropped") async (canon lift (core func $core "trap-after-stream-reader-async-dropped"))) - (func (export "trap-after-stream-writer-eager-dropped") async (param "bool" bool) (result $ST) (canon lift (core func $core "trap-after-stream-writer-eager-dropped"))) - (func (export "trap-after-stream-writer-async-dropped") async (param "bool" bool) (result $ST) (canon lift (core func $core "trap-after-stream-writer-async-dropped"))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "trap-after-future-eager-write") (alias export $d "trap-after-future-eager-write")) - (func (export "trap-after-future-async-write") (alias export $d "trap-after-future-async-write")) - (func (export "trap-after-future-reader-dropped") (alias export $d "trap-after-future-reader-dropped")) - (func (export "trap-after-future-eager-read") (alias export $d "trap-after-future-eager-read")) - (func (export "trap-after-future-async-read") (alias export $d "trap-after-future-async-read")) - (func (export "trap-after-stream-reader-eager-dropped") (alias export $d "trap-after-stream-reader-eager-dropped")) - (func (export "trap-after-stream-reader-async-dropped") (alias export $d "trap-after-stream-reader-async-dropped")) - (func (export "trap-after-stream-writer-eager-dropped") (alias export $d "trap-after-stream-writer-eager-dropped")) - (func (export "trap-after-stream-writer-async-dropped") (alias export $d "trap-after-stream-writer-async-dropped")) -) - -(component instance $i1 $Tester) -(assert_trap (invoke "trap-after-future-eager-write") "cannot write to future after previous write succeeded") -(component instance $i2 $Tester) -(assert_trap (invoke "trap-after-future-async-write") "cannot write to future after previous write succeeded") -(component instance $i3 $Tester) -(assert_trap (invoke "trap-after-future-reader-dropped") "cannot write to future after previous write succeeded or readable end dropped") -(component instance $i4.1 $Tester) -(assert_trap (invoke "trap-after-future-eager-read" (bool.const false)) "cannot read from future after previous read succeeded") -(component instance $i4.2 $Tester) -(assert_trap (invoke "trap-after-future-eager-read" (bool.const true)) "cannot lift future after previous read succeeded") -(component instance $i5.1 $Tester) -(assert_trap (invoke "trap-after-future-async-read" (bool.const false)) "cannot read from future after previous read succeeded") -(component instance $i5.2 $Tester) -(assert_trap (invoke "trap-after-future-async-read" (bool.const true)) "cannot lift future after previous read succeeded") -(component instance $i6 $Tester) -(assert_trap (invoke "trap-after-stream-reader-eager-dropped") "cannot write to stream after being notified that the readable end dropped") -(component instance $i7 $Tester) -(assert_trap (invoke "trap-after-stream-reader-async-dropped") "cannot write to stream after being notified that the readable end dropped") -(component instance $i8.1 $Tester) -(assert_trap (invoke "trap-after-stream-writer-eager-dropped" (bool.const false)) "cannot read from stream after being notified that the writable end dropped") -(component instance $i8.2 $Tester) -(assert_trap (invoke "trap-after-stream-writer-eager-dropped" (bool.const true)) "cannot lift stream after being notified that the writable end dropped") -(component instance $i9.1 $Tester) -(assert_trap (invoke "trap-after-stream-writer-async-dropped" (bool.const false)) "cannot read from stream after being notified that the writable end dropped") -(component instance $i9.2 $Tester) -(assert_trap (invoke "trap-after-stream-writer-async-dropped" (bool.const true)) "cannot lift stream after being notified that the writable end dropped") diff --git a/parser/src/test/resources/spec-tests/async/trap-on-reenter.wast b/parser/src/test/resources/spec-tests/async/trap-on-reenter.wast deleted file mode 100644 index f363f6d..0000000 --- a/parser/src/test/resources/spec-tests/async/trap-on-reenter.wast +++ /dev/null @@ -1,110 +0,0 @@ -;; This test creates an asynchronous recursive call stack: -;; $Parent --> $Child --> $Parent -;; That should trap when $Child tries to call $Parent. -(component $Parent - (core module $CoreInner - (memory (export "mem") 1) - (func (export "a") (result i32) - unreachable - ) - (func (export "a-cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (core instance $core_inner (instantiate $CoreInner)) - (func $a async (canon lift - (core func $core_inner "a") - async (callback (func $core_inner "a-cb")) - )) - - (component $Child - (import "a" (func $a async)) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - - (core module $CoreChild - (import "" "a" (func $a (result i32))) - (func (export "b") (result i32) - (i32.const 1 (; YIELD ;)) - ) - (func (export "b-cb") (param i32 i32 i32) (result i32) - (call $a) - unreachable - ) - ) - (canon lower (func $a) async (memory $memory "mem") (core func $a')) - (core instance $core_child (instantiate $CoreChild (with "" (instance - (export "a" (func $a')) - )))) - (func (export "b") async (canon lift - (core func $core_child "b") - async (callback (func $core_child "b-cb")) - )) - ) - (instance $child (instantiate $Child (with "a" (func $a)))) - - (core module $CoreOuter - (import "" "b" (func $b (result i32))) - (func $c (export "c") (result i32) - (i32.const 1 (; YIELD ;)) - ) - (func $c-cb (export "c-cb") (param i32 i32 i32) (result i32) - (call $b) - ) - ) - (canon lower (func $child "b") async (memory $core_inner "mem") (core func $b)) - (core instance $core_outer (instantiate $CoreOuter (with "" (instance - (export "b" (func $b)) - )))) - (func $c (export "c") async (canon lift - (core func $core_outer "c") - async (callback (func $core_outer "c-cb")) - )) -) -(assert_trap (invoke "c") "wasm trap: cannot enter component instance") - -;; also, for now, trap on parent-to-child -(component $Parent - (component $Child - (core module $CoreChild - (func (export "f")) - ) - (core instance $core_child (instantiate $CoreChild)) - (func (export "f") (canon lift (core func $core_child "f"))) - ) - (instance $child (instantiate $Child)) - (canon lower (func $child "f") (core func $f)) - - (core module $CoreOuter - (import "" "f" (func $f)) - (func (export "g") (call $f)) - ) - (core instance $core_outer (instantiate $CoreOuter (with "" (instance (export "f" (func $f)))))) - (func $g (export "g") (canon lift (core func $core_outer "g"))) -) -(assert_trap (invoke "g") "wasm trap: cannot enter component instance") - -;; also, for now, trap on child-to-parent -(component $Parent - (core module $CoreInner - (func (export "f")) - ) - (core instance $core_inner (instantiate $CoreInner)) - (func $f (canon lift (core func $core_inner "f"))) - - (component $Child - (import "f" (func $f)) - (canon lower (func $f) (core func $f')) - (core module $CoreChild - (import "" "f" (func $f)) - (func (export "g") (call $f)) - ) - (core instance $core_child (instantiate $CoreChild (with "" (instance (export "f" (func $f')))))) - (func (export "g") (canon lift (core func $core_child "g"))) - ) - (instance $child (instantiate $Child (with "f" (func $f)))) - (alias export $child "g" (func $g)) - (export "g" (func $g)) -) -(assert_trap (invoke "g") "wasm trap: cannot enter component instance") diff --git a/parser/src/test/resources/spec-tests/async/wait-during-callback.wast b/parser/src/test/resources/spec-tests/async/wait-during-callback.wast deleted file mode 100644 index 3f95d5b..0000000 --- a/parser/src/test/resources/spec-tests/async/wait-during-callback.wast +++ /dev/null @@ -1,77 +0,0 @@ -;; This test calls waitable-set.wait from under an async-callback-lifted export. -(component - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - - (func $run (export "run") (result i32) - (local $ret i32) (local $ret64 i64) - (local $futr i32) (local $futw i32) (local $ws i32) - (local $event_code i32) (local $retp i32) - - ;; create a future pair - (local.set $ret64 (call $future.new)) - (local.set $futr (i32.wrap_i64 (local.get $ret64))) - (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - - ;; start a pending read that will block - (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; perform a write to make the above read ready - (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - ;; wait on a waitable set containing our now-ready future.read which - ;; should then immediately resolve - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $futr) (local.get $ws)) - (local.set $retp (i32.const 0)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp))) - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $futr) (i32.load (local.get $retp))) - (then unreachable)) - - ;; return 42 - (call $task.return (i32.const 42)) - (i32.const 0 (; EXIT ;)) - ) - (func (export "run_cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (type $FT (future)) - (canon task.return (result u32) (core func $task.return)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon future.new $FT (core func $future.new)) - (canon future.read $FT async (core func $future.read)) - (canon future.write $FT async (core func $future.write)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "future.new" (func $future.new)) - (export "future.read" (func $future.read)) - (export "future.write" (func $future.write)) - )))) - (func (export "run") async (result u32) (canon lift - (core func $cm "run") - async (callback (func $cm "run_cb")) - )) -) -(assert_return (invoke "run") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/async/zero-length.wast b/parser/src/test/resources/spec-tests/async/zero-length.wast deleted file mode 100644 index fab7765..0000000 --- a/parser/src/test/resources/spec-tests/async/zero-length.wast +++ /dev/null @@ -1,223 +0,0 @@ -;; This example defines 3 nested components $Producer, $Consumer and $Parent -;; $Parent imports $Consumer and $Producer, calling $Producer.produce, which -;; returns a stream that $Parent passes to $Consumer.consume. -;; $Producer and $Consumer both start by performing 0-length reads/writes to -;; detect when the other side is ready. Once signalled ready, a 4-byte -;; payload is written/read. -(component - (component $Producer - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CoreProducer - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - ;; $ws is waited on by 'produce' - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - ;; $outsw is written by 'produce' - (global $outsw (mut i32) (i32.const 0)) - (global $outbufp (mut i32) (i32.const 0x20)) - - (global $state (mut i32) (i32.const 0)) - - (func $produce (export "produce") (result i32) - (local $ret i32) (local $ret64 i64) (local $outsr i32) - - ;; create a new stream r/w pair $outsr/$outsw - (local.set $ret64 (call $stream.new)) - (local.set $outsr (i32.wrap_i64 (local.get $ret64))) - (global.set $outsw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - - ;; return the readable end of the stream to the caller - (call $task.return (local.get $outsr)) - - ;; initiate a zero-length write - (local.set $ret (call $stream.write (global.get $outsw) (i32.const 0xdeadbeef) (i32.const 0))) - (if (i32.ne (i32.const -1) (local.get $ret)) - (then unreachable)) - - ;; wait for the stream.write to complete - (call $waitable.join (global.get $outsw) (global.get $ws)) - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) - ) - (func $produce_cb (export "produce_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - (local $ret i32) - - ;; confirm we're getting a write for the stream $outsw - (if (i32.ne (local.get $event_code) (i32.const 3 (; STREAM_WRITE ;))) - (then unreachable)) - (if (i32.ne (local.get $index) (global.get $outsw)) - (then unreachable)) - - ;; the first call to produce_cb: - (if (i32.eq (global.get $state) (i32.const 0)) (then - ;; confirm we're seeing the zero-length write complete - (if (i32.ne (local.get $payload) (i32.const 0 (; COMPLETED=0 | (0 << 4) ;))) - (then unreachable)) - - ;; issue an async non-zero-length write which should block per spec - (i32.store (i32.const 0) (i32.const 0x12345678)) - (local.set $ret (call $stream.write (global.get $outsw) (i32.const 0) (i32.const 4))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - (global.set $state (i32.const 1)) - - ;; wait on $ws - (return (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4)))) - )) - - ;; the second call to produce_cb: - (if (i32.eq (global.get $state) (i32.const 1)) (then - ;; confirm we're seeing the non-zero-length write complete - (if (i32.ne (local.get $payload) (i32.const 0x41 (; DROPPED=1 | (4 << 4) ;))) - (then unreachable)) - - (call $stream.drop-writable (global.get $outsw)) - (return (i32.const 0 (; EXIT ;))) - )) - - unreachable - ) - ) - (type $ST (stream u8)) - (canon task.return (result $ST) (core func $task.return)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $core_producer (instantiate $CoreProducer (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "stream.new" (func $stream.new)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (func (export "produce") async (result (stream u8)) (canon lift - (core func $core_producer "produce") - async (callback (func $core_producer "produce_cb")) - )) - ) - - (component $Consumer - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CoreConsumer - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - - ;; $ws is waited on by 'consume' - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - ;; $insr is read by 'consume' - (global $insr (mut i32) (i32.const 0)) - (global $inbufp (mut i32) (i32.const 0x20)) - - (func $consume (export "consume") (param $insr i32) (result i32) - (local $ret i32) - (global.set $insr (local.get $insr)) - - ;; initiate a zero-length read which will also block (even though there is - ;; a pending write, b/c the pending write is 0-length, per spec) - (local.set $ret (call $stream.read (global.get $insr) (i32.const 0xdeadbeef) (i32.const 0))) - (if (i32.ne (i32.const -1) (local.get $ret)) - (then unreachable)) - - ;; wait for the stream.read to complete - (call $waitable.join (global.get $insr) (global.get $ws)) - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) - ) - (func $consume_cb (export "consume_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - (local $ret i32) - - ;; confirm we're seeing the zero-length read complete - (if (i32.ne (local.get $event_code) (i32.const 2 (; STREAM_READ ;))) - (then unreachable)) - (if (i32.ne (local.get $index) (global.get $insr)) - (then unreachable)) - (if (i32.ne (local.get $payload) (i32.const 0 (; COMPLETED=0 | (0 << 4) ;))) - (then unreachable)) - - ;; perform a non-zero-length read which should succeed without blocking - (local.set $ret (call $stream.read (global.get $insr) (i32.const 0) (i32.const 100))) - (if (i32.ne (i32.const 0x40 (; (4 << 4) | COMPLETED=0 ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (i32.load (i32.const 0))) - (if (i32.ne (i32.const 0x12345678) (local.get $ret)) - (then unreachable)) - - (call $stream.drop-readable (global.get $insr)) - - ;; return 42 to the top-level assert_return - (call $task.return (i32.const 42)) - (i32.const 0 (; EXIT ;)) - ) - ) - (type $ST (stream u8)) - (canon task.return (result u32) (core func $task.return)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (core instance $core_consumer (instantiate $CoreConsumer (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "stream.read" (func $stream.read)) - (export "stream.drop-readable" (func $stream.drop-readable)) - )))) - (func (export "consume") async (param "in" (stream u8)) (result u32) (canon lift - (core func $core_consumer "consume") - async (callback (func $core_consumer "consume_cb")) - )) - ) - - (component $Parent - (import "produce" (func $produce async (result (stream u8)))) - (import "consume" (func $consume async (param "in" (stream u8)) (result u32))) - - (core module $CoreParent - (import "" "produce" (func $produce (result i32))) - (import "" "consume" (func $consume (param i32) (result i32))) - (memory 1) - (func $run (export "run") (result i32) - (call $consume (call $produce)) - ) - ) - - (canon lower (func $produce) (core func $produce')) - (canon lower (func $consume) (core func $consume')) - (core instance $core_parent (instantiate $CoreParent (with "" (instance - (export "produce" (func $produce')) - (export "consume" (func $consume')) - )))) - (func (export "run") async (result u32) (canon lift (core func $core_parent "run"))) - ) - - (instance $producer (instantiate $Producer)) - (instance $consumer (instantiate $Consumer)) - (instance $parent (instantiate $Parent - (with "produce" (func $producer "produce")) - (with "consume" (func $consumer "consume")) - )) - (func (export "run") (alias export $parent "run")) -) -(assert_return (invoke "run") (u32.const 42)) diff --git a/parser/src/test/resources/spec-tests/failed.wasm b/parser/src/test/resources/spec-tests/failed.wasm deleted file mode 100644 index e96e6020ccfbbe58add30bddc23572ce478c78a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45 ycmZQbEY9U+U}RwDW-h4BXJV*yU;y&O_>%K;3-a?)^GbB{5_3}-S(zD`7)t=td" (func))))) - "not a valid export name") -(assert_invalid - (component (type (component (export "url=" (func))))) - "not a valid export name") -(assert_invalid - (component (type (component (export "relative-url=" (func))))) - "not a valid extern name") -(assert_invalid - (component (type (component (export "locked-dep=" (func))))) - "not a valid export name") -(assert_invalid - (component (type (component (export "unlocked-dep=" (func))))) - "not a valid export name") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/func.wast b/parser/src/test/resources/spec-tests/wasm-tools/func.wast deleted file mode 100644 index 4a207f9..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/func.wast +++ /dev/null @@ -1,146 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component definition - (import "a" (func (param "foo" string))) - (import "b" (func (param "foo" string) (param "bar" s32) (param "baz" u32))) - (import "c" (func (result (tuple u8)))) -) - -(component definition - (import "a" (func)) - (import "b" (func (param "p1" string))) - (import "c" (func (result u32))) - (import "d" (func (param "p1" bool) (result string))) -) - - -(assert_invalid - (component - (type (func (param "foo" string) (param "FOO" u32))) - ) - "function parameter name `FOO` conflicts with previous parameter name `foo`" -) - -(assert_invalid - (component - (core module $m - (memory (export "memory") 1) - (func (export "foo") (result i32) unreachable) - ) - (core instance $i (instantiate $m)) - - (func (export "tuple") (result (tuple s8 u8)) - (canon lift (core func $i "foo")) - ) - ) - "canonical option `memory` is required" -) - -(component definition - (import "a" (func $log (param "msg" string))) - (core module $libc - (memory (export "memory") 1) - ) - (core instance $libc (instantiate $libc)) - (core func (canon lower (func $log) (memory $libc "memory"))) -) - -(component - (core module $m - (memory (export "memory") 1) - (func (export "ret-list") (result i32) unreachable) - ) - (core instance $i (instantiate $m)) - - (func (export "ret-list") (result (list u8)) - (canon lift (core func $i "ret-list") (memory $i "memory")) - ) -) - -(component - (type $big (func - (param "p1" u32) (param "p2" u32) (param "p3" u32) (param "p4" u32) (param "p5" u32) - (param "p6" u32) (param "p7" u32) (param "p8" u32) (param "p9" u32) (param "p10" u32) - (param "p11" u32) (param "p12" u32) (param "p13" u32) (param "p14" u32) (param "p15" u32) - (param "p16" u32) (param "p17" u32) (param "p18" u32) (param "p19" u32) (param "p20" u32) - )) - - (component $c - (import "big" (func $big (type $big))) - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core func $big (canon lower (func $big) (memory $libc "memory"))) - ) -) - -(assert_invalid - (component - (core module $m - (memory (export "memory") 1) - (func (export "roundtrip") (param i32)) - ) - (core instance $m (instantiate $m)) - - (type $roundtrip (func - (param "p1" u32) (param "p2" u32) (param "p3" u32) (param "p4" u32) (param "p5" u32) - (param "p6" u32) (param "p7" u32) (param "p8" u32) (param "p9" u32) (param "p10" u32) - (param "p11" u32) (param "p12" u32) (param "p13" u32) (param "p14" u32) (param "p15" u32) - (param "p16" u32) (param "p17" u32) (param "p18" u32) (param "p19" u32) (param "p20" u32) - )) - - (func $roundtrip (type $roundtrip) - (canon lift (core func $m "roundtrip") (memory $m "memory")) - ) - (export "roundtrip" (func $roundtrip)) - ) - "canonical option `realloc` is required" -) - -(assert_invalid - (component - (import "a" (func $log (result string))) - (core module $libc - (memory (export "memory") 1) - ) - (core instance $libc (instantiate $libc)) - (core func (canon lower (func $log) (memory $libc "memory"))) - ) - "canonical option `realloc` is required" -) - -(assert_invalid - (component - (core module $m - (memory (export "memory") 1) - (func (export "param-list") (param i32 i32) unreachable) - ) - (core instance $i (instantiate $m)) - - (func (export "param-list") (param "bytes" (list u8)) - (canon lift (core func $i "param-list") (memory $i "memory")) - ) - ) - "canonical option `realloc` is required" -) - -(assert_malformed - (component binary - "\00asm" "\0d\00\01\00" ;; component header - "\07\05" ;; component type section, 5 bytes - "\01" ;; 1 count - "\40" ;; component function type - "\00" ;; 0 parameters - "\01\01" ;; invalid result encoding - ) - "invalid leading byte (0x1) for number of results") - -(assert_malformed - (component binary - "\00asm" "\0d\00\01\00" ;; component header - "\07\05" ;; component type section, 5 bytes - "\01" ;; 1 count - "\40" ;; component function type - "\00" ;; 0 parameters - "\02\00" ;; invalid result encoding - ) - "invalid leading byte (0x2) for component function results") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/import.wast b/parser/src/test/resources/spec-tests/wasm-tools/import.wast deleted file mode 100644 index b226157..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/import.wast +++ /dev/null @@ -1,359 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component - (component - (import "a" (func)) - (import "b" (instance)) - (import "c" (instance - (export "a" (func)) - )) - (import "d" (component - (import "a" (core module)) - (export "b" (func)) - )) - (type $t (func)) - (import "e" (type (eq $t))) - ) -) - -(assert_invalid - (component - (type $f (func)) - (import "a" (instance (type $f))) - ) - "type index 0 is not an instance type") - -(assert_invalid - (component - (core type $f (func)) - (import "a" (core module (type $f))) - ) - "core type index 0 is not a module type") - -(assert_invalid - (component - (type $f string) - (import "a" (func (type $f))) - ) - "type index 0 is not a function type") - -;; Disallow duplicate imports for core wasm modules -(assert_invalid - (component - (core type (module - (import "" "" (func)) - (import "" "" (func)) - )) - ) - "duplicate import name `:`") -(assert_invalid - (component - (core module - (import "" "" (func)) - (import "" "" (func)) - ) - ) - "duplicate import name `:`") -(assert_invalid - (component - (core type (module - (import "" "a" (func)) - (import "" "a" (func)) - )) - ) - "duplicate import name `:a`") -(assert_invalid - (component - (core module - (import "" "a" (func)) - (import "" "a" (func)) - ) - ) - "duplicate import name `:a`") - -(assert_invalid - (component - (import "a" (func)) - (import "a" (func)) - ) - "import name `a` conflicts with previous name `a`") - -(assert_invalid - (component - (type (component - (import "a" (func)) - (import "a" (func)) - )) - ) - "import name `a` conflicts with previous name `a`") - -(assert_invalid - (component - (import "a" (func (type 100))) - ) - "type index out of bounds") - -(assert_invalid - (component - (core module $m (func (export ""))) - (core instance $i (instantiate $m)) - (func (type 100) (canon lift (core func $i ""))) - ) - "type index out of bounds") - -(component definition - (import "wasi:http/types" (func)) - (import "wasi:http/types@1.0.0" (func)) - (import "wasi:http/types@2.0.0" (func)) - (import "a-b:c-d/e-f@123456.7890.488" (func)) - (import "a:b/c@1.2.3" (func)) - (import "a:b/c@0.0.0" (func)) - (import "a:b/c@0.0.0+abcd" (func)) - (import "a:b/c@0.0.0+abcd-efg" (func)) - (import "a:b/c@0.0.0-abcd+efg" (func)) - (import "a:b/c@0.0.0-abcd.1.2+efg.4.ee.5" (func)) -) - -(assert_invalid - (component - (import "wasi:http/types" (func)) - (import "wasi:http/types" (func)) - ) - "conflicts with previous name") - -(assert_invalid - (component (import "" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "wasi:" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "wasi:/" (func))) - "not in kebab case") -(assert_invalid - (component (import ":/" (func))) - "not in kebab case") -(assert_invalid - (component (import "wasi/http" (func))) - "`wasi/http` is not in kebab case") -(assert_invalid - (component (import "wasi:http/TyPeS" (func))) - "`TyPeS` is not in kebab case") -(assert_invalid - (component (import "WaSi:http/types" (func))) - "`WaSi` is not in kebab case") -(assert_invalid - (component (import "wasi:HtTp/types" (func))) - "`HtTp` is not in kebab case") -(assert_invalid - (component (import "wasi:http/types@" (func))) - "empty string") -(assert_invalid - (component (import "wasi:http/types@." (func))) - "unexpected character '.'") -(assert_invalid - (component (import "wasi:http/types@1." (func))) - "unexpected end of input") -(assert_invalid - (component (import "wasi:http/types@a.2" (func))) - "unexpected character 'a'") -(assert_invalid - (component (import "wasi:http/types@2.b" (func))) - "unexpected character 'b'") -(assert_invalid - (component (import "wasi:http/types@2.0x0" (func))) - "unexpected character 'x'") -(assert_invalid - (component (import "wasi:http/types@2.0.0+" (func))) - "empty identifier segment") -(assert_invalid - (component (import "wasi:http/types@2.0.0-" (func))) - "empty identifier segment") -(assert_invalid - (component (import "foo:bar:baz/qux" (func))) - "expected `/` after package name") -(assert_invalid - (component (import "foo:bar/baz/qux" (func))) - "trailing characters found: `/qux`") - -(component - (component - (import "a" (func $a)) - (export "a" (func $a)) - ) -) - -(component definition - (import "unlocked-dep=" (func)) - (import "unlocked-dep=" (func)) - (import "unlocked-dep==1.2.3}>" (func)) - (import "unlocked-dep==1.2.3-rc}>" (func)) - (import "unlocked-dep=" (func)) - (import "unlocked-dep=" (func)) - (import "unlocked-dep==1.2.3 <1.2.3}>" (func)) - (import "unlocked-dep==1.2.3-rc <1.2.3}>" (func)) -) - -(assert_invalid - (component (import "unlocked-dep=" (func))) - "expected `<` at ``") -(assert_invalid - (component (import "unlocked-dep=<" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "unlocked-dep=<>" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "unlocked-dep=<:>" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "unlocked-dep=" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "unlocked-dep=<:a>" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "unlocked-dep=" (func))) - "expected `{` at `>`") -(assert_invalid - (component (import "unlocked-dep=" (func))) - "expected `>=` or `<` at start of version range") -(assert_invalid - (component (import "unlocked-dep=" (func))) - "`xyz` is not a valid semver") -(assert_invalid - (component (import "unlocked-dep==2.3.4}>" (func))) - "`1.2.3 >=2.3.4` is not a valid semver") - -(component definition - (import "locked-dep=" (func)) - (import "locked-dep=" (func)) - (import "locked-dep=,integrity=" (func)) - (import "locked-dep=,integrity=" (func)) -) - -(assert_invalid - (component (import "locked-dep=" (func))) - "expected `<` at ``") -(assert_invalid - (component (import "locked-dep=<" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "locked-dep=<:" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "locked-dep=<:>" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "locked-dep=" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "locked-dep=<:a>" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "locked-dep=` at ``") -(assert_invalid - (component (import "locked-dep=" (func))) - "is not a valid semver") -(assert_invalid - (component (import "locked-dep=` at ``") -(assert_invalid - (component (import "locked-dep=," (func))) - "expected `integrity=<`") -(assert_invalid - (component (import "locked-dep=x" (func))) - "trailing characters found: `x`") - -(component definition - (import "url=<>" (func)) - (import "url=" (func)) - (import "url=,integrity=" (func)) -) - -(assert_invalid - (component (import "url=" (func))) - "expected `<` at ``") -(assert_invalid - (component (import "url=<" (func))) - "failed to find `>`") -(assert_invalid - (component (import "url=<<>" (func))) - "url cannot contain `<`") - -(assert_invalid - (component - (import "relative-url=<>" (func)) - (import "relative-url=" (func)) - (import "relative-url=,integrity=" (func)) - ) - "not a valid extern name") - -(assert_invalid - (component (import "relative-url=" (func))) - "not a valid extern name") -(assert_invalid - (component (import "relative-url=<" (func))) - "not a valid extern name") -(assert_invalid - (component (import "relative-url=<<>" (func))) - "not a valid extern name") - -(component definition - (import "integrity=" (func)) - (import "integrity=" (func)) - (import "integrity=" (func)) - (import "integrity=" (func)) - (import "integrity=< sha512-a sha256-b >" (func)) - (import "integrity=< sha512-a?abcd >" (func)) - (import "integrity=" (func)) - (import "integrity=" (func)) - (import "integrity=" (func)) - (import "integrity=" (func)) -) -(assert_invalid - (component (import "integrity=<>" (func))) - "integrity hash cannot be empty") -(assert_invalid - (component (import "integrity=" (func))) - "expected `-` after hash algorithm") -(assert_invalid - (component (import "integrity=" (func))) - "not valid base64") -(assert_invalid - (component (import "integrity=" (func))) - "not valid base64") -(assert_invalid - (component (import "integrity=" (func))) - "not valid base64") -(assert_invalid - (component (import "integrity=" (func))) - "not valid base64") -(assert_invalid - (component (import "integrity=" (func))) - "not valid base64") -(assert_invalid - (component (import "integrity=" (func))) - "unrecognized hash algorithm") - -;; Prior to WebAssembly/component-model#263 this was a valid component. -;; Specifically the 0x01 prefix byte on the import was valid. Nowadays that's -;; not valid in the spec but it's accepted for backwards compatibility. This -;; tests is here to ensure such compatibility. In the future this test should -;; be changed to `(assert_invalid ...)` -(component definition binary - "\00asm" "\0d\00\01\00" ;; component header - - "\07\05" ;; type section, 5 bytes large - "\01" ;; 1 count - "\40" ;; function - "\00" ;; parameters, 0 count - "\01\00" ;; results, named, 0 count - - "\0a\06" ;; import section, 6 bytes large - "\01" ;; 1 count - "\01" ;; prefix byte of 0x01 (invalid by the spec nowadays) - "\01a" ;; name = "a" - "\01\00" ;; type = func ($type 0) -) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/imports-exports.wast b/parser/src/test/resources/spec-tests/wasm-tools/imports-exports.wast deleted file mode 100644 index e650c8c..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/imports-exports.wast +++ /dev/null @@ -1,26 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -;; With what's defined so far, we can define a component that imports, links and exports other components: - -(component - (component - (import "c" (instance $c - (export "f" (func (result string))) - )) - (import "d" (component $D - (import "c" (instance $c - (export "f" (func (result string))) - )) - (export "g" (func (result string))) - )) - (instance $d1 (instantiate $D - (with "c" (instance $c)) - )) - (instance $d2 (instantiate $D - (with "c" (instance - (export "f" (func $d1 "g")) - )) - )) - (export "d2" (instance $d2)) - ) -) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/inline-exports.wast b/parser/src/test/resources/spec-tests/wasm-tools/inline-exports.wast deleted file mode 100644 index 2c3ff56..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/inline-exports.wast +++ /dev/null @@ -1,9 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component - (type (export "foo") u8) -) - -(assert_malformed - (component quote "(type (component (type (export \"\") (func))))") - "unexpected token") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/instance-type.wast b/parser/src/test/resources/spec-tests/wasm-tools/instance-type.wast deleted file mode 100644 index 2f4b140..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/instance-type.wast +++ /dev/null @@ -1,234 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -;; instances -(component - (type (instance)) - - (type $foo (func)) - - (type $t (func (result string))) - - (core type (module - (type $local_type (func)) - ;; functions - (export "a" (func)) - (export "b" (func $foo)) - (export "c" (func)) - (export "d" (func $foo)) - (export "e" (func (type $local_type))) - (export "f" (func (param i32))) - (export "g" (func (param i32) (result i32 i64))) - (export "h" (func (type $local_type) (result i32))) - - ;; globals - (export "i" (global i32)) - (export "j" (global $foo i32)) - (export "k" (global (mut i32))) - - ;; tables - (export "l" (table 1 funcref)) - (export "m" (table $foo 1 funcref)) - - ;; memory - (export "n" (memory 1)) - (export "o" (memory $foo 1)) - (export "p" (memory 1 2)) - (export "q" (memory 1 2 shared)) - )) - - (type $outer (instance - (type $local_type (func)) - ;; functions - (export "a" (func)) - (export "a2" (func (type $local_type))) - (export "b" (func)) - (export "c" (func)) - (export "d" (func)) - (export "e" (func (type $t))) - (export "f" (func (param "f" string))) - (export "g" (func (param "g" s32) (result u32))) - (export "h" (func (type $t))) - - ;; components - (type $component_type (component)) - (export "c1" (component)) - (export "c2" (component (import "i1" (func)))) - (export "c3" (component (export "e1" (func)))) - (export "c4" (component (type $component_type))) - (export "c5" (component - (type $nested_func_type (func)) - (alias outer $outer $local_type (type $my_type)) - (import "i1" (func (type $nested_func_type))) - (import "i2" (component)) - (export "e1" (func (type $my_type))) - (export "e2" (component)) - )) - )) -) - -;; expand inline types -(component - (type (instance (export "a" (instance)))) -) - -;; reference outer types -(component - (type (instance - (type $t (instance)) - (export "a" (instance (type $t))) - )) - (type $x (instance)) - (type (instance (export "a" (instance (type $x))))) -) - -;; recursive -(component - (type (instance (export "a" (core module - (type $functype (func)) - - (export "a" (func)) - (export "b" (func (type 0))) - (export "c" (func (param i32))) - (export "d" (func (type $functype))) - - ;; globals - (export "e" (global i32)) - (export "f" (global (mut i32))) - - ;; tables - (export "g" (table 1 funcref)) - - ;; memory - (export "h" (memory 1)) - (export "i" (memory 1 2)) - (export "j" (memory 1 2 shared)) - )))) -) - -;; modules -(component - (core type (module)) - - (core type $foo (module)) - - (type $empty (func)) - (type $i (instance)) - - (core type (module - (type $empty (func)) - (import "" "a" (func)) - (import "" "b" (func (type $empty))) - (import "" "c" (func (param i32))) - (import "" "d" (func (param i32) (result i32))) - - (import "" "e" (global i32)) - (import "" "f" (memory 1)) - (import "" "g" (table 1 funcref)) - - (export "a" (func)) - (export "b" (global i32)) - (export "c" (memory 1)) - (export "d" (table 1 funcref)) - - (export "e" (func (type $empty))) - (export "f" (func (param i32))) - )) - - (type (component - (import "a" (func)) - (import "b" (func (type $empty))) - (import "c" (func (param "c" s32))) - (import "d" (func (param "d" s32) (result s32))) - - (import "h" (instance)) - (import "i" (instance (type $i))) - (import "j" (instance - (export "a" (func)) - (export "b" (func (type $empty))) - (export "c" (func (param "c" s32))) - )) - - (import "k" (core module)) - (import "l" (core module - (type $empty (func)) - (import "" "a" (func (type $empty))) - (import "" "b" (func (param i32))) - (export "a" (func (type $empty))) - (export "b" (func (param i32))) - )) - - (export "m" (func)) - (export "n" (func (type $empty))) - (export "o" (func (param "f" s32))) - - (export "p" (instance - (export "a" (func)) - (export "b" (func (type $empty))) - (export "c" (func (param "c" s32))) - )) - - (export "q" (core module - (type $empty (func)) - (import "" "a" (func (type $empty))) - (import "" "b" (func (param i32))) - (export "a" (func (type $empty))) - (export "b" (func (param i32))) - )) - )) -) - -(assert_invalid - (component - (type (instance - (export "a" (func)) - (export "a" (func))))) - "export name `a` conflicts with previous name `a`") - -(assert_invalid - (component - (type $t (func)) - (type (instance - (export "a" (instance (type $t))) - ))) - "type index 0 is not an instance type") - -(assert_invalid - (component - (core type $t (func)) - (type (instance - (export "a" (core module (type $t))) - ))) - "core type index 0 is not a module type") - -(assert_malformed - (component quote - "(type $t (func))" - "(type (instance (export \"a\" (core module (type $t)))))" - ) - "unknown core type") - -(assert_invalid - (component - (type $t (record (field "a" string))) - (type (instance - (export "a" (func (type $t))) - ))) - "type index 0 is not a function type") - -(assert_invalid - (component - (type $t (instance)) - (type (instance - (export "a" (func (type $t))) - ))) - "type index 0 is not a function type") - -(assert_invalid - (component - (type $t (instance)) - (type (instance - (export "a" (instance - (export "a" (func (type $t))) - )) - ))) - "type index 0 is not a function type") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/instantiate.wast b/parser/src/test/resources/spec-tests/wasm-tools/instantiate.wast deleted file mode 100644 index cb99239..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/instantiate.wast +++ /dev/null @@ -1,976 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component definition - (import "a" (core module $m)) - (core instance $a (instantiate $m)) -) - -(component - (component - (import "a" (func $i)) - (import "b" (component $c (import "a" (func)))) - (instance (instantiate $c (with "a" (func $i)))) - ) -) - -(component - (component - (import "a" (component $i)) - (import "b" (component $c (import "a" (component)))) - (instance (instantiate $c (with "a" (component $i)))) - ) -) - -(component - (component - (import "a" (core module $i)) - (import "b" (component $c (import "a" (core module)))) - (instance (instantiate $c (with "a" (core module $i)))) - ) -) - -(component - (component - (import "a" (instance $i)) - (import "b" (component $c (import "a" (instance)))) - (instance (instantiate $c (with "a" (instance $i)))) - ) -) - -(component definition - (import "a" (core module $m - (import "" "a" (func)) - (import "" "b" (global i32)) - (import "" "c" (table 1 funcref)) - (import "" "d" (memory 1)) - )) - (import "b" (core module $m2 - (export "a" (func)) - (export "b" (global i32)) - (export "c" (table 1 funcref)) - (export "d" (memory 1)) - )) - (core instance $x (instantiate $m2)) - (core instance (instantiate $m (with "" (instance $x)))) -) - -(component definition - (import "a" (core module $m - (import "" "d" (func)) - (import "" "c" (global i32)) - (import "" "b" (table 1 funcref)) - (import "" "a" (memory 1)) - )) - (import "b" (core module $m2 - (export "a" (func)) - (export "b" (global i32)) - (export "c" (table 1 funcref)) - (export "d" (memory 1)) - )) - (core instance $x (instantiate $m2)) - - (core instance (instantiate $m (with "" (instance - (export "d" (func $x "a")) - (export "c" (global $x "b")) - (export "b" (table $x "c")) - (export "a" (memory $x "d")) - )))) -) - -(component - (component - (import "a" (component $m - (import "a" (instance - (export "a" (core module)) - )) - )) - (import "b" (component $m2 - (export "b" (core module)) - )) - (instance $x (instantiate $m2)) - - (instance (instantiate $m (with "a" (instance - (export "a" (core module $x "b")) - )))) - ) -) - -(component - (component - (import "a" (component $c - (import "a" (core module)) - (import "b" (func)) - (import "c" (component)) - (import "d" (instance)) - )) - (core module $m (import "b")) - (func $f (import "c")) - (component $c2 (import "d")) - (instance $i (import "e")) - - (instance - (instantiate $c - (with "a" (core module $m)) - (with "b" (func $f)) - (with "c" (component $c2)) - (with "d" (instance $i)) - ) - ) - - (core instance $c (instantiate $m)) - (core instance (instantiate $m)) - - ;; inline exports/imports - (type $empty (instance)) - (instance $d (import "g") (type $empty)) - (instance (import "h")) - (instance (import "i") - (export "x" (func))) - (instance (export "j") (export "k") (import "x")) - ) -) - -(assert_invalid - (component - (core instance (instantiate 0)) - ) - "unknown module") -(assert_invalid - (component - (instance (instantiate 0)) - ) - "unknown component") -(assert_invalid - (component - (import "a" (core module)) - (core instance (instantiate 1)) - ) - "unknown module") - -(component - (component - (import "a" (func $f)) - (import "b" (component $c)) - (instance (instantiate $c (with "a" (func $f)))) - ) -) -(assert_invalid - (component - (import "a" (core module $m (import "" "" (func)))) - (core instance (instantiate $m)) - ) - "missing module instantiation argument") -(assert_invalid - (component - (import "a" (component $m (import "a" (func)))) - (instance (instantiate $m)) - ) - "missing import named `a`") - -(assert_invalid - (component - (import "a" (component $m - (import "a" (func)) - )) - (import "b" (component $c)) - (instance $i (instantiate $m (with "a" (component $c)))) - ) - "expected func, found component") - -(assert_invalid - (component - (import "a" (component $m - (import "a" (func)) - )) - (import "b" (func $f (result string))) - (instance $i (instantiate $m (with "a" (func $f)))) - ) - "expected a result, found none") - -(assert_invalid - (component - (import "a" (component $m - (import "a" (func)) - )) - (import "b" (func (param "i" string))) - (instance $i (instantiate $m (with "a" (func 0)))) - ) - "expected 0 parameters, found 1") - -(assert_invalid - (component - (import "a" (component $m - (import "a" (core module - (import "" "" (func)) - )) - )) - (import "b" (core module $i - (import "" "" (global i32)) - )) - (instance $i (instantiate $m (with "a" (core module $i)))) - ) - "type mismatch in import `::`") - -(assert_invalid - (component - (import "a" (component $m - (import "a" (core module)) - )) - (import "b" (core module $i - (import "" "foobar" (global i32)) - )) - (instance $i (instantiate $m (with "a" (core module $i)))) - ) - "missing expected import `::foobar`") -(assert_invalid - (component - (import "a" (component $m - (import "a" (core module (export "x" (func)))) - )) - (import "b" (core module $i)) - (instance $i (instantiate $m (with "a" (core module $i)))) - ) - "missing expected export `x`") - -;; it's ok to give a module with fewer imports -(component - (component - (import "a" (component $m - (import "a" (core module - (import "" "" (global i32)) - (import "" "f" (func)) - )) - )) - (import "b" (core module $i - (import "" "" (global i32)) - )) - (instance $i (instantiate $m (with "a" (core module $i)))) - ) -) - -;; export subsets -(component - (component - (import "a" (component $m - (import "a" (core module - (export "" (func)) - )) - )) - (import "b" (core module $i - (export "" (func)) - (export "a" (func)) - )) - (instance $i (instantiate $m (with "a" (core module $i)))) - ) -) -(component - (component - (import "a" (component $m - (import "a" (instance - (export "a" (func)) - )) - )) - (import "b" (instance $i - (export "a" (func)) - (export "b" (func)) - )) - (instance (instantiate $m (with "a" (instance $i)))) - ) -) - - -;; ============================================================================ -;; core wasm type checking - -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (func)))) - (import "m2" (core module $m2 (export "" (func (param i32))))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "expected: (func)") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (func)))) - (import "m2" (core module $m2 (export "" (func (result i32))))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "expected: (func)") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (global i32)))) - (import "m2" (core module $m2 (export "" (global i64)))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "expected global type i32, found i64") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (table 1 funcref)))) - (import "m2" (core module $m2 (export "" (table 2 externref)))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "expected table element type funcref, found externref") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (table 1 2 funcref)))) - (import "m2" (core module $m2 (export "" (table 2 funcref)))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "mismatch in table limits") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (table 2 2 funcref)))) - (import "m2" (core module $m2 (export "" (table 1 funcref)))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "mismatch in table limits") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (table 2 2 funcref)))) - (import "m2" (core module $m2 (export "" (table 2 3 funcref)))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "mismatch in table limits") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (memory 1 2 shared)))) - (import "m2" (core module $m2 (export "" (memory 1)))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "mismatch in the shared flag for memories") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (memory 1)))) - (import "m2" (core module $m2 (export "" (memory 0)))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "mismatch in memory limits") -(assert_invalid - (component - (import "m1" (core module $m1 (export "g" (func)))) - (component $c - (import "m" (core module (export "g" (global i32)))) - ) - (instance (instantiate $c (with "m" (core module $m1)))) - ) - "type mismatch in export `g`") - -(assert_invalid - (component - (core instance (instantiate 0)) - ) - "unknown module") - -(component - (component $m - (core module $sub (export "module") - (func $f (export "") (result i32) - i32.const 5)) - ) - (instance $a (instantiate $m)) - (alias export $a "module" (core module $sub)) - (core instance $b (instantiate $sub)) - - (core module $final - (import "" "" (func $b (result i32))) - (func (export "get") (result i32) - call $b)) - - (core instance (instantiate $final (with "" (instance $b)))) -) - -(assert_invalid - (component (instance $i (export "" (func 0)))) - "function index out of bounds") - -(assert_invalid - (component (instance (export "" (instance 0)))) - "index out of bounds") - -(assert_invalid - (component (instance $i (export "" (component 0)))) - "index out of bounds") - -(assert_invalid - (component (instance (export "" (instance 0)))) - "index out of bounds") - -(assert_invalid - (component (instance $i (export "" (core module 0)))) - "index out of bounds") - -(assert_invalid - (component (core instance (export "" (func 0)))) - "index out of bounds") - -(assert_invalid - (component (core instance (export "" (table 0)))) - "index out of bounds") - -(assert_invalid - (component (core instance (export "" (global 0)))) - "index out of bounds") - -(assert_invalid - (component (core instance (export "" (memory 0)))) - "index out of bounds") - -(assert_invalid - (component - (core module $m) - (core instance $i (instantiate $m)) - (core instance (instantiate $m - (with "" (instance $i)) - (with "" (instance $i)) - )) - ) - "duplicate module instantiation argument named ``" -) - -(assert_invalid - (component - (core module $m (func (export ""))) - (core instance $i (instantiate $m)) - (core instance (instantiate $m - (with "" (instance $i)) - (with "" (instance $i)) - )) - ) - "duplicate module instantiation argument named ``") - -(assert_invalid - (component - (core module $m1 (func (export ""))) - (core module $m2 (import "" "" (global i32))) - (core instance $i (instantiate $m1)) - (core instance (instantiate $m2 - (with "" (instance $i)) - )) - ) - "expected global, found func") - -(assert_invalid - (component - (component $m) - (instance $i (instantiate $m)) - (instance (instantiate $m - (with "a" (instance $i)) - (with "a" (instance $i)) - )) - ) - "instantiation argument `a` conflicts with previous argument `a`") - -(assert_invalid - (component - (component $c (import "a" (func))) - (instance (instantiate $c - (with "a" (component $c)) - )) - ) - "expected func, found component") - -(assert_invalid - (component - (component $c) - (instance (instantiate $c - (with "" (core module 0)) - )) - ) - "index out of bounds") - -(assert_invalid - (component - (component $c) - (instance (instantiate $c - (with "" (instance 0)) - )) - ) - "index out of bounds") - -(assert_invalid - (component - (component $c) - (instance (instantiate $c - (with "" (func 0)) - )) - ) - "index out of bounds") - -(assert_invalid - (component - (component $c) - (instance (instantiate $c - (with "" (component 100)) - )) - ) - "index out of bounds") - -(assert_invalid - (component - (component $c) - (instance - (export "a" (component $c)) - (export "a" (component $c)) - ) - ) - "export name `a` conflicts with previous name `a`") - -(component - (component - (import "a" (instance $i)) - (import "b" (func $f)) - (import "c" (component $c)) - (import "d" (core module $m)) - (instance - (export "a" (instance $i)) - (export "b" (func $f)) - (export "c" (component $c)) - (export "d" (core module $m)) - ) - ) -) - -(component - (core module $m - (func (export "1")) - (memory (export "2") 1) - (table (export "3") 1 funcref) - (global (export "4") i32 i32.const 0) - ) - (core instance $i (instantiate $m)) - (core instance - (export "a" (func $i "1")) - (export "b" (memory $i "2")) - (export "c" (table $i "3")) - (export "d" (global $i "4")) - ) -) - -(assert_invalid - (component - (core module $m (func (export ""))) - (core instance $i (instantiate $m)) - (core instance - (export "" (func $i "")) - (export "" (func $i "")) - ) - ) - "export name `` already defined") - -(assert_invalid - (component - (component $c) - (instance $i (instantiate $c)) - (export "a" (instance $i "a")) - ) - "no export named `a`") - -(assert_invalid - (component - (export "a" (instance 100 "a")) - ) - "index out of bounds") - -(assert_invalid - (component - (import "a" (core module $libc - (export "memory" (memory 1)) - (export "table" (table 0 funcref)) - (export "func" (func)) - (export "global" (global i32)) - (export "global mut" (global (mut i64))) - )) - (core instance $libc (instantiate $libc)) - (alias core export $libc "memory" (core memory $mem)) - (alias core export $libc "table" (core table $tbl)) - (alias core export $libc "func" (core func $func)) - (alias core export $libc "global" (core global $global)) - (alias core export $libc "global mut" (core global $global_mut)) - - (import "x" (core module $needs_libc - (import "" "memory" (memory 1)) - (import "" "table" (table 0 funcref)) - (import "" "func" (func)) - (import "" "global" (global i32)) - (import "" "global mut" (global (mut i64))) - )) - - (core instance - (instantiate $needs_libc - (with "" (instance (export "memory" (memory $mem)))) - ) - ) - ) - "module instantiation argument `` does not export an item named `table`") - -;; Ensure a type can be an instantiation argument -(component - (type (tuple u32 u32)) - (import "a" (type (eq 0))) - (component - (type (tuple u32 u32)) - (import "a" (type (eq 0))) - ) - (instance (instantiate 0 - (with "a" (type 1)) - ) - ) -) - -(assert_invalid - (component - (type $t (tuple string string)) - (import "a" (type $a (eq $t))) - (component $c - (type $t (tuple u32 u32)) - (import "a" (type (eq $t))) - ) - (instance (instantiate $c - (with "a" (type $a)) - ) - ) - ) - "expected primitive `u32` found primitive `string`") - - -;; subtyping for module imports reverses order of imports/exports for the -;; subtyping check -;; -;; Here `C` imports a module, and the module itself imports a table of min size -;; 1. A module import which imports a min-size table of 0, however, is valid to -;; supply for this since it'll already be given at least 1 anyway. -;; -;; Similarly for exports `C` imports a module that exports a table of at least -;; size 1. If it's given a module that exports a larger table that's ok too. -(component - (core module $a - (import "" "" (table 0 funcref)) - (table (export "x") 2 funcref) - ) - (component $C - (import "a" (core module - (import "" "" (table 1 funcref)) - (export "x" (table 1 funcref)) - )) - ) - (instance (instantiate $C (with "a" (core module $a)))) -) - -;; same as above but for memories -(component - (core module $a1 (import "" "" (memory 0))) - (core module $a2 (memory (export "x") 2)) - (component $C - (import "a1" (core module (import "" "" (memory 1)))) - (import "a2" (core module (export "x" (memory 1)))) - ) - (instance (instantiate $C - (with "a1" (core module $a1)) - (with "a2" (core module $a2)) - )) -) - -(assert_invalid - (component - (import "x" (func $x (param "x" u32))) - (import "y" (component $c - (import "x" (func (param "y" u32))) - )) - - (instance (instantiate $c (with "x" (func $x)))) - ) - "expected parameter named `y`, found `x`") -(assert_invalid - (component - (import "x" (func $x (param "x" u32))) - (import "y" (component $c - (import "x" (func (param "x" s32))) - )) - - (instance (instantiate $c (with "x" (func $x)))) - ) - "type mismatch in function parameter `x`") -(assert_invalid - (component - (import "x" (func $x (result u32))) - (import "y" (component $c - (import "x" (func (result s32))) - )) - - (instance (instantiate $c (with "x" (func $x)))) - ) - "type mismatch with result type") - -(assert_invalid - (component - (import "x" (instance $x (export "a" (func)))) - (import "y" (component $c - (import "x" (instance $x (export "a" (component)))) - )) - - (instance (instantiate $c (with "x" (instance $x)))) - ) - "type mismatch in instance export `a`") - -(assert_invalid - (component - (import "y" (component $c - (type $t u32) - (import "x" (type (eq $t))) - )) - - (type $x (record (field "f" u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected primitive, found record") - -(assert_invalid - (component - (import "y" (component $c - (type $t (record (field "f" u32))) - (import "x" (type (eq $t))) - )) - - (type $x u32) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected record, found u32") - -(assert_invalid - (component - (import "y" (component $c - (type $t (record (field "x" u32))) - (import "x" (type (eq $t))) - )) - - (type $f (tuple u8)) - (type $x (record (field "x" $f))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected u32, found tuple") - -(assert_invalid - (component - (import "y" (component $c - (type $f (option s32)) - (type $t (record (field "x" $f))) - (import "x" (type (eq $t))) - )) - - (type $x (record (field "x" u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "type mismatch in record field `x`") - -(assert_invalid - (component - (import "y" (component $c - (type $t (record (field "x" u32))) - (import "x" (type (eq $t))) - )) - - (type $x (record (field "y" u32) (field "z" u64))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected 1 fields, found 2") - -(assert_invalid - (component - (import "y" (component $c - (type $t (record (field "a" u32))) - (import "x" (type (eq $t))) - )) - - (type $x (record (field "b" u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected field name `a`, found `b`") - -(assert_invalid - (component - (import "y" (component $c - (type $t (variant (case "x" u32))) - (import "x" (type (eq $t))) - )) - - (type $x (variant (case "x" u32) (case "y" u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected 1 cases, found 2") - -(assert_invalid - (component - (import "y" (component $c - (type $t (variant (case "x" u32))) - (import "x" (type (eq $t))) - )) - - (type $x (variant (case "y" u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected case named `x`, found `y`") - -(assert_invalid - (component - (import "y" (component $c - (type $t (variant (case "x" u32))) - (import "x" (type (eq $t))) - )) - - (type $x (variant (case "x"))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected case `x` to have a type, found none") - -(assert_invalid - (component - (import "y" (component $c - (type $t (variant (case "x"))) - (import "x" (type (eq $t))) - )) - - (type $x (variant (case "x" u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected case `x` to have no type") - -(assert_invalid - (component - (import "y" (component $c - (type $t (variant (case "x" u32))) - (import "x" (type (eq $t))) - )) - - (type $x (variant (case "x" s32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "type mismatch in variant case `x`") - -(assert_invalid - (component - (import "y" (component $c - (type $t (tuple u8)) - (import "x" (type (eq $t))) - )) - - (type $x (tuple u32 u32)) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected 1 types, found 2") - -(assert_invalid - (component - (import "y" (component $c - (type $t (tuple u8)) - (import "x" (type (eq $t))) - )) - - (type $x (tuple u16)) - (instance (instantiate $c (with "x" (type $x)))) - ) - "type mismatch in tuple field 0") - -(assert_invalid - (component - (import "y" (component $c - (type $t (flags "a")) - (import "x" (type (eq $t))) - )) - - (type $x (flags "x")) - (instance (instantiate $c (with "x" (type $x)))) - ) - "mismatch in flags elements") - -(assert_invalid - (component - (import "y" (component $c - (type $t (enum "a")) - (import "x" (type (eq $t))) - )) - - (type $x (enum "x")) - (instance (instantiate $c (with "x" (type $x)))) - ) - "mismatch in enum elements") - -(assert_invalid - (component - (import "y" (component $c - (type $t (result s32)) - (import "x" (type (eq $t))) - )) - - (type $x (result u32)) - (instance (instantiate $c (with "x" (type $x)))) - ) - "type mismatch in ok variant") - -(assert_invalid - (component - (import "y" (component $c - (type $t (result (error s32))) - (import "x" (type (eq $t))) - )) - - (type $x (result (error u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "type mismatch in err variant") - -(assert_invalid - (component - (import "y" (component $c - (type $t (result)) - (import "x" (type (eq $t))) - )) - - (type $x (result u32)) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected ok type to not be present") - -(assert_invalid - (component - (import "y" (component $c - (type $t (result u32)) - (import "x" (type (eq $t))) - )) - - (type $x (result)) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected ok type, but found none") - -(assert_invalid - (component - (import "y" (component $c - (type $t (result)) - (import "x" (type (eq $t))) - )) - - (type $x (result (error u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected err type to not be present") - -(assert_invalid - (component - (import "y" (component $c - (type $t (result (error u32))) - (import "x" (type (eq $t))) - )) - - (type $x (result)) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected err type, but found none") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/invalid.wast b/parser/src/test/resources/spec-tests/wasm-tools/invalid.wast deleted file mode 100644 index 267b31f..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/invalid.wast +++ /dev/null @@ -1,34 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_invalid - (component - (core type (module - (import "" "" (func (type 1))) - )) - (type (func)) - ) - "type index out of bounds") - -(assert_malformed - (component quote - "(export \"\" (func $foo))" - ) - "unknown func") - -(assert_malformed - (component quote - "(alias outer 100 $foo (type $foo))" - ) - "outer count of `100` is too large") - -(assert_malformed - (component quote - "(alias outer $nonexistent $foo (type $foo))" - ) - "outer component `nonexistent` not found") - -(assert_malformed - (component quote - "(import \"x\" (func $x))" - "(component (export \"x\" (func $x)))") - "outer item `x` is not a module, type, or component") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/link.wast b/parser/src/test/resources/spec-tests/wasm-tools/link.wast deleted file mode 100644 index 7202365..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/link.wast +++ /dev/null @@ -1,14 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -;; Based on this, we can link two modules $A and $B together with the following component: - -(component - (core module $A - (func (export "one") (result i32) (i32.const 1)) - ) - (core module $B - (func (import "a" "one") (result i32)) - ) - (core instance $a (instantiate $A)) - (core instance $b (instantiate $B (with "a" (instance $a)))) -) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast b/parser/src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast deleted file mode 100644 index 32e1a27..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast +++ /dev/null @@ -1,179 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component - (core module $m - (memory (export "m") 1) - (table (export "t") 1 funcref) - (global (export "g") i32 i32.const 0) - (func (export "f")) - ) - (core instance $i (instantiate $m)) - - ;; 160 memories (4 per row 40 rows) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - - ;; 160 tables (4 per row 40 rows) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - - ;; 160 globals (4 per row 40 rows) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - - ;; 160 functions (4 per row 40 rows) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) -) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/lower.wast b/parser/src/test/resources/spec-tests/wasm-tools/lower.wast deleted file mode 100644 index 5b9e13b..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/lower.wast +++ /dev/null @@ -1,17 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_invalid - (component - (import "f" (func $f (param "x" (list u8)))) - (core func $f (canon lower (func $f) - )) - ) - "canonical option `memory` is required") - -(assert_invalid - (component - (import "f" (func $f (result (list u8)))) - (core func $f (canon lower (func $f) - )) - ) - "canonical option `memory` is required") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/memory64.wast b/parser/src/test/resources/spec-tests/wasm-tools/memory64.wast deleted file mode 100644 index a72eb3b..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/memory64.wast +++ /dev/null @@ -1,55 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_invalid - (component - (core module $A - (import "" "" (memory 1))) - (core module $B - (memory (export "") i64 1)) - (core instance $b (instantiate $B)) - (core instance $a (instantiate $A (with "" (instance $b)))) - ) - "mismatch in index type used for memories") - -(assert_invalid - (component - (core module $A - (import "" "" (memory i64 1))) - (core module $B - (memory (export "") 1)) - (core instance $b (instantiate $B)) - (core instance $a (instantiate $A (with "" (instance $b)))) - ) - "mismatch in index type used for memories") - -(component - (core module $A - (memory (export "m") i64 1)) - (core instance $A (instantiate $A)) - (alias core export $A "m" (core memory $m)) - - (core module $B (import "" "" (memory i64 1))) - (core instance (instantiate $B (with "" (instance (export "" (memory $m)))))) -) - -(component - (core module $A - (table (export "m") i64 1 funcref)) - (core instance $A (instantiate $A)) - (alias core export $A "m" (core table $m)) - - (core module $B (import "" "" (table i64 1 funcref))) - (core instance (instantiate $B (with "" (instance (export "" (table $m)))))) -) - -(component - (import "x" (func $x (param "x" string))) - (core module $A - (memory (export "m") i64 1) - (func (export "realloc") (param i64 i64 i64 i64) (result i64) unreachable) - ) - (core instance $A (instantiate $A)) - (alias core export $A "m" (core memory $m)) - (core func $realloc (alias core export $A "realloc")) - (core func (canon lower (func $x) (memory $m) (realloc (func $realloc)))) -) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/module-link.wast b/parser/src/test/resources/spec-tests/wasm-tools/module-link.wast deleted file mode 100644 index 119da23..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/module-link.wast +++ /dev/null @@ -1,98 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component - (type $Wasi (instance)) - (component $B) - (component $B_wrap - (import "wasi" (instance $wasi (type $Wasi))) - (instance $b (instantiate $B)) - ) -) - -(component - (type $Wasi (instance)) - (import "wasi" (instance $wasi (type $Wasi))) - - (component $A - (type $Wasi (instance)) - (import "wasi" (instance (type $Wasi))) - - (core module $m - (func (export "a")) - ) - - (core instance $i (instantiate $m)) - (func (export "a") - (canon lift (core func $i "a")) - ) - ) - - (component $B - (type $Wasi (instance)) - (import "wasi" (instance $wasi (type $Wasi))) - (import "a1-x" (component $A - (import "wasi" (instance (type $Wasi))) - (export "a" (func)) - )) - (instance $a (instantiate $A (with "wasi" (instance $wasi)))) - - (core func $lower (canon lower (func $a "a"))) - (core module $b - (import "a" "a" (func)) - (func (export "b")) - ) - (core instance $b (instantiate $b - (with "a" (instance (export "a" (func $lower)))) - )) - (func (export "b") - (canon lift (core func $b "b")) - ) - ) - (component $B_wrap - (type $Wasi (instance)) - (import "wasi" (instance $wasi (type $Wasi))) - (instance $b (instantiate $B - (with "wasi" (instance $wasi)) - (with "a1-x" (component $A))) - ) - (export "b" (func $b "b")) - ) - - (component $C - (type $Wasi (instance)) - (import "wasi" (instance $wasi (type $Wasi))) - (import "b1-x" (component $B - (import "wasi" (instance $wasi (type $Wasi))) - (export "b" (func)) - )) - (instance $b (instantiate $B (with "wasi" (instance $wasi)))) - (export "c" (func $b "b")) - ) - (component $C_wrap - (type $Wasi (instance)) - (import "wasi" (instance $wasi (type $Wasi))) - (instance $c (instantiate $C - (with "wasi" (instance $wasi)) - (with "b1-x" (component $B_wrap)) - )) - (export "c" (func $c "c")) - ) - - (component $D - (type $Wasi (instance)) - (import "wasi" (instance $wasi (type $Wasi))) - (import "c1-x" (component $C - (import "wasi" (instance $wasi (type $Wasi))) - (export "c" (func)) - )) - (instance $c (instantiate $C (with "wasi" (instance $wasi)))) - (export "d" (func $c "c")) - ) - - (instance $d (instantiate $D - (with "wasi" (instance $wasi)) - (with "c1-x" (component $C_wrap)) - )) - - (export "d" (func $d "d")) -) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/more-flags.wast b/parser/src/test/resources/spec-tests/wasm-tools/more-flags.wast deleted file mode 100644 index ebcced0..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/more-flags.wast +++ /dev/null @@ -1,41 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_invalid - (component - (type (flags - "f1" - "f2" - "f3" - "f4" - "f5" - "f6" - "f7" - "f8" - "f9" - "f10" - "f11" - "f12" - "f13" - "f14" - "f15" - "f16" - "f17" - "f18" - "f19" - "f20" - "f21" - "f22" - "f23" - "f24" - "f25" - "f26" - "f27" - "f28" - "f29" - "f30" - "f31" - "f32" - "f33" - )) - ) - "cannot have more than 32 flags") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/naming.wast b/parser/src/test/resources/spec-tests/wasm-tools/naming.wast deleted file mode 100644 index 5decf55..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/naming.wast +++ /dev/null @@ -1,127 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component definition - (func (import "a")) - (component) - (instance (instantiate 0 (with "NotKebab-Case" (func 0)))) -) - -(assert_invalid - (component - (import "f" (func)) - (instance (export "1" (func 0))) - ) - "`1` is not in kebab case" -) - -(assert_invalid - (component - (instance) - (alias export 0 "Xml" (func)) - ) - "instance 0 has no export named `Xml`" -) - -(component definition - (type (flags "a-1-c")) -) - -(assert_invalid - (component - (type (enum "NevEr")) - ) - "enum tag name `NevEr` is not in kebab case" -) - -(assert_invalid - (component - (type (record (field "GoNnA" string))) - ) - "record field name `GoNnA` is not in kebab case" -) - -(assert_invalid - (component - (type (variant (case "GIVe" string))) - ) - "variant case name `GIVe` is not in kebab case" -) - - -(assert_invalid - (component - (type (func (param "yOu" string))) - ) - "function parameter name `yOu` is not in kebab case" -) - -(assert_invalid - (component - (type (component (export "NevEr" (func)))) - ) - "`NevEr` is not in kebab case" -) - -(assert_invalid - (component - (type (component (import "GonnA" (func)))) - ) - "`GonnA` is not in kebab case" -) - -(assert_invalid - (component - (type (instance (export "lET" (func)))) - ) - "`lET` is not in kebab case" -) - -(assert_invalid - (component - (instance (export "YoU")) - ) - "`YoU` is not in kebab case" -) - -(assert_invalid - (component - (instance (import "DOWn")) - ) - "`DOWn` is not in kebab case" -) - -(assert_invalid - (component - (instance (import "A:b/c")) - ) - "character `A` is not lowercase in package name/namespace" -) -(assert_invalid - (component - (instance (import "a:B/c")) - ) - "character `B` is not lowercase in package name/namespace" -) -(component - (instance (import "a:b/c")) - (instance (import "a1:b1/c")) -) - -(component definition - (import "a" (type $a (sub resource))) - (import "[constructor]a" (func (result (own $a)))) -) - -(assert_invalid - (component - (import "a" (type $a (sub resource))) - (import "[method]a.a" (func (param "self" (borrow $a)))) - ) - "import name `[method]a.a` conflicts with previous name `a`") - -(assert_invalid - (component - (import "a" (type $a (sub resource))) - (import "[static]a.a" (func)) - ) - "import name `[static]a.a` conflicts with previous name `a`") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/nested-modules.wast b/parser/src/test/resources/spec-tests/wasm-tools/nested-modules.wast deleted file mode 100644 index 5e629ea..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/nested-modules.wast +++ /dev/null @@ -1,50 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component definition - (import "i1" (core module)) - - (core module) - (core module) - - (core module (export "x")) - - (component - (core module) - ) - - (component - (core module $m) - (import "a" (func (param "p" string))) - (export "b" (core module $m)) - ) -) - -;; does the `import` use the type annotation specified later? -(component definition - (import "a" (core module)) - (core type (module)) -) - -;; be sure to typecheck nested modules -(assert_invalid - (component - (core module - (func - i32.add) - ) - ) - "type mismatch") - -;; interleave module definitions with imports/aliases and ensure that we -;; typecheck the module code section correctly -(component definition - (core module - (func (export "")) - ) - (import "a" (core module)) - (core module - (func (export "") (result i32) i32.const 5) - ) - (import "b" (instance (export "a" (core module)))) - (alias export 0 "a" (core module)) -) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/resources.wast b/parser/src/test/resources/spec-tests/wasm-tools/resources.wast deleted file mode 100644 index 14509c5..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/resources.wast +++ /dev/null @@ -1,1195 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component - (type $x (resource (rep i32))) -) - -(component - (type $x (resource (rep i32))) - - (core func (canon resource.new $x)) - (core func (canon resource.rep $x)) - (core func (canon resource.drop $x)) -) - -(component definition - (import "x" (type $x (sub resource))) - - (core func (canon resource.drop $x)) -) - -(component - (core module $m - (func (export "dtor") (param i32)) - ) - (core instance $m (instantiate $m)) - (type $x (resource (rep i32) (dtor (func $m "dtor")))) - (core func (canon resource.new $x)) -) - -(component - (type $x (resource (rep i32))) - (core func $f1 (canon resource.new $x)) - (core func $f2 (canon resource.rep $x)) - (core func $f3 (canon resource.drop $x)) - - (core module $m - (import "" "f1" (func (param i32) (result i32))) - (import "" "f2" (func (param i32) (result i32))) - (import "" "f3" (func (param i32))) - ) - - (core instance (instantiate $m - (with "" (instance - (export "f1" (func $f1)) - (export "f2" (func $f2)) - (export "f3" (func $f3)) - )) - )) -) - -(assert_invalid - (component - (type $x (resource (rep i64))) - ) - "resources can only be represented by `i32`") - -(assert_invalid - (component - (type $x (own 100)) - ) - "type index out of bounds") - -(assert_invalid - (component - (type $x (borrow 100)) - ) - "type index out of bounds") - -(assert_invalid - (component - (type $t u8) - (type $x (borrow $t)) - ) - "not a resource type") - -(assert_invalid - (component - (type $t u8) - (type $x (own $t)) - ) - "not a resource type") - -(assert_invalid - (component - (import "x" (type $x (sub resource))) - (core func (canon resource.new $x)) - ) - "not a local resource") - -(assert_invalid - (component - (import "x" (type $x (sub resource))) - (core func (canon resource.rep $x)) - ) - "not a local resource") - -(assert_invalid - (component - (type $t (tuple u32)) - (core func (canon resource.drop $t)) - ) - "not a resource type") - -(assert_invalid - (component - (core func (canon resource.drop 100)) - ) - "type index out of bounds") - -(assert_invalid - (component - (type (component)) - (core func (canon resource.drop 0)) - ) - "not a resource type") - -(assert_invalid - (component - (type (component)) - (core func (canon resource.new 0)) - ) - "not a resource type") - -(assert_invalid - (component - (core module $m - (func (export "dtor")) - ) - (core instance $m (instantiate $m)) - (type $x (resource (rep i32) (dtor (func $m "dtor")))) - (core func (canon resource.new $x)) - ) - "wrong signature for a destructor") - -(assert_invalid - (component - (type (resource (rep i32) (dtor (func 100)))) - ) - "function index out of bounds") - -(assert_invalid - (component - (import "x" (type $x (sub resource))) - (import "y" (type $y (sub resource))) - (import "z" (func $z (param "x" (own $x)) (param "y" (own $y)))) - - (component $c - (import "x" (type $x (sub resource))) - (import "z" (func (param "x" (own $x)) (param "y" (own $x)))) - ) - - (instance (instantiate $c (with "x" (type $x)) (with "z" (func $z)))) - ) - "resource types are not the same") - -(component - (type (component - (import "x" (type $x (sub resource))) - (export "y" (type (eq $x))) - (export "z" (type (sub resource))) - )) -) - -(assert_invalid - (component - (type (component - (type $x (resource (rep i32))) - )) - ) - "resources can only be defined within a concrete component") - -(assert_invalid - (component - (type (instance - (type $x (resource (rep i32))) - )) - ) - "resources can only be defined within a concrete component") - -(component - (type (component - (import "x" (instance $i - (export "t" (type $t (sub resource))) - (export "f" (func (result (own $t)))) - )) - (alias export $i "t" (type $t)) - (export "f" (func (result (own $t)))) - )) -) - -(component definition - (import "fancy-fs" (instance $fancy-fs - (export "fs" (instance $fs - (export "file" (type (sub resource))) - )) - (alias export $fs "file" (type $file)) - (export "fancy-op" (func (param "f" (borrow $file)))) - )) -) - -(component $C - (type $T (list (tuple string bool))) - (type $U (option $T)) - (type $G (func (param "x" (list $T)) (result $U))) - (type $D (component - (alias outer $C $T (type $C_T)) - (type $L (list $C_T)) - (import "f" (func (param "x" $L) (result (list u8)))) - (import "g" (func (type $G))) - (export "g2" (func (type $G))) - (export "h" (func (result $U))) - (import "T" (type $T (sub resource))) - (import "i" (func (param "x" (list (own $T))))) - (export "T2" (type $T' (eq $T))) - (export "U" (type $U' (sub resource))) - (export "j" (func (param "x" (borrow $T')) (result (own $U')))) - )) -) - -(component definition - (import "T1" (type $T1 (sub resource))) - (import "T2" (type $T2 (sub resource))) -) - -(component definition $C - (import "T1" (type $T1 (sub resource))) - (import "T2" (type $T2 (sub resource))) - (import "T3" (type $T3 (eq $T2))) - (type $ListT1 (list (own $T1))) - (type $ListT2 (list (own $T2))) - (type $ListT3 (list (own $T3))) -) - -(component definition - (import "T" (type $T (sub resource))) - (import "U" (type $U (sub resource))) - (type $Own1 (own $T)) - (type $Own2 (own $T)) - (type $Own3 (own $U)) - (type $ListOwn1 (list $Own1)) - (type $ListOwn2 (list $Own2)) - (type $ListOwn3 (list $Own3)) - (type $Borrow1 (borrow $T)) - (type $Borrow2 (borrow $T)) - (type $Borrow3 (borrow $U)) - (type $ListBorrow1 (list $Borrow1)) - (type $ListBorrow2 (list $Borrow2)) - (type $ListBorrow3 (list $Borrow3)) -) - -(component - (component - (import "C" (component $C - (export "T1" (type (sub resource))) - (export "T2" (type $T2 (sub resource))) - (export "T3" (type (eq $T2))) - )) - (instance $c (instantiate $C)) - (alias export $c "T1" (type $T1)) - (alias export $c "T2" (type $T2)) - (alias export $c "T3" (type $T3)) - ) -) - -(component - (component $C - (type $r1 (export "r1") (resource (rep i32))) - (type $r2 (export "r2") (resource (rep i32))) - ) - (instance $c1 (instantiate $C)) - (instance $c2 (instantiate $C)) - (alias export $c1 "r1" (type $c1r1)) - (alias export $c1 "r2" (type $c1r2)) - (alias export $c2 "r1" (type $c2r1)) - (alias export $c2 "r2" (type $c2r2)) -) - -(component - (type $r (resource (rep i32))) - (export "r1" (type $r)) - (export "r2" (type $r)) -) - -(component - (type (component - (export "r1" (type (sub resource))) - (export "r2" (type (sub resource))) - )) -) - -(component - (type $r (resource (rep i32))) - (export $r1 "r1" (type $r)) - (export "r2" (type $r1)) -) - -(component - (type (component - (export "r1" (type $r1 (sub resource))) - (export "r2" (type (eq $r1))) - )) -) - -(component - (component $P - (import "C1" (component $C1 - (import "T" (type $T (sub resource))) - (export "foo" (func (param "t" (own $T)))) - )) - (import "C2" (component $C2 - (import "T" (type $T (sub resource))) - (import "foo" (func (param "t" (own $T)))) - )) - (type $R (resource (rep i32))) - (instance $c1 (instantiate $C1 (with "T" (type $R)))) - (instance $c2 (instantiate $C2 - (with "T" (type $R)) - (with "foo" (func $c1 "foo")) - )) - ) -) - -(component - (component - (import "C1" (component $C1 - (import "T1" (type $T1 (sub resource))) - (import "T2" (type $T2 (sub resource))) - (export "foo" (func (param "t" (tuple (own $T1) (own $T2))))) - )) - (import "C2" (component $C2 - (import "T" (type $T (sub resource))) - (export "foo" (func (param "t" (tuple (own $T) (own $T))))) - )) - (type $R (resource (rep i32))) - (instance $c1 (instantiate $C1 - (with "T1" (type $R)) - (with "T2" (type $R)) - )) - (instance $c2 (instantiate $C2 - (with "T" (type $R)) - (with "foo" (func $c1 "foo")) - )) - ) -) - -(assert_invalid - (component - (component $C - (type $R (resource (rep i32))) - (export "R" (type $R)) - ) - (instance $c (instantiate $C)) - (alias export $c "R" (type $R)) - (core func (canon resource.rep $R)) - ) - "not a local resource") - -(component - (component $C - (type $R (resource (rep i32))) - (export "R" (type $R)) - ) - (instance $c (instantiate $C)) - (alias export $c "R" (type $R)) - (core func (canon resource.drop $R)) -) - -(component - (component $C1 - (import "X" (type (sub resource))) - ) - (component $C2 - (import "C1" (component - (import "X" (type (sub resource))) - )) - ) - (instance $c (instantiate $C2 (with "C1" (component $C1)))) -) - -(component - (component $C1 - (import "X" (type $X (sub resource))) - (import "f" (func $f (result (own $X)))) - (export "g" (func $f)) - ) - (component $C2 - (import "C1" (component - (import "X" (type $X (sub resource))) - (import "f" (func (result (own $X)))) - (export "g" (func (result (own $X)))) - )) - ) - (instance $c (instantiate $C2 (with "C1" (component $C1)))) -) - -(component - (component $C1 - (type $X' (resource (rep i32))) - (export $X "X" (type $X')) - - (core func $f (canon resource.drop $X)) - (func (export "f") (param "X" (own $X)) (canon lift (core func $f))) - ) - (instance $c1 (instantiate $C1)) - - (component $C2 - (import "X" (type $X (sub resource))) - (import "f" (func (param "X" (own $X)))) - ) - (instance $c2 (instantiate $C2 - (with "X" (type $c1 "X")) - (with "f" (func $c1 "f")) - )) -) - -(assert_invalid - (component - (component $C1 - (type $X' (resource (rep i32))) - (export $X "X" (type $X')) - - (core func $f (canon resource.drop $X)) - (func (export "f") (param "X" (own $X)) (canon lift (core func $f))) - ) - (instance $c1 (instantiate $C1)) - (instance $c2 (instantiate $C1)) - - (component $C2 - (import "X" (type $X (sub resource))) - (import "f" (func (param "X" (own $X)))) - ) - (instance $c3 (instantiate $C2 - (with "X" (type $c1 "X")) - (with "f" (func $c2 "f")) - )) - ) - "resource types are not the same") - -(component - (component $C1 - (type $X (resource (rep i32))) - (export $X1 "X1" (type $X)) - (export $X2 "X2" (type $X)) - - (core func $f (canon resource.drop $X)) - (func (export "f1") (param "X" (own $X1)) (canon lift (core func $f))) - (func (export "f2") (param "X" (own $X2)) (canon lift (core func $f))) - ) - (instance $c1 (instantiate $C1)) - - (component $C2 - (import "X" (type $X (sub resource))) - (import "f" (func (param "X" (own $X)))) - ) - (instance $c2 (instantiate $C2 - (with "X" (type $c1 "X1")) - (with "f" (func $c1 "f1")) - )) - (instance $c3 (instantiate $C2 - (with "X" (type $c1 "X2")) - (with "f" (func $c1 "f2")) - )) -) - -(component - (component $C1 - (type $X (resource (rep i32))) - (export $X1 "X1" (type $X)) - (export $X2 "X2" (type $X)) - - (core func $f (canon resource.drop $X)) - (func (export "f1") (param "X" (own $X1)) (canon lift (core func $f))) - (func (export "f2") (param "X" (own $X2)) (canon lift (core func $f))) - ) - (instance $c1 (instantiate $C1)) - - (component $C2 - (import "X" (type $X (sub resource))) - (import "f" (func (param "X" (own $X)))) - ) - (instance $c2 (instantiate $C2 - (with "X" (type $c1 "X1")) - (with "f" (func $c1 "f2")) - )) - (instance $c3 (instantiate $C2 - (with "X" (type $c1 "X2")) - (with "f" (func $c1 "f1")) - )) -) - -(assert_invalid - (component - (component $c - (import "x" (type (sub resource))) - ) - (type $x u32) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected resource, found defined type") - -(assert_invalid - (component - (component $c - (type $t u32) - (import "x" (type (eq $t))) - ) - (type $x (resource (rep i32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected defined type, found resource") - -(assert_invalid - (component - (component $c - (import "x1" (type $x1 (sub resource))) - (import "x2" (type $x2 (eq $x1))) - ) - (type $x1 (resource (rep i32))) - (type $x2 (resource (rep i32))) - (instance (instantiate $c - (with "x1" (type $x1)) - (with "x2" (type $x2)) - )) - ) - "resource types are not the same") - -(component - (type $x (resource (rep i32))) - (component $c - (import "x" (type $t (sub resource))) - (export "y" (type $t)) - ) - (instance $c (instantiate $c (with "x" (type $x)))) - - (alias export $c "y" (type $x2)) - (core func (canon resource.rep $x2)) - -) - -(assert_invalid - (component - (type $r (resource (rep i32))) - (import "x" (func (result (own $r)))) - ) - "func not valid to be used as import") - -(assert_invalid - (component - (type (component - (export "x" (type $x (sub resource))) - (import "f" (func (result (own $x)))) - )) - ) - "func not valid to be used as import") - -(assert_invalid - (component - (type $r (resource (rep i32))) - - (core func $f (canon resource.drop $r)) - (func (export "f") (param "x" (own $r)) - (canon lift (core func $f))) - ) - "func not valid to be used as export") - -;; direct exports count as "explicit in" for resources -(component - (type $r' (resource (rep i32))) - (export $r "r" (type $r')) - - (core func $f (canon resource.drop $r)) - (func (export "f") (param "x" (own $r)) - (canon lift (core func $f))) -) - -;; instances-as-a-bundle count as "explicit in" for resources -(component - (type $r' (resource (rep i32))) - (instance $i' - (export "r" (type $r')) - ) - (export $i "i" (instance $i')) - (alias export $i "r" (type $r)) - - (core func $f (canon resource.drop $r)) - (func (export "f") (param "x" (own $r)) - (canon lift (core func $f))) -) - -;; Transitive bundles count for "explicit in" -(component - (type $r' (resource (rep i32))) - (instance $i' - (export "r" (type $r')) - ) - (instance $i2' - (export "i" (instance $i')) - ) - (export $i2 "i2" (instance $i2')) - (alias export $i2 "i" (instance $i)) - (alias export $i "r" (type $r)) - - (core func $f (canon resource.drop $r)) - (func (export "f") (param "x" (own $r)) - (canon lift (core func $f))) -) - -;; Component instantiations count for "explicit in" -(component - (type $r' (resource (rep i32))) - (component $C - (import "x" (type $x (sub resource))) - (export "y" (type $x)) - ) - (instance $c' (instantiate $C (with "x" (type $r')))) - (export $c "c" (instance $c')) - (alias export $c "y" (type $r)) - - (core func $f (canon resource.drop $r)) - (func (export "f") (param "x" (own $r)) - (canon lift (core func $f))) -) - -;; Make sure threading things around is valid for "explicit in" -(component - (type $r' (resource (rep i32))) - (component $C - (import "x" (type $x (sub resource))) - (export "y" (type $x)) - ) - (instance $c (instantiate $C (with "x" (type $r')))) - (instance $i (export "x" (type $c "y"))) - - (component $C2 - (import "x" (instance $i - (export "i1" (instance - (export "i2" (type (sub resource))) - )) - )) - (export "y" (type $i "i1" "i2")) - ) - - (instance $i2 (export "i2" (type $i "x"))) - (instance $i1 (export "i1" (instance $i2))) - (instance $c2 (instantiate $C2 - (with "x" (instance $i1)) - )) - (export $r "x" (type $c2 "y")) - - (core func $f (canon resource.drop $r)) - (func (export "f") (param "x" (own $r)) - (canon lift (core func $f))) -) - -;; Importing-and-exporting instances through instantiation counts for "explicit -;; in" -(component - (type $r' (resource (rep i32))) - (component $C - (import "x" (instance $x (export "t" (type (sub resource))))) - (export "y" (instance $x)) - ) - (instance $c' (instantiate $C - (with "x" (instance - (export "t" (type $r')) - )) - )) - (export $c "c" (instance $c')) - (alias export $c "y" (instance $y)) - (alias export $y "t" (type $r)) - - (core func $f (canon resource.drop $r)) - (func (export "f") (param "x" (own $r)) - (canon lift (core func $f))) -) - -(component definition - (type $i (instance - (export "r" (type $r (sub resource))) - (export "f" (func (result (own $r)))) - )) - (import "i1" (instance $i1 (type $i))) - (import "i2" (instance $i2 (type $i))) - - (component $c - (import "r" (type $t (sub resource))) - (import "f" (func (result (own $t)))) - ) - (instance (instantiate $c - (with "r" (type $i1 "r")) - (with "f" (func $i1 "f")) - )) - (instance (instantiate $c - (with "r" (type $i2 "r")) - (with "f" (func $i2 "f")) - )) -) - - -(assert_invalid - (component - (type $i (instance - (export "r" (type $r (sub resource))) - (export "f" (func (result (own $r)))) - )) - (import "i1" (instance $i1 (type $i))) - (import "i2" (instance $i2 (type $i))) - - (component $c - (import "r" (type $t (sub resource))) - (import "f" (func (result (own $t)))) - ) - (instance (instantiate $c - (with "r" (type $i1 "r")) - (with "f" (func $i2 "f")) - )) - ) - "resource types are not the same") - -;; substitution works -(component - (type $t (resource (rep i32))) - (component $c - (import "x" (type $t (sub resource))) - (export "y" (type $t)) - ) - (instance $c1 (instantiate $c (with "x" (type $t)))) - (instance $c2 (instantiate $c (with "x" (type $t)))) - - (component $c2 - (import "x1" (type $t (sub resource))) - (import "x2" (type (eq $t))) - (import "x3" (type (eq $t))) - ) - (instance (instantiate $c2 - (with "x1" (type $t)) - (with "x2" (type $c1 "y")) - (with "x3" (type $c2 "y")) - )) -) - -;; must supply a resource to instantiation -(assert_invalid - (component - (component $c - (import "x" (type (sub resource))) - ) - (instance (instantiate $c)) - ) - "missing import named `x`") -(assert_invalid - (component - (type $x (resource (rep i32))) - (component $c - (import "x" (type (sub resource))) - (import "y" (type (sub resource))) - ) - (instance (instantiate $c (with "x" (type $x)))) - ) - "missing import named `y`") - -;; supply the wrong resource -(assert_invalid - (component - (type $x (resource (rep i32))) - (type $y (resource (rep i32))) - (component $c - (import "x" (type $t (sub resource))) - (import "y" (type (eq $t))) - ) - (instance (instantiate $c - (with "x" (type $x)) - (with "y" (type $y)) - )) - ) - "resource types are not the same") - -;; aliasing outer resources is ok -(component $A - (type $C (component - (import "x" (type $x (sub resource))) - - (type $y (component - (alias outer $C $x (type $my-x)) - (import "x" (type (eq $my-x))) - )) - - (import "y" (component (type $y))) - (export "z" (component (type $y))) - )) - - (type $t (resource (rep i32))) - - (alias outer $A $t (type $other-t)) - - (type (instance (export "t" (type (eq $t))))) - (type (component (export "t" (type (eq $t))))) - (type (component (import "t" (type (eq $t))))) -) - -;; aliasing beyond components, however, is not ok -(assert_invalid - (component $A - (type $t (resource (rep i32))) - (component (alias outer $A $t (type $foo))) - ) - "refers to resources not defined in the current component") -(assert_invalid - (component $A - (type $t (resource (rep i32))) - (type $u (record (field "x" (own $t)))) - (component (alias outer $A $u (type $foo))) - ) - "refers to resources not defined in the current component") -(assert_invalid - (component $A - (type $t (resource (rep i32))) - (type $u (borrow $t)) - (component (alias outer $A $u (type $foo))) - ) - "refers to resources not defined in the current component") -(assert_invalid - (component $A - (type $t (resource (rep i32))) - (type $u (component (export "a" (type (eq $t))))) - (component (alias outer $A $u (type $foo))) - ) - "refers to resources not defined in the current component") -(assert_invalid - (component $A - (type $t (resource (rep i32))) - (type $u (component (import "a" (type (eq $t))))) - (component (alias outer $A $u (type $foo))) - ) - "refers to resources not defined in the current component") - -(assert_invalid - (component - (component $X - (type $t (resource (rep i32))) - (export "t" (type $t)) - ) - (component $F - (import "x" (component (export "t" (type $t (sub resource))))) - ) - (instance $x1 (instantiate $X)) - (instance $f1 (instantiate $F (with "x" (instance $x1)))) - ) - "expected component, found instance") - -;; Show that two instantiations of the same component produce unique exported -;; resource types. -(assert_invalid - (component - (component $F - (type $t1 (resource (rep i32))) - (export "t1" (type $t1)) - ) - (instance $f1 (instantiate $F)) - (instance $f2 (instantiate $F)) - (alias export $f1 "t1" (type $t1)) - (alias export $f2 "t1" (type $t2)) - (component $T - (import "x" (type $x (sub resource))) - (import "y" (type (eq $x))) - ) - (instance $test - (instantiate $T (with "x" (type $t1)) (with "y" (type $t2)))) - ) - "type mismatch for import `y`") - -;; Show that re-exporting imported resources from an imported component doesn't -;; change the identity of that resource. -(component - (component $X - (type $t (resource (rep i32))) - (export "t" (type $t)) - ) - (component $F - (import "x" (instance $i (export "t" (type $t (sub resource))))) - (alias export $i "t" (type $t)) - (export "t" (type $t)) - ) - (instance $x1 (instantiate $X)) - (instance $f1 (instantiate $F (with "x" (instance $x1)))) - (instance $f2 (instantiate $F (with "x" (instance $x1)))) - (alias export $f1 "t" (type $t1)) - (alias export $f2 "t" (type $t2)) - (component $T - (import "x" (type $x (sub resource))) - (import "y" (type (eq $x))) - ) - (instance $test - (instantiate $T (with "x" (type $t1)) (with "y" (type $t2)))) -) - -(assert_invalid - (component (import "[static]" (func))) - "failed to find `.` character") - -;; validation of `[constructor]foo` -(assert_invalid - (component (import "[constructor]" (func))) - "not in kebab case") -(assert_invalid - (component (import "[constructor]a" (func))) - "should return one value") -(assert_invalid - (component (import "[constructor]a" (func (result u32)))) - "should return `(own $T)`") -(assert_invalid - (component - (import "b" (type $a (sub resource))) - (import "[constructor]a" (func (result (own $a))))) - "import name `[constructor]a` is not valid") -(assert_invalid - (component - (import "b" (type $a (sub resource))) - (import "[constructor]a" (func (result (own $a))))) - "function does not match expected resource name `b`") -(assert_invalid - (component - (import "b" (type $a (sub resource))) - (import "[constructor]a" (func (result (result(own $a)))))) - "function does not match expected resource name `b`") -(component definition - (import "a" (type $a (sub resource))) - (import "[constructor]a" (func (result (own $a))))) -(component definition - (import "a" (type $a (sub resource))) - (import "[constructor]a" (func (result (result (own $a)))))) -(component definition - (import "a" (type $a (sub resource))) - (import "[constructor]a" (func (result (result (own $a) (error string)))))) -(component definition - (import "a" (type $a (sub resource))) - (import "[constructor]a" (func (param "x" u32) (result (own $a))))) -(assert_invalid - (component - (import "a" (type $a (sub resource))) - (import "[constructor]a" (func (result string)))) - "function should return `(own $T)` or `(result (own $T))`") -(assert_invalid - (component - (import "a" (type $a (sub resource))) - (import "[constructor]a" (func (result (result string))))) - "function should return `(own $T)` or `(result (own $T))`") - -;; validation of `[method]a.b` -(assert_invalid - (component (import "[method]" (func))) - "failed to find `.` character") -(assert_invalid - (component (import "[method]a" (func))) - "failed to find `.` character") -(assert_invalid - (component (import "[method]a." (func))) - "not in kebab case") -(assert_invalid - (component (import "[method].a" (func))) - "not in kebab case") -(assert_invalid - (component (import "[method]a.b.c" (func))) - "not in kebab case") -(assert_invalid - (component (import "[method]a.b" (instance))) - "is not a func") -(assert_invalid - (component (import "[method]a.b" (func))) - "should have at least one argument") -(assert_invalid - (component (import "[method]a.b" (func (param "x" u32)))) - "should have a first argument called `self`") -(assert_invalid - (component (import "[method]a.b" (func (param "self" u32)))) - "should take a first argument of `(borrow $T)`") -(assert_invalid - (component - (import "b" (type $T (sub resource))) - (import "[method]a.b" (func (param "self" (borrow $T))))) - "does not match expected resource name") -(component definition - (import "a" (type $T (sub resource))) - (import "[method]a.b" (func (param "self" (borrow $T))))) - -;; validation of `[static]a.b` -(assert_invalid - (component (import "[static]" (func))) - "failed to find `.` character") -(assert_invalid - (component (import "[static]a" (func))) - "failed to find `.` character") -(assert_invalid - (component (import "[static]a." (func))) - "not in kebab case") -(assert_invalid - (component (import "[static].a" (func))) - "not in kebab case") -(assert_invalid - (component (import "[static]a.b.c" (func))) - "not in kebab case") -(assert_invalid - (component (import "[static]a.b" (instance))) - "is not a func") -(assert_invalid - (component (import "[static]a.b" (func))) - "static resource name is not known in this context") - -(component definition - (import "a" (type (sub resource))) - (import "[static]a.b" (func))) - -;; exports/imports are disjoint -(assert_invalid - (component - (import "b" (type $T (sub resource))) - (import "f" (func $f (param "self" (borrow $T)))) - (export "[method]b.foo" (func $f)) - ) - "resource used in function does not have a name in this context") - -(component - (component - (import "b" (type $T (sub resource))) - (import "f" (func $f (param "self" (borrow $T)))) - (export $c "c" (type $T)) - (export "[method]c.foo" (func $f) (func (param "self" (borrow $c)))) - ) -) - -;; imports aren't transitive -(assert_invalid - (component - (import "i" (instance $i - (export "t" (type (sub resource))) - )) - (alias export $i "t" (type $t)) - (import "[method]t.foo" (func (param "self" (borrow $t)))) - ) - "resource used in function does not have a name in this context") - -;; validation happens in a type context -(assert_invalid - (component - (type (component - (import "b" (type $T (sub resource))) - (import "[constructor]a" (func (result (own $T)))) - )) - ) - "function does not match expected resource name `b`") - -;; bag-of-exports validation -(assert_invalid - (component - (type $T (resource (rep i32))) - (core module $m (func (export "a") (result i32) unreachable)) - (core instance $i (instantiate $m)) - (func $f (result (own $T)) (canon lift (core func $i "a"))) - (instance - (export "a" (type $T)) - (export "[constructor]a" (func $f)) - ) - ) - "resource used in function does not have a name in this context") - -(component - (component $C) - (instance (instantiate $C (with "this is not kebab case" (component $C)))) -) - -;; Test that unused arguments to instantiation are not validated to have -;; appropriate types with respect to kebab naming conventions which require -;; functions/interfaces/etc. -(component - (component $C) - (instance (instantiate $C (with "[method]foo.bar" (component $C)))) -) - -;; thread a resource through a few layers -(component - (component $C - (import "in" (type $r (sub resource))) - (export "out" (type $r)) - ) - - (type $r (resource (rep i32))) - - (instance $c1 (instantiate $C (with "in" (type $r)))) - (instance $c2 (instantiate $C (with "in" (type $c1 "out")))) - (instance $c3 (instantiate $C (with "in" (type $c2 "out")))) - (instance $c4 (instantiate $C (with "in" (type $c3 "out")))) - (instance $c5 (instantiate $C (with "in" (type $c4 "out")))) - - (component $C2 - (import "in1" (type $r (sub resource))) - (import "in2" (type (eq $r))) - (import "in3" (type (eq $r))) - (import "in4" (type (eq $r))) - (import "in5" (type (eq $r))) - (import "in6" (type (eq $r))) - ) - - (instance (instantiate $C2 - (with "in1" (type $r)) - (with "in2" (type $c1 "out")) - (with "in3" (type $c2 "out")) - (with "in4" (type $c3 "out")) - (with "in5" (type $c4 "out")) - (with "in6" (type $c5 "out")) - )) -) - -;; exporting an instance type "freshens" resources -(assert_invalid - (component - (import "x" (instance $i - (type $i (instance - (export "r" (type (sub resource))) - )) - (export "a" (instance (type $i))) - (export "b" (instance (type $i))) - )) - - (component $C - (import "x" (type $x (sub resource))) - (import "y" (type (eq $x))) - ) - (instance (instantiate $C - (with "x" (type $i "a" "r")) - (with "y" (type $i "b" "r")) - )) - ) - "resource types are not the same") - -(component - (type (export "x") (component - (type $t' (instance - (export "r" (type (sub resource))) - )) - (export "t" (instance $t (type $t'))) - (alias export $t "r" (type $r)) - (type $t2' (instance - (export "r2" (type (eq $r))) - (export "r" (type (sub resource))) - )) - (export "t2" (instance (type $t2'))) - )) -) - -(component - (type (component - (type (instance - (export "bar" (type (sub resource))) - (export "[static]bar.a" (func)) - )) - (export "x" (instance (type 0))) - )) -) - -(assert_invalid - (component - (type $r (resource (rep i32))) - (type (func (result (borrow $r)))) - ) - "function result cannot contain a `borrow` type") -(assert_invalid - (component - (type $r (resource (rep i32))) - (type (func (result (list (borrow $r))))) - ) - "function result cannot contain a `borrow` type") -(assert_invalid - (component - (type $r (resource (rep i32))) - (type (func (result (option (borrow $r))))) - ) - "function result cannot contain a `borrow` type") -(assert_invalid - (component - (type $r (resource (rep i32))) - (type $t (record (field "f" (borrow $r)))) - (type (func (result (option (list $t))))) - ) - "function result cannot contain a `borrow` type") - -;; forms of canon builtins -(component - (type $r (resource (rep i32))) - (core func (canon resource.new $r)) - (canon resource.new $r (core func)) - (core func (canon resource.drop $r)) - (canon resource.drop $r (core func)) - (core func (canon resource.rep $r)) - (canon resource.rep $r (core func)) -) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/tags.wast b/parser/src/test/resources/spec-tests/wasm-tools/tags.wast deleted file mode 100644 index 5c70d3a..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/tags.wast +++ /dev/null @@ -1,30 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_invalid - (component - (core module $m (func (export ""))) - (core instance $i (instantiate $m)) - (alias core export $i "" (core tag $t)) - ) - "export `` for core instance 0 is not a tag") - -(component - (core module $m (tag (export ""))) - (core instance $i (instantiate $m)) - (alias core export $i "" (core tag $t)) -) - -(component - (core module $m (tag (export ""))) - (core instance $i (instantiate $m)) - (core instance - (export "" (tag $i "")))) - -(assert_invalid - (component - (core module $m (func (export ""))) - (core instance $i (instantiate $m)) - (core instance - (export "" (tag 0))) - ) - "unknown tag 0") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast b/parser/src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast deleted file mode 100644 index d2971f8..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast +++ /dev/null @@ -1,504 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -;; Test that unnamed types in various types are all detected - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (record (field "f" $t))) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (list $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (tuple $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (variant (case "c" $t))) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (option $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (result $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -;; Test that various types are all flagged as "requires a name" - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (list $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (enum "a")) - (type $f (list $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (flags "a")) - (type $f (list $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (variant (case "a"))) - (type $f (list $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (resource (rep i32))) - (type $f (list (own $t))) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -;; Some types don't need names -(component - (type $t1 (tuple (tuple u32))) - (export "t1" (type $t1)) - - (type $t2 (option (tuple (list u8) (result (list u32) (error (option string)))))) - (export "t2" (type $t2)) - - (type $t3 u32) - (export "t3" (type $t3)) -) - -(component - (type $t' (record (field "f" u32))) - (export $t "t" (type $t')) - (type $t2 (record (field "x" $t))) - (export "t2" (type $t2)) -) - -;; imports are validated as well -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $t2 (record (field "f" $t))) - (import "x" (type (eq $t2))) - ) - "type not valid to be used as import") -(component - (type $t (record (field "f" u32))) - (import "t" (type $t' (eq $t))) - (type $t2 (record (field "f" $t'))) - (import "x" (type (eq $t2))) -) -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $t2 (record (field "f" $t))) - (import "x" (func (param "x" $t2))) - ) - "func not valid to be used as import") - -(assert_invalid - (component - (type $t (resource (rep i32))) - (export "t" (type $t)) - (type $f (list (own $t))) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -;; validate within the type context -(assert_invalid - (component - (type (component - (type $t (record (field "f" u32))) - (export "f" (func (param "x" $t))) - )) - ) - "func not valid to be used as export") -(assert_invalid - (component - (type (component - (type $t (record (field "f" u32))) - (type $f (record (field "t" $t))) - (export "f" (type (eq $f))) - )) - ) - "type not valid to be used as export") - -;; instances of unexported types is ok -(component - (type $t (record (field "f" u32))) - (type $f (record (field "t" $t))) - (instance - (export "f" (type $f)) - ) -) -;; .. but exporting them is not -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (record (field "t" $t))) - (instance $i - (export "f" (type $f)) - ) - (export "i" (instance $i)) - ) - "instance not valid to be used as export") - -;; Can't export a lifted function with unexported types -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (record (field "t" $t))) - - (core module $m (func $f (export "f") (param i32))) - (core instance $i (instantiate $m)) - (func $f (param "f" $f) (canon lift (core func $i "f"))) - (export "f" (func $f)) - ) - "func not valid to be used as export") - -;; Unexported instances don't work -(assert_invalid - (component - (type $t' (record (field "f" u32))) - (instance $i - (export "t" (type $t')) - ) - (alias export $i "t" (type $t)) - - (core module $m (func $f (export "f") (param i32))) - (core instance $i (instantiate $m)) - (func $f (param "f" $t) (canon lift (core func $i "f"))) - (export "f" (func $f)) - ) - "func not valid to be used as export") - -;; Even through a component it doesn't work -(assert_invalid - (component - (component $C - (type $t (record (field "f" u32))) - (export "t" (type $t)) - ) - (instance $i (instantiate $C)) - (alias export $i "t" (type $t)) - - (core module $m (func $f (export "f") (param i32))) - (core instance $i (instantiate $m)) - (func $f (param "f" $t) (canon lift (core func $i "f"))) - (export "f" (func $f)) - ) - "func not valid to be used as export") - -;; through exported instances is ok though -(component - (type $t' (record (field "f" u32))) - (instance $i' - (export "t" (type $t')) - ) - (export $i "i" (instance $i')) - (alias export $i "t" (type $t)) - - (core module $m (func $f (export "f") (param i32))) - (core instance $i (instantiate $m)) - (func $f (param "f" $t) (canon lift (core func $i "f"))) - (export "f" (func $f)) -) -(component - (component $C - (type $t (record (field "f" u32))) - (export "t" (type $t)) - ) - (instance $i' (instantiate $C)) - (export $i "i" (instance $i')) - (alias export $i "t" (type $t)) - - (core module $m (func $f (export "f") (param i32))) - (core instance $i (instantiate $m)) - (func $f (param "f" $t) (canon lift (core func $i "f"))) - (export "f" (func $f)) -) - -;; a type-ascribed export which is otherwise invalid can become valid -(component - (type $t (record (field "f" u32))) - - (core module $m (func (export "f") (param i32))) - (core instance $i (instantiate $m)) - (func $f (param "x" $t) (canon lift (core func $i "f"))) - - (export $t' "t" (type $t)) - (export "f" (func $f) (func (param "x" $t'))) -) - -;; imports can't reference exports -(assert_invalid - (component - (type $t1 (record (field "f" u32))) - (export $t2 "t1" (type $t1)) - (import "i" (func (result $t2))) - ) - "func not valid to be used as import") - -;; exports can reference imports -(component - (type $t1 (record (field "f" u32))) - (import "t1" (type $t2 (eq $t1))) - (export "e-t1" (type $t2)) -) -(component - (component - (type $t1 (record (field "f" u32))) - (import "t1" (type $t2 (eq $t1))) - (import "i" (func $f (result $t2))) - - (export "e-i" (func $f)) - ) -) - -;; outer aliases don't work for imports/exports -(assert_invalid - (component - (type $t1 (record (field "f" u32))) - (import "t1" (type $t2 (eq $t1))) - (component - (import "i" (func $f (result $t2))) - ) - ) - "func not valid to be used as import") -(assert_invalid - (component - (type $t1 (record (field "f" u32))) - (export $t2 "t1" (type $t1)) - (component - (core module $m (func (export "f") (result i32) unreachable)) - (core instance $i (instantiate $m)) - (func $f (export "i") (result $t2) (canon lift (core func $i "f"))) - ) - ) - "func not valid to be used as export") - -;; outer aliases work for components, modules, and resources -(component - (type $c (component)) - (type (component - (import "c" (component (type $c))) - )) - (component - (import "c" (component (type $c))) - ) - (type $i (instance)) - (type (component - (import "c" (instance (type $i))) - )) - - (type $r (resource (rep i32))) - (type (component - (import "r" (type (eq $r))) - )) -) - -;; reexport of an import is fine -(component - (component - (import "r" (func $r)) - (export "r2" (func $r)) - ) -) -(component - (type $t (record (field "f" u32))) - (import "r" (type $r (eq $t))) - (export "r2" (type $r)) -) -(component - (import "r" (instance $r)) - (export "r2" (instance $r)) -) -(component definition - (import "r" (type $r (sub resource))) - (export "r2" (type $r)) -) - -;; bag of exports cannot be exported by carrying through context that's not -;; otherwise exported -(assert_invalid - (component - (component $A - (type $t (record (field "f" u32))) - (export $t2 "t" (type $t)) - (core module $m (func (export "f") (result i32) unreachable)) - (core instance $i (instantiate $m)) - (func $f (result $t2) (canon lift (core func $i "f"))) - - (instance (export "i") - (export "f" (func $f)) - ) - ) - - (instance $a (instantiate $A)) - ;; this component only exports `f`, not the record type that is the result - ;; of `f`, so it should be invalid. - (export "a" (instance $a "i")) - ) - "instance not valid to be used as export") - -;; instance types can be "temporarily invalid", but not if they're attached -;; to a concrete component -(component - (type (instance - (type $t (record (field "f" u32))) - (export "f" (func (param "x" $t))) - )) -) -(assert_invalid - (component - (type $i (instance - (type $t (record (field "f" u32))) - (type $f (record (field "t" $t))) - (export "f" (type (eq $f))) - )) - (import "f" (instance (type $i))) - ) - "instance not valid to be used as import") - -;; allow for one import to refer to another -(component definition $C - (import "foo" (instance $i - (type $baz' (record (field "f" u32))) - (export "baz" (type $baz (eq $baz'))) - (type $bar' (record (field "baz" $baz))) - (export "bar" (type $bar (eq $bar'))) - )) - (alias export $i "bar" (type $bar)) - (import "bar" (instance - (alias outer $C $bar (type $bar')) - (export "bar" (type $bar (eq $bar'))) - (export "a" (func $f (result $bar))) - )) -) - -;; allow for one import to refer to another -(component - (type $r' (record (field "f" u32))) - (import "r" (type $r (eq $r'))) - (component $C - (type $r' (record (field "f" u32))) - (import "r" (type $r (eq $r'))) - (type $r2' (record (field "r" $r))) - (export "r2" (type $r2')) - ) - (instance $c (instantiate $C (with "r" (type $r)))) - (export "r2" (type $c "r2")) -) - -;; types are validated when they are exported -(assert_invalid - (component - (type $i (instance - (type $t (record (field "f" u32))) - (type $f (record (field "t" $t))) - (export "f" (type (eq $f))) - )) - (import "f" (type (eq $i))) - ) - "type not valid to be used as import") -(assert_invalid - (component - (type $i (instance - (type $t (record (field "f" u32))) - (type $f (record (field "t" $t))) - (export "f" (type (eq $f))) - )) - (export "f" (type $i)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (func (result $t))) - (import "f" (type (eq $f))) - ) - "type not valid to be used as import") -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (func (result $t))) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(component - (type (;0;) - (instance - (type (;0;) (enum "qux")) - (export (;1;) "baz" (type (eq 0))) - (type (;2;) (record (field "bar" 1) )) - (export (;3;) "foo" (type (eq 2))) - ) - ) - (import (interface "demo:component/types") (instance (;0;) (type 0))) - (component - (type (;0;) - (instance - (type (;0;) (enum "qux")) - (export (;1;) "baz" (type (eq 0))) - (type (;2;) (record (field "bar" 1) )) - (export (;3;) "foo" (type (eq 2))) - ) - ) - (import (interface "demo:component/types") (instance (;0;) (type 0))) - (component (;0;) - (type (;0;) (enum "qux")) - (import "import-type-baz" (type (;1;) (eq 0))) - (type (;2;) (record (field "bar" 1) )) - (import "import-type-bar" (type (;3;) (eq 2))) - (export (;4;) "foo" (type 3)) - ) - (instance (;1;) (instantiate 0 - (with "import-type-baz" (type 0 "baz")) - (with "import-type-bar" (type 0 "foo")) - ) - ) - (export (;0;) (interface "demo:component/types") (instance 1)) - ) - (instance (instantiate 0 (with "demo:component/types" (instance 0)))) - (export (interface "demo:component/types") (instance 1 "demo:component/types")) -) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/types.wast b/parser/src/test/resources/spec-tests/wasm-tools/types.wast deleted file mode 100644 index 5df1ec9..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/types.wast +++ /dev/null @@ -1,374 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_invalid - (component - (type $t (instance)) - (import "a" (func (type $t))) - ) - "type index 0 is not a function type") - -(assert_invalid - (component - (core type $t (func)) - (import "a" (core module (type $t))) - ) - "core type index 0 is not a module type") - -(assert_invalid - (component - (type $t (func)) - (import "a" (instance (type $t))) - ) - "type index 0 is not an instance type") - -(assert_invalid - (component - (type $t (func)) - (type (component - (import "a" (instance (type $t))) - )) - ) - "type index 0 is not an instance type") - -(assert_invalid - (component - (core type $t (func)) - (type (component - (import "a" (core module (type $t))) - )) - ) - "core type index 0 is not a module type") - -(assert_invalid - (component - (type $t (instance)) - (type (component - (import "a" (func (type $t))) - )) - ) - "type index 0 is not a function type") - -(assert_invalid - (component - (export "a" (core module 0)) - ) - "module index out of bounds") - -(assert_invalid - (component - (export "a" (instance 0)) - ) - "instance index out of bounds") - -(assert_invalid - (component - (core type (module - (export "a" (func (type 0))) - )) - ) - "type index out of bounds") - -(assert_invalid - (component - (core type (module - (export "a" (func)) - (export "a" (func)) - )) - ) - "export name `a` already defined") - -(assert_invalid - (component - (core type (module - (import "" "" (func)) - (import "" "" (func)) - )) - ) - "duplicate import name") - -(assert_invalid - (component - (core type (module - (import "" "" (memory 70000)) - )) - ) - "memory size must be at most") - -(assert_invalid - (component - (type (component - (export "a" (func (type 0))) - )) - ) - "type index out of bounds") - -(assert_invalid - (component - (type (component - (export "a" (func)) - (export "A" (func)) - )) - ) - "export name `A` conflicts with previous name `a`") - -(assert_invalid - (component - (type (component - (import "A" (func)) - (import "a" (func)) - )) - ) - "import name `a` conflicts with previous name `A`") - -(assert_malformed - (component quote - "(component $c (core type $t (module (alias outer $c $t (type)))))" - ) - "unknown core type") - -(assert_invalid - (component - (core type (module - (alias outer 1 0 (type)) - )) - ) - "type index out of bounds") - -(component $c - (core type $f (func)) - (core type $t (module - (alias outer $c $f (type)) - )) -) - -(assert_malformed - (component quote - "(component $c (type $t (component (alias outer $c $t (type)))))" - ) - "unknown type") - -(assert_invalid - (component - (type (component - (alias outer 1 0 (type)) - )) - ) - "type index out of bounds") - -(assert_invalid - (component $c - (type $f (func)) - (type $t (component - (alias outer 100 0 (type)) - )) - ) - "invalid outer alias count of 100") - -(assert_invalid - (component $c - (type $f (func)) - (type $t (component - (core type (module - (export "" (func)) - (export "" (func)) - )) - )) - ) - "name `` already defined") - -(assert_invalid - (component - (type (instance - (export "" (func (type 0))) - )) - ) - "type index out of bounds") - -(assert_invalid - (component - (type (instance - (export "foo-BAR-baz" (func)) - (export "FOO-bar-BAZ" (func)) - )) - ) - "export name `FOO-bar-BAZ` conflicts with previous name `foo-BAR-baz`") - -(assert_malformed - (component quote - "(component $c (type $t (instance (alias outer $c $t (type)))))" - ) - "unknown type") - -(assert_invalid - (component - (type (instance - (alias outer 1 0 (type)) - )) - ) - "type index out of bounds") - -(assert_invalid - (component $c - (type $f (func)) - (type $t (instance - (alias outer 100 0 (type)) - )) - ) - "invalid outer alias count of 100") - -(assert_invalid - (component $c - (type $f (func)) - (type $t (instance - (core type (module - (export "" (func)) - (export "" (func)) - )) - )) - ) - "name `` already defined") - -(assert_invalid - (component $c - (type $f (func (param "" string))) - ) - "function parameter name cannot be empty") - -(component - (type $t (func (result (tuple (list u8) u32)))) -) - -(component $C - (core type $t (func)) - (core type (module - (alias outer $C $t (type $a)) - (import "" "" (func (type $a))) - )) -) - -(component $C - (component $C2 - (core type $t (func)) - (core type (module - (alias outer $C2 $t (type $a)) - (import "" "" (func (type $a))) - )) - ) -) - -(component $C - (core type $t (func)) - (component $C2 - (core type (module - (alias outer $C $t (type $a)) - (import "" "" (func (type $a))) - )) - ) -) - -(component - (type (instance - (type string) - (export "a" (type (eq 0))) - )) -) - -(component - (type (component - (type string) - (import "a" (type (eq 0))) - (export "b" (type (eq 0))) - )) -) - -(assert_invalid - (component - (type (variant)) - ) - "variant type must have at least one case") - -(assert_invalid - (component - (type (enum)) - ) - "enum type must have at least one variant") - -(assert_invalid - (component - (type (record)) - ) - "record type must have at least one field") - -(assert_invalid - (component - (type (flags)) - ) - "flags must have at least one entry") - -(assert_invalid - (component - (type (tuple)) - ) - "tuple type must have at least one type") - -(component $c - (core type $f (func)) - (component $c2 - (core type $t (module - (alias outer $c $f (type)) - )) - ) -) - -(assert_invalid - (component - (type (flags - "f1" - "f2" - "f3" - "f4" - "f5" - "f6" - "f7" - "f8" - "f9" - "f10" - "f11" - "f12" - "f13" - "f14" - "f15" - "f16" - "f17" - "f18" - "f19" - "f20" - "f21" - "f22" - "f23" - "f24" - "f25" - "f26" - "f27" - "f28" - "f29" - "f30" - "f31" - "f32" - "f33" - )) - ) - "cannot have more than 32 flags") - -(assert_invalid - (component - (core type $t (module)) - (core type (func (param (ref $t)))) - ) - "type index 0 is a module type") - -(assert_invalid - (component - (core type (func (param (ref 100)))) - ) - "type index out of bounds") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/very-nested.wast b/parser/src/test/resources/spec-tests/wasm-tools/very-nested.wast deleted file mode 100644 index 42c5aed..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/very-nested.wast +++ /dev/null @@ -1,1954 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_invalid - (component $$esl - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "00AGG554M******+*****e 4$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "anonmm-x23foinas-ASDOJASD") - ) - (component - (export "c t.****0*********") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "agds-ASF-TT-yy") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "0+AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00A$qq") - ) - (component - (export "c t.*************") - (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "15AG:GG!le*$$qq") - ) - (component - (export "c t.*") - (component - (export "c 3@EGGGG$qq**") - (export "bsdew2-sdbsdb") - ) - (component - (export "c t.********)*eleo &m Nx2GGGGle*$$qq") - ) - (component - (export "c 1.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "0*************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "00AGG554M******+*****e 4$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "anonmm-x23foinas-ASDOJASD") - ) - (component - (export "c t.****0*********") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "agds-ASF-TT-yy") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "0+AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00A$qq") - ) - (component - (export "c t.*************") - (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "15AG:GG!le*$$qq") - ) - (component - (export "c .t*") - (component - (export "c 3@EGGGG$qq**") - (export "bsdew2-sdbsdb") - ) - (component - (export "c t.********)*eleo &m Nx2GGGGle*$$qq") - ) - (component - (export "c 1.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle '$$qq") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c *****") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "00AGG554M******+*****e 4$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "anonmm-x23foinas-ASDOJASD") - ) - (component - (export "c t.****0*********") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "agds-ASF-TT-yy") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "0+AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00A$qq") - ) - (component - (export "c t.*************") - (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "15AG:GG!le*$$qq") - ) - (component - (export "c t.*") - (component - (export "c 3@EGGGG$qq**") - (export "bsdew2-sdbsdb") - ) - (component - (export "c t.********)*eleo &m Nx2GGGGle*$$qq") - ) - (component - (export "c 1.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "0*************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "00AGG554M******+*****e 4$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "anonmm-x23foinas-ASDOJASD") - ) - (component - (export "c t.****0*********") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "agds-ASF-TT-yy") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "0+AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00A$qq") - ) - (component - (export "c t.*************") - (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "15AG:GG!le*$$qq") - ) - (component - (export "c .t*") - (component - (export "c 3@EGGGG$qq**") - (export "bsdew2-sdbsdb") - ) - (component - (export "c t.********)*eleo &m Nx2GGGGle*$$qq") - ) - (component - (export "c 1.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle '$$qq") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 1.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E***0AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle '$$qq") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 1.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E**************777777777777777777777777777777777777777777777777777777777777771.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E***0AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle '$$qq") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 1.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - ) - "conflicts with previous name") - -(assert_invalid - (component - (type $m0 (component)) - (type $m1 (component - (import "i1" (component (type $m0))) - (import "i2" (component (type $m0))) - (import "i3" (component (type $m0))) - (import "i4" (component (type $m0))) - (import "i5" (component (type $m0))) - (import "i6" (component (type $m0))) - (import "i7" (component (type $m0))) - (import "i8" (component (type $m0))) - (import "i9" (component (type $m0))) - (import "i10" (component (type $m0))) - )) - (type $m2 (component - (import "i1" (component (type $m1))) - (import "i2" (component (type $m1))) - (import "i3" (component (type $m1))) - (import "i4" (component (type $m1))) - (import "i5" (component (type $m1))) - (import "i6" (component (type $m1))) - (import "i7" (component (type $m1))) - (import "i8" (component (type $m1))) - (import "i9" (component (type $m1))) - (import "i10" (component (type $m1))) - )) - (type $m3 (component - (import "i1" (component (type $m2))) - (import "i2" (component (type $m2))) - (import "i3" (component (type $m2))) - (import "i4" (component (type $m2))) - (import "i5" (component (type $m2))) - (import "i6" (component (type $m2))) - (import "i7" (component (type $m2))) - (import "i8" (component (type $m2))) - (import "i9" (component (type $m2))) - (import "i10" (component (type $m2))) - )) - (type $m4 (component - (import "i1" (component (type $m3))) - (import "i2" (component (type $m3))) - (import "i3" (component (type $m3))) - (import "i4" (component (type $m3))) - (import "i5" (component (type $m3))) - (import "i6" (component (type $m3))) - (import "i7" (component (type $m3))) - (import "i8" (component (type $m3))) - (import "i9" (component (type $m3))) - (import "i10" (component (type $m3))) - )) - (type $m5 (component - (import "i1" (component (type $m4))) - (import "i2" (component (type $m4))) - (import "i3" (component (type $m4))) - (import "i4" (component (type $m4))) - (import "i5" (component (type $m4))) - (import "i6" (component (type $m4))) - (import "i7" (component (type $m4))) - (import "i8" (component (type $m4))) - (import "i9" (component (type $m4))) - (import "i10" (component (type $m4))) - )) - (type $m6 (component - (import "i1" (component (type $m5))) - (import "i2" (component (type $m5))) - (import "i3" (component (type $m5))) - (import "i4" (component (type $m5))) - (import "i5" (component (type $m5))) - (import "i6" (component (type $m5))) - (import "i7" (component (type $m5))) - (import "i8" (component (type $m5))) - (import "i9" (component (type $m5))) - (import "i10" (component (type $m5))) - )) - (type $m7 (component - (import "i1" (component (type $m6))) - (import "i2" (component (type $m6))) - (import "i3" (component (type $m6))) - (import "i4" (component (type $m6))) - (import "i5" (component (type $m6))) - (import "i6" (component (type $m6))) - (import "i7" (component (type $m6))) - (import "i8" (component (type $m6))) - (import "i9" (component (type $m6))) - (import "i10" (component (type $m6))) - )) - (type $m8 (component - (import "i1" (component (type $m7))) - (import "i2" (component (type $m7))) - (import "i3" (component (type $m7))) - (import "i4" (component (type $m7))) - (import "i5" (component (type $m7))) - (import "i6" (component (type $m7))) - (import "i7" (component (type $m7))) - (import "i8" (component (type $m7))) - (import "i9" (component (type $m7))) - (import "i10" (component (type $m7))) - )) - (type $m9 (component - (import "i1" (component (type $m8))) - (import "i2" (component (type $m8))) - (import "i3" (component (type $m8))) - (import "i4" (component (type $m8))) - (import "i5" (component (type $m8))) - (import "i6" (component (type $m8))) - (import "i7" (component (type $m8))) - (import "i8" (component (type $m8))) - (import "i9" (component (type $m8))) - (import "i10" (component (type $m8))) - )) - - (type $m (component - (import "a" (component (type $m9))) - )) - (import "a" (component $a (type $m9))) - (import "b" (component $b (type $m))) - (instance (instantiate $b (with "a" (component $a)))) - ) - "effective type size exceeds the limit") - -(assert_invalid - (component - (component $m0) - (component $m1 - (instance (export "e0") (instantiate $m0)) - (instance (export "e1") (instantiate $m0)) - (instance (export "e2") (instantiate $m0)) - (instance (export "e3") (instantiate $m0)) - (instance (export "e4") (instantiate $m0)) - (instance (export "e5") (instantiate $m0)) - (instance (export "e6") (instantiate $m0)) - (instance (export "e7") (instantiate $m0)) - (instance (export "e8") (instantiate $m0)) - (instance (export "e9") (instantiate $m0)) - ) - (component $m2 - (instance (export "e0") (instantiate $m1)) - (instance (export "e1") (instantiate $m1)) - (instance (export "e2") (instantiate $m1)) - (instance (export "e3") (instantiate $m1)) - (instance (export "e4") (instantiate $m1)) - (instance (export "e5") (instantiate $m1)) - (instance (export "e6") (instantiate $m1)) - (instance (export "e7") (instantiate $m1)) - (instance (export "e8") (instantiate $m1)) - (instance (export "e9") (instantiate $m1)) - ) - (component $m3 - (instance (export "e0") (instantiate $m2)) - (instance (export "e1") (instantiate $m2)) - (instance (export "e2") (instantiate $m2)) - (instance (export "e3") (instantiate $m2)) - (instance (export "e4") (instantiate $m2)) - (instance (export "e5") (instantiate $m2)) - (instance (export "e6") (instantiate $m2)) - (instance (export "e7") (instantiate $m2)) - (instance (export "e8") (instantiate $m2)) - (instance (export "e9") (instantiate $m2)) - ) - (component $m4 - (instance (export "e0") (instantiate $m3)) - (instance (export "e1") (instantiate $m3)) - (instance (export "e2") (instantiate $m3)) - (instance (export "e3") (instantiate $m3)) - (instance (export "e4") (instantiate $m3)) - (instance (export "e5") (instantiate $m3)) - (instance (export "e6") (instantiate $m3)) - (instance (export "e7") (instantiate $m3)) - (instance (export "e8") (instantiate $m3)) - (instance (export "e9") (instantiate $m3)) - ) - (component $m5 - (instance (export "e0") (instantiate $m4)) - (instance (export "e1") (instantiate $m4)) - (instance (export "e2") (instantiate $m4)) - (instance (export "e3") (instantiate $m4)) - (instance (export "e4") (instantiate $m4)) - (instance (export "e5") (instantiate $m4)) - (instance (export "e6") (instantiate $m4)) - (instance (export "e7") (instantiate $m4)) - (instance (export "e8") (instantiate $m4)) - (instance (export "e9") (instantiate $m4)) - ) - (component $m6 - (instance (export "e0") (instantiate $m5)) - (instance (export "e1") (instantiate $m5)) - (instance (export "e2") (instantiate $m5)) - (instance (export "e3") (instantiate $m5)) - (instance (export "e4") (instantiate $m5)) - (instance (export "e5") (instantiate $m5)) - (instance (export "e6") (instantiate $m5)) - (instance (export "e7") (instantiate $m5)) - (instance (export "e8") (instantiate $m5)) - (instance (export "e9") (instantiate $m5)) - ) - (component $m7 - (instance (export "e0") (instantiate $m6)) - (instance (export "e1") (instantiate $m6)) - (instance (export "e2") (instantiate $m6)) - (instance (export "e3") (instantiate $m6)) - (instance (export "e4") (instantiate $m6)) - (instance (export "e5") (instantiate $m6)) - (instance (export "e6") (instantiate $m6)) - (instance (export "e7") (instantiate $m6)) - (instance (export "e8") (instantiate $m6)) - (instance (export "e9") (instantiate $m6)) - ) - ) - "effective type size exceeds the limit") - -(assert_invalid - (component - ;; size(t0) == 1 - (type $t0 (flags "x")) - - ;; size(t1) == 10 - (type $t1 (record - (field "f0" $t0) - (field "f1" $t0) - (field "f2" $t0) - (field "f3" $t0) - (field "f4" $t0) - (field "f5" $t0) - (field "f6" $t0) - (field "f7" $t0) - (field "f8" $t0) - (field "f9" $t0) - )) - - ;; size(t2) == 100 - (type $t2 (record - (field "f0" $t1) - (field "f1" $t1) - (field "f2" $t1) - (field "f3" $t1) - (field "f4" $t1) - (field "f5" $t1) - (field "f6" $t1) - (field "f7" $t1) - (field "f8" $t1) - (field "f9" $t1) - )) - - ;; size(t3) == 1000 - (type $t3 (record - (field "f0" $t2) - (field "f1" $t2) - (field "f2" $t2) - (field "f3" $t2) - (field "f4" $t2) - (field "f5" $t2) - (field "f6" $t2) - (field "f7" $t2) - (field "f8" $t2) - (field "f9" $t2) - )) - - ;; size(t4) == 10000 - (type $t4 (record - (field "f0" $t3) - (field "f1" $t3) - (field "f2" $t3) - (field "f3" $t3) - (field "f4" $t3) - (field "f5" $t3) - (field "f6" $t3) - (field "f7" $t3) - (field "f8" $t3) - (field "f9" $t3) - )) - - ;; size(t5) == 100000 - (type $t5 (record - (field "f0" $t4) - (field "f1" $t4) - (field "f2" $t4) - (field "f3" $t4) - (field "f4" $t4) - (field "f5" $t4) - (field "f6" $t4) - (field "f7" $t4) - (field "f8" $t4) - (field "f9" $t4) - )) - - (type $f (func - (param "a" $t5) - (param "b" $t5) - (param "c" $t5) - (param "d" $t5) - (param "e" $t5) - (param "f" $t5) - (param "g" $t5) - (param "h" $t5) - (param "i" $t5) - (param "j" $t5) - )) - ) - "effective type size exceeds the limit") - -(assert_malformed - (component quote - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - ) - "nesting too deep") diff --git a/parser/src/test/resources/spec-tests/wasm-tools/virtualize.wast b/parser/src/test/resources/spec-tests/wasm-tools/virtualize.wast deleted file mode 100644 index d60b73b..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/virtualize.wast +++ /dev/null @@ -1,119 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component - (core module $libc - (memory (export "mem") 0) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - unreachable - ) - ) - (core instance $libc (instantiate $libc)) - - (component $child - (import "wasi-file" (instance $wasi-file - (export "read" (func (param "count" u32) (result (list u8)))) - (export "write" (func (param "bytes" (list u8)) (result u32))) - )) - - (core instance $libc (instantiate $libc)) - - (core module $m - (import "wasi-file" "read" (func $read (param i32 i32))) - (func $play (export "play") - unreachable - ) - ) - - (core func $wasi_file_read - (canon lower (func $wasi-file "read") - (memory $libc "mem") - (realloc (func $libc "realloc")) - ) - ) - - (core instance $i (instantiate $m - (with "wasi-file" (instance - (export "read" (func $wasi_file_read)) - )) - )) - - (func (export "play") - (canon lift (core func $i "play")) - ) - ) - - (component $virtualize - (import "wasi-file" (instance $wasi-file - (export "read" (func (param "len" u32) (result (list u8)))) - (export "write" (func (param "buf" (list u8)) (result u32))) - )) - (export "read" (func $wasi-file "read")) - (export "write" (func $wasi-file "write")) - ) - - (component - (type $WasiFile (instance - (export "read" (func (param "len" u32) (result (list u8)))) - (export "write" (func (param "buf" (list u8)) (result u32))) - )) - (import "wasi-file" (instance $real-wasi (type $WasiFile))) - (import "virtualize" (component $VIRTUALIZE - (import "wasi-file" (instance (type $WasiFile))) - (export "read" (func (param "len" u32) (result (list u8)))) - (export "write" (func (param "buf" (list u8)) (result u32))) - )) - (import "child" (component $CHILD - (import "wasi-file" (instance (type $WasiFile))) - (export "play" (func)) - ) - ) - - (instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi-file" (instance $real-wasi)))) - (instance $child (instantiate $CHILD (with "wasi-file" (instance $virt-wasi)))) - - (export "work" (func $child "play")) - ) - - (component - (type $WasiFile (instance - (export "read" (func (param "len" u32) (result (list u8)))) - (export "write" (func (param "buf" (list u8)) (result u32))) - )) - (import "wasi-file" (instance $real-wasi (type $WasiFile))) - - (core instance $libc (instantiate $libc)) - - (core module $CHILD - (import "wasi-file" "read" (func $wasi-file (param i32 i32))) - (func $play (export "play") - unreachable - ) - ) - - (core module $VIRTUALIZE - (import "wasi-file" "read" (func (param i32 i32))) - (func (export "read") (param i32 i32) - unreachable - ) - (func (export "write") (param i32 i32 i32) - unreachable - ) - ) - - (core func $real-wasi-read - (canon lower (func $real-wasi "read") - (memory $libc "mem") - (realloc (func $libc "realloc")) - ) - ) - - (core instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi-file" (instance (export "read" (func $real-wasi-read)))))) - (core instance $child (instantiate $CHILD (with "wasi-file" (instance $virt-wasi)))) - (func (export "work") - (canon lift (core func $child "play") - (memory $libc "mem") - (realloc (func $libc "realloc")) - ) - ) - ) -) diff --git a/parser/src/test/resources/spec-tests/wasm-tools/wrong-order.wast b/parser/src/test/resources/spec-tests/wasm-tools/wrong-order.wast deleted file mode 100644 index 098fc41..0000000 --- a/parser/src/test/resources/spec-tests/wasm-tools/wrong-order.wast +++ /dev/null @@ -1,11 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_malformed - (module binary - "\00asm\01\00\00\00" - - "\01\01\00" ;; type section, 1 byte, 0 entries - "\0b\01\00" ;; data section, 1 byte, 0 entries - "\01\01\00" ;; type section, 1 byte, 0 entries - ) - "section out of order") diff --git a/parser/src/test/resources/spec-tests/wasmtime/adapter.wast b/parser/src/test/resources/spec-tests/wasmtime/adapter.wast deleted file mode 100644 index 8432d58..0000000 --- a/parser/src/test/resources/spec-tests/wasmtime/adapter.wast +++ /dev/null @@ -1,137 +0,0 @@ -;;! multi_memory = true - -;; basic function lifting -(component - (core module $m - (func (export "")) - ) - (core instance $i (instantiate $m)) - - (func (export "thunk") - (canon lift (core func $i "")) - ) -) - -;; use an aliased type -(component $c - (core module $m - (func (export "")) - ) - (core instance $i (instantiate $m)) - - (type $to_alias (func)) - (alias outer $c $to_alias (type $alias)) - - (func (export "thunk") (type $alias) - (canon lift (core func $i "")) - ) -) - -;; test out some various canonical abi -(component $c - (core module $m - (func (export "") (param i32 i32)) - (memory (export "memory") 1) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - unreachable) - ) - (core instance $i (instantiate $m)) - - (func (export "thunk") (param "a" string) - (canon lift - (core func $i "") - (memory $i "memory") - (realloc (func $i "realloc")) - ) - ) - - (func (export "thunk8") (param "a" string) - (canon lift - (core func $i "") - string-encoding=utf8 - (memory $i "memory") - (realloc (func $i "realloc")) - ) - ) - - (func (export "thunk16") (param "a" string) - (canon lift - (core func $i "") - string-encoding=utf16 - (memory $i "memory") - (realloc (func $i "realloc")) - ) - ) - - (func (export "thunklatin16") (param "a" string) - (canon lift - (core func $i "") - string-encoding=latin1+utf16 - (memory $i "memory") - (realloc (func $i "realloc")) - ) - ) -) - -;; lower something then immediately lift it -(component $c - (import "host-return-two" (func $f (result u32))) - - (core func $f_lower - (canon lower (func $f)) - ) - (func $f2 (result s32) - (canon lift (core func $f_lower)) - ) - (export "f" (func $f2)) -) - -;; valid, but odd -(component - (core module $m (func (export ""))) - (core instance $m (instantiate $m)) - - (func $f1 (canon lift (core func $m ""))) - (core func $f2 (canon lower (func $f1))) -) -(assert_trap - (component - (core module $m (func (export ""))) - (core instance $m (instantiate $m)) - - (func $f1 (canon lift (core func $m ""))) - (core func $f2 (canon lower (func $f1))) - - (core module $m2 - (import "" "" (func $f)) - (func $start - call $f) - (start $start) - ) - (core instance (instantiate $m2 - (with "" (instance (export "" (func $f2)))) - )) - ) - "cannot enter component instance") - -;; fiddling with 0-sized lists -(component $c - (core module $m - (func (export "x") (param i32 i32)) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - i32.const -1) - (memory (export "memory") 0) - ) - (core instance $m (instantiate $m)) - (type $t' (result)) - (export $t "t" (type $t')) - (func $f (param "a" (list $t)) - (canon lift - (core func $m "x") - (realloc (func $m "realloc")) - (memory $m "memory") - ) - ) - (export "empty-list" (func $f)) -) -(assert_trap (invoke "empty-list" (list.const)) "realloc return: beyond end of memory") diff --git a/parser/src/test/resources/spec-tests/wasmtime/aliasing.wast b/parser/src/test/resources/spec-tests/wasmtime/aliasing.wast deleted file mode 100644 index ad18f93..0000000 --- a/parser/src/test/resources/spec-tests/wasmtime/aliasing.wast +++ /dev/null @@ -1,29 +0,0 @@ -(component - (component - (component - (component) - (instance (instantiate 0)) - (export "a" (instance 0)) - ) - (instance (instantiate 0)) - (export "a" (instance 0)) - ) - - (instance (instantiate 0)) ;; instance 0 - (alias export 0 "a" (instance)) ;; instance 1 - (export "a" (instance 1)) ;; instance 2 - (alias export 2 "a" (instance)) ;; instance 3 - (export "inner-a" (instance 3)) ;; instance 4 -) - -(component - (component - (core module) - (export "a" (core module 0)) - ) - - (instance (instantiate 0)) - (alias export 0 "a" (core module)) ;; module 0 - (export "a" (core module 0)) ;; module 1 - (core instance (instantiate 1)) -) diff --git a/parser/src/test/resources/spec-tests/wasmtime/fused.wast b/parser/src/test/resources/spec-tests/wasmtime/fused.wast deleted file mode 100644 index 87fe846..0000000 --- a/parser/src/test/resources/spec-tests/wasmtime/fused.wast +++ /dev/null @@ -1,1391 +0,0 @@ -;;! multi_memory = true - -;; smoke test with no arguments and no results -(component - (component $a - (core module $m - (func (export "")) - ) - (core instance $m (instantiate $m)) - (func (export "foo") (canon lift (core func $m ""))) - ) - (instance $a (instantiate $a)) - - (component $c - (import "a" (instance $a - (export "foo" (func)) - )) - - (core func $foo (canon lower (func $a "foo"))) - (core module $m2 - (import "" "" (func)) - (start 0) - ) - (core instance $m2 (instantiate $m2 (with "" (instance (export "" (func $foo)))))) - ) - - (instance $c (instantiate $c (with "a" (instance $a)))) -) - -;; boolean parameters -(component - (component $a - (core module $m - (func (export "assert_true") (param i32) - local.get 0 - i32.const 1 - i32.eq - i32.eqz - if unreachable end - ) - (func (export "assert_false") (param i32) - local.get 0 - if unreachable end - ) - (func (export "ret-bool") (param i32) (result i32) - local.get 0 - ) - ) - (core instance $m (instantiate $m)) - (func (export "assert-true") (param "a" bool) (canon lift (core func $m "assert_true"))) - (func (export "assert-false") (param "a" bool) (canon lift (core func $m "assert_false"))) - (func (export "ret-bool") (param "a" u32) (result bool) (canon lift (core func $m "ret-bool"))) - ) - (instance $a (instantiate $a)) - - (component $c - (import "a" (instance $a - (export "assert-true" (func (param "a" bool))) - (export "assert-false" (func (param "a" bool))) - (export "ret-bool" (func (param "a" u32) (result bool))) - )) - - (core func $assert_true (canon lower (func $a "assert-true"))) - (core func $assert_false (canon lower (func $a "assert-false"))) - (core func $ret_bool (canon lower (func $a "ret-bool"))) - - (core module $m2 - (import "" "assert-true" (func $assert_true (param i32))) - (import "" "assert-false" (func $assert_false (param i32))) - (import "" "ret-bool" (func $ret_bool (param i32) (result i32))) - - (func $start - (call $assert_true (i32.const 1)) - (call $assert_true (i32.const 2)) - (call $assert_true (i32.const -1)) - (call $assert_false (i32.const 0)) - - (if (i32.ne (call $ret_bool (i32.const 1)) (i32.const 1)) - (then (unreachable))) - (if (i32.ne (call $ret_bool (i32.const 2)) (i32.const 1)) - (then (unreachable))) - (if (i32.ne (call $ret_bool (i32.const -1)) (i32.const 1)) - (then (unreachable))) - (if (i32.ne (call $ret_bool (i32.const 0)) (i32.const 0)) - (then (unreachable))) - ) - (start $start) - ) - (core instance $m2 (instantiate $m2 - (with "" (instance - (export "assert-true" (func $assert_true)) - (export "assert-false" (func $assert_false)) - (export "ret-bool" (func $ret_bool)) - )) - )) - ) - - (instance $c (instantiate $c (with "a" (instance $a)))) -) - -;; lots of parameters and results -(component - (component $a - (type $roundtrip (func - ;; 20 u32 params - (param "a1" u32) (param "a2" u32) (param "a3" u32) (param "a4" u32) (param "a5" u32) - (param "a6" u32) (param "a7" u32) (param "a8" u32) (param "a9" u32) (param "a10" u32) - (param "a11" u32) (param "a12" u32) (param "a13" u32) (param "a14" u32) (param "a15" u32) - (param "a16" u32) (param "a17" u32) (param "a18" u32) (param "a19" u32) (param "a20" u32) - - ;; 10 u32 results - (result (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) - )) - - (core module $m - (memory (export "memory") 1) - (func (export "roundtrip") (param $src i32) (result i32) - (local $dst i32) - (if (i32.ne (local.get $src) (i32.const 16)) - (then (unreachable))) - - (if (i32.ne (i32.load offset=0 (local.get $src)) (i32.const 1)) (then (unreachable))) - (if (i32.ne (i32.load offset=4 (local.get $src)) (i32.const 2)) (then (unreachable))) - (if (i32.ne (i32.load offset=8 (local.get $src)) (i32.const 3)) (then (unreachable))) - (if (i32.ne (i32.load offset=12 (local.get $src)) (i32.const 4)) (then (unreachable))) - (if (i32.ne (i32.load offset=16 (local.get $src)) (i32.const 5)) (then (unreachable))) - (if (i32.ne (i32.load offset=20 (local.get $src)) (i32.const 6)) (then (unreachable))) - (if (i32.ne (i32.load offset=24 (local.get $src)) (i32.const 7)) (then (unreachable))) - (if (i32.ne (i32.load offset=28 (local.get $src)) (i32.const 8)) (then (unreachable))) - (if (i32.ne (i32.load offset=32 (local.get $src)) (i32.const 9)) (then (unreachable))) - (if (i32.ne (i32.load offset=36 (local.get $src)) (i32.const 10)) (then (unreachable))) - (if (i32.ne (i32.load offset=40 (local.get $src)) (i32.const 11)) (then (unreachable))) - (if (i32.ne (i32.load offset=44 (local.get $src)) (i32.const 12)) (then (unreachable))) - (if (i32.ne (i32.load offset=48 (local.get $src)) (i32.const 13)) (then (unreachable))) - (if (i32.ne (i32.load offset=52 (local.get $src)) (i32.const 14)) (then (unreachable))) - (if (i32.ne (i32.load offset=56 (local.get $src)) (i32.const 15)) (then (unreachable))) - (if (i32.ne (i32.load offset=60 (local.get $src)) (i32.const 16)) (then (unreachable))) - (if (i32.ne (i32.load offset=64 (local.get $src)) (i32.const 17)) (then (unreachable))) - (if (i32.ne (i32.load offset=68 (local.get $src)) (i32.const 18)) (then (unreachable))) - (if (i32.ne (i32.load offset=72 (local.get $src)) (i32.const 19)) (then (unreachable))) - (if (i32.ne (i32.load offset=76 (local.get $src)) (i32.const 20)) (then (unreachable))) - - (local.set $dst (i32.const 500)) - - (i32.store offset=0 (local.get $dst) (i32.const 21)) - (i32.store offset=4 (local.get $dst) (i32.const 22)) - (i32.store offset=8 (local.get $dst) (i32.const 23)) - (i32.store offset=12 (local.get $dst) (i32.const 24)) - (i32.store offset=16 (local.get $dst) (i32.const 25)) - (i32.store offset=20 (local.get $dst) (i32.const 26)) - (i32.store offset=24 (local.get $dst) (i32.const 27)) - (i32.store offset=28 (local.get $dst) (i32.const 28)) - (i32.store offset=32 (local.get $dst) (i32.const 29)) - (i32.store offset=36 (local.get $dst) (i32.const 30)) - - local.get $dst - ) - - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - i32.const 16) - ) - (core instance $m (instantiate $m)) - - (func (export "roundtrip") (type $roundtrip) - (canon lift (core func $m "roundtrip") (memory $m "memory") - (realloc (func $m "realloc"))) - ) - ) - (instance $a (instantiate $a)) - - (component $c - (type $roundtrip (func - ;; 20 u32 params - (param "a1" u32) (param "a2" u32) (param "a3" u32) (param "a4" u32) (param "a5" u32) - (param "a6" u32) (param "a7" u32) (param "a8" u32) (param "a9" u32) (param "a10" u32) - (param "a11" u32) (param "a12" u32) (param "a13" u32) (param "a14" u32) (param "a15" u32) - (param "a16" u32) (param "a17" u32) (param "a18" u32) (param "a19" u32) (param "a20" u32) - - ;; 10 u32 results - (result (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) - )) - - (import "a" (instance $a - (export "roundtrip" (func (type $roundtrip))) - )) - - (core module $libc - (memory (export "memory") 1) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) - ) - (core instance $libc (instantiate $libc)) - (core func $roundtrip - (canon lower (func $a "roundtrip") - (memory $libc "memory") - (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary - ) - ) - - (core module $m2 - (import "libc" "memory" (memory 1)) - (import "" "roundtrip" (func $roundtrip (param i32 i32))) - - (func $start - (local $addr i32) - (local $retaddr i32) - - (local.set $addr (i32.const 100)) - (call $store_many (i32.const 20) (local.get $addr)) - - (local.set $retaddr (i32.const 200)) - (call $roundtrip (local.get $addr) (local.get $retaddr)) - - (if (i32.ne (i32.load offset=0 (local.get $retaddr)) (i32.const 21)) (then (unreachable))) - (if (i32.ne (i32.load offset=4 (local.get $retaddr)) (i32.const 22)) (then (unreachable))) - (if (i32.ne (i32.load offset=8 (local.get $retaddr)) (i32.const 23)) (then (unreachable))) - (if (i32.ne (i32.load offset=12 (local.get $retaddr)) (i32.const 24)) (then (unreachable))) - (if (i32.ne (i32.load offset=16 (local.get $retaddr)) (i32.const 25)) (then (unreachable))) - (if (i32.ne (i32.load offset=20 (local.get $retaddr)) (i32.const 26)) (then (unreachable))) - (if (i32.ne (i32.load offset=24 (local.get $retaddr)) (i32.const 27)) (then (unreachable))) - (if (i32.ne (i32.load offset=28 (local.get $retaddr)) (i32.const 28)) (then (unreachable))) - (if (i32.ne (i32.load offset=32 (local.get $retaddr)) (i32.const 29)) (then (unreachable))) - (if (i32.ne (i32.load offset=36 (local.get $retaddr)) (i32.const 30)) (then (unreachable))) - ) - - (func $store_many (param $amt i32) (param $addr i32) - (local $c i32) - (loop $loop - (local.set $c (i32.add (local.get $c) (i32.const 1))) - (i32.store (local.get $addr) (local.get $c)) - (local.set $addr (i32.add (local.get $addr) (i32.const 4))) - - (if (i32.ne (local.get $amt) (local.get $c)) (then (br $loop))) - ) - ) - (start $start) - ) - (core instance $m2 (instantiate $m2 - (with "libc" (instance $libc)) - (with "" (instance (export "roundtrip" (func $roundtrip)))) - )) - ) - - (instance $c (instantiate $c (with "a" (instance $a)))) -) - -;; this will require multiple adapter modules to get generated -(component - (component $c0 - (core module $root (func (export "") (result i32) - i32.const 0 - )) - (core instance $root (instantiate $root)) - (func (export "thunk") (result u32) (canon lift (core func $root ""))) - ) - (instance $c0 (instantiate $c0)) - - (component $c - (import "thunk" (instance $thunk - (export "thunk" (func (result u32))) - )) - (core func $import (canon lower (func $thunk "thunk"))) - (core module $reexport - (import "" "" (func $thunk (result i32))) - (func (export "thunk") (result i32) - call $thunk - i32.const 1 - i32.add) - ) - (core instance $reexport (instantiate $reexport - (with "" (instance - (export "" (func $import)) - )) - )) - (func $export (export "thunk") (result u32) - (canon lift (core func $reexport "thunk")) - ) - ) - - (instance $c1 (instantiate $c (with "thunk" (instance $c0)))) - (instance $c2 (instantiate $c (with "thunk" (instance $c1)))) - (instance $c3 (instantiate $c (with "thunk" (instance $c2)))) - (instance $c4 (instantiate $c (with "thunk" (instance $c3)))) - (instance $c5 (instantiate $c (with "thunk" (instance $c4)))) - (instance $c6 (instantiate $c (with "thunk" (instance $c5)))) - - (component $verify - (import "thunk" (instance $thunk - (export "thunk" (func (result u32))) - )) - (core func $thunk (canon lower (func $thunk "thunk"))) - (core module $verify - (import "" "" (func $thunk (result i32))) - - (func $start - call $thunk - i32.const 6 - i32.ne - if unreachable end - ) - (start $start) - ) - (core instance (instantiate $verify - (with "" (instance - (export "" (func $thunk)) - )) - )) - ) - (instance (instantiate $verify (with "thunk" (instance $c6)))) -) - -;; Fancy case of an adapter using an adapter. Note that this is silly and -;; doesn't actually make any sense at runtime, we just shouldn't panic on a -;; valid component. -(component - (type $tuple20 (tuple - u32 u32 u32 u32 u32 - u32 u32 u32 u32 u32 - u32 u32 u32 u32 u32 - u32 u32 u32 u32 u32)) - - (component $realloc - (core module $realloc - (memory (export "memory") 1) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - unreachable) - ) - (core instance $realloc (instantiate $realloc)) - (func $realloc (param "a" (tuple u32 u32 u32 u32)) (result u32) - (canon lift (core func $realloc "realloc")) - ) - (export "realloc" (func $realloc)) - ) - (instance $realloc (instantiate $realloc)) - (core func $realloc (canon lower (func $realloc "realloc"))) - - (core module $m - (memory (export "memory") 1) - (func (export "foo") (param i32)) - ) - (core instance $m (instantiate $m)) - (func $foo (param "a" $tuple20) - (canon lift - (core func $m "foo") - (memory $m "memory") - (realloc (func $realloc)) - ) - ) - - (component $c - (import "foo" (func $foo (param "a" $tuple20))) - - (core module $libc - (memory (export "memory") 1) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - unreachable) - ) - (core instance $libc (instantiate $libc)) - (core func $foo - (canon lower (func $foo) - (memory $libc "memory") - (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary - ) - ) - (core module $something - (import "" "foo" (func (param i32))) - ) - (core instance (instantiate $something - (with "" (instance - (export "foo" (func $foo)) - )) - )) - ) - (instance (instantiate $c - (with "foo" (func $foo)) - )) -) - -;; Don't panic or otherwise create extraneous adapter modules when the same -;; adapter is used twice for a module's argument. -(component - (core module $m - (func (export "foo") (param)) - ) - (core instance $m (instantiate $m)) - (func $foo (canon lift (core func $m "foo"))) - - (component $c - (import "foo" (func $foo)) - (core func $foo (canon lower (func $foo))) - - (core module $something - (import "" "a" (func)) - (import "" "b" (func)) - ) - (core instance (instantiate $something - (with "" (instance - (export "a" (func $foo)) - (export "b" (func $foo)) - )) - )) - ) - (instance (instantiate $c (with "foo" (func $foo)))) -) - -;; post-return should get invoked by the generated adapter, if specified -(component - (component $a - (core module $m - (global $post_called (mut i32) (i32.const 0)) - (func (export "foo") - ;; assert `foo-post` not called yet - global.get $post_called - i32.const 1 - i32.eq - if unreachable end - ) - (func (export "foo-post") - ;; assert `foo-post` not called before - global.get $post_called - i32.const 1 - i32.eq - if unreachable end - ;; ... then flag as called - i32.const 1 - global.set $post_called - ) - (func (export "assert-post") - global.get $post_called - i32.const 1 - i32.ne - if unreachable end - ) - ) - (core instance $m (instantiate $m)) - (func (export "foo") (canon lift (core func $m "foo") (post-return (func $m "foo-post")))) - (func (export "assert-post") (canon lift (core func $m "assert-post"))) - ) - (instance $a (instantiate $a)) - - (component $c - (import "a" (instance $a - (export "foo" (func)) - (export "assert-post" (func)) - )) - (core func $foo (canon lower (func $a "foo"))) - (core func $assert_post (canon lower (func $a "assert-post"))) - - (core module $something - (import "" "foo" (func $foo)) - (import "" "assert-post" (func $assert_post)) - - (func $start - call $foo - call $assert_post - ) - (start $start) - ) - (core instance (instantiate $something - (with "" (instance - (export "foo" (func $foo)) - (export "assert-post" (func $assert_post)) - )) - )) - ) - (instance (instantiate $c (with "a" (instance $a)))) -) - -;; post-return passes the results -(component - (component $a - (core module $m - (func (export "foo") (result i32) i32.const 100) - (func (export "foo-post") (param i32) - (if (i32.ne (local.get 0) (i32.const 100)) (then (unreachable)))) - ) - (core instance $m (instantiate $m)) - (func (export "foo") (result u32) - (canon lift (core func $m "foo") (post-return (func $m "foo-post")))) - ) - (instance $a (instantiate $a)) - - (component $c - (import "a" (instance $a - (export "foo" (func (result u32))) - )) - (core func $foo (canon lower (func $a "foo"))) - - (core module $something - (import "" "foo" (func $foo (result i32))) - (func $start - (if (i32.ne (call $foo) (i32.const 100)) (then (unreachable)))) - (start $start) - ) - (core instance (instantiate $something - (with "" (instance - (export "foo" (func $foo)) - )) - )) - ) - (instance (instantiate $c (with "a" (instance $a)))) -) - -;; callee retptr misaligned -(assert_trap - (component - (component $c1 - (core module $m - (memory (export "memory") 1) - (func (export "r") (result i32) i32.const 1) - ) - (core instance $m (instantiate $m)) - (func (export "r") (result (tuple u32 u32)) - (canon lift (core func $m "r") (memory $m "memory")) - ) - ) - (component $c2 - (import "r" (func $r (result (tuple u32 u32)))) - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core func $r (canon lower (func $r) (memory $libc "memory"))) - - (core module $m - (import "" "r" (func $r (param i32))) - (func $start - i32.const 4 - call $r - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance (export "r" (func $r)))) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) - ) - "unaligned pointer") - -;; caller retptr misaligned -(assert_trap - (component - (component $c1 - (core module $m - (memory (export "memory") 1) - (func (export "r") (result i32) i32.const 0) - ) - (core instance $m (instantiate $m)) - (func (export "r") (result (tuple u32 u32)) - (canon lift (core func $m "r") (memory $m "memory")) - ) - ) - (component $c2 - (import "r" (func $r (result (tuple u32 u32)))) - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core func $r (canon lower (func $r) (memory $libc "memory"))) - - (core module $m - (import "" "r" (func $r (param i32))) - (func $start - i32.const 1 - call $r - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance (export "r" (func $r)))) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) - ) - "unaligned pointer") - -;; callee argptr misaligned -(assert_trap - (component - (type $big (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) - - (component $c1 - (core module $m - (memory (export "memory") 1) - (func (export "r") (param i32)) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - i32.const 1) - ) - (core instance $m (instantiate $m)) - (func (export "r") (param "a" $big) - (canon lift (core func $m "r") (memory $m "memory") (realloc (func $m "realloc"))) - ) - ) - (component $c2 - (import "r" (func $r (param "a" $big))) - (core module $libc - (memory (export "memory") 1) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) - ) - (core instance $libc (instantiate $libc)) - (core func $r - (canon lower (func $r) - (memory $libc "memory") - (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary - ) - ) - - (core module $m - (import "" "r" (func $r (param i32))) - (func $start - i32.const 4 - call $r - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance (export "r" (func $r)))) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) - ) - "unaligned pointer") - -;; caller argptr misaligned -(assert_trap - (component - (type $big (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) - - (component $c1 - (core module $m - (memory (export "memory") 1) - (func (export "r") (param i32)) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - i32.const 4) - ) - (core instance $m (instantiate $m)) - (func (export "r") (param "a" $big) - (canon lift (core func $m "r") (memory $m "memory") (realloc (func $m "realloc"))) - ) - ) - (component $c2 - (import "r" (func $r (param "a" $big))) - (core module $libc - (memory (export "memory") 1) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) - ) - (core instance $libc (instantiate $libc)) - (core func $r - (canon lower (func $r) - (memory $libc "memory") - (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary - ) - ) - - - (core module $m - (import "" "r" (func $r (param i32))) - (func $start - i32.const 1 - call $r - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance (export "r" (func $r)))) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) - ) - "unaligned pointer") - -;; simple variant translation -(component - (component $c1 - (type $a' (variant (case "x"))) - (export $a "a" (type $a')) - (type $b' (variant (case "y"))) - (export $b "b" (type $b')) - - (core module $m - (func (export "r") (param i32) (result i32) - (if (i32.ne (local.get 0) (i32.const 0)) (then (unreachable))) - i32.const 0 - ) - ) - (core instance $m (instantiate $m)) - (func (export "r") (param "a" $a) (result $b) (canon lift (core func $m "r"))) - ) - (component $c2 - (type $a' (variant (case "x"))) - (import "a" (type $a (eq $a'))) - (type $b' (variant (case "y"))) - (import "b" (type $b (eq $b'))) - - (import "r" (func $r (param "a" $a) (result $b))) - (core func $r (canon lower (func $r))) - - (core module $m - (import "" "r" (func $r (param i32) (result i32))) - (func $start - i32.const 0 - call $r - i32.const 0 - i32.ne - if unreachable end - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance (export "r" (func $r)))) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 - (with "a" (type $c1 "a")) - (with "b" (type $c1 "b")) - (with "r" (func $c1 "r")) - )) -) - -;; invalid variant discriminant in a parameter -(assert_trap - (component - (component $c1 - (type $a' (variant (case "x"))) - (export $a "a" (type $a')) - (core module $m - (func (export "r") (param i32)) - ) - (core instance $m (instantiate $m)) - (func (export "r") (param "a" $a) (canon lift (core func $m "r"))) - ) - (component $c2 - (type $a' (variant (case "x"))) - (import "a" (type $a (eq $a'))) - (import "r" (func $r (param "a" $a))) - (core func $r (canon lower (func $r))) - - (core module $m - (import "" "r" (func $r (param i32))) - (func $start - i32.const 1 - call $r - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance (export "r" (func $r)))) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 - (with "a" (type $c1 "a")) - (with "r" (func $c1 "r")) - )) - ) - "invalid variant discriminant") - -;; invalid variant discriminant in a result -(assert_trap - (component - (component $c1 - (type $a' (variant (case "x"))) - (export $a "a" (type $a')) - (core module $m - (func (export "r") (result i32) i32.const 1) - ) - (core instance $m (instantiate $m)) - (func (export "r") (result $a) (canon lift (core func $m "r"))) - ) - (component $c2 - (type $a' (variant (case "x"))) - (import "a" (type $a (eq $a'))) - (import "r" (func $r (result $a))) - (core func $r (canon lower (func $r))) - - (core module $m - (import "" "r" (func $r (result i32))) - (func $start call $r drop) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance (export "r" (func $r)))) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 - (with "a" (type $c1 "a")) - (with "r" (func $c1 "r")) - )) - ) - "invalid variant discriminant") - - -;; extra bits are chopped off -(component - (component $c1 - (core module $m - (func (export "u") (param i32) - (if (i32.ne (local.get 0) (i32.const 0)) (then (unreachable))) - ) - (func (export "s") (param i32) - (if (i32.ne (local.get 0) (i32.const -1)) (then (unreachable))) - ) - ) - (core instance $m (instantiate $m)) - (func (export "u8") (param "a" u8) (canon lift (core func $m "u"))) - (func (export "u16") (param "a" u16) (canon lift (core func $m "u"))) - (func (export "s8") (param "a" s8) (canon lift (core func $m "s"))) - (func (export "s16") (param "a" s16) (canon lift (core func $m "s"))) - ) - (component $c2 - (import "a" (instance $i - (export "u8" (func (param "a" u8))) - (export "s8" (func (param "a" s8))) - (export "u16" (func (param "a" u16))) - (export "s16" (func (param "a" s16))) - )) - - (core func $u8 (canon lower (func $i "u8"))) - (core func $s8 (canon lower (func $i "s8"))) - (core func $u16 (canon lower (func $i "u16"))) - (core func $s16 (canon lower (func $i "s16"))) - - (core module $m - (import "" "u8" (func $u8 (param i32))) - (import "" "s8" (func $s8 (param i32))) - (import "" "u16" (func $u16 (param i32))) - (import "" "s16" (func $s16 (param i32))) - - (func $start - (call $u8 (i32.const 0)) - (call $u8 (i32.const 0xff00)) - (call $s8 (i32.const -1)) - (call $s8 (i32.const 0xff)) - (call $s8 (i32.const 0xffff)) - - (call $u16 (i32.const 0)) - (call $u16 (i32.const 0xff0000)) - (call $s16 (i32.const -1)) - (call $s16 (i32.const 0xffff)) - (call $s16 (i32.const 0xffffff)) - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "u8" (func $u8)) - (export "s8" (func $s8)) - (export "u16" (func $u16)) - (export "s16" (func $s16)) - )) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) -) - -;; translation of locals between different types -(component - (component $c1 - (type $a' (variant (case "a" u8) (case "b" float32))) - (type $b' (variant (case "a" u16) (case "b" s64))) - (type $c' (variant (case "a" u64) (case "b" float64))) - (type $d' (variant (case "a" float32) (case "b" float64))) - (type $e' (variant (case "a" float32) (case "b" s64))) - (export $a "t-a" (type $a')) - (export $b "t-b" (type $b')) - (export $c "t-c" (type $c')) - (export $d "t-d" (type $d')) - (export $e "t-e" (type $e')) - - (type $func_a (func (param "x" bool) (param "a" $a))) - (type $func_b (func (param "x" bool) (param "b" $b))) - (type $func_c (func (param "x" bool) (param "c" $c))) - (type $func_d (func (param "x" bool) (param "d" $d))) - (type $func_e (func (param "x" bool) (param "e" $d))) - - (core module $m - (func (export "a") (param i32 i32 i32) - (i32.eqz (local.get 0)) - if - (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) - (if (i32.ne (local.get 2) (i32.const 2)) (then (unreachable))) - else - (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) - (if (f32.ne (f32.reinterpret_i32 (local.get 2)) (f32.const 3)) (then (unreachable))) - end - ) - (func (export "b") (param i32 i32 i64) - (i32.eqz (local.get 0)) - if - (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) - (if (i64.ne (local.get 2) (i64.const 4)) (then (unreachable))) - else - (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) - (if (i64.ne (local.get 2) (i64.const 5)) (then (unreachable))) - end - ) - (func (export "c") (param i32 i32 i64) - (i32.eqz (local.get 0)) - if - (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) - (if (i64.ne (local.get 2) (i64.const 6)) (then (unreachable))) - else - (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) - (if (f64.ne (f64.reinterpret_i64 (local.get 2)) (f64.const 7)) (then (unreachable))) - end - ) - (func (export "d") (param i32 i32 i64) - (i32.eqz (local.get 0)) - if - (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) - (if (f32.ne (f32.reinterpret_i32 (i32.wrap_i64 (local.get 2))) (f32.const 8)) (then (unreachable))) - else - (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) - (if (f64.ne (f64.reinterpret_i64 (local.get 2)) (f64.const 9)) (then (unreachable))) - end - ) - (func (export "e") (param i32 i32 i64) - (i32.eqz (local.get 0)) - if - (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) - (if (f32.ne (f32.reinterpret_i32 (i32.wrap_i64 (local.get 2))) (f32.const 10)) (then (unreachable))) - else - (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) - (if (i64.ne (local.get 2) (i64.const 11)) (then (unreachable))) - end - ) - ) - (core instance $m (instantiate $m)) - (func (export "a") (type $func_a) (canon lift (core func $m "a"))) - (func (export "b") (type $func_b) (canon lift (core func $m "b"))) - (func (export "c") (type $func_c) (canon lift (core func $m "c"))) - (func (export "d") (type $func_d) (canon lift (core func $m "d"))) - (func (export "e") (type $func_e) (canon lift (core func $m "e"))) - ) - (component $c2 - (import "a" (instance $i - (type $a' (variant (case "a" u8) (case "b" float32))) - (type $b' (variant (case "a" u16) (case "b" s64))) - (type $c' (variant (case "a" u64) (case "b" float64))) - (type $d' (variant (case "a" float32) (case "b" float64))) - (type $e' (variant (case "a" float32) (case "b" s64))) - (export "t-a" (type $a (eq $a'))) - (export "t-b" (type $b (eq $b'))) - (export "t-c" (type $c (eq $c'))) - (export "t-d" (type $d (eq $d'))) - (export "t-e" (type $e (eq $e'))) - (type $func_a (func (param "x" bool) (param "a" $a))) - (type $func_b (func (param "x" bool) (param "b" $b))) - (type $func_c (func (param "x" bool) (param "c" $c))) - (type $func_d (func (param "x" bool) (param "d" $d))) - (type $func_e (func (param "x" bool) (param "e" $d))) - - (export "a" (func (type $func_a))) - (export "b" (func (type $func_b))) - (export "c" (func (type $func_c))) - (export "d" (func (type $func_d))) - (export "e" (func (type $func_e))) - )) - - (core func $a (canon lower (func $i "a"))) - (core func $b (canon lower (func $i "b"))) - (core func $c (canon lower (func $i "c"))) - (core func $d (canon lower (func $i "d"))) - (core func $e (canon lower (func $i "e"))) - - (core module $m - (import "" "a" (func $a (param i32 i32 i32))) - (import "" "b" (func $b (param i32 i32 i64))) - (import "" "c" (func $c (param i32 i32 i64))) - (import "" "d" (func $d (param i32 i32 i64))) - (import "" "e" (func $e (param i32 i32 i64))) - - (func $start - ;; upper bits should get masked - (call $a (i32.const 0) (i32.const 0) (i32.const 0xff_02)) - (call $a (i32.const 1) (i32.const 1) (i32.reinterpret_f32 (f32.const 3))) - - ;; upper bits should get masked - (call $b (i32.const 0) (i32.const 0) (i64.const 0xff_00_04)) - (call $b (i32.const 1) (i32.const 1) (i64.const 5)) - - (call $c (i32.const 0) (i32.const 0) (i64.const 6)) - (call $c (i32.const 1) (i32.const 1) (i64.reinterpret_f64 (f64.const 7))) - - (call $d (i32.const 0) (i32.const 0) (i64.extend_i32_u (i32.reinterpret_f32 (f32.const 8)))) - (call $d (i32.const 1) (i32.const 1) (i64.reinterpret_f64 (f64.const 9))) - - (call $e (i32.const 0) (i32.const 0) (i64.extend_i32_u (i32.reinterpret_f32 (f32.const 10)))) - (call $e (i32.const 1) (i32.const 1) (i64.const 11)) - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "a" (func $a)) - (export "b" (func $b)) - (export "c" (func $c)) - (export "d" (func $d)) - (export "e" (func $e)) - )) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) -) - -;; different size variants -(component - (component $c1 - (type $a' (variant - (case "a") - (case "b" float32) - (case "c" (tuple float32 u32)) - (case "d" (tuple float32 u64 u8)) - )) - (export $a "t-a" (type $a')) - - (core module $m - (func (export "a") (param i32 i32 f32 i64 i32) - (if (i32.eq (local.get 0) (i32.const 0)) - (then (block - (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) - (if (f32.ne (local.get 2) (f32.const 0)) (then (unreachable))) - (if (i64.ne (local.get 3) (i64.const 0)) (then (unreachable))) - (if (i32.ne (local.get 4) (i32.const 0)) (then (unreachable))) - )) - ) - (if (i32.eq (local.get 0) (i32.const 1)) - (then (block - (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) - (if (f32.ne (local.get 2) (f32.const 1)) (then (unreachable))) - (if (i64.ne (local.get 3) (i64.const 0)) (then (unreachable))) - (if (i32.ne (local.get 4) (i32.const 0)) (then (unreachable))) - )) - ) - (if (i32.eq (local.get 0) (i32.const 2)) - (then (block - (if (i32.ne (local.get 1) (i32.const 2)) (then (unreachable))) - (if (f32.ne (local.get 2) (f32.const 2)) (then (unreachable))) - (if (i64.ne (local.get 3) (i64.const 2)) (then (unreachable))) - (if (i32.ne (local.get 4) (i32.const 0)) (then (unreachable))) - )) - ) - (if (i32.eq (local.get 0) (i32.const 3)) - (then (block - (if (i32.ne (local.get 1) (i32.const 3)) (then (unreachable))) - (if (f32.ne (local.get 2) (f32.const 3)) (then (unreachable))) - (if (i64.ne (local.get 3) (i64.const 3)) (then (unreachable))) - (if (i32.ne (local.get 4) (i32.const 3)) (then (unreachable))) - )) - ) - (if (i32.gt_u (local.get 0) (i32.const 3)) - (then (unreachable))) - ) - ) - (core instance $m (instantiate $m)) - (func (export "a") (param "x" u8) (param "a" $a) (canon lift (core func $m "a"))) - ) - (component $c2 - (import "a" (instance $i - (type $a' (variant - (case "a") - (case "b" float32) - (case "c" (tuple float32 u32)) - (case "d" (tuple float32 u64 u8)) - )) - (export "t-a" (type $a (eq $a'))) - (export "a" (func (param "x" u8) (param "a" $a))) - )) - - (core func $a (canon lower (func $i "a"))) - - (core module $m - (import "" "a" (func $a (param i32 i32 f32 i64 i32))) - - (func $start - ;; variant a - (call $a - (i32.const 0) - (i32.const 0) - (f32.const 0) - (i64.const 0) - (i32.const 0)) - ;; variant b - (call $a - (i32.const 1) - (i32.const 1) - (f32.const 1) - (i64.const 0) - (i32.const 0)) - ;; variant c - (call $a - (i32.const 2) - (i32.const 2) - (f32.const 2) - (i64.const 2) - (i32.const 0)) - ;; variant d - (call $a - (i32.const 3) - (i32.const 3) - (f32.const 3) - (i64.const 3) - (i32.const 3)) - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "a" (func $a)) - )) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) -) - -;; roundtrip some valid chars -(component - (component $c1 - (core module $m - (func (export "a") (param i32) (result i32) local.get 0) - ) - (core instance $m (instantiate $m)) - (func (export "a") (param "a" char) (result char) (canon lift (core func $m "a"))) - ) - (component $c2 - (import "a" (instance $i - (export "a" (func (param "a" char) (result char))) - )) - - (core func $a (canon lower (func $i "a"))) - - (core module $m - (import "" "a" (func $a (param i32) (result i32))) - - (func $start - (call $roundtrip (i32.const 0)) - (call $roundtrip (i32.const 0xab)) - (call $roundtrip (i32.const 0xd7ff)) - (call $roundtrip (i32.const 0xe000)) - (call $roundtrip (i32.const 0x10ffff)) - ) - (func $roundtrip (export "roundtrip") (param i32) - local.get 0 - call $a - local.get 0 - i32.ne - if unreachable end - ) - (start $start) - ) - (core instance $m (instantiate $m - (with "" (instance - (export "a" (func $a)) - )) - )) - - (func (export "roundtrip") (param "a" char) (canon lift (core func $m "roundtrip"))) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) - - (export "roundtrip" (func $c2 "roundtrip")) -) - -(assert_return (invoke "roundtrip" (char.const "x"))) -(assert_return (invoke "roundtrip" (char.const "⛳"))) -(assert_return (invoke "roundtrip" (char.const "🍰"))) - -;; invalid chars -(assert_trap - (component - (component $c1 - (core module $m (func (export "a") (param i32))) - (core instance $m (instantiate $m)) - (func (export "a") (param "a" char) (canon lift (core func $m "a"))) - ) - (component $c2 - (import "a" (instance $i (export "a" (func (param "a" char))))) - (core func $a (canon lower (func $i "a"))) - (core module $m - (import "" "a" (func $a (param i32))) - (func $start (call $a (i32.const 0xd800))) - (start $start) - ) - (core instance (instantiate $m (with "" (instance (export "a" (func $a)))))) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) - ) - "invalid `char` bit pattern") -(assert_trap - (component - (component $c1 - (core module $m (func (export "a") (param i32))) - (core instance $m (instantiate $m)) - (func (export "a") (param "a" char) (canon lift (core func $m "a"))) - ) - (component $c2 - (import "a" (instance $i (export "a" (func (param "a" char))))) - (core func $a (canon lower (func $i "a"))) - (core module $m - (import "" "a" (func $a (param i32))) - (func $start (call $a (i32.const 0xdfff))) - (start $start) - ) - (core instance (instantiate $m (with "" (instance (export "a" (func $a)))))) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) - ) - "invalid `char` bit pattern") -(assert_trap - (component - (component $c1 - (core module $m (func (export "a") (param i32))) - (core instance $m (instantiate $m)) - (func (export "a") (param "a" char) (canon lift (core func $m "a"))) - ) - (component $c2 - (import "a" (instance $i (export "a" (func (param "a" char))))) - (core func $a (canon lower (func $i "a"))) - (core module $m - (import "" "a" (func $a (param i32))) - (func $start (call $a (i32.const 0x110000))) - (start $start) - ) - (core instance (instantiate $m (with "" (instance (export "a" (func $a)))))) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) - ) - "invalid `char` bit pattern") - -;; test that flags get their upper bits all masked off -(component - (type $f1' (flags "f1")) - (type $f8' (flags "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8")) - (type $f9' (flags "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" "f9")) - (type $f16' (flags - "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" - "g1" "g2" "g3" "g4" "g5" "g6" "g7" "g8" - )) - (type $f17' (flags - "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" - "g1" "g2" "g3" "g4" "g5" "g6" "g7" "g8" - "g9" - )) - (type $f32' (flags - "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" - "g1" "g2" "g3" "g4" "g5" "g6" "g7" "g8" - "h1" "h2" "h3" "h4" "h5" "h6" "h7" "h8" - "i1" "i2" "i3" "i4" "i5" "i6" "i7" "i8" - )) - - (component $c1 - (export $f1 "t-f1" (type $f1')) - (export $f8 "t-f8" (type $f8')) - (export $f9 "t-f9" (type $f9')) - (export $f16 "t-f16" (type $f16')) - (export $f17 "t-f17" (type $f17')) - (export $f32 "t-f32" (type $f32')) - (core module $m - (func (export "f1") (param i32) - (if (i32.ne (local.get 0) (i32.const 0x1)) (then (unreachable))) - ) - (func (export "f8") (param i32) - (if (i32.ne (local.get 0) (i32.const 0x11)) (then (unreachable))) - ) - (func (export "f9") (param i32) - (if (i32.ne (local.get 0) (i32.const 0x111)) (then (unreachable))) - ) - (func (export "f16") (param i32) - (if (i32.ne (local.get 0) (i32.const 0x1111)) (then (unreachable))) - ) - (func (export "f17") (param i32) - (if (i32.ne (local.get 0) (i32.const 0x11111)) (then (unreachable))) - ) - (func (export "f32") (param i32) - (if (i32.ne (local.get 0) (i32.const 0x11111111)) (then (unreachable))) - ) - ) - (core instance $m (instantiate $m)) - (func (export "f1") (param "a" $f1) (canon lift (core func $m "f1"))) - (func (export "f8") (param "a" $f8) (canon lift (core func $m "f8"))) - (func (export "f9") (param "a" $f9) (canon lift (core func $m "f9"))) - (func (export "f16") (param "a" $f16) (canon lift (core func $m "f16"))) - (func (export "f17") (param "a" $f17) (canon lift (core func $m "f17"))) - (func (export "f32") (param "a" $f32) (canon lift (core func $m "f32"))) - ) - (instance $c1 (instantiate $c1)) - - (component $c2 - (import "a" (instance $i - (export "t-f1" (type $f1 (eq $f1'))) - (export "t-f8" (type $f8 (eq $f8'))) - (export "t-f9" (type $f9 (eq $f9'))) - (export "t-f16" (type $f16 (eq $f16'))) - (export "t-f17" (type $f17 (eq $f17'))) - (export "t-f32" (type $f32 (eq $f32'))) - (export "f1" (func (param "a" $f1))) - (export "f8" (func (param "a" $f8))) - (export "f9" (func (param "a" $f9))) - (export "f16" (func (param "a" $f16))) - (export "f17" (func (param "a" $f17))) - (export "f32" (func (param "a" $f32))) - )) - (core func $f1 (canon lower (func $i "f1"))) - (core func $f8 (canon lower (func $i "f8"))) - (core func $f9 (canon lower (func $i "f9"))) - (core func $f16 (canon lower (func $i "f16"))) - (core func $f17 (canon lower (func $i "f17"))) - (core func $f32 (canon lower (func $i "f32"))) - - (core module $m - (import "" "f1" (func $f1 (param i32))) - (import "" "f8" (func $f8 (param i32))) - (import "" "f9" (func $f9 (param i32))) - (import "" "f16" (func $f16 (param i32))) - (import "" "f17" (func $f17 (param i32))) - (import "" "f32" (func $f32 (param i32))) - - (func $start - (call $f1 (i32.const 0xffffff01)) - (call $f8 (i32.const 0xffffff11)) - (call $f9 (i32.const 0xffffff11)) - (call $f16 (i32.const 0xffff1111)) - (call $f17 (i32.const 0xffff1111)) - (call $f32 (i32.const 0x11111111)) - ) - - (start $start) - ) - (core instance $m (instantiate $m - (with "" (instance - (export "f1" (func $f1)) - (export "f8" (func $f8)) - (export "f9" (func $f9)) - (export "f16" (func $f16)) - (export "f17" (func $f17)) - (export "f32" (func $f32)) - )) - )) - ) - (instance (instantiate $c2 (with "a" (instance $c1)))) -) - -;; Adapters are used slightly out-of-order here to stress the internals of -;; dependencies between adapters. -(component - (core module $m - (func (export "execute")) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) - (memory (export "memory") 1) - ) - - (component $root - (core instance $m (instantiate $m)) - (func (export "execute") - (canon lift (core func $m "execute")) - ) - ) - (component $c - (import "backend" (instance $i - (export "execute" (func)) - )) - (core module $shim2 (import "" "0" (func))) - (core instance $m (instantiate $m)) - - ;; This adapter, when fused with itself on the second instantiation of this - ;; component, will depended on the prior instance `$m` so it which means - ;; that the adapter module containing this must be placed in the right - ;; location. - (core func $execute - (canon lower (func $i "execute") (memory $m "memory") (realloc (func $m "realloc"))) - ) - (core instance (instantiate $shim2 - (with "" (instance - (export "0" (func $execute)) - )) - )) - (func (export "execute") (canon lift (core func $m "execute"))) - ) - (instance $root (instantiate $root)) - (instance $c1 (instantiate $c (with "backend" (instance $root)))) - (instance $c2 (instantiate $c (with "backend" (instance $c1)))) -) diff --git a/parser/src/test/resources/spec-tests/wasmtime/import.wast b/parser/src/test/resources/spec-tests/wasmtime/import.wast deleted file mode 100644 index 20688ef..0000000 --- a/parser/src/test/resources/spec-tests/wasmtime/import.wast +++ /dev/null @@ -1,20 +0,0 @@ -(assert_invalid - (component - (import "host-return-two" (func $f (result u32))) - (export "x" (func $f))) - "component export `x` is a reexport of an imported function which is not implemented") - -(assert_unlinkable - (component - (import "host-return-two" (instance)) - ) - "expected instance found func") - -;; empty instances don't need to be supplied by the host, even recursively -;; empty instances. -(component - (import "not-provided-by-the-host" (instance)) - (import "not-provided-by-the-host2" (instance - (export "x" (instance)) - )) -) diff --git a/parser/src/test/resources/spec-tests/wasmtime/instance.wast b/parser/src/test/resources/spec-tests/wasmtime/instance.wast deleted file mode 100644 index 4216cdc..0000000 --- a/parser/src/test/resources/spec-tests/wasmtime/instance.wast +++ /dev/null @@ -1,327 +0,0 @@ -(component - (core module $m) - (core instance (instantiate $m)) -) - -(component - (core module $m - (func (export "")) - ) - (core instance $i (instantiate $m)) - - (core module $m2 - (func (import "" "")) - ) - (core instance (instantiate $m2 (with "" (instance $i)))) -) - -(component - (core module $m - (func (export "a")) - ) - (core instance $i (instantiate $m)) - - (core module $m2 - (func (import "" "b")) - ) - (core instance (instantiate $m2 - (with "" (instance (export "b" (func $i "a")))) - )) -) - -;; all kinds of imports for core wasm modules, and register a start function on -;; one module to ensure that everything is correct -(component - (core module $m - (func (export "a")) - (table (export "b") 1 funcref) - (memory (export "c") 1) - (global (export "d") i32 i32.const 1) - ) - (core instance $i (instantiate $m)) - - (core module $m2 - (import "" "a" (func $f)) - (import "" "b" (table 1 funcref)) - (import "" "c" (memory 1)) - (import "" "d" (global $g i32)) - - (func $start - global.get $g - i32.const 1 - i32.ne - if - unreachable - end - - call $f - ) - - (start $start) - - (data (i32.const 0) "hello") - (elem (i32.const 0) $start) - ) - (core instance (instantiate $m2 - (with "" (instance $i)) - )) -) - -;; Test to see if a component with a type export can be instantiated. -(component - (type string) - (export "a" (type 0)) -) - -;; double-check the start function runs by ensuring that a trap shows up and it -;; sees the wrong value for the global import -(assert_trap - (component - (core module $m - (global (export "g") i32 i32.const 1) - ) - (core instance $i (instantiate $m)) - - (core module $m2 - (import "" "g" (global $g i32)) - - (func $start - global.get $g - i32.const 0 - i32.ne - if - unreachable - end - ) - - (start $start) - ) - (core instance (instantiate $m2 (with "" (instance $i)))) - ) - "unreachable") - -;; shuffle around imports to get to what the target core wasm module needs -(component - (core module $m - (func (export "1")) - (table (export "2") 1 funcref) - (memory (export "3") 1) - (global (export "4") i32 i32.const 1) - ) - (core instance $i (instantiate $m)) - - (core module $m2 - (import "" "a" (func $f)) - (import "" "b" (table 1 funcref)) - (import "" "c" (memory 1)) - (import "" "d" (global $g i32)) - ) - (core instance (instantiate $m2 - (with "" (instance - (export "a" (func $i "1")) - (export "b" (table $i "2")) - (export "c" (memory $i "3")) - (export "d" (global $i "4")) - )) - )) -) - -;; indirect references through a synthetic instance -(component - (core module $m - (func (export "a")) - (table (export "b") 1 funcref) - (memory (export "c") 1) - (global (export "d") i32 i32.const 1) - ) - (core instance $i (instantiate $m)) - (core instance $i2 - (export "a1" (func $i "a")) - (export "a2" (table $i "b")) - (export "a3" (memory $i "c")) - (export "a4" (global $i "d")) - ) - - (core module $m2 - (import "" "1" (func $f)) - (import "" "2" (table 1 funcref)) - (import "" "3" (memory 1)) - (import "" "4" (global $g i32)) - ) - (core instance (instantiate $m2 - (with "" (instance - (export "1" (func $i2 "a1")) - (export "2" (table $i2 "a2")) - (export "3" (memory $i2 "a3")) - (export "4" (global $i2 "a4")) - )) - )) -) - -(component - (import "host" (instance $i (export "return-three" (func (result u32))))) - - (core module $m - (import "host" "return-three" (func $three (result i32))) - (func $start - call $three - i32.const 3 - i32.ne - if unreachable end - ) - (start $start) - ) - (core func $three_lower - (canon lower (func $i "return-three")) - ) - (core instance (instantiate $m - (with "host" (instance (export "return-three" (func $three_lower)))) - )) -) - -(component - (import "host" (instance $i - (type $x' (record (field "x" u32))) - (export "x" (type $x (eq $x'))) - (type $rec' (record (field "x" $x) (field "y" string))) - (export "rec" (type $rec (eq $rec'))) - (export "some-record" (type (eq $rec))))) -) - -(component - (import "host" (instance $i - (export "nested" (instance - (export "return-four" (func (result u32))) - )) - )) - - (core module $m - (import "host" "return-three" (func $three (result i32))) - (func $start - call $three - i32.const 4 - i32.ne - if unreachable end - ) - (start $start) - ) - (core func $three_lower - (canon lower (func $i "nested" "return-four")) - ) - (core instance (instantiate $m - (with "host" (instance (export "return-three" (func $three_lower)))) - )) -) - -(component - (import "host" (instance $i - (export "simple-module" (core module)) - )) - - (core instance (instantiate (module $i "simple-module"))) -) - -(component - (import "host" (instance $i - (export "simple-module" (core module - (export "f" (func (result i32))) - (export "g" (global i32)) - )) - )) - - (core instance $i (instantiate (module $i "simple-module"))) - (core module $verify - (import "host" "f" (func $f (result i32))) - (import "host" "g" (global $g i32)) - - (func $start - call $f - i32.const 101 - i32.ne - if unreachable end - - global.get $g - i32.const 100 - i32.ne - if unreachable end - ) - (start $start) - ) - - (core instance (instantiate $verify (with "host" (instance $i)))) -) - -;; export an instance -(component - (core module $m) - (instance $i (export "m" (core module $m))) - (export "i" (instance $i)) -) -(component - (component $c) - (instance $i (instantiate $c)) - (export "i" (instance $i)) -) -(component - (import "host" (instance $i)) - (export "i" (instance $i)) -) - - -(component definition $C1 - (type $r1 (resource (rep i32))) - (export "r" (type $r1)) -) -(component definition $C2 - (type $r1 (resource (rep i32))) - (export "r" (type $r1)) -) - -(component instance $I1 $C1) -(component instance $I2 $C1) -(component instance $I3 $C2) -(component instance $I4 $C2) - -;; all instances have different resource types -(assert_unlinkable - (component - (import "I1" (instance $i1 (export "r" (type (sub resource))))) - (alias export $i1 "r" (type $r)) - (import "I2" (instance $i2 (export "r" (type (eq $r))))) - ) - "mismatched resource types") -(assert_unlinkable - (component - (import "I1" (instance $i1 (export "r" (type (sub resource))))) - (alias export $i1 "r" (type $r)) - (import "I3" (instance $i2 (export "r" (type (eq $r))))) - ) - "mismatched resource types") -(assert_unlinkable - (component - (import "I1" (instance $i1 (export "r" (type (sub resource))))) - (alias export $i1 "r" (type $r)) - (import "I4" (instance $i2 (export "r" (type (eq $r))))) - ) - "mismatched resource types") -(assert_unlinkable - (component - (import "I2" (instance $i1 (export "r" (type (sub resource))))) - (alias export $i1 "r" (type $r)) - (import "I3" (instance $i2 (export "r" (type (eq $r))))) - ) - "mismatched resource types") -(assert_unlinkable - (component - (import "I2" (instance $i1 (export "r" (type (sub resource))))) - (alias export $i1 "r" (type $r)) - (import "I4" (instance $i2 (export "r" (type (eq $r))))) - ) - "mismatched resource types") -(assert_unlinkable - (component - (import "I3" (instance $i1 (export "r" (type (sub resource))))) - (alias export $i1 "r" (type $r)) - (import "I4" (instance $i2 (export "r" (type (eq $r))))) - ) - "mismatched resource types") diff --git a/parser/src/test/resources/spec-tests/wasmtime/linking.wast b/parser/src/test/resources/spec-tests/wasmtime/linking.wast deleted file mode 100644 index 966926f..0000000 --- a/parser/src/test/resources/spec-tests/wasmtime/linking.wast +++ /dev/null @@ -1,18 +0,0 @@ -(assert_unlinkable - (component - (import "undefined-name" (core module)) - ) - "was not found") -(component $i) -(component - (import "i" (instance)) -) -(assert_unlinkable - (component (import "i" (core module))) - "expected module found instance") -(assert_unlinkable - (component (import "i" (func))) - "expected function found instance") -(assert_unlinkable - (component (import "i" (instance (export "x" (func))))) - "was not found") diff --git a/parser/src/test/resources/spec-tests/wasmtime/modules.wast b/parser/src/test/resources/spec-tests/wasmtime/modules.wast deleted file mode 100644 index 6014f94..0000000 --- a/parser/src/test/resources/spec-tests/wasmtime/modules.wast +++ /dev/null @@ -1,479 +0,0 @@ -;;! reference_types = true - -(component $foo - (core module (export "a-module")) -) - -;; the above instance can be imported into this component -(component - (import "foo" (instance - (export "a-module" (core module)) - )) -) - -;; specifying extra imports is ok -(component - (import "foo" (instance - (export "a-module" (core module - (import "foo" "bar" (func)) - )) - )) -) - -;; specifying extra exports is not ok -(assert_unlinkable - (component - (import "foo" (instance - (export "a-module" (core module - (export "the-export" (func)) - )) - )) - ) - "module export `the-export` not defined") - -(component $foo - (core module (export "a-module") - (import "env" "something" (func)) - ) -) - -;; imports must be specified -(assert_unlinkable - (component - (import "foo" (instance - (export "a-module" (core module)) - )) - ) - "module import `env::something` not defined") - -(component - (import "foo" (instance - (export "a-module" (core module - (import "env" "something" (func)) - )) - )) -) - -;; extra imports still ok -(component - (import "foo" (instance - (export "a-module" (core module - (import "env" "something" (func)) - (import "env" "other" (global i32)) - )) - )) -) - -(component $foo - (core module (export "a-module") - (func (export "f")) - ) -) - -;; dropping exports is ok -(component - (import "foo" (instance - (export "a-module" (core module)) - )) -) - -(component - (import "foo" (instance - (export "a-module" (core module - (export "f" (func)) - )) - )) -) - -(assert_unlinkable - (component - (import "foo" (instance - (export "a-module" (core module - (export "f" (func (param i32))) - )) - )) - ) - "expected type `(func (param i32))`, found type `(func)`") - -(assert_unlinkable - (component - (import "foo" (instance - (export "a-module" (core module - (export "f" (global i32)) - )) - )) - ) - "expected global found func") - -(component $foo - (core module (export "m") - (func (export "f")) - (table (export "t") 1 funcref) - (memory (export "m") 1) - (global (export "g") i32 i32.const 0) - ) -) - -;; wrong class of item -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "f" (global i32)))) - )) - ) - "expected global found func") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "t" (func)))) - )) - ) - "expected func found table") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "m" (func)))) - )) - ) - "expected func found memory") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "g" (func)))) - )) - ) - "expected func found global") - -;; wrong item type -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "f" (func (param i32))))) - )) - ) - "export `f` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "t" (table 1 externref)))) - )) - ) - "export `t` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "t" (table 2 funcref)))) - )) - ) - "export `t` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "m" (memory 2)))) - )) - ) - "export `m` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "g" (global f32)))) - )) - ) - "export `g` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "g" (global (mut i32))))) - )) - ) - "export `g` has the wrong type") - -;; subtyping ok -(component - (import "foo" (instance - (export "m" (core module - (export "t" (table 0 funcref)) - (export "m" (memory 0)) - )) - )) -) - -(component $foo - (core module (export "f") (func (import "" ""))) - (core module (export "t") (table (import "" "") 1 funcref)) - (core module (export "m") (memory (import "" "") 1)) - (core module (export "g") (global (import "" "") i32)) -) - -;; wrong class of item -(assert_unlinkable - (component - (import "foo" (instance - (export "f" (core module (import "" "" (global i32)))) - )) - ) - "expected func found global") -(assert_unlinkable - (component - (import "foo" (instance - (export "t" (core module (import "" "" (func)))) - )) - ) - "expected table found func") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (import "" "" (func)))) - )) - ) - "expected memory found func") -(assert_unlinkable - (component - (import "foo" (instance - (export "g" (core module (import "" "" (func)))) - )) - ) - "expected global found func") - -;; wrong item type -(assert_unlinkable - (component - (import "foo" (instance - (export "f" (core module (import "" "" (func (param i32))))) - )) - ) - "module import `::` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "t" (core module (import "" "" (table 1 externref)))) - )) - ) - "module import `::` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "t" (core module (import "" "" (table 0 funcref)))) - )) - ) - "module import `::` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (import "" "" (memory 0)))) - )) - ) - "module import `::` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "g" (core module (import "" "" (global f32)))) - )) - ) - "module import `::` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "g" (core module (import "" "" (global (mut i32))))) - )) - ) - "module import `::` has the wrong type") - -;; subtyping ok, but in the opposite direction of imports -(component - (import "foo" (instance - (export "t" (core module (import "" "" (table 2 funcref)))) - (export "m" (core module (import "" "" (memory 2)))) - )) -) - -;; An instance can reexport a module, define a module, and everything can be -;; used by something else -(component $src - (core module (export "m") - (global (export "g") i32 i32.const 2) - ) -) - -(component $reexport - (core module $m1 - (global (export "g") i32 i32.const 1) - ) - (import "src" (instance $src - (export "m" (core module (export "g" (global i32)))) - )) - - (core module $m3 - (global (export "g") i32 i32.const 3) - ) - - (export "m1" (core module $m1)) - (export "m2" (core module $src "m")) - (export "m3" (core module $m3)) -) - -(component - (core type $modulety (module (export "g" (global i32)))) - (import "reexport" (instance $reexport - (export "m1" (core module (type $modulety))) - (export "m2" (core module (type $modulety))) - (export "m3" (core module (type $modulety))) - )) - - (core module $assert_ok - (import "m1" "g" (global $m1 i32)) - (import "m2" "g" (global $m2 i32)) - (import "m3" "g" (global $m3 i32)) - - (func $assert_ok - block - global.get $m1 - i32.const 1 - i32.eq - br_if 0 - unreachable - end - block - global.get $m2 - i32.const 2 - i32.eq - br_if 0 - unreachable - end - block - global.get $m3 - i32.const 3 - i32.eq - br_if 0 - unreachable - end - ) - - (start $assert_ok) - ) - - (core instance $m1 (instantiate (module $reexport "m1"))) - (core instance $m2 (instantiate (module $reexport "m2"))) - (core instance $m3 (instantiate (module $reexport "m3"))) - - (core instance (instantiate $assert_ok - (with "m1" (instance $m1)) - (with "m2" (instance $m2)) - (with "m3" (instance $m3)) - )) -) - -;; order of imports and exports can be shuffled between definition site and -;; use-site -(component $provider - (core module (export "m") - (import "" "1" (global $i1 i32)) - (import "" "2" (global $i2 i32)) - (import "" "3" (global $i3 i32)) - (import "" "4" (global $i4 i32)) - - (global $g1 i32 i32.const 100) - (global $g2 i32 i32.const 101) - (global $g3 i32 i32.const 102) - (global $g4 i32 i32.const 103) - - (func $assert_imports - (block - global.get $i1 - i32.const 1 - i32.eq - br_if 0 - unreachable) - (block - global.get $i2 - i32.const 2 - i32.eq - br_if 0 - unreachable) - (block - global.get $i3 - i32.const 3 - i32.eq - br_if 0 - unreachable) - (block - global.get $i4 - i32.const 4 - i32.eq - br_if 0 - unreachable) - ) - - (start $assert_imports) - - (export "g1" (global $g1)) - (export "g2" (global $g2)) - (export "g3" (global $g3)) - (export "g4" (global $g4)) - ) -) - -(component - (import "provider" (instance $provider - (export "m" (core module - (import "" "4" (global i32)) - (import "" "3" (global i32)) - (import "" "2" (global i32)) - (import "" "1" (global i32)) - - (export "g4" (global i32)) - (export "g3" (global i32)) - (export "g2" (global i32)) - (export "g1" (global i32)) - )) - )) - - (core module $imports - (global (export "1") i32 (i32.const 1)) - (global (export "3") i32 (i32.const 3)) - (global (export "2") i32 (i32.const 2)) - (global (export "4") i32 (i32.const 4)) - ) - (core instance $imports (instantiate $imports)) - (core instance $m (instantiate (module $provider "m") - (with "" (instance $imports)) - )) - - (core module $import_globals - (import "" "g4" (global $g4 i32)) - (import "" "g3" (global $g3 i32)) - (import "" "g2" (global $g2 i32)) - (import "" "g1" (global $g1 i32)) - - (func $assert_imports - (block - global.get $g1 - i32.const 100 - i32.eq - br_if 0 - unreachable) - (block - global.get $g2 - i32.const 101 - i32.eq - br_if 0 - unreachable) - (block - global.get $g3 - i32.const 102 - i32.eq - br_if 0 - unreachable) - (block - global.get $g4 - i32.const 103 - i32.eq - br_if 0 - unreachable) - ) - - (start $assert_imports) - ) - - (core instance (instantiate $import_globals (with "" (instance $m)))) -) diff --git a/parser/src/test/resources/spec-tests/wasmtime/nested.wast b/parser/src/test/resources/spec-tests/wasmtime/nested.wast deleted file mode 100644 index 8cb4c38..0000000 --- a/parser/src/test/resources/spec-tests/wasmtime/nested.wast +++ /dev/null @@ -1,451 +0,0 @@ -;; simple nested component -(component - (component) -) - -;; simple nested component with a nested module -(component - (component - (core module) - ) -) - -;; simple instantiation of a nested component -(component - (component $c) - (instance (instantiate $c)) - (instance (instantiate $c - (with "x" (component $c)) - )) -) - -;; instantiate a module during a nested component, and also instantiate it -;; as an export of the nested component -(component - (component $c - (core module $m) - (core instance (instantiate $m)) - (export "m" (core module $m)) - ) - (instance $i (instantiate $c)) - (core instance $i (instantiate (module $i "m"))) -) - -;; instantiate an inner exported module with two different modules and -;; verify imports match -(component - (component $c - (core module $m - (import "" "g" (global $g i32)) - (import "" "f" (func $f (result i32))) - - (func $start - call $f - global.get $g - i32.ne - if unreachable end) - - (start $start) - ) - - (core module $m2 - (global (export "g") i32 i32.const 1) - (func (export "f") (result i32) i32.const 1) - ) - (core instance $i2 (instantiate $m2)) - (core instance (instantiate $m (with "" (instance $i2)))) - - (export "m" (core module $m)) - ) - (instance $i (instantiate $c)) - (core module $m2 - (global (export "g") i32 i32.const 5) - (func (export "f") (result i32) i32.const 5) - ) - (core instance $i2 (instantiate $m2)) - (core instance (instantiate (module $i "m") (with "" (instance $i2)))) -) - -;; instantiate an inner component with a module import -(component - (component $c - (import "m" (core module $m - (export "g" (global i32)) - )) - - (core instance $i (instantiate $m)) - - (core module $verify - (import "" "g" (global $g i32)) - - (func $start - global.get $g - i32.const 2 - i32.ne - if unreachable end - ) - - (start $start) - ) - (core instance (instantiate $verify (with "" (instance $i)))) - ) - - (core module $m - (global (export "g") i32 (i32.const 2)) - ) - (instance (instantiate $c (with "m" (core module $m)))) -) - -;; instantiate an inner component with a module import that itself has imports -(component - (component $c - (import "m" (core module $m - (import "" "g" (global i32)) - )) - (core module $m2 - (global (export "g") i32 i32.const 2100) - ) - (core instance $m2 (instantiate $m2)) - (core instance (instantiate $m (with "" (instance $m2)))) - ) - - (core module $verify - (import "" "g" (global $g i32)) - - (func $start - global.get $g - i32.const 2100 - i32.ne - if unreachable end - ) - - (start $start) - ) - (instance (instantiate $c (with "m" (core module $verify)))) -) - -;; instantiate an inner component with an export from the outer component -(component $c - (core module (export "m") - (import "" "g1" (global $g1 i32)) - (import "" "g2" (global $g2 i32)) - - (func $start - global.get $g1 - i32.const 10000 - i32.ne - if unreachable end - - global.get $g2 - i32.const 20000 - i32.ne - if unreachable end - ) - - (start $start) - ) -) - -(component - (import "c" (instance $i - (export "m" (core module - (import "" "g2" (global i32)) - (import "" "g1" (global i32)) - )) - )) - - (component $c - (import "m" (core module $verify - (import "" "g2" (global i32)) - (import "" "g1" (global i32)) - )) - - (core module $m - (global (export "g1") i32 i32.const 10000) - (global (export "g2") i32 i32.const 20000) - ) - (core instance $m (instantiate $m)) - (core instance (instantiate $verify (with "" (instance $m)))) - ) - - (instance (instantiate $c (with "m" (core module $i "m")))) -) - -;; instantiate a reexported module -(component - (core module $m - (global (export "g") i32 i32.const 7) - ) - (component $c - (import "i" (instance $i - (export "m" (core module - (import "" "" (func)) - (export "g" (global i32)) - )) - )) - - (export "m" (core module $i "m")) - ) - - (instance $c (instantiate $c (with "i" (instance (export "m" (core module $m)))))) - (core module $dummy - (func (export "")) - ) - (core instance $dummy (instantiate $dummy)) - - (core instance $m (instantiate (module $c "m") (with "" (instance $dummy)))) - - (core module $verify - (import "" "g" (global i32)) - (func $start - global.get 0 - i32.const 7 - i32.ne - if unreachable end - ) - - (start $start) - ) - (core instance (instantiate $verify (with "" (instance $m)))) -) - -;; module must be found through a few layers of imports -(component $c - (core module (export "m") - (global (export "g") i32 i32.const 101) - ) -) - -(component - (import "c" (instance $i - (export "m" (core module - (export "g" (global i32)) - )) - )) - (component $c1 - (import "c" (instance $i - (export "m" (core module - (export "g" (global i32)) - )) - )) - (core module $verify - (import "" "g" (global i32)) - (func $start - global.get 0 - i32.const 101 - i32.ne - if unreachable end - ) - - (start $start) - ) - (core instance $m (instantiate (module $i "m"))) - (core instance (instantiate $verify (with "" (instance $m)))) - ) - (instance (instantiate $c1 (with "c" (instance $i)))) -) - -;; instantiate outer alias to self -(component $C - (core module $m) - (alias outer $C $m (core module $other_m)) - (core instance (instantiate $other_m)) -) - -(component $C - (component $m) - (alias outer $C $m (component $other_m)) - (instance (instantiate $other_m)) -) - - -;; closing over an outer alias which is actually an argument to some -;; instantiation -(component - (component $c - (import "c" (core module $c - (export "a" (global i32)) - )) - - (component (export "c2") - (export "m" (core module $c)) - ) - ) - - (core module $m1 (global (export "a") i32 i32.const 1)) - (core module $m2 (global (export "a") i32 i32.const 2)) - - (instance $c1 (instantiate $c (with "c" (core module $m1)))) - (instance $c2 (instantiate $c (with "c" (core module $m2)))) - - (instance $m1_container (instantiate (component $c1 "c2"))) - (instance $m2_container (instantiate (component $c2 "c2"))) - - (core instance $core1 (instantiate (module $m1_container "m"))) - (core instance $core2 (instantiate (module $m2_container "m"))) - - (core module $verify - (import "core1" "a" (global $a i32)) - (import "core2" "a" (global $b i32)) - - (func $start - global.get $a - i32.const 1 - i32.ne - if unreachable end - - global.get $b - i32.const 2 - i32.ne - if unreachable end - ) - - (start $start) - ) - (core instance (instantiate $verify - (with "core1" (instance $core1)) - (with "core2" (instance $core2)) - )) -) - -;; simple importing of a component -(component - (component $C) - (component $other - (import "x" (component $c)) - (instance (instantiate $c)) - ) - (instance (instantiate $other (with "x" (component $C)))) -) - -;; deep nesting -(component $C - (core module $m - (global (export "g") i32 (i32.const 1)) - ) - (component $c - (core module (export "m") - (global (export "g") i32 (i32.const 2)) - ) - ) - - (component $c1 - (component $c2 (export "a") - (component $c3 (export "a") - (alias outer $C $m (core module $my_module)) - (alias outer $C $c (component $my_component)) - - (export "m" (core module $my_module)) - (export "c" (component $my_component)) - ) - ) - ) - - (instance $i1 (instantiate $c1)) - (instance $i2 (instantiate (component $i1 "a"))) - (instance $i3 (instantiate (component $i2 "a"))) - - (core instance $m1 (instantiate (module $i3 "m"))) - (instance $c (instantiate (component $i3 "c"))) - (core instance $m2 (instantiate (module $c "m"))) - - (core module $verify - (import "m1" "g" (global $m1 i32)) - (import "m2" "g" (global $m2 i32)) - - (func $start - global.get $m1 - i32.const 1 - i32.ne - if unreachable end - - global.get $m2 - i32.const 2 - i32.ne - if unreachable end - ) - (start $start) - ) - (core instance (instantiate $verify (with "m1" (instance $m1)) (with "m2" (instance $m2)))) -) - -;; Try threading through component instantiation arguments as various forms of -;; instances. -(component - (component $c - (core module $m (export "m")) - (component $c (export "c") - (core module (export "m")) - ) - (instance $i (instantiate $c)) - (instance $i2 - (export "m" (core module $m)) - (export "c" (component $c)) - (export "i" (instance $i)) - ) - (export "i" (instance $i)) - (export "i2" (instance $i2)) - ) - (instance $i (instantiate $c)) - - (component $another - (import "host" (instance - (export "m" (core module)) - (export "c" (component)) - (export "i" (instance)) - )) - ) - (instance (instantiate $another (with "host" (instance $i)))) - (instance (instantiate $another (with "host" (instance $i "i2")))) - - (instance $reexport - (export "c" (component $i "c")) - (export "m" (core module $i "m")) - (export "i" (instance $i "i")) - ) - (instance (instantiate $another (with "host" (instance $reexport)))) -) - -;; thread host functions around -(component - (import "host-return-two" (func $import (result u32))) - - ;; thread the host function through an instance - (component $c - (import "a" (func $f (result u32))) - (export "f" (func $f)) - ) - (instance $c (instantiate $c (with "a" (func $import)))) - (alias export $c "f" (func $import2)) - - ;; thread the host function into a nested component - (component $c2 - (import "host" (instance $i (export "return-two" (func (result u32))))) - - (core module $m - (import "host" "return-two" (func $host (result i32))) - (func $start - call $host - i32.const 2 - i32.ne - if unreachable end - ) - (start $start) - ) - - (core func $return_two - (canon lower (func $i "return-two")) - ) - (core instance (instantiate $m - (with "host" (instance - (export "return-two" (func $return_two)) - )) - )) - ) - - (instance (instantiate $c2 - (with "host" (instance - (export "return-two" (func $import2)) - )) - )) -) diff --git a/parser/src/test/resources/spec-tests/wasmtime/resources.wast b/parser/src/test/resources/spec-tests/wasmtime/resources.wast deleted file mode 100644 index 28e68ad..0000000 --- a/parser/src/test/resources/spec-tests/wasmtime/resources.wast +++ /dev/null @@ -1,1091 +0,0 @@ -;; bare bones "intrinsics work" -(component - (type $r (resource (rep i32))) - (core func $rep (canon resource.rep $r)) - (core func $new (canon resource.new $r)) - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "rep" (func $rep (param i32) (result i32))) - (import "" "new" (func $new (param i32) (result i32))) - (import "" "drop" (func $drop (param i32))) - - (func $start - (local $r i32) - (local.set $r (call $new (i32.const 100))) - - (if (i32.ne (local.get $r) (i32.const 1)) (then (unreachable))) - (if (i32.ne (call $rep (local.get $r)) (i32.const 100)) (then (unreachable))) - - (call $drop (local.get $r)) - ) - - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "rep" (func $rep)) - (export "new" (func $new)) - (export "drop" (func $drop)) - )) - )) -) - -;; cannot call `resource.drop` on a nonexistent resource -(component - (type $r (resource (rep i32))) - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "drop" (func $drop (param i32))) - - (func (export "r") - (call $drop (i32.const 0)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - )) - )) - - (func (export "r") (canon lift (core func $i "r"))) -) -(assert_trap (invoke "r") "unknown handle index 0") - -;; cannot call `resource.rep` on a nonexistent resource -(component - (type $r (resource (rep i32))) - (core func $rep (canon resource.rep $r)) - - (core module $m - (import "" "rep" (func $rep (param i32) (result i32))) - - (func (export "r") - (drop (call $rep (i32.const 0))) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "rep" (func $rep)) - )) - )) - - (func (export "r") (canon lift (core func $i "r"))) -) -(assert_trap (invoke "r") "unknown handle index 0") - -;; index reuse behavior of handles -(component - (type $r (resource (rep i32))) - (core func $rep (canon resource.rep $r)) - (core func $new (canon resource.new $r)) - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "rep" (func $rep (param i32) (result i32))) - (import "" "new" (func $new (param i32) (result i32))) - (import "" "drop" (func $drop (param i32))) - - (func $start - (local $r1 i32) - (local $r2 i32) - (local $r3 i32) - (local $r4 i32) - - ;; resources assigned sequentially - (local.set $r1 (call $new (i32.const 100))) - (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) - - (local.set $r2 (call $new (i32.const 200))) - (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) - - (local.set $r3 (call $new (i32.const 300))) - (if (i32.ne (local.get $r3) (i32.const 3)) (then (unreachable))) - - ;; representations all look good - (if (i32.ne (call $rep (local.get $r1)) (i32.const 100)) (then (unreachable))) - (if (i32.ne (call $rep (local.get $r2)) (i32.const 200)) (then (unreachable))) - (if (i32.ne (call $rep (local.get $r3)) (i32.const 300)) (then (unreachable))) - - ;; reallocate r2 - (call $drop (local.get $r2)) - (local.set $r2 (call $new (i32.const 400))) - - ;; should have reused index 3 - (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) - - ;; representations all look good - (if (i32.ne (call $rep (local.get $r1)) (i32.const 100)) (then (unreachable))) - (if (i32.ne (call $rep (local.get $r2)) (i32.const 400)) (then (unreachable))) - (if (i32.ne (call $rep (local.get $r3)) (i32.const 300)) (then (unreachable))) - - ;; deallocate, then reallocate - (call $drop (local.get $r1)) - (call $drop (local.get $r2)) - (call $drop (local.get $r3)) - - (local.set $r1 (call $new (i32.const 500))) - (local.set $r2 (call $new (i32.const 600))) - (local.set $r3 (call $new (i32.const 700))) - - ;; representations all look good - (if (i32.ne (call $rep (local.get $r1)) (i32.const 500)) (then (unreachable))) - (if (i32.ne (call $rep (local.get $r2)) (i32.const 600)) (then (unreachable))) - (if (i32.ne (call $rep (local.get $r3)) (i32.const 700)) (then (unreachable))) - - ;; indices should be lifo - (if (i32.ne (local.get $r1) (i32.const 3)) (then (unreachable))) - (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) - (if (i32.ne (local.get $r3) (i32.const 1)) (then (unreachable))) - - ;; bump one more time - (local.set $r4 (call $new (i32.const 800))) - (if (i32.ne (local.get $r4) (i32.const 4)) (then (unreachable))) - - ;; deallocate everything - (call $drop (local.get $r1)) - (call $drop (local.get $r2)) - (call $drop (local.get $r3)) - (call $drop (local.get $r4)) - ) - - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "rep" (func $rep)) - (export "new" (func $new)) - (export "drop" (func $drop)) - )) - )) -) - -(assert_unlinkable - (component - (import "host" (instance - (export "missing" (type (sub resource))) - )) - ) - "was not found") -(assert_unlinkable - (component - (import "host" (instance - (export "return-three" (type (sub resource))) - )) - ) - "expected resource found func") - -;; all resources can be uniquely imported -(component - (import "host" (instance - (export "resource1" (type (sub resource))) - (export "resource2" (type (sub resource))) - (export "resource1-again" (type (sub resource))) - )) -) - -;; equality constraints also work -(component - (import "host" (instance - (export "resource1" (type $r1 (sub resource))) - (export "resource2" (type (sub resource))) - (export "resource1-again" (type (eq $r1))) - )) -) - -;; equality constraints are checked if resources are supplied -(assert_unlinkable - (component - (import "host" (instance - (export "resource1" (type (sub resource))) - (export "resource2" (type $r1 (sub resource))) - (export "resource1-again" (type (eq $r1))) - )) - ) - "mismatched resource types") - -;; equality constraints mean that types don't need to be supplied -(component - (import "host" (instance - (export "resource1" (type $r1 (sub resource))) - (export "resource2" (type (sub resource))) - (export "this-name-is-not-provided-in-the-wast-harness" (type (eq $r1))) - )) -) - -;; simple properties of handles -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32))) - )) - (alias export $host "resource1" (type $r)) - (alias export $host "[constructor]resource1" (func $ctor)) - (alias export $host "[static]resource1.assert" (func $assert)) - - (core func $drop (canon resource.drop $r)) - (core func $ctor (canon lower (func $ctor))) - (core func $assert (canon lower (func $assert))) - - (core module $m - (import "" "drop" (func $drop (param i32))) - (import "" "ctor" (func $ctor (param i32) (result i32))) - (import "" "assert" (func $assert (param i32 i32))) - - (func $start - (local $r1 i32) - (local $r2 i32) - (local.set $r1 (call $ctor (i32.const 100))) - (local.set $r2 (call $ctor (i32.const 200))) - - ;; assert r1/r2 are sequential - (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) - (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) - - ;; reallocate r1 and it should be reassigned the same index - (call $drop (local.get $r1)) - (local.set $r1 (call $ctor (i32.const 300))) - (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) - - ;; internal values should match - (call $assert (local.get $r1) (i32.const 300)) - (call $assert (local.get $r2) (i32.const 200)) - ) - - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - (export "ctor" (func $ctor)) - (export "assert" (func $assert)) - )) - )) -) - -;; Using an index that has never been valid is a trap -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32))) - )) - (alias export $host "resource1" (type $r)) - (alias export $host "[static]resource1.assert" (func $assert)) - (core func $assert (canon lower (func $assert))) - - (core module $m - (import "" "assert" (func $assert (param i32 i32))) - - (func (export "f") - (call $assert (i32.const 0) (i32.const 0)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "assert" (func $assert)) - )) - )) - - (func (export "f") (canon lift (core func $i "f"))) -) - -(assert_trap (invoke "f") "unknown handle index") - -;; Using an index which was previously valid but no longer valid is also a trap. -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32))) - )) - (alias export $host "[constructor]resource1" (func $ctor)) - (alias export $host "[static]resource1.assert" (func $assert)) - - (core func $assert (canon lower (func $assert))) - (core func $ctor (canon lower (func $ctor))) - - (core module $m - (import "" "assert" (func $assert (param i32 i32))) - (import "" "ctor" (func $ctor (param i32) (result i32))) - - (global $handle (mut i32) i32.const 0) - - (func (export "f") - (global.set $handle (call $ctor (i32.const 100))) - (call $assert (global.get $handle) (i32.const 100)) - ) - - (func (export "f2") - (call $assert (global.get $handle) (i32.const 100)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "assert" (func $assert)) - (export "ctor" (func $ctor)) - )) - )) - - (func (export "f") (canon lift (core func $i "f"))) - (func (export "f2") (canon lift (core func $i "f2"))) -) - -(assert_return (invoke "f")) -(assert_trap (invoke "f2") "unknown handle index") - -;; Also invalid to pass a previously valid handle to the drop intrinsic -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - )) - (alias export $host "resource1" (type $r)) - (alias export $host "[constructor]resource1" (func $ctor)) - - (core func $drop (canon resource.drop $r)) - (core func $ctor (canon lower (func $ctor))) - - (core module $m - (import "" "drop" (func $drop (param i32))) - (import "" "ctor" (func $ctor (param i32) (result i32))) - - (global $handle (mut i32) i32.const 0) - - (func (export "f") - (global.set $handle (call $ctor (i32.const 100))) - (call $drop (global.get $handle)) - ) - - (func (export "f2") - (call $drop (global.get $handle)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "ctor" (func $ctor)) - (export "drop" (func $drop)) - )) - )) - - (func (export "f") (canon lift (core func $i "f"))) - (func (export "f2") (canon lift (core func $i "f2"))) -) - -(assert_return (invoke "f")) -(assert_trap (invoke "f2") "unknown handle index") - -;; If an inner component instantiates a resource then an outer component -;; should not implicitly have access to that resource. -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - )) - - ;; an inner component which upon instantiation will invoke the constructor, - ;; assert that it's zero, and then forget about it. - (component $inner - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - )) - (alias export $host "[constructor]resource1" (func $ctor)) - - (core func $ctor (canon lower (func $ctor))) - - (core module $m - (import "" "ctor" (func $ctor (param i32) (result i32))) - - (func $start - (if (i32.ne (call $ctor (i32.const 100)) (i32.const 0)) (then (unreachable))) - ) - ) - (core instance $i (instantiate $m - (with "" (instance (export "ctor" (func $ctor)))) - )) - ) - (instance $i (instantiate $inner (with "host" (instance $host)))) - - ;; the rest of this component which is a single function that invokes `drop` - ;; for index 0. The index 0 should be valid within the above component, but - ;; it is not valid within this component - (alias export $host "resource1" (type $r)) - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "drop" (func $drop (param i32))) - - (func (export "f") - (call $drop (i32.const 0)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - )) - )) - - (func (export "f") (canon lift (core func $i "f"))) -) - -(assert_trap (invoke "f") "unknown handle index") - -;; Same as the above test, but for resources defined within a component -(component - (component $inner - (type $r (resource (rep i32))) - - (core func $ctor (canon resource.new $r)) - - (core module $m - (import "" "ctor" (func $ctor (param i32) (result i32))) - - (func $start - (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) - ) - (start $start) - ) - (core instance $i (instantiate $m - (with "" (instance (export "ctor" (func $ctor)))) - )) - (export "r" (type $r)) - ) - (instance $i (instantiate $inner)) - - ;; the rest of this component which is a single function that invokes `drop` - ;; for index 1. The index 1 should be valid within the above component, but - ;; it is not valid within this component - (alias export $i "r" (type $r)) - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "drop" (func $drop (param i32))) - - (func (export "f") - (call $drop (i32.const 1)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - )) - )) - - (func (export "f") (canon lift (core func $i "f"))) -) - -(assert_trap (invoke "f") "unknown handle index 1") - -;; Each instantiation of a component generates a unique resource type, so -;; allocating in one component and deallocating in another should fail. -(component - (component $inner - (type $r (resource (rep i32))) - - (core func $ctor (canon resource.new $r)) - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "ctor" (func $ctor (param i32) (result i32))) - (import "" "drop" (func $drop (param i32))) - - (func (export "alloc") - (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) - ) - (func (export "dealloc") - (call $drop (i32.const 1)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "ctor" (func $ctor)) - (export "drop" (func $drop)) - )) - )) - (func (export "alloc") (canon lift (core func $i "alloc"))) - (func (export "dealloc") (canon lift (core func $i "dealloc"))) - ) - (instance $i1 (instantiate $inner)) - (instance $i2 (instantiate $inner)) - - (alias export $i1 "alloc" (func $alloc_in_1)) - (alias export $i1 "dealloc" (func $dealloc_in_1)) - (alias export $i2 "alloc" (func $alloc_in_2)) - (alias export $i2 "dealloc" (func $dealloc_in_2)) - - (export "alloc-in1" (func $alloc_in_1)) - (export "dealloc-in1" (func $dealloc_in_1)) - (export "alloc-in2" (func $alloc_in_2)) - (export "dealloc-in2" (func $dealloc_in_2)) -) - -(assert_return (invoke "alloc-in1")) -(assert_return (invoke "dealloc-in1")) -(assert_return (invoke "alloc-in1")) -(assert_return (invoke "alloc-in2")) -(assert_return (invoke "dealloc-in2")) -(assert_trap (invoke "dealloc-in2") "unknown handle index") - -;; Same as above, but the same host resource type is imported into a -;; component that is instantiated twice. Each component instance should -;; receive different tables tracking resources so a resource allocated in one -;; should not be visible in the other. -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - )) - (alias export $host "resource1" (type $r)) - (alias export $host "[constructor]resource1" (func $ctor)) - - (component $inner - (import "r" (type $r (sub resource))) - (import "[constructor]r" (func $ctor (param "r" u32) (result (own $r)))) - - (core func $ctor (canon lower (func $ctor))) - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "ctor" (func $ctor (param i32) (result i32))) - (import "" "drop" (func $drop (param i32))) - - (func (export "alloc") - (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) - ) - (func (export "dealloc") - (call $drop (i32.const 1)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "ctor" (func $ctor)) - (export "drop" (func $drop)) - )) - )) - (func (export "alloc") (canon lift (core func $i "alloc"))) - (func (export "dealloc") (canon lift (core func $i "dealloc"))) - ) - (instance $i1 (instantiate $inner - (with "r" (type $r)) - (with "[constructor]r" (func $ctor)) - )) - (instance $i2 (instantiate $inner - (with "r" (type $r)) - (with "[constructor]r" (func $ctor)) - )) - - (alias export $i1 "alloc" (func $alloc_in_1)) - (alias export $i1 "dealloc" (func $dealloc_in_1)) - (alias export $i2 "alloc" (func $alloc_in_2)) - (alias export $i2 "dealloc" (func $dealloc_in_2)) - - (export "alloc-in1" (func $alloc_in_1)) - (export "dealloc-in1" (func $dealloc_in_1)) - (export "alloc-in2" (func $alloc_in_2)) - (export "dealloc-in2" (func $dealloc_in_2)) -) - -(assert_return (invoke "alloc-in1")) -(assert_return (invoke "dealloc-in1")) -(assert_return (invoke "alloc-in1")) -(assert_return (invoke "alloc-in2")) -(assert_return (invoke "dealloc-in2")) -(assert_trap (invoke "dealloc-in2") "unknown handle index") - -;; Multiple copies of intrinsics all work -(component - (type $r (resource (rep i32))) - - (core func $new1 (canon resource.new $r)) - (core func $new2 (canon resource.new $r)) - (core func $drop1 (canon resource.drop $r)) - (core func $drop2 (canon resource.drop $r)) - - (core module $m - (import "" "new1" (func $new1 (param i32) (result i32))) - (import "" "new2" (func $new2 (param i32) (result i32))) - (import "" "drop1" (func $drop1 (param i32))) - (import "" "drop2" (func $drop2 (param i32))) - - (func $start - ;; 2x2 matrix of pairing new/drop - (call $drop1 (call $new1 (i32.const 101))) - (call $drop2 (call $new1 (i32.const 102))) - (call $drop1 (call $new2 (i32.const 103))) - (call $drop2 (call $new2 (i32.const 104))) - - ;; should be referencing the same namespace - (if (i32.ne (call $new1 (i32.const 105)) (i32.const 1)) (then (unreachable))) - (if (i32.ne (call $new2 (i32.const 105)) (i32.const 2)) (then (unreachable))) - - ;; use different drops out of order - (call $drop2 (i32.const 1)) - (call $drop1 (i32.const 2)) - ) - - (start $start) - ) - - (core instance (instantiate $m - (with "" (instance - (export "new1" (func $new1)) - (export "new2" (func $new2)) - (export "drop1" (func $drop1)) - (export "drop2" (func $drop2)) - )) - )) -) - -;; u32::MAX isn't special in some weird way, it's just probably always invalid -;; because that's a lot of handles. -(component - (type $r (resource (rep i32))) - - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "drop" (func $drop (param i32))) - - (func (export "f") - (call $drop (i32.const 0xffffffff)) - ) - ) - - (core instance $i (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - )) - )) - (func (export "f") (canon lift (core func $i "f"))) -) -(assert_trap (invoke "f") "unknown handle index") - -;; Test behavior of running a destructor for local resources -(component - (core module $m1 - (global $drops (mut i32) i32.const 0) - (global $last_drop (mut i32) i32.const -1) - - (func (export "dtor") (param i32) - (global.set $drops (i32.add (global.get $drops) (i32.const 1))) - (global.set $last_drop (local.get 0)) - ) - (func (export "drops") (result i32) global.get $drops) - (func (export "last-drop") (result i32) global.get $last_drop) - ) - (core instance $i1 (instantiate $m1)) - - (type $r1 (resource (rep i32))) - (type $r2 (resource (rep i32) (dtor (func $i1 "dtor")))) - - (core func $drop1 (canon resource.drop $r1)) - (core func $drop2 (canon resource.drop $r2)) - (core func $new1 (canon resource.new $r1)) - (core func $new2 (canon resource.new $r2)) - - (core module $m2 - (import "" "drop1" (func $drop1 (param i32))) - (import "" "drop2" (func $drop2 (param i32))) - (import "" "new1" (func $new1 (param i32) (result i32))) - (import "" "new2" (func $new2 (param i32) (result i32))) - (import "i1" "drops" (func $drops (result i32))) - (import "i1" "last-drop" (func $last-drop (result i32))) - - (func $start - (local $r1 i32) - (local $r2 i32) - - (local.set $r1 (call $new1 (i32.const 100))) - (local.set $r2 (call $new2 (i32.const 200))) - - ;; indexes start at 2 and while they have distinct types they should be - ;; within the same table. - (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) - (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) - - ;; nothing should be dropped yet - (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) - (if (i32.ne (call $last-drop) (i32.const -1)) (then (unreachable))) - - ;; dropping a resource without a destructor is ok, but shouldn't tamper - ;; with anything. - (call $drop1 (local.get $r1)) - (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) - (if (i32.ne (call $last-drop) (i32.const -1)) (then (unreachable))) - - ;; drop r2 which should record a drop and additionally record the private - ;; representation value which was dropped - (call $drop2 (local.get $r2)) - (if (i32.ne (call $drops) (i32.const 1)) (then (unreachable))) - (if (i32.ne (call $last-drop) (i32.const 200)) (then (unreachable))) - - ;; do it all over again - (local.set $r2 (call $new2 (i32.const 300))) - (call $drop2 (local.get $r2)) - (if (i32.ne (call $drops) (i32.const 2)) (then (unreachable))) - (if (i32.ne (call $last-drop) (i32.const 300)) (then (unreachable))) - ) - - (start $start) - ) - - (core instance $i2 (instantiate $m2 - (with "" (instance - (export "drop1" (func $drop1)) - (export "drop2" (func $drop2)) - (export "new1" (func $new1)) - (export "new2" (func $new2)) - )) - (with "i1" (instance $i1)) - )) -) - -;; Test dropping a host resource -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - (export "[static]resource1.last-drop" (func (result u32))) - (export "[static]resource1.drops" (func (result u32))) - )) - - (alias export $host "resource1" (type $r)) - (alias export $host "[constructor]resource1" (func $ctor)) - (alias export $host "[static]resource1.last-drop" (func $last-drop)) - (alias export $host "[static]resource1.drops" (func $drops)) - - (core func $drop (canon resource.drop $r)) - (core func $ctor (canon lower (func $ctor))) - (core func $last-drop (canon lower (func $last-drop))) - (core func $drops (canon lower (func $drops))) - - (core module $m - (import "" "drop" (func $drop (param i32))) - (import "" "ctor" (func $ctor (param i32) (result i32))) - (import "" "last-drop" (func $last-drop (result i32))) - (import "" "drops" (func $raw-drops (result i32))) - - (global $init-drop-cnt (mut i32) i32.const 0) - - (func $drops (result i32) - (i32.sub (call $raw-drops) (global.get $init-drop-cnt)) - ) - - (func $start - (local $r1 i32) - (global.set $init-drop-cnt (call $raw-drops)) - - (local.set $r1 (call $ctor (i32.const 100))) - - ;; should be no drops yet - (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) - - ;; should count a drop - (call $drop (local.get $r1)) - (if (i32.ne (call $drops) (i32.const 1)) (then (unreachable))) - (if (i32.ne (call $last-drop) (i32.const 100)) (then (unreachable))) - - ;; do it again to be sure - (local.set $r1 (call $ctor (i32.const 200))) - (call $drop (local.get $r1)) - (if (i32.ne (call $drops) (i32.const 2)) (then (unreachable))) - (if (i32.ne (call $last-drop) (i32.const 200)) (then (unreachable))) - ) - - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - (export "ctor" (func $ctor)) - (export "last-drop" (func $last-drop)) - (export "drops" (func $drops)) - )) - )) -) - -;; Test some bare-bones basics of borrowed resources -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - (export "[method]resource1.simple" (func (param "self" (borrow $r)) (param "rep" u32))) - (export "[method]resource1.take-borrow" (func (param "self" (borrow $r)) (param "b" (borrow $r)))) - (export "[method]resource1.take-own" (func (param "self" (borrow $r)) (param "b" (own $r)))) - )) - - (alias export $host "resource1" (type $r)) - (alias export $host "[constructor]resource1" (func $ctor)) - (alias export $host "[method]resource1.simple" (func $simple)) - (alias export $host "[method]resource1.take-borrow" (func $take-borrow)) - (alias export $host "[method]resource1.take-own" (func $take-own)) - - (core func $drop (canon resource.drop $r)) - (core func $ctor (canon lower (func $ctor))) - (core func $simple (canon lower (func $simple))) - (core func $take-own (canon lower (func $take-own))) - (core func $take-borrow (canon lower (func $take-borrow))) - - (core module $m - (import "" "drop" (func $drop (param i32))) - (import "" "ctor" (func $ctor (param i32) (result i32))) - (import "" "simple" (func $simple (param i32 i32))) - (import "" "take-own" (func $take-own (param i32 i32))) - (import "" "take-borrow" (func $take-borrow (param i32 i32))) - - - (func $start - (local $r1 i32) - (local $r2 i32) - (local.set $r1 (call $ctor (i32.const 100))) - (local.set $r2 (call $ctor (i32.const 200))) - - (call $simple (local.get $r1) (i32.const 100)) - (call $simple (local.get $r1) (i32.const 100)) - (call $simple (local.get $r2) (i32.const 200)) - (call $simple (local.get $r1) (i32.const 100)) - (call $simple (local.get $r2) (i32.const 200)) - (call $simple (local.get $r2) (i32.const 200)) - - (call $drop (local.get $r1)) - (call $drop (local.get $r2)) - - - (local.set $r1 (call $ctor (i32.const 200))) - (local.set $r2 (call $ctor (i32.const 300))) - (call $take-borrow (local.get $r1) (local.get $r2)) - (call $take-borrow (local.get $r2) (local.get $r1)) - (call $take-borrow (local.get $r1) (local.get $r1)) - (call $take-borrow (local.get $r2) (local.get $r2)) - - (call $take-own (local.get $r1) (call $ctor (i32.const 400))) - (call $take-own (local.get $r2) (call $ctor (i32.const 500))) - (call $take-own (local.get $r2) (local.get $r1)) - (call $drop (local.get $r2)) - - ;; table should be empty at this point, so a fresh allocation should get - ;; index 2 - (if (i32.ne (call $ctor (i32.const 600)) (i32.const 1)) (then (unreachable))) - ) - - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - (export "ctor" (func $ctor)) - (export "simple" (func $simple)) - (export "take-own" (func $take-own)) - (export "take-borrow" (func $take-borrow)) - )) - )) -) - -;; Cannot pass out an owned resource when it's borrowed by the same call -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - (export "[method]resource1.take-own" (func (param "self" (borrow $r)) (param "b" (own $r)))) - )) - - (alias export $host "resource1" (type $r)) - (alias export $host "[constructor]resource1" (func $ctor)) - (alias export $host "[method]resource1.take-own" (func $take-own)) - - (core func $drop (canon resource.drop $r)) - (core func $ctor (canon lower (func $ctor))) - (core func $take-own (canon lower (func $take-own))) - - (core module $m - (import "" "drop" (func $drop (param i32))) - (import "" "ctor" (func $ctor (param i32) (result i32))) - (import "" "take-own" (func $take-own (param i32 i32))) - - - (func (export "f") - (local $r i32) - (local.set $r (call $ctor (i32.const 100))) - (call $take-own (local.get $r) (local.get $r)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - (export "ctor" (func $ctor)) - (export "take-own" (func $take-own)) - )) - )) - - (func (export "f") (canon lift (core func $i "f"))) -) - -(assert_trap (invoke "f") "cannot remove owned resource while borrowed") - -;; Borrows must actually exist -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[method]resource1.simple" (func (param "self" (borrow $r)) (param "b" u32))) - )) - - (alias export $host "resource1" (type $r)) - (alias export $host "[method]resource1.simple" (func $simple)) - - (core func $drop (canon resource.drop $r)) - (core func $simple (canon lower (func $simple))) - - (core module $m - (import "" "drop" (func $drop (param i32))) - (import "" "simple" (func $simple (param i32 i32))) - - - (func (export "f") - (call $simple (i32.const 0) (i32.const 0)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - (export "simple" (func $simple)) - )) - )) - - (func (export "f") (canon lift (core func $i "f"))) -) - -(assert_trap (invoke "f") "unknown handle index 0") - -(component - (component $A - (type $t' (resource (rep i32))) - (export $t "t" (type $t')) - - (core func $ctor (canon resource.new $t)) - (core func $dtor (canon resource.drop $t)) - (core func $rep (canon resource.rep $t)) - - (core module $m - (import "" "dtor" (func $dtor (param i32))) - (import "" "rep" (func $rep (param i32) (result i32))) - - (func (export "[method]t.assert") (param i32 i32) - (if (i32.ne (local.get 0) (local.get 1)) (then (unreachable))) - ) - (func (export "[static]t.assert-own") (param i32 i32) - (if (i32.ne (call $rep (local.get 0)) (local.get 1)) (then (unreachable))) - (call $dtor (local.get 0)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "dtor" (func $dtor)) - (export "rep" (func $rep)) - )) - )) - (func (export "[constructor]t") (param "x" u32) (result (own $t)) - (canon lift (core func $ctor))) - (func (export "[method]t.assert") (param "self" (borrow $t)) (param "x" u32) - (canon lift (core func $i "[method]t.assert"))) - (func (export "[static]t.assert-own") (param "self" (own $t)) (param "x" u32) - (canon lift (core func $i "[static]t.assert-own"))) - ) - (instance $a (instantiate $A)) - - (component $B - (import "a" (instance $i - (export "t" (type $t (sub resource))) - (export "[constructor]t" (func (param "x" u32) (result (own $t)))) - (export "[method]t.assert" (func (param "self" (borrow $t)) (param "x" u32))) - (export "[static]t.assert-own" (func (param "self" (own $t)) (param "x" u32))) - )) - - (alias export $i "t" (type $t)) - (alias export $i "[constructor]t" (func $ctor)) - (alias export $i "[method]t.assert" (func $assert-borrow)) - (alias export $i "[static]t.assert-own" (func $assert-own)) - - (core func $ctor (canon lower (func $ctor))) - (core func $dtor (canon resource.drop $t)) - (core func $assert-own (canon lower (func $assert-own))) - (core func $assert-borrow (canon lower (func $assert-borrow))) - - (core module $m - (import "" "ctor" (func $ctor (param i32) (result i32))) - (import "" "dtor" (func $dtor (param i32))) - (import "" "assert-own" (func $assert-own (param i32 i32))) - (import "" "assert-borrow" (func $assert-borrow (param i32 i32))) - - (func (export "f") - (local $r1 i32) - (local $r2 i32) - - (local.set $r1 (call $ctor (i32.const 100))) - (local.set $r2 (call $ctor (i32.const 200))) - - (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) - (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) - - (call $assert-borrow (local.get $r2) (i32.const 200)) - (call $assert-borrow (local.get $r1) (i32.const 100)) - - (call $assert-own (local.get $r2) (i32.const 200)) - (call $dtor (local.get $r1)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "ctor" (func $ctor)) - (export "dtor" (func $dtor)) - (export "assert-own" (func $assert-own)) - (export "assert-borrow" (func $assert-borrow)) - )) - )) - (func (export "f") (canon lift (core func $i "f"))) - ) - (instance $b (instantiate $B (with "a" (instance $a)))) - (export "f" (func $b "f")) -) - -(assert_return (invoke "f")) - -;; Test destructor behavior when using the wrong resource type -(component definition $C - (type $r1 (resource (rep i32))) - (type $r2 (resource (rep i32))) - - (core func $drop1 (canon resource.drop $r1)) - (core func $drop2 (canon resource.drop $r2)) - (core func $new1 (canon resource.new $r1)) - (core func $new2 (canon resource.new $r2)) - - (core module $m2 - (import "" "drop1" (func $drop1 (param i32))) - (import "" "drop2" (func $drop2 (param i32))) - (import "" "new1" (func $new1 (param i32) (result i32))) - (import "" "new2" (func $new2 (param i32) (result i32))) - - (func (export "drop-r1-as-r2") (call $drop2 (call $new1 (i32.const 100)))) - (func (export "return-r1-as-r2") (result i32) (call $new1 (i32.const 100))) - ) - - (core instance $i2 (instantiate $m2 - (with "" (instance - (export "drop1" (func $drop1)) - (export "drop2" (func $drop2)) - (export "new1" (func $new1)) - (export "new2" (func $new2)) - )) - )) - - (export $r2' "r2" (type $r2)) - (func (export "drop-r1-as-r2") (canon lift (core func $i2 "drop-r1-as-r2"))) - (func (export "return-r1-as-r2") (result (own $r2')) (canon lift (core func $i2 "return-r1-as-r2"))) -) - -(component instance $C1 $C) -(assert_trap (invoke "drop-r1-as-r2") "handle index 1 used with the wrong type, expected guest-defined resource but found a different guest-defined resource") -(component instance $C1 $C) -(assert_trap (invoke "return-r1-as-r2") "handle index 1 used with the wrong type, expected guest-defined resource but found a different guest-defined resource") diff --git a/parser/src/test/resources/spec-tests/wasmtime/restrictions.wast b/parser/src/test/resources/spec-tests/wasmtime/restrictions.wast deleted file mode 100644 index 9bd53e7..0000000 --- a/parser/src/test/resources/spec-tests/wasmtime/restrictions.wast +++ /dev/null @@ -1,22 +0,0 @@ -(assert_invalid - (component (import "x" (component))) - "root-level component imports are not supported") - -(assert_invalid - (component (component (export "x"))) - "exporting a component from the root component is not supported") - -(assert_invalid - (component - (import "f" (func $f)) - (export "f" (func $f)) - ) - "component export `f` is a reexport of an imported function which is not implemented") - -(assert_invalid - (component - (import "x" (component - (export "x" (type (sub resource))) - )) - ) - "root-level component imports are not supported") diff --git a/parser/src/test/resources/spec-tests/wasmtime/simple.wast b/parser/src/test/resources/spec-tests/wasmtime/simple.wast deleted file mode 100644 index 7bf2ab1..0000000 --- a/parser/src/test/resources/spec-tests/wasmtime/simple.wast +++ /dev/null @@ -1,42 +0,0 @@ -(component) - -(component - (core module) -) - -(component - (core module) - (core module) - (core module) -) - -(component - (core module - (func (export "a") (result i32) i32.const 0) - (func (export "b") (result i64) i64.const 0) - ) - (core module - (func (export "c") (result f32) f32.const 0) - (func (export "d") (result f64) f64.const 0) - ) -) - -(assert_invalid - (component - (import "a" (component)) - ) - "root-level component imports are not supported") - -(assert_invalid - (component - (component (export "a")) - ) - "exporting a component from the root component is not supported") - -(component - (core module $m (func (export ""))) - (core instance $m (instantiate $m)) - (func (export "a") (canon lift (core func $m ""))) -) - -(assert_return (invoke "a")) diff --git a/parser/src/test/resources/spec-tests/wasmtime/strings.wast b/parser/src/test/resources/spec-tests/wasmtime/strings.wast deleted file mode 100644 index 943fd31..0000000 --- a/parser/src/test/resources/spec-tests/wasmtime/strings.wast +++ /dev/null @@ -1,110 +0,0 @@ -;;! multi_memory = true - -;; unaligned utf16 string -(assert_trap - (component - (component $c - (core module $m - (func (export "") (param i32 i32)) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 0) - (memory (export "memory") 1) - ) - (core instance $m (instantiate $m)) - (func (export "a") (param "a" string) - (canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory")) - ) - ) - - (component $c2 - (import "a" (func $f (param "a" string))) - (core module $libc - (memory (export "memory") 1) - ) - (core instance $libc (instantiate $libc)) - (core func $f (canon lower (func $f) string-encoding=utf16 (memory $libc "memory"))) - (core module $m - (import "" "" (func $f (param i32 i32))) - - (func $start (call $f (i32.const 1) (i32.const 0))) - (start $start) - ) - (core instance (instantiate $m (with "" (instance (export "" (func $f)))))) - ) - - (instance $c (instantiate $c)) - (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) - ) - "unaligned pointer") - -;; unaligned latin1+utf16 string, even with the latin1 encoding -(assert_trap - (component - (component $c - (core module $m - (func (export "") (param i32 i32)) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 0) - (memory (export "memory") 1) - ) - (core instance $m (instantiate $m)) - (func (export "a") (param "a" string) - (canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory")) - ) - ) - - (component $c2 - (import "a" (func $f (param "a" string))) - (core module $libc - (memory (export "memory") 1) - ) - (core instance $libc (instantiate $libc)) - (core func $f (canon lower (func $f) string-encoding=latin1+utf16 (memory $libc "memory"))) - (core module $m - (import "" "" (func $f (param i32 i32))) - - (func $start (call $f (i32.const 1) (i32.const 0))) - (start $start) - ) - (core instance (instantiate $m (with "" (instance (export "" (func $f)))))) - ) - - (instance $c (instantiate $c)) - (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) - ) - "unaligned pointer") - -;; out of bounds utf8->utf8 string -(assert_trap - (component - (component $c - (core module $m - (func (export "") (param i32 i32)) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 0) - (memory (export "memory") 1) - ) - (core instance $m (instantiate $m)) - (func (export "a") (param "a" string) - (canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory") - string-encoding=utf8) - ) - ) - - (component $c2 - (import "a" (func $f (param "a" string))) - (core module $libc - (memory (export "memory") 1) - ) - (core instance $libc (instantiate $libc)) - (core func $f (canon lower (func $f) string-encoding=utf8 (memory $libc "memory"))) - (core module $m - (import "" "" (func $f (param i32 i32))) - - (func $start (call $f (i32.const 0x8000_0000) (i32.const 1))) - (start $start) - ) - (core instance (instantiate $m (with "" (instance (export "" (func $f)))))) - ) - - (instance $c (instantiate $c)) - (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) - ) - "string content out-of-bounds") diff --git a/parser/src/test/resources/spec-tests/wasmtime/tags.wast b/parser/src/test/resources/spec-tests/wasmtime/tags.wast deleted file mode 100644 index cac1fde..0000000 --- a/parser/src/test/resources/spec-tests/wasmtime/tags.wast +++ /dev/null @@ -1,14 +0,0 @@ -;;! exceptions = true - -(component - (core module $a (tag (export "t"))) - (core module $b (import "a" "t" (tag))) - - (core instance $a (instantiate $a)) - (core instance (instantiate $b (with "a" (instance $a)))) - (core instance (instantiate $b - (with "a" (instance - (export "t" (tag $a "t")) - )) - )) -) diff --git a/parser/src/test/resources/spec-tests/wasmtime/types.wast b/parser/src/test/resources/spec-tests/wasmtime/types.wast deleted file mode 100644 index 9596ebe..0000000 --- a/parser/src/test/resources/spec-tests/wasmtime/types.wast +++ /dev/null @@ -1,355 +0,0 @@ -(component - (type string) - (type (func (param "a" string))) - (type $r (record (field "x" (result)) (field "y" string))) - (type $u (variant (case "r" $r) (case "s" string))) - (type $e (result $u (error u32))) - (type (result $u)) - (type (result (error $u))) - (type (result)) - - (type (func (param "a" $e) (result (option $r)))) - - (type (variant - (case "a" string) - (case "b" u32) - (case "c" float32) - (case "d" float64) - )) - - (type $errno (enum "a" "b" "e")) - (type (list $errno)) - (type $oflags (flags "read" "write" "exclusive")) - (type (tuple $oflags $errno $r)) - - ;; primitives in functions - (type (func - (param "a" bool) - (param "b" u8) - (param "c" s8) - (param "d" u16) - (param "e" s16) - (param "f" u32) - (param "g" s32) - (param "h" u64) - (param "i" s64) - (param "j" char) - (param "k" string) - )) - - ;; primitives in types - (type bool) - (type u8) - (type s8) - (type u16) - (type s16) - (type u32) - (type s32) - (type u64) - (type s64) - (type char) - (type string) -) - -(component - (type $empty (func)) - (type (func (param "a" string) (result u32))) - (type (component)) - (core type (module)) - (core type (func)) - (type (instance)) - - (type (component - (import "x" (func (type $empty))) - (import "y" (func)) - (import "z" (component)) - - (type $t (instance)) - - (export "a" (core module)) - (export "b" (instance (type $t))) - )) - - (type (instance - (export "x" (func (type $empty))) - (export "y" (func)) - (export "z" (component)) - - (type $t (instance)) - - (export "a" (core module)) - (export "b" (instance (type $t))) - )) - - (core type (module - (import "" "" (func (param i32))) - (import "" "1" (func (result i32))) - (export "1" (global i32)) - (export "2" (memory 1)) - (export "3" (table 1 funcref)) - )) -) - -;; outer core aliases work -(component $C - (core type $f (func)) - (core type $m (module)) - - (component $C2 - (alias outer $C $f (core type $my_f)) - (import "a" (core module (type $m))) - (import "x" (core module - (alias outer $C2 $my_f (type $my_f)) - (import "" "1" (func (type $my_f))) - )) - ) -) - -;; type exports work -(component $C - (component $C2 - (type string) - (export "x" (type 0)) - ) - (instance (instantiate 0)) - (alias export 0 "x" (type)) - (export "x" (type 0)) -) - -(component - (core module $m (func (export "") (param i32) (result i32) local.get 0)) - (core instance $m (instantiate $m)) - (func (export "i-to-b") (param "a" u32) (result bool) (canon lift (core func $m ""))) - (func (export "i-to-u8") (param "a" u32) (result u8) (canon lift (core func $m ""))) - (func (export "i-to-s8") (param "a" u32) (result s8) (canon lift (core func $m ""))) - (func (export "i-to-u16") (param "a" u32) (result u16) (canon lift (core func $m ""))) - (func (export "i-to-s16") (param "a" u32) (result s16) (canon lift (core func $m ""))) -) -(assert_return (invoke "i-to-b" (u32.const 0)) (bool.const false)) -(assert_return (invoke "i-to-b" (u32.const 1)) (bool.const true)) -(assert_return (invoke "i-to-b" (u32.const 2)) (bool.const true)) -(assert_return (invoke "i-to-u8" (u32.const 0x00)) (u8.const 0)) -(assert_return (invoke "i-to-u8" (u32.const 0x01)) (u8.const 1)) -(assert_return (invoke "i-to-u8" (u32.const 0xf01)) (u8.const 1)) -(assert_return (invoke "i-to-u8" (u32.const 0xf00)) (u8.const 0)) -(assert_return (invoke "i-to-s8" (u32.const 0xffffffff)) (s8.const -1)) -(assert_return (invoke "i-to-s8" (u32.const 127)) (s8.const 127)) -(assert_return (invoke "i-to-u16" (u32.const 0)) (u16.const 0)) -(assert_return (invoke "i-to-u16" (u32.const 1)) (u16.const 1)) -(assert_return (invoke "i-to-u16" (u32.const 0xffffffff)) (u16.const 0xffff)) -(assert_return (invoke "i-to-s16" (u32.const 0)) (s16.const 0)) -(assert_return (invoke "i-to-s16" (u32.const 1)) (s16.const 1)) -(assert_return (invoke "i-to-s16" (u32.const 0xffffffff)) (s16.const -1)) - -(assert_invalid - (component - (type $t1 string) - (type $t2 (list $t1)) - (type $t3 (list $t2)) - (type $t4 (list $t3)) - (type $t5 (list $t4)) - (type $t6 (list $t5)) - (type $t7 (list $t6)) - (type $t8 (list $t7)) - (type $t9 (list $t8)) - (type $t10 (list $t9)) - (type $t11 (list $t10)) - (type $t12 (list $t11)) - (type $t13 (list $t12)) - (type $t14 (list $t13)) - (type $t15 (list $t14)) - (type $t16 (list $t15)) - (type $t17 (list $t16)) - (type $t18 (list $t17)) - (type $t19 (list $t18)) - (type $t20 (list $t19)) - (type $t21 (list $t20)) - (type $t22 (list $t21)) - (type $t23 (list $t22)) - (type $t24 (list $t23)) - (type $t25 (list $t24)) - (type $t26 (list $t25)) - (type $t27 (list $t26)) - (type $t28 (list $t27)) - (type $t29 (list $t28)) - (type $t30 (list $t29)) - (type $t31 (list $t30)) - (type $t32 (list $t31)) - (type $t33 (list $t32)) - (type $t34 (list $t33)) - (type $t35 (list $t34)) - (type $t36 (list $t35)) - (type $t37 (list $t36)) - (type $t38 (list $t37)) - (type $t39 (list $t38)) - (type $t40 (list $t39)) - (type $t41 (list $t40)) - (type $t42 (list $t41)) - (type $t43 (list $t42)) - (type $t44 (list $t43)) - (type $t45 (list $t44)) - (type $t46 (list $t45)) - (type $t47 (list $t46)) - (type $t48 (list $t47)) - (type $t49 (list $t48)) - (type $t50 (list $t49)) - (type $t51 (list $t50)) - (type $t52 (list $t51)) - (type $t53 (list $t52)) - (type $t54 (list $t53)) - (type $t55 (list $t54)) - (type $t56 (list $t55)) - (type $t57 (list $t56)) - (type $t58 (list $t57)) - (type $t59 (list $t58)) - (type $t60 (list $t59)) - (type $t61 (list $t60)) - (type $t62 (list $t61)) - (type $t63 (list $t62)) - (type $t64 (list $t63)) - (type $t65 (list $t64)) - (type $t66 (list $t65)) - (type $t67 (list $t66)) - (type $t68 (list $t67)) - (type $t69 (list $t68)) - (type $t70 (list $t69)) - (type $t71 (list $t70)) - (type $t72 (list $t71)) - (type $t73 (list $t72)) - (type $t74 (list $t73)) - (type $t75 (list $t74)) - (type $t76 (list $t75)) - (type $t77 (list $t76)) - (type $t78 (list $t77)) - (type $t79 (list $t78)) - (type $t80 (list $t79)) - (type $t81 (list $t80)) - (type $t82 (list $t81)) - (type $t83 (list $t82)) - (type $t84 (list $t83)) - (type $t85 (list $t84)) - (type $t86 (list $t85)) - (type $t87 (list $t86)) - (type $t88 (list $t87)) - (type $t89 (list $t88)) - (type $t90 (list $t89)) - (type $t91 (list $t90)) - (type $t92 (list $t91)) - (type $t93 (list $t92)) - (type $t94 (list $t93)) - (type $t95 (list $t94)) - (type $t96 (list $t95)) - (type $t97 (list $t96)) - (type $t98 (list $t97)) - (type $t99 (list $t98)) - (type $t100 (list $t99)) - (type $t101 (list $t100)) - (export "t" (type $t101)) - ) - "type nesting is too deep") - -(component - (type (instance - (export "x" (instance $x - (type $t u32) - (export "y" (type (eq $t))) - )) - (alias export $x "y" (type $t)) - (export "my-y" (type (eq $t))) - )) - - (type (component - (import "x" (instance $x - (type $t u32) - (export "y" (type (eq $t))) - )) - (alias export $x "y" (type $t)) - (export "my-y" (type (eq $t))) - )) -) - -(component - (type $t u32) - (export $t2 "t" (type $t)) - (type $r (record (field "x" $t2))) - (export "r" (type $r)) -) - -(component - (component - (import "x" (instance $i - (type $i u32) - (export "i" (type (eq $i))) - )) - (alias export $i "i" (type $i)) - (export "i" (type $i)) - ) -) - -(component - (type $u u32) - (instance $i - (export "i" (type $u)) - ) - (alias export $i "i" (type $i)) - (export "i" (type $i)) -) - -(component - (component $c - (type $t u32) - (export "t" (type $t)) - ) - (instance $c (instantiate $c)) - (export "i" (type $c "t")) -) - -(component - (component $c - (import "x" (component $c - (type $t u32) - (export "t" (type (eq $t))) - )) - (instance $c (instantiate $c)) - (export "i" (type $c "t")) - ) - - (component $x - (type $t u32) - (export "t" (type $t)) - ) - - (instance $c (instantiate $c (with "x" (component $x)))) -) - -(component - (type $t1 u64) - (import "a" (type $t2 (eq $t1))) - (import "b" (type $t3 (eq $t2))) -) - -(component - (import "a" (instance - (type $t1 u64) - (export "a" (type $t2 (eq $t1))) - (export "b" (type (eq $t2))) - )) -) - -(component - (type (export "x") (component - (type $t' (instance - (export "r" (type (sub resource))) - )) - (export "t" (instance $t (type $t'))) - )) -) - -(component - (type (export "x") (instance - (type $t' (instance - (export "r" (type (sub resource))) - )) - (export "t" (instance $t (type $t'))) - )) -) From 76a7a65ec58f1774e5772f9c6f88af10eecc169a Mon Sep 17 00:00:00 2001 From: Jeremy Grelle Date: Tue, 23 Jun 2026 06:17:02 -0400 Subject: [PATCH 5/8] Cleanup --- Readme.md | 12 + docs/phases/00-type-model.md | 2 +- docs/phases/01-binary-parser.md | 5 +- docs/phases/02-wasm-tools.md | 2 +- parser/pom.xml | 21 +- .../run/endive/cm/parser/ComponentParser.java | 43 +- .../java/run/endive/cm/parser/CoreParser.java | 29 +- .../cm/parser/ComponentParserTests.java | 60 +- .../run/endive/cm/parser/JsonFromWast.java | 18 +- .../java/run/endive/cm/parser/WastTests.java | 85 +- pom.xml | 24 +- .../spec-tests/async/async-calls-sync.wast | 251 +++ .../spec-tests/async/cancel-stream.wast | 202 ++ .../spec-tests/async/cancel-subtask.wast | 201 ++ .../spec-tests/async/cancellable.wast | 325 +++ .../spec-tests/async/closed-stream.wast | 102 + .../spec-tests/async/cross-abi-calls.wast | 519 +++++ .../spec-tests/async/cross-task-future.wast | 103 + .../resources/spec-tests/async/deadlock.wast | 73 + .../spec-tests/async/dont-block-start.wast | 50 + .../async/drop-cross-task-borrow.wast | 309 +++ .../spec-tests/async/drop-stream.wast | 160 ++ .../spec-tests/async/drop-subtask.wast | 140 ++ .../spec-tests/async/drop-waitable-set.wast | 84 + .../spec-tests/async/empty-wait.wast | 199 ++ .../spec-tests/async/futures-must-write.wast | 118 + .../async/partial-stream-copies.wast | 238 ++ .../spec-tests/async/passing-resources.wast | 176 ++ .../async/same-component-stream-future.wast | 259 +++ .../spec-tests/async/sync-barges-in.wast | 311 +++ .../spec-tests/async/sync-streams.wast | 178 ++ .../async/trap-if-block-and-sync.wast | 334 +++ .../spec-tests/async/trap-if-done.wast | 470 ++++ .../async/trap-if-sync-and-waitable-set.wast | 288 +++ .../trap-if-transfer-in-waitable-set.wast | 51 + .../spec-tests/async/trap-on-reenter.wast | 110 + .../validate-no-async-abi-for-sync-type.wast | 27 + .../async/validate-no-stream-char.wast | 7 + .../async/wait-during-callback.wast | 77 + .../spec-tests/async/zero-length.wast | 223 ++ .../resources/spec-tests/names/kebab.wast | 60 + .../resources/multiple-resources.wast | 170 ++ .../spec-tests/validation/implements.wast | 108 + .../spec-tests/values/post-return.wast | 384 ++++ .../resources/spec-tests/values/strings.wast | 136 ++ .../spec-tests/wasm-tools/adapt.wast | 287 +++ .../spec-tests/wasm-tools/alias.wast | 301 +++ .../resources/spec-tests/wasm-tools/big.wast | 36 + .../spec-tests/wasm-tools/definedtypes.wast | 123 ++ .../spec-tests/wasm-tools/empty.wast | 4 + .../spec-tests/wasm-tools/example.wast | 17 + .../wasm-tools/export-ascription.wast | 44 + .../wasm-tools/export-introduces-alias.wast | 48 + .../spec-tests/wasm-tools/export.wast | 63 + .../resources/spec-tests/wasm-tools/func.wast | 146 ++ .../spec-tests/wasm-tools/import.wast | 359 +++ .../wasm-tools/imports-exports.wast | 26 + .../spec-tests/wasm-tools/inline-exports.wast | 9 + .../spec-tests/wasm-tools/instance-type.wast | 234 ++ .../spec-tests/wasm-tools/instantiate.wast | 976 ++++++++ .../spec-tests/wasm-tools/invalid.wast | 34 + .../resources/spec-tests/wasm-tools/link.wast | 14 + .../wasm-tools/lots-of-aliases.wast | 179 ++ .../spec-tests/wasm-tools/lower.wast | 17 + .../spec-tests/wasm-tools/memory64.wast | 55 + .../spec-tests/wasm-tools/module-link.wast | 98 + .../spec-tests/wasm-tools/more-flags.wast | 41 + .../spec-tests/wasm-tools/naming.wast | 127 ++ .../spec-tests/wasm-tools/nested-modules.wast | 50 + .../spec-tests/wasm-tools/resources.wast | 1195 ++++++++++ .../resources/spec-tests/wasm-tools/tags.wast | 30 + .../wasm-tools/type-export-restrictions.wast | 504 +++++ .../spec-tests/wasm-tools/types.wast | 374 ++++ .../spec-tests/wasm-tools/very-nested.wast | 1954 +++++++++++++++++ .../spec-tests/wasm-tools/virtualize.wast | 119 + .../spec-tests/wasm-tools/wrong-order.wast | 11 + .../spec-tests/wasmtime/adapter.wast | 137 ++ .../spec-tests/wasmtime/aliasing.wast | 29 + .../resources/spec-tests/wasmtime/fused.wast | 1391 ++++++++++++ .../resources/spec-tests/wasmtime/import.wast | 20 + .../spec-tests/wasmtime/instance.wast | 327 +++ .../spec-tests/wasmtime/linking.wast | 18 + .../spec-tests/wasmtime/modules.wast | 479 ++++ .../resources/spec-tests/wasmtime/nested.wast | 451 ++++ .../spec-tests/wasmtime/resources.wast | 1091 +++++++++ .../spec-tests/wasmtime/restrictions.wast | 22 + .../resources/spec-tests/wasmtime/simple.wast | 42 + .../spec-tests/wasmtime/strings.wast | 110 + .../resources/spec-tests/wasmtime/tags.wast | 14 + .../resources/spec-tests/wasmtime/types.wast | 355 +++ .../java/run/endive/cm/types/CoreAlias.java | 2 +- .../java/run/endive/cm/types/CoreType.java | 28 +- .../run/endive/cm/types/CoreTypeSection.java | 8 +- .../java/run/endive/cm/types/ModuleDecl.java | 25 +- .../java/run/endive/cm/types/ModuleType.java | 8 +- .../run/endive/cm/types/WasmComponent.java | 8 +- wasm-tools/pom.xml | 46 + .../endive/cm/tools/ComponentValidate.java | 0 .../cm/tools/ComponentValidateException.java | 0 99 files changed, 18707 insertions(+), 123 deletions(-) create mode 100644 src/test/resources/spec-tests/async/async-calls-sync.wast create mode 100644 src/test/resources/spec-tests/async/cancel-stream.wast create mode 100644 src/test/resources/spec-tests/async/cancel-subtask.wast create mode 100644 src/test/resources/spec-tests/async/cancellable.wast create mode 100644 src/test/resources/spec-tests/async/closed-stream.wast create mode 100644 src/test/resources/spec-tests/async/cross-abi-calls.wast create mode 100644 src/test/resources/spec-tests/async/cross-task-future.wast create mode 100644 src/test/resources/spec-tests/async/deadlock.wast create mode 100644 src/test/resources/spec-tests/async/dont-block-start.wast create mode 100644 src/test/resources/spec-tests/async/drop-cross-task-borrow.wast create mode 100644 src/test/resources/spec-tests/async/drop-stream.wast create mode 100644 src/test/resources/spec-tests/async/drop-subtask.wast create mode 100644 src/test/resources/spec-tests/async/drop-waitable-set.wast create mode 100644 src/test/resources/spec-tests/async/empty-wait.wast create mode 100644 src/test/resources/spec-tests/async/futures-must-write.wast create mode 100644 src/test/resources/spec-tests/async/partial-stream-copies.wast create mode 100644 src/test/resources/spec-tests/async/passing-resources.wast create mode 100644 src/test/resources/spec-tests/async/same-component-stream-future.wast create mode 100644 src/test/resources/spec-tests/async/sync-barges-in.wast create mode 100644 src/test/resources/spec-tests/async/sync-streams.wast create mode 100644 src/test/resources/spec-tests/async/trap-if-block-and-sync.wast create mode 100644 src/test/resources/spec-tests/async/trap-if-done.wast create mode 100644 src/test/resources/spec-tests/async/trap-if-sync-and-waitable-set.wast create mode 100644 src/test/resources/spec-tests/async/trap-if-transfer-in-waitable-set.wast create mode 100644 src/test/resources/spec-tests/async/trap-on-reenter.wast create mode 100644 src/test/resources/spec-tests/async/validate-no-async-abi-for-sync-type.wast create mode 100644 src/test/resources/spec-tests/async/validate-no-stream-char.wast create mode 100644 src/test/resources/spec-tests/async/wait-during-callback.wast create mode 100644 src/test/resources/spec-tests/async/zero-length.wast create mode 100644 src/test/resources/spec-tests/names/kebab.wast create mode 100644 src/test/resources/spec-tests/resources/multiple-resources.wast create mode 100644 src/test/resources/spec-tests/validation/implements.wast create mode 100644 src/test/resources/spec-tests/values/post-return.wast create mode 100644 src/test/resources/spec-tests/values/strings.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/adapt.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/alias.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/big.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/definedtypes.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/empty.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/example.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/export-ascription.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/export-introduces-alias.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/export.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/func.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/import.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/imports-exports.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/inline-exports.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/instance-type.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/instantiate.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/invalid.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/link.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/lower.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/memory64.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/module-link.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/more-flags.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/naming.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/nested-modules.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/resources.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/tags.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/types.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/very-nested.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/virtualize.wast create mode 100644 src/test/resources/spec-tests/wasm-tools/wrong-order.wast create mode 100644 src/test/resources/spec-tests/wasmtime/adapter.wast create mode 100644 src/test/resources/spec-tests/wasmtime/aliasing.wast create mode 100644 src/test/resources/spec-tests/wasmtime/fused.wast create mode 100644 src/test/resources/spec-tests/wasmtime/import.wast create mode 100644 src/test/resources/spec-tests/wasmtime/instance.wast create mode 100644 src/test/resources/spec-tests/wasmtime/linking.wast create mode 100644 src/test/resources/spec-tests/wasmtime/modules.wast create mode 100644 src/test/resources/spec-tests/wasmtime/nested.wast create mode 100644 src/test/resources/spec-tests/wasmtime/resources.wast create mode 100644 src/test/resources/spec-tests/wasmtime/restrictions.wast create mode 100644 src/test/resources/spec-tests/wasmtime/simple.wast create mode 100644 src/test/resources/spec-tests/wasmtime/strings.wast create mode 100644 src/test/resources/spec-tests/wasmtime/tags.wast create mode 100644 src/test/resources/spec-tests/wasmtime/types.wast create mode 100644 wasm-tools/pom.xml rename {parser => wasm-tools}/src/main/java/run/endive/cm/tools/ComponentValidate.java (100%) rename {parser => wasm-tools}/src/main/java/run/endive/cm/tools/ComponentValidateException.java (100%) diff --git a/Readme.md b/Readme.md index 691e986..cd558a5 100644 --- a/Readme.md +++ b/Readme.md @@ -38,6 +38,9 @@ The long-term goal is to bring full Component Model support to Endive: ## Current Status +Initial work is in progress on the component type model (`types` module), binary parser (`parser` module), and +supporting infrastructure including initial `wasm-tools component` command support (`wasm-tools` module). + The repository includes a `wit-parser` module that wraps the [wasm-tools](https://github.com/bytecodealliance/wasm-tools) `component wit` command, using the same pattern as the @@ -65,6 +68,15 @@ mvn -Dquickly Then build endive-cm: +The tests of the `parser` module rely upon downloading a local copy of the .wast tests from the Component Model spec +repository. A shell script is provided that fetches the most recent copy of the .wast tests. To download (and update) +the .wast tests: +```shell +cd endive-cm +./parser/update-spec-tests.sh +``` + +Once the .wast tests have been downloaded, build endive-cm: ```sh cd endive-cm mvn clean install diff --git a/docs/phases/00-type-model.md b/docs/phases/00-type-model.md index 4fcad90..c47a2bb 100644 --- a/docs/phases/00-type-model.md +++ b/docs/phases/00-type-model.md @@ -1,6 +1,6 @@ # Phase 0: Type Model Foundation -**Status**: Not started +**Status**: In progress ## Goal diff --git a/docs/phases/01-binary-parser.md b/docs/phases/01-binary-parser.md index b652405..28084a3 100644 --- a/docs/phases/01-binary-parser.md +++ b/docs/phases/01-binary-parser.md @@ -1,6 +1,6 @@ # Phase 1: Binary Parser -**Status**: Not started +**Status**: In progress **Depends on**: Phase 0 (Type Model) ## Goal @@ -81,6 +81,9 @@ and immutable fields for all sections. ## Testing +- **Component Model spec tests**: sync .wast tests from the [Component Model spec tests](https://github.com/WebAssembly/component-model/tree/main/test) + and use `wasm-tools json-from-wast` to extract and execute tests, parse with `ComponentParser`, and verify the .wast + assertions - **Round-trip with wasm-tools**: produce component binaries via `wasm-tools component new`, parse with `ComponentParser`, verify structure - **Error paths**: truncated input, wrong magic, wrong layer, malformed diff --git a/docs/phases/02-wasm-tools.md b/docs/phases/02-wasm-tools.md index 4ff8232..bb1019c 100644 --- a/docs/phases/02-wasm-tools.md +++ b/docs/phases/02-wasm-tools.md @@ -1,6 +1,6 @@ # Phase 2: wasm-tools Integration (Component Commands) -**Status**: Not started +**Status**: In progress **Depends on**: None (independent, but Phase 1 testing benefits from it) ## Goal diff --git a/parser/pom.xml b/parser/pom.xml index 3941a7e..cce28c4 100644 --- a/parser/pom.xml +++ b/parser/pom.xml @@ -42,14 +42,8 @@ types - org.junit.jupiter - junit-jupiter-api - test - - - org.junit.jupiter - junit-jupiter-params - test + run.endive.cm + wasm-tools com.fasterxml.jackson.core @@ -59,7 +53,16 @@ org.assertj assertj-core - 3.27.7 + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-params test diff --git a/parser/src/main/java/run/endive/cm/parser/ComponentParser.java b/parser/src/main/java/run/endive/cm/parser/ComponentParser.java index 7f66bbc..b877fc2 100644 --- a/parser/src/main/java/run/endive/cm/parser/ComponentParser.java +++ b/parser/src/main/java/run/endive/cm/parser/ComponentParser.java @@ -3,18 +3,28 @@ import static java.util.Objects.requireNonNull; import static run.endive.cm.parser.CoreParser.parseCustomSection; import static run.endive.cm.parser.CoreParser.parseRecType; -import static run.endive.wasm.Encoding.*; +import static run.endive.wasm.Encoding.readVarUInt32; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; -import java.util.Objects; import java.util.function.Supplier; - import run.endive.cm.tools.ComponentValidate; -import run.endive.cm.types.*; +import run.endive.cm.types.CoreAlias; +import run.endive.cm.types.CoreExportDecl; +import run.endive.cm.types.CoreImportDecl; +import run.endive.cm.types.CoreOuterAliasTarget; +import run.endive.cm.types.CoreSort; +import run.endive.cm.types.CoreType; +import run.endive.cm.types.CoreTypeSection; +import run.endive.cm.types.CustomSection; +import run.endive.cm.types.ModuleDecl; +import run.endive.cm.types.ModuleType; +import run.endive.cm.types.Section; +import run.endive.cm.types.SectionId; +import run.endive.cm.types.WasmComponent; import run.endive.wasm.MalformedException; import run.endive.wasm.io.InputStreams; @@ -50,8 +60,7 @@ public ComponentParser build() { } private static void onSection(WasmComponent.Builder module, Section s) { - switch(s.sectionId()) - { + switch (s.sectionId()) { case SectionId.CUSTOM: var coreCustomSection = (CustomSection) s; module.addCoreCustomSection(coreCustomSection); @@ -61,8 +70,7 @@ private static void onSection(WasmComponent.Builder module, Section s) { module.addCoreTypeSection(coreTypeSection); break; default: - throw new MalformedException( - "unsupported section id " + s.sectionId()); + throw new MalformedException("unsupported section id " + s.sectionId()); } } @@ -134,8 +142,10 @@ private void parse(InputStream in, ComponentParserListener listener) { switch (sectionId) { case SectionId.CUSTOM: { - var customSection = parseCustomSection(sectionByteBuffer, sectionSize, true); - var coreCustomSection = CustomSection.builder().withCustomSection(customSection).build(); + var customSection = + parseCustomSection(sectionByteBuffer, sectionSize, true); + var coreCustomSection = + CustomSection.builder().withCustomSection(customSection).build(); listener.onSection(coreCustomSection); break; } @@ -225,13 +235,15 @@ private static CoreTypeSection parseCoreTypeSection(ByteBuffer buffer) { private static CoreType parseCoreType(ByteBuffer buffer) { var typeBuilder = CoreType.builder(); var opcode = peekByte(buffer); - switch(opcode) { + switch (opcode) { case 0x50: buffer.position(buffer.position() + 1); typeBuilder.withModuleType(parseModuleType(buffer)); break; case 0x00: buffer.position(buffer.position() + 1); + typeBuilder.withRecType(parseRecType(buffer)); + break; default: typeBuilder.withRecType(parseRecType(buffer)); } @@ -284,10 +296,11 @@ private static CoreAlias parseCoreAlias(ByteBuffer buffer) { var typeIndex = readVarUInt32(buffer); var sortIndex = readVarUInt32(buffer); builder.withSort(sort); - builder.withOuterTarget(CoreOuterAliasTarget.builder() - .withTypeIndex(typeIndex) - .withSortIndex(sortIndex) - .build()); + builder.withOuterTarget( + CoreOuterAliasTarget.builder() + .withTypeIndex(typeIndex) + .withSortIndex(sortIndex) + .build()); return builder.build(); } diff --git a/parser/src/main/java/run/endive/cm/parser/CoreParser.java b/parser/src/main/java/run/endive/cm/parser/CoreParser.java index 127dece..80516a0 100644 --- a/parser/src/main/java/run/endive/cm/parser/CoreParser.java +++ b/parser/src/main/java/run/endive/cm/parser/CoreParser.java @@ -1,23 +1,33 @@ package run.endive.cm.parser; -import run.endive.wasm.MalformedException; -import run.endive.wasm.types.*; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; - import static run.endive.cm.parser.ComponentParser.readByte; import static run.endive.cm.parser.ComponentParser.readBytes; import static run.endive.wasm.Encoding.readName; import static run.endive.wasm.Encoding.readVarSInt32; import static run.endive.wasm.Encoding.readVarUInt32; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import run.endive.wasm.MalformedException; +import run.endive.wasm.types.ArrayType; +import run.endive.wasm.types.CompType; +import run.endive.wasm.types.CustomSection; +import run.endive.wasm.types.FieldType; +import run.endive.wasm.types.FunctionType; +import run.endive.wasm.types.MutabilityType; +import run.endive.wasm.types.PackedType; +import run.endive.wasm.types.RecType; +import run.endive.wasm.types.StorageType; +import run.endive.wasm.types.StructType; +import run.endive.wasm.types.SubType; +import run.endive.wasm.types.UnknownCustomSection; +import run.endive.wasm.types.ValType; + public final class CoreParser { private CoreParser() {} - static CustomSection parseCustomSection( ByteBuffer buffer, long sectionSize, boolean checkMalformed) { var sectionPos = buffer.position(); @@ -148,8 +158,7 @@ static RecType parseRecType(ByteBuffer buffer) { } } - static ValType.Builder readValueTypeBuilderFromOpCode( - ByteBuffer buffer, int valueTypeOpCode) { + static ValType.Builder readValueTypeBuilderFromOpCode(ByteBuffer buffer, int valueTypeOpCode) { var builder = ValType.builder().withOpcode(valueTypeOpCode); if (valueTypeOpCode == ValType.ID.Ref || valueTypeOpCode == ValType.ID.RefNull) { return builder.withTypeIdx((int) readVarSInt32(buffer)); diff --git a/parser/src/test/java/run/endive/cm/parser/ComponentParserTests.java b/parser/src/test/java/run/endive/cm/parser/ComponentParserTests.java index 36d6e1f..bd4fe7b 100644 --- a/parser/src/test/java/run/endive/cm/parser/ComponentParserTests.java +++ b/parser/src/test/java/run/endive/cm/parser/ComponentParserTests.java @@ -7,11 +7,17 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Map; - import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import run.endive.cm.types.*; +import run.endive.cm.types.CoreAlias; +import run.endive.cm.types.CoreOuterAliasTarget; +import run.endive.cm.types.CoreSort; +import run.endive.cm.types.CoreType; +import run.endive.cm.types.CoreTypeSection; +import run.endive.cm.types.ModuleDecl; +import run.endive.cm.types.ModuleType; +import run.endive.cm.types.WasmComponent; import run.endive.wasm.types.CompType; import run.endive.wasm.types.FunctionType; import run.endive.wasm.types.RecType; @@ -22,19 +28,23 @@ public class ComponentParserTests { static java.util.stream.Stream testLocations() { return java.util.stream.Stream.of( - // Arguments.arguments("./wasmtime/types.wast", new int[] {145}), - Arguments.arguments("./wasm-tools/types.wast", WasmToolsTypesAssertions.expectedComponents, new int[0])); + Arguments.arguments( + "./wasm-tools/types.wast", + WasmToolsTypesAssertions.expectedComponents, + new int[] {29, 30, 31, 32, 33, 34, 40})); } @ParameterizedTest @MethodSource("testLocations") - void allSpecTests(String testLocation, Map expectedComponents, int[] skipLines) throws IOException { + void allSpecTests( + String testLocation, Map expectedComponents, int[] skipCases) + throws IOException { var testDir = Path.of("src/test/resources/spec-tests"); var testFile = testDir.resolve(testLocation); try (var wast = Files.newInputStream(testFile); var wastTests = JsonFromWast.exec(wast)) { - wastTests.runTests(expectedComponents, skipLines); - } catch (Exception e) { + wastTests.runTests(expectedComponents, true, skipCases); + } catch (Throwable e) { if (e instanceof WastTests.CommandException) { var ce = (WastTests.CommandException) e; var outFile = testDir.resolve("./failed.wasm"); @@ -46,25 +56,41 @@ void allSpecTests(String testLocation, Map expectedCompo private static final class WasmToolsTypesAssertions { - private final static Map expectedComponents = Map.of(17, case17()); + private static final Map expectedComponents = Map.of(17, case17()); private static WasmComponent case17() { - var funcType = FunctionType.of(new ArrayList<>(), new ArrayList<>()); - var compType = CompType.builder().withFuncType(funcType).build(); - var subType = SubType.builder().withTypeIdx(new int[] {}).withFinal(true).withCompType(compType).build(); + var compType = + CompType.builder() + .withFuncType(FunctionType.of(new ArrayList<>(), new ArrayList<>())) + .build(); + var subType = + SubType.builder() + .withTypeIdx(new int[] {}) + .withFinal(true) + .withCompType(compType) + .build(); var recType = RecType.builder().withSubTypes(new SubType[] {subType}).build(); var coreFuncType = CoreType.builder().withRecType(recType).build(); - var alias = CoreAlias.builder().withSort(CoreSort.TYPE). - withOuterTarget(CoreOuterAliasTarget.builder() - .withTypeIndex(1) - .withSortIndex(0) - .build()).build(); + var alias = + CoreAlias.builder() + .withSort(CoreSort.TYPE) + .withOuterTarget( + CoreOuterAliasTarget.builder() + .withTypeIndex(1) + .withSortIndex(0) + .build()) + .build(); + var moduleDecl = ModuleDecl.builder().withAlias(alias).build(); var moduleType = ModuleType.builder().addModuleDecl(moduleDecl).build(); var coreModuleType = CoreType.builder().withModuleType(moduleType).build(); - var coreTypeSection = CoreTypeSection.builder().addCoreType(coreFuncType).addCoreType(coreModuleType).build(); + var coreTypeSection = + CoreTypeSection.builder() + .addCoreType(coreFuncType) + .addCoreType(coreModuleType) + .build(); return WasmComponent.builder().addCoreTypeSection(coreTypeSection).build(); } } diff --git a/parser/src/test/java/run/endive/cm/parser/JsonFromWast.java b/parser/src/test/java/run/endive/cm/parser/JsonFromWast.java index 4c49ac2..5611328 100644 --- a/parser/src/test/java/run/endive/cm/parser/JsonFromWast.java +++ b/parser/src/test/java/run/endive/cm/parser/JsonFromWast.java @@ -2,13 +2,6 @@ import io.roastedroot.zerofs.Configuration; import io.roastedroot.zerofs.ZeroFs; -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystem; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - import run.endive.cm.tools.ComponentValidateException; import run.endive.log.Logger; import run.endive.log.SystemLogger; @@ -21,6 +14,17 @@ import run.endive.wasi.WasiPreview1; import run.endive.wasm.WasmModule; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + public final class JsonFromWast { private JsonFromWast() {} diff --git a/parser/src/test/java/run/endive/cm/parser/WastTests.java b/parser/src/test/java/run/endive/cm/parser/WastTests.java index f5a31d0..6f25994 100644 --- a/parser/src/test/java/run/endive/cm/parser/WastTests.java +++ b/parser/src/test/java/run/endive/cm/parser/WastTests.java @@ -1,5 +1,7 @@ package run.endive.cm.parser; +import static org.assertj.core.api.Assertions.assertThat; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; @@ -14,12 +16,9 @@ import java.util.List; import java.util.Map; import java.util.stream.IntStream; - import run.endive.cm.tools.ComponentValidateException; import run.endive.cm.types.WasmComponent; -import static org.assertj.core.api.Assertions.assertThat; - public final class WastTests implements AutoCloseable { private final WastTestFile wastTestFile; @@ -36,10 +35,11 @@ public WastTests(String wastJson, FileSystem wastFS) { } } - public void runTests(Map expectedComponents, int[] skipLines) { + public void runTests( + Map expectedComponents, boolean parseOnly, int[] skipCases) { var workingDir = wastFS.getPath("/work"); for (var command : wastTestFile.commands()) { - command.execute(workingDir, expectedComponents, skipLines); + command.execute(workingDir, expectedComponents, parseOnly, skipCases); } } @@ -72,11 +72,16 @@ List commands() { @JsonSubTypes({ @JsonSubTypes.Type(value = Module.class, name = "module"), @JsonSubTypes.Type(value = AssertMalformed.class, name = "assert_malformed"), - @JsonSubTypes.Type(value = AssertInvalid.class, name = "assert_invalid"), + @JsonSubTypes.Type(value = AssertInvalid.class, name = "assert_invalid") }) interface Command { - void execute(Path location, Map expectedComponents, int... skipLines) throws CommandException; + void execute( + Path location, + Map expectedComponents, + boolean parseOnly, + int... skipCases) + throws CommandException; default WasmComponent parseComponent(Path location, String filename) throws CommandException { @@ -160,17 +165,24 @@ String text() { } @Override - public void execute(Path location, Map expectedComponents, int... skipLines) throws CommandException { - if (skipLines.length > 0) { - if (IntStream.of(skipLines).anyMatch(i -> i == line)) { + public void execute( + Path location, + Map expectedComponents, + boolean parseOnly, + int... skipCases) + throws CommandException { + var testId = Integer.parseInt(filename.split("\\.")[1]); + if (skipCases.length > 0) { + if (IntStream.of(skipCases).anyMatch(i -> i == testId)) { return; } } try { parseComponent(location, filename); - } catch (Exception e) { + } catch (Throwable e) { if (!(e instanceof ComponentValidateException)) { - throw new CommandException(location.resolve(filename), + throw new CommandException( + location.resolve(filename), String.format( "Expected validation of %s to fail at line %d due to '%s' but" + " got unexpected exception of type %s", @@ -179,7 +191,8 @@ public void execute(Path location, Map expectedComponent } return; } - throw new CommandException(location.resolve(filename), + throw new CommandException( + location.resolve(filename), String.format( "\"Expected validation of %s to fail at line %d due to '%s' ", filename, line, text)); @@ -220,17 +233,24 @@ String text() { } @Override - public void execute(Path location, Map expectedComponents, int... skipLines) throws CommandException { - if (skipLines.length > 0) { - if (IntStream.of(skipLines).anyMatch(i -> i == line)) { + public void execute( + Path location, + Map expectedComponents, + boolean parseOnly, + int... skipCases) + throws CommandException { + var testId = Integer.parseInt(filename.split("\\.")[1]); + if (skipCases.length > 0) { + if (IntStream.of(skipCases).anyMatch(i -> i == testId)) { return; } } try { parseComponent(location, filename); - } catch (Exception e) { + } catch (Throwable e) { if (!(e instanceof ComponentValidateException)) { - throw new CommandException(location.resolve(filename), + throw new CommandException( + location.resolve(filename), String.format( "Expected validation of %s to fail at line %d due to '%s' but" + " got unexpected exception of type %s", @@ -239,7 +259,8 @@ public void execute(Path location, Map expectedComponent } return; } - throw new CommandException(location.resolve(filename), + throw new CommandException( + location.resolve(filename), String.format( "\"Expected validation of %s to fail at line %d due to '%s' ", filename, line, text)); @@ -353,23 +374,35 @@ String moduleType() { } @Override - public void execute(Path location, Map expectedComponents, int... skipLines) throws CommandException { - if (skipLines.length > 0) { - if (IntStream.of(skipLines).anyMatch(i -> i == line)) { + public void execute( + Path location, + Map expectedComponents, + boolean parseOnly, + int... skipCases) + throws CommandException { + var testId = Integer.parseInt(filename.split("\\.")[1]); + if (skipCases.length > 0) { + if (IntStream.of(skipCases).anyMatch(i -> i == testId)) { return; } } try { WasmComponent actualComponent = parseComponent(location, filename); - var testId = Integer.parseInt(filename.split("\\.")[1]); if (expectedComponents.containsKey(testId)) { WasmComponent expectedComponent = expectedComponents.get(testId); - assertThat(actualComponent).usingRecursiveComparison() + assertThat(actualComponent) + .usingRecursiveComparison() .ignoringFields("customSections") .isEqualTo(expectedComponent); } - } catch (Exception e) { - throw new CommandException(location.resolve(filename), + if (!parseOnly) { + // TODO Include component instantiation here once implemented + throw new UnsupportedOperationException( + "Component instantiation not yet implemented"); + } + } catch (Throwable e) { + throw new CommandException( + location.resolve(filename), String.format( "Failed to load module %s due to error at line %d", filename, line), e); diff --git a/pom.xml b/pom.xml index 22de6f5..dd41c87 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,7 @@ parser types + wasm-tools wit-parser @@ -39,16 +40,12 @@ 999-SNAPSHOT 0.1.0 2.18.3 + 3.27.7 5.14.4 - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - io.roastedroot zerofs @@ -89,6 +86,23 @@ types ${project.version} + + run.endive.cm + wasm-tools + ${project.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + test + + + org.assertj + assertj-core + ${assertj.version} + test + org.junit.jupiter junit-jupiter-api diff --git a/src/test/resources/spec-tests/async/async-calls-sync.wast b/src/test/resources/spec-tests/async/async-calls-sync.wast new file mode 100644 index 0000000..5172bb4 --- /dev/null +++ b/src/test/resources/spec-tests/async/async-calls-sync.wast @@ -0,0 +1,251 @@ +;; This test contains 3 components, $AsyncInner, $SyncMiddle and $AsyncOuter, +;; where there are two instances of $SyncMiddle that import a single instance +;; of $AsyncInner, and $AsyncOuter imports all 3 preceding instances. +;; +;; $AsyncOuter.run asynchronously calls $SyncMiddle.sync-func twice concurrently +;; in each instance (4 total calls), hitting the synchronous backpressure case +;; in 2 of the 4 calls. +;; +;; $SyncMiddle.sync-func makes a blocking call to $AsyncInner.blocking-call +;; which is used to emulate a host call that blocks until $AsyncOuter.run +;; calls $AsyncInner.unblock to unblock all the 'blocking-call' calls. +(component + (component $AsyncInner + (core module $CoreAsyncInner + (import "" "context.set" (func $context.set (param i32))) + (import "" "context.get" (func $context.get (result i32))) + (import "" "task.return0" (func $task.return0)) + (import "" "task.return1" (func $task.return1 (param i32))) + + (memory 1) + (global $blocked (mut i32) (i32.const 1)) + (global $counter (mut i32) (i32.const 2)) + + ;; 'blocking-call' cooperatively "spin-waits" until $blocked is 0. + (func $blocking-call (export "blocking-call") (result i32) + (call $context.set (global.get $counter)) + (global.set $counter (i32.add (i32.const 1) (global.get $counter))) + (i32.const 1 (; YIELD ;)) + ) + (func $blocking-call-cb (export "blocking-call-cb") (param i32 i32 i32) (result i32) + (if (i32.eqz (global.get $blocked)) (then + (call $task.return1 (call $context.get)) + (return (i32.const 0 (; EXIT ;))) + )) + (i32.const 1 (; YIELD ;)) + ) + (func $unblock (export "unblock") (result i32) + (global.set $blocked (i32.const 0)) + (call $task.return0) + (i32.const 0 (; EXIT ;)) + ) + (func $unblock-cb (export "unblock-cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (canon task.return (core func $task.return0)) + (canon task.return (result u32) (core func $task.return1)) + (canon context.set i32 0 (core func $context.set)) + (canon context.get i32 0 (core func $context.get)) + (core instance $core_async_inner (instantiate $CoreAsyncInner (with "" (instance + (export "task.return0" (func $task.return0)) + (export "task.return1" (func $task.return1)) + (export "context.set" (func $context.set)) + (export "context.get" (func $context.get)) + )))) + (func (export "blocking-call") async (result u32) (canon lift + (core func $core_async_inner "blocking-call") + async (callback (func $core_async_inner "blocking-call-cb")) + )) + (func (export "unblock") async (canon lift + (core func $core_async_inner "unblock") + async (callback (func $core_async_inner "unblock-cb")) + )) + ) + + (component $SyncMiddle + (import "blocking-call" (func $blocking-call async (result u32))) + (core module $CoreSyncMiddle + (import "" "blocking-call" (func $blocking-call (result i32))) + (func $sync-func (export "sync-func") (result i32) + (call $blocking-call) + ) + ) + (canon lower (func $blocking-call) (core func $blocking-call')) + (core instance $core_sync_middle (instantiate $CoreSyncMiddle (with "" (instance + (export "blocking-call" (func $blocking-call')) + )))) + (func (export "sync-func") async (result u32) (canon lift + (core func $core_sync_middle "sync-func") + )) + ) + + (component $AsyncMiddle + (import "blocking-call" (func $blocking-call async (result u32))) + (core module $CoreSyncMiddle + (import "" "task.return" (func $task.return (param i32))) + (import "" "blocking-call" (func $blocking-call (result i32))) + (func $sync-func (export "sync-func") (result i32) + (call $task.return (call $blocking-call)) + (i32.const 0 (; EXIT ;)) + ) + (func $sync-func-cb (export "sync-func-cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (canon task.return (result u32) (core func $task.return)) + (canon lower (func $blocking-call) (core func $blocking-call')) + (core instance $core_sync_middle (instantiate $CoreSyncMiddle (with "" (instance + (export "task.return" (func $task.return)) + (export "blocking-call" (func $blocking-call')) + )))) + (func (export "sync-func") async (result u32) (canon lift + (core func $core_sync_middle "sync-func") + async (callback (func $core_sync_middle "sync-func-cb")) + )) + ) + + (component $AsyncOuter + (import "unblock" (func $unblock async)) + (import "sync-func1" (func $sync-func1 async (result u32))) + (import "sync-func2" (func $sync-func2 async (result u32))) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CoreAsyncOuter + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "subtask.drop" (func $subtask.drop (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "unblock" (func $unblock)) + (import "" "sync-func1" (func $sync-func1 (param i32) (result i32))) + (import "" "sync-func2" (func $sync-func2 (param i32) (result i32))) + + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + ;; set $remain to the number of tasks to wait to complete + (global $remain (mut i32) (i32.const 4)) + + (func $run (export "run") (result i32) + (local $ret i32) + + ;; call 'sync-func1' and 'sync-func2' asynchronously, both of which will block + ;; (on $AsyncInner.blocking-call). because 'sync-func1/2' are in different instances, + ;; both calls will reach the STARTED state. + (local.set $ret (call $sync-func1 (i32.const 8))) + (if (i32.ne (i32.const 0x21 (; STARTED=1 | (subtask=2 << 4) ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (i32.const 2) (global.get $ws)) + (local.set $ret (call $sync-func2 (i32.const 12))) + (if (i32.ne (i32.const 0x31 (; STARTED=1 | (subtask=3 << 4) ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (i32.const 3) (global.get $ws)) + + ;; now start another pair of 'sync-func1/2' calls, both of which should see auto + ;; backpressure and get stuck in the STARTING state. + (local.set $ret (call $sync-func1 (i32.const 16))) + (if (i32.ne (i32.const 0x40 (; STARTING=0 | (subtask=4 << 4) ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (i32.const 4) (global.get $ws)) + (local.set $ret (call $sync-func2 (i32.const 20))) + (if (i32.ne (i32.const 0x50 (; STARTING=0 | (subtask=5 << 4) ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (i32.const 5) (global.get $ws)) + + ;; unblock all the tasks and start waiting to complete + (call $unblock) + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) + ) + (func $run-cb (export "run-cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + (local $ret i32) + + ;; confirm we only receive SUBTASK events. + (if (i32.ne (local.get $event_code) (i32.const 1 (; SUBTASK ;))) + (then unreachable)) + + ;; if we receive a SUBTASK STARTED event, it should only be for the 3rd or + ;; 4th subtask (at indices 4/5, resp), so keep waiting for completion + (if (i32.eq (local.get $payload) (i32.const 1 (; STARTED ;))) (then + (if (i32.and + (i32.ne (local.get $index) (i32.const 4)) + (i32.ne (local.get $index) (i32.const 5))) + (then unreachable)) + (return (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4)))) + )) + + ;; when we receive a SUBTASK RETURNED event, check the return value is equal to the + ;; subtask index (which we've ensured by having $AsyncInner.$counter start at 2, the + ;; first subtask index. The address of the return buffer is the index*4. + (if (i32.ne (local.get $payload) (i32.const 2 (; RETURNED ;))) + (then unreachable)) + (if (i32.ne (local.get $index) (i32.load (i32.mul (local.get $index) (i32.const 4)))) + (then unreachable)) + + ;; decrement $remain and exit if 0 + (call $subtask.drop (local.get $index)) + (global.set $remain (i32.sub (global.get $remain) (i32.const 1))) + (if (i32.gt_u (global.get $remain) (i32.const 0)) (then + (return (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4)))) + )) + (call $task.return (i32.const 42)) + (i32.const 0 (; EXIT ;)) + ) + ) + (canon task.return (result u32) (core func $task.return)) + (canon subtask.drop (core func $subtask.drop)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon lower (func $unblock) (core func $unblock)) + (canon lower (func $sync-func1) async (memory $memory "mem") (core func $sync-func1')) + (canon lower (func $sync-func2) async (memory $memory "mem") (core func $sync-func2')) + (core instance $em (instantiate $CoreAsyncOuter (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "subtask.drop" (func $subtask.drop)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "unblock" (func $unblock)) + (export "sync-func1" (func $sync-func1')) + (export "sync-func2" (func $sync-func2')) + )))) + (func (export "run") async (result u32) (canon lift + (core func $em "run") + async (callback (func $em "run-cb")) + )) + ) + + ;; run1 uses $SyncMiddle + (instance $async_inner1 (instantiate $AsyncInner)) + (instance $sync_middle11 (instantiate $SyncMiddle + (with "blocking-call" (func $async_inner1 "blocking-call")) + )) + (instance $sync_middle12 (instantiate $SyncMiddle + (with "blocking-call" (func $async_inner1 "blocking-call")) + )) + (instance $async_outer1 (instantiate $AsyncOuter + (with "unblock" (func $async_inner1 "unblock")) + (with "sync-func1" (func $sync_middle11 "sync-func")) + (with "sync-func2" (func $sync_middle12 "sync-func")) + )) + (func (export "run1") (alias export $async_outer1 "run")) + + ;; run2 uses $AsyncMiddle + (instance $async_inner2 (instantiate $AsyncInner)) + (instance $sync_middle21 (instantiate $SyncMiddle + (with "blocking-call" (func $async_inner2 "blocking-call")) + )) + (instance $sync_middle22 (instantiate $AsyncMiddle + (with "blocking-call" (func $async_inner2 "blocking-call")) + )) + (instance $async_outer2 (instantiate $AsyncOuter + (with "unblock" (func $async_inner2 "unblock")) + (with "sync-func1" (func $sync_middle21 "sync-func")) + (with "sync-func2" (func $sync_middle22 "sync-func")) + )) + (func (export "run2") (alias export $async_outer2 "run")) +) +(assert_return (invoke "run1") (u32.const 42)) +(assert_return (invoke "run2") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/cancel-stream.wast b/src/test/resources/spec-tests/async/cancel-stream.wast new file mode 100644 index 0000000..336b5ac --- /dev/null +++ b/src/test/resources/spec-tests/async/cancel-stream.wast @@ -0,0 +1,202 @@ +;; This test contains two components $C and $D that test cancelling reads +;; and writes in the presence and absence of partial reads/writes. +;; +;; $C exports a function 'start-stream' that creates and holds onto a writable +;; stream in the global $sw as well as various operations that operate on $sw. +;; $D calls $C.start-stream to get the readable end and then drives the test. +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + (global $sw (mut i32) (i32.const 0)) + + (func $start-stream (export "start-stream") (result i32) + ;; create a new stream, return the readable end to the caller + (local $ret64 i64) + (local.set $ret64 (call $stream.new)) + (global.set $sw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (i32.wrap_i64 (local.get $ret64)) + ) + + (func $write4 (export "write4") + ;; write 6 bytes into the stream, expecting to rendezvous with a stream.read + (local $ret i32) + (i32.store (i32.const 8) (i32.const 0xabcd)) + (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 4))) + (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + ) + + (func $write4-and-drop (export "write4-and-drop") + (call $write4) + (call $stream.drop-writable (global.get $sw)) + ) + + (func $start-blocking-write (export "start-blocking-write") + (local $ret i32) + + ;; prepare the write buffer + (i64.store (i32.const 8) (i64.const 0x123456789abcdef)) + + ;; start one blocking write and immediately cancel it + (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 8))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $stream.cancel-write (global.get $sw))) + (if (i32.ne (i32.const 0x2 (; CANCELLED ;)) (local.get $ret)) + (then unreachable)) + + ;; start a second blockign write and leave it pending + (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 8))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + ) + + (func $cancel-after-read4 (export "cancel-after-read4") + (local $ret i32) + (local.set $ret (call $stream.cancel-write (global.get $sw))) + (if (i32.ne (i32.const 0x42 (; CANCELLED=2 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + ) + ) + (type $ST (stream u8)) + (canon task.return (result u32) (core func $task.return)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.cancel-write $ST (core func $stream.cancel-write)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "stream.new" (func $stream.new)) + (export "stream.write" (func $stream.write)) + (export "stream.cancel-write" (func $stream.cancel-write)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (func (export "start-stream") async (result (stream u8)) (canon lift (core func $cm "start-stream"))) + (func (export "write4") async (canon lift (core func $cm "write4"))) + (func (export "write4-and-drop") async (canon lift (core func $cm "write4-and-drop"))) + (func (export "start-blocking-write") async (canon lift (core func $cm "start-blocking-write"))) + (func (export "cancel-after-read4") async (canon lift (core func $cm "cancel-after-read4"))) + ) + + (component $D + (import "c" (instance $c + (export "start-stream" (func async (result (stream u8)))) + (export "write4" (func async)) + (export "write4-and-drop" (func async)) + (export "start-blocking-write" (func async)) + (export "cancel-after-read4" (func async)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.cancel-read" (func $stream.cancel-read (param i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "start-stream" (func $start-stream (result i32))) + (import "" "write4" (func $write4)) + (import "" "write4-and-drop" (func $write4-and-drop)) + (import "" "start-blocking-write" (func $start-blocking-write)) + (import "" "cancel-after-read4" (func $cancel-after-read4)) + + (func $run (export "run") (result i32) + (local $ret i32) + (local $sr i32) + + ;; call 'start-stream' to get the stream we'll be working with + (local.set $sr (call $start-stream)) + (if (i32.ne (i32.const 1) (local.get $sr)) + (then unreachable)) + + ;; start read that will block + (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) + (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) + (then unreachable)) + + ;; cancelling it will finish without anything having been written + (local.set $ret (call $stream.cancel-read (local.get $sr))) + (if (i32.ne (i32.const 0x2 (; CANCELLED ;)) (local.get $ret)) + (then unreachable)) + + ;; read, block, call $C to write 4 bytes into the buffer, + ;; then cancel, which should show "4+cancelled" + (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) + (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) + (then unreachable)) + (call $write4) + (local.set $ret (call $stream.cancel-read (local.get $sr))) + (if (i32.ne (i32.const 0x42 (; CANCELLED=2 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0xabcd) (i32.load (i32.const 8))) + (then unreachable)) + + ;; read, block, call $C to write 4 bytes into the buffer and drop, then cancel + (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) + (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) + (then unreachable)) + (call $write4-and-drop) + (local.set $ret (call $stream.cancel-read (local.get $sr))) + (if (i32.ne (i32.const 0x41 (; DROPPED=1 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0xabcd) (i32.load (i32.const 8))) + (then unreachable)) + (call $stream.drop-readable (local.get $sr)) + + ;; get a new $sr + (local.set $sr (call $start-stream)) + (if (i32.ne (i32.const 1) (local.get $sr)) + (then unreachable)) + + ;; start outstanding write in $C, read 4 of it, then call back into $C + ;; which will cancel and see 4 written. + (call $start-blocking-write) + (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 4))) + (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0x89abcdef) (i32.load (i32.const 8))) + (then unreachable)) + (call $cancel-after-read4) + + ;; return 42 to the top-level assert_return + (i32.const 42) + ) + ) + (type $ST (stream u8)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.cancel-read $ST (core func $stream.cancel-read)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon lower (func $c "start-stream") (core func $start-stream')) + (canon lower (func $c "write4") (core func $write4')) + (canon lower (func $c "write4-and-drop") (core func $write4-and-drop')) + (canon lower (func $c "start-blocking-write") (core func $start-blocking-write')) + (canon lower (func $c "cancel-after-read4") (core func $cancel-after-read4')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "stream.read" (func $stream.read)) + (export "stream.cancel-read" (func $stream.cancel-read)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "start-stream" (func $start-stream')) + (export "write4" (func $write4')) + (export "write4-and-drop" (func $write4-and-drop')) + (export "start-blocking-write" (func $start-blocking-write')) + (export "cancel-after-read4" (func $cancel-after-read4')) + )))) + (func (export "run") async (result u32) (canon lift (core func $dm "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "run") (alias export $d "run")) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/cancel-subtask.wast b/src/test/resources/spec-tests/async/cancel-subtask.wast new file mode 100644 index 0000000..57a0f33 --- /dev/null +++ b/src/test/resources/spec-tests/async/cancel-subtask.wast @@ -0,0 +1,201 @@ +;; This test contains two components $C and $D where $D imports and calls $C. +;; $D.run calls $C.f, which blocks on an empty waitable set +;; $D.run then subtask.cancels $C.f, which resumes $C.f which promptly resolves +;; without returning a value. +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.cancel" (func $task.cancel)) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + + ;; $ws is waited on by 'f' + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + (func $f (export "f") (result i32) + ;; wait on $ws which is currently empty, expected to get cancelled + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) + ) + (func $f_cb (export "f_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + ;; confirm that we've received a cancellation request + (if (i32.ne (local.get $event_code) (i32.const 6 (; TASK_CANCELLED ;))) + (then unreachable)) + (if (i32.ne (local.get $index) (i32.const 0)) + (then unreachable)) + (if (i32.ne (local.get $payload) (i32.const 0)) + (then unreachable)) + + ;; finish without returning a value + (call $task.cancel) + (i32.const 0 (; EXIT ;)) + ) + + (func $g (export "g") (param $futr i32) (result i32) + (local $ret i32) + (local $event_code i32) + + ;; perform a future.read which will block, waiting for the caller to write + (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (local.get $futr) (global.get $ws)) + + ;; wait on $ws synchronously, don't expect cancellation + (local.set $event_code (call $waitable-set.wait (global.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) + (then unreachable)) + + ;; finish returning a value + (i32.const 42) + ) + ) + (type $FT (future)) + (canon task.cancel (core func $task.cancel)) + (canon future.read $FT async (memory $memory "mem") (core func $future.read)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.cancel" (func $task.cancel)) + (export "future.read" (func $future.read)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + )))) + (func (export "f") async (result u32) (canon lift + (core func $cm "f") + async (callback (func $cm "f_cb")) + )) + (func (export "g") async (param "fut" $FT) (result u32) (canon lift + (core func $cm "g") + )) + ) + + (component $D + (type $FT (future)) + (import "f" (func $f async (result u32))) + (import "g" (func $g async (param "fut" $FT) (result u32))) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) + (import "" "subtask.drop" (func $subtask.drop (param i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "f" (func $f (param i32) (result i32))) + (import "" "g" (func $g (param i32 i32) (result i32))) + + (func $run (export "run") (result i32) + (local $ret i32) (local $ret64 i64) + (local $retp i32) (local $retp1 i32) (local $retp2 i32) + (local $subtask i32) + (local $event_code i32) + (local $futr i32) (local $futw i32) + (local $ws i32) + + ;; call 'f'; it should block + (local.set $retp (i32.const 4)) + (i32.store (local.get $retp) (i32.const 0xbad0bad0)) + (local.set $ret (call $f (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; cancel 'f'; it should complete without blocking + (local.set $ret (call $subtask.cancel (local.get $subtask))) + (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (local.get $ret)) + (then unreachable)) + + ;; The $retp memory shouldn't have changed + (if (i32.ne (i32.load (local.get $retp)) (i32.const 0xbad0bad0)) + (then unreachable)) + + (call $subtask.drop (local.get $subtask)) + + ;; create future that g will wait on + (local.set $ret64 (call $future.new)) + (local.set $futr (i32.wrap_i64 (local.get $ret64))) + (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + + ;; call 'g'; it should block + (local.set $retp1 (i32.const 4)) + (local.set $retp2 (i32.const 8)) + (i32.store (local.get $retp1) (i32.const 0xbad0bad0)) + (i32.store (local.get $retp2) (i32.const 0xbad0bad0)) + (local.set $ret (call $g (local.get $futr) (local.get $retp1))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; cancel 'g'; it should block + (local.set $ret (call $subtask.cancel (local.get $subtask))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; future.write, unblocking 'g' + (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + ;; wait to see 'g' finish and check its return value + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtask) (local.get $ws)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load (local.get $retp1))) + (then unreachable)) + + ;; return to the top-level assert_return + (i32.const 42) + ) + ) + (canon subtask.cancel async (core func $subtask.cancel)) + (canon subtask.drop (core func $subtask.drop)) + (canon future.new $FT (core func $future.new)) + (canon future.write $FT async (memory $memory "mem") (core func $future.write)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon lower (func $f) async (memory $memory "mem") (core func $f')) + (canon lower (func $g) async (memory $memory "mem") (core func $g')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "subtask.cancel" (func $subtask.cancel)) + (export "subtask.drop" (func $subtask.drop)) + (export "future.new" (func $future.new)) + (export "future.write" (func $future.write)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "f" (func $f')) + (export "g" (func $g')) + )))) + (func (export "run") async (result u32) (canon lift (core func $dm "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D + (with "f" (func $c "f")) + (with "g" (func $c "g")) + )) + (func (export "run") (alias export $d "run")) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/cancellable.wast b/src/test/resources/spec-tests/async/cancellable.wast new file mode 100644 index 0000000..2c5614c --- /dev/null +++ b/src/test/resources/spec-tests/async/cancellable.wast @@ -0,0 +1,325 @@ +;; This test exercises the 'cancellable' immediate on waitable-set.wait, +;; waitable-set.poll, and thread.yield. +;; +;; Component $C exports five async callback-lifted functions that block in +;; their initial core function (the callbacks are never invoked): +;; wait-cancel: blocks on cancellable waitable-set.wait, expects TASK_CANCELLED +;; yield-cancel: yields with cancellable, caller cancels during yield +;; poll-cancel-pending: blocks on non-cancellable wait, then polls with cancellable +;; yield-cancel-pending: blocks on non-cancellable wait, then yields with cancellable +;; +;; Component $D calls each function and cancels it, verifying the cancel is +;; delivered correctly through the cancellable built-in in each case. +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.cancel" (func $task.cancel)) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait-cancellable" (func $waitable-set.wait-cancellable (param i32 i32) (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "waitable-set.poll-cancellable" (func $waitable-set.poll-cancellable (param i32 i32) (result i32))) + (import "" "thread.yield-cancellable" (func $thread.yield-cancellable (result i32))) + + ;; Test 1: direct cancel delivery through cancellable waitable-set.wait + (func $wait-cancel (export "wait-cancel") (result i32) + (local $event_code i32) + (local $ws i32) + (local.set $ws (call $waitable-set.new)) + ;; wait on empty waitable set with cancellable; blocks until cancelled + (local.set $event_code (call $waitable-set.wait-cancellable (local.get $ws) (i32.const 0))) + (if (i32.ne (local.get $event_code) (i32.const 6 (; TASK_CANCELLED ;))) + (then unreachable)) + (call $task.cancel) + (i32.const 0 (; EXIT ;)) + ) + + ;; Test 2: direct cancel delivery through cancellable thread.yield + (func $yield-cancel (export "yield-cancel") (result i32) + (local $ret i32) + ;; yield with cancellable; suspends with cancellable=true, caller cancels + (local.set $ret (call $thread.yield-cancellable)) + (if (i32.ne (i32.const 1 (; CANCELLED ;)) (local.get $ret)) + (then unreachable)) + (call $task.cancel) + (i32.const 0 (; EXIT ;)) + ) + + ;; Test 3: deferred cancel delivered through cancellable waitable-set.poll + (func $poll-cancel-pending (export "poll-cancel-pending") (param $futr i32) (result i32) + (local $ws i32) + (local $ret i32) + (local $event_code i32) + (local.set $ws (call $waitable-set.new)) + ;; read future - blocks (caller hasn't written yet) + (local.set $ret (call $future.read (local.get $futr) (i32.const 0))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (local.get $futr) (local.get $ws)) + ;; wait WITHOUT cancellable - cancel will be deferred as PENDING_CANCEL + (local.set $event_code (call $waitable-set.wait (local.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) + (then unreachable)) + ;; poll WITH cancellable - delivers the pending cancel + (local.set $event_code (call $waitable-set.poll-cancellable (local.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 6 (; TASK_CANCELLED ;)) (local.get $event_code)) + (then unreachable)) + (call $task.cancel) + (i32.const 0 (; EXIT ;)) + ) + + ;; Test 4: deferred cancel delivered through cancellable thread.yield + (func $yield-cancel-pending (export "yield-cancel-pending") (param $futr i32) (result i32) + (local $ws i32) + (local $ret i32) + (local $event_code i32) + (local.set $ws (call $waitable-set.new)) + ;; read future - blocks (caller hasn't written yet) + (local.set $ret (call $future.read (local.get $futr) (i32.const 0))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (local.get $futr) (local.get $ws)) + ;; wait WITHOUT cancellable - cancel will be deferred as PENDING_CANCEL + (local.set $event_code (call $waitable-set.wait (local.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) + (then unreachable)) + ;; yield WITH cancellable - delivers the pending cancel + (local.set $ret (call $thread.yield-cancellable)) + (if (i32.ne (i32.const 1 (; CANCELLED ;)) (local.get $ret)) + (then unreachable)) + (call $task.cancel) + (i32.const 0 (; EXIT ;)) + ) + + ;; callback that should never be called + (func (export "unreachable-cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (type $FT (future)) + (canon task.cancel (core func $task.cancel)) + (canon future.read $FT async (memory $memory "mem") (core func $future.read)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait cancellable (memory $memory "mem") (core func $waitable-set.wait-cancellable)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon waitable-set.poll cancellable (memory $memory "mem") (core func $waitable-set.poll-cancellable)) + (canon thread.yield cancellable (core func $thread.yield-cancellable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.cancel" (func $task.cancel)) + (export "future.read" (func $future.read)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait-cancellable" (func $waitable-set.wait-cancellable)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "waitable-set.poll-cancellable" (func $waitable-set.poll-cancellable)) + (export "thread.yield-cancellable" (func $thread.yield-cancellable)) + )))) + (func (export "wait-cancel") async (result u32) (canon lift + (core func $cm "wait-cancel") + async (callback (func $cm "unreachable-cb")) + )) + (func (export "yield-cancel") async (result u32) (canon lift + (core func $cm "yield-cancel") + async (callback (func $cm "unreachable-cb")) + )) + (func (export "poll-cancel-pending") async (param "fut" $FT) (result u32) (canon lift + (core func $cm "poll-cancel-pending") + async (callback (func $cm "unreachable-cb")) + )) + (func (export "yield-cancel-pending") async (param "fut" $FT) (result u32) (canon lift + (core func $cm "yield-cancel-pending") + async (callback (func $cm "unreachable-cb")) + )) + ) + + (component $D + (type $FT (future)) + (import "wait-cancel" (func $wait-cancel async (result u32))) + (import "yield-cancel" (func $yield-cancel async (result u32))) + (import "poll-cancel-pending" (func $poll-cancel-pending async (param "fut" $FT) (result u32))) + (import "yield-cancel-pending" (func $yield-cancel-pending async (param "fut" $FT) (result u32))) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) + (import "" "subtask.drop" (func $subtask.drop (param i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "wait-cancel" (func $wait-cancel (param i32) (result i32))) + (import "" "yield-cancel" (func $yield-cancel (param i32) (result i32))) + (import "" "poll-cancel-pending" (func $poll-cancel-pending (param i32 i32) (result i32))) + (import "" "yield-cancel-pending" (func $yield-cancel-pending (param i32 i32) (result i32))) + + (func $run (export "run") (result i32) + (local $ret i32) (local $ret64 i64) + (local $retp i32) (local $retp2 i32) + (local $subtask i32) + (local $event_code i32) + (local $futr i32) (local $futw i32) + (local $ws i32) + + ;; ========================================== + ;; Test 1: waitable-set.wait cancellable + ;; ========================================== + + ;; call wait-cancel; it should block in cancellable wait + (local.set $retp (i32.const 4)) + (local.set $ret (call $wait-cancel (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; cancel; completes immediately (C is in cancellable wait) + (local.set $ret (call $subtask.cancel (local.get $subtask))) + (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (local.get $ret)) + (then unreachable)) + (call $subtask.drop (local.get $subtask)) + + ;; ========================================== + ;; Test 2: thread.yield cancellable + ;; ========================================== + + ;; call yield-cancel; it should suspend in cancellable yield + (local.set $ret (call $yield-cancel (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; cancel; completes immediately (C is in cancellable yield) + (local.set $ret (call $subtask.cancel (local.get $subtask))) + (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (local.get $ret)) + ;; TODO: this currently fails in Wasmtime due to cancellable + ;; thread.yield not being directly resumed by subtask.cancel, but it + ;; seems like it should pass: + (then unreachable)) + (call $subtask.drop (local.get $subtask)) + + ;; ========================================== + ;; Test 3: waitable-set.poll cancellable (pending) + ;; ========================================== + + ;; create future for poll-cancel-pending to read + (local.set $ret64 (call $future.new)) + (local.set $futr (i32.wrap_i64 (local.get $ret64))) + (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + + ;; call poll-cancel-pending; it should block in non-cancellable wait + (local.set $retp (i32.const 4)) + (local.set $retp2 (i32.const 8)) + (local.set $ret (call $poll-cancel-pending (local.get $futr) (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; cancel; blocks because C's wait is not cancellable + (local.set $ret (call $subtask.cancel (local.get $subtask))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; write to future; unblocks C's non-cancellable wait + (local.set $ret (call $future.write (local.get $futw) (i32.const 0))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + ;; wait for subtask to complete + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtask) (local.get $ws)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (i32.load offset=4 (local.get $retp2))) + (then unreachable)) + (call $subtask.drop (local.get $subtask)) + + ;; ========================================== + ;; Test 4: thread.yield cancellable (pending) + ;; ========================================== + + ;; create future for yield-cancel-pending to read + (local.set $ret64 (call $future.new)) + (local.set $futr (i32.wrap_i64 (local.get $ret64))) + (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + + ;; call yield-cancel-pending; it should block in non-cancellable wait + (local.set $ret (call $yield-cancel-pending (local.get $futr) (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; cancel; blocks because C's wait is not cancellable + (local.set $ret (call $subtask.cancel (local.get $subtask))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; write to future; unblocks C's non-cancellable wait + (local.set $ret (call $future.write (local.get $futw) (i32.const 0))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + ;; wait for subtask to complete + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtask) (local.get $ws)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (i32.load offset=4 (local.get $retp2))) + (then unreachable)) + (call $subtask.drop (local.get $subtask)) + + ;; all tests passed + (i32.const 42) + ) + ) + (canon subtask.cancel async (core func $subtask.cancel)) + (canon subtask.drop (core func $subtask.drop)) + (canon future.new $FT (core func $future.new)) + (canon future.write $FT async (memory $memory "mem") (core func $future.write)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon lower (func $wait-cancel) async (memory $memory "mem") (core func $wait-cancel')) + (canon lower (func $yield-cancel) async (memory $memory "mem") (core func $yield-cancel')) + (canon lower (func $poll-cancel-pending) async (memory $memory "mem") (core func $poll-cancel-pending')) + (canon lower (func $yield-cancel-pending) async (memory $memory "mem") (core func $yield-cancel-pending')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "subtask.cancel" (func $subtask.cancel)) + (export "subtask.drop" (func $subtask.drop)) + (export "future.new" (func $future.new)) + (export "future.write" (func $future.write)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "wait-cancel" (func $wait-cancel')) + (export "yield-cancel" (func $yield-cancel')) + (export "poll-cancel-pending" (func $poll-cancel-pending')) + (export "yield-cancel-pending" (func $yield-cancel-pending')) + )))) + (func (export "run") async (result u32) (canon lift (core func $dm "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D + (with "wait-cancel" (func $c "wait-cancel")) + (with "yield-cancel" (func $c "yield-cancel")) + (with "poll-cancel-pending" (func $c "poll-cancel-pending")) + (with "yield-cancel-pending" (func $c "yield-cancel-pending")) + )) + (func (export "run") (alias export $d "run")) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/closed-stream.wast b/src/test/resources/spec-tests/async/closed-stream.wast new file mode 100644 index 0000000..eb462c8 --- /dev/null +++ b/src/test/resources/spec-tests/async/closed-stream.wast @@ -0,0 +1,102 @@ +;; This test contains two components $C and $D that test that if the writable side +;; of a stream is dropped, the other side registers a STREAM DROPPED status +;; when attempting to read from the stream. +(component definition $Tester + ;; Creates a stream and keeps a handle to the writable end of it. + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + ;; Store the writable end of a stream + (global $sw (mut i32) (i32.const 0)) + + ;; Create a new stream, return the readable end to the caller + (func $start-stream (export "start-stream") (result i32) + (local $ret64 i64) + (local.set $ret64 (call $stream.new)) + (global.set $sw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (i32.wrap_i64 (local.get $ret64)) + ) + + ;; Drop the writable end of a stream + (func $drop-writable (export "drop-writable") + (call $stream.drop-writable (global.get $sw)) + ) + ) + (type $ST (stream u8)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "stream.new" (func $stream.new)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (func (export "start-stream") (result (stream u8)) (canon lift (core func $cm "start-stream"))) + (func (export "drop-writable") (canon lift (core func $cm "drop-writable"))) + ) + + ;; Gets a readable stream from component $C and calls operations on it. + (component $D + (import "c" (instance $c + (export "start-stream" (func (result (stream u8)))) + (export "drop-writable" (func)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + (import "" "start-stream" (func $start-stream (result i32))) + (import "" "drop-writable" (func $drop-writable)) + + (func (export "read-from-closed-stream") + (local $ret i32) (local $sr i32) + + ;; call 'start-stream' to get the stream we'll be working with + (local.set $sr (call $start-stream)) + (if (i32.ne (i32.const 1) (local.get $sr)) + (then unreachable)) + + ;; drop the writable end and then attempt to read from it + (call $drop-writable) + (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 4))) + (if (i32.ne (i32.const 1 (; DROPPED ;)) (local.get $ret)) + (then unreachable)) + ) + ) + (type $ST (stream u8)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (canon lower (func $c "start-stream") (core func $start-stream')) + (canon lower (func $c "drop-writable") (core func $drop-writable')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-writable" (func $stream.drop-writable)) + (export "start-stream" (func $start-stream')) + (export "drop-writable" (func $drop-writable')) + )))) + (func (export "read-from-closed-stream") (canon lift (core func $core "read-from-closed-stream"))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "read-from-closed-stream") (alias export $d "read-from-closed-stream")) +) + +(component instance $new-tester-instance $Tester) +(invoke "read-from-closed-stream") diff --git a/src/test/resources/spec-tests/async/cross-abi-calls.wast b/src/test/resources/spec-tests/async/cross-abi-calls.wast new file mode 100644 index 0000000..8f1370b --- /dev/null +++ b/src/test/resources/spec-tests/async/cross-abi-calls.wast @@ -0,0 +1,519 @@ +;; This test pairs sync and async-callback calls from $Bottom into $Top, +;; testing different numbers of parameters and results that hit the various +;; flat-vs-heap cases in the spec. +(component definition $C + (component $Top + (core module $Memory + (memory (export "mem") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + i32.const 0 ;; cheat -- there's never more than 1 allocation alive + ) + ) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 0)) + (import "" "task.return0" (func $task.return0)) + (import "" "task.return1" (func $task.return1 (param f64))) + (import "" "task.return16" (func $task.return16 (param i32 i64 f32 f64 i32 i64 f32 f64 i32 i64 f32 f64 i32 i64 f32 f64))) + (import "" "task.return17" (func $task.return17 (param i32))) + (func (export "sync-4-param") (param i32 i64 f32 f64) + (if (i32.ne (i32.const 42) (local.get 0)) + (then unreachable)) + (if (i64.ne (i64.const 43) (local.get 1)) + (then unreachable)) + (if (f32.ne (f32.const 44.4) (local.get 2)) + (then unreachable)) + (if (f64.ne (f64.const 45.5) (local.get 3)) + (then unreachable)) + ) + (func (export "sync-5-param") (param i32 i64 f32 f64 i32) + (if (i32.ne (i32.const -1) (local.get 0)) + (then unreachable)) + (if (i64.ne (i64.const -2) (local.get 1)) + (then unreachable)) + (if (f32.ne (f32.const -3.3) (local.get 2)) + (then unreachable)) + (if (f64.ne (f64.const -4.4) (local.get 3)) + (then unreachable)) + (if (i32.ne (i32.const -5) (local.get 4)) + (then unreachable)) + ) + (func $check-17 (param $ptr i32) + (if (i32.ne (i32.const -1) (i32.load (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -2) (i64.load offset=8 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -3.3) (f32.load offset=16 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -4.4) (f64.load offset=24 (local.get $ptr))) + (then unreachable)) + (if (i32.ne (i32.const -5) (i32.load offset=32 (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -6) (i64.load offset=40 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -7.7) (f32.load offset=48 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -8.8) (f64.load offset=56 (local.get $ptr))) + (then unreachable)) + (if (i32.ne (i32.const -9) (i32.load offset=64 (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -10) (i64.load offset=72 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -11.11) (f32.load offset=80 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -12.12) (f64.load offset=88 (local.get $ptr))) + (then unreachable)) + (if (i32.ne (i32.const -13) (i32.load offset=96 (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -14) (i64.load offset=104 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -15.15) (f32.load offset=112 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -16.16) (f64.load offset=120 (local.get $ptr))) + (then unreachable)) + (if (i32.ne (i32.const -17) (i32.load offset=128 (local.get $ptr))) + (then unreachable)) + ) + (func (export "sync-17-param") (param $ptr i32) + (call $check-17 (local.get $ptr)) + ) + (func (export "sync-1-result") (result f64) + (f64.const -1.1) + ) + (func $setup-16 (param $ptr i32) + (i32.store (local.get $ptr) (i32.const -1)) + (i64.store offset=8 (local.get $ptr) (i64.const -2)) + (f32.store offset=16 (local.get $ptr) (f32.const -3.3)) + (f64.store offset=24 (local.get $ptr) (f64.const -4.4)) + (i32.store offset=32 (local.get $ptr) (i32.const -5)) + (i64.store offset=40 (local.get $ptr) (i64.const -6)) + (f32.store offset=48 (local.get $ptr) (f32.const -7.7)) + (f64.store offset=56 (local.get $ptr) (f64.const -8.8)) + (i32.store offset=64 (local.get $ptr) (i32.const -9)) + (i64.store offset=72 (local.get $ptr) (i64.const -10)) + (f32.store offset=80 (local.get $ptr) (f32.const -11.11)) + (f64.store offset=88 (local.get $ptr) (f64.const -12.12)) + (i32.store offset=96 (local.get $ptr) (i32.const -13)) + (i64.store offset=104 (local.get $ptr) (i64.const -14)) + (f32.store offset=112 (local.get $ptr) (f32.const -15.15)) + (f64.store offset=120 (local.get $ptr) (f64.const -16.16)) + ) + (func $setup-17 (param $ptr i32) + (call $setup-16 (local.get $ptr)) + (i32.store offset=128 (local.get $ptr) (i32.const -17)) + ) + (func (export "sync-16-result") (result i32) + (local $ptr i32) + (call $setup-16 (local.get $ptr)) + (local.get $ptr) + ) + (func (export "sync-17-result") (result i32) + (local $ptr i32) + (call $setup-17 (local.get $ptr)) + (local.get $ptr) + ) + (func (export "async-4-param") (param i32 i64 f32 f64) (result i32) + (if (i32.ne (i32.const 42) (local.get 0)) + (then unreachable)) + (if (i64.ne (i64.const 43) (local.get 1)) + (then unreachable)) + (if (f32.ne (f32.const 44.4) (local.get 2)) + (then unreachable)) + (if (f64.ne (f64.const 45.5) (local.get 3)) + (then unreachable)) + (call $task.return0) + (i32.const 0 (; EXIT ;)) + ) + (func (export "async-5-param") (param i32 i64 f32 f64 i32) (result i32) + (if (i32.ne (i32.const -1) (local.get 0)) + (then unreachable)) + (if (i64.ne (i64.const -2) (local.get 1)) + (then unreachable)) + (if (f32.ne (f32.const -3.3) (local.get 2)) + (then unreachable)) + (if (f64.ne (f64.const -4.4) (local.get 3)) + (then unreachable)) + (if (i32.ne (i32.const -5) (local.get 4)) + (then unreachable)) + (call $task.return0) + (i32.const 0 (; EXIT ;)) + ) + (func (export "async-17-param") (param $ptr i32) (result i32) + (call $check-17 (local.get $ptr)) + (call $task.return0) + (i32.const 0 (; EXIT ;)) + ) + (func (export "async-1-result") (result i32) + (call $task.return1 (f64.const -1.1)) + (i32.const 0 (; EXIT ;)) + ) + (func (export "async-16-result") (result i32) + (call $task.return16 (i32.const -1) (i64.const -2) (f32.const -3.3) (f64.const -4.4) + (i32.const -5) (i64.const -6) (f32.const -7.7) (f64.const -8.8) + (i32.const -9) (i64.const -10) (f32.const -11.11) (f64.const -12.12) + (i32.const -13) (i64.const -14) (f32.const -15.15) (f64.const -16.16)) + (i32.const 0 (; EXIT ;)) + ) + (func (export "async-17-result") (result i32) + (local $ptr i32) + (call $setup-17 (local.get $ptr)) + (call $task.return17 (local.get $ptr)) + (i32.const 0 (; EXIT ;)) + ) + (func (export "unreachable-cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (canon task.return (core func $task.return0)) + (canon task.return (result f64) (core func $task.return1)) + (canon task.return (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)) (core func $task.return16)) + (canon task.return (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)) (memory $memory "mem") (core func $task.return17)) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return0" (func $task.return0)) + (export "task.return1" (func $task.return1)) + (export "task.return16" (func $task.return16)) + (export "task.return17" (func $task.return17)) + )))) + (func (export "sync-4-param") async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) + (canon lift (core func $core "sync-4-param")) + ) + (func (export "sync-5-param") async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) (param "e" u32) + (canon lift (core func $core "sync-5-param")) + ) + (func (export "sync-17-param") async + (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) + (param "e" u32) (param "f" u64) (param "g" f32) (param "h" f64) + (param "i" u32) (param "j" u64) (param "k" f32) (param "l" f64) + (param "m" u32) (param "n" u64) (param "o" f32) (param "p" f64) + (param "q" u32) + (canon lift (core func $core "sync-17-param") (memory $memory "mem") (realloc (func $memory "realloc"))) + ) + (func (export "sync-1-result") async (result f64) + (canon lift (core func $core "sync-1-result")) + ) + (func (export "sync-16-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)) + (canon lift (core func $core "sync-16-result") (memory $memory "mem")) + ) + (func (export "sync-17-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)) + (canon lift (core func $core "sync-17-result") (memory $memory "mem")) + ) + (func (export "async-4-param") async + (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) + (canon lift (core func $core "async-4-param") async (callback (func $core "unreachable-cb"))) + ) + (func (export "async-5-param") async + (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) (param "e" u32) + (canon lift (core func $core "async-5-param") async (callback (func $core "unreachable-cb"))) + ) + (func (export "async-17-param") async + (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) + (param "e" u32) (param "f" u64) (param "g" f32) (param "h" f64) + (param "i" u32) (param "j" u64) (param "k" f32) (param "l" f64) + (param "m" u32) (param "n" u64) (param "o" f32) (param "p" f64) + (param "q" u32) + (canon lift (core func $core "async-17-param") async (callback (func $core "unreachable-cb")) (memory $memory "mem") (realloc (func $memory "realloc"))) + ) + (func (export "async-1-result") async (result f64) + (canon lift (core func $core "async-1-result") async (callback (func $core "unreachable-cb"))) + ) + (func (export "async-16-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)) + (canon lift (core func $core "async-16-result") async (callback (func $core "unreachable-cb"))) + ) + (func (export "async-17-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)) + (canon lift (core func $core "async-17-result") async (callback (func $core "unreachable-cb")) (memory $memory "mem") (realloc (func $memory "realloc"))) + ) + ) + (component $Bottom + (import "func-4-param" (func $func-4-param async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64))) + (import "func-5-param" (func $func-5-param async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) (param "e" u32))) + (import "func-17-param" (func $func-17-param async + (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) + (param "e" u32) (param "f" u64) (param "g" f32) (param "h" f64) + (param "i" u32) (param "j" u64) (param "k" f32) (param "l" f64) + (param "m" u32) (param "n" u64) (param "o" f32) (param "p" f64) + (param "q" u32))) + (import "func-1-result" (func $func-1-result async (result f64))) + (import "func-16-result" (func $func-16-result async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)))) + (import "func-17-result" (func $func-17-result async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)))) + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "sync-4-param" (func $sync-4-param (param i32 i64 f32 f64))) + (import "" "async-4-param" (func $async-4-param (param i32 i64 f32 f64) (result i32))) + (import "" "sync-5-param" (func $sync-5-param (param i32 i64 f32 f64 i32))) + (import "" "async-5-param" (func $async-5-param (param i32) (result i32))) + (import "" "sync-17-param" (func $sync-17-param (param i32))) + (import "" "async-17-param" (func $async-17-param (param i32) (result i32))) + (import "" "sync-1-result" (func $sync-1-result (result f64))) + (import "" "async-1-result" (func $async-1-result (param i32) (result i32))) + (import "" "sync-16-result" (func $sync-16-result (param i32))) + (import "" "async-16-result" (func $async-16-result (param i32) (result i32))) + (import "" "sync-17-result" (func $sync-17-result (param i32))) + (import "" "async-17-result" (func $async-17-result (param i32) (result i32))) + (func (export "call-sync-4-param") (result i32) + (call $sync-4-param (i32.const 42) (i64.const 43) (f32.const 44.4) (f64.const 45.5)) + (i32.const 83) + ) + (func (export "call-async-4-param") (result i32) + (if (i32.ne (call $async-4-param (i32.const 42) (i64.const 43) (f32.const 44.4) (f64.const 45.5)) + (i32.const 2 (; RETURNED ;))) + (then unreachable)) + (i32.const 84) + ) + (func (export "call-sync-5-param") (result i32) + (call $sync-5-param (i32.const -1) (i64.const -2) (f32.const -3.3) (f64.const -4.4) (i32.const -5)) + (i32.const 85) + ) + (func (export "call-async-5-param") (result i32) + (local $ptr i32) + (i32.store (local.get $ptr) (i32.const -1)) + (i64.store offset=8 (local.get $ptr) (i64.const -2)) + (f32.store offset=16 (local.get $ptr) (f32.const -3.3)) + (f64.store offset=24 (local.get $ptr) (f64.const -4.4)) + (i32.store offset=32 (local.get $ptr) (i32.const -5)) + (if (i32.ne (call $async-5-param (local.get $ptr)) (i32.const 2 (; RETURNED ;))) + (then unreachable)) + (i32.const 86) + ) + (func $setup-17 (param $ptr i32) + (i32.store (local.get $ptr) (i32.const -1)) + (i64.store offset=8 (local.get $ptr) (i64.const -2)) + (f32.store offset=16 (local.get $ptr) (f32.const -3.3)) + (f64.store offset=24 (local.get $ptr) (f64.const -4.4)) + (i32.store offset=32 (local.get $ptr) (i32.const -5)) + (i64.store offset=40 (local.get $ptr) (i64.const -6)) + (f32.store offset=48 (local.get $ptr) (f32.const -7.7)) + (f64.store offset=56 (local.get $ptr) (f64.const -8.8)) + (i32.store offset=64 (local.get $ptr) (i32.const -9)) + (i64.store offset=72(local.get $ptr) (i64.const -10)) + (f32.store offset=80 (local.get $ptr) (f32.const -11.11)) + (f64.store offset=88 (local.get $ptr) (f64.const -12.12)) + (i32.store offset=96 (local.get $ptr) (i32.const -13)) + (i64.store offset=104 (local.get $ptr) (i64.const -14)) + (f32.store offset=112 (local.get $ptr) (f32.const -15.15)) + (f64.store offset=120 (local.get $ptr) (f64.const -16.16)) + (i32.store offset=128 (local.get $ptr) (i32.const -17)) + ) + (func (export "call-sync-17-param") (result i32) + (call $setup-17 (i32.const 0)) + (call $sync-17-param (i32.const 0)) + (i32.const 87) + ) + (func (export "call-async-17-param") (result i32) + (call $setup-17 (i32.const 0)) + (if (i32.ne (call $async-17-param (i32.const 0)) (i32.const 2 (; RETURNED ;))) + (then unreachable)) + (i32.const 88) + ) + (func (export "call-sync-1-result") (result i32) + (if (f64.ne (call $sync-1-result) (f64.const -1.1)) + (then unreachable)) + (i32.const 89) + ) + (func (export "call-async-1-result") (result i32) + (local $ptr i32) + (if (i32.ne (call $async-1-result (local.get $ptr)) (i32.const 2 (; RETURNED ;))) + (then unreachable)) + (if (f64.ne (f64.load (local.get $ptr)) (f64.const -1.1)) + (then unreachable)) + (i32.const 90) + ) + (func $check-16 (param $ptr i32) + (if (i32.ne (i32.const -1) (i32.load (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -2) (i64.load offset=8 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -3.3) (f32.load offset=16 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -4.4) (f64.load offset=24 (local.get $ptr))) + (then unreachable)) + (if (i32.ne (i32.const -5) (i32.load offset=32 (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -6) (i64.load offset=40 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -7.7) (f32.load offset=48 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -8.8) (f64.load offset=56 (local.get $ptr))) + (then unreachable)) + (if (i32.ne (i32.const -9) (i32.load offset=64 (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -10) (i64.load offset=72 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -11.11) (f32.load offset=80 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -12.12) (f64.load offset=88 (local.get $ptr))) + (then unreachable)) + (if (i32.ne (i32.const -13) (i32.load offset=96 (local.get $ptr))) + (then unreachable)) + (if (i64.ne (i64.const -14) (i64.load offset=104 (local.get $ptr))) + (then unreachable)) + (if (f32.ne (f32.const -15.15) (f32.load offset=112 (local.get $ptr))) + (then unreachable)) + (if (f64.ne (f64.const -16.16) (f64.load offset=120 (local.get $ptr))) + (then unreachable)) + ) + (func $check-17 (param $ptr i32) + (call $check-16 (local.get $ptr)) + (if (i32.ne (i32.const -17) (i32.load offset=128 (local.get $ptr))) + (then unreachable)) + ) + (func (export "call-sync-16-result") (result i32) + (local $ptr i32) + (call $sync-16-result (local.get $ptr)) + (call $check-16 (local.get $ptr)) + (i32.const 91) + ) + (func (export "call-async-16-result") (result i32) + (local $ptr i32) + (if (i32.ne (call $async-16-result (local.get $ptr)) (i32.const 2 (; RETURNED ;))) + (then unreachable)) + (call $check-16 (local.get $ptr)) + (i32.const 92) + ) + (func (export "call-sync-17-result") (result i32) + (local $ptr i32) + (call $sync-17-result (local.get $ptr)) + (call $check-17 (local.get $ptr)) + (i32.const 93) + ) + (func (export "call-async-17-result") (result i32) + (local $ptr i32) + (if (i32.ne (call $async-17-result (local.get $ptr)) (i32.const 2 (; RETURNED ;))) + (then unreachable)) + (call $check-17 (local.get $ptr)) + (i32.const 94) + ) + ) + (canon lower (func $func-4-param) (core func $sync-4-param)) + (canon lower (func $func-4-param) async (memory $memory "mem") (core func $async-4-param)) + (canon lower (func $func-5-param) (core func $sync-5-param)) + (canon lower (func $func-5-param) async (memory $memory "mem") (core func $async-5-param)) + (canon lower (func $func-17-param) (memory $memory "mem") (core func $sync-17-param)) + (canon lower (func $func-17-param) async (memory $memory "mem") (core func $async-17-param)) + (canon lower (func $func-1-result) (core func $sync-1-result)) + (canon lower (func $func-1-result) async (memory $memory "mem") (core func $async-1-result)) + (canon lower (func $func-16-result) (memory $memory "mem") (core func $sync-16-result)) + (canon lower (func $func-16-result) async (memory $memory "mem") (core func $async-16-result)) + (canon lower (func $func-17-result) (memory $memory "mem") (core func $sync-17-result)) + (canon lower (func $func-17-result) async (memory $memory "mem") (core func $async-17-result)) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "sync-4-param" (func $sync-4-param)) + (export "async-4-param" (func $async-4-param)) + (export "sync-5-param" (func $sync-5-param)) + (export "async-5-param" (func $async-5-param)) + (export "sync-17-param" (func $sync-17-param)) + (export "async-17-param" (func $async-17-param)) + (export "sync-1-result" (func $sync-1-result)) + (export "async-1-result" (func $async-1-result)) + (export "sync-16-result" (func $sync-16-result)) + (export "async-16-result" (func $async-16-result)) + (export "sync-17-result" (func $sync-17-result)) + (export "async-17-result" (func $async-17-result)) + )))) + (func (export "call-sync-4-param") async (result u32) (canon lift (core func $core "call-sync-4-param"))) + (func (export "call-async-4-param") async (result u32) (canon lift (core func $core "call-async-4-param"))) + (func (export "call-sync-5-param") async (result u32) (canon lift (core func $core "call-sync-5-param"))) + (func (export "call-async-5-param") async (result u32) (canon lift (core func $core "call-async-5-param"))) + (func (export "call-sync-17-param") async (result u32) (canon lift (core func $core "call-sync-17-param"))) + (func (export "call-async-17-param") async (result u32) (canon lift (core func $core "call-async-17-param"))) + (func (export "call-sync-1-result") async (result u32) (canon lift (core func $core "call-sync-1-result"))) + (func (export "call-async-1-result") async (result u32) (canon lift (core func $core "call-async-1-result"))) + (func (export "call-sync-16-result") async (result u32) (canon lift (core func $core "call-sync-16-result"))) + (func (export "call-async-16-result") async (result u32) (canon lift (core func $core "call-async-16-result"))) + (func (export "call-sync-17-result") async (result u32) (canon lift (core func $core "call-sync-17-result"))) + (func (export "call-async-17-result") async (result u32) (canon lift (core func $core "call-async-17-result"))) + ) + (instance $top (instantiate $Top)) + (instance $bottom-to-sync (instantiate $Bottom + (with "func-4-param" (func $top "sync-4-param")) + (with "func-5-param" (func $top "sync-5-param")) + (with "func-17-param" (func $top "sync-17-param")) + (with "func-1-result" (func $top "sync-1-result")) + (with "func-16-result" (func $top "sync-16-result")) + (with "func-17-result" (func $top "sync-17-result")) + )) + (instance $bottom-to-async (instantiate $Bottom + (with "func-4-param" (func $top "async-4-param")) + (with "func-5-param" (func $top "async-5-param")) + (with "func-17-param" (func $top "async-17-param")) + (with "func-1-result" (func $top "async-1-result")) + (with "func-16-result" (func $top "async-16-result")) + (with "func-17-result" (func $top "async-17-result")) + )) + (func (export "sync-calls-sync-4-param") (alias export $bottom-to-sync "call-sync-4-param")) + (func (export "sync-calls-async-4-param") (alias export $bottom-to-async "call-sync-4-param")) + (func (export "async-calls-sync-4-param") (alias export $bottom-to-sync "call-async-4-param")) + (func (export "async-calls-async-4-param") (alias export $bottom-to-async "call-async-4-param")) + (func (export "sync-calls-sync-5-param") (alias export $bottom-to-sync "call-sync-5-param")) + (func (export "sync-calls-async-5-param") (alias export $bottom-to-async "call-sync-5-param")) + (func (export "async-calls-sync-5-param") (alias export $bottom-to-sync "call-async-5-param")) + (func (export "async-calls-async-5-param") (alias export $bottom-to-async "call-async-5-param")) + (func (export "sync-calls-sync-17-param") (alias export $bottom-to-sync "call-sync-17-param")) + (func (export "sync-calls-async-17-param") (alias export $bottom-to-async "call-sync-17-param")) + (func (export "async-calls-sync-17-param") (alias export $bottom-to-sync "call-async-17-param")) + (func (export "async-calls-async-17-param") (alias export $bottom-to-async "call-async-17-param")) + (func (export "sync-calls-sync-1-result") (alias export $bottom-to-sync "call-sync-1-result")) + (func (export "sync-calls-async-1-result") (alias export $bottom-to-async "call-sync-1-result")) + (func (export "async-calls-sync-1-result") (alias export $bottom-to-sync "call-async-1-result")) + (func (export "async-calls-async-1-result") (alias export $bottom-to-async "call-async-1-result")) + (func (export "sync-calls-sync-16-result") (alias export $bottom-to-sync "call-sync-16-result")) + (func (export "sync-calls-async-16-result") (alias export $bottom-to-async "call-sync-16-result")) + (func (export "async-calls-sync-16-result") (alias export $bottom-to-sync "call-async-16-result")) + (func (export "async-calls-async-16-result") (alias export $bottom-to-async "call-async-16-result")) + (func (export "sync-calls-sync-17-result") (alias export $bottom-to-sync "call-sync-17-result")) + (func (export "sync-calls-async-17-result") (alias export $bottom-to-async "call-sync-17-result")) + (func (export "async-calls-sync-17-result") (alias export $bottom-to-sync "call-async-17-result")) + (func (export "async-calls-async-17-result") (alias export $bottom-to-async "call-async-17-result")) +) + +(component instance $i $C) +(assert_return (invoke "sync-calls-sync-4-param") (u32.const 83)) +(component instance $i $C) +(assert_return (invoke "sync-calls-async-4-param") (u32.const 83)) +(component instance $i $C) +(assert_return (invoke "async-calls-sync-4-param") (u32.const 84)) +(component instance $i $C) +(assert_return (invoke "async-calls-async-4-param") (u32.const 84)) +(component instance $i $C) +(assert_return (invoke "sync-calls-sync-5-param") (u32.const 85)) +(component instance $i $C) +(assert_return (invoke "sync-calls-async-5-param") (u32.const 85)) +(component instance $i $C) +(assert_return (invoke "async-calls-sync-5-param") (u32.const 86)) +(component instance $i $C) +(assert_return (invoke "async-calls-async-5-param") (u32.const 86)) +(component instance $i $C) +(assert_return (invoke "sync-calls-sync-17-param") (u32.const 87)) +(component instance $i $C) +(assert_return (invoke "sync-calls-async-17-param") (u32.const 87)) +(component instance $i $C) +(assert_return (invoke "async-calls-sync-17-param") (u32.const 88)) +(component instance $i $C) +(assert_return (invoke "async-calls-async-17-param") (u32.const 88)) +(component instance $i $C) +(assert_return (invoke "sync-calls-sync-1-result") (u32.const 89)) +(component instance $i $C) +(assert_return (invoke "sync-calls-async-1-result") (u32.const 89)) +(component instance $i $C) +(assert_return (invoke "async-calls-sync-1-result") (u32.const 90)) +(component instance $i $C) +(assert_return (invoke "async-calls-async-1-result") (u32.const 90)) +(component instance $i $C) +(assert_return (invoke "sync-calls-sync-16-result") (u32.const 91)) +(component instance $i $C) +(assert_return (invoke "sync-calls-async-16-result") (u32.const 91)) +(component instance $i $C) +(assert_return (invoke "async-calls-sync-16-result") (u32.const 92)) +(component instance $i $C) +(assert_return (invoke "async-calls-async-16-result") (u32.const 92)) +(component instance $i $C) +(assert_return (invoke "sync-calls-sync-17-result") (u32.const 93)) +(component instance $i $C) +(assert_return (invoke "sync-calls-async-17-result") (u32.const 93)) +(component instance $i $C) +(assert_return (invoke "async-calls-sync-17-result") (u32.const 94)) +(component instance $i $C) +(assert_return (invoke "async-calls-async-17-result") (u32.const 94)) diff --git a/src/test/resources/spec-tests/async/cross-task-future.wast b/src/test/resources/spec-tests/async/cross-task-future.wast new file mode 100644 index 0000000..7f76b6e --- /dev/null +++ b/src/test/resources/spec-tests/async/cross-task-future.wast @@ -0,0 +1,103 @@ +;; This exercises that future ends are not tied to the task that created them. +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + + (global $futr (mut i32) (i32.const 0)) + (global $futw (mut i32) (i32.const 0)) + + (func $one (export "one") + (local $ret i32) (local $ret64 i64) + (local.set $ret64 (call $future.new)) + (global.set $futr (i32.wrap_i64 (local.get $ret64))) + (global.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + ) + (func $two (export "two") (result i32) + (local $ret i32) (local $ptr i32) + (call $task.return (global.get $futr)) + (local.set $ptr (i32.const 32)) + (i32.store (local.get $ptr) (i32.const 0x42)) + (local.set $ret (call $future.write (global.get $futw) (local.get $ptr))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (i32.const 0 (; EXIT ;)) + ) + (func $two_cb (export "two_cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (type $FT (future u8)) + (canon task.return (result $FT) (core func $task.return)) + (canon future.new $FT (core func $future.new)) + (canon future.write $FT async (memory $memory "mem") (core func $future.write)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "future.new" (func $future.new)) + (export "future.write" (func $future.write)) + )))) + (func (export "one") (canon lift + (core func $cm "one") + )) + (func (export "two") async (result (future u8)) (canon lift + (core func $cm "two") + async (callback (func $cm "two_cb")) + )) + ) + + (component $D + (import "c" (instance $c + (export "one" (func)) + (export "two" (func async (result (future u8)))) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "one" (func $one)) + (import "" "two" (func $two (result i32))) + + (func $run (export "run") (result i32) + (local $ret i32) + (local $retp i32) + (local $futr i32) + + (call $one) + (local.set $futr (call $two)) + (local.set $retp (i32.const 32)) + (local.set $ret (call $future.read (local.get $futr) (local.get $retp))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.load8_u (local.get $retp)) (i32.const 0x42)) + (then unreachable)) + + (i32.const 42) + ) + ) + (type $FT (future u8)) + (canon future.read $FT async (memory $memory "mem") (core func $future.read)) + (canon lower (func $c "one") (core func $one')) + (canon lower (func $c "two") (core func $two')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "future.read" (func $future.read)) + (export "one" (func $one')) + (export "two" (func $two')) + )))) + (func (export "run") async (result u32) (canon lift (core func $dm "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "run") (alias export $d "run")) +) + +(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/deadlock.wast b/src/test/resources/spec-tests/async/deadlock.wast new file mode 100644 index 0000000..6d50c9f --- /dev/null +++ b/src/test/resources/spec-tests/async/deadlock.wast @@ -0,0 +1,73 @@ +;; This test defines components $C and $D where $D imports and calls $C +;; $C.f waits on an empty waitable set +;; $D.g calls $C.f and then waits for it to finish, which fails due to deadlock +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + + (func (export "f") (result i32) + ;; wait on a new empty waitable set + (local $ws i32) + (local.set $ws (call $waitable-set.new)) + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (local.get $ws) (i32.const 4))) + ) + (func (export "cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + unreachable + ) + ) + (canon waitable-set.new (core func $waitable-set.new)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable-set.new" (func $waitable-set.new)) + )))) + (func (export "f") async (result u32) (canon lift + (core func $cm "f") + async (memory $memory "mem") (callback (func $cm "cb")) + )) + ) + + (component $D + (import "f" (func $f async (result u32))) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "f" (func $f (param i32) (result i32))) + + (func (export "g") (result i32) + (local $ws i32) (local $ret i32) (local $subtaski i32) + (local.set $ret (call $f (i32.const 0))) + (local.set $subtaski (i32.shr_u (local.get $ret) (i32.const 4))) + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtaski) (local.get $ws)) + (call $waitable-set.wait (local.get $ws) (i32.const 0)) + unreachable + ) + ) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon lower (func $f) async (memory $memory "mem") (core func $f')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "f" (func $f')) + )))) + (func (export "f") async (result u32) (canon lift (core func $dm "g"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "f" (func $c "f")))) + (func (export "f") (alias export $d "f")) +) +(assert_trap (invoke "f") "wasm trap: deadlock detected: event loop cannot make further progress") diff --git a/src/test/resources/spec-tests/async/dont-block-start.wast b/src/test/resources/spec-tests/async/dont-block-start.wast new file mode 100644 index 0000000..5fab77f --- /dev/null +++ b/src/test/resources/spec-tests/async/dont-block-start.wast @@ -0,0 +1,50 @@ +;; test a few cases where components trap during core module instantiation +;; due to blocking during the (implicitly sync) start function +(assert_trap + (component + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $M + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (func $start + (drop (call $waitable-set.wait (call $waitable-set.new) (i32.const 0))) + ) + (start $start) + ) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (core instance $m (instantiate $M (with "" (instance + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + )))) + ) + "cannot block a synchronous task before returning" +) +(assert_trap + (component + (component $C + (core module $M + (func (export "f") (result i32) unreachable) + (func (export "f_cb") (param i32 i32 i32) (result i32) unreachable) + ) + (core instance $i (instantiate $M)) + (func (export "f") async (canon lift (core func $i "f") async (callback (func $i "f_cb")))) + ) + (component $D + (import "f" (func $f async)) + (core module $M + (import "" "f" (func $f)) + (func $start (call $f)) + (start $start) + ) + (canon lower (func $f) (core func $f')) + (core instance $m (instantiate $M (with "" (instance + (export "f" (func $f')) + )))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "f" (func $c "f")))) + ) + "cannot block a synchronous task before returning" +) diff --git a/src/test/resources/spec-tests/async/drop-cross-task-borrow.wast b/src/test/resources/spec-tests/async/drop-cross-task-borrow.wast new file mode 100644 index 0000000..139981c --- /dev/null +++ b/src/test/resources/spec-tests/async/drop-cross-task-borrow.wast @@ -0,0 +1,309 @@ +;; This test has 3 components $C, $D and $E +;; $C just implements a resource type that's used by $D and $E +;; $E calls async function $D.dont-drop, lending it a handle. +;; $D.dont-drop blocks, waiting on an empty waitable-set +;; $E then calls $D.drop-handle which drops the handle that $D.dont-drop +;; was lent, albeit from the "wrong" task ($D.drop-handle). +;; Then $E calls $D.resume-dont-drop to unblock $D.dont-drop, which +;; will call task.return which should not trap. +(component definition $Test + (component $C + (type $R' (resource (rep i32))) + (canon resource.new $R' (core func $resource.new)) + (core module $CM (func (export "id") (param i32) (result i32) (local.get 0))) + (core instance $cm (instantiate $CM)) + (alias core export $cm "id" (core func $resource.rep)) + (export $R "R" (type $R')) + (func (export "R-new") (param "rep" u32) (result (own $R)) (canon lift (core func $resource.new))) + (func (export "R-rep") (param "self" (borrow $R)) (result u32) (canon lift (core func $resource.rep))) + ) + + (component $D + (import "c" (instance $d + (export "R" (type $R (sub resource))) + (export "R-new" (func (param "rep" u32) (result (own $R)))) + (export "R-rep" (func (param "self" (borrow $R)) (result u32))) + )) + (core module $DM + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "task.return0" (func $task.return0)) + (import "" "task.return1" (func $task.return1 (param i32))) + (import "" "R-rep" (func $R-rep (param i32) (result i32))) + (import "" "R-drop" (func $R-drop (param i32))) + + (global $handle (mut i32) (i32.const 0)) + (global $dont-drop-result (mut i32) (i32.const 0)) + (global $dont-drop-ws (mut i32) (i32.const 0)) + + (func (export "dont-drop") (param $h i32) (result i32) + ;; Stash the given (borrow $R) handle in a global. + (global.set $handle (local.get $h)) + ;; Stash the result of $R-rep in a global for later task.return + (global.set $dont-drop-result (call $R-rep (local.get $h))) + ;; Stash the waitable-set we're waiting on in a global for resume-dont-drop to use + (global.set $dont-drop-ws (call $waitable-set.new)) + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $dont-drop-ws) (i32.const 4))) + ) + (func (export "dont-drop-cb") (param i32 i32 i32) (result i32) + ;; We were resumed by resume-dont-drop + (call $task.return1 (global.get $dont-drop-result)) + (i32.const 0 (; EXIT ;)) + ) + (func (export "drop-handle") (result i32) + ;; Drops the borrowed handle passed to dont-drop + (local $result i32) + (local.set $result (call $R-rep (global.get $handle))) + (call $R-drop (global.get $handle)) + (local.get $result) + ) + (func (export "resume-dont-drop") + ;; Add a waitable with a pending event to dont-drop's waitable-set to + ;; wake it up. + (local $ret i32) (local $ret64 i64) + (local $futw i32) (local $futr i32) + (local.set $ret64 (call $future.new)) + (local.set $futr (i32.wrap_i64 (local.get $ret64))) + (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (local.get $futr) (global.get $dont-drop-ws)) + ) + (func (export "drop-other-and-self") (param $h i32) (result i32) + (local $result i32) + (local.set $result (call $R-rep (global.get $handle))) + (call $R-drop (global.get $handle)) + (call $R-drop (local.get $h)) + (call $task.return1 (local.get $result)) + (i32.const 0 (; EXIT ;)) + ) + (func (export "drop-wrong-one") (param $h i32) (result i32) + (call $R-drop (global.get $handle)) + ;; trap b/c $h wasn't dropped + (call $task.return0) + (i32.const 0 (; EXIT ;)) + ) + (func (export "unreachable-cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (type $FT (future)) + (alias export $d "R" (type $R)) + (canon task.return (core func $task.return0)) + (canon task.return (result u32) (core func $task.return1)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon future.new $FT (core func $future.new)) + (canon future.read $FT async (core func $future.read)) + (canon future.write $FT async (core func $future.write)) + (canon lower (func $d "R-rep") (core func $R-rep)) + (canon resource.drop $R (core func $R-drop)) + (core instance $dm (instantiate $DM (with "" (instance + (export "task.return0" (func $task.return0)) + (export "task.return1" (func $task.return1)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "future.new" (func $future.new)) + (export "future.read" (func $future.read)) + (export "future.write" (func $future.write)) + (export "R-rep" (func $R-rep)) + (export "R-drop" (func $R-drop)) + )))) + (func (export "dont-drop") async (param "self" (borrow $R)) (result u32) + (canon lift (core func $dm "dont-drop") async (callback (func $dm "dont-drop-cb"))) + ) + (func (export "drop-handle") (result u32) + (canon lift (core func $dm "drop-handle")) + ) + (func (export "resume-dont-drop") + (canon lift (core func $dm "resume-dont-drop")) + ) + (func (export "drop-other-and-self") async (param "self" (borrow $R)) (result u32) + (canon lift (core func $dm "drop-other-and-self") async (callback (func $dm "unreachable-cb"))) + ) + (func (export "drop-wrong-one") async (param "self" (borrow $R)) + (canon lift (core func $dm "drop-wrong-one") async (callback (func $dm "unreachable-cb"))) + ) + ) + + (component $E + (import "c" (instance $c + (export "R" (type $R (sub resource))) + (export "R-new" (func (param "rep" u32) (result (own $R)))) + )) + (alias export $c "R" (type $R)) + (import "d" (instance $d + (export "dont-drop" (func async (param "self" (borrow $R)) (result u32))) + (export "drop-handle" (func (result u32))) + (export "resume-dont-drop" (func)) + (export "drop-other-and-self" (func async (param "self" (borrow $R)) (result u32))) + (export "drop-wrong-one" (func async (param "self" (borrow $R)))) + )) + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $EM + (import "" "mem" (memory 1)) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "R-new" (func $R-new (param i32) (result i32))) + (import "" "dont-drop" (func $dont-drop (param i32 i32) (result i32))) + (import "" "drop-handle" (func $drop-handle (result i32))) + (import "" "resume-dont-drop" (func $resume-dont-drop)) + (import "" "drop-other-and-self" (func $drop-other-and-self (param i32) (result i32))) + (import "" "drop-wrong-one" (func $drop-wrong-one (param i32))) + (func (export "drop-other-no-self") (result i32) + (local $ret i32) + (local $retp i32) (local $retp2 i32) + (local $handle i32) + (local $subtask i32) + (local $magic i32) + (local $ws i32) (local $event_code i32) + + ;; Create a resource storing $magic as it's rep + (local.set $magic (i32.const 10)) + (local.set $handle (call $R-new (local.get $magic))) + + ;; Kick off a call to dont-drop that will block + (local.set $retp (i32.const 16)) + (local.set $ret (call $dont-drop (local.get $handle) (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; drop-handle should return the rep of the handle passed to dont-drop + (local.set $ret (call $drop-handle)) + (if (i32.ne (local.get $magic) (local.get $ret)) + (then unreachable)) + + ;; this unblocks $subtask + (call $resume-dont-drop) + + ;; now wait for $subtask to return, so that it can run before the test is over + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtask) (local.get $ws)) + (local.set $retp2 (i32.const 32)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) + (then unreachable)) + + ;; $subtask should return the rep passed to $R-new. + (if (i32.ne (local.get $magic) (i32.load (local.get $retp))) + (then unreachable)) + + i32.const 42 + ) + (func (export "drop-other-and-self") (result i32) + (local $ret i32) + (local $retp i32) (local $retp2 i32) + (local $handle i32) + (local $subtask i32) + (local $magic i32) + (local $ws i32) (local $event_code i32) + + ;; Create a resource storing $magic as it's rep + (local.set $magic (i32.const 11)) + (local.set $handle (call $R-new (local.get $magic))) + + ;; Kick off a call to dont-drop that will block + (local.set $retp (i32.const 16)) + (local.set $ret (call $dont-drop (local.get $handle) (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; This will drop dont-drop's *and* its own borrowed handle + (local.set $ret (call $drop-other-and-self (local.get $handle))) + (if (i32.ne (local.get $magic) (local.get $ret)) + (then unreachable)) + + ;; this unblocks $subtask + (call $resume-dont-drop) + + ;; now wait for $subtask to return, so that it can run before the test is over + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtask) (local.get $ws)) + (local.set $retp2 (i32.const 32)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) + (then unreachable)) + + ;; $subtask should return the rep passed to $R-new. + (if (i32.ne (local.get $magic) (i32.load (local.get $retp))) + (then unreachable)) + + i32.const 43 + ) + (func (export "drop-other-miss-self") + (local $ret i32) + (local $retp i32) + (local $handle i32) + (local $subtask i32) + + (local.set $handle (call $R-new (i32.const 42))) + + ;; Kick off a call to dont-drop that will block + (local.set $retp (i32.const 16)) + (local.set $ret (call $dont-drop (local.get $handle) (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; Call drop-wrong-one which will drop the above call's borrow, but not its own and trap + (call $drop-wrong-one (local.get $handle)) + ) + ) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon lower (func $c "R-new") (core func $R-new)) + (canon lower (func $d "dont-drop") async (memory $memory "mem") (core func $dont-drop)) + (canon lower (func $d "drop-handle") (core func $drop-handle)) + (canon lower (func $d "resume-dont-drop") (core func $resume-dont-drop)) + (canon lower (func $d "drop-other-and-self") (core func $drop-other-and-self)) + (canon lower (func $d "drop-wrong-one") (core func $drop-wrong-one)) + (core instance $em (instantiate $EM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "R-new" (func $R-new)) + (export "dont-drop" (func $dont-drop)) + (export "drop-handle" (func $drop-handle)) + (export "resume-dont-drop" (func $resume-dont-drop)) + (export "drop-other-and-self" (func $drop-other-and-self)) + (export "drop-wrong-one" (func $drop-wrong-one)) + )))) + (func (export "drop-other-no-self") async (result u32) (canon lift (core func $em "drop-other-no-self"))) + (func (export "drop-other-and-self") async (result u32) (canon lift (core func $em "drop-other-and-self"))) + (func (export "drop-other-miss-self") async (canon lift (core func $em "drop-other-miss-self"))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (instance $e (instantiate $E (with "c" (instance $c)) (with "d" (instance $d)))) + (func (export "drop-other-no-self") (alias export $e "drop-other-no-self")) + (func (export "drop-other-and-self") (alias export $e "drop-other-and-self")) + (func (export "drop-other-miss-self") (alias export $e "drop-other-miss-self")) +) + +(component instance $i $Test) +(assert_return (invoke "drop-other-no-self") (u32.const 42)) +(component instance $i $Test) +(assert_return (invoke "drop-other-and-self") (u32.const 43)) +(component instance $i $Test) +(assert_trap (invoke "drop-other-miss-self") "borrow handles still remain at the end of the call") diff --git a/src/test/resources/spec-tests/async/drop-stream.wast b/src/test/resources/spec-tests/async/drop-stream.wast new file mode 100644 index 0000000..bf7212f --- /dev/null +++ b/src/test/resources/spec-tests/async/drop-stream.wast @@ -0,0 +1,160 @@ +;; This test contains two components $C and $D that test that traps occur +;; when closing the readable or writable end of stream while a read or write +;; is pending. In particular, even if a partial copy has happened into the +;; buffer such that waiting/polling for an event *would* produce a STREAM +;; READ/WRITE event, if the event has not been delivered, the operation is +;; still considered pending. +(component definition $Tester + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + (global $sw (mut i32) (i32.const 0)) + + (func $start-stream (export "start-stream") (result i32) + ;; create a new stream, return the readable end to the caller + (local $ret64 i64) + (local.set $ret64 (call $stream.new)) + (global.set $sw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (i32.wrap_i64 (local.get $ret64)) + ) + (func $write4 (export "write4") + ;; write 6 bytes into the stream, expecting to rendezvous with a stream.read + (local $ret i32) + (i32.store (i32.const 8) (i32.const 0x12345678)) + (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 4))) + (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + ) + (func $start-blocking-write (export "start-blocking-write") + (local $ret i32) + + ;; prepare the write buffer + (i64.store (i32.const 8) (i64.const 0x123456789abcdef)) + + ;; start a blocking write + (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 8))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + ) + (func $drop-writable (export "drop-writable") + ;; boom + (call $stream.drop-writable (global.get $sw)) + ) + ) + (type $ST (stream u8)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "stream.new" (func $stream.new)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (func (export "start-stream") (result (stream u8)) (canon lift (core func $cm "start-stream"))) + (func (export "write4") (canon lift (core func $cm "write4"))) + (func (export "start-blocking-write") (canon lift (core func $cm "start-blocking-write"))) + (func (export "drop-writable") (canon lift (core func $cm "drop-writable"))) + ) + (component $D + (import "c" (instance $c + (export "start-stream" (func (result (stream u8)))) + (export "write4" (func)) + (export "start-blocking-write" (func)) + (export "drop-writable" (func)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + (import "" "start-stream" (func $start-stream (result i32))) + (import "" "write4" (func $write4)) + (import "" "start-blocking-write" (func $start-blocking-write)) + (import "" "drop-writable" (func $drop-writable)) + + (func (export "drop-while-reading") + (local $ret i32) (local $sr i32) + + ;; call 'start-stream' to get the stream we'll be working with + (local.set $sr (call $start-stream)) + (if (i32.ne (i32.const 1) (local.get $sr)) + (then unreachable)) + + ;; start a blocking read + (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) + (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) + (then unreachable)) + + ;; write into the buffer, but the read is still in progress since we + ;; haven't received notification yet. + (call $write4) + (if (i32.ne (i32.const 0x12345678) (i32.load (i32.const 8))) + (then unreachable)) + + ;; boom + (call $stream.drop-readable (local.get $sr)) + ) + (func (export "drop-while-writing") + (local $ret i32) (local $sr i32) + + ;; call 'start-stream' to get the stream we'll be working with + (local.set $sr (call $start-stream)) + (if (i32.ne (i32.const 1) (local.get $sr)) + (then unreachable)) + + ;; start a blocking write and partially read from it + (call $start-blocking-write) + (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 4))) + (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0x89abcdef) (i32.load (i32.const 8))) + (then unreachable)) + (call $drop-writable) + ) + ) + (type $ST (stream u8)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (canon lower (func $c "start-stream") (core func $start-stream')) + (canon lower (func $c "write4") (core func $write4')) + (canon lower (func $c "start-blocking-write") (core func $start-blocking-write')) + (canon lower (func $c "drop-writable") (core func $drop-writable')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "stream.drop-writable" (func $stream.drop-writable)) + (export "start-stream" (func $start-stream')) + (export "write4" (func $write4')) + (export "start-blocking-write" (func $start-blocking-write')) + (export "drop-writable" (func $drop-writable')) + )))) + (func (export "drop-while-reading") (canon lift (core func $core "drop-while-reading"))) + (func (export "drop-while-writing") (canon lift (core func $core "drop-while-writing"))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "drop-while-reading") (alias export $d "drop-while-reading")) + (func (export "drop-while-writing") (alias export $d "drop-while-writing")) +) +(component instance $new-tester-instance $Tester) +(assert_trap (invoke "drop-while-reading") "cannot remove busy stream") +(component instance $new-tester-instance $Tester) +(assert_trap (invoke "drop-while-writing") "cannot drop busy stream") diff --git a/src/test/resources/spec-tests/async/drop-subtask.wast b/src/test/resources/spec-tests/async/drop-subtask.wast new file mode 100644 index 0000000..21eb9fc --- /dev/null +++ b/src/test/resources/spec-tests/async/drop-subtask.wast @@ -0,0 +1,140 @@ +;; This test contains two components: $Looper and $Caller. +;; $Caller starts an async subtask for $Looper.loop and then drops these +;; subtasks in both allowed and disallowed cases, testing for success and +;; traps. +(component + (component $Looper + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CoreLooper + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return)) + + (global $done (mut i32) (i32.const 0)) + + (func $loop (export "loop") (result i32) + (i32.const 1 (; YIELD ;)) + ) + (func $loop_cb (export "loop_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + ;; confirm that we've received a cancellation request + (if (i32.ne (local.get $event_code) (i32.const 0 (; NONE ;))) + (then unreachable)) + (if (i32.ne (local.get $index) (i32.const 0)) + (then unreachable)) + (if (i32.ne (local.get $payload) (i32.const 0)) + (then unreachable)) + + (if (i32.eqz (global.get $done)) + (then (return (i32.const 1 (; YIELD ;))))) + (call $task.return) + (i32.const 0 (; EXIT ;)) + ) + + (func $return (export "return") + (global.set $done (i32.const 1)) + ) + ) + (canon task.return (core func $task.return)) + (core instance $core_looper (instantiate $CoreLooper (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + )))) + (func (export "loop") async (canon lift + (core func $core_looper "loop") + async (callback (func $core_looper "loop_cb")) + )) + (func (export "return") async (canon lift + (core func $core_looper "return") + )) + ) + + (component $Caller + (import "looper" (instance $looper + (export "loop" (func async)) + (export "return" (func async)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CoreCaller + (import "" "mem" (memory 1)) + (import "" "subtask.drop" (func $subtask.drop (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "loop" (func $loop (result i32))) + (import "" "return" (func $return)) + + (func $drop-after-return (export "drop-after-return") (result i32) + (local $ret i32) (local $ws i32) (local $subtask i32) + + ;; start 'loop' + (local.set $ret (call $loop)) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; tell 'loop' to stop + (call $return) + + ;; wait for 'loop' to run and return + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtask) (local.get $ws)) + (local.set $ret (call $waitable-set.wait (local.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (i32.const 0))) + (then unreachable)) + (if (i32.ne (i32.const 2 (; RETURNED ;)) (i32.load (i32.const 4))) + (then unreachable)) + + ;; ok to drop + (call $subtask.drop (local.get $subtask)) + (i32.const 42) + ) + + (func $drop-before-return (export "drop-before-return") (result i32) + (local $ret i32) (local $subtask i32) + + ;; start 'loop' + (local.set $ret (call $loop (i32.const 0xdead) (i32.const 0xbeef))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + + ;; this should trap + (call $subtask.drop (local.get $subtask)) + unreachable + ) + ) + (canon subtask.drop (core func $subtask.drop)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon lower (func $looper "loop") async (memory $memory "mem") (core func $loop')) + (canon lower (func $looper "return") (memory $memory "mem") (core func $return')) + (core instance $core_caller (instantiate $CoreCaller (with "" (instance + (export "mem" (memory $memory "mem")) + (export "subtask.drop" (func $subtask.drop)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "loop" (func $loop')) + (export "return" (func $return')) + )))) + (func (export "drop-after-return") async (result u32) (canon lift + (core func $core_caller "drop-after-return") + )) + (func (export "drop-before-return") async (result u32) (canon lift + (core func $core_caller "drop-before-return") + )) + ) + + (instance $looper (instantiate $Looper)) + (instance $caller1 (instantiate $Caller (with "looper" (instance $looper)))) + (instance $caller2 (instantiate $Caller (with "looper" (instance $looper)))) + (func (export "drop-after-return") (alias export $caller1 "drop-after-return")) + (func (export "drop-before-return") (alias export $caller2 "drop-before-return")) +) +(assert_return (invoke "drop-after-return") (u32.const 42)) +(assert_trap (invoke "drop-before-return") "cannot drop a subtask which has not yet resolved") diff --git a/src/test/resources/spec-tests/async/drop-waitable-set.wast b/src/test/resources/spec-tests/async/drop-waitable-set.wast new file mode 100644 index 0000000..23fff15 --- /dev/null +++ b/src/test/resources/spec-tests/async/drop-waitable-set.wast @@ -0,0 +1,84 @@ +;; This test contains two components $C and $D +;; $D.run drives the test and first calls $C.wait-on-set, which waits on +;; a waitable-set. Then $D.run calls $C.drop-while-waiting which attempts +;; to drop the same waitable-set, which should trap. +(component + (component $C + (core module $Core + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.drop" (func $waitable-set.drop (param i32))) + + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + (func $wait-on-set (export "wait-on-set") (result i32) + ;; wait on $ws + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) + ) + (func $drop-while-waiting (export "drop-while-waiting") (result i32) + ;; boom + (call $waitable-set.drop (global.get $ws)) + unreachable + ) + (func $unreachable-cb (export "unreachable-cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.drop (core func $waitable-set.drop)) + (core instance $core (instantiate $Core (with "" (instance + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.drop" (func $waitable-set.drop)) + )))) + (func (export "wait-on-set") async (canon lift + (core func $core "wait-on-set") + async (callback (func $core "unreachable-cb")) + )) + (func (export "drop-while-waiting") async (canon lift + (core func $core "drop-while-waiting") + async (callback (func $core "unreachable-cb")) + )) + ) + + (component $D + (import "c" (instance $c + (export "wait-on-set" (func async)) + (export "drop-while-waiting" (func async)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "wait-on-set" (func $wait-on-set (result i32))) + (import "" "drop-while-waiting" (func $drop-while-waiting)) + (func $run (export "run") (result i32) + (local $ret i32) + + ;; start an async call to 'wait-on-set' which blocks, waiting on a + ;; waitable-set. + (local.set $ret (call $wait-on-set)) + (if (i32.ne (i32.const 0x11) (local.get $ret)) + (then unreachable)) + + ;; this call will try to drop the same waitable-set, which should trap. + (call $drop-while-waiting) + unreachable + ) + ) + (canon lower (func $c "wait-on-set") async (memory $memory "mem") (core func $wait-on-set')) + (canon lower (func $c "drop-while-waiting") (core func $drop-while-waiting')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "wait-on-set" (func $wait-on-set')) + (export "drop-while-waiting" (func $drop-while-waiting')) + )))) + (func (export "run") async (result u32) (canon lift (core func $core "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "run") (alias export $d "run")) +) +(assert_trap (invoke "run") "cannot drop waitable set with waiters") diff --git a/src/test/resources/spec-tests/async/empty-wait.wast b/src/test/resources/spec-tests/async/empty-wait.wast new file mode 100644 index 0000000..8b4d789 --- /dev/null +++ b/src/test/resources/spec-tests/async/empty-wait.wast @@ -0,0 +1,199 @@ +;; This test has two components $C and $D, where $D imports and calls $C +;; $C exports two functions: 'blocker' and 'unblocker' +;; 'blocker' blocks on an empty waitable set +;; 'unblocker' wakes blocker by adding a resolved future to blocker's waitable set +;; $D calls 'blocker' then 'unblocker', then waits for 'blocker' to finish +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "future.drop-readable" (func $future.drop-readable (param i32))) + (import "" "future.drop-writable" (func $future.drop-writable (param i32))) + + ;; $ws is waited on by 'blocker' and added to by 'unblocker' + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + ;; 'unblocker' initializes $futr with the readable end of a resolved future + (global $futr (mut i32) (i32.const 0)) + + (func $blocker (export "blocker") (result i32) + ;; wait on $ws which is currently empty; 'unblocker' will wake us up + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) + ) + (func $blocker_cb (export "blocker_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + ;; assert that we were in fact woken by 'unblocker' adding $futr to $ws + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (global.get $futr) (local.get $index)) + (then unreachable)) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $payload)) + (then unreachable)) + + (call $future.drop-readable (global.get $futr)) + + ;; return 42 to $D.run + (call $task.return (i32.const 42)) + (i32.const 0) + ) + + (func $unblocker (export "unblocker") (result i32) + (local $ret i32) (local $ret64 i64) + (local $futw i32) + + ;; create a future that will be used to unblock 'blocker', storing r/w ends in $futr/$futw + (local.set $ret64 (call $future.new)) + (global.set $futr (i32.wrap_i64 (local.get $ret64))) + (if (i32.ne (i32.const 2) (global.get $futr)) + (then unreachable)) + (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (if (i32.ne (i32.const 3) (local.get $futw)) + (then unreachable)) + + ;; perform a future.read which will block, and add this future to the waitable-set + ;; being waited on by 'blocker' + (local.set $ret (call $future.read (global.get $futr) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (global.get $futr) (global.get $ws)) + + ;; perform a future.write which will rendezvous with the write and complete + (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + (call $future.drop-writable (local.get $futw)) + + ;; return 43 to $D.run + (call $task.return (i32.const 43)) + (i32.const 0) + ) + (func $unblocker_cb (export "unblocker_cb") (param i32 i32 i32) (result i32) + ;; 'unblocker' doesn't block + unreachable + ) + ) + (type $FT (future)) + (canon task.return (result u32) (core func $task.return)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon future.new $FT (core func $future.new)) + (canon future.read $FT async (core func $future.read)) + (canon future.write $FT async (core func $future.write)) + (canon future.drop-readable $FT (core func $future.drop-readable)) + (canon future.drop-writable $FT (core func $future.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "future.new" (func $future.new)) + (export "future.read" (func $future.read)) + (export "future.write" (func $future.write)) + (export "future.drop-readable" (func $future.drop-readable)) + (export "future.drop-writable" (func $future.drop-writable)) + )))) + (func (export "blocker") async (result u32) (canon lift + (core func $cm "blocker") + async (callback (func $cm "blocker_cb")) + )) + (func (export "unblocker") async (result u32) (canon lift + (core func $cm "unblocker") + async (callback (func $cm "unblocker_cb")) + )) + ) + + (component $D + (import "c" (instance $c + (export "blocker" (func async (result u32))) + (export "unblocker" (func async (result u32))) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "subtask.drop" (func $subtask.drop (param i32))) + (import "" "blocker" (func $blocker (param i32) (result i32))) + (import "" "unblocker" (func $unblocker (param i32) (result i32))) + + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + (func $run (export "run") (result i32) + (local $ret i32) (local $retp1 i32) (local $retp2 i32) + (local $subtask i32) + (local $event_code i32) + + ;; call 'blocker'; it should block + (local.set $retp1 (i32.const 4)) + (local.set $ret (call $blocker (local.get $retp1))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (if (i32.ne (i32.const 2) (local.get $subtask)) + (then unreachable)) + + ;; call 'unblocker' to unblock 'blocker'; it should complete eagerly + (local.set $retp2 (i32.const 8)) + (local.set $ret (call $unblocker (local.get $retp2))) + (if (i32.ne (i32.const 2 (; RETURNED ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 43) (i32.load (local.get $retp2))) + (then unreachable)) + + ;; wait for 'blocker' to be scheduled, run, and return + (call $waitable.join (local.get $subtask) (global.get $ws)) + (local.set $retp2 (i32.const 8)) + (local.set $event_code (call $waitable-set.wait (global.get $ws) (local.get $retp2))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load (local.get $retp1))) + (then unreachable)) + + (call $subtask.drop (local.get $subtask)) + + ;; return 44 to the top-level test harness + (i32.const 44) + ) + ) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon subtask.drop (core func $subtask.drop)) + (canon lower (func $c "blocker") async (memory $memory "mem") (core func $blocker')) + (canon lower (func $c "unblocker") async (memory $memory "mem") (core func $unblocker')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "subtask.drop" (func $subtask.drop)) + (export "blocker" (func $blocker')) + (export "unblocker" (func $unblocker')) + )))) + (func (export "run") async (result u32) (canon lift (core func $dm "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "run") (alias export $d "run")) +) +(assert_return (invoke "run") (u32.const 44)) diff --git a/src/test/resources/spec-tests/async/futures-must-write.wast b/src/test/resources/spec-tests/async/futures-must-write.wast new file mode 100644 index 0000000..ce2446b --- /dev/null +++ b/src/test/resources/spec-tests/async/futures-must-write.wast @@ -0,0 +1,118 @@ +;; This test contains two components $C and $D that test that a trap occurs +;; when closing the writable end of a future (in $C) before having written +;; a value while closing the readable end of a future (in $D) before reading +;; a value is fine. +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "future.drop-writable" (func $future.drop-writable (param i32))) + + (global $fw (mut i32) (i32.const 0)) + + (func $start-future (export "start-future") (result i32) + ;; create a new future, return the readable end to the caller + (local $ret64 i64) + (local.set $ret64 (call $future.new)) + (global.set $fw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (i32.wrap_i64 (local.get $ret64)) + ) + (func $attempt-write (export "attempt-write") (result i32) + ;; because the caller already dropped the readable end, this write will eagerly + ;; return DROPPED having written no values. + (local $ret i32) + (local.set $ret (call $future.write (global.get $fw) (i32.const 42))) + (if (i32.ne (i32.const 0x01 (; DROPPED ;)) (local.get $ret)) + (then unreachable)) + + ;; return without trapping + (i32.const 42) + ) + (func $drop-writable (export "drop-writable") + ;; maybe boom + (call $future.drop-writable (global.get $fw)) + ) + ) + (type $FT (future u8)) + (canon future.new $FT (core func $future.new)) + (canon future.write $FT async (memory $memory "mem") (core func $future.write)) + (canon future.drop-writable $FT (core func $future.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "future.new" (func $future.new)) + (export "future.write" (func $future.write)) + (export "future.drop-writable" (func $future.drop-writable)) + )))) + (func (export "start-future") (result (future u8)) (canon lift (core func $cm "start-future"))) + (func (export "attempt-write") (result u32) (canon lift (core func $cm "attempt-write"))) + (func (export "drop-writable") (canon lift (core func $cm "drop-writable"))) + ) + (component $D + (import "c" (instance $c + (export "start-future" (func (result (future u8)))) + (export "attempt-write" (func (result u32))) + (export "drop-writable" (func)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "future.drop-readable" (func $future.drop-readable (param i32))) + (import "" "start-future" (func $start-future (result i32))) + (import "" "attempt-write" (func $attempt-write (result i32))) + (import "" "drop-writable" (func $drop-writable)) + + (func $drop-readable-future-before-read (export "drop-readable-future-before-read") (result i32) + ;; call 'start-future' to get the future we'll be working with + (local $fr i32) + (local.set $fr (call $start-future)) + (if (i32.ne (i32.const 1) (local.get $fr)) + (then unreachable)) + + ;; ok to immediately drop the readable end + (call $future.drop-readable (local.get $fr)) + + ;; the callee will see that we dropped the readable end when it tries to write + (call $attempt-write) + ) + (func $drop-writable-future-before-write (export "drop-writable-future-before-write") + ;; call 'start-future' to get the future we'll be working with + (local $fr i32) + (local.set $fr (call $start-future)) + (if (i32.ne (i32.const 1) (local.get $fr)) + (then unreachable)) + + ;; boom + (call $drop-writable) + ) + ) + (type $FT (future u8)) + (canon future.new $FT (core func $future.new)) + (canon future.drop-readable $FT (core func $future.drop-readable)) + (canon lower (func $c "start-future") (core func $start-future')) + (canon lower (func $c "attempt-write") (core func $attempt-write')) + (canon lower (func $c "drop-writable") (core func $drop-writable')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "future.new" (func $future.new)) + (export "future.drop-readable" (func $future.drop-readable)) + (export "start-future" (func $start-future')) + (export "attempt-write" (func $attempt-write')) + (export "drop-writable" (func $drop-writable')) + )))) + (func (export "drop-readable-future-before-read") (result u32) (canon lift (core func $core "drop-readable-future-before-read"))) + (func (export "drop-writable-future-before-write") (canon lift (core func $core "drop-writable-future-before-write"))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "drop-writable-future-before-write") (alias export $d "drop-writable-future-before-write")) + (func (export "drop-readable-future-before-read") (alias export $d "drop-readable-future-before-read")) +) + +(assert_return (invoke "drop-readable-future-before-read") (u32.const 42)) +(assert_trap (invoke "drop-writable-future-before-write") "cannot drop future write end without first writing a value") diff --git a/src/test/resources/spec-tests/async/partial-stream-copies.wast b/src/test/resources/spec-tests/async/partial-stream-copies.wast new file mode 100644 index 0000000..d70ece2 --- /dev/null +++ b/src/test/resources/spec-tests/async/partial-stream-copies.wast @@ -0,0 +1,238 @@ +;; This test has two components $C and $D, where $D imports and calls $C.transform +;; $C.transform takes and returns a stream +;; Before $C.transform blocks the first time, it supplies a 12-byte read buffer +;; When $D.run regains control after $C.transform blocks, it can perform multiple +;; successful writes until it fully uses up the 12-byte buffer. +;; ... and that's where I am so far ... +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + ;; $ws is waited on by 'transform' + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + ;; $insr/$outsw are read/written by 'transform' + (global $insr (mut i32) (i32.const 0)) + (global $inbufp (mut i32) (i32.const 0x10)) + (global $outsw (mut i32) (i32.const 0)) + (global $outbufp (mut i32) (i32.const 0x20)) + + (func $transform (export "transform") (param i32) (result i32) + (local $ret i32) (local $ret64 i64) (local $outsr i32) + + ;; check the incoming readable stream end + (global.set $insr (local.get 0)) + (if (i32.ne (i32.const 2) (global.get $insr)) + (then unreachable)) + + ;; create a new stream r/w pair $outsr/$outsw + (local.set $ret64 (call $stream.new)) + (local.set $outsr (i32.wrap_i64 (local.get $ret64))) + (if (i32.ne (i32.const 3) (local.get $outsr)) + (then unreachable)) + (global.set $outsw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (if (i32.ne (i32.const 4) (global.get $outsw)) + (then unreachable)) + + ;; start async read on $insr which will block + (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 12))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; return the readable end of the outgoing stream to the caller + (call $task.return (local.get $outsr)) + + ;; wait for the stream.read/write to complete + (call $waitable.join (global.get $insr) (global.get $ws)) + (call $waitable.join (global.get $outsw) (global.get $ws)) + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) + ) + (func $transform_cb (export "transform_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + (local $ret i32) (local $ret64 i64) + + ;; confirm the read succeeded fully + (if (i32.ne (local.get $event_code) (i32.const 2 (; STREAM_READ ;))) + (then unreachable)) + (if (i32.ne (local.get $index) (global.get $insr)) + (then unreachable)) + (if (i32.ne (local.get $payload) (i32.const 0xc0 (; COMPLETED=0 | (12 << 4) ;))) + (then unreachable)) + (if (i32.ne (i32.const 0x89abcdef) (i32.load offset=0 (global.get $inbufp))) + (then unreachable)) + (if (i32.ne (i32.const 0x01234567) (i32.load offset=4 (global.get $inbufp))) + (then unreachable)) + (if (i32.ne (i32.const 0x89abcdef) (i32.load offset=8 (global.get $inbufp))) + (then unreachable)) + + ;; multiple read calls succeed until 12-byte buffer is consumed + (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 4))) + (if (i32.ne (i32.const 0x40) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0x76543210) (i32.load (global.get $inbufp))) + (then unreachable)) + (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 2))) + (if (i32.ne (i32.const 0x20) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0xba98) (i32.load16_u (global.get $inbufp))) + (then unreachable)) + (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 8))) + (if (i32.ne (i32.const 0x60) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0x3210fedc) (i32.load (global.get $inbufp))) + (then unreachable)) + (if (i32.ne (i32.const 0x7654) (i32.load16_u offset=4 (global.get $inbufp))) + (then unreachable)) + + (call $stream.drop-readable (global.get $insr)) + (call $stream.drop-writable (global.get $outsw)) + (return (i32.const 0 (; EXIT ;))) + ) + ) + (type $ST (stream u8)) + (canon task.return (result $ST) (memory $memory "mem") (core func $task.return)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (func (export "transform") async (param "in" (stream u8)) (result (stream u8)) (canon lift + (core func $cm "transform") + async (memory $memory "mem") (callback (func $cm "transform_cb")) + )) + ) + + (component $D + (import "transform" (func $transform async (param "in" (stream u8)) (result (stream u8)))) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + (import "" "transform" (func $transform (param i32 i32) (result i32))) + + (func $run (export "run") (result i32) + (local $ret i32) (local $ret64 i64) (local $retp i32) + (local $insr i32) (local $insw i32) (local $outsr i32) + (local $subtask i32) (local $event_code i32) (local $index i32) (local $payload i32) + (local $ws i32) + + ;; create a new stream r/w pair $insr/$insw + (local.set $ret64 (call $stream.new)) + (local.set $insr (i32.wrap_i64 (local.get $ret64))) + (if (i32.ne (i32.const 1) (local.get $insr)) + (then unreachable)) + (local.set $insw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (if (i32.ne (i32.const 2) (local.get $insw)) + (then unreachable)) + + ;; call 'transform' which will return a readable stream $outsr eagerly + (local.set $retp (i32.const 8)) + (local.set $ret (call $transform (local.get $insr) (local.get $retp))) + (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (local.get $ret)) + (then unreachable)) + (local.set $outsr (i32.load (local.get $retp))) + (if (i32.ne (i32.const 1) (local.get $outsr)) + (then unreachable)) + + ;; multiple write calls succeed until 12-byte buffer is filled + (i64.store (i32.const 16) (i64.const 0x0123456789abcdef)) + (local.set $ret (call $stream.write (local.get $insw) (i32.const 16) (i32.const 8))) + (if (i32.ne (i32.const 0x80) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $stream.write (local.get $insw) (i32.const 16) (i32.const 8))) + (if (i32.ne (i32.const 0x40) (local.get $ret)) + (then unreachable)) + + ;; start a blocking write with a 12-byte buffer + (i64.store (i32.const 16) (i64.const 0xfedcba9876543210)) + (i32.store (i32.const 24) (i32.const 0x76543210)) + (local.set $ret (call $stream.write (local.get $insw) (i32.const 16) (i32.const 12))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; wait for transform to read our write and drop all the streams + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $insw) (local.get $ws)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (i32.const 0))) + (local.set $index (i32.load (i32.const 0))) + (local.set $payload (i32.load (i32.const 4))) + + ;; confirm the write and the dropped stream + (if (i32.ne (local.get $event_code) (i32.const 3 (; STREAM_WRITE ;))) + (then unreachable)) + (if (i32.ne (local.get $index) (local.get $insw)) + (then unreachable)) + (if (i32.ne (local.get $payload) (i32.const 0xc1 (; DROPPED=1 | (12 << 4) ;))) + (then unreachable)) + + (call $stream.drop-writable (local.get $insw)) + (call $stream.drop-readable (local.get $outsr)) + + ;; return 42 to the top-level test harness + (i32.const 42) + ) + ) + (type $ST (stream u8)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (canon lower (func $transform) async (memory $memory "mem") (core func $transform')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "stream.drop-writable" (func $stream.drop-writable)) + (export "transform" (func $transform')) + )))) + (func (export "run") async (result u32) (canon lift (core func $dm "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "transform" (func $c "transform")))) + (func (export "run") (alias export $d "run")) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/passing-resources.wast b/src/test/resources/spec-tests/async/passing-resources.wast new file mode 100644 index 0000000..d8a7c50 --- /dev/null +++ b/src/test/resources/spec-tests/async/passing-resources.wast @@ -0,0 +1,176 @@ +;; This test contains two components, $Producer and $Consumer. +;; $Producer.run drives the test and calls $Producer.start-stream to create +;; a stream and attempt to write 2 owned handles. $Producer.run then reads +;; just 1 element. The test finishes by confirming that $Consumer owns the +;; first resource, $Producer (still) owns the second resource, and $Producer +;; traps if it attempts to access the index of the first resource. +(component + (component $Producer + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "resource.new" (func $resource.new (param i32) (result i32))) + (import "" "resource.rep" (func $resource.rep (param i32) (result i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + (global $ws (mut i32) (i32.const 0)) + (global $res1 (mut i32) (i32.const 0)) + (global $res2 (mut i32) (i32.const 0)) + + (func $start-stream (export "start-stream") (result i32) + (local $ret i32) (local $ret64 i64) + (local $rs i32) + + ;; create a new stream, return the readable end to the caller + (local.set $ret64 (call $stream.new)) + (global.set $ws (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $rs (i32.wrap_i64 (local.get $ret64))) + + ;; create two resources and write them into a buffer to pass to stream.write + (global.set $res1 (call $resource.new (i32.const 50))) + (global.set $res2 (call $resource.new (i32.const 51))) + (i32.store (i32.const 8) (global.get $res1)) + (i32.store (i32.const 12) (global.get $res2)) + + ;; start a write which will block + (local.set $ret (call $stream.write (global.get $ws) (i32.const 8) (i32.const 2))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; check that this instance still owns both resources (ownership has not + ;; yet been transferred). + (if (i32.ne (i32.const 50) (call $resource.rep (global.get $res1))) + (then unreachable)) + (if (i32.ne (i32.const 51) (call $resource.rep (global.get $res2))) + (then unreachable)) + + (local.get $rs) + ) + (func $cancel-write (export "cancel-write") + (local $ret i32) + + ;; cancel the write, confirming that the first element was transferred + (local.set $ret (call $stream.cancel-write (global.get $ws))) + (if (i32.ne (i32.const 0x11 (; DROPPED=1 | (1 << 4) ;)) (local.get $ret)) + (then unreachable)) + + ;; we still own $res2 + (if (i32.ne (i32.const 51) (call $resource.rep (global.get $res2))) + (then unreachable)) + + (call $stream.drop-writable (global.get $ws)) + ) + (func $R.foo (export "R.foo") (param $rep i32) (result i32) + (i32.add (local.get $rep) (i32.const 50)) + ) + (func $fail-accessing-res1 (export "fail-accessing-res1") + ;; boom + (call $resource.rep (global.get $res1)) + unreachable + ) + ) + (type $R (resource (rep i32))) + (type $ST (stream (own $R))) + (canon resource.new $R (core func $resource.new)) + (canon resource.rep $R (core func $resource.rep)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.cancel-write $ST (core func $stream.cancel-write)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "resource.new" (func $resource.new)) + (export "resource.rep" (func $resource.rep)) + (export "stream.new" (func $stream.new)) + (export "stream.write" (func $stream.write)) + (export "stream.cancel-write" (func $stream.cancel-write)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (export $R' "R" (type $R)) + (func (export "[method]R.foo") async (param "self" (borrow $R')) (result u32) (canon lift (core func $core "R.foo"))) + (func (export "start-stream") async (result (stream (own $R'))) (canon lift (core func $core "start-stream"))) + (func (export "cancel-write") async (canon lift (core func $core "cancel-write"))) + (func (export "fail-accessing-res1") async (canon lift (core func $core "fail-accessing-res1"))) + ) + + (component $Consumer + (import "producer" (instance $producer + (export "R" (type $R (sub resource))) + (export "[method]R.foo" (func async (param "self" (borrow $R)) (result u32))) + (export "start-stream" (func async (result (stream (own $R))))) + (export "cancel-write" (func async)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "R.foo" (func $R.foo (param i32) (result i32))) + (import "" "start-stream" (func $start-stream (result i32))) + (import "" "cancel-write" (func $cancel-write)) + + (func $run (export "run") (result i32) + (local $ret i32) (local $rs i32) + (local $res1 i32) + + ;; get the readable end of a stream which has a pending write + (local.set $rs (call $start-stream)) + (if (i32.ne (local.get $rs) (i32.const 1)) + (then unreachable)) + + ;; read only 1 (of the 2 pending) elements, which won't block + (i64.store (i32.const 8) (i64.const 0xdeadbeefdeadbeef)) + (local.set $ret (call $stream.read (local.get $rs) (i32.const 8) (i32.const 1))) + (if (i32.ne (i32.const 0x10) (local.get $ret)) + (then unreachable)) + + ;; only 1 handle should have been transferred + (local.set $res1 (i32.load (i32.const 8))) + (if (i32.ne (i32.load (i32.const 12)) (i32.const 0xdeadbeef)) + (then unreachable)) + + ;; check that we got the first resource and it works + (local.set $ret (call $R.foo (local.get $res1))) + (if (i32.ne (i32.const 100) (local.get $ret)) + (then unreachable)) + + ;; drop the stream and then let $C run and assert stuff + (call $stream.drop-readable (local.get $rs)) + (call $cancel-write) + + (i32.const 42) + ) + ) + (alias export $producer "R" (type $R)) + (type $ST (stream (own $R))) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon lower (func $producer "[method]R.foo") (core func $R.foo')) + (canon lower (func $producer "start-stream") (core func $start-stream')) + (canon lower (func $producer "cancel-write") (core func $cancel-write')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "stream.read" (func $stream.read)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "R.foo" (func $R.foo')) + (export "start-stream" (func $start-stream')) + (export "cancel-write" (func $cancel-write')) + )))) + (func (export "run") async (result u32) (canon lift + (core func $core "run") + )) + ) + + (instance $producer (instantiate $Producer)) + (instance $consumer (instantiate $Consumer (with "producer" (instance $producer)))) + (func (export "run") (alias export $consumer "run")) + (func (export "fail-accessing-res1") (alias export $producer "fail-accessing-res1")) +) +(assert_return (invoke "run") (u32.const 42)) +(assert_trap (invoke "fail-accessing-res1") "unknown handle index 3") diff --git a/src/test/resources/spec-tests/async/same-component-stream-future.wast b/src/test/resources/spec-tests/async/same-component-stream-future.wast new file mode 100644 index 0000000..18d4a14 --- /dev/null +++ b/src/test/resources/spec-tests/async/same-component-stream-future.wast @@ -0,0 +1,259 @@ +;; This test tests same-component reading/writing of a stream and future +;; from the same component instance (which either traps or succeeds), +;; depending on the element type. + +(component definition $Tester + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $M + (import "" "mem" (memory 1)) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "future.newb" (func $future.newb (result i64))) + (import "" "future.readb" (func $future.readb (param i32 i32) (result i32))) + (import "" "future.writeb" (func $future.writeb (param i32 i32) (result i32))) + (import "" "stream.newb" (func $stream.newb (result i64))) + (import "" "stream.readb" (func $stream.readb (param i32 i32 i32) (result i32))) + (import "" "stream.writeb" (func $stream.writeb (param i32 i32 i32) (result i32))) + (import "" "future.newc" (func $future.newc (result i64))) + (import "" "future.readc" (func $future.readc (param i32 i32) (result i32))) + (import "" "future.writec" (func $future.writec (param i32 i32) (result i32))) + + (func (export "test-empty") (result i32) + (local $ret i32) (local $ret64 i64) + (local $rx i32) (local $tx i32) + + ;; test future reader then writer + (local.set $ret64 (call $future.new)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $future.read (local.get $rx) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $future.write (local.get $tx) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + ;; test future writer than reader + (local.set $ret64 (call $future.new)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $future.write (local.get $tx) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $future.read (local.get $rx) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + ;; test stream reader then writer + (local.set $ret64 (call $stream.new)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $stream.read (local.get $rx) (i32.const 0xdeadbeef) (i32.const 1))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $stream.write (local.get $tx) (i32.const 0xdeadbeef) (i32.const 1))) + (if (i32.ne (i32.const 0x10 (; COMPLETED=0 | (1<<4) ;)) (local.get $ret)) + (then unreachable)) + + ;; test stream writer than reader + (local.set $ret64 (call $stream.new)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $stream.write (local.get $tx) (i32.const 0xdeadbeef) (i32.const 1))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $stream.read (local.get $rx) (i32.const 0xdeadbeef) (i32.const 1))) + (if (i32.ne (i32.const 0x10 (; COMPLETED=0 | (1<<4) ;)) (local.get $ret)) + (then unreachable)) + + (i32.const 42) + ) + + (func $test-stream (param $srcp i32) (param $dstp i32) + (local $ret i32) (local $ret64 i64) + (local $rx i32) (local $tx i32) + + ;; test stream reader then writer + (i64.store (local.get $dstp) (i64.const 0)) + (i64.store (local.get $srcp) (i64.const 0x0123456789abcdef)) + (local.set $ret64 (call $stream.newb)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $stream.readb (local.get $rx) (local.get $dstp) (i32.const 8))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $stream.writeb (local.get $tx) (local.get $srcp) (i32.const 8))) + (if (i32.ne (i32.const 0x80 (; COMPLETED=0 | (8<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i64.ne (i64.load (local.get $dstp)) (i64.const 0x0123456789abcdef)) + (then unreachable)) + + ;; test stream writer than reader + (i64.store (local.get $dstp) (i64.const 0)) + (i64.store (local.get $srcp) (i64.const 0x0123456789abcdef)) + (local.set $ret64 (call $stream.newb)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $stream.writeb (local.get $tx) (local.get $srcp) (i32.const 8))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $stream.readb (local.get $rx) (local.get $dstp) (i32.const 8))) + (if (i32.ne (i32.const 0x80 (; COMPLETED=0 | (8<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i64.ne (i64.load (local.get $dstp)) (i64.const 0x0123456789abcdef)) + (then unreachable)) + ) + + (func (export "test-bytes") (result i32) + (local $ret i32) (local $ret64 i64) + (local $rx i32) (local $tx i32) + (local $dstp i32) (local $srcp i32) + + ;; because pointers must be aligned and futures are single-element, + ;; it's not possible to test the interesting overlap case + (local.set $srcp (i32.const 16)) + (local.set $dstp (i32.const 17)) + (i32.store8 (local.get $dstp) (i32.const 0)) + (i32.store8 (local.get $srcp) (i32.const 42)) + + ;; test future reader then writer + (local.set $ret64 (call $future.newb)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $future.readb (local.get $rx) (local.get $dstp))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $future.writeb (local.get $tx) (local.get $srcp))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.load8_u (local.get $dstp)) (i32.const 42)) + (then unreachable)) + + ;; reset memory and then test future writer than reader + (i32.store8 (local.get $dstp) (i32.const 0)) + (i32.store8 (local.get $srcp) (i32.const 42)) + (local.set $ret64 (call $future.newb)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $future.writeb (local.get $tx) (local.get $srcp))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (call $future.readb (local.get $rx) (local.get $dstp))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.load8_u (local.get $dstp)) (i32.const 42)) + (then unreachable)) + + ;; test a bunch of different overlapping cases + (call $test-stream (i32.const 16) (i32.const 8)) + (call $test-stream (i32.const 16) (i32.const 9)) + (call $test-stream (i32.const 16) (i32.const 10)) + (call $test-stream (i32.const 16) (i32.const 11)) + (call $test-stream (i32.const 16) (i32.const 12)) + (call $test-stream (i32.const 16) (i32.const 13)) + (call $test-stream (i32.const 16) (i32.const 14)) + (call $test-stream (i32.const 16) (i32.const 15)) + (call $test-stream (i32.const 16) (i32.const 16)) + (call $test-stream (i32.const 16) (i32.const 17)) + (call $test-stream (i32.const 16) (i32.const 18)) + (call $test-stream (i32.const 16) (i32.const 19)) + (call $test-stream (i32.const 16) (i32.const 20)) + (call $test-stream (i32.const 16) (i32.const 21)) + (call $test-stream (i32.const 16) (i32.const 22)) + (call $test-stream (i32.const 16) (i32.const 23)) + (call $test-stream (i32.const 16) (i32.const 24)) + + (i32.const 43) + ) + + (func (export "test-no-read-char") + (local $ret i32) (local $ret64 i64) + (local $rx i32) (local $tx i32) + (local.set $ret64 (call $future.newc)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $future.readc (local.get $rx) (i32.const 0))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (call $future.writec (local.get $tx) (i32.const 0)) + unreachable + ) + + (func (export "test-no-write-char") + (local $ret i32) (local $ret64 i64) + (local $rx i32) (local $tx i32) + (local.set $ret64 (call $future.newc)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (local.set $ret (call $future.writec (local.get $tx) (i32.const 0))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (call $future.readc (local.get $rx) (i32.const 0)) + unreachable + ) + ) + (type $FT (future)) + (type $ST (stream)) + (type $FTB (future u8)) + (type $STB (stream u8)) + (type $FTC (future char)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon future.new $FT (core func $future.new)) + (canon future.read $FT async (core func $future.read)) + (canon future.write $FT async (core func $future.write)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST async (core func $stream.read)) + (canon stream.write $ST async (core func $stream.write)) + (canon future.new $FTB (core func $future.newb)) + (canon future.read $FTB async (memory $memory "mem") (core func $future.readb)) + (canon future.write $FTB async (memory $memory "mem") (core func $future.writeb)) + (canon stream.new $STB (core func $stream.newb)) + (canon stream.read $STB async (memory $memory "mem") (core func $stream.readb)) + (canon stream.write $STB async (memory $memory "mem") (core func $stream.writeb)) + (canon future.new $FTC (core func $future.newc)) + (canon future.read $FTC async (memory $memory "mem") (core func $future.readc)) + (canon future.write $FTC async (memory $memory "mem") (core func $future.writec)) + (core instance $m (instantiate $M (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "future.new" (func $future.new)) + (export "future.read" (func $future.read)) + (export "future.write" (func $future.write)) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "future.newb" (func $future.newb)) + (export "future.readb" (func $future.readb)) + (export "future.writeb" (func $future.writeb)) + (export "stream.newb" (func $stream.newb)) + (export "stream.readb" (func $stream.readb)) + (export "stream.writeb" (func $stream.writeb)) + (export "future.newc" (func $future.newc)) + (export "future.readc" (func $future.readc)) + (export "future.writec" (func $future.writec)) + )))) + (func (export "test-empty") (result u32) (canon lift (core func $m "test-empty"))) + (func (export "test-bytes") (result u32) (canon lift (core func $m "test-bytes"))) + (func (export "test-no-read-char") (canon lift (core func $m "test-no-read-char"))) + (func (export "test-no-write-char") (canon lift (core func $m "test-no-write-char"))) +) +(component instance $i $Tester) +(assert_return (invoke "test-empty") (u32.const 42)) +(component instance $i $Tester) +(assert_return (invoke "test-bytes") (u32.const 43)) +(component instance $i $Tester) +(assert_trap (invoke "test-no-read-char") "cannot read from and write to intra-component future") +(component instance $i $Tester) +(assert_trap (invoke "test-no-write-char") "cannot read from and write to intra-component future") diff --git a/src/test/resources/spec-tests/async/sync-barges-in.wast b/src/test/resources/spec-tests/async/sync-barges-in.wast new file mode 100644 index 0000000..3161f93 --- /dev/null +++ b/src/test/resources/spec-tests/async/sync-barges-in.wast @@ -0,0 +1,311 @@ +;; This test tests that a blocked previous sync- or async-lifted callee +;; can be synchronously reentered by a sync-typed function without the +;; usual backpressure triggering. The $Tester component has two nested +;; components $C and $D, where $D imports and calls $C. $C contains utilities +;; used by $D to perform all the tests. +(component definition $Tester + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "thread.yield" (func $thread.yield (result i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + + (global $unblock-value (mut i32) (i32.const 0)) + + ;; $ws is waited on by 'blocker' and added to by 'unblocker' + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + (func (export "blocker") + ;; wait on $ws, which is initially empty, but will be populated with + ;; a completed future when "unblocker" synchronously barges in. + (local $ret i32) + (local.set $ret (call $waitable-set.wait (global.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (i32.load (i32.const 4))) + (then unreachable)) + + (call $task.return (global.get $unblock-value)) + ) + + (func (export "blocker-cb") (result i32) + ;; wait on $ws, which is initially empty, but will be populated with + ;; a completed future when "unblocker" synchronously barges in. + (i32.or + (i32.const 2 (; WAIT ;)) + (i32.shl (global.get $ws) (i32.const 4))) + ) + (func (export "blocker-cb-cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $payload)) + (then unreachable)) + + (call $task.return (global.get $unblock-value)) + (i32.const 0 (; EXIT ;)) + ) + + (func $unblocker (export "unblocker") (param $val i32) + (local $ret i32) (local $ret64 i64) + (local $futr i32) (local $futw i32) + + ;; create read/write futures that will be used to unblock 'blocker' + (local.set $ret64 (call $future.new)) + (local.set $futr (i32.wrap_i64 (local.get $ret64))) + (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + + ;; perform a future.read which will block, and add this future to the waitable-set + ;; being waited on by 'blocker' + (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + (call $waitable.join (local.get $futr) (global.get $ws)) + + ;; perform a future.write which will rendezvous with the write and complete + (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + (global.set $unblock-value (local.get $val)) + ) + + (func (export "yielder") + (drop (call $thread.yield)) + (call $task.return (global.get $unblock-value)) + ) + (func (export "yielder-cb") (result i32) + (i32.const 1 (; YIELD ;)) + ) + (func (export "yielder-cb-cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + (if (i32.ne (i32.const 0 (; EVENT_NONE ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (i32.const 0) (local.get $index)) + (then unreachable)) + (if (i32.ne (i32.const 0) (local.get $payload)) + (then unreachable)) + (call $task.return (global.get $unblock-value)) + (i32.const 0 (; EXIT ;)) + ) + (func (export "poker") (param $val i32) + (global.set $unblock-value (local.get $val)) + ) + ) + (type $FT (future)) + (canon task.return (result u32) (core func $task.return)) + (canon thread.yield (core func $thread.yield)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon future.new $FT (core func $future.new)) + (canon future.read $FT async (core func $future.read)) + (canon future.write $FT async (core func $future.write)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "thread.yield" (func $thread.yield)) + (export "task.return" (func $task.return)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "future.new" (func $future.new)) + (export "future.read" (func $future.read)) + (export "future.write" (func $future.write)) + )))) + (type $R (resource (rep i32) (dtor (func $cm "unblocker")))) + (type $S (resource (rep i32) (dtor (func $cm "poker")))) + (canon resource.new $R (core func $new-R)) + (canon resource.new $S (core func $new-S)) + (export $R' "R" (type $R)) + (export $S' "S" (type $S)) + (func (export "new-R") (param "rep" u32) (result (own $R')) (canon lift (core func $new-R))) + (func (export "blocker") async (result u32) (canon lift (core func $cm "blocker") async)) + (func (export "blocker-cb") async (result u32) (canon lift (core func $cm "blocker-cb") async (callback (func $cm "blocker-cb-cb")))) + (func (export "unblocker") (param "val" u32) (canon lift (core func $cm "unblocker"))) + (func (export "new-S") (param "rep" u32) (result (own $S')) (canon lift (core func $new-S))) + (func (export "yielder") async (result u32) (canon lift (core func $cm "yielder") async)) + (func (export "yielder-cb") async (result u32) (canon lift (core func $cm "yielder-cb") async (callback (func $cm "yielder-cb-cb")))) + (func (export "poker") (param "val" u32) (canon lift (core func $cm "poker"))) + ) + (component $D + (import "c" (instance $c + (export "R" (type $R (sub resource))) + (export "new-R" (func (param "rep" u32) (result (own $R)))) + (export "blocker" (func async (result u32))) + (export "blocker-cb" (func async (result u32))) + (export "unblocker" (func (param "val" u32))) + (export "S" (type $S (sub resource))) + (export "new-S" (func (param "rep" u32) (result (own $S)))) + (export "yielder" (func async (result u32))) + (export "yielder-cb" (func async (result u32))) + (export "poker" (func (param "val" u32))) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "subtask.drop" (func $subtask.drop (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.drop" (func $waitable-set.drop (param i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "waitable-set.poll" (func $waitable-set.poll (param i32 i32) (result i32))) + (import "" "new-R" (func $new-R (param i32) (result i32))) + (import "" "drop-R" (func $drop-R (param i32))) + (import "" "blocker" (func $blocker (param i32) (result i32))) + (import "" "blocker-cb" (func $blocker-cb (param i32) (result i32))) + (import "" "unblocker" (func $unblocker (param i32))) + (import "" "new-S" (func $new-S (param i32) (result i32))) + (import "" "drop-S" (func $drop-S (param i32))) + (import "" "yielder" (func $yielder (param i32) (result i32))) + (import "" "yielder-cb" (func $yielder-cb (param i32) (result i32))) + (import "" "poker" (func $poker (param i32))) + + (func $wait-for-return (param $subtask i32) (param $retp i32) (param $expect i32) + (local $outp i32) + (local $ws i32) (local $event_code i32) + + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $subtask) (local.get $ws)) + (local.set $outp (i32.const 32)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $outp))) + (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $subtask) (i32.load (local.get $outp))) + (then unreachable)) + (if (i32.ne (i32.const 2 (; RETURNED=2 ;)) (i32.load offset=4 (local.get $outp))) + (then unreachable)) + (if (i32.ne (local.get $expect) (i32.load (local.get $retp))) + (then unreachable)) + (call $subtask.drop (local.get $subtask)) + (call $waitable-set.drop (local.get $ws)) + ) + + (func (export "run") (result i32) + (local $ret i32) (local $retp i32) + (local $subtask i32) (local $handle i32) + + (local.set $retp (i32.const 8)) + + ;; call $blocker which will block during a synchronous function. + ;; normally calling another function would hit backpressure until + ;; $blocker was done, but calling the sync-typed function $unblocker + ;; barges in synchronously. + (local.set $ret (call $blocker (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $unblocker (i32.const 90)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 90)) + + ;; do it all again, but this time unblock via resource.drop: + (local.set $handle (call $new-R (i32.const 91))) + (local.set $ret (call $blocker (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $drop-R (local.get $handle)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 91)) + + ;; do both of the above again, but for $blocker-cb instead of $blocker + (local.set $ret (call $blocker-cb (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $unblocker (i32.const 92)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 92)) + (local.set $handle (call $new-R (i32.const 93))) + (local.set $ret (call $blocker-cb (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $drop-R (local.get $handle)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 93)) + + ;; now do all the above again, but for 'yielder'/'yielder-cb', which + ;; yield, instead of waiting, using 'poker' to deliver a specific value + (local.set $ret (call $yielder (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $poker (i32.const 94)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 94)) + (local.set $handle (call $new-S (i32.const 95))) + (local.set $ret (call $yielder (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $drop-S (local.get $handle)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 95)) + (local.set $ret (call $yielder-cb (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $poker (i32.const 96)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 96)) + (local.set $handle (call $new-S (i32.const 97))) + (local.set $ret (call $yielder-cb (local.get $retp))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) + (call $drop-S (local.get $handle)) + (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 97)) + + (i32.const 100) + ) + ) + (alias export $c "R" (type $R)) + (alias export $c "S" (type $S)) + (canon resource.drop $R (core func $drop-R')) + (canon resource.drop $S (core func $drop-S')) + (canon subtask.drop (core func $subtask.drop)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.drop (core func $waitable-set.drop)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon waitable-set.poll (memory $memory "mem") (core func $waitable-set.poll)) + (canon lower (func $c "new-R") (core func $new-R')) + (canon lower (func $c "blocker") (memory $memory "mem") async (core func $blocker')) + (canon lower (func $c "blocker-cb") (memory $memory "mem") async (core func $blocker-cb')) + (canon lower (func $c "unblocker") (core func $unblocker')) + (canon lower (func $c "new-S") (core func $new-S')) + (canon lower (func $c "yielder") (memory $memory "mem") async (core func $yielder')) + (canon lower (func $c "yielder-cb") (memory $memory "mem") async (core func $yielder-cb')) + (canon lower (func $c "poker") (core func $poker')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "subtask.drop" (func $subtask.drop)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.drop" (func $waitable-set.drop)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "waitable-set.poll" (func $waitable-set.poll)) + (export "new-R" (func $new-R')) + (export "drop-R" (func $drop-R')) + (export "blocker" (func $blocker')) + (export "blocker-cb" (func $blocker-cb')) + (export "unblocker" (func $unblocker')) + (export "new-S" (func $new-S')) + (export "drop-S" (func $drop-S')) + (export "yielder" (func $yielder')) + (export "yielder-cb" (func $yielder-cb')) + (export "poker" (func $poker')) + )))) + (func (export "run") async (result u32) (canon lift (core func $core "run"))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "run") (alias export $d "run")) +) + +(component instance $i $Tester) +(assert_return (invoke "run") (u32.const 100)) diff --git a/src/test/resources/spec-tests/async/sync-streams.wast b/src/test/resources/spec-tests/async/sync-streams.wast new file mode 100644 index 0000000..364ba9c --- /dev/null +++ b/src/test/resources/spec-tests/async/sync-streams.wast @@ -0,0 +1,178 @@ +;; This test calls sync stream.write in $C.get and sync stream.read in $C.set. +;; Both of these calls block because $C is first to the rendezvous. But since +;; they are synchronous, control flow switches to $D.run which will do +;; a complementary read/write that rendezvous, and then control flow will +;; switch back to $C.get/set where the synchronous read/write will return +;; without blocking. +(component + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.return0" (func $task.return0)) + (import "" "task.return1" (func $task.return1 (param i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + (func (export "get") (result i32) + (local $ret i32) (local $ret64 i64) + (local $tx i32) (local $rx i32) + (local $bufp i32) + + ;; ($rx, $tx) = stream.new + (local.set $ret64 (call $stream.new)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + + ;; return $rx + (call $task.return1 (local.get $rx)) + + ;; (stream.write $tx $bufp 4) will block and, because called + ;; synchronously, switch to the caller who will read and rendezvous + (local.set $bufp (i32.const 16)) + (i32.store (local.get $bufp) (i32.const 0x01234567)) + (local.set $ret (call $stream.write (local.get $tx) (local.get $bufp) (i32.const 4))) + (if (i32.ne (i32.const 0x41 (; DROPPED=1 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + + (call $stream.drop-writable (local.get $tx)) + (return (i32.const 0 (; EXIT ;))) + ) + (func (export "get_cb") (param i32 i32 i32) (result i32) + unreachable + ) + + (func (export "set") (param $rx i32) (result i32) + (local $ret i32) (local $ret64 i64) + (local $bufp i32) + + ;; return immediately so that the caller can just call synchronously + (call $task.return0) + + ;; (stream.read $rx $bufp 4) will block and, because called + ;; synchronously, switch to the caller who will write and rendezvous + (local.set $bufp (i32.const 16)) + (local.set $ret (call $stream.read (local.get $rx) (local.get $bufp) (i32.const 4))) + (if (i32.ne (i32.const 0x41 (; DROPPED=1 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0x89abcdef) (i32.load (local.get $bufp))) + (then unreachable)) + + (call $stream.drop-readable (local.get $rx)) + (return (i32.const 0 (; EXIT ;))) + ) + (func (export "set_cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (type $ST (stream u8)) + (canon task.return (memory $memory "mem") (core func $task.return0)) + (canon task.return (result $ST) (memory $memory "mem") (core func $task.return1)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return0" (func $task.return0)) + (export "task.return1" (func $task.return1)) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (func (export "get") async (result (stream u8)) (canon lift + (core func $cm "get") + async (memory $memory "mem") (callback (func $cm "get_cb")) + )) + (func (export "set") async (param "in" (stream u8)) (canon lift + (core func $cm "set") + async (memory $memory "mem") (callback (func $cm "set_cb")) + )) + ) + (component $D + (import "get" (func $get async (result (stream u8)))) + (import "set" (func $set async (param "in" (stream u8)))) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + (import "" "get" (func $get (result i32))) + (import "" "set" (func $set (param i32))) + + (func (export "run") (result i32) + (local $ret i32) (local $ret64 i64) + (local $rx i32) (local $tx i32) + (local $bufp i32) + + ;; $rx = $C.get() + (local.set $rx (call $get)) + + ;; (stream.read $rx $bufp 4) will succeed without blocking + (local.set $bufp (i32.const 20)) + (local.set $ret (call $stream.read (local.get $rx) (local.get $bufp) (i32.const 4))) + (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0x01234567) (i32.load (local.get $bufp))) + (then unreachable)) + + (call $stream.drop-readable (local.get $rx)) + + ;; ($rx, $tx) = stream.new + ;; $C.set($rx) + (local.set $ret64 (call $stream.new)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (call $set (local.get $rx)) + + ;; (stream.write $tx $bufp 4) will succeed without blocking + (local.set $bufp (i32.const 16)) + (local.set $ret (call $stream.write (local.get $tx) (local.get $bufp) (i32.const 4))) + (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) + (then unreachable)) + + (call $stream.drop-writable (local.get $tx)) + (i32.const 42) + ) + ) + (type $ST (stream u8)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (canon lower (func $get) (core func $get')) + (canon lower (func $set) (core func $set')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "stream.drop-writable" (func $stream.drop-writable)) + (export "get" (func $get')) + (export "set" (func $set')) + )))) + (func (export "run") async (result u32) (canon lift (core func $dm "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D + (with "get" (func $c "get")) + (with "set" (func $c "set")) + )) + (func (export "run") (alias export $d "run")) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/trap-if-block-and-sync.wast b/src/test/resources/spec-tests/async/trap-if-block-and-sync.wast new file mode 100644 index 0000000..14d81ff --- /dev/null +++ b/src/test/resources/spec-tests/async/trap-if-block-and-sync.wast @@ -0,0 +1,334 @@ +;; The $Tester component has two nested components $C and $D, where $D imports +;; and calls $C. $C contains utilities used by $D to perform all the tests. +;; Most of the tests trap, $Tester exports 1 function per test and a fresh +;; $Tester is created to run each test. +(component definition $Tester + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (func (export "sync-async-func") + unreachable + ) + (func (export "async-async-func") (result i32) + unreachable + ) + (func (export "async-async-func-cb") (param i32 i32 i32) (result i32) + unreachable + ) + (func (export "sync-blocks-and-traps") + (call $waitable-set.wait (call $waitable-set.new) (i32.const 0xdeadbeef)) + unreachable + ) + ) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (core instance $cm (instantiate $CM (with "" (instance + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + )))) + (func (export "sync-async-func") async (canon lift (core func $cm "sync-async-func"))) + (func (export "async-async-func") async (canon lift (core func $cm "async-async-func") async (callback (func $cm "async-async-func-cb")))) + (func (export "sync-blocks-and-traps") (canon lift (core func $cm "sync-blocks-and-traps"))) + ) + (component $D + (import "c" (instance $c + (export "sync-async-func" (func async)) + (export "async-async-func" (func async)) + (export "sync-blocks-and-traps" (func)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core module $Table + (table (export "__indirect_function_table") 2 funcref)) + (core instance $memory (instantiate $Memory)) + (core instance $table (instantiate $Table)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) + (import "" "thread.yield" (func $thread.yield (result i32))) + ;;(import "" "thread.yield-to" (func $thread.yield-to (param i32) (result i32))) + ;;(import "" "thread.switch-to" (func $thread.switch-to (param i32) (result i32))) + ;;(import "" "thread.resume-later" (func $thread.resume-later (param i32))) + (import "" "thread.index" (func $thread-index (result i32))) + (import "" "thread.suspend" (func $thread.suspend (result i32))) + (import "" "thread.new-indirect" (func $thread.new-indirect (param i32 i32) (result i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "waitable-set.poll" (func $waitable-set.poll (param i32 i32) (result i32))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "stream.cancel-read" (func $stream.cancel-read (param i32) (result i32))) + (import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32))) + (import "" "future.cancel-read" (func $future.cancel-read (param i32) (result i32))) + (import "" "future.cancel-write" (func $future.cancel-write (param i32) (result i32))) + (import "" "await-sync-async-func" (func $await-sync-async-func)) + (import "" "await-async-async-func" (func $await-async-async-func)) + (import "" "sync-blocks-and-traps" (func $sync-blocks-and-traps)) + (import "" "__indirect_function_table" (table $indirect-function-table 2 funcref)) + + (func (export "unreachable-cb") (param i32 i32 i32) (result i32) + unreachable + ) + (func (export "return-42-cb") (param i32 i32 i32) (result i32) + (call $task.return (i32.const 42)) + (i32.const 0 (; EXIT ;)) + ) + + (func (export "trap-if-sync-call-async1") + (call $await-sync-async-func) + ) + (func (export "trap-if-sync-call-async2") + (call $await-async-async-func) + ) + (func (export "trap-if-async-calls-sync-and-blocks") (result i32) + (call $sync-blocks-and-traps) + unreachable + ) + (func (export "trap-if-suspend") + (call $thread.suspend) + unreachable + ) + (func (export "trap-if-wait") + (call $waitable-set.wait (call $waitable-set.new) (i32.const 0xdeadbeef)) + unreachable + ) + (func (export "poll-is-fine") (result i32) + (local $ret i32) + (local.set $ret (call $waitable-set.poll (call $waitable-set.new) (i32.const 0))) + (if (i32.ne (i32.const 0 (; NONE ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 0) (i32.load (i32.const 0))) + (then unreachable)) + (if (i32.ne (i32.const 0) (i32.load (i32.const 4))) + (then unreachable)) + (i32.const 42) + ) + (func (export "trap-if-invalid-callback-code") (param $invalid-code i32) (result i32) + (i32.or + (local.get $invalid-code) + (i32.shl (call $waitable-set.new) (i32.const 4))) + ) + (func (export "yield-is-fine") (result i32) + (drop (call $thread.yield)) + (i32.const 42) + ) + (func (export "yield-is-fine-cb") (result i32) + (i32.or + (i32.const 1 (; YIELD ;)) + (i32.shl (i32.const 0xdead) (i32.const 4))) + ) + (func $thread-start-noop (param i32)) + (elem (table $indirect-function-table) (i32.const 0) func $thread-start-noop) + (func (export "yield-to-is-fine") (result i32) + ;; TODO: rename and reenable + ;;(drop (call $thread.yield-to (call $thread.new-indirect (i32.const 0) (i32.const 0)))) + (i32.const 42) + ) + (func $thread-start-switch-back (param i32) + ;;(drop (call $thread.switch-to (local.get 0))) + ) + (elem (table $indirect-function-table) (i32.const 1) func $thread-start-switch-back) + (func (export "switch-to-is-fine") (result i32) + ;; TODO: rename and reenable + ;;(drop (call $thread.switch-to (call $thread.new-indirect (i32.const 1) (call $thread-index)))) + (i32.const 42) + ) + (func (export "resume-later-is-fine") (result i32) + ;; TODO: rename and reenable + ;;(call $thread.resume-later (call $thread.new-indirect (i32.const 0) (i32.const 0))) + (i32.const 42) + ) + (func (export "trap-if-sync-cancel") + (call $subtask.cancel (i32.const 0xdeadbeef)) + unreachable + ) + (func (export "trap-if-sync-stream-read") + (call $stream.read (i32.const 0xdead) (i32.const 0xbeef) (i32.const 0xdead)) + unreachable + ) + (func (export "trap-if-sync-stream-write") + (call $stream.write (i32.const 0xdead) (i32.const 0xbeef) (i32.const 0xdead)) + unreachable + ) + (func (export "trap-if-sync-future-read") + (call $future.read (i32.const 0xdead) (i32.const 0xdeadbeef)) + unreachable + ) + (func (export "trap-if-sync-future-write") + (call $future.write (i32.const 0xdead) (i32.const 0xdeadbeef)) + unreachable + ) + (func (export "trap-if-sync-stream-cancel-read") + (call $stream.cancel-read (i32.const 0xdead)) + unreachable + ) + (func (export "trap-if-sync-stream-cancel-write") + (call $stream.cancel-write (i32.const 0xdead)) + unreachable + ) + (func (export "trap-if-sync-future-cancel-read") + (call $future.cancel-read (i32.const 0xdead) (i32.const 0xdeadbeef)) + unreachable + ) + (func (export "trap-if-sync-future-cancel-write") + (call $future.cancel-write (i32.const 0xdead) (i32.const 0xdeadbeef)) + unreachable + ) + ) + (type $FT (future u8)) + (type $ST (stream u8)) + (core type $start-func-ty (func (param i32))) + (alias core export $table "__indirect_function_table" (core table $indirect-function-table)) + (core func $thread.new-indirect + (canon thread.new-indirect $start-func-ty (table $indirect-function-table))) + (canon task.return (result u32) (core func $task.return)) + (canon subtask.cancel (core func $subtask.cancel)) + (canon thread.yield (core func $thread.yield)) + (canon thread.suspend (core func $thread.suspend)) + ;;(canon thread.yield-to (core func $thread.yield-to)) + ;;(canon thread.switch-to (core func $thread.switch-to)) + ;;(canon thread.resume-later (core func $thread.resume-later)) + (canon thread.index (core func $thread.index)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon waitable-set.poll (memory $memory "mem") (core func $waitable-set.poll)) + (canon stream.read $ST (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST (memory $memory "mem") (core func $stream.write)) + (canon future.read $FT (memory $memory "mem") (core func $future.read)) + (canon future.write $FT (memory $memory "mem") (core func $future.write)) + (canon stream.cancel-read $ST (core func $stream.cancel-read)) + (canon stream.cancel-write $ST (core func $stream.cancel-write)) + (canon future.cancel-read $FT (core func $future.cancel-read)) + (canon future.cancel-write $FT (core func $future.cancel-write)) + (canon lower (func $c "sync-async-func") (core func $await-sync-async-func')) + (canon lower (func $c "async-async-func") (core func $await-async-async-func')) + (canon lower (func $c "sync-blocks-and-traps") (core func $sync-blocks-and-traps')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "subtask.cancel" (func $subtask.cancel)) + (export "thread.yield" (func $thread.yield)) + (export "thread.suspend" (func $thread.suspend)) + ;;(export "thread.yield-to" (func $thread.yield-to)) + ;;(export "thread.switch-to" (func $thread.switch-to)) + ;;(export "thread.resume-later" (func $thread.resume-later)) + (export "thread.index" (func $thread.index)) + (export "thread.new-indirect" (func $thread.new-indirect)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "waitable-set.poll" (func $waitable-set.poll)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "future.read" (func $future.read)) + (export "future.write" (func $future.write)) + (export "stream.cancel-read" (func $stream.cancel-read)) + (export "stream.cancel-write" (func $stream.cancel-write)) + (export "future.cancel-read" (func $future.cancel-read)) + (export "future.cancel-write" (func $future.cancel-write)) + (export "await-sync-async-func" (func $await-sync-async-func')) + (export "await-async-async-func" (func $await-async-async-func')) + (export "sync-blocks-and-traps" (func $sync-blocks-and-traps')) + (export "__indirect_function_table" (table $indirect-function-table)) + )))) + (func (export "trap-if-suspend") (canon lift (core func $core "trap-if-suspend"))) + (func (export "trap-if-wait") (canon lift (core func $core "trap-if-wait"))) + (func (export "poll-is-fine") (result u32) (canon lift (core func $core "poll-is-fine"))) + (func (export "trap-if-invalid-callback-code") async (param "invalid-code" u32) (canon lift (core func $core "trap-if-invalid-callback-code") async (callback (func $core "unreachable-cb")))) + (func (export "yield-is-fine") (result u32) (canon lift (core func $core "yield-is-fine"))) + (func (export "yield-is-fine-cb") async (result u32) (canon lift (core func $core "yield-is-fine-cb") async (callback (func $core "return-42-cb")))) + (func (export "yield-to-is-fine") (result u32) (canon lift (core func $core "yield-to-is-fine"))) + (func (export "switch-to-is-fine") (result u32) (canon lift (core func $core "switch-to-is-fine"))) + (func (export "resume-later-is-fine") (result u32) (canon lift (core func $core "resume-later-is-fine"))) + (func (export "trap-if-sync-call-async1") (canon lift (core func $core "trap-if-sync-call-async1"))) + (func (export "trap-if-sync-call-async2") (canon lift (core func $core "trap-if-sync-call-async2"))) + (func (export "trap-if-async-calls-sync-and-blocks") async (canon lift (core func $core "trap-if-async-calls-sync-and-blocks") async (callback (func $core "unreachable-cb")))) + (func (export "trap-if-sync-cancel") (canon lift (core func $core "trap-if-sync-cancel"))) + (func (export "trap-if-sync-stream-read") (canon lift (core func $core "trap-if-sync-stream-read"))) + (func (export "trap-if-sync-stream-write") (canon lift (core func $core "trap-if-sync-stream-write"))) + (func (export "trap-if-sync-future-read") (canon lift (core func $core "trap-if-sync-future-read"))) + (func (export "trap-if-sync-future-write") (canon lift (core func $core "trap-if-sync-future-write"))) + (func (export "trap-if-sync-stream-cancel-read") (canon lift (core func $core "trap-if-sync-stream-cancel-read"))) + (func (export "trap-if-sync-stream-cancel-write") (canon lift (core func $core "trap-if-sync-stream-cancel-write"))) + (func (export "trap-if-sync-future-cancel-read") (canon lift (core func $core "trap-if-sync-future-cancel-read"))) + (func (export "trap-if-sync-future-cancel-write") (canon lift (core func $core "trap-if-sync-future-cancel-write"))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "trap-if-sync-call-async1") (alias export $d "trap-if-sync-call-async1")) + (func (export "trap-if-sync-call-async2") (alias export $d "trap-if-sync-call-async2")) + (func (export "trap-if-async-calls-sync-and-blocks") (alias export $d "trap-if-async-calls-sync-and-blocks")) + (func (export "trap-if-suspend") (alias export $d "trap-if-suspend")) + (func (export "trap-if-wait") (alias export $d "trap-if-wait")) + (func (export "poll-is-fine") (alias export $d "poll-is-fine")) + (func (export "trap-if-invalid-callback-code") (alias export $d "trap-if-invalid-callback-code")) + (func (export "yield-is-fine") (alias export $d "yield-is-fine")) + (func (export "yield-is-fine-cb") (alias export $d "yield-is-fine-cb")) + (func (export "yield-to-is-fine") (alias export $d "yield-to-is-fine")) + (func (export "switch-to-is-fine") (alias export $d "switch-to-is-fine")) + (func (export "resume-later-is-fine") (alias export $d "resume-later-is-fine")) + (func (export "trap-if-sync-cancel") (alias export $d "trap-if-sync-cancel")) + (func (export "trap-if-sync-stream-read") (alias export $d "trap-if-sync-stream-read")) + (func (export "trap-if-sync-stream-write") (alias export $d "trap-if-sync-stream-write")) + (func (export "trap-if-sync-future-read") (alias export $d "trap-if-sync-future-read")) + (func (export "trap-if-sync-future-write") (alias export $d "trap-if-sync-future-write")) + (func (export "trap-if-sync-stream-cancel-read") (alias export $d "trap-if-sync-stream-cancel-read")) + (func (export "trap-if-sync-stream-cancel-write") (alias export $d "trap-if-sync-stream-cancel-write")) + (func (export "trap-if-sync-future-cancel-read") (alias export $d "trap-if-sync-future-cancel-read")) + (func (export "trap-if-sync-future-cancel-write") (alias export $d "trap-if-sync-future-cancel-write")) +) + +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-call-async1") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-call-async2") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-async-calls-sync-and-blocks") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-suspend") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-wait") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_return (invoke "poll-is-fine") (u32.const 42)) +(component instance $i $Tester) +(assert_trap (invoke "trap-if-invalid-callback-code" (u32.const 3)) "unsupported callback code") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-invalid-callback-code" (u32.const 4)) "unsupported callback code") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-invalid-callback-code" (u32.const 15)) "unsupported callback code") +(component instance $i $Tester) +(assert_return (invoke "yield-is-fine") (u32.const 42)) +(component instance $i $Tester) +(assert_return (invoke "yield-is-fine-cb") (u32.const 42)) +(component instance $i $Tester) +(assert_return (invoke "yield-to-is-fine") (u32.const 42)) +(component instance $i $Tester) +(assert_return (invoke "switch-to-is-fine") (u32.const 42)) +(component instance $i $Tester) +(assert_return (invoke "resume-later-is-fine") (u32.const 42)) +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-cancel") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-stream-read") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-stream-write") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-future-read") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-future-write") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-stream-cancel-read") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-stream-cancel-write") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-future-cancel-read") "cannot block a synchronous task before returning") +(component instance $i $Tester) +(assert_trap (invoke "trap-if-sync-future-cancel-write") "cannot block a synchronous task before returning") diff --git a/src/test/resources/spec-tests/async/trap-if-done.wast b/src/test/resources/spec-tests/async/trap-if-done.wast new file mode 100644 index 0000000..8f84cd3 --- /dev/null +++ b/src/test/resources/spec-tests/async/trap-if-done.wast @@ -0,0 +1,470 @@ +;; This test has two components $C and $D, where $D imports and calls $C. +;; $C contains utility functions used by $D to create futures/streams, +;; write to them and close them. $D uses these utility functions to test for +;; all the cases where, once a future/stream is "done", further uses of the +;; future/stream trap. +;; +;; $D exports a list of functions, one for each case of trapping. Since traps +;; take out their containing instance, a fresh instance of $Tester is created +;; for each call to a $D export. +;; +;; When testing traps involving the readable end, the exports of $D take a +;; "bool" parameter that toggles whether the trap is triggered by +;; {stream,future}.{read,write} or by lifting, and the top-level commands +;; pass 'false' and 'true'. +(component definition $Tester + (component $C + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "future.drop-writable" (func $future.drop-writable (param i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + (global $writable-end (mut i32) (i32.const 0)) + (global $ws (mut i32) (i32.const 0)) + + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + (func $start-future (export "start-future") (result i32) + ;; create a new future, return the readable end to the caller + (local $ret64 i64) + (local.set $ret64 (call $future.new)) + (global.set $writable-end (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (call $waitable.join (global.get $writable-end) (global.get $ws) ) + (i32.wrap_i64 (local.get $ret64)) + ) + (func $future-write (export "future-write") (result i32) + ;; the caller will assert what they expect the return value to be + (i32.store (i32.const 16) (i32.const 42)) + (call $future.write (global.get $writable-end) (i32.const 16)) + ) + (func $acknowledge-future-write (export "acknowledge-future-write") + ;; confirm we got a FUTURE_WRITE $writable-end COMPLETED event + (local $ret i32) + (local.set $ret (call $waitable-set.wait (global.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 5 (; FUTURE_WRITE ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (global.get $writable-end) (i32.load (i32.const 0))) + (then unreachable)) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (i32.load (i32.const 4))) + (then unreachable)) + ) + (func $future-drop-writable (export "future-drop-writable") + ;; maybe boom + (call $future.drop-writable (global.get $writable-end)) + ) + + (func $start-stream (export "start-stream") (result i32) + ;; create a new stream, return the readable end to the caller + (local $ret64 i64) + (local.set $ret64 (call $stream.new)) + (global.set $writable-end (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + (call $waitable.join (global.get $writable-end) (global.get $ws) ) + (i32.wrap_i64 (local.get $ret64)) + ) + (func $stream-write (export "stream-write") (result i32) + ;; the caller will assert what they expect the return value to be + (i32.store (i32.const 16) (i32.const 42)) + (call $stream.write (global.get $writable-end) (i32.const 16) (i32.const 1)) + ) + (func $acknowledge-stream-write (export "acknowledge-stream-write") + ;; confirm we got a STREAM_WRITE $writable-end COMPLETED event + (local $ret i32) + (local.set $ret (call $waitable-set.wait (global.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 3 (; STREAM_WRITE ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (global.get $writable-end) (i32.load (i32.const 0))) + (then unreachable)) + (if (i32.ne (i32.const 0x11 (; DROPPED=1 | (1<<4) ;)) (i32.load (i32.const 4))) + (then unreachable)) + ) + (func $stream-drop-writable (export "stream-drop-writable") + ;; maybe boom + (call $stream.drop-writable (global.get $writable-end)) + ) + ) + (type $FT (future u8)) + (type $ST (stream u8)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon future.new $FT (core func $future.new)) + (canon future.write $FT async (memory $memory "mem") (core func $future.write)) + (canon future.drop-writable $FT (core func $future.drop-writable)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "future.new" (func $future.new)) + (export "future.write" (func $future.write)) + (export "future.drop-writable" (func $future.drop-writable)) + (export "stream.new" (func $stream.new)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (func (export "start-future") async (result (future u8)) (canon lift (core func $cm "start-future"))) + (func (export "future-write") async (result u32) (canon lift (core func $cm "future-write"))) + (func (export "acknowledge-future-write") async (canon lift (core func $cm "acknowledge-future-write"))) + (func (export "future-drop-writable") async (canon lift (core func $cm "future-drop-writable"))) + (func (export "start-stream") async (result (stream u8)) (canon lift (core func $cm "start-stream"))) + (func (export "stream-write") async (result u32) (canon lift (core func $cm "stream-write"))) + (func (export "acknowledge-stream-write") async (canon lift (core func $cm "acknowledge-stream-write"))) + (func (export "stream-drop-writable") async (canon lift (core func $cm "stream-drop-writable"))) + ) + (component $D + (import "c" (instance $c + (export "start-future" (func async (result (future u8)))) + (export "future-write" (func async (result u32))) + (export "acknowledge-future-write" (func async)) + (export "future-drop-writable" (func async)) + (export "start-stream" (func async (result (stream u8)))) + (export "stream-write" (func async (result u32))) + (export "acknowledge-stream-write" (func async)) + (export "stream-drop-writable" (func async)) + )) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $Core + (import "" "mem" (memory 1)) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.drop-readable" (func $future.drop-readable (param i32))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "start-future" (func $start-future (result i32))) + (import "" "future-write" (func $future-write (result i32))) + (import "" "acknowledge-future-write" (func $acknowledge-future-write)) + (import "" "future-drop-writable" (func $future-drop-writable)) + (import "" "start-stream" (func $start-stream (result i32))) + (import "" "stream-write" (func $stream-write (result i32))) + (import "" "acknowledge-stream-write" (func $acknowledge-stream-write)) + (import "" "stream-drop-writable" (func $stream-drop-writable)) + + (func $trap-after-future-eager-write (export "trap-after-future-eager-write") + (local $ret i32) + (local $fr i32) + (local.set $fr (call $start-future)) + + ;; start a read on our end so the next write will succeed + (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; calling future.write in $C should succeed eagerly + (local.set $ret (call $future-write)) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) + (then unreachable)) + + ;; calling future.write in $C now should trap + (drop (call $future-write)) + ) + (func $trap-after-future-async-write (export "trap-after-future-async-write") + (local $ret i32) + (local $fr i32) + (local.set $fr (call $start-future)) + + ;; calling future.write in $C should block + (local.set $ret (call $future-write)) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; our future.read should then succeed eagerly + (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) + (then unreachable)) + + ;; let $C see the write completed so the future is 'done' + (call $acknowledge-future-write) + + ;; trying to call future.write again in $C should trap + (drop (call $future-write)) + ) + (func $trap-after-future-reader-dropped (export "trap-after-future-reader-dropped") + (local $ret i32) + (local $fr i32) + (local.set $fr (call $start-future)) + + ;; drop our readable end before writer can write + (call $future.drop-readable (local.get $fr)) + + ;; let $C try to future.write and find out we DROPPED + (local.set $ret (call $future-write)) + (if (i32.ne (i32.const 1 (; DROPPED ;)) (local.get $ret)) + (then unreachable)) + + ;; trying to call future.write again in $C should trap + (drop (call $future-write)) + ) + (func $trap-after-future-eager-read (export "trap-after-future-eager-read") (param $bool i32) (result i32) + (local $ret i32) + (local $fr i32) + (local.set $fr (call $start-future)) + + ;; calling future.write in $C should block + (local.set $ret (call $future-write)) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; our future.read should then succeed eagerly + (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) + (then unreachable)) + + (if (i32.eqz (local.get $bool)) (then + ;; calling future.read again should then trap + (drop (call $future.read (local.get $fr) (i32.const 16))) + ) (else + ;; lifting the future by returning it should also trap + (return (local.get $fr)) + )) + unreachable + ) + (func $trap-after-future-async-read (export "trap-after-future-async-read") (param $bool i32) (result i32) + (local $ret i32) (local $ws i32) + (local $fr i32) + (local.set $fr (call $start-future)) + + ;; read first, so it blocks + (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; calling future.write in $C should then succeed eagerly + (local.set $ret (call $future-write)) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) + (then unreachable)) + + ;; wait to see that our blocked future.read COMPLETED, producing '42' + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $fr) (local.get $ws)) + (local.set $ret (call $waitable-set.wait (local.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (local.get $fr) (i32.load (i32.const 0))) + (then unreachable)) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (i32.load (i32.const 4))) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load (i32.const 16))) + (then unreachable)) + + (call $waitable.join (local.get $fr) (i32.const 0)) + + (if (i32.eqz (local.get $bool)) (then + ;; calling future.read again should then trap + (drop (call $future.read (local.get $fr) (i32.const 16))) + ) (else + ;; lifting the future by returning it should also trap + (return (local.get $fr)) + )) + unreachable + ) + (func $trap-after-stream-reader-eager-dropped (export "trap-after-stream-reader-eager-dropped") + (local $ret i32) + (local $sr i32) + (local.set $sr (call $start-stream)) + + ;; drop our readable end before writer can write + (call $stream.drop-readable (local.get $sr)) + + ;; let $C try to stream.write and find out we DROPPED + (local.set $ret (call $stream-write)) + (if (i32.ne (i32.const 1 (; DROPPED ;)) (local.get $ret)) + (then unreachable)) + + ;; trying to call stream.write again in $C should trap + (drop (call $stream-write)) + ) + (func $trap-after-stream-reader-async-dropped (export "trap-after-stream-reader-async-dropped") + (local $ret i32) + (local $sr i32) + (local.set $sr (call $start-stream)) + + ;; calling stream.write in $C should block + (local.set $ret (call $stream-write)) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; our stream.read should then succeed eagerly + (local.set $ret (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) + (if (i32.ne (i32.const 0x10 (; COMPLETED=0 | (1<<4) ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) + (then unreachable)) + + ;; then drop our readable end + (call $stream.drop-readable (local.get $sr)) + + ;; let $C see that it's stream.write COMPLETED and wrote 1 elem + (call $acknowledge-stream-write) + + ;; now calling stream.write again in $C will trap + (drop (call $stream-write)) + ) + (func $trap-after-stream-writer-eager-dropped (export "trap-after-stream-writer-eager-dropped") (param $bool i32) (result i32) + (local $ret i32) + (local $sr i32) + (local.set $sr (call $start-stream)) + + ;; immediately drop the writable end + (call $stream-drop-writable) + + ;; calling stream.read will see that the writer dropped + (local.set $ret (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) + (if (i32.ne (i32.const 0x01 (; DROPPED=1 | (0<<4) ;)) (local.get $ret)) + (then unreachable)) + + (if (i32.eqz (local.get $bool)) (then + ;; calling stream.read again should then trap + (drop (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) + ) (else + ;; lifting the stream by returning it should also trap + (return (local.get $sr)) + )) + unreachable + ) + (func $trap-after-stream-writer-async-dropped (export "trap-after-stream-writer-async-dropped") (param $bool i32) (result i32) + (local $ret i32) (local $ws i32) + (local $sr i32) + (local.set $sr (call $start-stream)) + + ;; start a read on our end first which will block + (local.set $ret (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; drop the writable end before writing anything + (call $stream-drop-writable) + + ;; wait to see that our blocked stream.read was DROPPED + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $sr) (local.get $ws)) + (local.set $ret (call $waitable-set.wait (local.get $ws) (i32.const 0))) + (if (i32.ne (i32.const 2 (; STREAM_READ ;)) (local.get $ret)) + (then unreachable)) + (if (i32.ne (local.get $sr) (i32.load (i32.const 0))) + (then unreachable)) + (if (i32.ne (i32.const 0x01 (; DROPPED=1 | (0<<4) ;)) (i32.load (i32.const 4))) + (then unreachable)) + + (if (i32.eqz (local.get $bool)) (then + ;; calling stream.read again should then trap + (drop (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) + ) (else + ;; lifting the stream by returning it should also trap + (return (local.get $sr)) + )) + unreachable + ) + ) + (type $FT (future u8)) + (type $ST (stream u8)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon future.new $FT (core func $future.new)) + (canon future.read $FT async (memory $memory "mem") (core func $future.read)) + (canon future.drop-readable $FT (core func $future.drop-readable)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon lower (func $c "start-future") (core func $start-future')) + (canon lower (func $c "future-write") (core func $future-write')) + (canon lower (func $c "acknowledge-future-write") (core func $acknowledge-future-write')) + (canon lower (func $c "future-drop-writable") (core func $future-drop-writable')) + (canon lower (func $c "start-stream") (core func $start-stream')) + (canon lower (func $c "stream-write") (core func $stream-write')) + (canon lower (func $c "acknowledge-stream-write") (core func $acknowledge-stream-write')) + (canon lower (func $c "stream-drop-writable") (core func $stream-drop-writable')) + (core instance $core (instantiate $Core (with "" (instance + (export "mem" (memory $memory "mem")) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "future.new" (func $future.new)) + (export "future.read" (func $future.read)) + (export "future.drop-readable" (func $future.drop-readable)) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "start-future" (func $start-future')) + (export "future-write" (func $future-write')) + (export "acknowledge-future-write" (func $acknowledge-future-write')) + (export "future-drop-writable" (func $future-drop-writable')) + (export "start-stream" (func $start-stream')) + (export "stream-write" (func $stream-write')) + (export "acknowledge-stream-write" (func $acknowledge-stream-write')) + (export "stream-drop-writable" (func $stream-drop-writable')) + )))) + (func (export "trap-after-future-eager-write") async (canon lift (core func $core "trap-after-future-eager-write"))) + (func (export "trap-after-future-async-write") async (canon lift (core func $core "trap-after-future-async-write"))) + (func (export "trap-after-future-reader-dropped") async (canon lift (core func $core "trap-after-future-reader-dropped"))) + (func (export "trap-after-future-eager-read") async (param "bool" bool) (result $FT) (canon lift (core func $core "trap-after-future-eager-read"))) + (func (export "trap-after-future-async-read") async (param "bool" bool) (result $FT) (canon lift (core func $core "trap-after-future-async-read"))) + (func (export "trap-after-stream-reader-eager-dropped") async (canon lift (core func $core "trap-after-stream-reader-eager-dropped"))) + (func (export "trap-after-stream-reader-async-dropped") async (canon lift (core func $core "trap-after-stream-reader-async-dropped"))) + (func (export "trap-after-stream-writer-eager-dropped") async (param "bool" bool) (result $ST) (canon lift (core func $core "trap-after-stream-writer-eager-dropped"))) + (func (export "trap-after-stream-writer-async-dropped") async (param "bool" bool) (result $ST) (canon lift (core func $core "trap-after-stream-writer-async-dropped"))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "trap-after-future-eager-write") (alias export $d "trap-after-future-eager-write")) + (func (export "trap-after-future-async-write") (alias export $d "trap-after-future-async-write")) + (func (export "trap-after-future-reader-dropped") (alias export $d "trap-after-future-reader-dropped")) + (func (export "trap-after-future-eager-read") (alias export $d "trap-after-future-eager-read")) + (func (export "trap-after-future-async-read") (alias export $d "trap-after-future-async-read")) + (func (export "trap-after-stream-reader-eager-dropped") (alias export $d "trap-after-stream-reader-eager-dropped")) + (func (export "trap-after-stream-reader-async-dropped") (alias export $d "trap-after-stream-reader-async-dropped")) + (func (export "trap-after-stream-writer-eager-dropped") (alias export $d "trap-after-stream-writer-eager-dropped")) + (func (export "trap-after-stream-writer-async-dropped") (alias export $d "trap-after-stream-writer-async-dropped")) +) + +(component instance $i1 $Tester) +(assert_trap (invoke "trap-after-future-eager-write") "cannot write to future after previous write succeeded") +(component instance $i2 $Tester) +(assert_trap (invoke "trap-after-future-async-write") "cannot write to future after previous write succeeded") +(component instance $i3 $Tester) +(assert_trap (invoke "trap-after-future-reader-dropped") "cannot write to future after previous write succeeded or readable end dropped") +(component instance $i4.1 $Tester) +(assert_trap (invoke "trap-after-future-eager-read" (bool.const false)) "cannot read from future after previous read succeeded") +(component instance $i4.2 $Tester) +(assert_trap (invoke "trap-after-future-eager-read" (bool.const true)) "cannot lift future after previous read succeeded") +(component instance $i5.1 $Tester) +(assert_trap (invoke "trap-after-future-async-read" (bool.const false)) "cannot read from future after previous read succeeded") +(component instance $i5.2 $Tester) +(assert_trap (invoke "trap-after-future-async-read" (bool.const true)) "cannot lift future after previous read succeeded") +(component instance $i6 $Tester) +(assert_trap (invoke "trap-after-stream-reader-eager-dropped") "cannot write to stream after being notified that the readable end dropped") +(component instance $i7 $Tester) +(assert_trap (invoke "trap-after-stream-reader-async-dropped") "cannot write to stream after being notified that the readable end dropped") +(component instance $i8.1 $Tester) +(assert_trap (invoke "trap-after-stream-writer-eager-dropped" (bool.const false)) "cannot read from stream after being notified that the writable end dropped") +(component instance $i8.2 $Tester) +(assert_trap (invoke "trap-after-stream-writer-eager-dropped" (bool.const true)) "cannot lift stream after being notified that the writable end dropped") +(component instance $i9.1 $Tester) +(assert_trap (invoke "trap-after-stream-writer-async-dropped" (bool.const false)) "cannot read from stream after being notified that the writable end dropped") +(component instance $i9.2 $Tester) +(assert_trap (invoke "trap-after-stream-writer-async-dropped" (bool.const true)) "cannot lift stream after being notified that the writable end dropped") diff --git a/src/test/resources/spec-tests/async/trap-if-sync-and-waitable-set.wast b/src/test/resources/spec-tests/async/trap-if-sync-and-waitable-set.wast new file mode 100644 index 0000000..2d2d439 --- /dev/null +++ b/src/test/resources/spec-tests/async/trap-if-sync-and-waitable-set.wast @@ -0,0 +1,288 @@ +;; Tests the trap conditions associated with mixing synchronous and +;; asynchronous waiting on the same waitable. +(component definition $Tester + (component $C + (core module $CM + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (func (export "blocks-forever") (result i32) + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (call $waitable-set.new) (i32.const 4))) + ) + (func (export "blocks-forever-cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (canon waitable-set.new (core func $waitable-set.new)) + (core instance $cm (instantiate $CM (with "" (instance + (export "waitable-set.new" (func $waitable-set.new)) + )))) + (func (export "blocks-forever") async (result u32) (canon lift + (core func $cm "blocks-forever") + async (callback (func $cm "blocks-forever-cb")) + )) + ) + (instance $c (instantiate $C)) + + (core module $MemTable + (table (export "ftbl") 4 funcref) + (memory (export "mem") 1) + ) + (core instance $memTable (instantiate $MemTable)) + + (core module $m + (import "" "thread.new-indirect" (func $thread.new-indirect (param i32 i32) (result i32))) + (import "" "thread.yield-to-suspended" (func $thread.yield-to-suspended (param i32) (result i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "subtask.cancel-sync" (func $subtask.cancel-sync (param i32) (result i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.read-sync" (func $future.read-sync (param i32 i32) (result i32))) + (import "" "future.write-sync" (func $future.write-sync (param i32 i32) (result i32))) + (import "" "future.read-async" (func $future.read-async (param i32 i32) (result i32))) + (import "" "future.write-async" (func $future.write-async (param i32 i32) (result i32))) + (import "" "future.cancel-read-sync" (func $future.cancel-read-sync (param i32) (result i32))) + (import "" "future.cancel-write-sync" (func $future.cancel-write-sync (param i32) (result i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read-sync" (func $stream.read-sync (param i32 i32 i32) (result i32))) + (import "" "stream.write-sync" (func $stream.write-sync (param i32 i32 i32) (result i32))) + (import "" "stream.read-async" (func $stream.read-async (param i32 i32 i32) (result i32))) + (import "" "stream.write-async" (func $stream.write-async (param i32 i32 i32) (result i32))) + (import "" "stream.cancel-read-sync" (func $stream.cancel-read-sync (param i32) (result i32))) + (import "" "stream.cancel-write-sync" (func $stream.cancel-write-sync (param i32) (result i32))) + (import "" "blocks-forever" (func $blocks-forever (param i32) (result i32))) + (import "" "ftbl" (table $ftbl 4 funcref)) + + (func $new-future-rx (result i32) + (i32.wrap_i64 (call $future.new)) + ) + (func $new-future-tx (result i32) + (i32.wrap_i64 (i64.shr_u (call $future.new) (i64.const 32))) + ) + (func $new-stream-rx (result i32) + (i32.wrap_i64 (call $stream.new)) + ) + (func $new-stream-tx (result i32) + (i32.wrap_i64 (i64.shr_u (call $stream.new) (i64.const 32))) + ) + (func $spawn-and-yield (param $idx i32) (param $arg i32) + (drop (call $thread.yield-to-suspended + (call $thread.new-indirect (local.get $idx) (local.get $arg)))) + ) + (func $assert-blocked (param $ret i32) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + ) + + ;; thread-start funcs used by the join-during-sync-* tests: + (func $thread-future-read-sync (param $rx i32) + (drop (call $future.read-sync (local.get $rx) (i32.const 0))) + ) + (elem (table $ftbl) (i32.const 0) func $thread-future-read-sync) + (func $thread-future-write-sync (param $tx i32) + (drop (call $future.write-sync (local.get $tx) (i32.const 0))) + ) + (elem (table $ftbl) (i32.const 1) func $thread-future-write-sync) + (func $thread-stream-read-sync (param $rx i32) + (drop (call $stream.read-sync (local.get $rx) (i32.const 0) (i32.const 4))) + ) + (elem (table $ftbl) (i32.const 2) func $thread-stream-read-sync) + (func $thread-stream-write-sync (param $tx i32) + (drop (call $stream.write-sync (local.get $tx) (i32.const 0) (i32.const 4))) + ) + (elem (table $ftbl) (i32.const 3) func $thread-stream-write-sync) + + (func (export "join-during-sync-future-read") + (local $rx i32) + (local.set $rx (call $new-future-rx)) + (call $spawn-and-yield (i32.const 0) (local.get $rx)) + (call $waitable.join (local.get $rx) (call $waitable-set.new)) + unreachable + ) + (func (export "join-during-sync-future-write") + (local $tx i32) + (local.set $tx (call $new-future-tx)) + (call $spawn-and-yield (i32.const 1) (local.get $tx)) + (call $waitable.join (local.get $tx) (call $waitable-set.new)) + unreachable + ) + (func (export "join-during-sync-stream-read") + (local $rx i32) + (local.set $rx (call $new-stream-rx)) + (call $spawn-and-yield (i32.const 2) (local.get $rx)) + (call $waitable.join (local.get $rx) (call $waitable-set.new)) + unreachable + ) + (func (export "join-during-sync-stream-write") + (local $tx i32) + (local.set $tx (call $new-stream-tx)) + (call $spawn-and-yield (i32.const 3) (local.get $tx)) + (call $waitable.join (local.get $tx) (call $waitable-set.new)) + unreachable + ) + + (func (export "sync-future-read-when-in-set") + (local $rx i32) + (local.set $rx (call $new-future-rx)) + (call $waitable.join (local.get $rx) (call $waitable-set.new)) + (drop (call $future.read-sync (local.get $rx) (i32.const 0))) + unreachable + ) + (func (export "sync-future-write-when-in-set") + (local $tx i32) + (local.set $tx (call $new-future-tx)) + (call $waitable.join (local.get $tx) (call $waitable-set.new)) + (drop (call $future.write-sync (local.get $tx) (i32.const 0))) + unreachable + ) + (func (export "sync-stream-read-when-in-set") + (local $rx i32) + (local.set $rx (call $new-stream-rx)) + (call $waitable.join (local.get $rx) (call $waitable-set.new)) + (drop (call $stream.read-sync (local.get $rx) (i32.const 0) (i32.const 4))) + unreachable + ) + (func (export "sync-stream-write-when-in-set") + (local $tx i32) + (local.set $tx (call $new-stream-tx)) + (call $waitable.join (local.get $tx) (call $waitable-set.new)) + (drop (call $stream.write-sync (local.get $tx) (i32.const 0) (i32.const 4))) + unreachable + ) + (func (export "sync-future-cancel-read-when-in-set") + (local $rx i32) + (local.set $rx (call $new-future-rx)) + (call $assert-blocked (call $future.read-async (local.get $rx) (i32.const 0))) + (call $waitable.join (local.get $rx) (call $waitable-set.new)) + (drop (call $future.cancel-read-sync (local.get $rx))) + unreachable + ) + + (func (export "sync-future-cancel-write-when-in-set") + (local $tx i32) + (local.set $tx (call $new-future-tx)) + (call $assert-blocked (call $future.write-async (local.get $tx) (i32.const 0))) + (call $waitable.join (local.get $tx) (call $waitable-set.new)) + (drop (call $future.cancel-write-sync (local.get $tx))) + unreachable + ) + (func (export "sync-stream-cancel-read-when-in-set") + (local $rx i32) + (local.set $rx (call $new-stream-rx)) + (call $assert-blocked (call $stream.read-async (local.get $rx) (i32.const 0) (i32.const 4))) + (call $waitable.join (local.get $rx) (call $waitable-set.new)) + (drop (call $stream.cancel-read-sync (local.get $rx))) + unreachable + ) + (func (export "sync-stream-cancel-write-when-in-set") + (local $tx i32) + (local.set $tx (call $new-stream-tx)) + (call $assert-blocked (call $stream.write-async (local.get $tx) (i32.const 0) (i32.const 4))) + (call $waitable.join (local.get $tx) (call $waitable-set.new)) + (drop (call $stream.cancel-write-sync (local.get $tx))) + unreachable + ) + + (func (export "sync-subtask-cancel-when-in-set") + (local $ret i32) (local $sub i32) + (local.set $ret (call $blocks-forever (i32.const 0))) + (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) + (then unreachable)) + (local.set $sub (i32.shr_u (local.get $ret) (i32.const 4))) + (call $waitable.join (local.get $sub) (call $waitable-set.new)) + (drop (call $subtask.cancel-sync (local.get $sub))) + unreachable + ) + ) + + (core type $start-func-ty (func (param i32))) + (alias core export $memTable "ftbl" (core table $ftbl)) + + (core func $thread.new-indirect (canon thread.new-indirect $start-func-ty (table $ftbl))) + (core func $thread.yield-to-suspended (canon thread.yield-to-suspended)) + (core func $waitable-set.new (canon waitable-set.new)) + (core func $waitable.join (canon waitable.join)) + (core func $subtask.cancel-sync (canon subtask.cancel)) + (type $future (future)) + (type $stream (stream u8)) + (core func $future.new (canon future.new $future)) + (core func $future.read-sync (canon future.read $future (memory $memTable "mem"))) + (core func $future.write-sync (canon future.write $future (memory $memTable "mem"))) + (core func $future.read-async (canon future.read $future async (memory $memTable "mem"))) + (core func $future.write-async (canon future.write $future async (memory $memTable "mem"))) + (core func $future.cancel-read-sync (canon future.cancel-read $future)) + (core func $future.cancel-write-sync (canon future.cancel-write $future)) + (core func $stream.new (canon stream.new $stream)) + (core func $stream.read-sync (canon stream.read $stream (memory $memTable "mem"))) + (core func $stream.write-sync (canon stream.write $stream (memory $memTable "mem"))) + (core func $stream.read-async (canon stream.read $stream async (memory $memTable "mem"))) + (core func $stream.write-async (canon stream.write $stream async (memory $memTable "mem"))) + (core func $stream.cancel-read-sync (canon stream.cancel-read $stream)) + (core func $stream.cancel-write-sync (canon stream.cancel-write $stream)) + (canon lower (func $c "blocks-forever") async (memory $memTable "mem") (core func $blocks-forever)) + + (core instance $m (instantiate $m + (with "" (instance + (export "thread.new-indirect" (func $thread.new-indirect)) + (export "thread.yield-to-suspended" (func $thread.yield-to-suspended)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable.join" (func $waitable.join)) + (export "subtask.cancel-sync" (func $subtask.cancel-sync)) + (export "future.new" (func $future.new)) + (export "future.read-sync" (func $future.read-sync)) + (export "future.write-sync" (func $future.write-sync)) + (export "future.read-async" (func $future.read-async)) + (export "future.write-async" (func $future.write-async)) + (export "future.cancel-read-sync" (func $future.cancel-read-sync)) + (export "future.cancel-write-sync" (func $future.cancel-write-sync)) + (export "stream.new" (func $stream.new)) + (export "stream.read-sync" (func $stream.read-sync)) + (export "stream.write-sync" (func $stream.write-sync)) + (export "stream.read-async" (func $stream.read-async)) + (export "stream.write-async" (func $stream.write-async)) + (export "stream.cancel-read-sync" (func $stream.cancel-read-sync)) + (export "stream.cancel-write-sync" (func $stream.cancel-write-sync)) + (export "blocks-forever" (func $blocks-forever)) + (export "ftbl" (table $ftbl)) + )) + )) + + (func (export "join-during-sync-future-read") async (canon lift (core func $m "join-during-sync-future-read"))) + (func (export "join-during-sync-future-write") async (canon lift (core func $m "join-during-sync-future-write"))) + (func (export "join-during-sync-stream-read") async (canon lift (core func $m "join-during-sync-stream-read"))) + (func (export "join-during-sync-stream-write") async (canon lift (core func $m "join-during-sync-stream-write"))) + (func (export "sync-future-read-when-in-set") async (canon lift (core func $m "sync-future-read-when-in-set"))) + (func (export "sync-future-write-when-in-set") async (canon lift (core func $m "sync-future-write-when-in-set"))) + (func (export "sync-stream-read-when-in-set") async (canon lift (core func $m "sync-stream-read-when-in-set"))) + (func (export "sync-stream-write-when-in-set") async (canon lift (core func $m "sync-stream-write-when-in-set"))) + (func (export "sync-future-cancel-read-when-in-set") async (canon lift (core func $m "sync-future-cancel-read-when-in-set"))) + (func (export "sync-future-cancel-write-when-in-set") async (canon lift (core func $m "sync-future-cancel-write-when-in-set"))) + (func (export "sync-stream-cancel-read-when-in-set") async (canon lift (core func $m "sync-stream-cancel-read-when-in-set"))) + (func (export "sync-stream-cancel-write-when-in-set") async (canon lift (core func $m "sync-stream-cancel-write-when-in-set"))) + (func (export "sync-subtask-cancel-when-in-set") async (canon lift (core func $m "sync-subtask-cancel-when-in-set"))) +) + +(component instance $i $Tester) +(assert_trap (invoke "join-during-sync-future-read") "waitable cannot be used synchronously while added to a waitable set") +(component instance $i $Tester) +(assert_trap (invoke "join-during-sync-future-write") "waitable cannot be used synchronously while added to a waitable set") +(component instance $i $Tester) +(assert_trap (invoke "join-during-sync-stream-read") "waitable cannot be used synchronously while added to a waitable set") +(component instance $i $Tester) +(assert_trap (invoke "join-during-sync-stream-write") "waitable cannot be used synchronously while added to a waitable set") +(component instance $i $Tester) +(assert_trap (invoke "sync-future-read-when-in-set") "waitable cannot be used synchronously while added to a waitable set") +(component instance $i $Tester) +(assert_trap (invoke "sync-future-write-when-in-set") "waitable cannot be used synchronously while added to a waitable set") +(component instance $i $Tester) +(assert_trap (invoke "sync-stream-read-when-in-set") "waitable cannot be used synchronously while added to a waitable set") +(component instance $i $Tester) +(assert_trap (invoke "sync-stream-write-when-in-set") "waitable cannot be used synchronously while added to a waitable set") +(component instance $i $Tester) +(assert_trap (invoke "sync-future-cancel-read-when-in-set") "waitable cannot be used synchronously while added to a waitable set") +(component instance $i $Tester) +(assert_trap (invoke "sync-future-cancel-write-when-in-set") "waitable cannot be used synchronously while added to a waitable set") +(component instance $i $Tester) +(assert_trap (invoke "sync-stream-cancel-read-when-in-set") "waitable cannot be used synchronously while added to a waitable set") +(component instance $i $Tester) +(assert_trap (invoke "sync-stream-cancel-write-when-in-set") "waitable cannot be used synchronously while added to a waitable set") +(component instance $i $Tester) +(assert_trap (invoke "sync-subtask-cancel-when-in-set") "waitable cannot be used synchronously while added to a waitable set") diff --git a/src/test/resources/spec-tests/async/trap-if-transfer-in-waitable-set.wast b/src/test/resources/spec-tests/async/trap-if-transfer-in-waitable-set.wast new file mode 100644 index 0000000..cb2accf --- /dev/null +++ b/src/test/resources/spec-tests/async/trap-if-transfer-in-waitable-set.wast @@ -0,0 +1,51 @@ +;; This test contains a single component $Tester which creates a stream and +;; future, joins the readable end into a waitable set, and then attempts to +;; lift the readable end by returning it from an export. Because the readable +;; end is in a waitable set, lifting must trap. + +(component definition $Tester + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $M + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "stream.new" (func $stream.new (result i64))) + + (func $return-future-in-set (export "return-future-in-set") (result i32) + (local $ret64 i64) (local $rx i32) (local $ws i32) + (local.set $ret64 (call $future.new)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $rx) (local.get $ws)) + (local.get $rx) + ) + (func $return-stream-in-set (export "return-stream-in-set") (result i32) + (local $ret64 i64) (local $rx i32) (local $ws i32) + (local.set $ret64 (call $stream.new)) + (local.set $rx (i32.wrap_i64 (local.get $ret64))) + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $rx) (local.get $ws)) + (local.get $rx) + ) + ) + (type $FT (future u8)) + (type $ST (stream u8)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon future.new $FT (core func $future.new)) + (canon stream.new $ST (core func $stream.new)) + (core instance $m (instantiate $M (with "" (instance + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "future.new" (func $future.new)) + (export "stream.new" (func $stream.new)) + )))) + (func (export "return-future-in-set") async (result $FT) (canon lift (core func $m "return-future-in-set"))) + (func (export "return-stream-in-set") async (result $ST) (canon lift (core func $m "return-stream-in-set"))) +) + +(component instance $i1 $Tester) +(assert_trap (invoke "return-future-in-set") "cannot lift future in a waitable set") +(component instance $i2 $Tester) +(assert_trap (invoke "return-stream-in-set") "cannot lift stream in a waitable set") diff --git a/src/test/resources/spec-tests/async/trap-on-reenter.wast b/src/test/resources/spec-tests/async/trap-on-reenter.wast new file mode 100644 index 0000000..f363f6d --- /dev/null +++ b/src/test/resources/spec-tests/async/trap-on-reenter.wast @@ -0,0 +1,110 @@ +;; This test creates an asynchronous recursive call stack: +;; $Parent --> $Child --> $Parent +;; That should trap when $Child tries to call $Parent. +(component $Parent + (core module $CoreInner + (memory (export "mem") 1) + (func (export "a") (result i32) + unreachable + ) + (func (export "a-cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (core instance $core_inner (instantiate $CoreInner)) + (func $a async (canon lift + (core func $core_inner "a") + async (callback (func $core_inner "a-cb")) + )) + + (component $Child + (import "a" (func $a async)) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + + (core module $CoreChild + (import "" "a" (func $a (result i32))) + (func (export "b") (result i32) + (i32.const 1 (; YIELD ;)) + ) + (func (export "b-cb") (param i32 i32 i32) (result i32) + (call $a) + unreachable + ) + ) + (canon lower (func $a) async (memory $memory "mem") (core func $a')) + (core instance $core_child (instantiate $CoreChild (with "" (instance + (export "a" (func $a')) + )))) + (func (export "b") async (canon lift + (core func $core_child "b") + async (callback (func $core_child "b-cb")) + )) + ) + (instance $child (instantiate $Child (with "a" (func $a)))) + + (core module $CoreOuter + (import "" "b" (func $b (result i32))) + (func $c (export "c") (result i32) + (i32.const 1 (; YIELD ;)) + ) + (func $c-cb (export "c-cb") (param i32 i32 i32) (result i32) + (call $b) + ) + ) + (canon lower (func $child "b") async (memory $core_inner "mem") (core func $b)) + (core instance $core_outer (instantiate $CoreOuter (with "" (instance + (export "b" (func $b)) + )))) + (func $c (export "c") async (canon lift + (core func $core_outer "c") + async (callback (func $core_outer "c-cb")) + )) +) +(assert_trap (invoke "c") "wasm trap: cannot enter component instance") + +;; also, for now, trap on parent-to-child +(component $Parent + (component $Child + (core module $CoreChild + (func (export "f")) + ) + (core instance $core_child (instantiate $CoreChild)) + (func (export "f") (canon lift (core func $core_child "f"))) + ) + (instance $child (instantiate $Child)) + (canon lower (func $child "f") (core func $f)) + + (core module $CoreOuter + (import "" "f" (func $f)) + (func (export "g") (call $f)) + ) + (core instance $core_outer (instantiate $CoreOuter (with "" (instance (export "f" (func $f)))))) + (func $g (export "g") (canon lift (core func $core_outer "g"))) +) +(assert_trap (invoke "g") "wasm trap: cannot enter component instance") + +;; also, for now, trap on child-to-parent +(component $Parent + (core module $CoreInner + (func (export "f")) + ) + (core instance $core_inner (instantiate $CoreInner)) + (func $f (canon lift (core func $core_inner "f"))) + + (component $Child + (import "f" (func $f)) + (canon lower (func $f) (core func $f')) + (core module $CoreChild + (import "" "f" (func $f)) + (func (export "g") (call $f)) + ) + (core instance $core_child (instantiate $CoreChild (with "" (instance (export "f" (func $f')))))) + (func (export "g") (canon lift (core func $core_child "g"))) + ) + (instance $child (instantiate $Child (with "f" (func $f)))) + (alias export $child "g" (func $g)) + (export "g" (func $g)) +) +(assert_trap (invoke "g") "wasm trap: cannot enter component instance") diff --git a/src/test/resources/spec-tests/async/validate-no-async-abi-for-sync-type.wast b/src/test/resources/spec-tests/async/validate-no-async-abi-for-sync-type.wast new file mode 100644 index 0000000..e319bb4 --- /dev/null +++ b/src/test/resources/spec-tests/async/validate-no-async-abi-for-sync-type.wast @@ -0,0 +1,27 @@ +(assert_invalid + (component + (core module $M + (func (export "f")) + ) + (core instance $i (instantiate $M)) + (func (export "f") (canon lift (core func $i "f") async)) + ) + "the `async` canonical option requires an async function type") + +(assert_invalid + (component + (core module $M + (func (export "f") (param i32) (result i32) unreachable) + (func (export "f_cb") (param i32 i32 i32) (result i32) unreachable) + ) + (core instance $i (instantiate $M)) + (func (export "f") (canon lift (core func $i "f") async (callback (func $i "f_cb")))) + ) + "the `async` canonical option requires an async function type") + +(assert_invalid + (component + (import "f" (func $f)) + (core func $f' (canon lower (func $f) async)) + ) + "the `async` canonical option requires an async function type") diff --git a/src/test/resources/spec-tests/async/validate-no-stream-char.wast b/src/test/resources/spec-tests/async/validate-no-stream-char.wast new file mode 100644 index 0000000..30d1408 --- /dev/null +++ b/src/test/resources/spec-tests/async/validate-no-stream-char.wast @@ -0,0 +1,7 @@ +;; Test that `stream` is rejected as a validation error. +;; This is a temporary limitation; see https://github.com/WebAssembly/component-model/pull/607 +(assert_invalid + (component + (type (stream char)) + ) + "`stream` is not valid") diff --git a/src/test/resources/spec-tests/async/wait-during-callback.wast b/src/test/resources/spec-tests/async/wait-during-callback.wast new file mode 100644 index 0000000..3f95d5b --- /dev/null +++ b/src/test/resources/spec-tests/async/wait-during-callback.wast @@ -0,0 +1,77 @@ +;; This test calls waitable-set.wait from under an async-callback-lifted export. +(component + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CM + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + + (func $run (export "run") (result i32) + (local $ret i32) (local $ret64 i64) + (local $futr i32) (local $futw i32) (local $ws i32) + (local $event_code i32) (local $retp i32) + + ;; create a future pair + (local.set $ret64 (call $future.new)) + (local.set $futr (i32.wrap_i64 (local.get $ret64))) + (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + + ;; start a pending read that will block + (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + ;; perform a write to make the above read ready + (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) + (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) + (then unreachable)) + + ;; wait on a waitable set containing our now-ready future.read which + ;; should then immediately resolve + (local.set $ws (call $waitable-set.new)) + (call $waitable.join (local.get $futr) (local.get $ws)) + (local.set $retp (i32.const 0)) + (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp))) + (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) + (then unreachable)) + (if (i32.ne (local.get $futr) (i32.load (local.get $retp))) + (then unreachable)) + + ;; return 42 + (call $task.return (i32.const 42)) + (i32.const 0 (; EXIT ;)) + ) + (func (export "run_cb") (param i32 i32 i32) (result i32) + unreachable + ) + ) + (type $FT (future)) + (canon task.return (result u32) (core func $task.return)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon future.new $FT (core func $future.new)) + (canon future.read $FT async (core func $future.read)) + (canon future.write $FT async (core func $future.write)) + (core instance $cm (instantiate $CM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "future.new" (func $future.new)) + (export "future.read" (func $future.read)) + (export "future.write" (func $future.write)) + )))) + (func (export "run") async (result u32) (canon lift + (core func $cm "run") + async (callback (func $cm "run_cb")) + )) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/zero-length.wast b/src/test/resources/spec-tests/async/zero-length.wast new file mode 100644 index 0000000..fab7765 --- /dev/null +++ b/src/test/resources/spec-tests/async/zero-length.wast @@ -0,0 +1,223 @@ +;; This example defines 3 nested components $Producer, $Consumer and $Parent +;; $Parent imports $Consumer and $Producer, calling $Producer.produce, which +;; returns a stream that $Parent passes to $Consumer.consume. +;; $Producer and $Consumer both start by performing 0-length reads/writes to +;; detect when the other side is ready. Once signalled ready, a 4-byte +;; payload is written/read. +(component + (component $Producer + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CoreProducer + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + + ;; $ws is waited on by 'produce' + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + ;; $outsw is written by 'produce' + (global $outsw (mut i32) (i32.const 0)) + (global $outbufp (mut i32) (i32.const 0x20)) + + (global $state (mut i32) (i32.const 0)) + + (func $produce (export "produce") (result i32) + (local $ret i32) (local $ret64 i64) (local $outsr i32) + + ;; create a new stream r/w pair $outsr/$outsw + (local.set $ret64 (call $stream.new)) + (local.set $outsr (i32.wrap_i64 (local.get $ret64))) + (global.set $outsw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) + + ;; return the readable end of the stream to the caller + (call $task.return (local.get $outsr)) + + ;; initiate a zero-length write + (local.set $ret (call $stream.write (global.get $outsw) (i32.const 0xdeadbeef) (i32.const 0))) + (if (i32.ne (i32.const -1) (local.get $ret)) + (then unreachable)) + + ;; wait for the stream.write to complete + (call $waitable.join (global.get $outsw) (global.get $ws)) + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) + ) + (func $produce_cb (export "produce_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + (local $ret i32) + + ;; confirm we're getting a write for the stream $outsw + (if (i32.ne (local.get $event_code) (i32.const 3 (; STREAM_WRITE ;))) + (then unreachable)) + (if (i32.ne (local.get $index) (global.get $outsw)) + (then unreachable)) + + ;; the first call to produce_cb: + (if (i32.eq (global.get $state) (i32.const 0)) (then + ;; confirm we're seeing the zero-length write complete + (if (i32.ne (local.get $payload) (i32.const 0 (; COMPLETED=0 | (0 << 4) ;))) + (then unreachable)) + + ;; issue an async non-zero-length write which should block per spec + (i32.store (i32.const 0) (i32.const 0x12345678)) + (local.set $ret (call $stream.write (global.get $outsw) (i32.const 0) (i32.const 4))) + (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) + (then unreachable)) + + (global.set $state (i32.const 1)) + + ;; wait on $ws + (return (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4)))) + )) + + ;; the second call to produce_cb: + (if (i32.eq (global.get $state) (i32.const 1)) (then + ;; confirm we're seeing the non-zero-length write complete + (if (i32.ne (local.get $payload) (i32.const 0x41 (; DROPPED=1 | (4 << 4) ;))) + (then unreachable)) + + (call $stream.drop-writable (global.get $outsw)) + (return (i32.const 0 (; EXIT ;))) + )) + + unreachable + ) + ) + (type $ST (stream u8)) + (canon task.return (result $ST) (core func $task.return)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (core instance $core_producer (instantiate $CoreProducer (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "stream.new" (func $stream.new)) + (export "stream.write" (func $stream.write)) + (export "stream.drop-writable" (func $stream.drop-writable)) + )))) + (func (export "produce") async (result (stream u8)) (canon lift + (core func $core_producer "produce") + async (callback (func $core_producer "produce_cb")) + )) + ) + + (component $Consumer + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (core module $CoreConsumer + (import "" "mem" (memory 1)) + (import "" "task.return" (func $task.return (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + + ;; $ws is waited on by 'consume' + (global $ws (mut i32) (i32.const 0)) + (func $start (global.set $ws (call $waitable-set.new))) + (start $start) + + ;; $insr is read by 'consume' + (global $insr (mut i32) (i32.const 0)) + (global $inbufp (mut i32) (i32.const 0x20)) + + (func $consume (export "consume") (param $insr i32) (result i32) + (local $ret i32) + (global.set $insr (local.get $insr)) + + ;; initiate a zero-length read which will also block (even though there is + ;; a pending write, b/c the pending write is 0-length, per spec) + (local.set $ret (call $stream.read (global.get $insr) (i32.const 0xdeadbeef) (i32.const 0))) + (if (i32.ne (i32.const -1) (local.get $ret)) + (then unreachable)) + + ;; wait for the stream.read to complete + (call $waitable.join (global.get $insr) (global.get $ws)) + (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) + ) + (func $consume_cb (export "consume_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) + (local $ret i32) + + ;; confirm we're seeing the zero-length read complete + (if (i32.ne (local.get $event_code) (i32.const 2 (; STREAM_READ ;))) + (then unreachable)) + (if (i32.ne (local.get $index) (global.get $insr)) + (then unreachable)) + (if (i32.ne (local.get $payload) (i32.const 0 (; COMPLETED=0 | (0 << 4) ;))) + (then unreachable)) + + ;; perform a non-zero-length read which should succeed without blocking + (local.set $ret (call $stream.read (global.get $insr) (i32.const 0) (i32.const 100))) + (if (i32.ne (i32.const 0x40 (; (4 << 4) | COMPLETED=0 ;)) (local.get $ret)) + (then unreachable)) + (local.set $ret (i32.load (i32.const 0))) + (if (i32.ne (i32.const 0x12345678) (local.get $ret)) + (then unreachable)) + + (call $stream.drop-readable (global.get $insr)) + + ;; return 42 to the top-level assert_return + (call $task.return (i32.const 42)) + (i32.const 0 (; EXIT ;)) + ) + ) + (type $ST (stream u8)) + (canon task.return (result u32) (core func $task.return)) + (canon waitable.join (core func $waitable.join)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (core instance $core_consumer (instantiate $CoreConsumer (with "" (instance + (export "mem" (memory $memory "mem")) + (export "task.return" (func $task.return)) + (export "waitable.join" (func $waitable.join)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "stream.read" (func $stream.read)) + (export "stream.drop-readable" (func $stream.drop-readable)) + )))) + (func (export "consume") async (param "in" (stream u8)) (result u32) (canon lift + (core func $core_consumer "consume") + async (callback (func $core_consumer "consume_cb")) + )) + ) + + (component $Parent + (import "produce" (func $produce async (result (stream u8)))) + (import "consume" (func $consume async (param "in" (stream u8)) (result u32))) + + (core module $CoreParent + (import "" "produce" (func $produce (result i32))) + (import "" "consume" (func $consume (param i32) (result i32))) + (memory 1) + (func $run (export "run") (result i32) + (call $consume (call $produce)) + ) + ) + + (canon lower (func $produce) (core func $produce')) + (canon lower (func $consume) (core func $consume')) + (core instance $core_parent (instantiate $CoreParent (with "" (instance + (export "produce" (func $produce')) + (export "consume" (func $consume')) + )))) + (func (export "run") async (result u32) (canon lift (core func $core_parent "run"))) + ) + + (instance $producer (instantiate $Producer)) + (instance $consumer (instantiate $Consumer)) + (instance $parent (instantiate $Parent + (with "produce" (func $producer "produce")) + (with "consume" (func $consumer "consume")) + )) + (func (export "run") (alias export $parent "run")) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/names/kebab.wast b/src/test/resources/spec-tests/names/kebab.wast new file mode 100644 index 0000000..df135f8 --- /dev/null +++ b/src/test/resources/spec-tests/names/kebab.wast @@ -0,0 +1,60 @@ +(component (component + (import "a" (func)) + (import "a1" (func)) + (import "a-1" (func)) + (import "a-1-b-2-c-3" (func)) + (import "B" (func)) + (import "B1" (func)) + (import "B-1" (func)) + (import "B-1-C-2-D-3" (func)) + (import "a11-B11-123-ABC-abc" (func)) + (import "ns-1-a:b-1-c/D-2" (func)) +)) +(assert_invalid + (component + (import "1" (func))) + "is not in kebab case") +(assert_invalid + (component + (import "1-a" (func))) + "is not in kebab case") +(assert_invalid + (component + (import "" (func))) + "is not in kebab case") +(assert_invalid + (component + (import "a-" (func))) + "is not in kebab case") +(assert_invalid + (component + (import "a--" (func))) + "is not in kebab case") +(assert_invalid + (component + (import "1:a/b" (func))) + "is not in kebab case") +(assert_invalid + (component + (import "A:b/c" (func))) + "is not a valid extern name") +(assert_invalid + (component + (import "1:b/c" (func))) + "is not a valid extern name") +(assert_invalid + (component + (import "ns-A:b/c" (func))) + "is not a valid extern name") +(assert_invalid + (component + (import "ns:A/b" (func))) + "is not a valid extern name") +(assert_invalid + (component + (import "ns:1/a" (func))) + "is not a valid extern name") +(assert_invalid + (component + (import "ns:pkg-A/b" (func))) + "is not a valid extern name") diff --git a/src/test/resources/spec-tests/resources/multiple-resources.wast b/src/test/resources/spec-tests/resources/multiple-resources.wast new file mode 100644 index 0000000..77549ad --- /dev/null +++ b/src/test/resources/spec-tests/resources/multiple-resources.wast @@ -0,0 +1,170 @@ +;; This test has two components $C and $D where $D imports and calls $C +;; $C implements two resource types imported and used by $D +;; $D creates instances of both resource types, uses them and destroys them +(component + (component $C + (core module $Indirect + (table (export "ftbl") 2 funcref) + (type $FT (func (param i32))) + (func (export "R1-dtor") (param i32) + (call_indirect (type $FT) (local.get 0) (i32.const 0)) + ) + (func (export "R2-dtor") (param i32) + (call_indirect (type $FT) (local.get 0) (i32.const 1)) + ) + ) + (core instance $indirect (instantiate $Indirect)) + (type $R1' (resource (rep i32) (dtor (func $indirect "R1-dtor")))) + (type $R2' (resource (rep i32) (dtor (func $indirect "R2-dtor")))) + (export $R1 "R1" (type $R1')) + (export $R2 "R2" (type $R2')) + (canon resource.new $R1' (core func $R1.resource.new)) + (canon resource.new $R2' (core func $R2.resource.new)) + + (core module $CM + (import "" "ftbl" (table 1 funcref)) + (import "" "R1.resource.new" (func $R1.resource.new (param i32) (result i32))) + (import "" "R2.resource.new" (func $R2.resource.new (param i32) (result i32))) + (memory 1) + (global $num-live-R1 (mut i32) (i32.const 0)) + (global $num-live-R2 (mut i32) (i32.const 0)) + + ;; constructors + (func $make-R1 (export "make-R1") (result i32) + (local $h i32) + (global.set $num-live-R1 (i32.add (global.get $num-live-R1) (i32.const 1))) + (call $R1.resource.new (i32.add (i32.const 0x40) (global.get $num-live-R1))) + ) + (func $make-R2 (export "make-R2") (result i32) + (local $h i32) + (global.set $num-live-R2 (i32.add (global.get $num-live-R2) (i32.const 1))) + (call $R2.resource.new (i32.add (i32.const 0x80) (global.get $num-live-R2))) + ) + + ;; accessors + (func $get-rep-R1 (export "get-rep-R1") (param $rep i32) (result i32) + (local.get $rep) + ) + (func $get-rep-R2 (export "get-rep-R2") (param $rep i32) (result i32) + (local.get $rep) + ) + + ;; destructors + (func $R1-dtor (param $rep i32) + (if (i32.or (i32.lt_u (local.get $rep) (i32.const 0x41)) (i32.gt_u (local.get $rep) (i32.const 0x42))) + (then unreachable)) + (if (i32.eqz (global.get $num-live-R1)) + (then unreachable)) + (global.set $num-live-R1 (i32.sub (global.get $num-live-R1) (i32.const 1))) + ) + (func $R2-dtor (param $rep i32) + (if (i32.or (i32.lt_u (local.get $rep) (i32.const 0x81)) (i32.gt_u (local.get $rep) (i32.const 0x82))) + (then unreachable)) + (if (i32.eqz (global.get $num-live-R2)) + (then unreachable)) + (global.set $num-live-R2 (i32.sub (global.get $num-live-R2) (i32.const 1))) + ) + (func $num-live (export "num-live") (result i32) + (i32.add (global.get $num-live-R1) (global.get $num-live-R2)) + ) + (elem (i32.const 0) $R1-dtor $R2-dtor) + ) + (core instance $cm (instantiate $CM (with "" (instance + (export "ftbl" (table $indirect "ftbl")) + (export "R1.resource.new" (func $R1.resource.new)) + (export "R2.resource.new" (func $R2.resource.new)) + )))) + (func $make-R1 (export "make-R1") (result (own $R1)) (canon lift (core func $cm "make-R1"))) + (func $make-R2 (export "make-R2") (result (own $R2)) (canon lift (core func $cm "make-R2"))) + (func $get-rep-R1 (export "get-rep-R1") (param "r" (borrow $R1)) (result u32) (canon lift (core func $cm "get-rep-R1"))) + (func $get-rep-R2 (export "get-rep-R2") (param "r" (borrow $R2)) (result u32) (canon lift (core func $cm "get-rep-R2"))) + (func (export "num-live") (result u32) (canon lift (core func $cm "num-live"))) + ) + + (component $D + (import "c" (instance $c + (export "R1" (type $R1 (sub resource))) + (export "R2" (type $R2 (sub resource))) + (export "make-R1" (func (result (own $R1)))) + (export "make-R2" (func (result (own $R2)))) + (export "get-rep-R1" (func (param "r" (borrow $R1)) (result u32))) + (export "get-rep-R2" (func (param "r" (borrow $R2)) (result u32))) + (export "num-live" (func (result u32))) + )) + (core module $DM + (import "" "R1.resource.drop" (func $R1.resource.drop (param i32))) + (import "" "R2.resource.drop" (func $R2.resource.drop (param i32))) + (import "" "make-R1" (func $make-R1 (result i32))) + (import "" "make-R2" (func $make-R2 (result i32))) + (import "" "get-rep-R1" (func $get-rep-R1 (param i32) (result i32))) + (import "" "get-rep-R2" (func $get-rep-R2 (param i32) (result i32))) + (import "" "num-live" (func $num-live (result i32))) + (memory 1) + + (func $run (export "run") (result i32) + (local $ret i32) + (local $h1 i32) (local $h2 i32) (local $h3 i32) (local $h4 i32) + + ;; create 4 resources + (local.set $h1 (call $make-R1)) + (if (i32.ne (i32.const 1) (local.get $h1)) + (then unreachable)) + (local.set $h2 (call $make-R2)) + (if (i32.ne (i32.const 2) (local.get $h2)) + (then unreachable)) + (local.set $h3 (call $make-R1)) + (if (i32.ne (i32.const 3) (local.get $h3)) + (then unreachable)) + (local.set $h4 (call $make-R2)) + (if (i32.ne (i32.const 4) (local.get $h4)) + (then unreachable)) + (if (i32.ne (i32.const 4) (call $num-live)) + (then unreachable)) + + ;; use and destroy resources + (if (i32.ne (i32.const 0x81) (call $get-rep-R2 (local.get $h2))) + (then unreachable)) + (call $R2.resource.drop (local.get $h2)) + (if (i32.ne (i32.const 0x41) (call $get-rep-R1 (local.get $h1))) + (then unreachable)) + (call $R1.resource.drop (local.get $h1)) + (if (i32.ne (i32.const 0x82) (call $get-rep-R2 (local.get $h4))) + (then unreachable)) + (call $R2.resource.drop (local.get $h4)) + (if (i32.ne (i32.const 0x42) (call $get-rep-R1 (local.get $h3))) + (then unreachable)) + (call $R1.resource.drop (local.get $h3)) + + ;; everything should be destroyed + (if (i32.ne (i32.const 0) (call $num-live)) + (then unreachable)) + + (i32.const 42) + ) + ) + (alias export $c "R1" (type $R1)) + (alias export $c "R2" (type $R2)) + (canon resource.drop $R1 (core func $R1.resource.drop)) + (canon resource.drop $R2 (core func $R2.resource.drop)) + (canon lower (func $c "make-R1") (core func $make-R1')) + (canon lower (func $c "make-R2") (core func $make-R2')) + (canon lower (func $c "get-rep-R1") (core func $get-rep-R1')) + (canon lower (func $c "get-rep-R2") (core func $get-rep-R2')) + (canon lower (func $c "num-live") (core func $num-live')) + (core instance $dm (instantiate $DM (with "" (instance + (export "R1.resource.drop" (func $R1.resource.drop)) + (export "R2.resource.drop" (func $R2.resource.drop)) + (export "make-R1" (func $make-R1')) + (export "make-R2" (func $make-R2')) + (export "get-rep-R1" (func $get-rep-R1')) + (export "get-rep-R2" (func $get-rep-R2')) + (export "num-live" (func $num-live')) + )))) + (func (export "run") (result u32) (canon lift (core func $dm "run"))) + ) + + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "c" (instance $c)))) + (func (export "run") (alias export $d "run")) +) +(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/validation/implements.wast b/src/test/resources/spec-tests/validation/implements.wast new file mode 100644 index 0000000..7df0024 --- /dev/null +++ b/src/test/resources/spec-tests/validation/implements.wast @@ -0,0 +1,108 @@ +;; valid usages of `implements` +(component + (component + (import "a" (implements "a:b/c") (instance)) + (import "b" (implements "a:b/c") (instance)) + (import "c" (implements "a:b/c@1.0.0") (instance)) + (import "my-label" (implements "ns:pkg/iface") (instance)) + (import "a:b/c" (instance)) + (import "a:b/c@1.0.0" (instance)) + + (instance $a) + + (export "a" (implements "a:b/c") (instance $a)) + (export "b" (implements "a:b/c") (instance $a)) + (export "c" (implements "a:b/c@1.0.0") (instance $a)) + (export "my-label" (implements "ns:pkg/iface") (instance $a)) + (export "a:b/c" (instance $a)) + (export "a:b/c@1.0.0" (instance $a)) + ) + + (type (instance + (export "a" (implements "a:b/c") (instance)) + )) + (type (component + (import "a" (implements "a:b/c") (instance)) + (export "a" (implements "a:b/c") (instance)) + )) + + (instance $a) + (instance + (export "a" (implements "a:b/c") (instance $a)) + ) +) + +;; invalid, `not-valid` should be something like `a:b/c` +(assert_invalid + (component (import "a" (implements "not-valid") (instance))) + "must be an interface") + +;; invalid, `""` must be a valid kebab-name. +(assert_invalid + (component (import "a" (implements "") (instance))) + "not a valid name") + +;; invalid, can't import the same plain-name twice. +(assert_invalid + (component + (import "a" (implements "a:b/c") (instance)) + (import "a" (implements "a:b/c") (instance)) + ) + "conflicts with previous name") + +;; invalid, can't import the same plain-name twice. +(assert_invalid + (component + (import "a" (implements "a1:b/c") (instance)) + (import "a" (implements "a2:b/c") (instance)) + ) + "conflicts with previous name") + +;; invalid, can't import the same plain-name twice. +(assert_invalid + (component + (import "a" (implements "a:b/c") (instance)) + (import "a" (implements "a:b/c@1.0.0") (instance)) + ) + "conflicts with previous name") + +;; invalid, can't import the same plain-name twice. +(assert_invalid + (component + (import "a" (instance)) + (import "a" (implements "a:b/c") (instance)) + ) + "conflicts with previous name") + +;; invalid, `implements` can only be used by imports/exports typed as `instance` +(assert_invalid + (component + (import "a" (implements "a:b/c") (func)) + ) + "only instance names can have an `implements`") + +;; invalid, `implements` can only be used by imports/exports named with a +;; plainname. +(assert_invalid + (component + (import "a1:b/c" (implements "a2:b/c") (instance)) + ) + "name `a1:b/c` is not valid with `implements`") + +;; validity checks apply to other locations of `implements`, such as +;; component/instance types and bag-of-exports. +(assert_invalid + (component (type (component (import "a" (implements "not-valid") (instance))))) + "must be an interface") +(assert_invalid + (component (type (component (export "a" (implements "") (instance))))) + "not a valid name") +(assert_invalid + (component (type (instance (export "a" (implements "a:b/c") (func))))) + "only instance names") +(assert_invalid + (component + (instance) + (instance (export "x" (implements "a") (instance 0))) + ) + "must be an interface") diff --git a/src/test/resources/spec-tests/values/post-return.wast b/src/test/resources/spec-tests/values/post-return.wast new file mode 100644 index 0000000..7bc6d66 --- /dev/null +++ b/src/test/resources/spec-tests/values/post-return.wast @@ -0,0 +1,384 @@ +;; Tests behavior of built-ins called from inside a post-return function. + +;; built-ins that trap when called from post-return: +(component definition $Tester + (component $C + (core module $CM + (func (export "import")) + ) + (core instance $cm (instantiate $CM)) + (func (export "import") (canon lift (core func $cm "import"))) + ) + (component $D + (import "import" (func $import)) + + (core module $Memory (memory (export "mem") 1)) + (core instance $memory (instantiate $Memory)) + (type $R (resource (rep i32))) + (type $ST (stream u32)) + (type $FT (future u32)) + (canon resource.new $R (core func $resource.new)) + (canon resource.drop $R (core func $resource.drop)) + (canon task.return (core func $task.return)) + (canon task.cancel (core func $task.cancel)) + (canon thread.yield (core func $yield)) + (canon waitable-set.new (core func $waitable-set.new)) + (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) + (canon waitable-set.poll (memory $memory "mem") (core func $waitable-set.poll)) + (canon waitable-set.drop (core func $waitable-set.drop)) + (canon waitable.join (core func $waitable.join)) + (canon subtask.cancel (core func $subtask.cancel)) + (canon subtask.drop (core func $subtask.drop)) + (canon stream.new $ST (core func $stream.new)) + (canon stream.read $ST (memory $memory "mem") (core func $stream.read)) + (canon stream.write $ST (memory $memory "mem") (core func $stream.write)) + (canon stream.cancel-read $ST (core func $stream.cancel-read)) + (canon stream.cancel-write $ST (core func $stream.cancel-write)) + (canon stream.drop-readable $ST (core func $stream.drop-readable)) + (canon stream.drop-writable $ST (core func $stream.drop-writable)) + (canon future.new $FT (core func $future.new)) + (canon future.read $FT (memory $memory "mem") (core func $future.read)) + (canon future.write $FT (memory $memory "mem") (core func $future.write)) + (canon future.cancel-read $FT (core func $future.cancel-read)) + (canon future.cancel-write $FT (core func $future.cancel-write)) + (canon future.drop-readable $FT (core func $future.drop-readable)) + (canon future.drop-writable $FT (core func $future.drop-writable)) + (core module $DM + (import "" "mem" (memory 1)) + (import "" "import" (func $import)) + (import "" "resource.new" (func $resource.new (param i32) (result i32))) + (import "" "resource.drop" (func $resource.drop (param i32))) + (import "" "task.return" (func $task.return)) + (import "" "task.cancel" (func $task.cancel)) + (import "" "yield" (func $yield (result i32))) + (import "" "waitable-set.new" (func $waitable-set.new (result i32))) + (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) + (import "" "waitable-set.poll" (func $waitable-set.poll (param i32 i32) (result i32))) + (import "" "waitable-set.drop" (func $waitable-set.drop (param i32))) + (import "" "waitable.join" (func $waitable.join (param i32 i32))) + (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) + (import "" "subtask.drop" (func $subtask.drop (param i32))) + (import "" "stream.new" (func $stream.new (result i64))) + (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) + (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) + (import "" "stream.cancel-read" (func $stream.cancel-read (param i32) (result i32))) + (import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32))) + (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) + (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) + (import "" "future.new" (func $future.new (result i64))) + (import "" "future.read" (func $future.read (param i32 i32) (result i32))) + (import "" "future.write" (func $future.write (param i32 i32) (result i32))) + (import "" "future.cancel-read" (func $future.cancel-read (param i32) (result i32))) + (import "" "future.cancel-write" (func $future.cancel-write (param i32) (result i32))) + (import "" "future.drop-readable" (func $future.drop-readable (param i32))) + (import "" "future.drop-writable" (func $future.drop-writable (param i32))) + + (func (export "noop")) + (func (export "trap-calling-import") (call $import)) + (func (export "trap-calling-resource-new") (drop (call $resource.new (i32.const 0)))) + (func (export "trap-calling-resource-drop") (call $resource.drop (i32.const 0))) + (func (export "trap-calling-task-return") (call $task.return)) + (func (export "trap-calling-task-cancel") (call $task.cancel)) + (func (export "trap-calling-yield") (drop (call $yield))) + (func (export "trap-calling-waitable-set-new") (drop (call $waitable-set.new))) + (func (export "trap-calling-waitable-set-wait") (drop (call $waitable-set.wait (i32.const 0) (i32.const 0)))) + (func (export "trap-calling-waitable-set-poll") (drop (call $waitable-set.poll (i32.const 0) (i32.const 0)))) + (func (export "trap-calling-waitable-set-drop") (call $waitable-set.drop (i32.const 0))) + (func (export "trap-calling-waitable-join") (call $waitable.join (i32.const 0) (i32.const 0))) + (func (export "trap-calling-subtask-cancel") (drop (call $subtask.cancel (i32.const 0)))) + (func (export "trap-calling-subtask-drop") (call $subtask.drop (i32.const 0))) + (func (export "trap-calling-stream-new") (drop (call $stream.new))) + (func (export "trap-calling-stream-read") (drop (call $stream.read (i32.const 0) (i32.const 0) (i32.const 0)))) + (func (export "trap-calling-stream-write") (drop (call $stream.write (i32.const 0) (i32.const 0) (i32.const 0)))) + (func (export "trap-calling-stream-cancel-read") (drop (call $stream.cancel-read (i32.const 0)))) + (func (export "trap-calling-stream-cancel-write") (drop (call $stream.cancel-write (i32.const 0)))) + (func (export "trap-calling-stream-drop-readable") (call $stream.drop-readable (i32.const 0))) + (func (export "trap-calling-stream-drop-writable") (call $stream.drop-writable (i32.const 0))) + (func (export "trap-calling-future-new") (drop (call $future.new))) + (func (export "trap-calling-future-read") (drop (call $future.read (i32.const 0) (i32.const 0)))) + (func (export "trap-calling-future-write") (drop (call $future.write (i32.const 0) (i32.const 0)))) + (func (export "trap-calling-future-cancel-read") (drop (call $future.cancel-read (i32.const 0)))) + (func (export "trap-calling-future-cancel-write") (drop (call $future.cancel-write (i32.const 0)))) + (func (export "trap-calling-future-drop-readable") (call $future.drop-readable (i32.const 0))) + (func (export "trap-calling-future-drop-writable") (call $future.drop-writable (i32.const 0))) + ) + (canon lower (func $import) (core func $import')) + (core instance $dm (instantiate $DM (with "" (instance + (export "mem" (memory $memory "mem")) + (export "import" (func $import')) + (export "resource.new" (func $resource.new)) + (export "resource.drop" (func $resource.drop)) + (export "task.return" (func $task.return)) + (export "task.cancel" (func $task.cancel)) + (export "yield" (func $yield)) + (export "waitable-set.new" (func $waitable-set.new)) + (export "waitable-set.wait" (func $waitable-set.wait)) + (export "waitable-set.poll" (func $waitable-set.poll)) + (export "waitable-set.drop" (func $waitable-set.drop)) + (export "waitable.join" (func $waitable.join)) + (export "subtask.cancel" (func $subtask.cancel)) + (export "subtask.drop" (func $subtask.drop)) + (export "stream.new" (func $stream.new)) + (export "stream.read" (func $stream.read)) + (export "stream.write" (func $stream.write)) + (export "stream.cancel-read" (func $stream.cancel-read)) + (export "stream.cancel-write" (func $stream.cancel-write)) + (export "stream.drop-readable" (func $stream.drop-readable)) + (export "stream.drop-writable" (func $stream.drop-writable)) + (export "future.new" (func $future.new)) + (export "future.read" (func $future.read)) + (export "future.write" (func $future.write)) + (export "future.cancel-read" (func $future.cancel-read)) + (export "future.cancel-write" (func $future.cancel-write)) + (export "future.drop-readable" (func $future.drop-readable)) + (export "future.drop-writable" (func $future.drop-writable)) + )))) + (func (export "trap-calling-import") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-import")))) + (func (export "trap-calling-resource-new") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-resource-new")))) + (func (export "trap-calling-resource-drop") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-resource-drop")))) + (func (export "trap-calling-task-return") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-task-return")))) + (func (export "trap-calling-task-cancel") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-task-cancel")))) + (func (export "trap-calling-yield") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-yield")))) + (func (export "trap-calling-waitable-set-new") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-waitable-set-new")))) + (func (export "trap-calling-waitable-set-wait") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-waitable-set-wait")))) + (func (export "trap-calling-waitable-set-poll") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-waitable-set-poll")))) + (func (export "trap-calling-waitable-set-drop") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-waitable-set-drop")))) + (func (export "trap-calling-waitable-join") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-waitable-join")))) + (func (export "trap-calling-subtask-cancel") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-subtask-cancel")))) + (func (export "trap-calling-subtask-drop") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-subtask-drop")))) + (func (export "trap-calling-stream-new") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-new")))) + (func (export "trap-calling-stream-read") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-read")))) + (func (export "trap-calling-stream-write") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-write")))) + (func (export "trap-calling-stream-cancel-read") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-cancel-read")))) + (func (export "trap-calling-stream-cancel-write") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-cancel-write")))) + (func (export "trap-calling-stream-drop-readable") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-drop-readable")))) + (func (export "trap-calling-stream-drop-writable") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-drop-writable")))) + (func (export "trap-calling-future-new") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-new")))) + (func (export "trap-calling-future-read") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-read")))) + (func (export "trap-calling-future-write") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-write")))) + (func (export "trap-calling-future-cancel-read") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-cancel-read")))) + (func (export "trap-calling-future-cancel-write") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-cancel-write")))) + (func (export "trap-calling-future-drop-readable") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-drop-readable")))) + (func (export "trap-calling-future-drop-writable") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-drop-writable")))) + ) + (instance $c (instantiate $C)) + (instance $d (instantiate $D (with "import" (func $c "import")))) + (func (export "trap-calling-import") (alias export $d "trap-calling-import")) + (func (export "trap-calling-resource-new") (alias export $d "trap-calling-resource-new")) + (func (export "trap-calling-resource-drop") (alias export $d "trap-calling-resource-drop")) + (func (export "trap-calling-task-return") (alias export $d "trap-calling-task-return")) + (func (export "trap-calling-task-cancel") (alias export $d "trap-calling-task-cancel")) + (func (export "trap-calling-yield") (alias export $d "trap-calling-yield")) + (func (export "trap-calling-waitable-set-new") (alias export $d "trap-calling-waitable-set-new")) + (func (export "trap-calling-waitable-set-wait") (alias export $d "trap-calling-waitable-set-wait")) + (func (export "trap-calling-waitable-set-poll") (alias export $d "trap-calling-waitable-set-poll")) + (func (export "trap-calling-waitable-set-drop") (alias export $d "trap-calling-waitable-set-drop")) + (func (export "trap-calling-waitable-join") (alias export $d "trap-calling-waitable-join")) + (func (export "trap-calling-subtask-cancel") (alias export $d "trap-calling-subtask-cancel")) + (func (export "trap-calling-subtask-drop") (alias export $d "trap-calling-subtask-drop")) + (func (export "trap-calling-stream-new") (alias export $d "trap-calling-stream-new")) + (func (export "trap-calling-stream-read") (alias export $d "trap-calling-stream-read")) + (func (export "trap-calling-stream-write") (alias export $d "trap-calling-stream-write")) + (func (export "trap-calling-stream-cancel-read") (alias export $d "trap-calling-stream-cancel-read")) + (func (export "trap-calling-stream-cancel-write") (alias export $d "trap-calling-stream-cancel-write")) + (func (export "trap-calling-stream-drop-readable") (alias export $d "trap-calling-stream-drop-readable")) + (func (export "trap-calling-stream-drop-writable") (alias export $d "trap-calling-stream-drop-writable")) + (func (export "trap-calling-future-new") (alias export $d "trap-calling-future-new")) + (func (export "trap-calling-future-read") (alias export $d "trap-calling-future-read")) + (func (export "trap-calling-future-write") (alias export $d "trap-calling-future-write")) + (func (export "trap-calling-future-cancel-read") (alias export $d "trap-calling-future-cancel-read")) + (func (export "trap-calling-future-cancel-write") (alias export $d "trap-calling-future-cancel-write")) + (func (export "trap-calling-future-drop-readable") (alias export $d "trap-calling-future-drop-readable")) + (func (export "trap-calling-future-drop-writable") (alias export $d "trap-calling-future-drop-writable")) +) + +(component instance $i1 $Tester) +(assert_trap (invoke "trap-calling-import") "cannot leave component instance") +(component instance $i2 $Tester) +(assert_trap (invoke "trap-calling-resource-new") "cannot leave component instance") +(component instance $i3 $Tester) +(assert_trap (invoke "trap-calling-resource-drop") "cannot leave component instance") +(component instance $i4 $Tester) +(assert_trap (invoke "trap-calling-task-return") "cannot leave component instance") +(component instance $i5 $Tester) +(assert_trap (invoke "trap-calling-task-cancel") "cannot leave component instance") +(component instance $i6 $Tester) +(assert_trap (invoke "trap-calling-yield") "cannot leave component instance") +(component instance $i7 $Tester) +(assert_trap (invoke "trap-calling-waitable-set-new") "cannot leave component instance") +(component instance $i8 $Tester) +(assert_trap (invoke "trap-calling-waitable-set-wait") "cannot leave component instance") +(component instance $i9 $Tester) +(assert_trap (invoke "trap-calling-waitable-set-poll") "cannot leave component instance") +(component instance $i10 $Tester) +(assert_trap (invoke "trap-calling-waitable-set-drop") "cannot leave component instance") +(component instance $i11 $Tester) +(assert_trap (invoke "trap-calling-waitable-join") "cannot leave component instance") +(component instance $i12 $Tester) +(assert_trap (invoke "trap-calling-subtask-cancel") "cannot leave component instance") +(component instance $i13 $Tester) +(assert_trap (invoke "trap-calling-subtask-drop") "cannot leave component instance") +(component instance $i14 $Tester) +(assert_trap (invoke "trap-calling-stream-new") "cannot leave component instance") +(component instance $i15 $Tester) +(assert_trap (invoke "trap-calling-stream-read") "cannot leave component instance") +(component instance $i16 $Tester) +(assert_trap (invoke "trap-calling-stream-write") "cannot leave component instance") +(component instance $i17 $Tester) +(assert_trap (invoke "trap-calling-stream-cancel-read") "cannot leave component instance") +(component instance $i18 $Tester) +(assert_trap (invoke "trap-calling-stream-cancel-write") "cannot leave component instance") +(component instance $i19 $Tester) +(assert_trap (invoke "trap-calling-stream-drop-readable") "cannot leave component instance") +(component instance $i20 $Tester) +(assert_trap (invoke "trap-calling-stream-drop-writable") "cannot leave component instance") +(component instance $i21 $Tester) +(assert_trap (invoke "trap-calling-future-new") "cannot leave component instance") +(component instance $i22 $Tester) +(assert_trap (invoke "trap-calling-future-read") "cannot leave component instance") +(component instance $i23 $Tester) +(assert_trap (invoke "trap-calling-future-write") "cannot leave component instance") +(component instance $i24 $Tester) +(assert_trap (invoke "trap-calling-future-cancel-read") "cannot leave component instance") +(component instance $i25 $Tester) +(assert_trap (invoke "trap-calling-future-cancel-write") "cannot leave component instance") +(component instance $i26 $Tester) +(assert_trap (invoke "trap-calling-future-drop-readable") "cannot leave component instance") +(component instance $i27 $Tester) +(assert_trap (invoke "trap-calling-future-drop-writable") "cannot leave component instance") + + +;; built-ins that don't trap: +(component + (canon context.get i32 0 (core func $context.get)) + (canon context.set i32 0 (core func $context.set)) + (core module $CM + (import "" "context.get" (func $context.get (result i32))) + (import "" "context.set" (func $context.set (param i32))) + (global $saved (mut i32) (i32.const 0)) + + (func (export "f") (result i32) + (call $context.set (i32.const 42)) + (i32.const 7) + ) + (func (export "f-pr") (param i32) + (global.set $saved (call $context.get)) + (call $context.set (i32.const 99)) + ) + (func (export "check") (result i32) + (global.get $saved) + ) + ) + (core instance $cm (instantiate $CM (with "" (instance + (export "context.get" (func $context.get)) + (export "context.set" (func $context.set)) + )))) + (func (export "f") (result u32) (canon lift + (core func $cm "f") + (post-return (func $cm "f-pr")) + )) + (func (export "check") (result u32) (canon lift + (core func $cm "check") + )) +) +(assert_return (invoke "f") (u32.const 7)) +(assert_return (invoke "check") (u32.const 42)) + + +(component + (type $R (resource (rep i32))) + (canon resource.new $R (core func $resource.new)) + (canon resource.rep $R (core func $resource.rep)) + (core module $CM + (import "" "resource.new" (func $resource.new (param i32) (result i32))) + (import "" "resource.rep" (func $resource.rep (param i32) (result i32))) + + (global $handle (mut i32) (i32.const 0)) + (global $saved-rep (mut i32) (i32.const 0)) + + (func (export "f") (result i32) + (global.set $handle (call $resource.new (i32.const 123))) + (i32.const 5) + ) + (func (export "f-pr") (param i32) + (global.set $saved-rep (call $resource.rep (global.get $handle))) + ) + (func (export "check") (result i32) + (global.get $saved-rep) + ) + ) + (core instance $cm (instantiate $CM (with "" (instance + (export "resource.new" (func $resource.new)) + (export "resource.rep" (func $resource.rep)) + )))) + (func (export "f") (result u32) (canon lift + (core func $cm "f") + (post-return (func $cm "f-pr")) + )) + (func (export "check") (result u32) (canon lift + (core func $cm "check") + )) +) +(assert_return (invoke "f") (u32.const 5)) +(assert_return (invoke "check") (u32.const 123)) + + +(component + (canon backpressure.inc (core func $bp.inc)) + (canon backpressure.dec (core func $bp.dec)) + (core module $CM + (import "" "bp.inc" (func $bp.inc)) + (import "" "bp.dec" (func $bp.dec)) + + (func (export "f") (result i32) + (i32.const 11) + ) + (func (export "f-pr") (param i32) + (call $bp.inc) + (call $bp.dec) + ) + ) + (core instance $cm (instantiate $CM (with "" (instance + (export "bp.inc" (func $bp.inc)) + (export "bp.dec" (func $bp.dec)) + )))) + (func (export "f") (result u32) (canon lift + (core func $cm "f") + (post-return (func $cm "f-pr")) + )) +) +(assert_return (invoke "f") (u32.const 11)) + + +(component + (canon thread.index (core func $thread.index)) + (core module $CM + (import "" "thread.index" (func $thread.index (result i32))) + + (global $body-idx (mut i32) (i32.const -1)) + (global $pr-idx (mut i32) (i32.const -1)) + + (func (export "f") (result i32) + (global.set $body-idx (call $thread.index)) + (i32.const 13) + ) + (func (export "f-pr") (param i32) + (global.set $pr-idx (call $thread.index)) + ) + (func (export "check") (result i32) + (i32.eq (global.get $body-idx) (global.get $pr-idx)) + ) + ) + (core instance $cm (instantiate $CM (with "" (instance + (export "thread.index" (func $thread.index)) + )))) + (func (export "f") (result u32) (canon lift + (core func $cm "f") + (post-return (func $cm "f-pr")) + )) + (func (export "check") (result u32) (canon lift + (core func $cm "check") + )) +) +(assert_return (invoke "f") (u32.const 13)) +(assert_return (invoke "check") (u32.const 1)) diff --git a/src/test/resources/spec-tests/values/strings.wast b/src/test/resources/spec-tests/values/strings.wast new file mode 100644 index 0000000..e838ccd --- /dev/null +++ b/src/test/resources/spec-tests/values/strings.wast @@ -0,0 +1,136 @@ +(component + (core module $M + (memory (export "mem") 1) + (func (export "f1") (result i32) + (i32.store (i32.const 0) (i32.const 8)) + (i32.store (i32.const 4) (i32.const 1)) + (i32.store8 (i32.const 8) (i32.const 97)) + (i32.const 0) + ) + (func (export "f2") (result i32) + (i32.store (i32.const 0) (i32.const 8)) + (i32.store (i32.const 4) (i32.const 14)) + (i64.store (i32.const 8) (i64.const 0xb8_ef_ba_98_e2_83_98_e2)) + (i32.store (i32.const 16) (i32.const 0xe3_b6_c3_8f)) + (i32.store16 (i32.const 20) (i32.const 0x84_83)) + (i32.const 0) + ) + ;; TODO: so many cases left to test, everyone feel free to fill in... + ) + (core instance $m (instantiate $M)) + (func (export "f1") (result string) (canon lift (core func $m "f1") (memory $m "mem"))) + (func (export "f2") (result string) (canon lift (core func $m "f2") (memory $m "mem"))) +) +(assert_return (invoke "f1") (str.const "a")) +(assert_return (invoke "f2") (str.const "☃☺️öツ")) + +;; empty string with ptr=0, len=0 +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 0)) + (i32.store (i32.const 4) (i32.const 0)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_return (invoke "f") (str.const "")) + +;; empty string with non-zero in-bounds ptr, len=0 +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 100)) + (i32.store (i32.const 4) (i32.const 0)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_return (invoke "f") (str.const "")) + +;; out-of-bounds pointer traps even with len=0 +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 0xdeadbeef)) + (i32.store (i32.const 4) (i32.const 0)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_trap (invoke "f") "string pointer/length out of bounds of memory") + +;; invalid UTF-8: 0xFF is never valid +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 8)) + (i32.store (i32.const 4) (i32.const 1)) + (i32.store8 (i32.const 8) (i32.const 0xff)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_trap (invoke "f") "invalid utf-8") + +;; truncated multibyte UTF-8: leading byte 0xC3 expects a continuation byte +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 8)) + (i32.store (i32.const 4) (i32.const 1)) + (i32.store8 (i32.const 8) (i32.const 0xc3)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_trap (invoke "f") "incomplete utf-8 byte sequence") + +;; string at end of memory page boundary +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + ;; place "ok" at the very end of the first page (65536 - 2 = 65534) + (i32.store (i32.const 0) (i32.const 65534)) + (i32.store (i32.const 4) (i32.const 2)) + (i32.store8 (i32.const 65534) (i32.const 111)) ;; 'o' + (i32.store8 (i32.const 65535) (i32.const 107)) ;; 'k' + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_return (invoke "f") (str.const "ok")) + +;; string one byte past end of memory traps +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 65535)) + (i32.store (i32.const 4) (i32.const 2)) + (i32.store8 (i32.const 65535) (i32.const 111)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_trap (invoke "f") "string pointer/length out of bounds of memory") diff --git a/src/test/resources/spec-tests/wasm-tools/adapt.wast b/src/test/resources/spec-tests/wasm-tools/adapt.wast new file mode 100644 index 0000000..8cc76f8 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/adapt.wast @@ -0,0 +1,287 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (import "log" (func $log (param "msg" string))) + (core module $libc + (memory (export "memory") 1) + (func (export "canonical_abi_realloc") (param i32 i32 i32 i32) (result i32) + unreachable) + ) + + (core module $my_module + (import "env" "log-utf8" (func $log_utf8 (param i32 i32))) + (import "env" "log-utf16" (func $log_utf16 (param i32 i32))) + (import "env" "log-compact-utf16" (func $log_compact_utf16 (param i32 i32))) + + (func (export "log-utf8") (param i32 i32) + local.get 0 + local.get 1 + call $log_utf8 + ) + (func (export "log-utf16") (param i32 i32) + local.get 0 + local.get 1 + call $log_utf16 + ) + (func (export "log-compact-utf16") (param i32 i32) + local.get 0 + local.get 1 + call $log_compact_utf16 + ) + ) + + (core instance $libc (instantiate $libc)) + + (alias core export $libc "canonical_abi_realloc" (core func $realloc)) + (alias core export $libc "memory" (core memory $memory)) + (core func $log_lower_utf8 (canon lower (func $log) string-encoding=utf8 (memory $memory) (realloc $realloc))) + (core func $log_lower_utf16 (canon lower (func $log) string-encoding=utf16 (memory $memory) (realloc $realloc))) + (core func $log_lower_compact_utf16 (canon lower (func $log) string-encoding=latin1+utf16 (memory $memory) (realloc $realloc))) + + (core instance $my_instance (instantiate $my_module + (with "libc" (instance $libc)) + (with "env" (instance + (export "log-utf8" (func $log_lower_utf8)) + (export "log-utf16" (func $log_lower_utf16)) + (export "log-compact-utf16" (func $log_lower_compact_utf16)) + )) + )) + + (func (export "log1") (param "msg" string) + (canon lift + (core func $my_instance "log-utf8") + string-encoding=utf8 + (memory $memory) + (realloc $realloc) + ) + ) + (func (export "log2") (param "msg" string) + (canon lift + (core func $my_instance "log-utf16") + string-encoding=utf16 + (memory $memory) + (realloc $realloc) + ) + ) + (func (export "log3") (param "msg" string) + (canon lift + (core func $my_instance "log-compact-utf16") + string-encoding=latin1+utf16 + (memory $memory) + (realloc $realloc) + ) + ) +) + +(assert_invalid + (component + (import "i" (func $f)) + (core func (canon lower (func $f) string-encoding=utf8 string-encoding=utf16)) + ) + "canonical encoding option `utf8` conflicts with option `utf16`") + +(assert_invalid + (component + (import "i" (func $f)) + (core func (canon lower (func $f) string-encoding=utf8 string-encoding=latin1+utf16)) + ) + "canonical encoding option `utf8` conflicts with option `latin1-utf16`") + +(assert_invalid + (component + (import "i" (func $f)) + (core func (canon lower (func $f) string-encoding=utf16 string-encoding=latin1+utf16)) + ) + "canonical encoding option `utf16` conflicts with option `latin1-utf16`") + +(assert_invalid + (component + (import "i" (func $f)) + (core func (canon lower (func $f) (memory 0))) + ) + "memory index out of bounds") + +(assert_invalid + (component + (import "i" (func $f)) + (core module $m (memory (export "memory") 1)) + (core instance $i (instantiate $m)) + (core func (canon lower (func $f) (memory $i "memory") (memory $i "memory"))) + ) + "`memory` is specified more than once") + +(assert_invalid + (component + (core module $m + (func (export "f") (param i32 i32)) + ) + (core instance $i (instantiate $m)) + (func (param "p1" (list u8)) (canon lift (core func $i "f"))) + ) + "canonical option `memory` is required") + +(assert_invalid + (component + (core module $m + (memory (export "m") 1) + (func (export "f") (param i32 i32)) + ) + (core instance $i (instantiate $m)) + (func (param "p1" (list u8)) + (canon lift (core func $i "f") + (memory $i "m") + ) + ) + ) + "canonical option `realloc` is required") + +(assert_invalid + (component + (core module $m + (memory (export "m") 1) + (func (export "f") (param i32 i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + ) + (core instance $i (instantiate $m)) + (func (param "p1" (list u8)) + (canon lift (core func $i "f") + (memory $i "m") + (realloc (func $i "r")) + (realloc (func $i "r")) + ) + ) + ) + "canonical option `realloc` is specified more than once") + +(assert_invalid + (component + (core module $m + (memory (export "m") 1) + (func (export "f") (param i32 i32)) + (func (export "r")) + ) + (core instance $i (instantiate $m)) + (func (param "p1" (list u8)) + (canon lift (core func $i "f") + (memory $i "m") + (realloc (func $i "r")) + ) + ) + ) + "canonical option `realloc` uses a core function with an incorrect signature") + +(assert_invalid + (component + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + (func (export "p")) + ) + (core instance $i (instantiate $m)) + (func (result string) + (canon lift (core func $i "f") + (memory $i "m") + (realloc (func $i "r")) + (post-return (func $i "p")) + ) + ) + ) + "canonical option `post-return` uses a core function with an incorrect signature") + +(assert_invalid + (component + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + (func (export "p") (param i32)) + ) + (core instance $i (instantiate $m)) + (func (result string) + (canon lift (core func $i "f") + (memory $i "m") + (realloc (func $i "r")) + (post-return (func $i "p")) + (post-return (func $i "p")) + ) + ) + ) + "canonical option `post-return` is specified more than once") + +(assert_invalid + (component + (import "i" (func $f (param "p1" string))) + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + (func (export "p") (param i32)) + ) + (core instance $i (instantiate $m)) + (core func + (canon lower (func $f) + (memory $i "m") + (realloc (func $i "r")) + (post-return (func $i "p")) + ) + ) + ) + "canonical option `post-return` cannot be specified for lowerings") + +(component + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32) unreachable) + (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable) + (func (export "p") (param i32)) + ) + (core instance $i (instantiate $m)) + (func (result string) + (canon lift (core func $i "f") + (memory $i "m") + (realloc (func $i "r")) + (post-return (func $i "p")) + ) + ) +) + +(assert_malformed + (component quote + "(core module $m (func (export \"\")))" + "(core instance $i (instantiate $m))" + "(core func (canon lower (func $i \"\")))" + ) + "unknown instance: failed to find name `$i`") + +(assert_invalid + (component + (core module $m (func (export "foo") (param i32))) + (core instance $i (instantiate $m)) + (func (export "foo") (canon lift (core func $i "foo"))) + ) + "lowered parameter types `[]` do not match parameter types `[I32]`") + +(assert_invalid + (component + (core module $m (func (export "foo") (result i32))) + (core instance $i (instantiate $m)) + (func (export "foo") (canon lift (core func $i "foo"))) + ) + "lowered result types `[]` do not match result types `[I32]`") + +(assert_invalid + (component + (type $f string) + (core module $m (func (export "foo"))) + (core instance $i (instantiate $m)) + (func (export "foo") (type $f) (canon lift (core func $i "foo"))) + ) + "not a function type") + +(assert_malformed + (component quote + "(import \"a\" (func $f))" + "(func (export \"foo\") (canon lift (core func $f)))" + ) + "unknown core func: failed to find name `$f`") diff --git a/src/test/resources/spec-tests/wasm-tools/alias.wast b/src/test/resources/spec-tests/wasm-tools/alias.wast new file mode 100644 index 0000000..dd9d1b3 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/alias.wast @@ -0,0 +1,301 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (component + (import "i" (instance $i + (export "f1" (func)) + (export "f2" (func (param "p1" string))) + )) + (export "run" (func $i "f1")) + ) +) + +(component + (component + (import "i" (component $c + (export "f1" (func)) + (export "f2" (func (param "p1" string))) + )) + (instance $i (instantiate $c)) + (export "run" (func $i "f1")) + ) +) + +(component definition + (import "i" (core module $m + (export "f1" (func $f1)) + (export "f2" (func $f2 (param i32))) + )) + (core instance $i (instantiate $m)) + + (core module $m2 (import "" "" (func))) + + (core instance (instantiate $m2 (with "" (instance (export "" (func $i "f1")))))) +) + +(component definition + (import "a" (core module $libc + (export "memory" (memory 1)) + (export "table" (table 0 funcref)) + (export "func" (func)) + (export "global" (global i32)) + (export "global mut" (global (mut i64))) + )) + (core instance $libc (instantiate $libc)) + (alias core export $libc "memory" (core memory $mem)) + (alias core export $libc "table" (core table $tbl)) + (alias core export $libc "func" (core func $func)) + (alias core export $libc "global" (core global $global)) + (alias core export $libc "global mut" (core global $global_mut)) + + (import "x" (core module $needs_libc + (import "" "memory" (memory 1)) + (import "" "table" (table 0 funcref)) + (import "" "func" (func)) + (import "" "global" (global i32)) + (import "" "global mut" (global (mut i64))) + )) + + (core instance (instantiate $needs_libc (with "" (instance + (export "memory" (memory $mem)) + (export "table" (table $tbl)) + (export "func" (func $func)) + (export "global" (global $global)) + (export "global mut" (global $global_mut)) + )))) +) + +(component + (component + (import "a" (instance $i + (export "a" (func)) + (export "b" (core module)) + (export "c" (instance)) + )) + (export "b" (func $i "a")) + (export "c" (core module $i "b")) + (export "d" (instance $i "c")) + ) +) + + +(component definition + (import "a" (core module $libc + (export "memory" (memory 1)) + (export "table" (table 0 funcref)) + (export "func" (func)) + (export "global" (global i32)) + (export "global mut" (global (mut i64))) + )) + + (import "b" (core module $needs_libc + (import "" "memory" (memory 1)) + (import "" "table" (table 0 funcref)) + (import "" "func" (func)) + (import "" "global" (global i32)) + (import "" "global mut" (global (mut i64))) + )) + + (core instance $libc (instantiate $libc)) + (core instance (instantiate $needs_libc (with "" (instance + (export "memory" (memory $libc "memory")) + (export "table" (table $libc "table")) + (export "func" (func $libc "func")) + (export "global" (global $libc "global")) + (export "global mut" (global $libc "global mut")) + )))) +) + +(assert_invalid + (component + (import "a" (instance (export "a" (func)))) + (export "a" (core module 0 "a")) + ) + "export `a` for instance 0 is not a module") + +(assert_invalid + (component + (component + (component (export "a")) + ) + (instance (instantiate 0)) + (export "a" (core module 0 "a")) + ) + "export `a` for instance 0 is not a module") + +(assert_invalid + (component + (import "a" (core module)) + (core instance (instantiate 0)) + (alias core export 0 "a" (core func)) + ) + "core instance 0 has no export named `a`") + +(assert_invalid + (component + (core module) + (core instance (instantiate 0)) + (alias core export 0 "a" (core func)) + ) + "core instance 0 has no export named `a`") + +(assert_invalid + (component + (import "a" (component)) + (instance (instantiate 0)) + (alias export 0 "a" (func)) + ) + "instance 0 has no export named `a`") + +(assert_invalid + (component + (import "a" (core module $a (export "" (func)))) + (import "b" (core module $b (import "" "" (func (param i32))))) + + (core instance $a (instantiate $a)) + (core instance $b (instantiate $b (with "" (instance $a)))) + ) + "type mismatch") + +;; aliasing various items works + +(component $PARENT + (type $t (func (result string))) + (component + (import "a" (func (type $t))) + ) + (component + (alias outer $PARENT $t (type $my_type)) + (alias outer 0 $my_type (type $my_type_again)) + (import "a" (func (type $my_type_again))) + ) +) + +(component + (type $a (func (result string))) + (component + (type $b (func (result u32))) + (component + (type $c (func (result s32))) + + (component + (import "a" (func $a (type $a))) + (import "b" (func $b (type $b))) + (import "c" (func $c (type $c))) + + (import "d" (component $C + (import "a" (func (result string))) + (import "b" (func (result u32))) + (import "c" (func (result s32))) + )) + + (instance (instantiate $C + (with "a" (func $a)) + (with "b" (func $b)) + (with "c" (func $c)) + )) + ) + ) + ) +) + +;; multiple projections in alias sugar +(component + (component $a + (import "a" (instance $a + (export "a" (instance + (export "a" (instance + (export "a" (instance + (export "a" (func)) + )) + )) + )) + )) + + (import "b" (component $b (import "a" (func)))) + + (instance (instantiate $b + (with "a" (func $a "a" "a" "a" "a")) + )) + ) +) + +;; alias some constructs +(component + (component + (import "a" (instance $foo (export "v" (component)))) + (export "v" (component $foo "v")) + ) +) + +(component definition + (import "a" (instance $foo (export "v" (core module)))) + (export "v" (core module $foo "v")) +) + +(component $C + (core type $t (func)) + (component $C2 + (alias outer $C $t (core type $t2)) + (component + (alias outer $C $t (core type)) + (alias outer $C2 $t2 (core type)) + ) + ) +) + +(component $C + (core module $m) + (alias outer $C $m (core module $target)) + (export "v" (core module $target)) +) + +(component + (component $C + (component $m) + (alias outer $C $m (component $target)) + (export "v" (component $target)) + ) +) + +(assert_invalid + (component (alias outer 100 0 (core type))) + "invalid outer alias count of 100") + +(assert_invalid + (component (alias outer 0 0 (core type))) + "index out of bounds") + +(assert_invalid + (component (alias outer 100 0 (core module))) + "invalid outer alias count of 100") + +(assert_invalid + (component (alias outer 0 0 (core module))) + "index out of bounds") + +(assert_invalid + (component (alias outer 100 0 (component))) + "invalid outer alias count of 100") + +(assert_invalid + (component (alias outer 0 0 (component))) + "index out of bounds") + +(component definition + (import "a" (instance $i + (export "x" (core module)) + )) + ;; inline alias injection sugar works for module references + (core instance (instantiate (module $i "x"))) +) + +(component + (component + (import "a" (instance $i + (export "x" (component)) + )) + ;; inline alias injection sugar works for component references + (instance (instantiate (component $i "x"))) + ) +) diff --git a/src/test/resources/spec-tests/wasm-tools/big.wast b/src/test/resources/spec-tests/wasm-tools/big.wast new file mode 100644 index 0000000..770df0a --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/big.wast @@ -0,0 +1,36 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (import "wasi-logging" (instance $logging + (export "log" (func (param "msg" string))) + )) + (import "libc" (core module $Libc + (export "memory" (memory 1)) + (export "realloc" (func (param i32 i32 i32 i32) (result i32))) + )) + (core instance $libc (instantiate $Libc)) + (core func $log (canon lower + (func $logging "log") + (memory $libc "memory") (realloc (func $libc "realloc")) + )) + (core module $Main + (import "libc" "memory" (memory 1)) + (import "libc" "realloc" (func (param i32 i32 i32 i32) (result i32))) + (import "wasi-logging" "log" (func $log (param i32 i32))) + (func (export "run") (param i32 i32) (result i32) + (local.get 0) + (local.get 1) + (call $log) + (unreachable) + ) + ) + (core instance $main (instantiate $Main + (with "libc" (instance $libc)) + (with "wasi-logging" (instance (export "log" (func $log)))) + )) + (func $run (param "in" string) (result string) (canon lift + (core func $main "run") + (memory $libc "memory") (realloc (func $libc "realloc")) + )) + (export "run" (func $run)) +) diff --git a/src/test/resources/spec-tests/wasm-tools/definedtypes.wast b/src/test/resources/spec-tests/wasm-tools/definedtypes.wast new file mode 100644 index 0000000..ca24c12 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/definedtypes.wast @@ -0,0 +1,123 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component $C + (type $A1 bool) + (type $A2 u8) + (type $A3 s8) + (type $A4 u16) + (type $A5 s16) + (type $A6 u32) + (type $A7 s32) + (type $A8 u64) + (type $A9 s64) + (type $A10a f32) + (type $A11a f64) + (type $A10b float32) + (type $A11b float64) + (type $A12 char) + (type $A13 string) + + (type $A14b (record (field "x" (tuple char)))) + (type $A14c (record (field "x" $A1))) + + (type $A15a (variant (case "x"))) + (type $A15b (variant (case "x" $A1))) + (type $A15c (variant (case $x "x") (case $y "y" string) (case "z" string))) + (type $A15d (variant (case "x") (case "y" string) (case "z" string))) + + (type $A16a (list (tuple u8))) + (type $A16b (list $A3)) + + (type $A17a (tuple u8)) + (type $A17b (tuple $A4)) + + (type $A18b (flags "x")) + + (type $A19b (enum "x")) + + (type $A21a (option (tuple u32))) + (type $A21b (option $A6)) + + (type $A22a (result)) + (type $A22b (result $A7)) + (type $A22c (result (error $A8))) + (type $A22d (result $A9 (error $A10a))) +) + +(assert_malformed + (component quote + "(type $t string)" + "(type $v (variant (case $x \"x\" $t) (case $x \"y\" $t)))" + ) + "duplicate variant case identifier" +) + +(assert_invalid + (component + (type $t (func)) + (type (func (param "t" $t))) + ) + "type index 0 is not a defined type") + +(assert_invalid + (component + (type $t (instance)) + (type (func (result $t))) + ) + "type index 0 is not a defined type") + +(assert_invalid + (component + (type $t (component)) + (type (option $t)) + ) + "type index 0 is not a defined type") + +(assert_invalid + (component (type (option 0))) + "index out of bounds") +(assert_invalid + (component (type (list 0))) + "index out of bounds") +(assert_invalid + (component (type (record (field "x" 0)))) + "index out of bounds") +(assert_invalid + (component (type (variant (case "x" 0)))) + "index out of bounds") +(assert_invalid + (component (type (result 0 (error 1)))) + "index out of bounds") +(assert_invalid + (component (type (tuple 0))) + "index out of bounds") + +(assert_invalid + (component (type (record (field "a-B-c-D" string) (field "A-b-C-d" u8)))) + "record field name `A-b-C-d` conflicts with previous field name `a-B-c-D`") +(assert_invalid + (component (type (variant (case "x" s64) (case "x" s64)))) + "variant case name `x` conflicts with previous case name `x`") +(assert_invalid + (component (type (flags "x" "y" "X"))) + "flag name `X` conflicts with previous flag name `x`") +(assert_invalid + (component (type (enum "x" "y" "X"))) + "enum tag name `X` conflicts with previous tag name `x`") + +(assert_invalid + (component (type (record (field "" s32)))) + "name cannot be empty") +(assert_invalid + (component (type (variant (case "" s32)))) + "name cannot be empty") +(assert_invalid + (component (type (flags ""))) + "name cannot be empty") +(assert_invalid + (component (type (enum ""))) + "name cannot be empty") + +(assert_invalid + (component (type (variant))) + "variant type must have at least one case") diff --git a/src/test/resources/spec-tests/wasm-tools/empty.wast b/src/test/resources/spec-tests/wasm-tools/empty.wast new file mode 100644 index 0000000..7f22181 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/empty.wast @@ -0,0 +1,4 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; The most minimal component. +(component) diff --git a/src/test/resources/spec-tests/wasm-tools/example.wast b/src/test/resources/spec-tests/wasm-tools/example.wast new file mode 100644 index 0000000..9ba429f --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/example.wast @@ -0,0 +1,17 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; With what's defined so far, we can define the following component: + +(component + (component + (core module (func (export "one") (result i32) (i32.const 1))) + (core module (func (export "two") (result f32) (f32.const 2))) + ) + (core module (func (export "three") (result i64) (i64.const 3))) + (component + (component + (core module (func (export "four") (result f64) (f64.const 4))) + ) + ) + (component) +) diff --git a/src/test/resources/spec-tests/wasm-tools/export-ascription.wast b/src/test/resources/spec-tests/wasm-tools/export-ascription.wast new file mode 100644 index 0000000..ca70736 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/export-ascription.wast @@ -0,0 +1,44 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (component + (import "f" (func $f)) + (export "f2" (func $f) (func)) + ) +) + +;; subtyping works +(component + (component + (import "f" (instance $i (export "f" (func)))) + (export "f2" (instance $i) (instance)) + ) +) + +;; make sure subtyping works in the right direction +(assert_invalid + (component + (import "f" (instance $i)) + (export "f2" (instance $i) (instance (export "f" (func)))) + ) + "ascribed type of export is not compatible") + +;; make sure the type is actually changed +(assert_invalid + (component + (import "f" (func $f)) + + (component $c + (import "f" (instance $i (export "f" (func)))) + (export "f2" (instance $i) (instance)) + ) + + (instance $c (instantiate $c (with "f" (instance (export "f" (func $f)))))) + + (component $consume + (import "arg" (instance $i (export "f" (func)))) + ) + + (instance (instantiate $consume (with "arg" (instance $c "f2")))) + ) + "missing expected export `f`") diff --git a/src/test/resources/spec-tests/wasm-tools/export-introduces-alias.wast b/src/test/resources/spec-tests/wasm-tools/export-introduces-alias.wast new file mode 100644 index 0000000..40d33ef --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/export-introduces-alias.wast @@ -0,0 +1,48 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (component + (import "x" (func $f)) + + (export $g "g" (func $f)) + (export $g2 "g2" (func $g)) + ) +) + +(component + (type (component + (type $t u8) + (import "x" (instance $i (export "t" (type (eq $t))))) + (alias export $i "t" (type $my-t)) + )) +) + +(component + (type (component + (type $t u8) + (import "x" (instance $i + (export "i" (instance + (export "t" (type (eq $t))) + )) + )) + (alias export $i "i" (instance $my-i)) + (alias export $my-i "t" (type $my-t)) + )) +) + +(assert_malformed + (component quote + "(type (instance" + "(type $t u8)" + "(export \"t\" (type $t (eq $t)))" + "))" + ) + "duplicate type identifier") + +(component + (type (instance + (type $t u8) + (export "t" (type $t2 (eq $t))) + (export "t2" (type $t3 (eq $t2))) + )) +) diff --git a/src/test/resources/spec-tests/wasm-tools/export.wast b/src/test/resources/spec-tests/wasm-tools/export.wast new file mode 100644 index 0000000..73d094c --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/export.wast @@ -0,0 +1,63 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component (export "" (instance 0))) + "index out of bounds") + +(assert_invalid + (component (export "" (component 0))) + "index out of bounds") + +(assert_invalid + (component (export "" (core module 0))) + "index out of bounds") + +(assert_invalid + (component (export "" (func 0))) + "index out of bounds") + +(component + (component + (import "a" (instance $i)) + (import "b" (core module $m)) + (import "c" (component $c)) + (import "e" (func $f)) + + (export "f" (instance $i)) + (export "g" (core module $m)) + (export "h" (component $c)) + (export "j" (func $f)) + ) +) + +(component + (component + (import "a" (func)) + (export (interface "wasi:http/types@2.0.0") (func 0)) + ) +) + +;; import/exports can overlap on ids +(component + (component + (import (interface "wasi:http/types@2.0.0") (func)) + (export (interface "wasi:http/types@2.0.0") (func 0)) + ) +) + +;; cannot export some types of strings +(assert_invalid + (component (type (component (export "integrity=" (func))))) + "not a valid export name") +(assert_invalid + (component (type (component (export "url=" (func))))) + "not a valid export name") +(assert_invalid + (component (type (component (export "relative-url=" (func))))) + "not a valid extern name") +(assert_invalid + (component (type (component (export "locked-dep=" (func))))) + "not a valid export name") +(assert_invalid + (component (type (component (export "unlocked-dep=" (func))))) + "not a valid export name") diff --git a/src/test/resources/spec-tests/wasm-tools/func.wast b/src/test/resources/spec-tests/wasm-tools/func.wast new file mode 100644 index 0000000..4a207f9 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/func.wast @@ -0,0 +1,146 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (import "a" (func (param "foo" string))) + (import "b" (func (param "foo" string) (param "bar" s32) (param "baz" u32))) + (import "c" (func (result (tuple u8)))) +) + +(component definition + (import "a" (func)) + (import "b" (func (param "p1" string))) + (import "c" (func (result u32))) + (import "d" (func (param "p1" bool) (result string))) +) + + +(assert_invalid + (component + (type (func (param "foo" string) (param "FOO" u32))) + ) + "function parameter name `FOO` conflicts with previous parameter name `foo`" +) + +(assert_invalid + (component + (core module $m + (memory (export "memory") 1) + (func (export "foo") (result i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "tuple") (result (tuple s8 u8)) + (canon lift (core func $i "foo")) + ) + ) + "canonical option `memory` is required" +) + +(component definition + (import "a" (func $log (param "msg" string))) + (core module $libc + (memory (export "memory") 1) + ) + (core instance $libc (instantiate $libc)) + (core func (canon lower (func $log) (memory $libc "memory"))) +) + +(component + (core module $m + (memory (export "memory") 1) + (func (export "ret-list") (result i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "ret-list") (result (list u8)) + (canon lift (core func $i "ret-list") (memory $i "memory")) + ) +) + +(component + (type $big (func + (param "p1" u32) (param "p2" u32) (param "p3" u32) (param "p4" u32) (param "p5" u32) + (param "p6" u32) (param "p7" u32) (param "p8" u32) (param "p9" u32) (param "p10" u32) + (param "p11" u32) (param "p12" u32) (param "p13" u32) (param "p14" u32) (param "p15" u32) + (param "p16" u32) (param "p17" u32) (param "p18" u32) (param "p19" u32) (param "p20" u32) + )) + + (component $c + (import "big" (func $big (type $big))) + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func $big (canon lower (func $big) (memory $libc "memory"))) + ) +) + +(assert_invalid + (component + (core module $m + (memory (export "memory") 1) + (func (export "roundtrip") (param i32)) + ) + (core instance $m (instantiate $m)) + + (type $roundtrip (func + (param "p1" u32) (param "p2" u32) (param "p3" u32) (param "p4" u32) (param "p5" u32) + (param "p6" u32) (param "p7" u32) (param "p8" u32) (param "p9" u32) (param "p10" u32) + (param "p11" u32) (param "p12" u32) (param "p13" u32) (param "p14" u32) (param "p15" u32) + (param "p16" u32) (param "p17" u32) (param "p18" u32) (param "p19" u32) (param "p20" u32) + )) + + (func $roundtrip (type $roundtrip) + (canon lift (core func $m "roundtrip") (memory $m "memory")) + ) + (export "roundtrip" (func $roundtrip)) + ) + "canonical option `realloc` is required" +) + +(assert_invalid + (component + (import "a" (func $log (result string))) + (core module $libc + (memory (export "memory") 1) + ) + (core instance $libc (instantiate $libc)) + (core func (canon lower (func $log) (memory $libc "memory"))) + ) + "canonical option `realloc` is required" +) + +(assert_invalid + (component + (core module $m + (memory (export "memory") 1) + (func (export "param-list") (param i32 i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "param-list") (param "bytes" (list u8)) + (canon lift (core func $i "param-list") (memory $i "memory")) + ) + ) + "canonical option `realloc` is required" +) + +(assert_malformed + (component binary + "\00asm" "\0d\00\01\00" ;; component header + "\07\05" ;; component type section, 5 bytes + "\01" ;; 1 count + "\40" ;; component function type + "\00" ;; 0 parameters + "\01\01" ;; invalid result encoding + ) + "invalid leading byte (0x1) for number of results") + +(assert_malformed + (component binary + "\00asm" "\0d\00\01\00" ;; component header + "\07\05" ;; component type section, 5 bytes + "\01" ;; 1 count + "\40" ;; component function type + "\00" ;; 0 parameters + "\02\00" ;; invalid result encoding + ) + "invalid leading byte (0x2) for component function results") diff --git a/src/test/resources/spec-tests/wasm-tools/import.wast b/src/test/resources/spec-tests/wasm-tools/import.wast new file mode 100644 index 0000000..b226157 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/import.wast @@ -0,0 +1,359 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (component + (import "a" (func)) + (import "b" (instance)) + (import "c" (instance + (export "a" (func)) + )) + (import "d" (component + (import "a" (core module)) + (export "b" (func)) + )) + (type $t (func)) + (import "e" (type (eq $t))) + ) +) + +(assert_invalid + (component + (type $f (func)) + (import "a" (instance (type $f))) + ) + "type index 0 is not an instance type") + +(assert_invalid + (component + (core type $f (func)) + (import "a" (core module (type $f))) + ) + "core type index 0 is not a module type") + +(assert_invalid + (component + (type $f string) + (import "a" (func (type $f))) + ) + "type index 0 is not a function type") + +;; Disallow duplicate imports for core wasm modules +(assert_invalid + (component + (core type (module + (import "" "" (func)) + (import "" "" (func)) + )) + ) + "duplicate import name `:`") +(assert_invalid + (component + (core module + (import "" "" (func)) + (import "" "" (func)) + ) + ) + "duplicate import name `:`") +(assert_invalid + (component + (core type (module + (import "" "a" (func)) + (import "" "a" (func)) + )) + ) + "duplicate import name `:a`") +(assert_invalid + (component + (core module + (import "" "a" (func)) + (import "" "a" (func)) + ) + ) + "duplicate import name `:a`") + +(assert_invalid + (component + (import "a" (func)) + (import "a" (func)) + ) + "import name `a` conflicts with previous name `a`") + +(assert_invalid + (component + (type (component + (import "a" (func)) + (import "a" (func)) + )) + ) + "import name `a` conflicts with previous name `a`") + +(assert_invalid + (component + (import "a" (func (type 100))) + ) + "type index out of bounds") + +(assert_invalid + (component + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (func (type 100) (canon lift (core func $i ""))) + ) + "type index out of bounds") + +(component definition + (import "wasi:http/types" (func)) + (import "wasi:http/types@1.0.0" (func)) + (import "wasi:http/types@2.0.0" (func)) + (import "a-b:c-d/e-f@123456.7890.488" (func)) + (import "a:b/c@1.2.3" (func)) + (import "a:b/c@0.0.0" (func)) + (import "a:b/c@0.0.0+abcd" (func)) + (import "a:b/c@0.0.0+abcd-efg" (func)) + (import "a:b/c@0.0.0-abcd+efg" (func)) + (import "a:b/c@0.0.0-abcd.1.2+efg.4.ee.5" (func)) +) + +(assert_invalid + (component + (import "wasi:http/types" (func)) + (import "wasi:http/types" (func)) + ) + "conflicts with previous name") + +(assert_invalid + (component (import "" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "wasi:" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "wasi:/" (func))) + "not in kebab case") +(assert_invalid + (component (import ":/" (func))) + "not in kebab case") +(assert_invalid + (component (import "wasi/http" (func))) + "`wasi/http` is not in kebab case") +(assert_invalid + (component (import "wasi:http/TyPeS" (func))) + "`TyPeS` is not in kebab case") +(assert_invalid + (component (import "WaSi:http/types" (func))) + "`WaSi` is not in kebab case") +(assert_invalid + (component (import "wasi:HtTp/types" (func))) + "`HtTp` is not in kebab case") +(assert_invalid + (component (import "wasi:http/types@" (func))) + "empty string") +(assert_invalid + (component (import "wasi:http/types@." (func))) + "unexpected character '.'") +(assert_invalid + (component (import "wasi:http/types@1." (func))) + "unexpected end of input") +(assert_invalid + (component (import "wasi:http/types@a.2" (func))) + "unexpected character 'a'") +(assert_invalid + (component (import "wasi:http/types@2.b" (func))) + "unexpected character 'b'") +(assert_invalid + (component (import "wasi:http/types@2.0x0" (func))) + "unexpected character 'x'") +(assert_invalid + (component (import "wasi:http/types@2.0.0+" (func))) + "empty identifier segment") +(assert_invalid + (component (import "wasi:http/types@2.0.0-" (func))) + "empty identifier segment") +(assert_invalid + (component (import "foo:bar:baz/qux" (func))) + "expected `/` after package name") +(assert_invalid + (component (import "foo:bar/baz/qux" (func))) + "trailing characters found: `/qux`") + +(component + (component + (import "a" (func $a)) + (export "a" (func $a)) + ) +) + +(component definition + (import "unlocked-dep=" (func)) + (import "unlocked-dep=" (func)) + (import "unlocked-dep==1.2.3}>" (func)) + (import "unlocked-dep==1.2.3-rc}>" (func)) + (import "unlocked-dep=" (func)) + (import "unlocked-dep=" (func)) + (import "unlocked-dep==1.2.3 <1.2.3}>" (func)) + (import "unlocked-dep==1.2.3-rc <1.2.3}>" (func)) +) + +(assert_invalid + (component (import "unlocked-dep=" (func))) + "expected `<` at ``") +(assert_invalid + (component (import "unlocked-dep=<" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "unlocked-dep=<>" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "unlocked-dep=<:>" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "unlocked-dep=" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "unlocked-dep=<:a>" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "unlocked-dep=" (func))) + "expected `{` at `>`") +(assert_invalid + (component (import "unlocked-dep=" (func))) + "expected `>=` or `<` at start of version range") +(assert_invalid + (component (import "unlocked-dep=" (func))) + "`xyz` is not a valid semver") +(assert_invalid + (component (import "unlocked-dep==2.3.4}>" (func))) + "`1.2.3 >=2.3.4` is not a valid semver") + +(component definition + (import "locked-dep=" (func)) + (import "locked-dep=" (func)) + (import "locked-dep=,integrity=" (func)) + (import "locked-dep=,integrity=" (func)) +) + +(assert_invalid + (component (import "locked-dep=" (func))) + "expected `<` at ``") +(assert_invalid + (component (import "locked-dep=<" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "locked-dep=<:" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "locked-dep=<:>" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "locked-dep=" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "locked-dep=<:a>" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "locked-dep=` at ``") +(assert_invalid + (component (import "locked-dep=" (func))) + "is not a valid semver") +(assert_invalid + (component (import "locked-dep=` at ``") +(assert_invalid + (component (import "locked-dep=," (func))) + "expected `integrity=<`") +(assert_invalid + (component (import "locked-dep=x" (func))) + "trailing characters found: `x`") + +(component definition + (import "url=<>" (func)) + (import "url=" (func)) + (import "url=,integrity=" (func)) +) + +(assert_invalid + (component (import "url=" (func))) + "expected `<` at ``") +(assert_invalid + (component (import "url=<" (func))) + "failed to find `>`") +(assert_invalid + (component (import "url=<<>" (func))) + "url cannot contain `<`") + +(assert_invalid + (component + (import "relative-url=<>" (func)) + (import "relative-url=" (func)) + (import "relative-url=,integrity=" (func)) + ) + "not a valid extern name") + +(assert_invalid + (component (import "relative-url=" (func))) + "not a valid extern name") +(assert_invalid + (component (import "relative-url=<" (func))) + "not a valid extern name") +(assert_invalid + (component (import "relative-url=<<>" (func))) + "not a valid extern name") + +(component definition + (import "integrity=" (func)) + (import "integrity=" (func)) + (import "integrity=" (func)) + (import "integrity=" (func)) + (import "integrity=< sha512-a sha256-b >" (func)) + (import "integrity=< sha512-a?abcd >" (func)) + (import "integrity=" (func)) + (import "integrity=" (func)) + (import "integrity=" (func)) + (import "integrity=" (func)) +) +(assert_invalid + (component (import "integrity=<>" (func))) + "integrity hash cannot be empty") +(assert_invalid + (component (import "integrity=" (func))) + "expected `-` after hash algorithm") +(assert_invalid + (component (import "integrity=" (func))) + "not valid base64") +(assert_invalid + (component (import "integrity=" (func))) + "not valid base64") +(assert_invalid + (component (import "integrity=" (func))) + "not valid base64") +(assert_invalid + (component (import "integrity=" (func))) + "not valid base64") +(assert_invalid + (component (import "integrity=" (func))) + "not valid base64") +(assert_invalid + (component (import "integrity=" (func))) + "unrecognized hash algorithm") + +;; Prior to WebAssembly/component-model#263 this was a valid component. +;; Specifically the 0x01 prefix byte on the import was valid. Nowadays that's +;; not valid in the spec but it's accepted for backwards compatibility. This +;; tests is here to ensure such compatibility. In the future this test should +;; be changed to `(assert_invalid ...)` +(component definition binary + "\00asm" "\0d\00\01\00" ;; component header + + "\07\05" ;; type section, 5 bytes large + "\01" ;; 1 count + "\40" ;; function + "\00" ;; parameters, 0 count + "\01\00" ;; results, named, 0 count + + "\0a\06" ;; import section, 6 bytes large + "\01" ;; 1 count + "\01" ;; prefix byte of 0x01 (invalid by the spec nowadays) + "\01a" ;; name = "a" + "\01\00" ;; type = func ($type 0) +) diff --git a/src/test/resources/spec-tests/wasm-tools/imports-exports.wast b/src/test/resources/spec-tests/wasm-tools/imports-exports.wast new file mode 100644 index 0000000..e650c8c --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/imports-exports.wast @@ -0,0 +1,26 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; With what's defined so far, we can define a component that imports, links and exports other components: + +(component + (component + (import "c" (instance $c + (export "f" (func (result string))) + )) + (import "d" (component $D + (import "c" (instance $c + (export "f" (func (result string))) + )) + (export "g" (func (result string))) + )) + (instance $d1 (instantiate $D + (with "c" (instance $c)) + )) + (instance $d2 (instantiate $D + (with "c" (instance + (export "f" (func $d1 "g")) + )) + )) + (export "d2" (instance $d2)) + ) +) diff --git a/src/test/resources/spec-tests/wasm-tools/inline-exports.wast b/src/test/resources/spec-tests/wasm-tools/inline-exports.wast new file mode 100644 index 0000000..2c3ff56 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/inline-exports.wast @@ -0,0 +1,9 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (type (export "foo") u8) +) + +(assert_malformed + (component quote "(type (component (type (export \"\") (func))))") + "unexpected token") diff --git a/src/test/resources/spec-tests/wasm-tools/instance-type.wast b/src/test/resources/spec-tests/wasm-tools/instance-type.wast new file mode 100644 index 0000000..2f4b140 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/instance-type.wast @@ -0,0 +1,234 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; instances +(component + (type (instance)) + + (type $foo (func)) + + (type $t (func (result string))) + + (core type (module + (type $local_type (func)) + ;; functions + (export "a" (func)) + (export "b" (func $foo)) + (export "c" (func)) + (export "d" (func $foo)) + (export "e" (func (type $local_type))) + (export "f" (func (param i32))) + (export "g" (func (param i32) (result i32 i64))) + (export "h" (func (type $local_type) (result i32))) + + ;; globals + (export "i" (global i32)) + (export "j" (global $foo i32)) + (export "k" (global (mut i32))) + + ;; tables + (export "l" (table 1 funcref)) + (export "m" (table $foo 1 funcref)) + + ;; memory + (export "n" (memory 1)) + (export "o" (memory $foo 1)) + (export "p" (memory 1 2)) + (export "q" (memory 1 2 shared)) + )) + + (type $outer (instance + (type $local_type (func)) + ;; functions + (export "a" (func)) + (export "a2" (func (type $local_type))) + (export "b" (func)) + (export "c" (func)) + (export "d" (func)) + (export "e" (func (type $t))) + (export "f" (func (param "f" string))) + (export "g" (func (param "g" s32) (result u32))) + (export "h" (func (type $t))) + + ;; components + (type $component_type (component)) + (export "c1" (component)) + (export "c2" (component (import "i1" (func)))) + (export "c3" (component (export "e1" (func)))) + (export "c4" (component (type $component_type))) + (export "c5" (component + (type $nested_func_type (func)) + (alias outer $outer $local_type (type $my_type)) + (import "i1" (func (type $nested_func_type))) + (import "i2" (component)) + (export "e1" (func (type $my_type))) + (export "e2" (component)) + )) + )) +) + +;; expand inline types +(component + (type (instance (export "a" (instance)))) +) + +;; reference outer types +(component + (type (instance + (type $t (instance)) + (export "a" (instance (type $t))) + )) + (type $x (instance)) + (type (instance (export "a" (instance (type $x))))) +) + +;; recursive +(component + (type (instance (export "a" (core module + (type $functype (func)) + + (export "a" (func)) + (export "b" (func (type 0))) + (export "c" (func (param i32))) + (export "d" (func (type $functype))) + + ;; globals + (export "e" (global i32)) + (export "f" (global (mut i32))) + + ;; tables + (export "g" (table 1 funcref)) + + ;; memory + (export "h" (memory 1)) + (export "i" (memory 1 2)) + (export "j" (memory 1 2 shared)) + )))) +) + +;; modules +(component + (core type (module)) + + (core type $foo (module)) + + (type $empty (func)) + (type $i (instance)) + + (core type (module + (type $empty (func)) + (import "" "a" (func)) + (import "" "b" (func (type $empty))) + (import "" "c" (func (param i32))) + (import "" "d" (func (param i32) (result i32))) + + (import "" "e" (global i32)) + (import "" "f" (memory 1)) + (import "" "g" (table 1 funcref)) + + (export "a" (func)) + (export "b" (global i32)) + (export "c" (memory 1)) + (export "d" (table 1 funcref)) + + (export "e" (func (type $empty))) + (export "f" (func (param i32))) + )) + + (type (component + (import "a" (func)) + (import "b" (func (type $empty))) + (import "c" (func (param "c" s32))) + (import "d" (func (param "d" s32) (result s32))) + + (import "h" (instance)) + (import "i" (instance (type $i))) + (import "j" (instance + (export "a" (func)) + (export "b" (func (type $empty))) + (export "c" (func (param "c" s32))) + )) + + (import "k" (core module)) + (import "l" (core module + (type $empty (func)) + (import "" "a" (func (type $empty))) + (import "" "b" (func (param i32))) + (export "a" (func (type $empty))) + (export "b" (func (param i32))) + )) + + (export "m" (func)) + (export "n" (func (type $empty))) + (export "o" (func (param "f" s32))) + + (export "p" (instance + (export "a" (func)) + (export "b" (func (type $empty))) + (export "c" (func (param "c" s32))) + )) + + (export "q" (core module + (type $empty (func)) + (import "" "a" (func (type $empty))) + (import "" "b" (func (param i32))) + (export "a" (func (type $empty))) + (export "b" (func (param i32))) + )) + )) +) + +(assert_invalid + (component + (type (instance + (export "a" (func)) + (export "a" (func))))) + "export name `a` conflicts with previous name `a`") + +(assert_invalid + (component + (type $t (func)) + (type (instance + (export "a" (instance (type $t))) + ))) + "type index 0 is not an instance type") + +(assert_invalid + (component + (core type $t (func)) + (type (instance + (export "a" (core module (type $t))) + ))) + "core type index 0 is not a module type") + +(assert_malformed + (component quote + "(type $t (func))" + "(type (instance (export \"a\" (core module (type $t)))))" + ) + "unknown core type") + +(assert_invalid + (component + (type $t (record (field "a" string))) + (type (instance + (export "a" (func (type $t))) + ))) + "type index 0 is not a function type") + +(assert_invalid + (component + (type $t (instance)) + (type (instance + (export "a" (func (type $t))) + ))) + "type index 0 is not a function type") + +(assert_invalid + (component + (type $t (instance)) + (type (instance + (export "a" (instance + (export "a" (func (type $t))) + )) + ))) + "type index 0 is not a function type") diff --git a/src/test/resources/spec-tests/wasm-tools/instantiate.wast b/src/test/resources/spec-tests/wasm-tools/instantiate.wast new file mode 100644 index 0000000..cb99239 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/instantiate.wast @@ -0,0 +1,976 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (import "a" (core module $m)) + (core instance $a (instantiate $m)) +) + +(component + (component + (import "a" (func $i)) + (import "b" (component $c (import "a" (func)))) + (instance (instantiate $c (with "a" (func $i)))) + ) +) + +(component + (component + (import "a" (component $i)) + (import "b" (component $c (import "a" (component)))) + (instance (instantiate $c (with "a" (component $i)))) + ) +) + +(component + (component + (import "a" (core module $i)) + (import "b" (component $c (import "a" (core module)))) + (instance (instantiate $c (with "a" (core module $i)))) + ) +) + +(component + (component + (import "a" (instance $i)) + (import "b" (component $c (import "a" (instance)))) + (instance (instantiate $c (with "a" (instance $i)))) + ) +) + +(component definition + (import "a" (core module $m + (import "" "a" (func)) + (import "" "b" (global i32)) + (import "" "c" (table 1 funcref)) + (import "" "d" (memory 1)) + )) + (import "b" (core module $m2 + (export "a" (func)) + (export "b" (global i32)) + (export "c" (table 1 funcref)) + (export "d" (memory 1)) + )) + (core instance $x (instantiate $m2)) + (core instance (instantiate $m (with "" (instance $x)))) +) + +(component definition + (import "a" (core module $m + (import "" "d" (func)) + (import "" "c" (global i32)) + (import "" "b" (table 1 funcref)) + (import "" "a" (memory 1)) + )) + (import "b" (core module $m2 + (export "a" (func)) + (export "b" (global i32)) + (export "c" (table 1 funcref)) + (export "d" (memory 1)) + )) + (core instance $x (instantiate $m2)) + + (core instance (instantiate $m (with "" (instance + (export "d" (func $x "a")) + (export "c" (global $x "b")) + (export "b" (table $x "c")) + (export "a" (memory $x "d")) + )))) +) + +(component + (component + (import "a" (component $m + (import "a" (instance + (export "a" (core module)) + )) + )) + (import "b" (component $m2 + (export "b" (core module)) + )) + (instance $x (instantiate $m2)) + + (instance (instantiate $m (with "a" (instance + (export "a" (core module $x "b")) + )))) + ) +) + +(component + (component + (import "a" (component $c + (import "a" (core module)) + (import "b" (func)) + (import "c" (component)) + (import "d" (instance)) + )) + (core module $m (import "b")) + (func $f (import "c")) + (component $c2 (import "d")) + (instance $i (import "e")) + + (instance + (instantiate $c + (with "a" (core module $m)) + (with "b" (func $f)) + (with "c" (component $c2)) + (with "d" (instance $i)) + ) + ) + + (core instance $c (instantiate $m)) + (core instance (instantiate $m)) + + ;; inline exports/imports + (type $empty (instance)) + (instance $d (import "g") (type $empty)) + (instance (import "h")) + (instance (import "i") + (export "x" (func))) + (instance (export "j") (export "k") (import "x")) + ) +) + +(assert_invalid + (component + (core instance (instantiate 0)) + ) + "unknown module") +(assert_invalid + (component + (instance (instantiate 0)) + ) + "unknown component") +(assert_invalid + (component + (import "a" (core module)) + (core instance (instantiate 1)) + ) + "unknown module") + +(component + (component + (import "a" (func $f)) + (import "b" (component $c)) + (instance (instantiate $c (with "a" (func $f)))) + ) +) +(assert_invalid + (component + (import "a" (core module $m (import "" "" (func)))) + (core instance (instantiate $m)) + ) + "missing module instantiation argument") +(assert_invalid + (component + (import "a" (component $m (import "a" (func)))) + (instance (instantiate $m)) + ) + "missing import named `a`") + +(assert_invalid + (component + (import "a" (component $m + (import "a" (func)) + )) + (import "b" (component $c)) + (instance $i (instantiate $m (with "a" (component $c)))) + ) + "expected func, found component") + +(assert_invalid + (component + (import "a" (component $m + (import "a" (func)) + )) + (import "b" (func $f (result string))) + (instance $i (instantiate $m (with "a" (func $f)))) + ) + "expected a result, found none") + +(assert_invalid + (component + (import "a" (component $m + (import "a" (func)) + )) + (import "b" (func (param "i" string))) + (instance $i (instantiate $m (with "a" (func 0)))) + ) + "expected 0 parameters, found 1") + +(assert_invalid + (component + (import "a" (component $m + (import "a" (core module + (import "" "" (func)) + )) + )) + (import "b" (core module $i + (import "" "" (global i32)) + )) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) + "type mismatch in import `::`") + +(assert_invalid + (component + (import "a" (component $m + (import "a" (core module)) + )) + (import "b" (core module $i + (import "" "foobar" (global i32)) + )) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) + "missing expected import `::foobar`") +(assert_invalid + (component + (import "a" (component $m + (import "a" (core module (export "x" (func)))) + )) + (import "b" (core module $i)) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) + "missing expected export `x`") + +;; it's ok to give a module with fewer imports +(component + (component + (import "a" (component $m + (import "a" (core module + (import "" "" (global i32)) + (import "" "f" (func)) + )) + )) + (import "b" (core module $i + (import "" "" (global i32)) + )) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) +) + +;; export subsets +(component + (component + (import "a" (component $m + (import "a" (core module + (export "" (func)) + )) + )) + (import "b" (core module $i + (export "" (func)) + (export "a" (func)) + )) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) +) +(component + (component + (import "a" (component $m + (import "a" (instance + (export "a" (func)) + )) + )) + (import "b" (instance $i + (export "a" (func)) + (export "b" (func)) + )) + (instance (instantiate $m (with "a" (instance $i)))) + ) +) + + +;; ============================================================================ +;; core wasm type checking + +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (func)))) + (import "m2" (core module $m2 (export "" (func (param i32))))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "expected: (func)") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (func)))) + (import "m2" (core module $m2 (export "" (func (result i32))))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "expected: (func)") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (global i32)))) + (import "m2" (core module $m2 (export "" (global i64)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "expected global type i32, found i64") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (table 1 funcref)))) + (import "m2" (core module $m2 (export "" (table 2 externref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "expected table element type funcref, found externref") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (table 1 2 funcref)))) + (import "m2" (core module $m2 (export "" (table 2 funcref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "mismatch in table limits") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (table 2 2 funcref)))) + (import "m2" (core module $m2 (export "" (table 1 funcref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "mismatch in table limits") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (table 2 2 funcref)))) + (import "m2" (core module $m2 (export "" (table 2 3 funcref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "mismatch in table limits") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (memory 1 2 shared)))) + (import "m2" (core module $m2 (export "" (memory 1)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "mismatch in the shared flag for memories") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (memory 1)))) + (import "m2" (core module $m2 (export "" (memory 0)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "mismatch in memory limits") +(assert_invalid + (component + (import "m1" (core module $m1 (export "g" (func)))) + (component $c + (import "m" (core module (export "g" (global i32)))) + ) + (instance (instantiate $c (with "m" (core module $m1)))) + ) + "type mismatch in export `g`") + +(assert_invalid + (component + (core instance (instantiate 0)) + ) + "unknown module") + +(component + (component $m + (core module $sub (export "module") + (func $f (export "") (result i32) + i32.const 5)) + ) + (instance $a (instantiate $m)) + (alias export $a "module" (core module $sub)) + (core instance $b (instantiate $sub)) + + (core module $final + (import "" "" (func $b (result i32))) + (func (export "get") (result i32) + call $b)) + + (core instance (instantiate $final (with "" (instance $b)))) +) + +(assert_invalid + (component (instance $i (export "" (func 0)))) + "function index out of bounds") + +(assert_invalid + (component (instance (export "" (instance 0)))) + "index out of bounds") + +(assert_invalid + (component (instance $i (export "" (component 0)))) + "index out of bounds") + +(assert_invalid + (component (instance (export "" (instance 0)))) + "index out of bounds") + +(assert_invalid + (component (instance $i (export "" (core module 0)))) + "index out of bounds") + +(assert_invalid + (component (core instance (export "" (func 0)))) + "index out of bounds") + +(assert_invalid + (component (core instance (export "" (table 0)))) + "index out of bounds") + +(assert_invalid + (component (core instance (export "" (global 0)))) + "index out of bounds") + +(assert_invalid + (component (core instance (export "" (memory 0)))) + "index out of bounds") + +(assert_invalid + (component + (core module $m) + (core instance $i (instantiate $m)) + (core instance (instantiate $m + (with "" (instance $i)) + (with "" (instance $i)) + )) + ) + "duplicate module instantiation argument named ``" +) + +(assert_invalid + (component + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (core instance (instantiate $m + (with "" (instance $i)) + (with "" (instance $i)) + )) + ) + "duplicate module instantiation argument named ``") + +(assert_invalid + (component + (core module $m1 (func (export ""))) + (core module $m2 (import "" "" (global i32))) + (core instance $i (instantiate $m1)) + (core instance (instantiate $m2 + (with "" (instance $i)) + )) + ) + "expected global, found func") + +(assert_invalid + (component + (component $m) + (instance $i (instantiate $m)) + (instance (instantiate $m + (with "a" (instance $i)) + (with "a" (instance $i)) + )) + ) + "instantiation argument `a` conflicts with previous argument `a`") + +(assert_invalid + (component + (component $c (import "a" (func))) + (instance (instantiate $c + (with "a" (component $c)) + )) + ) + "expected func, found component") + +(assert_invalid + (component + (component $c) + (instance (instantiate $c + (with "" (core module 0)) + )) + ) + "index out of bounds") + +(assert_invalid + (component + (component $c) + (instance (instantiate $c + (with "" (instance 0)) + )) + ) + "index out of bounds") + +(assert_invalid + (component + (component $c) + (instance (instantiate $c + (with "" (func 0)) + )) + ) + "index out of bounds") + +(assert_invalid + (component + (component $c) + (instance (instantiate $c + (with "" (component 100)) + )) + ) + "index out of bounds") + +(assert_invalid + (component + (component $c) + (instance + (export "a" (component $c)) + (export "a" (component $c)) + ) + ) + "export name `a` conflicts with previous name `a`") + +(component + (component + (import "a" (instance $i)) + (import "b" (func $f)) + (import "c" (component $c)) + (import "d" (core module $m)) + (instance + (export "a" (instance $i)) + (export "b" (func $f)) + (export "c" (component $c)) + (export "d" (core module $m)) + ) + ) +) + +(component + (core module $m + (func (export "1")) + (memory (export "2") 1) + (table (export "3") 1 funcref) + (global (export "4") i32 i32.const 0) + ) + (core instance $i (instantiate $m)) + (core instance + (export "a" (func $i "1")) + (export "b" (memory $i "2")) + (export "c" (table $i "3")) + (export "d" (global $i "4")) + ) +) + +(assert_invalid + (component + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (core instance + (export "" (func $i "")) + (export "" (func $i "")) + ) + ) + "export name `` already defined") + +(assert_invalid + (component + (component $c) + (instance $i (instantiate $c)) + (export "a" (instance $i "a")) + ) + "no export named `a`") + +(assert_invalid + (component + (export "a" (instance 100 "a")) + ) + "index out of bounds") + +(assert_invalid + (component + (import "a" (core module $libc + (export "memory" (memory 1)) + (export "table" (table 0 funcref)) + (export "func" (func)) + (export "global" (global i32)) + (export "global mut" (global (mut i64))) + )) + (core instance $libc (instantiate $libc)) + (alias core export $libc "memory" (core memory $mem)) + (alias core export $libc "table" (core table $tbl)) + (alias core export $libc "func" (core func $func)) + (alias core export $libc "global" (core global $global)) + (alias core export $libc "global mut" (core global $global_mut)) + + (import "x" (core module $needs_libc + (import "" "memory" (memory 1)) + (import "" "table" (table 0 funcref)) + (import "" "func" (func)) + (import "" "global" (global i32)) + (import "" "global mut" (global (mut i64))) + )) + + (core instance + (instantiate $needs_libc + (with "" (instance (export "memory" (memory $mem)))) + ) + ) + ) + "module instantiation argument `` does not export an item named `table`") + +;; Ensure a type can be an instantiation argument +(component + (type (tuple u32 u32)) + (import "a" (type (eq 0))) + (component + (type (tuple u32 u32)) + (import "a" (type (eq 0))) + ) + (instance (instantiate 0 + (with "a" (type 1)) + ) + ) +) + +(assert_invalid + (component + (type $t (tuple string string)) + (import "a" (type $a (eq $t))) + (component $c + (type $t (tuple u32 u32)) + (import "a" (type (eq $t))) + ) + (instance (instantiate $c + (with "a" (type $a)) + ) + ) + ) + "expected primitive `u32` found primitive `string`") + + +;; subtyping for module imports reverses order of imports/exports for the +;; subtyping check +;; +;; Here `C` imports a module, and the module itself imports a table of min size +;; 1. A module import which imports a min-size table of 0, however, is valid to +;; supply for this since it'll already be given at least 1 anyway. +;; +;; Similarly for exports `C` imports a module that exports a table of at least +;; size 1. If it's given a module that exports a larger table that's ok too. +(component + (core module $a + (import "" "" (table 0 funcref)) + (table (export "x") 2 funcref) + ) + (component $C + (import "a" (core module + (import "" "" (table 1 funcref)) + (export "x" (table 1 funcref)) + )) + ) + (instance (instantiate $C (with "a" (core module $a)))) +) + +;; same as above but for memories +(component + (core module $a1 (import "" "" (memory 0))) + (core module $a2 (memory (export "x") 2)) + (component $C + (import "a1" (core module (import "" "" (memory 1)))) + (import "a2" (core module (export "x" (memory 1)))) + ) + (instance (instantiate $C + (with "a1" (core module $a1)) + (with "a2" (core module $a2)) + )) +) + +(assert_invalid + (component + (import "x" (func $x (param "x" u32))) + (import "y" (component $c + (import "x" (func (param "y" u32))) + )) + + (instance (instantiate $c (with "x" (func $x)))) + ) + "expected parameter named `y`, found `x`") +(assert_invalid + (component + (import "x" (func $x (param "x" u32))) + (import "y" (component $c + (import "x" (func (param "x" s32))) + )) + + (instance (instantiate $c (with "x" (func $x)))) + ) + "type mismatch in function parameter `x`") +(assert_invalid + (component + (import "x" (func $x (result u32))) + (import "y" (component $c + (import "x" (func (result s32))) + )) + + (instance (instantiate $c (with "x" (func $x)))) + ) + "type mismatch with result type") + +(assert_invalid + (component + (import "x" (instance $x (export "a" (func)))) + (import "y" (component $c + (import "x" (instance $x (export "a" (component)))) + )) + + (instance (instantiate $c (with "x" (instance $x)))) + ) + "type mismatch in instance export `a`") + +(assert_invalid + (component + (import "y" (component $c + (type $t u32) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "f" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected primitive, found record") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "f" u32))) + (import "x" (type (eq $t))) + )) + + (type $x u32) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected record, found u32") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $f (tuple u8)) + (type $x (record (field "x" $f))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected u32, found tuple") + +(assert_invalid + (component + (import "y" (component $c + (type $f (option s32)) + (type $t (record (field "x" $f))) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "x" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in record field `x`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "y" u32) (field "z" u64))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected 1 fields, found 2") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "a" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "b" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected field name `a`, found `b`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x" u32) (case "y" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected 1 cases, found 2") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "y" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected case named `x`, found `y`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x"))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected case `x` to have a type, found none") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x"))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected case `x` to have no type") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x" s32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in variant case `x`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (tuple u8)) + (import "x" (type (eq $t))) + )) + + (type $x (tuple u32 u32)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected 1 types, found 2") + +(assert_invalid + (component + (import "y" (component $c + (type $t (tuple u8)) + (import "x" (type (eq $t))) + )) + + (type $x (tuple u16)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in tuple field 0") + +(assert_invalid + (component + (import "y" (component $c + (type $t (flags "a")) + (import "x" (type (eq $t))) + )) + + (type $x (flags "x")) + (instance (instantiate $c (with "x" (type $x)))) + ) + "mismatch in flags elements") + +(assert_invalid + (component + (import "y" (component $c + (type $t (enum "a")) + (import "x" (type (eq $t))) + )) + + (type $x (enum "x")) + (instance (instantiate $c (with "x" (type $x)))) + ) + "mismatch in enum elements") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result s32)) + (import "x" (type (eq $t))) + )) + + (type $x (result u32)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in ok variant") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result (error s32))) + (import "x" (type (eq $t))) + )) + + (type $x (result (error u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in err variant") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result)) + (import "x" (type (eq $t))) + )) + + (type $x (result u32)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected ok type to not be present") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result u32)) + (import "x" (type (eq $t))) + )) + + (type $x (result)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected ok type, but found none") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result)) + (import "x" (type (eq $t))) + )) + + (type $x (result (error u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected err type to not be present") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result (error u32))) + (import "x" (type (eq $t))) + )) + + (type $x (result)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected err type, but found none") diff --git a/src/test/resources/spec-tests/wasm-tools/invalid.wast b/src/test/resources/spec-tests/wasm-tools/invalid.wast new file mode 100644 index 0000000..267b31f --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/invalid.wast @@ -0,0 +1,34 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (core type (module + (import "" "" (func (type 1))) + )) + (type (func)) + ) + "type index out of bounds") + +(assert_malformed + (component quote + "(export \"\" (func $foo))" + ) + "unknown func") + +(assert_malformed + (component quote + "(alias outer 100 $foo (type $foo))" + ) + "outer count of `100` is too large") + +(assert_malformed + (component quote + "(alias outer $nonexistent $foo (type $foo))" + ) + "outer component `nonexistent` not found") + +(assert_malformed + (component quote + "(import \"x\" (func $x))" + "(component (export \"x\" (func $x)))") + "outer item `x` is not a module, type, or component") diff --git a/src/test/resources/spec-tests/wasm-tools/link.wast b/src/test/resources/spec-tests/wasm-tools/link.wast new file mode 100644 index 0000000..7202365 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/link.wast @@ -0,0 +1,14 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; Based on this, we can link two modules $A and $B together with the following component: + +(component + (core module $A + (func (export "one") (result i32) (i32.const 1)) + ) + (core module $B + (func (import "a" "one") (result i32)) + ) + (core instance $a (instantiate $A)) + (core instance $b (instantiate $B (with "a" (instance $a)))) +) diff --git a/src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast b/src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast new file mode 100644 index 0000000..32e1a27 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast @@ -0,0 +1,179 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (core module $m + (memory (export "m") 1) + (table (export "t") 1 funcref) + (global (export "g") i32 i32.const 0) + (func (export "f")) + ) + (core instance $i (instantiate $m)) + + ;; 160 memories (4 per row 40 rows) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + + ;; 160 tables (4 per row 40 rows) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + + ;; 160 globals (4 per row 40 rows) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + + ;; 160 functions (4 per row 40 rows) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) +) diff --git a/src/test/resources/spec-tests/wasm-tools/lower.wast b/src/test/resources/spec-tests/wasm-tools/lower.wast new file mode 100644 index 0000000..5b9e13b --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/lower.wast @@ -0,0 +1,17 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (import "f" (func $f (param "x" (list u8)))) + (core func $f (canon lower (func $f) + )) + ) + "canonical option `memory` is required") + +(assert_invalid + (component + (import "f" (func $f (result (list u8)))) + (core func $f (canon lower (func $f) + )) + ) + "canonical option `memory` is required") diff --git a/src/test/resources/spec-tests/wasm-tools/memory64.wast b/src/test/resources/spec-tests/wasm-tools/memory64.wast new file mode 100644 index 0000000..a72eb3b --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/memory64.wast @@ -0,0 +1,55 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (core module $A + (import "" "" (memory 1))) + (core module $B + (memory (export "") i64 1)) + (core instance $b (instantiate $B)) + (core instance $a (instantiate $A (with "" (instance $b)))) + ) + "mismatch in index type used for memories") + +(assert_invalid + (component + (core module $A + (import "" "" (memory i64 1))) + (core module $B + (memory (export "") 1)) + (core instance $b (instantiate $B)) + (core instance $a (instantiate $A (with "" (instance $b)))) + ) + "mismatch in index type used for memories") + +(component + (core module $A + (memory (export "m") i64 1)) + (core instance $A (instantiate $A)) + (alias core export $A "m" (core memory $m)) + + (core module $B (import "" "" (memory i64 1))) + (core instance (instantiate $B (with "" (instance (export "" (memory $m)))))) +) + +(component + (core module $A + (table (export "m") i64 1 funcref)) + (core instance $A (instantiate $A)) + (alias core export $A "m" (core table $m)) + + (core module $B (import "" "" (table i64 1 funcref))) + (core instance (instantiate $B (with "" (instance (export "" (table $m)))))) +) + +(component + (import "x" (func $x (param "x" string))) + (core module $A + (memory (export "m") i64 1) + (func (export "realloc") (param i64 i64 i64 i64) (result i64) unreachable) + ) + (core instance $A (instantiate $A)) + (alias core export $A "m" (core memory $m)) + (core func $realloc (alias core export $A "realloc")) + (core func (canon lower (func $x) (memory $m) (realloc (func $realloc)))) +) diff --git a/src/test/resources/spec-tests/wasm-tools/module-link.wast b/src/test/resources/spec-tests/wasm-tools/module-link.wast new file mode 100644 index 0000000..119da23 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/module-link.wast @@ -0,0 +1,98 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (type $Wasi (instance)) + (component $B) + (component $B_wrap + (import "wasi" (instance $wasi (type $Wasi))) + (instance $b (instantiate $B)) + ) +) + +(component + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + + (component $A + (type $Wasi (instance)) + (import "wasi" (instance (type $Wasi))) + + (core module $m + (func (export "a")) + ) + + (core instance $i (instantiate $m)) + (func (export "a") + (canon lift (core func $i "a")) + ) + ) + + (component $B + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (import "a1-x" (component $A + (import "wasi" (instance (type $Wasi))) + (export "a" (func)) + )) + (instance $a (instantiate $A (with "wasi" (instance $wasi)))) + + (core func $lower (canon lower (func $a "a"))) + (core module $b + (import "a" "a" (func)) + (func (export "b")) + ) + (core instance $b (instantiate $b + (with "a" (instance (export "a" (func $lower)))) + )) + (func (export "b") + (canon lift (core func $b "b")) + ) + ) + (component $B_wrap + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (instance $b (instantiate $B + (with "wasi" (instance $wasi)) + (with "a1-x" (component $A))) + ) + (export "b" (func $b "b")) + ) + + (component $C + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (import "b1-x" (component $B + (import "wasi" (instance $wasi (type $Wasi))) + (export "b" (func)) + )) + (instance $b (instantiate $B (with "wasi" (instance $wasi)))) + (export "c" (func $b "b")) + ) + (component $C_wrap + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (instance $c (instantiate $C + (with "wasi" (instance $wasi)) + (with "b1-x" (component $B_wrap)) + )) + (export "c" (func $c "c")) + ) + + (component $D + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (import "c1-x" (component $C + (import "wasi" (instance $wasi (type $Wasi))) + (export "c" (func)) + )) + (instance $c (instantiate $C (with "wasi" (instance $wasi)))) + (export "d" (func $c "c")) + ) + + (instance $d (instantiate $D + (with "wasi" (instance $wasi)) + (with "c1-x" (component $C_wrap)) + )) + + (export "d" (func $d "d")) +) diff --git a/src/test/resources/spec-tests/wasm-tools/more-flags.wast b/src/test/resources/spec-tests/wasm-tools/more-flags.wast new file mode 100644 index 0000000..ebcced0 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/more-flags.wast @@ -0,0 +1,41 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (type (flags + "f1" + "f2" + "f3" + "f4" + "f5" + "f6" + "f7" + "f8" + "f9" + "f10" + "f11" + "f12" + "f13" + "f14" + "f15" + "f16" + "f17" + "f18" + "f19" + "f20" + "f21" + "f22" + "f23" + "f24" + "f25" + "f26" + "f27" + "f28" + "f29" + "f30" + "f31" + "f32" + "f33" + )) + ) + "cannot have more than 32 flags") diff --git a/src/test/resources/spec-tests/wasm-tools/naming.wast b/src/test/resources/spec-tests/wasm-tools/naming.wast new file mode 100644 index 0000000..5decf55 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/naming.wast @@ -0,0 +1,127 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (func (import "a")) + (component) + (instance (instantiate 0 (with "NotKebab-Case" (func 0)))) +) + +(assert_invalid + (component + (import "f" (func)) + (instance (export "1" (func 0))) + ) + "`1` is not in kebab case" +) + +(assert_invalid + (component + (instance) + (alias export 0 "Xml" (func)) + ) + "instance 0 has no export named `Xml`" +) + +(component definition + (type (flags "a-1-c")) +) + +(assert_invalid + (component + (type (enum "NevEr")) + ) + "enum tag name `NevEr` is not in kebab case" +) + +(assert_invalid + (component + (type (record (field "GoNnA" string))) + ) + "record field name `GoNnA` is not in kebab case" +) + +(assert_invalid + (component + (type (variant (case "GIVe" string))) + ) + "variant case name `GIVe` is not in kebab case" +) + + +(assert_invalid + (component + (type (func (param "yOu" string))) + ) + "function parameter name `yOu` is not in kebab case" +) + +(assert_invalid + (component + (type (component (export "NevEr" (func)))) + ) + "`NevEr` is not in kebab case" +) + +(assert_invalid + (component + (type (component (import "GonnA" (func)))) + ) + "`GonnA` is not in kebab case" +) + +(assert_invalid + (component + (type (instance (export "lET" (func)))) + ) + "`lET` is not in kebab case" +) + +(assert_invalid + (component + (instance (export "YoU")) + ) + "`YoU` is not in kebab case" +) + +(assert_invalid + (component + (instance (import "DOWn")) + ) + "`DOWn` is not in kebab case" +) + +(assert_invalid + (component + (instance (import "A:b/c")) + ) + "character `A` is not lowercase in package name/namespace" +) +(assert_invalid + (component + (instance (import "a:B/c")) + ) + "character `B` is not lowercase in package name/namespace" +) +(component + (instance (import "a:b/c")) + (instance (import "a1:b1/c")) +) + +(component definition + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (own $a)))) +) + +(assert_invalid + (component + (import "a" (type $a (sub resource))) + (import "[method]a.a" (func (param "self" (borrow $a)))) + ) + "import name `[method]a.a` conflicts with previous name `a`") + +(assert_invalid + (component + (import "a" (type $a (sub resource))) + (import "[static]a.a" (func)) + ) + "import name `[static]a.a` conflicts with previous name `a`") diff --git a/src/test/resources/spec-tests/wasm-tools/nested-modules.wast b/src/test/resources/spec-tests/wasm-tools/nested-modules.wast new file mode 100644 index 0000000..5e629ea --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/nested-modules.wast @@ -0,0 +1,50 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (import "i1" (core module)) + + (core module) + (core module) + + (core module (export "x")) + + (component + (core module) + ) + + (component + (core module $m) + (import "a" (func (param "p" string))) + (export "b" (core module $m)) + ) +) + +;; does the `import` use the type annotation specified later? +(component definition + (import "a" (core module)) + (core type (module)) +) + +;; be sure to typecheck nested modules +(assert_invalid + (component + (core module + (func + i32.add) + ) + ) + "type mismatch") + +;; interleave module definitions with imports/aliases and ensure that we +;; typecheck the module code section correctly +(component definition + (core module + (func (export "")) + ) + (import "a" (core module)) + (core module + (func (export "") (result i32) i32.const 5) + ) + (import "b" (instance (export "a" (core module)))) + (alias export 0 "a" (core module)) +) diff --git a/src/test/resources/spec-tests/wasm-tools/resources.wast b/src/test/resources/spec-tests/wasm-tools/resources.wast new file mode 100644 index 0000000..14509c5 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/resources.wast @@ -0,0 +1,1195 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (type $x (resource (rep i32))) +) + +(component + (type $x (resource (rep i32))) + + (core func (canon resource.new $x)) + (core func (canon resource.rep $x)) + (core func (canon resource.drop $x)) +) + +(component definition + (import "x" (type $x (sub resource))) + + (core func (canon resource.drop $x)) +) + +(component + (core module $m + (func (export "dtor") (param i32)) + ) + (core instance $m (instantiate $m)) + (type $x (resource (rep i32) (dtor (func $m "dtor")))) + (core func (canon resource.new $x)) +) + +(component + (type $x (resource (rep i32))) + (core func $f1 (canon resource.new $x)) + (core func $f2 (canon resource.rep $x)) + (core func $f3 (canon resource.drop $x)) + + (core module $m + (import "" "f1" (func (param i32) (result i32))) + (import "" "f2" (func (param i32) (result i32))) + (import "" "f3" (func (param i32))) + ) + + (core instance (instantiate $m + (with "" (instance + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + )) + )) +) + +(assert_invalid + (component + (type $x (resource (rep i64))) + ) + "resources can only be represented by `i32`") + +(assert_invalid + (component + (type $x (own 100)) + ) + "type index out of bounds") + +(assert_invalid + (component + (type $x (borrow 100)) + ) + "type index out of bounds") + +(assert_invalid + (component + (type $t u8) + (type $x (borrow $t)) + ) + "not a resource type") + +(assert_invalid + (component + (type $t u8) + (type $x (own $t)) + ) + "not a resource type") + +(assert_invalid + (component + (import "x" (type $x (sub resource))) + (core func (canon resource.new $x)) + ) + "not a local resource") + +(assert_invalid + (component + (import "x" (type $x (sub resource))) + (core func (canon resource.rep $x)) + ) + "not a local resource") + +(assert_invalid + (component + (type $t (tuple u32)) + (core func (canon resource.drop $t)) + ) + "not a resource type") + +(assert_invalid + (component + (core func (canon resource.drop 100)) + ) + "type index out of bounds") + +(assert_invalid + (component + (type (component)) + (core func (canon resource.drop 0)) + ) + "not a resource type") + +(assert_invalid + (component + (type (component)) + (core func (canon resource.new 0)) + ) + "not a resource type") + +(assert_invalid + (component + (core module $m + (func (export "dtor")) + ) + (core instance $m (instantiate $m)) + (type $x (resource (rep i32) (dtor (func $m "dtor")))) + (core func (canon resource.new $x)) + ) + "wrong signature for a destructor") + +(assert_invalid + (component + (type (resource (rep i32) (dtor (func 100)))) + ) + "function index out of bounds") + +(assert_invalid + (component + (import "x" (type $x (sub resource))) + (import "y" (type $y (sub resource))) + (import "z" (func $z (param "x" (own $x)) (param "y" (own $y)))) + + (component $c + (import "x" (type $x (sub resource))) + (import "z" (func (param "x" (own $x)) (param "y" (own $x)))) + ) + + (instance (instantiate $c (with "x" (type $x)) (with "z" (func $z)))) + ) + "resource types are not the same") + +(component + (type (component + (import "x" (type $x (sub resource))) + (export "y" (type (eq $x))) + (export "z" (type (sub resource))) + )) +) + +(assert_invalid + (component + (type (component + (type $x (resource (rep i32))) + )) + ) + "resources can only be defined within a concrete component") + +(assert_invalid + (component + (type (instance + (type $x (resource (rep i32))) + )) + ) + "resources can only be defined within a concrete component") + +(component + (type (component + (import "x" (instance $i + (export "t" (type $t (sub resource))) + (export "f" (func (result (own $t)))) + )) + (alias export $i "t" (type $t)) + (export "f" (func (result (own $t)))) + )) +) + +(component definition + (import "fancy-fs" (instance $fancy-fs + (export "fs" (instance $fs + (export "file" (type (sub resource))) + )) + (alias export $fs "file" (type $file)) + (export "fancy-op" (func (param "f" (borrow $file)))) + )) +) + +(component $C + (type $T (list (tuple string bool))) + (type $U (option $T)) + (type $G (func (param "x" (list $T)) (result $U))) + (type $D (component + (alias outer $C $T (type $C_T)) + (type $L (list $C_T)) + (import "f" (func (param "x" $L) (result (list u8)))) + (import "g" (func (type $G))) + (export "g2" (func (type $G))) + (export "h" (func (result $U))) + (import "T" (type $T (sub resource))) + (import "i" (func (param "x" (list (own $T))))) + (export "T2" (type $T' (eq $T))) + (export "U" (type $U' (sub resource))) + (export "j" (func (param "x" (borrow $T')) (result (own $U')))) + )) +) + +(component definition + (import "T1" (type $T1 (sub resource))) + (import "T2" (type $T2 (sub resource))) +) + +(component definition $C + (import "T1" (type $T1 (sub resource))) + (import "T2" (type $T2 (sub resource))) + (import "T3" (type $T3 (eq $T2))) + (type $ListT1 (list (own $T1))) + (type $ListT2 (list (own $T2))) + (type $ListT3 (list (own $T3))) +) + +(component definition + (import "T" (type $T (sub resource))) + (import "U" (type $U (sub resource))) + (type $Own1 (own $T)) + (type $Own2 (own $T)) + (type $Own3 (own $U)) + (type $ListOwn1 (list $Own1)) + (type $ListOwn2 (list $Own2)) + (type $ListOwn3 (list $Own3)) + (type $Borrow1 (borrow $T)) + (type $Borrow2 (borrow $T)) + (type $Borrow3 (borrow $U)) + (type $ListBorrow1 (list $Borrow1)) + (type $ListBorrow2 (list $Borrow2)) + (type $ListBorrow3 (list $Borrow3)) +) + +(component + (component + (import "C" (component $C + (export "T1" (type (sub resource))) + (export "T2" (type $T2 (sub resource))) + (export "T3" (type (eq $T2))) + )) + (instance $c (instantiate $C)) + (alias export $c "T1" (type $T1)) + (alias export $c "T2" (type $T2)) + (alias export $c "T3" (type $T3)) + ) +) + +(component + (component $C + (type $r1 (export "r1") (resource (rep i32))) + (type $r2 (export "r2") (resource (rep i32))) + ) + (instance $c1 (instantiate $C)) + (instance $c2 (instantiate $C)) + (alias export $c1 "r1" (type $c1r1)) + (alias export $c1 "r2" (type $c1r2)) + (alias export $c2 "r1" (type $c2r1)) + (alias export $c2 "r2" (type $c2r2)) +) + +(component + (type $r (resource (rep i32))) + (export "r1" (type $r)) + (export "r2" (type $r)) +) + +(component + (type (component + (export "r1" (type (sub resource))) + (export "r2" (type (sub resource))) + )) +) + +(component + (type $r (resource (rep i32))) + (export $r1 "r1" (type $r)) + (export "r2" (type $r1)) +) + +(component + (type (component + (export "r1" (type $r1 (sub resource))) + (export "r2" (type (eq $r1))) + )) +) + +(component + (component $P + (import "C1" (component $C1 + (import "T" (type $T (sub resource))) + (export "foo" (func (param "t" (own $T)))) + )) + (import "C2" (component $C2 + (import "T" (type $T (sub resource))) + (import "foo" (func (param "t" (own $T)))) + )) + (type $R (resource (rep i32))) + (instance $c1 (instantiate $C1 (with "T" (type $R)))) + (instance $c2 (instantiate $C2 + (with "T" (type $R)) + (with "foo" (func $c1 "foo")) + )) + ) +) + +(component + (component + (import "C1" (component $C1 + (import "T1" (type $T1 (sub resource))) + (import "T2" (type $T2 (sub resource))) + (export "foo" (func (param "t" (tuple (own $T1) (own $T2))))) + )) + (import "C2" (component $C2 + (import "T" (type $T (sub resource))) + (export "foo" (func (param "t" (tuple (own $T) (own $T))))) + )) + (type $R (resource (rep i32))) + (instance $c1 (instantiate $C1 + (with "T1" (type $R)) + (with "T2" (type $R)) + )) + (instance $c2 (instantiate $C2 + (with "T" (type $R)) + (with "foo" (func $c1 "foo")) + )) + ) +) + +(assert_invalid + (component + (component $C + (type $R (resource (rep i32))) + (export "R" (type $R)) + ) + (instance $c (instantiate $C)) + (alias export $c "R" (type $R)) + (core func (canon resource.rep $R)) + ) + "not a local resource") + +(component + (component $C + (type $R (resource (rep i32))) + (export "R" (type $R)) + ) + (instance $c (instantiate $C)) + (alias export $c "R" (type $R)) + (core func (canon resource.drop $R)) +) + +(component + (component $C1 + (import "X" (type (sub resource))) + ) + (component $C2 + (import "C1" (component + (import "X" (type (sub resource))) + )) + ) + (instance $c (instantiate $C2 (with "C1" (component $C1)))) +) + +(component + (component $C1 + (import "X" (type $X (sub resource))) + (import "f" (func $f (result (own $X)))) + (export "g" (func $f)) + ) + (component $C2 + (import "C1" (component + (import "X" (type $X (sub resource))) + (import "f" (func (result (own $X)))) + (export "g" (func (result (own $X)))) + )) + ) + (instance $c (instantiate $C2 (with "C1" (component $C1)))) +) + +(component + (component $C1 + (type $X' (resource (rep i32))) + (export $X "X" (type $X')) + + (core func $f (canon resource.drop $X)) + (func (export "f") (param "X" (own $X)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c2 (instantiate $C2 + (with "X" (type $c1 "X")) + (with "f" (func $c1 "f")) + )) +) + +(assert_invalid + (component + (component $C1 + (type $X' (resource (rep i32))) + (export $X "X" (type $X')) + + (core func $f (canon resource.drop $X)) + (func (export "f") (param "X" (own $X)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + (instance $c2 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c3 (instantiate $C2 + (with "X" (type $c1 "X")) + (with "f" (func $c2 "f")) + )) + ) + "resource types are not the same") + +(component + (component $C1 + (type $X (resource (rep i32))) + (export $X1 "X1" (type $X)) + (export $X2 "X2" (type $X)) + + (core func $f (canon resource.drop $X)) + (func (export "f1") (param "X" (own $X1)) (canon lift (core func $f))) + (func (export "f2") (param "X" (own $X2)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c2 (instantiate $C2 + (with "X" (type $c1 "X1")) + (with "f" (func $c1 "f1")) + )) + (instance $c3 (instantiate $C2 + (with "X" (type $c1 "X2")) + (with "f" (func $c1 "f2")) + )) +) + +(component + (component $C1 + (type $X (resource (rep i32))) + (export $X1 "X1" (type $X)) + (export $X2 "X2" (type $X)) + + (core func $f (canon resource.drop $X)) + (func (export "f1") (param "X" (own $X1)) (canon lift (core func $f))) + (func (export "f2") (param "X" (own $X2)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c2 (instantiate $C2 + (with "X" (type $c1 "X1")) + (with "f" (func $c1 "f2")) + )) + (instance $c3 (instantiate $C2 + (with "X" (type $c1 "X2")) + (with "f" (func $c1 "f1")) + )) +) + +(assert_invalid + (component + (component $c + (import "x" (type (sub resource))) + ) + (type $x u32) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected resource, found defined type") + +(assert_invalid + (component + (component $c + (type $t u32) + (import "x" (type (eq $t))) + ) + (type $x (resource (rep i32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected defined type, found resource") + +(assert_invalid + (component + (component $c + (import "x1" (type $x1 (sub resource))) + (import "x2" (type $x2 (eq $x1))) + ) + (type $x1 (resource (rep i32))) + (type $x2 (resource (rep i32))) + (instance (instantiate $c + (with "x1" (type $x1)) + (with "x2" (type $x2)) + )) + ) + "resource types are not the same") + +(component + (type $x (resource (rep i32))) + (component $c + (import "x" (type $t (sub resource))) + (export "y" (type $t)) + ) + (instance $c (instantiate $c (with "x" (type $x)))) + + (alias export $c "y" (type $x2)) + (core func (canon resource.rep $x2)) + +) + +(assert_invalid + (component + (type $r (resource (rep i32))) + (import "x" (func (result (own $r)))) + ) + "func not valid to be used as import") + +(assert_invalid + (component + (type (component + (export "x" (type $x (sub resource))) + (import "f" (func (result (own $x)))) + )) + ) + "func not valid to be used as import") + +(assert_invalid + (component + (type $r (resource (rep i32))) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) + ) + "func not valid to be used as export") + +;; direct exports count as "explicit in" for resources +(component + (type $r' (resource (rep i32))) + (export $r "r" (type $r')) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; instances-as-a-bundle count as "explicit in" for resources +(component + (type $r' (resource (rep i32))) + (instance $i' + (export "r" (type $r')) + ) + (export $i "i" (instance $i')) + (alias export $i "r" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Transitive bundles count for "explicit in" +(component + (type $r' (resource (rep i32))) + (instance $i' + (export "r" (type $r')) + ) + (instance $i2' + (export "i" (instance $i')) + ) + (export $i2 "i2" (instance $i2')) + (alias export $i2 "i" (instance $i)) + (alias export $i "r" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Component instantiations count for "explicit in" +(component + (type $r' (resource (rep i32))) + (component $C + (import "x" (type $x (sub resource))) + (export "y" (type $x)) + ) + (instance $c' (instantiate $C (with "x" (type $r')))) + (export $c "c" (instance $c')) + (alias export $c "y" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Make sure threading things around is valid for "explicit in" +(component + (type $r' (resource (rep i32))) + (component $C + (import "x" (type $x (sub resource))) + (export "y" (type $x)) + ) + (instance $c (instantiate $C (with "x" (type $r')))) + (instance $i (export "x" (type $c "y"))) + + (component $C2 + (import "x" (instance $i + (export "i1" (instance + (export "i2" (type (sub resource))) + )) + )) + (export "y" (type $i "i1" "i2")) + ) + + (instance $i2 (export "i2" (type $i "x"))) + (instance $i1 (export "i1" (instance $i2))) + (instance $c2 (instantiate $C2 + (with "x" (instance $i1)) + )) + (export $r "x" (type $c2 "y")) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Importing-and-exporting instances through instantiation counts for "explicit +;; in" +(component + (type $r' (resource (rep i32))) + (component $C + (import "x" (instance $x (export "t" (type (sub resource))))) + (export "y" (instance $x)) + ) + (instance $c' (instantiate $C + (with "x" (instance + (export "t" (type $r')) + )) + )) + (export $c "c" (instance $c')) + (alias export $c "y" (instance $y)) + (alias export $y "t" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +(component definition + (type $i (instance + (export "r" (type $r (sub resource))) + (export "f" (func (result (own $r)))) + )) + (import "i1" (instance $i1 (type $i))) + (import "i2" (instance $i2 (type $i))) + + (component $c + (import "r" (type $t (sub resource))) + (import "f" (func (result (own $t)))) + ) + (instance (instantiate $c + (with "r" (type $i1 "r")) + (with "f" (func $i1 "f")) + )) + (instance (instantiate $c + (with "r" (type $i2 "r")) + (with "f" (func $i2 "f")) + )) +) + + +(assert_invalid + (component + (type $i (instance + (export "r" (type $r (sub resource))) + (export "f" (func (result (own $r)))) + )) + (import "i1" (instance $i1 (type $i))) + (import "i2" (instance $i2 (type $i))) + + (component $c + (import "r" (type $t (sub resource))) + (import "f" (func (result (own $t)))) + ) + (instance (instantiate $c + (with "r" (type $i1 "r")) + (with "f" (func $i2 "f")) + )) + ) + "resource types are not the same") + +;; substitution works +(component + (type $t (resource (rep i32))) + (component $c + (import "x" (type $t (sub resource))) + (export "y" (type $t)) + ) + (instance $c1 (instantiate $c (with "x" (type $t)))) + (instance $c2 (instantiate $c (with "x" (type $t)))) + + (component $c2 + (import "x1" (type $t (sub resource))) + (import "x2" (type (eq $t))) + (import "x3" (type (eq $t))) + ) + (instance (instantiate $c2 + (with "x1" (type $t)) + (with "x2" (type $c1 "y")) + (with "x3" (type $c2 "y")) + )) +) + +;; must supply a resource to instantiation +(assert_invalid + (component + (component $c + (import "x" (type (sub resource))) + ) + (instance (instantiate $c)) + ) + "missing import named `x`") +(assert_invalid + (component + (type $x (resource (rep i32))) + (component $c + (import "x" (type (sub resource))) + (import "y" (type (sub resource))) + ) + (instance (instantiate $c (with "x" (type $x)))) + ) + "missing import named `y`") + +;; supply the wrong resource +(assert_invalid + (component + (type $x (resource (rep i32))) + (type $y (resource (rep i32))) + (component $c + (import "x" (type $t (sub resource))) + (import "y" (type (eq $t))) + ) + (instance (instantiate $c + (with "x" (type $x)) + (with "y" (type $y)) + )) + ) + "resource types are not the same") + +;; aliasing outer resources is ok +(component $A + (type $C (component + (import "x" (type $x (sub resource))) + + (type $y (component + (alias outer $C $x (type $my-x)) + (import "x" (type (eq $my-x))) + )) + + (import "y" (component (type $y))) + (export "z" (component (type $y))) + )) + + (type $t (resource (rep i32))) + + (alias outer $A $t (type $other-t)) + + (type (instance (export "t" (type (eq $t))))) + (type (component (export "t" (type (eq $t))))) + (type (component (import "t" (type (eq $t))))) +) + +;; aliasing beyond components, however, is not ok +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (component (alias outer $A $t (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (record (field "x" (own $t)))) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (borrow $t)) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (component (export "a" (type (eq $t))))) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (component (import "a" (type (eq $t))))) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") + +(assert_invalid + (component + (component $X + (type $t (resource (rep i32))) + (export "t" (type $t)) + ) + (component $F + (import "x" (component (export "t" (type $t (sub resource))))) + ) + (instance $x1 (instantiate $X)) + (instance $f1 (instantiate $F (with "x" (instance $x1)))) + ) + "expected component, found instance") + +;; Show that two instantiations of the same component produce unique exported +;; resource types. +(assert_invalid + (component + (component $F + (type $t1 (resource (rep i32))) + (export "t1" (type $t1)) + ) + (instance $f1 (instantiate $F)) + (instance $f2 (instantiate $F)) + (alias export $f1 "t1" (type $t1)) + (alias export $f2 "t1" (type $t2)) + (component $T + (import "x" (type $x (sub resource))) + (import "y" (type (eq $x))) + ) + (instance $test + (instantiate $T (with "x" (type $t1)) (with "y" (type $t2)))) + ) + "type mismatch for import `y`") + +;; Show that re-exporting imported resources from an imported component doesn't +;; change the identity of that resource. +(component + (component $X + (type $t (resource (rep i32))) + (export "t" (type $t)) + ) + (component $F + (import "x" (instance $i (export "t" (type $t (sub resource))))) + (alias export $i "t" (type $t)) + (export "t" (type $t)) + ) + (instance $x1 (instantiate $X)) + (instance $f1 (instantiate $F (with "x" (instance $x1)))) + (instance $f2 (instantiate $F (with "x" (instance $x1)))) + (alias export $f1 "t" (type $t1)) + (alias export $f2 "t" (type $t2)) + (component $T + (import "x" (type $x (sub resource))) + (import "y" (type (eq $x))) + ) + (instance $test + (instantiate $T (with "x" (type $t1)) (with "y" (type $t2)))) +) + +(assert_invalid + (component (import "[static]" (func))) + "failed to find `.` character") + +;; validation of `[constructor]foo` +(assert_invalid + (component (import "[constructor]" (func))) + "not in kebab case") +(assert_invalid + (component (import "[constructor]a" (func))) + "should return one value") +(assert_invalid + (component (import "[constructor]a" (func (result u32)))) + "should return `(own $T)`") +(assert_invalid + (component + (import "b" (type $a (sub resource))) + (import "[constructor]a" (func (result (own $a))))) + "import name `[constructor]a` is not valid") +(assert_invalid + (component + (import "b" (type $a (sub resource))) + (import "[constructor]a" (func (result (own $a))))) + "function does not match expected resource name `b`") +(assert_invalid + (component + (import "b" (type $a (sub resource))) + (import "[constructor]a" (func (result (result(own $a)))))) + "function does not match expected resource name `b`") +(component definition + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (own $a))))) +(component definition + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (result (own $a)))))) +(component definition + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (result (own $a) (error string)))))) +(component definition + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (param "x" u32) (result (own $a))))) +(assert_invalid + (component + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result string)))) + "function should return `(own $T)` or `(result (own $T))`") +(assert_invalid + (component + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (result string))))) + "function should return `(own $T)` or `(result (own $T))`") + +;; validation of `[method]a.b` +(assert_invalid + (component (import "[method]" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[method]a" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[method]a." (func))) + "not in kebab case") +(assert_invalid + (component (import "[method].a" (func))) + "not in kebab case") +(assert_invalid + (component (import "[method]a.b.c" (func))) + "not in kebab case") +(assert_invalid + (component (import "[method]a.b" (instance))) + "is not a func") +(assert_invalid + (component (import "[method]a.b" (func))) + "should have at least one argument") +(assert_invalid + (component (import "[method]a.b" (func (param "x" u32)))) + "should have a first argument called `self`") +(assert_invalid + (component (import "[method]a.b" (func (param "self" u32)))) + "should take a first argument of `(borrow $T)`") +(assert_invalid + (component + (import "b" (type $T (sub resource))) + (import "[method]a.b" (func (param "self" (borrow $T))))) + "does not match expected resource name") +(component definition + (import "a" (type $T (sub resource))) + (import "[method]a.b" (func (param "self" (borrow $T))))) + +;; validation of `[static]a.b` +(assert_invalid + (component (import "[static]" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[static]a" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[static]a." (func))) + "not in kebab case") +(assert_invalid + (component (import "[static].a" (func))) + "not in kebab case") +(assert_invalid + (component (import "[static]a.b.c" (func))) + "not in kebab case") +(assert_invalid + (component (import "[static]a.b" (instance))) + "is not a func") +(assert_invalid + (component (import "[static]a.b" (func))) + "static resource name is not known in this context") + +(component definition + (import "a" (type (sub resource))) + (import "[static]a.b" (func))) + +;; exports/imports are disjoint +(assert_invalid + (component + (import "b" (type $T (sub resource))) + (import "f" (func $f (param "self" (borrow $T)))) + (export "[method]b.foo" (func $f)) + ) + "resource used in function does not have a name in this context") + +(component + (component + (import "b" (type $T (sub resource))) + (import "f" (func $f (param "self" (borrow $T)))) + (export $c "c" (type $T)) + (export "[method]c.foo" (func $f) (func (param "self" (borrow $c)))) + ) +) + +;; imports aren't transitive +(assert_invalid + (component + (import "i" (instance $i + (export "t" (type (sub resource))) + )) + (alias export $i "t" (type $t)) + (import "[method]t.foo" (func (param "self" (borrow $t)))) + ) + "resource used in function does not have a name in this context") + +;; validation happens in a type context +(assert_invalid + (component + (type (component + (import "b" (type $T (sub resource))) + (import "[constructor]a" (func (result (own $T)))) + )) + ) + "function does not match expected resource name `b`") + +;; bag-of-exports validation +(assert_invalid + (component + (type $T (resource (rep i32))) + (core module $m (func (export "a") (result i32) unreachable)) + (core instance $i (instantiate $m)) + (func $f (result (own $T)) (canon lift (core func $i "a"))) + (instance + (export "a" (type $T)) + (export "[constructor]a" (func $f)) + ) + ) + "resource used in function does not have a name in this context") + +(component + (component $C) + (instance (instantiate $C (with "this is not kebab case" (component $C)))) +) + +;; Test that unused arguments to instantiation are not validated to have +;; appropriate types with respect to kebab naming conventions which require +;; functions/interfaces/etc. +(component + (component $C) + (instance (instantiate $C (with "[method]foo.bar" (component $C)))) +) + +;; thread a resource through a few layers +(component + (component $C + (import "in" (type $r (sub resource))) + (export "out" (type $r)) + ) + + (type $r (resource (rep i32))) + + (instance $c1 (instantiate $C (with "in" (type $r)))) + (instance $c2 (instantiate $C (with "in" (type $c1 "out")))) + (instance $c3 (instantiate $C (with "in" (type $c2 "out")))) + (instance $c4 (instantiate $C (with "in" (type $c3 "out")))) + (instance $c5 (instantiate $C (with "in" (type $c4 "out")))) + + (component $C2 + (import "in1" (type $r (sub resource))) + (import "in2" (type (eq $r))) + (import "in3" (type (eq $r))) + (import "in4" (type (eq $r))) + (import "in5" (type (eq $r))) + (import "in6" (type (eq $r))) + ) + + (instance (instantiate $C2 + (with "in1" (type $r)) + (with "in2" (type $c1 "out")) + (with "in3" (type $c2 "out")) + (with "in4" (type $c3 "out")) + (with "in5" (type $c4 "out")) + (with "in6" (type $c5 "out")) + )) +) + +;; exporting an instance type "freshens" resources +(assert_invalid + (component + (import "x" (instance $i + (type $i (instance + (export "r" (type (sub resource))) + )) + (export "a" (instance (type $i))) + (export "b" (instance (type $i))) + )) + + (component $C + (import "x" (type $x (sub resource))) + (import "y" (type (eq $x))) + ) + (instance (instantiate $C + (with "x" (type $i "a" "r")) + (with "y" (type $i "b" "r")) + )) + ) + "resource types are not the same") + +(component + (type (export "x") (component + (type $t' (instance + (export "r" (type (sub resource))) + )) + (export "t" (instance $t (type $t'))) + (alias export $t "r" (type $r)) + (type $t2' (instance + (export "r2" (type (eq $r))) + (export "r" (type (sub resource))) + )) + (export "t2" (instance (type $t2'))) + )) +) + +(component + (type (component + (type (instance + (export "bar" (type (sub resource))) + (export "[static]bar.a" (func)) + )) + (export "x" (instance (type 0))) + )) +) + +(assert_invalid + (component + (type $r (resource (rep i32))) + (type (func (result (borrow $r)))) + ) + "function result cannot contain a `borrow` type") +(assert_invalid + (component + (type $r (resource (rep i32))) + (type (func (result (list (borrow $r))))) + ) + "function result cannot contain a `borrow` type") +(assert_invalid + (component + (type $r (resource (rep i32))) + (type (func (result (option (borrow $r))))) + ) + "function result cannot contain a `borrow` type") +(assert_invalid + (component + (type $r (resource (rep i32))) + (type $t (record (field "f" (borrow $r)))) + (type (func (result (option (list $t))))) + ) + "function result cannot contain a `borrow` type") + +;; forms of canon builtins +(component + (type $r (resource (rep i32))) + (core func (canon resource.new $r)) + (canon resource.new $r (core func)) + (core func (canon resource.drop $r)) + (canon resource.drop $r (core func)) + (core func (canon resource.rep $r)) + (canon resource.rep $r (core func)) +) diff --git a/src/test/resources/spec-tests/wasm-tools/tags.wast b/src/test/resources/spec-tests/wasm-tools/tags.wast new file mode 100644 index 0000000..5c70d3a --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/tags.wast @@ -0,0 +1,30 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (alias core export $i "" (core tag $t)) + ) + "export `` for core instance 0 is not a tag") + +(component + (core module $m (tag (export ""))) + (core instance $i (instantiate $m)) + (alias core export $i "" (core tag $t)) +) + +(component + (core module $m (tag (export ""))) + (core instance $i (instantiate $m)) + (core instance + (export "" (tag $i "")))) + +(assert_invalid + (component + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (core instance + (export "" (tag 0))) + ) + "unknown tag 0") diff --git a/src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast b/src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast new file mode 100644 index 0000000..d2971f8 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast @@ -0,0 +1,504 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; Test that unnamed types in various types are all detected + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (record (field "f" $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (tuple $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (variant (case "c" $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (option $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (result $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +;; Test that various types are all flagged as "requires a name" + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (enum "a")) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (flags "a")) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (variant (case "a"))) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (resource (rep i32))) + (type $f (list (own $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +;; Some types don't need names +(component + (type $t1 (tuple (tuple u32))) + (export "t1" (type $t1)) + + (type $t2 (option (tuple (list u8) (result (list u32) (error (option string)))))) + (export "t2" (type $t2)) + + (type $t3 u32) + (export "t3" (type $t3)) +) + +(component + (type $t' (record (field "f" u32))) + (export $t "t" (type $t')) + (type $t2 (record (field "x" $t))) + (export "t2" (type $t2)) +) + +;; imports are validated as well +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $t2 (record (field "f" $t))) + (import "x" (type (eq $t2))) + ) + "type not valid to be used as import") +(component + (type $t (record (field "f" u32))) + (import "t" (type $t' (eq $t))) + (type $t2 (record (field "f" $t'))) + (import "x" (type (eq $t2))) +) +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $t2 (record (field "f" $t))) + (import "x" (func (param "x" $t2))) + ) + "func not valid to be used as import") + +(assert_invalid + (component + (type $t (resource (rep i32))) + (export "t" (type $t)) + (type $f (list (own $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +;; validate within the type context +(assert_invalid + (component + (type (component + (type $t (record (field "f" u32))) + (export "f" (func (param "x" $t))) + )) + ) + "func not valid to be used as export") +(assert_invalid + (component + (type (component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + ) + "type not valid to be used as export") + +;; instances of unexported types is ok +(component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (instance + (export "f" (type $f)) + ) +) +;; .. but exporting them is not +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (instance $i + (export "f" (type $f)) + ) + (export "i" (instance $i)) + ) + "instance not valid to be used as export") + +;; Can't export a lifted function with unexported types +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $f) (canon lift (core func $i "f"))) + (export "f" (func $f)) + ) + "func not valid to be used as export") + +;; Unexported instances don't work +(assert_invalid + (component + (type $t' (record (field "f" u32))) + (instance $i + (export "t" (type $t')) + ) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) + ) + "func not valid to be used as export") + +;; Even through a component it doesn't work +(assert_invalid + (component + (component $C + (type $t (record (field "f" u32))) + (export "t" (type $t)) + ) + (instance $i (instantiate $C)) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) + ) + "func not valid to be used as export") + +;; through exported instances is ok though +(component + (type $t' (record (field "f" u32))) + (instance $i' + (export "t" (type $t')) + ) + (export $i "i" (instance $i')) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) +) +(component + (component $C + (type $t (record (field "f" u32))) + (export "t" (type $t)) + ) + (instance $i' (instantiate $C)) + (export $i "i" (instance $i')) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) +) + +;; a type-ascribed export which is otherwise invalid can become valid +(component + (type $t (record (field "f" u32))) + + (core module $m (func (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "x" $t) (canon lift (core func $i "f"))) + + (export $t' "t" (type $t)) + (export "f" (func $f) (func (param "x" $t'))) +) + +;; imports can't reference exports +(assert_invalid + (component + (type $t1 (record (field "f" u32))) + (export $t2 "t1" (type $t1)) + (import "i" (func (result $t2))) + ) + "func not valid to be used as import") + +;; exports can reference imports +(component + (type $t1 (record (field "f" u32))) + (import "t1" (type $t2 (eq $t1))) + (export "e-t1" (type $t2)) +) +(component + (component + (type $t1 (record (field "f" u32))) + (import "t1" (type $t2 (eq $t1))) + (import "i" (func $f (result $t2))) + + (export "e-i" (func $f)) + ) +) + +;; outer aliases don't work for imports/exports +(assert_invalid + (component + (type $t1 (record (field "f" u32))) + (import "t1" (type $t2 (eq $t1))) + (component + (import "i" (func $f (result $t2))) + ) + ) + "func not valid to be used as import") +(assert_invalid + (component + (type $t1 (record (field "f" u32))) + (export $t2 "t1" (type $t1)) + (component + (core module $m (func (export "f") (result i32) unreachable)) + (core instance $i (instantiate $m)) + (func $f (export "i") (result $t2) (canon lift (core func $i "f"))) + ) + ) + "func not valid to be used as export") + +;; outer aliases work for components, modules, and resources +(component + (type $c (component)) + (type (component + (import "c" (component (type $c))) + )) + (component + (import "c" (component (type $c))) + ) + (type $i (instance)) + (type (component + (import "c" (instance (type $i))) + )) + + (type $r (resource (rep i32))) + (type (component + (import "r" (type (eq $r))) + )) +) + +;; reexport of an import is fine +(component + (component + (import "r" (func $r)) + (export "r2" (func $r)) + ) +) +(component + (type $t (record (field "f" u32))) + (import "r" (type $r (eq $t))) + (export "r2" (type $r)) +) +(component + (import "r" (instance $r)) + (export "r2" (instance $r)) +) +(component definition + (import "r" (type $r (sub resource))) + (export "r2" (type $r)) +) + +;; bag of exports cannot be exported by carrying through context that's not +;; otherwise exported +(assert_invalid + (component + (component $A + (type $t (record (field "f" u32))) + (export $t2 "t" (type $t)) + (core module $m (func (export "f") (result i32) unreachable)) + (core instance $i (instantiate $m)) + (func $f (result $t2) (canon lift (core func $i "f"))) + + (instance (export "i") + (export "f" (func $f)) + ) + ) + + (instance $a (instantiate $A)) + ;; this component only exports `f`, not the record type that is the result + ;; of `f`, so it should be invalid. + (export "a" (instance $a "i")) + ) + "instance not valid to be used as export") + +;; instance types can be "temporarily invalid", but not if they're attached +;; to a concrete component +(component + (type (instance + (type $t (record (field "f" u32))) + (export "f" (func (param "x" $t))) + )) +) +(assert_invalid + (component + (type $i (instance + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + (import "f" (instance (type $i))) + ) + "instance not valid to be used as import") + +;; allow for one import to refer to another +(component definition $C + (import "foo" (instance $i + (type $baz' (record (field "f" u32))) + (export "baz" (type $baz (eq $baz'))) + (type $bar' (record (field "baz" $baz))) + (export "bar" (type $bar (eq $bar'))) + )) + (alias export $i "bar" (type $bar)) + (import "bar" (instance + (alias outer $C $bar (type $bar')) + (export "bar" (type $bar (eq $bar'))) + (export "a" (func $f (result $bar))) + )) +) + +;; allow for one import to refer to another +(component + (type $r' (record (field "f" u32))) + (import "r" (type $r (eq $r'))) + (component $C + (type $r' (record (field "f" u32))) + (import "r" (type $r (eq $r'))) + (type $r2' (record (field "r" $r))) + (export "r2" (type $r2')) + ) + (instance $c (instantiate $C (with "r" (type $r)))) + (export "r2" (type $c "r2")) +) + +;; types are validated when they are exported +(assert_invalid + (component + (type $i (instance + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + (import "f" (type (eq $i))) + ) + "type not valid to be used as import") +(assert_invalid + (component + (type $i (instance + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + (export "f" (type $i)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (func (result $t))) + (import "f" (type (eq $f))) + ) + "type not valid to be used as import") +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (func (result $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(component + (type (;0;) + (instance + (type (;0;) (enum "qux")) + (export (;1;) "baz" (type (eq 0))) + (type (;2;) (record (field "bar" 1) )) + (export (;3;) "foo" (type (eq 2))) + ) + ) + (import (interface "demo:component/types") (instance (;0;) (type 0))) + (component + (type (;0;) + (instance + (type (;0;) (enum "qux")) + (export (;1;) "baz" (type (eq 0))) + (type (;2;) (record (field "bar" 1) )) + (export (;3;) "foo" (type (eq 2))) + ) + ) + (import (interface "demo:component/types") (instance (;0;) (type 0))) + (component (;0;) + (type (;0;) (enum "qux")) + (import "import-type-baz" (type (;1;) (eq 0))) + (type (;2;) (record (field "bar" 1) )) + (import "import-type-bar" (type (;3;) (eq 2))) + (export (;4;) "foo" (type 3)) + ) + (instance (;1;) (instantiate 0 + (with "import-type-baz" (type 0 "baz")) + (with "import-type-bar" (type 0 "foo")) + ) + ) + (export (;0;) (interface "demo:component/types") (instance 1)) + ) + (instance (instantiate 0 (with "demo:component/types" (instance 0)))) + (export (interface "demo:component/types") (instance 1 "demo:component/types")) +) diff --git a/src/test/resources/spec-tests/wasm-tools/types.wast b/src/test/resources/spec-tests/wasm-tools/types.wast new file mode 100644 index 0000000..5df1ec9 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/types.wast @@ -0,0 +1,374 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (type $t (instance)) + (import "a" (func (type $t))) + ) + "type index 0 is not a function type") + +(assert_invalid + (component + (core type $t (func)) + (import "a" (core module (type $t))) + ) + "core type index 0 is not a module type") + +(assert_invalid + (component + (type $t (func)) + (import "a" (instance (type $t))) + ) + "type index 0 is not an instance type") + +(assert_invalid + (component + (type $t (func)) + (type (component + (import "a" (instance (type $t))) + )) + ) + "type index 0 is not an instance type") + +(assert_invalid + (component + (core type $t (func)) + (type (component + (import "a" (core module (type $t))) + )) + ) + "core type index 0 is not a module type") + +(assert_invalid + (component + (type $t (instance)) + (type (component + (import "a" (func (type $t))) + )) + ) + "type index 0 is not a function type") + +(assert_invalid + (component + (export "a" (core module 0)) + ) + "module index out of bounds") + +(assert_invalid + (component + (export "a" (instance 0)) + ) + "instance index out of bounds") + +(assert_invalid + (component + (core type (module + (export "a" (func (type 0))) + )) + ) + "type index out of bounds") + +(assert_invalid + (component + (core type (module + (export "a" (func)) + (export "a" (func)) + )) + ) + "export name `a` already defined") + +(assert_invalid + (component + (core type (module + (import "" "" (func)) + (import "" "" (func)) + )) + ) + "duplicate import name") + +(assert_invalid + (component + (core type (module + (import "" "" (memory 70000)) + )) + ) + "memory size must be at most") + +(assert_invalid + (component + (type (component + (export "a" (func (type 0))) + )) + ) + "type index out of bounds") + +(assert_invalid + (component + (type (component + (export "a" (func)) + (export "A" (func)) + )) + ) + "export name `A` conflicts with previous name `a`") + +(assert_invalid + (component + (type (component + (import "A" (func)) + (import "a" (func)) + )) + ) + "import name `a` conflicts with previous name `A`") + +(assert_malformed + (component quote + "(component $c (core type $t (module (alias outer $c $t (type)))))" + ) + "unknown core type") + +(assert_invalid + (component + (core type (module + (alias outer 1 0 (type)) + )) + ) + "type index out of bounds") + +(component $c + (core type $f (func)) + (core type $t (module + (alias outer $c $f (type)) + )) +) + +(assert_malformed + (component quote + "(component $c (type $t (component (alias outer $c $t (type)))))" + ) + "unknown type") + +(assert_invalid + (component + (type (component + (alias outer 1 0 (type)) + )) + ) + "type index out of bounds") + +(assert_invalid + (component $c + (type $f (func)) + (type $t (component + (alias outer 100 0 (type)) + )) + ) + "invalid outer alias count of 100") + +(assert_invalid + (component $c + (type $f (func)) + (type $t (component + (core type (module + (export "" (func)) + (export "" (func)) + )) + )) + ) + "name `` already defined") + +(assert_invalid + (component + (type (instance + (export "" (func (type 0))) + )) + ) + "type index out of bounds") + +(assert_invalid + (component + (type (instance + (export "foo-BAR-baz" (func)) + (export "FOO-bar-BAZ" (func)) + )) + ) + "export name `FOO-bar-BAZ` conflicts with previous name `foo-BAR-baz`") + +(assert_malformed + (component quote + "(component $c (type $t (instance (alias outer $c $t (type)))))" + ) + "unknown type") + +(assert_invalid + (component + (type (instance + (alias outer 1 0 (type)) + )) + ) + "type index out of bounds") + +(assert_invalid + (component $c + (type $f (func)) + (type $t (instance + (alias outer 100 0 (type)) + )) + ) + "invalid outer alias count of 100") + +(assert_invalid + (component $c + (type $f (func)) + (type $t (instance + (core type (module + (export "" (func)) + (export "" (func)) + )) + )) + ) + "name `` already defined") + +(assert_invalid + (component $c + (type $f (func (param "" string))) + ) + "function parameter name cannot be empty") + +(component + (type $t (func (result (tuple (list u8) u32)))) +) + +(component $C + (core type $t (func)) + (core type (module + (alias outer $C $t (type $a)) + (import "" "" (func (type $a))) + )) +) + +(component $C + (component $C2 + (core type $t (func)) + (core type (module + (alias outer $C2 $t (type $a)) + (import "" "" (func (type $a))) + )) + ) +) + +(component $C + (core type $t (func)) + (component $C2 + (core type (module + (alias outer $C $t (type $a)) + (import "" "" (func (type $a))) + )) + ) +) + +(component + (type (instance + (type string) + (export "a" (type (eq 0))) + )) +) + +(component + (type (component + (type string) + (import "a" (type (eq 0))) + (export "b" (type (eq 0))) + )) +) + +(assert_invalid + (component + (type (variant)) + ) + "variant type must have at least one case") + +(assert_invalid + (component + (type (enum)) + ) + "enum type must have at least one variant") + +(assert_invalid + (component + (type (record)) + ) + "record type must have at least one field") + +(assert_invalid + (component + (type (flags)) + ) + "flags must have at least one entry") + +(assert_invalid + (component + (type (tuple)) + ) + "tuple type must have at least one type") + +(component $c + (core type $f (func)) + (component $c2 + (core type $t (module + (alias outer $c $f (type)) + )) + ) +) + +(assert_invalid + (component + (type (flags + "f1" + "f2" + "f3" + "f4" + "f5" + "f6" + "f7" + "f8" + "f9" + "f10" + "f11" + "f12" + "f13" + "f14" + "f15" + "f16" + "f17" + "f18" + "f19" + "f20" + "f21" + "f22" + "f23" + "f24" + "f25" + "f26" + "f27" + "f28" + "f29" + "f30" + "f31" + "f32" + "f33" + )) + ) + "cannot have more than 32 flags") + +(assert_invalid + (component + (core type $t (module)) + (core type (func (param (ref $t)))) + ) + "type index 0 is a module type") + +(assert_invalid + (component + (core type (func (param (ref 100)))) + ) + "type index out of bounds") diff --git a/src/test/resources/spec-tests/wasm-tools/very-nested.wast b/src/test/resources/spec-tests/wasm-tools/very-nested.wast new file mode 100644 index 0000000..42c5aed --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/very-nested.wast @@ -0,0 +1,1954 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component $$esl + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "00AGG554M******+*****e 4$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "anonmm-x23foinas-ASDOJASD") + ) + (component + (export "c t.****0*********") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "0+AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00A$qq") + ) + (component + (export "c t.*************") + (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "15AG:GG!le*$$qq") + ) + (component + (export "c t.*") + (component + (export "c 3@EGGGG$qq**") + (export "bsdew2-sdbsdb") + ) + (component + (export "c t.********)*eleo &m Nx2GGGGle*$$qq") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "0*************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "00AGG554M******+*****e 4$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "anonmm-x23foinas-ASDOJASD") + ) + (component + (export "c t.****0*********") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "0+AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00A$qq") + ) + (component + (export "c t.*************") + (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "15AG:GG!le*$$qq") + ) + (component + (export "c .t*") + (component + (export "c 3@EGGGG$qq**") + (export "bsdew2-sdbsdb") + ) + (component + (export "c t.********)*eleo &m Nx2GGGGle*$$qq") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle '$$qq") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c *****") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "00AGG554M******+*****e 4$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "anonmm-x23foinas-ASDOJASD") + ) + (component + (export "c t.****0*********") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "0+AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00A$qq") + ) + (component + (export "c t.*************") + (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "15AG:GG!le*$$qq") + ) + (component + (export "c t.*") + (component + (export "c 3@EGGGG$qq**") + (export "bsdew2-sdbsdb") + ) + (component + (export "c t.********)*eleo &m Nx2GGGGle*$$qq") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "0*************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "00AGG554M******+*****e 4$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "anonmm-x23foinas-ASDOJASD") + ) + (component + (export "c t.****0*********") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "0+AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00A$qq") + ) + (component + (export "c t.*************") + (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "15AG:GG!le*$$qq") + ) + (component + (export "c .t*") + (component + (export "c 3@EGGGG$qq**") + (export "bsdew2-sdbsdb") + ) + (component + (export "c t.********)*eleo &m Nx2GGGGle*$$qq") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle '$$qq") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E***0AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle '$$qq") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E**************777777777777777777777777777777777777777777777777777777777777771.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E***0AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle '$$qq") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + ) + "conflicts with previous name") + +(assert_invalid + (component + (type $m0 (component)) + (type $m1 (component + (import "i1" (component (type $m0))) + (import "i2" (component (type $m0))) + (import "i3" (component (type $m0))) + (import "i4" (component (type $m0))) + (import "i5" (component (type $m0))) + (import "i6" (component (type $m0))) + (import "i7" (component (type $m0))) + (import "i8" (component (type $m0))) + (import "i9" (component (type $m0))) + (import "i10" (component (type $m0))) + )) + (type $m2 (component + (import "i1" (component (type $m1))) + (import "i2" (component (type $m1))) + (import "i3" (component (type $m1))) + (import "i4" (component (type $m1))) + (import "i5" (component (type $m1))) + (import "i6" (component (type $m1))) + (import "i7" (component (type $m1))) + (import "i8" (component (type $m1))) + (import "i9" (component (type $m1))) + (import "i10" (component (type $m1))) + )) + (type $m3 (component + (import "i1" (component (type $m2))) + (import "i2" (component (type $m2))) + (import "i3" (component (type $m2))) + (import "i4" (component (type $m2))) + (import "i5" (component (type $m2))) + (import "i6" (component (type $m2))) + (import "i7" (component (type $m2))) + (import "i8" (component (type $m2))) + (import "i9" (component (type $m2))) + (import "i10" (component (type $m2))) + )) + (type $m4 (component + (import "i1" (component (type $m3))) + (import "i2" (component (type $m3))) + (import "i3" (component (type $m3))) + (import "i4" (component (type $m3))) + (import "i5" (component (type $m3))) + (import "i6" (component (type $m3))) + (import "i7" (component (type $m3))) + (import "i8" (component (type $m3))) + (import "i9" (component (type $m3))) + (import "i10" (component (type $m3))) + )) + (type $m5 (component + (import "i1" (component (type $m4))) + (import "i2" (component (type $m4))) + (import "i3" (component (type $m4))) + (import "i4" (component (type $m4))) + (import "i5" (component (type $m4))) + (import "i6" (component (type $m4))) + (import "i7" (component (type $m4))) + (import "i8" (component (type $m4))) + (import "i9" (component (type $m4))) + (import "i10" (component (type $m4))) + )) + (type $m6 (component + (import "i1" (component (type $m5))) + (import "i2" (component (type $m5))) + (import "i3" (component (type $m5))) + (import "i4" (component (type $m5))) + (import "i5" (component (type $m5))) + (import "i6" (component (type $m5))) + (import "i7" (component (type $m5))) + (import "i8" (component (type $m5))) + (import "i9" (component (type $m5))) + (import "i10" (component (type $m5))) + )) + (type $m7 (component + (import "i1" (component (type $m6))) + (import "i2" (component (type $m6))) + (import "i3" (component (type $m6))) + (import "i4" (component (type $m6))) + (import "i5" (component (type $m6))) + (import "i6" (component (type $m6))) + (import "i7" (component (type $m6))) + (import "i8" (component (type $m6))) + (import "i9" (component (type $m6))) + (import "i10" (component (type $m6))) + )) + (type $m8 (component + (import "i1" (component (type $m7))) + (import "i2" (component (type $m7))) + (import "i3" (component (type $m7))) + (import "i4" (component (type $m7))) + (import "i5" (component (type $m7))) + (import "i6" (component (type $m7))) + (import "i7" (component (type $m7))) + (import "i8" (component (type $m7))) + (import "i9" (component (type $m7))) + (import "i10" (component (type $m7))) + )) + (type $m9 (component + (import "i1" (component (type $m8))) + (import "i2" (component (type $m8))) + (import "i3" (component (type $m8))) + (import "i4" (component (type $m8))) + (import "i5" (component (type $m8))) + (import "i6" (component (type $m8))) + (import "i7" (component (type $m8))) + (import "i8" (component (type $m8))) + (import "i9" (component (type $m8))) + (import "i10" (component (type $m8))) + )) + + (type $m (component + (import "a" (component (type $m9))) + )) + (import "a" (component $a (type $m9))) + (import "b" (component $b (type $m))) + (instance (instantiate $b (with "a" (component $a)))) + ) + "effective type size exceeds the limit") + +(assert_invalid + (component + (component $m0) + (component $m1 + (instance (export "e0") (instantiate $m0)) + (instance (export "e1") (instantiate $m0)) + (instance (export "e2") (instantiate $m0)) + (instance (export "e3") (instantiate $m0)) + (instance (export "e4") (instantiate $m0)) + (instance (export "e5") (instantiate $m0)) + (instance (export "e6") (instantiate $m0)) + (instance (export "e7") (instantiate $m0)) + (instance (export "e8") (instantiate $m0)) + (instance (export "e9") (instantiate $m0)) + ) + (component $m2 + (instance (export "e0") (instantiate $m1)) + (instance (export "e1") (instantiate $m1)) + (instance (export "e2") (instantiate $m1)) + (instance (export "e3") (instantiate $m1)) + (instance (export "e4") (instantiate $m1)) + (instance (export "e5") (instantiate $m1)) + (instance (export "e6") (instantiate $m1)) + (instance (export "e7") (instantiate $m1)) + (instance (export "e8") (instantiate $m1)) + (instance (export "e9") (instantiate $m1)) + ) + (component $m3 + (instance (export "e0") (instantiate $m2)) + (instance (export "e1") (instantiate $m2)) + (instance (export "e2") (instantiate $m2)) + (instance (export "e3") (instantiate $m2)) + (instance (export "e4") (instantiate $m2)) + (instance (export "e5") (instantiate $m2)) + (instance (export "e6") (instantiate $m2)) + (instance (export "e7") (instantiate $m2)) + (instance (export "e8") (instantiate $m2)) + (instance (export "e9") (instantiate $m2)) + ) + (component $m4 + (instance (export "e0") (instantiate $m3)) + (instance (export "e1") (instantiate $m3)) + (instance (export "e2") (instantiate $m3)) + (instance (export "e3") (instantiate $m3)) + (instance (export "e4") (instantiate $m3)) + (instance (export "e5") (instantiate $m3)) + (instance (export "e6") (instantiate $m3)) + (instance (export "e7") (instantiate $m3)) + (instance (export "e8") (instantiate $m3)) + (instance (export "e9") (instantiate $m3)) + ) + (component $m5 + (instance (export "e0") (instantiate $m4)) + (instance (export "e1") (instantiate $m4)) + (instance (export "e2") (instantiate $m4)) + (instance (export "e3") (instantiate $m4)) + (instance (export "e4") (instantiate $m4)) + (instance (export "e5") (instantiate $m4)) + (instance (export "e6") (instantiate $m4)) + (instance (export "e7") (instantiate $m4)) + (instance (export "e8") (instantiate $m4)) + (instance (export "e9") (instantiate $m4)) + ) + (component $m6 + (instance (export "e0") (instantiate $m5)) + (instance (export "e1") (instantiate $m5)) + (instance (export "e2") (instantiate $m5)) + (instance (export "e3") (instantiate $m5)) + (instance (export "e4") (instantiate $m5)) + (instance (export "e5") (instantiate $m5)) + (instance (export "e6") (instantiate $m5)) + (instance (export "e7") (instantiate $m5)) + (instance (export "e8") (instantiate $m5)) + (instance (export "e9") (instantiate $m5)) + ) + (component $m7 + (instance (export "e0") (instantiate $m6)) + (instance (export "e1") (instantiate $m6)) + (instance (export "e2") (instantiate $m6)) + (instance (export "e3") (instantiate $m6)) + (instance (export "e4") (instantiate $m6)) + (instance (export "e5") (instantiate $m6)) + (instance (export "e6") (instantiate $m6)) + (instance (export "e7") (instantiate $m6)) + (instance (export "e8") (instantiate $m6)) + (instance (export "e9") (instantiate $m6)) + ) + ) + "effective type size exceeds the limit") + +(assert_invalid + (component + ;; size(t0) == 1 + (type $t0 (flags "x")) + + ;; size(t1) == 10 + (type $t1 (record + (field "f0" $t0) + (field "f1" $t0) + (field "f2" $t0) + (field "f3" $t0) + (field "f4" $t0) + (field "f5" $t0) + (field "f6" $t0) + (field "f7" $t0) + (field "f8" $t0) + (field "f9" $t0) + )) + + ;; size(t2) == 100 + (type $t2 (record + (field "f0" $t1) + (field "f1" $t1) + (field "f2" $t1) + (field "f3" $t1) + (field "f4" $t1) + (field "f5" $t1) + (field "f6" $t1) + (field "f7" $t1) + (field "f8" $t1) + (field "f9" $t1) + )) + + ;; size(t3) == 1000 + (type $t3 (record + (field "f0" $t2) + (field "f1" $t2) + (field "f2" $t2) + (field "f3" $t2) + (field "f4" $t2) + (field "f5" $t2) + (field "f6" $t2) + (field "f7" $t2) + (field "f8" $t2) + (field "f9" $t2) + )) + + ;; size(t4) == 10000 + (type $t4 (record + (field "f0" $t3) + (field "f1" $t3) + (field "f2" $t3) + (field "f3" $t3) + (field "f4" $t3) + (field "f5" $t3) + (field "f6" $t3) + (field "f7" $t3) + (field "f8" $t3) + (field "f9" $t3) + )) + + ;; size(t5) == 100000 + (type $t5 (record + (field "f0" $t4) + (field "f1" $t4) + (field "f2" $t4) + (field "f3" $t4) + (field "f4" $t4) + (field "f5" $t4) + (field "f6" $t4) + (field "f7" $t4) + (field "f8" $t4) + (field "f9" $t4) + )) + + (type $f (func + (param "a" $t5) + (param "b" $t5) + (param "c" $t5) + (param "d" $t5) + (param "e" $t5) + (param "f" $t5) + (param "g" $t5) + (param "h" $t5) + (param "i" $t5) + (param "j" $t5) + )) + ) + "effective type size exceeds the limit") + +(assert_malformed + (component quote + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + ) + "nesting too deep") diff --git a/src/test/resources/spec-tests/wasm-tools/virtualize.wast b/src/test/resources/spec-tests/wasm-tools/virtualize.wast new file mode 100644 index 0000000..d60b73b --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/virtualize.wast @@ -0,0 +1,119 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (core module $libc + (memory (export "mem") 0) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable + ) + ) + (core instance $libc (instantiate $libc)) + + (component $child + (import "wasi-file" (instance $wasi-file + (export "read" (func (param "count" u32) (result (list u8)))) + (export "write" (func (param "bytes" (list u8)) (result u32))) + )) + + (core instance $libc (instantiate $libc)) + + (core module $m + (import "wasi-file" "read" (func $read (param i32 i32))) + (func $play (export "play") + unreachable + ) + ) + + (core func $wasi_file_read + (canon lower (func $wasi-file "read") + (memory $libc "mem") + (realloc (func $libc "realloc")) + ) + ) + + (core instance $i (instantiate $m + (with "wasi-file" (instance + (export "read" (func $wasi_file_read)) + )) + )) + + (func (export "play") + (canon lift (core func $i "play")) + ) + ) + + (component $virtualize + (import "wasi-file" (instance $wasi-file + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) + )) + (export "read" (func $wasi-file "read")) + (export "write" (func $wasi-file "write")) + ) + + (component + (type $WasiFile (instance + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) + )) + (import "wasi-file" (instance $real-wasi (type $WasiFile))) + (import "virtualize" (component $VIRTUALIZE + (import "wasi-file" (instance (type $WasiFile))) + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) + )) + (import "child" (component $CHILD + (import "wasi-file" (instance (type $WasiFile))) + (export "play" (func)) + ) + ) + + (instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi-file" (instance $real-wasi)))) + (instance $child (instantiate $CHILD (with "wasi-file" (instance $virt-wasi)))) + + (export "work" (func $child "play")) + ) + + (component + (type $WasiFile (instance + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) + )) + (import "wasi-file" (instance $real-wasi (type $WasiFile))) + + (core instance $libc (instantiate $libc)) + + (core module $CHILD + (import "wasi-file" "read" (func $wasi-file (param i32 i32))) + (func $play (export "play") + unreachable + ) + ) + + (core module $VIRTUALIZE + (import "wasi-file" "read" (func (param i32 i32))) + (func (export "read") (param i32 i32) + unreachable + ) + (func (export "write") (param i32 i32 i32) + unreachable + ) + ) + + (core func $real-wasi-read + (canon lower (func $real-wasi "read") + (memory $libc "mem") + (realloc (func $libc "realloc")) + ) + ) + + (core instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi-file" (instance (export "read" (func $real-wasi-read)))))) + (core instance $child (instantiate $CHILD (with "wasi-file" (instance $virt-wasi)))) + (func (export "work") + (canon lift (core func $child "play") + (memory $libc "mem") + (realloc (func $libc "realloc")) + ) + ) + ) +) diff --git a/src/test/resources/spec-tests/wasm-tools/wrong-order.wast b/src/test/resources/spec-tests/wasm-tools/wrong-order.wast new file mode 100644 index 0000000..098fc41 --- /dev/null +++ b/src/test/resources/spec-tests/wasm-tools/wrong-order.wast @@ -0,0 +1,11 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_malformed + (module binary + "\00asm\01\00\00\00" + + "\01\01\00" ;; type section, 1 byte, 0 entries + "\0b\01\00" ;; data section, 1 byte, 0 entries + "\01\01\00" ;; type section, 1 byte, 0 entries + ) + "section out of order") diff --git a/src/test/resources/spec-tests/wasmtime/adapter.wast b/src/test/resources/spec-tests/wasmtime/adapter.wast new file mode 100644 index 0000000..8432d58 --- /dev/null +++ b/src/test/resources/spec-tests/wasmtime/adapter.wast @@ -0,0 +1,137 @@ +;;! multi_memory = true + +;; basic function lifting +(component + (core module $m + (func (export "")) + ) + (core instance $i (instantiate $m)) + + (func (export "thunk") + (canon lift (core func $i "")) + ) +) + +;; use an aliased type +(component $c + (core module $m + (func (export "")) + ) + (core instance $i (instantiate $m)) + + (type $to_alias (func)) + (alias outer $c $to_alias (type $alias)) + + (func (export "thunk") (type $alias) + (canon lift (core func $i "")) + ) +) + +;; test out some various canonical abi +(component $c + (core module $m + (func (export "") (param i32 i32)) + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "thunk") (param "a" string) + (canon lift + (core func $i "") + (memory $i "memory") + (realloc (func $i "realloc")) + ) + ) + + (func (export "thunk8") (param "a" string) + (canon lift + (core func $i "") + string-encoding=utf8 + (memory $i "memory") + (realloc (func $i "realloc")) + ) + ) + + (func (export "thunk16") (param "a" string) + (canon lift + (core func $i "") + string-encoding=utf16 + (memory $i "memory") + (realloc (func $i "realloc")) + ) + ) + + (func (export "thunklatin16") (param "a" string) + (canon lift + (core func $i "") + string-encoding=latin1+utf16 + (memory $i "memory") + (realloc (func $i "realloc")) + ) + ) +) + +;; lower something then immediately lift it +(component $c + (import "host-return-two" (func $f (result u32))) + + (core func $f_lower + (canon lower (func $f)) + ) + (func $f2 (result s32) + (canon lift (core func $f_lower)) + ) + (export "f" (func $f2)) +) + +;; valid, but odd +(component + (core module $m (func (export ""))) + (core instance $m (instantiate $m)) + + (func $f1 (canon lift (core func $m ""))) + (core func $f2 (canon lower (func $f1))) +) +(assert_trap + (component + (core module $m (func (export ""))) + (core instance $m (instantiate $m)) + + (func $f1 (canon lift (core func $m ""))) + (core func $f2 (canon lower (func $f1))) + + (core module $m2 + (import "" "" (func $f)) + (func $start + call $f) + (start $start) + ) + (core instance (instantiate $m2 + (with "" (instance (export "" (func $f2)))) + )) + ) + "cannot enter component instance") + +;; fiddling with 0-sized lists +(component $c + (core module $m + (func (export "x") (param i32 i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + i32.const -1) + (memory (export "memory") 0) + ) + (core instance $m (instantiate $m)) + (type $t' (result)) + (export $t "t" (type $t')) + (func $f (param "a" (list $t)) + (canon lift + (core func $m "x") + (realloc (func $m "realloc")) + (memory $m "memory") + ) + ) + (export "empty-list" (func $f)) +) +(assert_trap (invoke "empty-list" (list.const)) "realloc return: beyond end of memory") diff --git a/src/test/resources/spec-tests/wasmtime/aliasing.wast b/src/test/resources/spec-tests/wasmtime/aliasing.wast new file mode 100644 index 0000000..ad18f93 --- /dev/null +++ b/src/test/resources/spec-tests/wasmtime/aliasing.wast @@ -0,0 +1,29 @@ +(component + (component + (component + (component) + (instance (instantiate 0)) + (export "a" (instance 0)) + ) + (instance (instantiate 0)) + (export "a" (instance 0)) + ) + + (instance (instantiate 0)) ;; instance 0 + (alias export 0 "a" (instance)) ;; instance 1 + (export "a" (instance 1)) ;; instance 2 + (alias export 2 "a" (instance)) ;; instance 3 + (export "inner-a" (instance 3)) ;; instance 4 +) + +(component + (component + (core module) + (export "a" (core module 0)) + ) + + (instance (instantiate 0)) + (alias export 0 "a" (core module)) ;; module 0 + (export "a" (core module 0)) ;; module 1 + (core instance (instantiate 1)) +) diff --git a/src/test/resources/spec-tests/wasmtime/fused.wast b/src/test/resources/spec-tests/wasmtime/fused.wast new file mode 100644 index 0000000..87fe846 --- /dev/null +++ b/src/test/resources/spec-tests/wasmtime/fused.wast @@ -0,0 +1,1391 @@ +;;! multi_memory = true + +;; smoke test with no arguments and no results +(component + (component $a + (core module $m + (func (export "")) + ) + (core instance $m (instantiate $m)) + (func (export "foo") (canon lift (core func $m ""))) + ) + (instance $a (instantiate $a)) + + (component $c + (import "a" (instance $a + (export "foo" (func)) + )) + + (core func $foo (canon lower (func $a "foo"))) + (core module $m2 + (import "" "" (func)) + (start 0) + ) + (core instance $m2 (instantiate $m2 (with "" (instance (export "" (func $foo)))))) + ) + + (instance $c (instantiate $c (with "a" (instance $a)))) +) + +;; boolean parameters +(component + (component $a + (core module $m + (func (export "assert_true") (param i32) + local.get 0 + i32.const 1 + i32.eq + i32.eqz + if unreachable end + ) + (func (export "assert_false") (param i32) + local.get 0 + if unreachable end + ) + (func (export "ret-bool") (param i32) (result i32) + local.get 0 + ) + ) + (core instance $m (instantiate $m)) + (func (export "assert-true") (param "a" bool) (canon lift (core func $m "assert_true"))) + (func (export "assert-false") (param "a" bool) (canon lift (core func $m "assert_false"))) + (func (export "ret-bool") (param "a" u32) (result bool) (canon lift (core func $m "ret-bool"))) + ) + (instance $a (instantiate $a)) + + (component $c + (import "a" (instance $a + (export "assert-true" (func (param "a" bool))) + (export "assert-false" (func (param "a" bool))) + (export "ret-bool" (func (param "a" u32) (result bool))) + )) + + (core func $assert_true (canon lower (func $a "assert-true"))) + (core func $assert_false (canon lower (func $a "assert-false"))) + (core func $ret_bool (canon lower (func $a "ret-bool"))) + + (core module $m2 + (import "" "assert-true" (func $assert_true (param i32))) + (import "" "assert-false" (func $assert_false (param i32))) + (import "" "ret-bool" (func $ret_bool (param i32) (result i32))) + + (func $start + (call $assert_true (i32.const 1)) + (call $assert_true (i32.const 2)) + (call $assert_true (i32.const -1)) + (call $assert_false (i32.const 0)) + + (if (i32.ne (call $ret_bool (i32.const 1)) (i32.const 1)) + (then (unreachable))) + (if (i32.ne (call $ret_bool (i32.const 2)) (i32.const 1)) + (then (unreachable))) + (if (i32.ne (call $ret_bool (i32.const -1)) (i32.const 1)) + (then (unreachable))) + (if (i32.ne (call $ret_bool (i32.const 0)) (i32.const 0)) + (then (unreachable))) + ) + (start $start) + ) + (core instance $m2 (instantiate $m2 + (with "" (instance + (export "assert-true" (func $assert_true)) + (export "assert-false" (func $assert_false)) + (export "ret-bool" (func $ret_bool)) + )) + )) + ) + + (instance $c (instantiate $c (with "a" (instance $a)))) +) + +;; lots of parameters and results +(component + (component $a + (type $roundtrip (func + ;; 20 u32 params + (param "a1" u32) (param "a2" u32) (param "a3" u32) (param "a4" u32) (param "a5" u32) + (param "a6" u32) (param "a7" u32) (param "a8" u32) (param "a9" u32) (param "a10" u32) + (param "a11" u32) (param "a12" u32) (param "a13" u32) (param "a14" u32) (param "a15" u32) + (param "a16" u32) (param "a17" u32) (param "a18" u32) (param "a19" u32) (param "a20" u32) + + ;; 10 u32 results + (result (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) + )) + + (core module $m + (memory (export "memory") 1) + (func (export "roundtrip") (param $src i32) (result i32) + (local $dst i32) + (if (i32.ne (local.get $src) (i32.const 16)) + (then (unreachable))) + + (if (i32.ne (i32.load offset=0 (local.get $src)) (i32.const 1)) (then (unreachable))) + (if (i32.ne (i32.load offset=4 (local.get $src)) (i32.const 2)) (then (unreachable))) + (if (i32.ne (i32.load offset=8 (local.get $src)) (i32.const 3)) (then (unreachable))) + (if (i32.ne (i32.load offset=12 (local.get $src)) (i32.const 4)) (then (unreachable))) + (if (i32.ne (i32.load offset=16 (local.get $src)) (i32.const 5)) (then (unreachable))) + (if (i32.ne (i32.load offset=20 (local.get $src)) (i32.const 6)) (then (unreachable))) + (if (i32.ne (i32.load offset=24 (local.get $src)) (i32.const 7)) (then (unreachable))) + (if (i32.ne (i32.load offset=28 (local.get $src)) (i32.const 8)) (then (unreachable))) + (if (i32.ne (i32.load offset=32 (local.get $src)) (i32.const 9)) (then (unreachable))) + (if (i32.ne (i32.load offset=36 (local.get $src)) (i32.const 10)) (then (unreachable))) + (if (i32.ne (i32.load offset=40 (local.get $src)) (i32.const 11)) (then (unreachable))) + (if (i32.ne (i32.load offset=44 (local.get $src)) (i32.const 12)) (then (unreachable))) + (if (i32.ne (i32.load offset=48 (local.get $src)) (i32.const 13)) (then (unreachable))) + (if (i32.ne (i32.load offset=52 (local.get $src)) (i32.const 14)) (then (unreachable))) + (if (i32.ne (i32.load offset=56 (local.get $src)) (i32.const 15)) (then (unreachable))) + (if (i32.ne (i32.load offset=60 (local.get $src)) (i32.const 16)) (then (unreachable))) + (if (i32.ne (i32.load offset=64 (local.get $src)) (i32.const 17)) (then (unreachable))) + (if (i32.ne (i32.load offset=68 (local.get $src)) (i32.const 18)) (then (unreachable))) + (if (i32.ne (i32.load offset=72 (local.get $src)) (i32.const 19)) (then (unreachable))) + (if (i32.ne (i32.load offset=76 (local.get $src)) (i32.const 20)) (then (unreachable))) + + (local.set $dst (i32.const 500)) + + (i32.store offset=0 (local.get $dst) (i32.const 21)) + (i32.store offset=4 (local.get $dst) (i32.const 22)) + (i32.store offset=8 (local.get $dst) (i32.const 23)) + (i32.store offset=12 (local.get $dst) (i32.const 24)) + (i32.store offset=16 (local.get $dst) (i32.const 25)) + (i32.store offset=20 (local.get $dst) (i32.const 26)) + (i32.store offset=24 (local.get $dst) (i32.const 27)) + (i32.store offset=28 (local.get $dst) (i32.const 28)) + (i32.store offset=32 (local.get $dst) (i32.const 29)) + (i32.store offset=36 (local.get $dst) (i32.const 30)) + + local.get $dst + ) + + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + i32.const 16) + ) + (core instance $m (instantiate $m)) + + (func (export "roundtrip") (type $roundtrip) + (canon lift (core func $m "roundtrip") (memory $m "memory") + (realloc (func $m "realloc"))) + ) + ) + (instance $a (instantiate $a)) + + (component $c + (type $roundtrip (func + ;; 20 u32 params + (param "a1" u32) (param "a2" u32) (param "a3" u32) (param "a4" u32) (param "a5" u32) + (param "a6" u32) (param "a7" u32) (param "a8" u32) (param "a9" u32) (param "a10" u32) + (param "a11" u32) (param "a12" u32) (param "a13" u32) (param "a14" u32) (param "a15" u32) + (param "a16" u32) (param "a17" u32) (param "a18" u32) (param "a19" u32) (param "a20" u32) + + ;; 10 u32 results + (result (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) + )) + + (import "a" (instance $a + (export "roundtrip" (func (type $roundtrip))) + )) + + (core module $libc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) + ) + (core instance $libc (instantiate $libc)) + (core func $roundtrip + (canon lower (func $a "roundtrip") + (memory $libc "memory") + (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary + ) + ) + + (core module $m2 + (import "libc" "memory" (memory 1)) + (import "" "roundtrip" (func $roundtrip (param i32 i32))) + + (func $start + (local $addr i32) + (local $retaddr i32) + + (local.set $addr (i32.const 100)) + (call $store_many (i32.const 20) (local.get $addr)) + + (local.set $retaddr (i32.const 200)) + (call $roundtrip (local.get $addr) (local.get $retaddr)) + + (if (i32.ne (i32.load offset=0 (local.get $retaddr)) (i32.const 21)) (then (unreachable))) + (if (i32.ne (i32.load offset=4 (local.get $retaddr)) (i32.const 22)) (then (unreachable))) + (if (i32.ne (i32.load offset=8 (local.get $retaddr)) (i32.const 23)) (then (unreachable))) + (if (i32.ne (i32.load offset=12 (local.get $retaddr)) (i32.const 24)) (then (unreachable))) + (if (i32.ne (i32.load offset=16 (local.get $retaddr)) (i32.const 25)) (then (unreachable))) + (if (i32.ne (i32.load offset=20 (local.get $retaddr)) (i32.const 26)) (then (unreachable))) + (if (i32.ne (i32.load offset=24 (local.get $retaddr)) (i32.const 27)) (then (unreachable))) + (if (i32.ne (i32.load offset=28 (local.get $retaddr)) (i32.const 28)) (then (unreachable))) + (if (i32.ne (i32.load offset=32 (local.get $retaddr)) (i32.const 29)) (then (unreachable))) + (if (i32.ne (i32.load offset=36 (local.get $retaddr)) (i32.const 30)) (then (unreachable))) + ) + + (func $store_many (param $amt i32) (param $addr i32) + (local $c i32) + (loop $loop + (local.set $c (i32.add (local.get $c) (i32.const 1))) + (i32.store (local.get $addr) (local.get $c)) + (local.set $addr (i32.add (local.get $addr) (i32.const 4))) + + (if (i32.ne (local.get $amt) (local.get $c)) (then (br $loop))) + ) + ) + (start $start) + ) + (core instance $m2 (instantiate $m2 + (with "libc" (instance $libc)) + (with "" (instance (export "roundtrip" (func $roundtrip)))) + )) + ) + + (instance $c (instantiate $c (with "a" (instance $a)))) +) + +;; this will require multiple adapter modules to get generated +(component + (component $c0 + (core module $root (func (export "") (result i32) + i32.const 0 + )) + (core instance $root (instantiate $root)) + (func (export "thunk") (result u32) (canon lift (core func $root ""))) + ) + (instance $c0 (instantiate $c0)) + + (component $c + (import "thunk" (instance $thunk + (export "thunk" (func (result u32))) + )) + (core func $import (canon lower (func $thunk "thunk"))) + (core module $reexport + (import "" "" (func $thunk (result i32))) + (func (export "thunk") (result i32) + call $thunk + i32.const 1 + i32.add) + ) + (core instance $reexport (instantiate $reexport + (with "" (instance + (export "" (func $import)) + )) + )) + (func $export (export "thunk") (result u32) + (canon lift (core func $reexport "thunk")) + ) + ) + + (instance $c1 (instantiate $c (with "thunk" (instance $c0)))) + (instance $c2 (instantiate $c (with "thunk" (instance $c1)))) + (instance $c3 (instantiate $c (with "thunk" (instance $c2)))) + (instance $c4 (instantiate $c (with "thunk" (instance $c3)))) + (instance $c5 (instantiate $c (with "thunk" (instance $c4)))) + (instance $c6 (instantiate $c (with "thunk" (instance $c5)))) + + (component $verify + (import "thunk" (instance $thunk + (export "thunk" (func (result u32))) + )) + (core func $thunk (canon lower (func $thunk "thunk"))) + (core module $verify + (import "" "" (func $thunk (result i32))) + + (func $start + call $thunk + i32.const 6 + i32.ne + if unreachable end + ) + (start $start) + ) + (core instance (instantiate $verify + (with "" (instance + (export "" (func $thunk)) + )) + )) + ) + (instance (instantiate $verify (with "thunk" (instance $c6)))) +) + +;; Fancy case of an adapter using an adapter. Note that this is silly and +;; doesn't actually make any sense at runtime, we just shouldn't panic on a +;; valid component. +(component + (type $tuple20 (tuple + u32 u32 u32 u32 u32 + u32 u32 u32 u32 u32 + u32 u32 u32 u32 u32 + u32 u32 u32 u32 u32)) + + (component $realloc + (core module $realloc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable) + ) + (core instance $realloc (instantiate $realloc)) + (func $realloc (param "a" (tuple u32 u32 u32 u32)) (result u32) + (canon lift (core func $realloc "realloc")) + ) + (export "realloc" (func $realloc)) + ) + (instance $realloc (instantiate $realloc)) + (core func $realloc (canon lower (func $realloc "realloc"))) + + (core module $m + (memory (export "memory") 1) + (func (export "foo") (param i32)) + ) + (core instance $m (instantiate $m)) + (func $foo (param "a" $tuple20) + (canon lift + (core func $m "foo") + (memory $m "memory") + (realloc (func $realloc)) + ) + ) + + (component $c + (import "foo" (func $foo (param "a" $tuple20))) + + (core module $libc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable) + ) + (core instance $libc (instantiate $libc)) + (core func $foo + (canon lower (func $foo) + (memory $libc "memory") + (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary + ) + ) + (core module $something + (import "" "foo" (func (param i32))) + ) + (core instance (instantiate $something + (with "" (instance + (export "foo" (func $foo)) + )) + )) + ) + (instance (instantiate $c + (with "foo" (func $foo)) + )) +) + +;; Don't panic or otherwise create extraneous adapter modules when the same +;; adapter is used twice for a module's argument. +(component + (core module $m + (func (export "foo") (param)) + ) + (core instance $m (instantiate $m)) + (func $foo (canon lift (core func $m "foo"))) + + (component $c + (import "foo" (func $foo)) + (core func $foo (canon lower (func $foo))) + + (core module $something + (import "" "a" (func)) + (import "" "b" (func)) + ) + (core instance (instantiate $something + (with "" (instance + (export "a" (func $foo)) + (export "b" (func $foo)) + )) + )) + ) + (instance (instantiate $c (with "foo" (func $foo)))) +) + +;; post-return should get invoked by the generated adapter, if specified +(component + (component $a + (core module $m + (global $post_called (mut i32) (i32.const 0)) + (func (export "foo") + ;; assert `foo-post` not called yet + global.get $post_called + i32.const 1 + i32.eq + if unreachable end + ) + (func (export "foo-post") + ;; assert `foo-post` not called before + global.get $post_called + i32.const 1 + i32.eq + if unreachable end + ;; ... then flag as called + i32.const 1 + global.set $post_called + ) + (func (export "assert-post") + global.get $post_called + i32.const 1 + i32.ne + if unreachable end + ) + ) + (core instance $m (instantiate $m)) + (func (export "foo") (canon lift (core func $m "foo") (post-return (func $m "foo-post")))) + (func (export "assert-post") (canon lift (core func $m "assert-post"))) + ) + (instance $a (instantiate $a)) + + (component $c + (import "a" (instance $a + (export "foo" (func)) + (export "assert-post" (func)) + )) + (core func $foo (canon lower (func $a "foo"))) + (core func $assert_post (canon lower (func $a "assert-post"))) + + (core module $something + (import "" "foo" (func $foo)) + (import "" "assert-post" (func $assert_post)) + + (func $start + call $foo + call $assert_post + ) + (start $start) + ) + (core instance (instantiate $something + (with "" (instance + (export "foo" (func $foo)) + (export "assert-post" (func $assert_post)) + )) + )) + ) + (instance (instantiate $c (with "a" (instance $a)))) +) + +;; post-return passes the results +(component + (component $a + (core module $m + (func (export "foo") (result i32) i32.const 100) + (func (export "foo-post") (param i32) + (if (i32.ne (local.get 0) (i32.const 100)) (then (unreachable)))) + ) + (core instance $m (instantiate $m)) + (func (export "foo") (result u32) + (canon lift (core func $m "foo") (post-return (func $m "foo-post")))) + ) + (instance $a (instantiate $a)) + + (component $c + (import "a" (instance $a + (export "foo" (func (result u32))) + )) + (core func $foo (canon lower (func $a "foo"))) + + (core module $something + (import "" "foo" (func $foo (result i32))) + (func $start + (if (i32.ne (call $foo) (i32.const 100)) (then (unreachable)))) + (start $start) + ) + (core instance (instantiate $something + (with "" (instance + (export "foo" (func $foo)) + )) + )) + ) + (instance (instantiate $c (with "a" (instance $a)))) +) + +;; callee retptr misaligned +(assert_trap + (component + (component $c1 + (core module $m + (memory (export "memory") 1) + (func (export "r") (result i32) i32.const 1) + ) + (core instance $m (instantiate $m)) + (func (export "r") (result (tuple u32 u32)) + (canon lift (core func $m "r") (memory $m "memory")) + ) + ) + (component $c2 + (import "r" (func $r (result (tuple u32 u32)))) + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func $r (canon lower (func $r) (memory $libc "memory"))) + + (core module $m + (import "" "r" (func $r (param i32))) + (func $start + i32.const 4 + call $r + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) + ) + "unaligned pointer") + +;; caller retptr misaligned +(assert_trap + (component + (component $c1 + (core module $m + (memory (export "memory") 1) + (func (export "r") (result i32) i32.const 0) + ) + (core instance $m (instantiate $m)) + (func (export "r") (result (tuple u32 u32)) + (canon lift (core func $m "r") (memory $m "memory")) + ) + ) + (component $c2 + (import "r" (func $r (result (tuple u32 u32)))) + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func $r (canon lower (func $r) (memory $libc "memory"))) + + (core module $m + (import "" "r" (func $r (param i32))) + (func $start + i32.const 1 + call $r + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) + ) + "unaligned pointer") + +;; callee argptr misaligned +(assert_trap + (component + (type $big (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) + + (component $c1 + (core module $m + (memory (export "memory") 1) + (func (export "r") (param i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + i32.const 1) + ) + (core instance $m (instantiate $m)) + (func (export "r") (param "a" $big) + (canon lift (core func $m "r") (memory $m "memory") (realloc (func $m "realloc"))) + ) + ) + (component $c2 + (import "r" (func $r (param "a" $big))) + (core module $libc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) + ) + (core instance $libc (instantiate $libc)) + (core func $r + (canon lower (func $r) + (memory $libc "memory") + (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary + ) + ) + + (core module $m + (import "" "r" (func $r (param i32))) + (func $start + i32.const 4 + call $r + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) + ) + "unaligned pointer") + +;; caller argptr misaligned +(assert_trap + (component + (type $big (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) + + (component $c1 + (core module $m + (memory (export "memory") 1) + (func (export "r") (param i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + i32.const 4) + ) + (core instance $m (instantiate $m)) + (func (export "r") (param "a" $big) + (canon lift (core func $m "r") (memory $m "memory") (realloc (func $m "realloc"))) + ) + ) + (component $c2 + (import "r" (func $r (param "a" $big))) + (core module $libc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) + ) + (core instance $libc (instantiate $libc)) + (core func $r + (canon lower (func $r) + (memory $libc "memory") + (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary + ) + ) + + + (core module $m + (import "" "r" (func $r (param i32))) + (func $start + i32.const 1 + call $r + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) + ) + "unaligned pointer") + +;; simple variant translation +(component + (component $c1 + (type $a' (variant (case "x"))) + (export $a "a" (type $a')) + (type $b' (variant (case "y"))) + (export $b "b" (type $b')) + + (core module $m + (func (export "r") (param i32) (result i32) + (if (i32.ne (local.get 0) (i32.const 0)) (then (unreachable))) + i32.const 0 + ) + ) + (core instance $m (instantiate $m)) + (func (export "r") (param "a" $a) (result $b) (canon lift (core func $m "r"))) + ) + (component $c2 + (type $a' (variant (case "x"))) + (import "a" (type $a (eq $a'))) + (type $b' (variant (case "y"))) + (import "b" (type $b (eq $b'))) + + (import "r" (func $r (param "a" $a) (result $b))) + (core func $r (canon lower (func $r))) + + (core module $m + (import "" "r" (func $r (param i32) (result i32))) + (func $start + i32.const 0 + call $r + i32.const 0 + i32.ne + if unreachable end + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 + (with "a" (type $c1 "a")) + (with "b" (type $c1 "b")) + (with "r" (func $c1 "r")) + )) +) + +;; invalid variant discriminant in a parameter +(assert_trap + (component + (component $c1 + (type $a' (variant (case "x"))) + (export $a "a" (type $a')) + (core module $m + (func (export "r") (param i32)) + ) + (core instance $m (instantiate $m)) + (func (export "r") (param "a" $a) (canon lift (core func $m "r"))) + ) + (component $c2 + (type $a' (variant (case "x"))) + (import "a" (type $a (eq $a'))) + (import "r" (func $r (param "a" $a))) + (core func $r (canon lower (func $r))) + + (core module $m + (import "" "r" (func $r (param i32))) + (func $start + i32.const 1 + call $r + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 + (with "a" (type $c1 "a")) + (with "r" (func $c1 "r")) + )) + ) + "invalid variant discriminant") + +;; invalid variant discriminant in a result +(assert_trap + (component + (component $c1 + (type $a' (variant (case "x"))) + (export $a "a" (type $a')) + (core module $m + (func (export "r") (result i32) i32.const 1) + ) + (core instance $m (instantiate $m)) + (func (export "r") (result $a) (canon lift (core func $m "r"))) + ) + (component $c2 + (type $a' (variant (case "x"))) + (import "a" (type $a (eq $a'))) + (import "r" (func $r (result $a))) + (core func $r (canon lower (func $r))) + + (core module $m + (import "" "r" (func $r (result i32))) + (func $start call $r drop) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 + (with "a" (type $c1 "a")) + (with "r" (func $c1 "r")) + )) + ) + "invalid variant discriminant") + + +;; extra bits are chopped off +(component + (component $c1 + (core module $m + (func (export "u") (param i32) + (if (i32.ne (local.get 0) (i32.const 0)) (then (unreachable))) + ) + (func (export "s") (param i32) + (if (i32.ne (local.get 0) (i32.const -1)) (then (unreachable))) + ) + ) + (core instance $m (instantiate $m)) + (func (export "u8") (param "a" u8) (canon lift (core func $m "u"))) + (func (export "u16") (param "a" u16) (canon lift (core func $m "u"))) + (func (export "s8") (param "a" s8) (canon lift (core func $m "s"))) + (func (export "s16") (param "a" s16) (canon lift (core func $m "s"))) + ) + (component $c2 + (import "a" (instance $i + (export "u8" (func (param "a" u8))) + (export "s8" (func (param "a" s8))) + (export "u16" (func (param "a" u16))) + (export "s16" (func (param "a" s16))) + )) + + (core func $u8 (canon lower (func $i "u8"))) + (core func $s8 (canon lower (func $i "s8"))) + (core func $u16 (canon lower (func $i "u16"))) + (core func $s16 (canon lower (func $i "s16"))) + + (core module $m + (import "" "u8" (func $u8 (param i32))) + (import "" "s8" (func $s8 (param i32))) + (import "" "u16" (func $u16 (param i32))) + (import "" "s16" (func $s16 (param i32))) + + (func $start + (call $u8 (i32.const 0)) + (call $u8 (i32.const 0xff00)) + (call $s8 (i32.const -1)) + (call $s8 (i32.const 0xff)) + (call $s8 (i32.const 0xffff)) + + (call $u16 (i32.const 0)) + (call $u16 (i32.const 0xff0000)) + (call $s16 (i32.const -1)) + (call $s16 (i32.const 0xffff)) + (call $s16 (i32.const 0xffffff)) + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "u8" (func $u8)) + (export "s8" (func $s8)) + (export "u16" (func $u16)) + (export "s16" (func $s16)) + )) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) +) + +;; translation of locals between different types +(component + (component $c1 + (type $a' (variant (case "a" u8) (case "b" float32))) + (type $b' (variant (case "a" u16) (case "b" s64))) + (type $c' (variant (case "a" u64) (case "b" float64))) + (type $d' (variant (case "a" float32) (case "b" float64))) + (type $e' (variant (case "a" float32) (case "b" s64))) + (export $a "t-a" (type $a')) + (export $b "t-b" (type $b')) + (export $c "t-c" (type $c')) + (export $d "t-d" (type $d')) + (export $e "t-e" (type $e')) + + (type $func_a (func (param "x" bool) (param "a" $a))) + (type $func_b (func (param "x" bool) (param "b" $b))) + (type $func_c (func (param "x" bool) (param "c" $c))) + (type $func_d (func (param "x" bool) (param "d" $d))) + (type $func_e (func (param "x" bool) (param "e" $d))) + + (core module $m + (func (export "a") (param i32 i32 i32) + (i32.eqz (local.get 0)) + if + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (i32.ne (local.get 2) (i32.const 2)) (then (unreachable))) + else + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (f32.ne (f32.reinterpret_i32 (local.get 2)) (f32.const 3)) (then (unreachable))) + end + ) + (func (export "b") (param i32 i32 i64) + (i32.eqz (local.get 0)) + if + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (i64.ne (local.get 2) (i64.const 4)) (then (unreachable))) + else + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (i64.ne (local.get 2) (i64.const 5)) (then (unreachable))) + end + ) + (func (export "c") (param i32 i32 i64) + (i32.eqz (local.get 0)) + if + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (i64.ne (local.get 2) (i64.const 6)) (then (unreachable))) + else + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (f64.ne (f64.reinterpret_i64 (local.get 2)) (f64.const 7)) (then (unreachable))) + end + ) + (func (export "d") (param i32 i32 i64) + (i32.eqz (local.get 0)) + if + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (f32.ne (f32.reinterpret_i32 (i32.wrap_i64 (local.get 2))) (f32.const 8)) (then (unreachable))) + else + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (f64.ne (f64.reinterpret_i64 (local.get 2)) (f64.const 9)) (then (unreachable))) + end + ) + (func (export "e") (param i32 i32 i64) + (i32.eqz (local.get 0)) + if + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (f32.ne (f32.reinterpret_i32 (i32.wrap_i64 (local.get 2))) (f32.const 10)) (then (unreachable))) + else + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (i64.ne (local.get 2) (i64.const 11)) (then (unreachable))) + end + ) + ) + (core instance $m (instantiate $m)) + (func (export "a") (type $func_a) (canon lift (core func $m "a"))) + (func (export "b") (type $func_b) (canon lift (core func $m "b"))) + (func (export "c") (type $func_c) (canon lift (core func $m "c"))) + (func (export "d") (type $func_d) (canon lift (core func $m "d"))) + (func (export "e") (type $func_e) (canon lift (core func $m "e"))) + ) + (component $c2 + (import "a" (instance $i + (type $a' (variant (case "a" u8) (case "b" float32))) + (type $b' (variant (case "a" u16) (case "b" s64))) + (type $c' (variant (case "a" u64) (case "b" float64))) + (type $d' (variant (case "a" float32) (case "b" float64))) + (type $e' (variant (case "a" float32) (case "b" s64))) + (export "t-a" (type $a (eq $a'))) + (export "t-b" (type $b (eq $b'))) + (export "t-c" (type $c (eq $c'))) + (export "t-d" (type $d (eq $d'))) + (export "t-e" (type $e (eq $e'))) + (type $func_a (func (param "x" bool) (param "a" $a))) + (type $func_b (func (param "x" bool) (param "b" $b))) + (type $func_c (func (param "x" bool) (param "c" $c))) + (type $func_d (func (param "x" bool) (param "d" $d))) + (type $func_e (func (param "x" bool) (param "e" $d))) + + (export "a" (func (type $func_a))) + (export "b" (func (type $func_b))) + (export "c" (func (type $func_c))) + (export "d" (func (type $func_d))) + (export "e" (func (type $func_e))) + )) + + (core func $a (canon lower (func $i "a"))) + (core func $b (canon lower (func $i "b"))) + (core func $c (canon lower (func $i "c"))) + (core func $d (canon lower (func $i "d"))) + (core func $e (canon lower (func $i "e"))) + + (core module $m + (import "" "a" (func $a (param i32 i32 i32))) + (import "" "b" (func $b (param i32 i32 i64))) + (import "" "c" (func $c (param i32 i32 i64))) + (import "" "d" (func $d (param i32 i32 i64))) + (import "" "e" (func $e (param i32 i32 i64))) + + (func $start + ;; upper bits should get masked + (call $a (i32.const 0) (i32.const 0) (i32.const 0xff_02)) + (call $a (i32.const 1) (i32.const 1) (i32.reinterpret_f32 (f32.const 3))) + + ;; upper bits should get masked + (call $b (i32.const 0) (i32.const 0) (i64.const 0xff_00_04)) + (call $b (i32.const 1) (i32.const 1) (i64.const 5)) + + (call $c (i32.const 0) (i32.const 0) (i64.const 6)) + (call $c (i32.const 1) (i32.const 1) (i64.reinterpret_f64 (f64.const 7))) + + (call $d (i32.const 0) (i32.const 0) (i64.extend_i32_u (i32.reinterpret_f32 (f32.const 8)))) + (call $d (i32.const 1) (i32.const 1) (i64.reinterpret_f64 (f64.const 9))) + + (call $e (i32.const 0) (i32.const 0) (i64.extend_i32_u (i32.reinterpret_f32 (f32.const 10)))) + (call $e (i32.const 1) (i32.const 1) (i64.const 11)) + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "a" (func $a)) + (export "b" (func $b)) + (export "c" (func $c)) + (export "d" (func $d)) + (export "e" (func $e)) + )) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) +) + +;; different size variants +(component + (component $c1 + (type $a' (variant + (case "a") + (case "b" float32) + (case "c" (tuple float32 u32)) + (case "d" (tuple float32 u64 u8)) + )) + (export $a "t-a" (type $a')) + + (core module $m + (func (export "a") (param i32 i32 f32 i64 i32) + (if (i32.eq (local.get 0) (i32.const 0)) + (then (block + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (f32.ne (local.get 2) (f32.const 0)) (then (unreachable))) + (if (i64.ne (local.get 3) (i64.const 0)) (then (unreachable))) + (if (i32.ne (local.get 4) (i32.const 0)) (then (unreachable))) + )) + ) + (if (i32.eq (local.get 0) (i32.const 1)) + (then (block + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (f32.ne (local.get 2) (f32.const 1)) (then (unreachable))) + (if (i64.ne (local.get 3) (i64.const 0)) (then (unreachable))) + (if (i32.ne (local.get 4) (i32.const 0)) (then (unreachable))) + )) + ) + (if (i32.eq (local.get 0) (i32.const 2)) + (then (block + (if (i32.ne (local.get 1) (i32.const 2)) (then (unreachable))) + (if (f32.ne (local.get 2) (f32.const 2)) (then (unreachable))) + (if (i64.ne (local.get 3) (i64.const 2)) (then (unreachable))) + (if (i32.ne (local.get 4) (i32.const 0)) (then (unreachable))) + )) + ) + (if (i32.eq (local.get 0) (i32.const 3)) + (then (block + (if (i32.ne (local.get 1) (i32.const 3)) (then (unreachable))) + (if (f32.ne (local.get 2) (f32.const 3)) (then (unreachable))) + (if (i64.ne (local.get 3) (i64.const 3)) (then (unreachable))) + (if (i32.ne (local.get 4) (i32.const 3)) (then (unreachable))) + )) + ) + (if (i32.gt_u (local.get 0) (i32.const 3)) + (then (unreachable))) + ) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "x" u8) (param "a" $a) (canon lift (core func $m "a"))) + ) + (component $c2 + (import "a" (instance $i + (type $a' (variant + (case "a") + (case "b" float32) + (case "c" (tuple float32 u32)) + (case "d" (tuple float32 u64 u8)) + )) + (export "t-a" (type $a (eq $a'))) + (export "a" (func (param "x" u8) (param "a" $a))) + )) + + (core func $a (canon lower (func $i "a"))) + + (core module $m + (import "" "a" (func $a (param i32 i32 f32 i64 i32))) + + (func $start + ;; variant a + (call $a + (i32.const 0) + (i32.const 0) + (f32.const 0) + (i64.const 0) + (i32.const 0)) + ;; variant b + (call $a + (i32.const 1) + (i32.const 1) + (f32.const 1) + (i64.const 0) + (i32.const 0)) + ;; variant c + (call $a + (i32.const 2) + (i32.const 2) + (f32.const 2) + (i64.const 2) + (i32.const 0)) + ;; variant d + (call $a + (i32.const 3) + (i32.const 3) + (f32.const 3) + (i64.const 3) + (i32.const 3)) + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "a" (func $a)) + )) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) +) + +;; roundtrip some valid chars +(component + (component $c1 + (core module $m + (func (export "a") (param i32) (result i32) local.get 0) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" char) (result char) (canon lift (core func $m "a"))) + ) + (component $c2 + (import "a" (instance $i + (export "a" (func (param "a" char) (result char))) + )) + + (core func $a (canon lower (func $i "a"))) + + (core module $m + (import "" "a" (func $a (param i32) (result i32))) + + (func $start + (call $roundtrip (i32.const 0)) + (call $roundtrip (i32.const 0xab)) + (call $roundtrip (i32.const 0xd7ff)) + (call $roundtrip (i32.const 0xe000)) + (call $roundtrip (i32.const 0x10ffff)) + ) + (func $roundtrip (export "roundtrip") (param i32) + local.get 0 + call $a + local.get 0 + i32.ne + if unreachable end + ) + (start $start) + ) + (core instance $m (instantiate $m + (with "" (instance + (export "a" (func $a)) + )) + )) + + (func (export "roundtrip") (param "a" char) (canon lift (core func $m "roundtrip"))) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) + + (export "roundtrip" (func $c2 "roundtrip")) +) + +(assert_return (invoke "roundtrip" (char.const "x"))) +(assert_return (invoke "roundtrip" (char.const "⛳"))) +(assert_return (invoke "roundtrip" (char.const "🍰"))) + +;; invalid chars +(assert_trap + (component + (component $c1 + (core module $m (func (export "a") (param i32))) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" char) (canon lift (core func $m "a"))) + ) + (component $c2 + (import "a" (instance $i (export "a" (func (param "a" char))))) + (core func $a (canon lower (func $i "a"))) + (core module $m + (import "" "a" (func $a (param i32))) + (func $start (call $a (i32.const 0xd800))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "a" (func $a)))))) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) + ) + "invalid `char` bit pattern") +(assert_trap + (component + (component $c1 + (core module $m (func (export "a") (param i32))) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" char) (canon lift (core func $m "a"))) + ) + (component $c2 + (import "a" (instance $i (export "a" (func (param "a" char))))) + (core func $a (canon lower (func $i "a"))) + (core module $m + (import "" "a" (func $a (param i32))) + (func $start (call $a (i32.const 0xdfff))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "a" (func $a)))))) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) + ) + "invalid `char` bit pattern") +(assert_trap + (component + (component $c1 + (core module $m (func (export "a") (param i32))) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" char) (canon lift (core func $m "a"))) + ) + (component $c2 + (import "a" (instance $i (export "a" (func (param "a" char))))) + (core func $a (canon lower (func $i "a"))) + (core module $m + (import "" "a" (func $a (param i32))) + (func $start (call $a (i32.const 0x110000))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "a" (func $a)))))) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) + ) + "invalid `char` bit pattern") + +;; test that flags get their upper bits all masked off +(component + (type $f1' (flags "f1")) + (type $f8' (flags "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8")) + (type $f9' (flags "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" "f9")) + (type $f16' (flags + "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" + "g1" "g2" "g3" "g4" "g5" "g6" "g7" "g8" + )) + (type $f17' (flags + "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" + "g1" "g2" "g3" "g4" "g5" "g6" "g7" "g8" + "g9" + )) + (type $f32' (flags + "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" + "g1" "g2" "g3" "g4" "g5" "g6" "g7" "g8" + "h1" "h2" "h3" "h4" "h5" "h6" "h7" "h8" + "i1" "i2" "i3" "i4" "i5" "i6" "i7" "i8" + )) + + (component $c1 + (export $f1 "t-f1" (type $f1')) + (export $f8 "t-f8" (type $f8')) + (export $f9 "t-f9" (type $f9')) + (export $f16 "t-f16" (type $f16')) + (export $f17 "t-f17" (type $f17')) + (export $f32 "t-f32" (type $f32')) + (core module $m + (func (export "f1") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x1)) (then (unreachable))) + ) + (func (export "f8") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x11)) (then (unreachable))) + ) + (func (export "f9") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x111)) (then (unreachable))) + ) + (func (export "f16") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x1111)) (then (unreachable))) + ) + (func (export "f17") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x11111)) (then (unreachable))) + ) + (func (export "f32") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x11111111)) (then (unreachable))) + ) + ) + (core instance $m (instantiate $m)) + (func (export "f1") (param "a" $f1) (canon lift (core func $m "f1"))) + (func (export "f8") (param "a" $f8) (canon lift (core func $m "f8"))) + (func (export "f9") (param "a" $f9) (canon lift (core func $m "f9"))) + (func (export "f16") (param "a" $f16) (canon lift (core func $m "f16"))) + (func (export "f17") (param "a" $f17) (canon lift (core func $m "f17"))) + (func (export "f32") (param "a" $f32) (canon lift (core func $m "f32"))) + ) + (instance $c1 (instantiate $c1)) + + (component $c2 + (import "a" (instance $i + (export "t-f1" (type $f1 (eq $f1'))) + (export "t-f8" (type $f8 (eq $f8'))) + (export "t-f9" (type $f9 (eq $f9'))) + (export "t-f16" (type $f16 (eq $f16'))) + (export "t-f17" (type $f17 (eq $f17'))) + (export "t-f32" (type $f32 (eq $f32'))) + (export "f1" (func (param "a" $f1))) + (export "f8" (func (param "a" $f8))) + (export "f9" (func (param "a" $f9))) + (export "f16" (func (param "a" $f16))) + (export "f17" (func (param "a" $f17))) + (export "f32" (func (param "a" $f32))) + )) + (core func $f1 (canon lower (func $i "f1"))) + (core func $f8 (canon lower (func $i "f8"))) + (core func $f9 (canon lower (func $i "f9"))) + (core func $f16 (canon lower (func $i "f16"))) + (core func $f17 (canon lower (func $i "f17"))) + (core func $f32 (canon lower (func $i "f32"))) + + (core module $m + (import "" "f1" (func $f1 (param i32))) + (import "" "f8" (func $f8 (param i32))) + (import "" "f9" (func $f9 (param i32))) + (import "" "f16" (func $f16 (param i32))) + (import "" "f17" (func $f17 (param i32))) + (import "" "f32" (func $f32 (param i32))) + + (func $start + (call $f1 (i32.const 0xffffff01)) + (call $f8 (i32.const 0xffffff11)) + (call $f9 (i32.const 0xffffff11)) + (call $f16 (i32.const 0xffff1111)) + (call $f17 (i32.const 0xffff1111)) + (call $f32 (i32.const 0x11111111)) + ) + + (start $start) + ) + (core instance $m (instantiate $m + (with "" (instance + (export "f1" (func $f1)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f16" (func $f16)) + (export "f17" (func $f17)) + (export "f32" (func $f32)) + )) + )) + ) + (instance (instantiate $c2 (with "a" (instance $c1)))) +) + +;; Adapters are used slightly out-of-order here to stress the internals of +;; dependencies between adapters. +(component + (core module $m + (func (export "execute")) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) + (memory (export "memory") 1) + ) + + (component $root + (core instance $m (instantiate $m)) + (func (export "execute") + (canon lift (core func $m "execute")) + ) + ) + (component $c + (import "backend" (instance $i + (export "execute" (func)) + )) + (core module $shim2 (import "" "0" (func))) + (core instance $m (instantiate $m)) + + ;; This adapter, when fused with itself on the second instantiation of this + ;; component, will depended on the prior instance `$m` so it which means + ;; that the adapter module containing this must be placed in the right + ;; location. + (core func $execute + (canon lower (func $i "execute") (memory $m "memory") (realloc (func $m "realloc"))) + ) + (core instance (instantiate $shim2 + (with "" (instance + (export "0" (func $execute)) + )) + )) + (func (export "execute") (canon lift (core func $m "execute"))) + ) + (instance $root (instantiate $root)) + (instance $c1 (instantiate $c (with "backend" (instance $root)))) + (instance $c2 (instantiate $c (with "backend" (instance $c1)))) +) diff --git a/src/test/resources/spec-tests/wasmtime/import.wast b/src/test/resources/spec-tests/wasmtime/import.wast new file mode 100644 index 0000000..20688ef --- /dev/null +++ b/src/test/resources/spec-tests/wasmtime/import.wast @@ -0,0 +1,20 @@ +(assert_invalid + (component + (import "host-return-two" (func $f (result u32))) + (export "x" (func $f))) + "component export `x` is a reexport of an imported function which is not implemented") + +(assert_unlinkable + (component + (import "host-return-two" (instance)) + ) + "expected instance found func") + +;; empty instances don't need to be supplied by the host, even recursively +;; empty instances. +(component + (import "not-provided-by-the-host" (instance)) + (import "not-provided-by-the-host2" (instance + (export "x" (instance)) + )) +) diff --git a/src/test/resources/spec-tests/wasmtime/instance.wast b/src/test/resources/spec-tests/wasmtime/instance.wast new file mode 100644 index 0000000..4216cdc --- /dev/null +++ b/src/test/resources/spec-tests/wasmtime/instance.wast @@ -0,0 +1,327 @@ +(component + (core module $m) + (core instance (instantiate $m)) +) + +(component + (core module $m + (func (export "")) + ) + (core instance $i (instantiate $m)) + + (core module $m2 + (func (import "" "")) + ) + (core instance (instantiate $m2 (with "" (instance $i)))) +) + +(component + (core module $m + (func (export "a")) + ) + (core instance $i (instantiate $m)) + + (core module $m2 + (func (import "" "b")) + ) + (core instance (instantiate $m2 + (with "" (instance (export "b" (func $i "a")))) + )) +) + +;; all kinds of imports for core wasm modules, and register a start function on +;; one module to ensure that everything is correct +(component + (core module $m + (func (export "a")) + (table (export "b") 1 funcref) + (memory (export "c") 1) + (global (export "d") i32 i32.const 1) + ) + (core instance $i (instantiate $m)) + + (core module $m2 + (import "" "a" (func $f)) + (import "" "b" (table 1 funcref)) + (import "" "c" (memory 1)) + (import "" "d" (global $g i32)) + + (func $start + global.get $g + i32.const 1 + i32.ne + if + unreachable + end + + call $f + ) + + (start $start) + + (data (i32.const 0) "hello") + (elem (i32.const 0) $start) + ) + (core instance (instantiate $m2 + (with "" (instance $i)) + )) +) + +;; Test to see if a component with a type export can be instantiated. +(component + (type string) + (export "a" (type 0)) +) + +;; double-check the start function runs by ensuring that a trap shows up and it +;; sees the wrong value for the global import +(assert_trap + (component + (core module $m + (global (export "g") i32 i32.const 1) + ) + (core instance $i (instantiate $m)) + + (core module $m2 + (import "" "g" (global $g i32)) + + (func $start + global.get $g + i32.const 0 + i32.ne + if + unreachable + end + ) + + (start $start) + ) + (core instance (instantiate $m2 (with "" (instance $i)))) + ) + "unreachable") + +;; shuffle around imports to get to what the target core wasm module needs +(component + (core module $m + (func (export "1")) + (table (export "2") 1 funcref) + (memory (export "3") 1) + (global (export "4") i32 i32.const 1) + ) + (core instance $i (instantiate $m)) + + (core module $m2 + (import "" "a" (func $f)) + (import "" "b" (table 1 funcref)) + (import "" "c" (memory 1)) + (import "" "d" (global $g i32)) + ) + (core instance (instantiate $m2 + (with "" (instance + (export "a" (func $i "1")) + (export "b" (table $i "2")) + (export "c" (memory $i "3")) + (export "d" (global $i "4")) + )) + )) +) + +;; indirect references through a synthetic instance +(component + (core module $m + (func (export "a")) + (table (export "b") 1 funcref) + (memory (export "c") 1) + (global (export "d") i32 i32.const 1) + ) + (core instance $i (instantiate $m)) + (core instance $i2 + (export "a1" (func $i "a")) + (export "a2" (table $i "b")) + (export "a3" (memory $i "c")) + (export "a4" (global $i "d")) + ) + + (core module $m2 + (import "" "1" (func $f)) + (import "" "2" (table 1 funcref)) + (import "" "3" (memory 1)) + (import "" "4" (global $g i32)) + ) + (core instance (instantiate $m2 + (with "" (instance + (export "1" (func $i2 "a1")) + (export "2" (table $i2 "a2")) + (export "3" (memory $i2 "a3")) + (export "4" (global $i2 "a4")) + )) + )) +) + +(component + (import "host" (instance $i (export "return-three" (func (result u32))))) + + (core module $m + (import "host" "return-three" (func $three (result i32))) + (func $start + call $three + i32.const 3 + i32.ne + if unreachable end + ) + (start $start) + ) + (core func $three_lower + (canon lower (func $i "return-three")) + ) + (core instance (instantiate $m + (with "host" (instance (export "return-three" (func $three_lower)))) + )) +) + +(component + (import "host" (instance $i + (type $x' (record (field "x" u32))) + (export "x" (type $x (eq $x'))) + (type $rec' (record (field "x" $x) (field "y" string))) + (export "rec" (type $rec (eq $rec'))) + (export "some-record" (type (eq $rec))))) +) + +(component + (import "host" (instance $i + (export "nested" (instance + (export "return-four" (func (result u32))) + )) + )) + + (core module $m + (import "host" "return-three" (func $three (result i32))) + (func $start + call $three + i32.const 4 + i32.ne + if unreachable end + ) + (start $start) + ) + (core func $three_lower + (canon lower (func $i "nested" "return-four")) + ) + (core instance (instantiate $m + (with "host" (instance (export "return-three" (func $three_lower)))) + )) +) + +(component + (import "host" (instance $i + (export "simple-module" (core module)) + )) + + (core instance (instantiate (module $i "simple-module"))) +) + +(component + (import "host" (instance $i + (export "simple-module" (core module + (export "f" (func (result i32))) + (export "g" (global i32)) + )) + )) + + (core instance $i (instantiate (module $i "simple-module"))) + (core module $verify + (import "host" "f" (func $f (result i32))) + (import "host" "g" (global $g i32)) + + (func $start + call $f + i32.const 101 + i32.ne + if unreachable end + + global.get $g + i32.const 100 + i32.ne + if unreachable end + ) + (start $start) + ) + + (core instance (instantiate $verify (with "host" (instance $i)))) +) + +;; export an instance +(component + (core module $m) + (instance $i (export "m" (core module $m))) + (export "i" (instance $i)) +) +(component + (component $c) + (instance $i (instantiate $c)) + (export "i" (instance $i)) +) +(component + (import "host" (instance $i)) + (export "i" (instance $i)) +) + + +(component definition $C1 + (type $r1 (resource (rep i32))) + (export "r" (type $r1)) +) +(component definition $C2 + (type $r1 (resource (rep i32))) + (export "r" (type $r1)) +) + +(component instance $I1 $C1) +(component instance $I2 $C1) +(component instance $I3 $C2) +(component instance $I4 $C2) + +;; all instances have different resource types +(assert_unlinkable + (component + (import "I1" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I2" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") +(assert_unlinkable + (component + (import "I1" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I3" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") +(assert_unlinkable + (component + (import "I1" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I4" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") +(assert_unlinkable + (component + (import "I2" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I3" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") +(assert_unlinkable + (component + (import "I2" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I4" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") +(assert_unlinkable + (component + (import "I3" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I4" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") diff --git a/src/test/resources/spec-tests/wasmtime/linking.wast b/src/test/resources/spec-tests/wasmtime/linking.wast new file mode 100644 index 0000000..966926f --- /dev/null +++ b/src/test/resources/spec-tests/wasmtime/linking.wast @@ -0,0 +1,18 @@ +(assert_unlinkable + (component + (import "undefined-name" (core module)) + ) + "was not found") +(component $i) +(component + (import "i" (instance)) +) +(assert_unlinkable + (component (import "i" (core module))) + "expected module found instance") +(assert_unlinkable + (component (import "i" (func))) + "expected function found instance") +(assert_unlinkable + (component (import "i" (instance (export "x" (func))))) + "was not found") diff --git a/src/test/resources/spec-tests/wasmtime/modules.wast b/src/test/resources/spec-tests/wasmtime/modules.wast new file mode 100644 index 0000000..6014f94 --- /dev/null +++ b/src/test/resources/spec-tests/wasmtime/modules.wast @@ -0,0 +1,479 @@ +;;! reference_types = true + +(component $foo + (core module (export "a-module")) +) + +;; the above instance can be imported into this component +(component + (import "foo" (instance + (export "a-module" (core module)) + )) +) + +;; specifying extra imports is ok +(component + (import "foo" (instance + (export "a-module" (core module + (import "foo" "bar" (func)) + )) + )) +) + +;; specifying extra exports is not ok +(assert_unlinkable + (component + (import "foo" (instance + (export "a-module" (core module + (export "the-export" (func)) + )) + )) + ) + "module export `the-export` not defined") + +(component $foo + (core module (export "a-module") + (import "env" "something" (func)) + ) +) + +;; imports must be specified +(assert_unlinkable + (component + (import "foo" (instance + (export "a-module" (core module)) + )) + ) + "module import `env::something` not defined") + +(component + (import "foo" (instance + (export "a-module" (core module + (import "env" "something" (func)) + )) + )) +) + +;; extra imports still ok +(component + (import "foo" (instance + (export "a-module" (core module + (import "env" "something" (func)) + (import "env" "other" (global i32)) + )) + )) +) + +(component $foo + (core module (export "a-module") + (func (export "f")) + ) +) + +;; dropping exports is ok +(component + (import "foo" (instance + (export "a-module" (core module)) + )) +) + +(component + (import "foo" (instance + (export "a-module" (core module + (export "f" (func)) + )) + )) +) + +(assert_unlinkable + (component + (import "foo" (instance + (export "a-module" (core module + (export "f" (func (param i32))) + )) + )) + ) + "expected type `(func (param i32))`, found type `(func)`") + +(assert_unlinkable + (component + (import "foo" (instance + (export "a-module" (core module + (export "f" (global i32)) + )) + )) + ) + "expected global found func") + +(component $foo + (core module (export "m") + (func (export "f")) + (table (export "t") 1 funcref) + (memory (export "m") 1) + (global (export "g") i32 i32.const 0) + ) +) + +;; wrong class of item +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "f" (global i32)))) + )) + ) + "expected global found func") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "t" (func)))) + )) + ) + "expected func found table") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "m" (func)))) + )) + ) + "expected func found memory") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "g" (func)))) + )) + ) + "expected func found global") + +;; wrong item type +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "f" (func (param i32))))) + )) + ) + "export `f` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "t" (table 1 externref)))) + )) + ) + "export `t` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "t" (table 2 funcref)))) + )) + ) + "export `t` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "m" (memory 2)))) + )) + ) + "export `m` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "g" (global f32)))) + )) + ) + "export `g` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "g" (global (mut i32))))) + )) + ) + "export `g` has the wrong type") + +;; subtyping ok +(component + (import "foo" (instance + (export "m" (core module + (export "t" (table 0 funcref)) + (export "m" (memory 0)) + )) + )) +) + +(component $foo + (core module (export "f") (func (import "" ""))) + (core module (export "t") (table (import "" "") 1 funcref)) + (core module (export "m") (memory (import "" "") 1)) + (core module (export "g") (global (import "" "") i32)) +) + +;; wrong class of item +(assert_unlinkable + (component + (import "foo" (instance + (export "f" (core module (import "" "" (global i32)))) + )) + ) + "expected func found global") +(assert_unlinkable + (component + (import "foo" (instance + (export "t" (core module (import "" "" (func)))) + )) + ) + "expected table found func") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (import "" "" (func)))) + )) + ) + "expected memory found func") +(assert_unlinkable + (component + (import "foo" (instance + (export "g" (core module (import "" "" (func)))) + )) + ) + "expected global found func") + +;; wrong item type +(assert_unlinkable + (component + (import "foo" (instance + (export "f" (core module (import "" "" (func (param i32))))) + )) + ) + "module import `::` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "t" (core module (import "" "" (table 1 externref)))) + )) + ) + "module import `::` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "t" (core module (import "" "" (table 0 funcref)))) + )) + ) + "module import `::` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (import "" "" (memory 0)))) + )) + ) + "module import `::` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "g" (core module (import "" "" (global f32)))) + )) + ) + "module import `::` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "g" (core module (import "" "" (global (mut i32))))) + )) + ) + "module import `::` has the wrong type") + +;; subtyping ok, but in the opposite direction of imports +(component + (import "foo" (instance + (export "t" (core module (import "" "" (table 2 funcref)))) + (export "m" (core module (import "" "" (memory 2)))) + )) +) + +;; An instance can reexport a module, define a module, and everything can be +;; used by something else +(component $src + (core module (export "m") + (global (export "g") i32 i32.const 2) + ) +) + +(component $reexport + (core module $m1 + (global (export "g") i32 i32.const 1) + ) + (import "src" (instance $src + (export "m" (core module (export "g" (global i32)))) + )) + + (core module $m3 + (global (export "g") i32 i32.const 3) + ) + + (export "m1" (core module $m1)) + (export "m2" (core module $src "m")) + (export "m3" (core module $m3)) +) + +(component + (core type $modulety (module (export "g" (global i32)))) + (import "reexport" (instance $reexport + (export "m1" (core module (type $modulety))) + (export "m2" (core module (type $modulety))) + (export "m3" (core module (type $modulety))) + )) + + (core module $assert_ok + (import "m1" "g" (global $m1 i32)) + (import "m2" "g" (global $m2 i32)) + (import "m3" "g" (global $m3 i32)) + + (func $assert_ok + block + global.get $m1 + i32.const 1 + i32.eq + br_if 0 + unreachable + end + block + global.get $m2 + i32.const 2 + i32.eq + br_if 0 + unreachable + end + block + global.get $m3 + i32.const 3 + i32.eq + br_if 0 + unreachable + end + ) + + (start $assert_ok) + ) + + (core instance $m1 (instantiate (module $reexport "m1"))) + (core instance $m2 (instantiate (module $reexport "m2"))) + (core instance $m3 (instantiate (module $reexport "m3"))) + + (core instance (instantiate $assert_ok + (with "m1" (instance $m1)) + (with "m2" (instance $m2)) + (with "m3" (instance $m3)) + )) +) + +;; order of imports and exports can be shuffled between definition site and +;; use-site +(component $provider + (core module (export "m") + (import "" "1" (global $i1 i32)) + (import "" "2" (global $i2 i32)) + (import "" "3" (global $i3 i32)) + (import "" "4" (global $i4 i32)) + + (global $g1 i32 i32.const 100) + (global $g2 i32 i32.const 101) + (global $g3 i32 i32.const 102) + (global $g4 i32 i32.const 103) + + (func $assert_imports + (block + global.get $i1 + i32.const 1 + i32.eq + br_if 0 + unreachable) + (block + global.get $i2 + i32.const 2 + i32.eq + br_if 0 + unreachable) + (block + global.get $i3 + i32.const 3 + i32.eq + br_if 0 + unreachable) + (block + global.get $i4 + i32.const 4 + i32.eq + br_if 0 + unreachable) + ) + + (start $assert_imports) + + (export "g1" (global $g1)) + (export "g2" (global $g2)) + (export "g3" (global $g3)) + (export "g4" (global $g4)) + ) +) + +(component + (import "provider" (instance $provider + (export "m" (core module + (import "" "4" (global i32)) + (import "" "3" (global i32)) + (import "" "2" (global i32)) + (import "" "1" (global i32)) + + (export "g4" (global i32)) + (export "g3" (global i32)) + (export "g2" (global i32)) + (export "g1" (global i32)) + )) + )) + + (core module $imports + (global (export "1") i32 (i32.const 1)) + (global (export "3") i32 (i32.const 3)) + (global (export "2") i32 (i32.const 2)) + (global (export "4") i32 (i32.const 4)) + ) + (core instance $imports (instantiate $imports)) + (core instance $m (instantiate (module $provider "m") + (with "" (instance $imports)) + )) + + (core module $import_globals + (import "" "g4" (global $g4 i32)) + (import "" "g3" (global $g3 i32)) + (import "" "g2" (global $g2 i32)) + (import "" "g1" (global $g1 i32)) + + (func $assert_imports + (block + global.get $g1 + i32.const 100 + i32.eq + br_if 0 + unreachable) + (block + global.get $g2 + i32.const 101 + i32.eq + br_if 0 + unreachable) + (block + global.get $g3 + i32.const 102 + i32.eq + br_if 0 + unreachable) + (block + global.get $g4 + i32.const 103 + i32.eq + br_if 0 + unreachable) + ) + + (start $assert_imports) + ) + + (core instance (instantiate $import_globals (with "" (instance $m)))) +) diff --git a/src/test/resources/spec-tests/wasmtime/nested.wast b/src/test/resources/spec-tests/wasmtime/nested.wast new file mode 100644 index 0000000..8cb4c38 --- /dev/null +++ b/src/test/resources/spec-tests/wasmtime/nested.wast @@ -0,0 +1,451 @@ +;; simple nested component +(component + (component) +) + +;; simple nested component with a nested module +(component + (component + (core module) + ) +) + +;; simple instantiation of a nested component +(component + (component $c) + (instance (instantiate $c)) + (instance (instantiate $c + (with "x" (component $c)) + )) +) + +;; instantiate a module during a nested component, and also instantiate it +;; as an export of the nested component +(component + (component $c + (core module $m) + (core instance (instantiate $m)) + (export "m" (core module $m)) + ) + (instance $i (instantiate $c)) + (core instance $i (instantiate (module $i "m"))) +) + +;; instantiate an inner exported module with two different modules and +;; verify imports match +(component + (component $c + (core module $m + (import "" "g" (global $g i32)) + (import "" "f" (func $f (result i32))) + + (func $start + call $f + global.get $g + i32.ne + if unreachable end) + + (start $start) + ) + + (core module $m2 + (global (export "g") i32 i32.const 1) + (func (export "f") (result i32) i32.const 1) + ) + (core instance $i2 (instantiate $m2)) + (core instance (instantiate $m (with "" (instance $i2)))) + + (export "m" (core module $m)) + ) + (instance $i (instantiate $c)) + (core module $m2 + (global (export "g") i32 i32.const 5) + (func (export "f") (result i32) i32.const 5) + ) + (core instance $i2 (instantiate $m2)) + (core instance (instantiate (module $i "m") (with "" (instance $i2)))) +) + +;; instantiate an inner component with a module import +(component + (component $c + (import "m" (core module $m + (export "g" (global i32)) + )) + + (core instance $i (instantiate $m)) + + (core module $verify + (import "" "g" (global $g i32)) + + (func $start + global.get $g + i32.const 2 + i32.ne + if unreachable end + ) + + (start $start) + ) + (core instance (instantiate $verify (with "" (instance $i)))) + ) + + (core module $m + (global (export "g") i32 (i32.const 2)) + ) + (instance (instantiate $c (with "m" (core module $m)))) +) + +;; instantiate an inner component with a module import that itself has imports +(component + (component $c + (import "m" (core module $m + (import "" "g" (global i32)) + )) + (core module $m2 + (global (export "g") i32 i32.const 2100) + ) + (core instance $m2 (instantiate $m2)) + (core instance (instantiate $m (with "" (instance $m2)))) + ) + + (core module $verify + (import "" "g" (global $g i32)) + + (func $start + global.get $g + i32.const 2100 + i32.ne + if unreachable end + ) + + (start $start) + ) + (instance (instantiate $c (with "m" (core module $verify)))) +) + +;; instantiate an inner component with an export from the outer component +(component $c + (core module (export "m") + (import "" "g1" (global $g1 i32)) + (import "" "g2" (global $g2 i32)) + + (func $start + global.get $g1 + i32.const 10000 + i32.ne + if unreachable end + + global.get $g2 + i32.const 20000 + i32.ne + if unreachable end + ) + + (start $start) + ) +) + +(component + (import "c" (instance $i + (export "m" (core module + (import "" "g2" (global i32)) + (import "" "g1" (global i32)) + )) + )) + + (component $c + (import "m" (core module $verify + (import "" "g2" (global i32)) + (import "" "g1" (global i32)) + )) + + (core module $m + (global (export "g1") i32 i32.const 10000) + (global (export "g2") i32 i32.const 20000) + ) + (core instance $m (instantiate $m)) + (core instance (instantiate $verify (with "" (instance $m)))) + ) + + (instance (instantiate $c (with "m" (core module $i "m")))) +) + +;; instantiate a reexported module +(component + (core module $m + (global (export "g") i32 i32.const 7) + ) + (component $c + (import "i" (instance $i + (export "m" (core module + (import "" "" (func)) + (export "g" (global i32)) + )) + )) + + (export "m" (core module $i "m")) + ) + + (instance $c (instantiate $c (with "i" (instance (export "m" (core module $m)))))) + (core module $dummy + (func (export "")) + ) + (core instance $dummy (instantiate $dummy)) + + (core instance $m (instantiate (module $c "m") (with "" (instance $dummy)))) + + (core module $verify + (import "" "g" (global i32)) + (func $start + global.get 0 + i32.const 7 + i32.ne + if unreachable end + ) + + (start $start) + ) + (core instance (instantiate $verify (with "" (instance $m)))) +) + +;; module must be found through a few layers of imports +(component $c + (core module (export "m") + (global (export "g") i32 i32.const 101) + ) +) + +(component + (import "c" (instance $i + (export "m" (core module + (export "g" (global i32)) + )) + )) + (component $c1 + (import "c" (instance $i + (export "m" (core module + (export "g" (global i32)) + )) + )) + (core module $verify + (import "" "g" (global i32)) + (func $start + global.get 0 + i32.const 101 + i32.ne + if unreachable end + ) + + (start $start) + ) + (core instance $m (instantiate (module $i "m"))) + (core instance (instantiate $verify (with "" (instance $m)))) + ) + (instance (instantiate $c1 (with "c" (instance $i)))) +) + +;; instantiate outer alias to self +(component $C + (core module $m) + (alias outer $C $m (core module $other_m)) + (core instance (instantiate $other_m)) +) + +(component $C + (component $m) + (alias outer $C $m (component $other_m)) + (instance (instantiate $other_m)) +) + + +;; closing over an outer alias which is actually an argument to some +;; instantiation +(component + (component $c + (import "c" (core module $c + (export "a" (global i32)) + )) + + (component (export "c2") + (export "m" (core module $c)) + ) + ) + + (core module $m1 (global (export "a") i32 i32.const 1)) + (core module $m2 (global (export "a") i32 i32.const 2)) + + (instance $c1 (instantiate $c (with "c" (core module $m1)))) + (instance $c2 (instantiate $c (with "c" (core module $m2)))) + + (instance $m1_container (instantiate (component $c1 "c2"))) + (instance $m2_container (instantiate (component $c2 "c2"))) + + (core instance $core1 (instantiate (module $m1_container "m"))) + (core instance $core2 (instantiate (module $m2_container "m"))) + + (core module $verify + (import "core1" "a" (global $a i32)) + (import "core2" "a" (global $b i32)) + + (func $start + global.get $a + i32.const 1 + i32.ne + if unreachable end + + global.get $b + i32.const 2 + i32.ne + if unreachable end + ) + + (start $start) + ) + (core instance (instantiate $verify + (with "core1" (instance $core1)) + (with "core2" (instance $core2)) + )) +) + +;; simple importing of a component +(component + (component $C) + (component $other + (import "x" (component $c)) + (instance (instantiate $c)) + ) + (instance (instantiate $other (with "x" (component $C)))) +) + +;; deep nesting +(component $C + (core module $m + (global (export "g") i32 (i32.const 1)) + ) + (component $c + (core module (export "m") + (global (export "g") i32 (i32.const 2)) + ) + ) + + (component $c1 + (component $c2 (export "a") + (component $c3 (export "a") + (alias outer $C $m (core module $my_module)) + (alias outer $C $c (component $my_component)) + + (export "m" (core module $my_module)) + (export "c" (component $my_component)) + ) + ) + ) + + (instance $i1 (instantiate $c1)) + (instance $i2 (instantiate (component $i1 "a"))) + (instance $i3 (instantiate (component $i2 "a"))) + + (core instance $m1 (instantiate (module $i3 "m"))) + (instance $c (instantiate (component $i3 "c"))) + (core instance $m2 (instantiate (module $c "m"))) + + (core module $verify + (import "m1" "g" (global $m1 i32)) + (import "m2" "g" (global $m2 i32)) + + (func $start + global.get $m1 + i32.const 1 + i32.ne + if unreachable end + + global.get $m2 + i32.const 2 + i32.ne + if unreachable end + ) + (start $start) + ) + (core instance (instantiate $verify (with "m1" (instance $m1)) (with "m2" (instance $m2)))) +) + +;; Try threading through component instantiation arguments as various forms of +;; instances. +(component + (component $c + (core module $m (export "m")) + (component $c (export "c") + (core module (export "m")) + ) + (instance $i (instantiate $c)) + (instance $i2 + (export "m" (core module $m)) + (export "c" (component $c)) + (export "i" (instance $i)) + ) + (export "i" (instance $i)) + (export "i2" (instance $i2)) + ) + (instance $i (instantiate $c)) + + (component $another + (import "host" (instance + (export "m" (core module)) + (export "c" (component)) + (export "i" (instance)) + )) + ) + (instance (instantiate $another (with "host" (instance $i)))) + (instance (instantiate $another (with "host" (instance $i "i2")))) + + (instance $reexport + (export "c" (component $i "c")) + (export "m" (core module $i "m")) + (export "i" (instance $i "i")) + ) + (instance (instantiate $another (with "host" (instance $reexport)))) +) + +;; thread host functions around +(component + (import "host-return-two" (func $import (result u32))) + + ;; thread the host function through an instance + (component $c + (import "a" (func $f (result u32))) + (export "f" (func $f)) + ) + (instance $c (instantiate $c (with "a" (func $import)))) + (alias export $c "f" (func $import2)) + + ;; thread the host function into a nested component + (component $c2 + (import "host" (instance $i (export "return-two" (func (result u32))))) + + (core module $m + (import "host" "return-two" (func $host (result i32))) + (func $start + call $host + i32.const 2 + i32.ne + if unreachable end + ) + (start $start) + ) + + (core func $return_two + (canon lower (func $i "return-two")) + ) + (core instance (instantiate $m + (with "host" (instance + (export "return-two" (func $return_two)) + )) + )) + ) + + (instance (instantiate $c2 + (with "host" (instance + (export "return-two" (func $import2)) + )) + )) +) diff --git a/src/test/resources/spec-tests/wasmtime/resources.wast b/src/test/resources/spec-tests/wasmtime/resources.wast new file mode 100644 index 0000000..28e68ad --- /dev/null +++ b/src/test/resources/spec-tests/wasmtime/resources.wast @@ -0,0 +1,1091 @@ +;; bare bones "intrinsics work" +(component + (type $r (resource (rep i32))) + (core func $rep (canon resource.rep $r)) + (core func $new (canon resource.new $r)) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "rep" (func $rep (param i32) (result i32))) + (import "" "new" (func $new (param i32) (result i32))) + (import "" "drop" (func $drop (param i32))) + + (func $start + (local $r i32) + (local.set $r (call $new (i32.const 100))) + + (if (i32.ne (local.get $r) (i32.const 1)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r)) (i32.const 100)) (then (unreachable))) + + (call $drop (local.get $r)) + ) + + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "rep" (func $rep)) + (export "new" (func $new)) + (export "drop" (func $drop)) + )) + )) +) + +;; cannot call `resource.drop` on a nonexistent resource +(component + (type $r (resource (rep i32))) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "drop" (func $drop (param i32))) + + (func (export "r") + (call $drop (i32.const 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + )) + )) + + (func (export "r") (canon lift (core func $i "r"))) +) +(assert_trap (invoke "r") "unknown handle index 0") + +;; cannot call `resource.rep` on a nonexistent resource +(component + (type $r (resource (rep i32))) + (core func $rep (canon resource.rep $r)) + + (core module $m + (import "" "rep" (func $rep (param i32) (result i32))) + + (func (export "r") + (drop (call $rep (i32.const 0))) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "rep" (func $rep)) + )) + )) + + (func (export "r") (canon lift (core func $i "r"))) +) +(assert_trap (invoke "r") "unknown handle index 0") + +;; index reuse behavior of handles +(component + (type $r (resource (rep i32))) + (core func $rep (canon resource.rep $r)) + (core func $new (canon resource.new $r)) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "rep" (func $rep (param i32) (result i32))) + (import "" "new" (func $new (param i32) (result i32))) + (import "" "drop" (func $drop (param i32))) + + (func $start + (local $r1 i32) + (local $r2 i32) + (local $r3 i32) + (local $r4 i32) + + ;; resources assigned sequentially + (local.set $r1 (call $new (i32.const 100))) + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + + (local.set $r2 (call $new (i32.const 200))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + + (local.set $r3 (call $new (i32.const 300))) + (if (i32.ne (local.get $r3) (i32.const 3)) (then (unreachable))) + + ;; representations all look good + (if (i32.ne (call $rep (local.get $r1)) (i32.const 100)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r2)) (i32.const 200)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r3)) (i32.const 300)) (then (unreachable))) + + ;; reallocate r2 + (call $drop (local.get $r2)) + (local.set $r2 (call $new (i32.const 400))) + + ;; should have reused index 3 + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + + ;; representations all look good + (if (i32.ne (call $rep (local.get $r1)) (i32.const 100)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r2)) (i32.const 400)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r3)) (i32.const 300)) (then (unreachable))) + + ;; deallocate, then reallocate + (call $drop (local.get $r1)) + (call $drop (local.get $r2)) + (call $drop (local.get $r3)) + + (local.set $r1 (call $new (i32.const 500))) + (local.set $r2 (call $new (i32.const 600))) + (local.set $r3 (call $new (i32.const 700))) + + ;; representations all look good + (if (i32.ne (call $rep (local.get $r1)) (i32.const 500)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r2)) (i32.const 600)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r3)) (i32.const 700)) (then (unreachable))) + + ;; indices should be lifo + (if (i32.ne (local.get $r1) (i32.const 3)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + (if (i32.ne (local.get $r3) (i32.const 1)) (then (unreachable))) + + ;; bump one more time + (local.set $r4 (call $new (i32.const 800))) + (if (i32.ne (local.get $r4) (i32.const 4)) (then (unreachable))) + + ;; deallocate everything + (call $drop (local.get $r1)) + (call $drop (local.get $r2)) + (call $drop (local.get $r3)) + (call $drop (local.get $r4)) + ) + + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "rep" (func $rep)) + (export "new" (func $new)) + (export "drop" (func $drop)) + )) + )) +) + +(assert_unlinkable + (component + (import "host" (instance + (export "missing" (type (sub resource))) + )) + ) + "was not found") +(assert_unlinkable + (component + (import "host" (instance + (export "return-three" (type (sub resource))) + )) + ) + "expected resource found func") + +;; all resources can be uniquely imported +(component + (import "host" (instance + (export "resource1" (type (sub resource))) + (export "resource2" (type (sub resource))) + (export "resource1-again" (type (sub resource))) + )) +) + +;; equality constraints also work +(component + (import "host" (instance + (export "resource1" (type $r1 (sub resource))) + (export "resource2" (type (sub resource))) + (export "resource1-again" (type (eq $r1))) + )) +) + +;; equality constraints are checked if resources are supplied +(assert_unlinkable + (component + (import "host" (instance + (export "resource1" (type (sub resource))) + (export "resource2" (type $r1 (sub resource))) + (export "resource1-again" (type (eq $r1))) + )) + ) + "mismatched resource types") + +;; equality constraints mean that types don't need to be supplied +(component + (import "host" (instance + (export "resource1" (type $r1 (sub resource))) + (export "resource2" (type (sub resource))) + (export "this-name-is-not-provided-in-the-wast-harness" (type (eq $r1))) + )) +) + +;; simple properties of handles +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32))) + )) + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + (alias export $host "[static]resource1.assert" (func $assert)) + + (core func $drop (canon resource.drop $r)) + (core func $ctor (canon lower (func $ctor))) + (core func $assert (canon lower (func $assert))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "assert" (func $assert (param i32 i32))) + + (func $start + (local $r1 i32) + (local $r2 i32) + (local.set $r1 (call $ctor (i32.const 100))) + (local.set $r2 (call $ctor (i32.const 200))) + + ;; assert r1/r2 are sequential + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + + ;; reallocate r1 and it should be reassigned the same index + (call $drop (local.get $r1)) + (local.set $r1 (call $ctor (i32.const 300))) + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + + ;; internal values should match + (call $assert (local.get $r1) (i32.const 300)) + (call $assert (local.get $r2) (i32.const 200)) + ) + + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + (export "ctor" (func $ctor)) + (export "assert" (func $assert)) + )) + )) +) + +;; Using an index that has never been valid is a trap +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32))) + )) + (alias export $host "resource1" (type $r)) + (alias export $host "[static]resource1.assert" (func $assert)) + (core func $assert (canon lower (func $assert))) + + (core module $m + (import "" "assert" (func $assert (param i32 i32))) + + (func (export "f") + (call $assert (i32.const 0) (i32.const 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "assert" (func $assert)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) +) + +(assert_trap (invoke "f") "unknown handle index") + +;; Using an index which was previously valid but no longer valid is also a trap. +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32))) + )) + (alias export $host "[constructor]resource1" (func $ctor)) + (alias export $host "[static]resource1.assert" (func $assert)) + + (core func $assert (canon lower (func $assert))) + (core func $ctor (canon lower (func $ctor))) + + (core module $m + (import "" "assert" (func $assert (param i32 i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + + (global $handle (mut i32) i32.const 0) + + (func (export "f") + (global.set $handle (call $ctor (i32.const 100))) + (call $assert (global.get $handle) (i32.const 100)) + ) + + (func (export "f2") + (call $assert (global.get $handle) (i32.const 100)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "assert" (func $assert)) + (export "ctor" (func $ctor)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) + (func (export "f2") (canon lift (core func $i "f2"))) +) + +(assert_return (invoke "f")) +(assert_trap (invoke "f2") "unknown handle index") + +;; Also invalid to pass a previously valid handle to the drop intrinsic +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + )) + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + + (core func $drop (canon resource.drop $r)) + (core func $ctor (canon lower (func $ctor))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + + (global $handle (mut i32) i32.const 0) + + (func (export "f") + (global.set $handle (call $ctor (i32.const 100))) + (call $drop (global.get $handle)) + ) + + (func (export "f2") + (call $drop (global.get $handle)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "ctor" (func $ctor)) + (export "drop" (func $drop)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) + (func (export "f2") (canon lift (core func $i "f2"))) +) + +(assert_return (invoke "f")) +(assert_trap (invoke "f2") "unknown handle index") + +;; If an inner component instantiates a resource then an outer component +;; should not implicitly have access to that resource. +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + )) + + ;; an inner component which upon instantiation will invoke the constructor, + ;; assert that it's zero, and then forget about it. + (component $inner + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + )) + (alias export $host "[constructor]resource1" (func $ctor)) + + (core func $ctor (canon lower (func $ctor))) + + (core module $m + (import "" "ctor" (func $ctor (param i32) (result i32))) + + (func $start + (if (i32.ne (call $ctor (i32.const 100)) (i32.const 0)) (then (unreachable))) + ) + ) + (core instance $i (instantiate $m + (with "" (instance (export "ctor" (func $ctor)))) + )) + ) + (instance $i (instantiate $inner (with "host" (instance $host)))) + + ;; the rest of this component which is a single function that invokes `drop` + ;; for index 0. The index 0 should be valid within the above component, but + ;; it is not valid within this component + (alias export $host "resource1" (type $r)) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "drop" (func $drop (param i32))) + + (func (export "f") + (call $drop (i32.const 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) +) + +(assert_trap (invoke "f") "unknown handle index") + +;; Same as the above test, but for resources defined within a component +(component + (component $inner + (type $r (resource (rep i32))) + + (core func $ctor (canon resource.new $r)) + + (core module $m + (import "" "ctor" (func $ctor (param i32) (result i32))) + + (func $start + (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) + ) + (start $start) + ) + (core instance $i (instantiate $m + (with "" (instance (export "ctor" (func $ctor)))) + )) + (export "r" (type $r)) + ) + (instance $i (instantiate $inner)) + + ;; the rest of this component which is a single function that invokes `drop` + ;; for index 1. The index 1 should be valid within the above component, but + ;; it is not valid within this component + (alias export $i "r" (type $r)) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "drop" (func $drop (param i32))) + + (func (export "f") + (call $drop (i32.const 1)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) +) + +(assert_trap (invoke "f") "unknown handle index 1") + +;; Each instantiation of a component generates a unique resource type, so +;; allocating in one component and deallocating in another should fail. +(component + (component $inner + (type $r (resource (rep i32))) + + (core func $ctor (canon resource.new $r)) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "drop" (func $drop (param i32))) + + (func (export "alloc") + (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) + ) + (func (export "dealloc") + (call $drop (i32.const 1)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "ctor" (func $ctor)) + (export "drop" (func $drop)) + )) + )) + (func (export "alloc") (canon lift (core func $i "alloc"))) + (func (export "dealloc") (canon lift (core func $i "dealloc"))) + ) + (instance $i1 (instantiate $inner)) + (instance $i2 (instantiate $inner)) + + (alias export $i1 "alloc" (func $alloc_in_1)) + (alias export $i1 "dealloc" (func $dealloc_in_1)) + (alias export $i2 "alloc" (func $alloc_in_2)) + (alias export $i2 "dealloc" (func $dealloc_in_2)) + + (export "alloc-in1" (func $alloc_in_1)) + (export "dealloc-in1" (func $dealloc_in_1)) + (export "alloc-in2" (func $alloc_in_2)) + (export "dealloc-in2" (func $dealloc_in_2)) +) + +(assert_return (invoke "alloc-in1")) +(assert_return (invoke "dealloc-in1")) +(assert_return (invoke "alloc-in1")) +(assert_return (invoke "alloc-in2")) +(assert_return (invoke "dealloc-in2")) +(assert_trap (invoke "dealloc-in2") "unknown handle index") + +;; Same as above, but the same host resource type is imported into a +;; component that is instantiated twice. Each component instance should +;; receive different tables tracking resources so a resource allocated in one +;; should not be visible in the other. +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + )) + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + + (component $inner + (import "r" (type $r (sub resource))) + (import "[constructor]r" (func $ctor (param "r" u32) (result (own $r)))) + + (core func $ctor (canon lower (func $ctor))) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "drop" (func $drop (param i32))) + + (func (export "alloc") + (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) + ) + (func (export "dealloc") + (call $drop (i32.const 1)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "ctor" (func $ctor)) + (export "drop" (func $drop)) + )) + )) + (func (export "alloc") (canon lift (core func $i "alloc"))) + (func (export "dealloc") (canon lift (core func $i "dealloc"))) + ) + (instance $i1 (instantiate $inner + (with "r" (type $r)) + (with "[constructor]r" (func $ctor)) + )) + (instance $i2 (instantiate $inner + (with "r" (type $r)) + (with "[constructor]r" (func $ctor)) + )) + + (alias export $i1 "alloc" (func $alloc_in_1)) + (alias export $i1 "dealloc" (func $dealloc_in_1)) + (alias export $i2 "alloc" (func $alloc_in_2)) + (alias export $i2 "dealloc" (func $dealloc_in_2)) + + (export "alloc-in1" (func $alloc_in_1)) + (export "dealloc-in1" (func $dealloc_in_1)) + (export "alloc-in2" (func $alloc_in_2)) + (export "dealloc-in2" (func $dealloc_in_2)) +) + +(assert_return (invoke "alloc-in1")) +(assert_return (invoke "dealloc-in1")) +(assert_return (invoke "alloc-in1")) +(assert_return (invoke "alloc-in2")) +(assert_return (invoke "dealloc-in2")) +(assert_trap (invoke "dealloc-in2") "unknown handle index") + +;; Multiple copies of intrinsics all work +(component + (type $r (resource (rep i32))) + + (core func $new1 (canon resource.new $r)) + (core func $new2 (canon resource.new $r)) + (core func $drop1 (canon resource.drop $r)) + (core func $drop2 (canon resource.drop $r)) + + (core module $m + (import "" "new1" (func $new1 (param i32) (result i32))) + (import "" "new2" (func $new2 (param i32) (result i32))) + (import "" "drop1" (func $drop1 (param i32))) + (import "" "drop2" (func $drop2 (param i32))) + + (func $start + ;; 2x2 matrix of pairing new/drop + (call $drop1 (call $new1 (i32.const 101))) + (call $drop2 (call $new1 (i32.const 102))) + (call $drop1 (call $new2 (i32.const 103))) + (call $drop2 (call $new2 (i32.const 104))) + + ;; should be referencing the same namespace + (if (i32.ne (call $new1 (i32.const 105)) (i32.const 1)) (then (unreachable))) + (if (i32.ne (call $new2 (i32.const 105)) (i32.const 2)) (then (unreachable))) + + ;; use different drops out of order + (call $drop2 (i32.const 1)) + (call $drop1 (i32.const 2)) + ) + + (start $start) + ) + + (core instance (instantiate $m + (with "" (instance + (export "new1" (func $new1)) + (export "new2" (func $new2)) + (export "drop1" (func $drop1)) + (export "drop2" (func $drop2)) + )) + )) +) + +;; u32::MAX isn't special in some weird way, it's just probably always invalid +;; because that's a lot of handles. +(component + (type $r (resource (rep i32))) + + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "drop" (func $drop (param i32))) + + (func (export "f") + (call $drop (i32.const 0xffffffff)) + ) + ) + + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + )) + )) + (func (export "f") (canon lift (core func $i "f"))) +) +(assert_trap (invoke "f") "unknown handle index") + +;; Test behavior of running a destructor for local resources +(component + (core module $m1 + (global $drops (mut i32) i32.const 0) + (global $last_drop (mut i32) i32.const -1) + + (func (export "dtor") (param i32) + (global.set $drops (i32.add (global.get $drops) (i32.const 1))) + (global.set $last_drop (local.get 0)) + ) + (func (export "drops") (result i32) global.get $drops) + (func (export "last-drop") (result i32) global.get $last_drop) + ) + (core instance $i1 (instantiate $m1)) + + (type $r1 (resource (rep i32))) + (type $r2 (resource (rep i32) (dtor (func $i1 "dtor")))) + + (core func $drop1 (canon resource.drop $r1)) + (core func $drop2 (canon resource.drop $r2)) + (core func $new1 (canon resource.new $r1)) + (core func $new2 (canon resource.new $r2)) + + (core module $m2 + (import "" "drop1" (func $drop1 (param i32))) + (import "" "drop2" (func $drop2 (param i32))) + (import "" "new1" (func $new1 (param i32) (result i32))) + (import "" "new2" (func $new2 (param i32) (result i32))) + (import "i1" "drops" (func $drops (result i32))) + (import "i1" "last-drop" (func $last-drop (result i32))) + + (func $start + (local $r1 i32) + (local $r2 i32) + + (local.set $r1 (call $new1 (i32.const 100))) + (local.set $r2 (call $new2 (i32.const 200))) + + ;; indexes start at 2 and while they have distinct types they should be + ;; within the same table. + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + + ;; nothing should be dropped yet + (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const -1)) (then (unreachable))) + + ;; dropping a resource without a destructor is ok, but shouldn't tamper + ;; with anything. + (call $drop1 (local.get $r1)) + (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const -1)) (then (unreachable))) + + ;; drop r2 which should record a drop and additionally record the private + ;; representation value which was dropped + (call $drop2 (local.get $r2)) + (if (i32.ne (call $drops) (i32.const 1)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const 200)) (then (unreachable))) + + ;; do it all over again + (local.set $r2 (call $new2 (i32.const 300))) + (call $drop2 (local.get $r2)) + (if (i32.ne (call $drops) (i32.const 2)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const 300)) (then (unreachable))) + ) + + (start $start) + ) + + (core instance $i2 (instantiate $m2 + (with "" (instance + (export "drop1" (func $drop1)) + (export "drop2" (func $drop2)) + (export "new1" (func $new1)) + (export "new2" (func $new2)) + )) + (with "i1" (instance $i1)) + )) +) + +;; Test dropping a host resource +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + (export "[static]resource1.last-drop" (func (result u32))) + (export "[static]resource1.drops" (func (result u32))) + )) + + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + (alias export $host "[static]resource1.last-drop" (func $last-drop)) + (alias export $host "[static]resource1.drops" (func $drops)) + + (core func $drop (canon resource.drop $r)) + (core func $ctor (canon lower (func $ctor))) + (core func $last-drop (canon lower (func $last-drop))) + (core func $drops (canon lower (func $drops))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "last-drop" (func $last-drop (result i32))) + (import "" "drops" (func $raw-drops (result i32))) + + (global $init-drop-cnt (mut i32) i32.const 0) + + (func $drops (result i32) + (i32.sub (call $raw-drops) (global.get $init-drop-cnt)) + ) + + (func $start + (local $r1 i32) + (global.set $init-drop-cnt (call $raw-drops)) + + (local.set $r1 (call $ctor (i32.const 100))) + + ;; should be no drops yet + (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) + + ;; should count a drop + (call $drop (local.get $r1)) + (if (i32.ne (call $drops) (i32.const 1)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const 100)) (then (unreachable))) + + ;; do it again to be sure + (local.set $r1 (call $ctor (i32.const 200))) + (call $drop (local.get $r1)) + (if (i32.ne (call $drops) (i32.const 2)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const 200)) (then (unreachable))) + ) + + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + (export "ctor" (func $ctor)) + (export "last-drop" (func $last-drop)) + (export "drops" (func $drops)) + )) + )) +) + +;; Test some bare-bones basics of borrowed resources +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + (export "[method]resource1.simple" (func (param "self" (borrow $r)) (param "rep" u32))) + (export "[method]resource1.take-borrow" (func (param "self" (borrow $r)) (param "b" (borrow $r)))) + (export "[method]resource1.take-own" (func (param "self" (borrow $r)) (param "b" (own $r)))) + )) + + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + (alias export $host "[method]resource1.simple" (func $simple)) + (alias export $host "[method]resource1.take-borrow" (func $take-borrow)) + (alias export $host "[method]resource1.take-own" (func $take-own)) + + (core func $drop (canon resource.drop $r)) + (core func $ctor (canon lower (func $ctor))) + (core func $simple (canon lower (func $simple))) + (core func $take-own (canon lower (func $take-own))) + (core func $take-borrow (canon lower (func $take-borrow))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "simple" (func $simple (param i32 i32))) + (import "" "take-own" (func $take-own (param i32 i32))) + (import "" "take-borrow" (func $take-borrow (param i32 i32))) + + + (func $start + (local $r1 i32) + (local $r2 i32) + (local.set $r1 (call $ctor (i32.const 100))) + (local.set $r2 (call $ctor (i32.const 200))) + + (call $simple (local.get $r1) (i32.const 100)) + (call $simple (local.get $r1) (i32.const 100)) + (call $simple (local.get $r2) (i32.const 200)) + (call $simple (local.get $r1) (i32.const 100)) + (call $simple (local.get $r2) (i32.const 200)) + (call $simple (local.get $r2) (i32.const 200)) + + (call $drop (local.get $r1)) + (call $drop (local.get $r2)) + + + (local.set $r1 (call $ctor (i32.const 200))) + (local.set $r2 (call $ctor (i32.const 300))) + (call $take-borrow (local.get $r1) (local.get $r2)) + (call $take-borrow (local.get $r2) (local.get $r1)) + (call $take-borrow (local.get $r1) (local.get $r1)) + (call $take-borrow (local.get $r2) (local.get $r2)) + + (call $take-own (local.get $r1) (call $ctor (i32.const 400))) + (call $take-own (local.get $r2) (call $ctor (i32.const 500))) + (call $take-own (local.get $r2) (local.get $r1)) + (call $drop (local.get $r2)) + + ;; table should be empty at this point, so a fresh allocation should get + ;; index 2 + (if (i32.ne (call $ctor (i32.const 600)) (i32.const 1)) (then (unreachable))) + ) + + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + (export "ctor" (func $ctor)) + (export "simple" (func $simple)) + (export "take-own" (func $take-own)) + (export "take-borrow" (func $take-borrow)) + )) + )) +) + +;; Cannot pass out an owned resource when it's borrowed by the same call +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + (export "[method]resource1.take-own" (func (param "self" (borrow $r)) (param "b" (own $r)))) + )) + + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + (alias export $host "[method]resource1.take-own" (func $take-own)) + + (core func $drop (canon resource.drop $r)) + (core func $ctor (canon lower (func $ctor))) + (core func $take-own (canon lower (func $take-own))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "take-own" (func $take-own (param i32 i32))) + + + (func (export "f") + (local $r i32) + (local.set $r (call $ctor (i32.const 100))) + (call $take-own (local.get $r) (local.get $r)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + (export "ctor" (func $ctor)) + (export "take-own" (func $take-own)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) +) + +(assert_trap (invoke "f") "cannot remove owned resource while borrowed") + +;; Borrows must actually exist +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[method]resource1.simple" (func (param "self" (borrow $r)) (param "b" u32))) + )) + + (alias export $host "resource1" (type $r)) + (alias export $host "[method]resource1.simple" (func $simple)) + + (core func $drop (canon resource.drop $r)) + (core func $simple (canon lower (func $simple))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "simple" (func $simple (param i32 i32))) + + + (func (export "f") + (call $simple (i32.const 0) (i32.const 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + (export "simple" (func $simple)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) +) + +(assert_trap (invoke "f") "unknown handle index 0") + +(component + (component $A + (type $t' (resource (rep i32))) + (export $t "t" (type $t')) + + (core func $ctor (canon resource.new $t)) + (core func $dtor (canon resource.drop $t)) + (core func $rep (canon resource.rep $t)) + + (core module $m + (import "" "dtor" (func $dtor (param i32))) + (import "" "rep" (func $rep (param i32) (result i32))) + + (func (export "[method]t.assert") (param i32 i32) + (if (i32.ne (local.get 0) (local.get 1)) (then (unreachable))) + ) + (func (export "[static]t.assert-own") (param i32 i32) + (if (i32.ne (call $rep (local.get 0)) (local.get 1)) (then (unreachable))) + (call $dtor (local.get 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "dtor" (func $dtor)) + (export "rep" (func $rep)) + )) + )) + (func (export "[constructor]t") (param "x" u32) (result (own $t)) + (canon lift (core func $ctor))) + (func (export "[method]t.assert") (param "self" (borrow $t)) (param "x" u32) + (canon lift (core func $i "[method]t.assert"))) + (func (export "[static]t.assert-own") (param "self" (own $t)) (param "x" u32) + (canon lift (core func $i "[static]t.assert-own"))) + ) + (instance $a (instantiate $A)) + + (component $B + (import "a" (instance $i + (export "t" (type $t (sub resource))) + (export "[constructor]t" (func (param "x" u32) (result (own $t)))) + (export "[method]t.assert" (func (param "self" (borrow $t)) (param "x" u32))) + (export "[static]t.assert-own" (func (param "self" (own $t)) (param "x" u32))) + )) + + (alias export $i "t" (type $t)) + (alias export $i "[constructor]t" (func $ctor)) + (alias export $i "[method]t.assert" (func $assert-borrow)) + (alias export $i "[static]t.assert-own" (func $assert-own)) + + (core func $ctor (canon lower (func $ctor))) + (core func $dtor (canon resource.drop $t)) + (core func $assert-own (canon lower (func $assert-own))) + (core func $assert-borrow (canon lower (func $assert-borrow))) + + (core module $m + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "dtor" (func $dtor (param i32))) + (import "" "assert-own" (func $assert-own (param i32 i32))) + (import "" "assert-borrow" (func $assert-borrow (param i32 i32))) + + (func (export "f") + (local $r1 i32) + (local $r2 i32) + + (local.set $r1 (call $ctor (i32.const 100))) + (local.set $r2 (call $ctor (i32.const 200))) + + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + + (call $assert-borrow (local.get $r2) (i32.const 200)) + (call $assert-borrow (local.get $r1) (i32.const 100)) + + (call $assert-own (local.get $r2) (i32.const 200)) + (call $dtor (local.get $r1)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "ctor" (func $ctor)) + (export "dtor" (func $dtor)) + (export "assert-own" (func $assert-own)) + (export "assert-borrow" (func $assert-borrow)) + )) + )) + (func (export "f") (canon lift (core func $i "f"))) + ) + (instance $b (instantiate $B (with "a" (instance $a)))) + (export "f" (func $b "f")) +) + +(assert_return (invoke "f")) + +;; Test destructor behavior when using the wrong resource type +(component definition $C + (type $r1 (resource (rep i32))) + (type $r2 (resource (rep i32))) + + (core func $drop1 (canon resource.drop $r1)) + (core func $drop2 (canon resource.drop $r2)) + (core func $new1 (canon resource.new $r1)) + (core func $new2 (canon resource.new $r2)) + + (core module $m2 + (import "" "drop1" (func $drop1 (param i32))) + (import "" "drop2" (func $drop2 (param i32))) + (import "" "new1" (func $new1 (param i32) (result i32))) + (import "" "new2" (func $new2 (param i32) (result i32))) + + (func (export "drop-r1-as-r2") (call $drop2 (call $new1 (i32.const 100)))) + (func (export "return-r1-as-r2") (result i32) (call $new1 (i32.const 100))) + ) + + (core instance $i2 (instantiate $m2 + (with "" (instance + (export "drop1" (func $drop1)) + (export "drop2" (func $drop2)) + (export "new1" (func $new1)) + (export "new2" (func $new2)) + )) + )) + + (export $r2' "r2" (type $r2)) + (func (export "drop-r1-as-r2") (canon lift (core func $i2 "drop-r1-as-r2"))) + (func (export "return-r1-as-r2") (result (own $r2')) (canon lift (core func $i2 "return-r1-as-r2"))) +) + +(component instance $C1 $C) +(assert_trap (invoke "drop-r1-as-r2") "handle index 1 used with the wrong type, expected guest-defined resource but found a different guest-defined resource") +(component instance $C1 $C) +(assert_trap (invoke "return-r1-as-r2") "handle index 1 used with the wrong type, expected guest-defined resource but found a different guest-defined resource") diff --git a/src/test/resources/spec-tests/wasmtime/restrictions.wast b/src/test/resources/spec-tests/wasmtime/restrictions.wast new file mode 100644 index 0000000..9bd53e7 --- /dev/null +++ b/src/test/resources/spec-tests/wasmtime/restrictions.wast @@ -0,0 +1,22 @@ +(assert_invalid + (component (import "x" (component))) + "root-level component imports are not supported") + +(assert_invalid + (component (component (export "x"))) + "exporting a component from the root component is not supported") + +(assert_invalid + (component + (import "f" (func $f)) + (export "f" (func $f)) + ) + "component export `f` is a reexport of an imported function which is not implemented") + +(assert_invalid + (component + (import "x" (component + (export "x" (type (sub resource))) + )) + ) + "root-level component imports are not supported") diff --git a/src/test/resources/spec-tests/wasmtime/simple.wast b/src/test/resources/spec-tests/wasmtime/simple.wast new file mode 100644 index 0000000..7bf2ab1 --- /dev/null +++ b/src/test/resources/spec-tests/wasmtime/simple.wast @@ -0,0 +1,42 @@ +(component) + +(component + (core module) +) + +(component + (core module) + (core module) + (core module) +) + +(component + (core module + (func (export "a") (result i32) i32.const 0) + (func (export "b") (result i64) i64.const 0) + ) + (core module + (func (export "c") (result f32) f32.const 0) + (func (export "d") (result f64) f64.const 0) + ) +) + +(assert_invalid + (component + (import "a" (component)) + ) + "root-level component imports are not supported") + +(assert_invalid + (component + (component (export "a")) + ) + "exporting a component from the root component is not supported") + +(component + (core module $m (func (export ""))) + (core instance $m (instantiate $m)) + (func (export "a") (canon lift (core func $m ""))) +) + +(assert_return (invoke "a")) diff --git a/src/test/resources/spec-tests/wasmtime/strings.wast b/src/test/resources/spec-tests/wasmtime/strings.wast new file mode 100644 index 0000000..943fd31 --- /dev/null +++ b/src/test/resources/spec-tests/wasmtime/strings.wast @@ -0,0 +1,110 @@ +;;! multi_memory = true + +;; unaligned utf16 string +(assert_trap + (component + (component $c + (core module $m + (func (export "") (param i32 i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 0) + (memory (export "memory") 1) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" string) + (canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory")) + ) + ) + + (component $c2 + (import "a" (func $f (param "a" string))) + (core module $libc + (memory (export "memory") 1) + ) + (core instance $libc (instantiate $libc)) + (core func $f (canon lower (func $f) string-encoding=utf16 (memory $libc "memory"))) + (core module $m + (import "" "" (func $f (param i32 i32))) + + (func $start (call $f (i32.const 1) (i32.const 0))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "" (func $f)))))) + ) + + (instance $c (instantiate $c)) + (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) + ) + "unaligned pointer") + +;; unaligned latin1+utf16 string, even with the latin1 encoding +(assert_trap + (component + (component $c + (core module $m + (func (export "") (param i32 i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 0) + (memory (export "memory") 1) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" string) + (canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory")) + ) + ) + + (component $c2 + (import "a" (func $f (param "a" string))) + (core module $libc + (memory (export "memory") 1) + ) + (core instance $libc (instantiate $libc)) + (core func $f (canon lower (func $f) string-encoding=latin1+utf16 (memory $libc "memory"))) + (core module $m + (import "" "" (func $f (param i32 i32))) + + (func $start (call $f (i32.const 1) (i32.const 0))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "" (func $f)))))) + ) + + (instance $c (instantiate $c)) + (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) + ) + "unaligned pointer") + +;; out of bounds utf8->utf8 string +(assert_trap + (component + (component $c + (core module $m + (func (export "") (param i32 i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 0) + (memory (export "memory") 1) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" string) + (canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory") + string-encoding=utf8) + ) + ) + + (component $c2 + (import "a" (func $f (param "a" string))) + (core module $libc + (memory (export "memory") 1) + ) + (core instance $libc (instantiate $libc)) + (core func $f (canon lower (func $f) string-encoding=utf8 (memory $libc "memory"))) + (core module $m + (import "" "" (func $f (param i32 i32))) + + (func $start (call $f (i32.const 0x8000_0000) (i32.const 1))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "" (func $f)))))) + ) + + (instance $c (instantiate $c)) + (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) + ) + "string content out-of-bounds") diff --git a/src/test/resources/spec-tests/wasmtime/tags.wast b/src/test/resources/spec-tests/wasmtime/tags.wast new file mode 100644 index 0000000..cac1fde --- /dev/null +++ b/src/test/resources/spec-tests/wasmtime/tags.wast @@ -0,0 +1,14 @@ +;;! exceptions = true + +(component + (core module $a (tag (export "t"))) + (core module $b (import "a" "t" (tag))) + + (core instance $a (instantiate $a)) + (core instance (instantiate $b (with "a" (instance $a)))) + (core instance (instantiate $b + (with "a" (instance + (export "t" (tag $a "t")) + )) + )) +) diff --git a/src/test/resources/spec-tests/wasmtime/types.wast b/src/test/resources/spec-tests/wasmtime/types.wast new file mode 100644 index 0000000..9596ebe --- /dev/null +++ b/src/test/resources/spec-tests/wasmtime/types.wast @@ -0,0 +1,355 @@ +(component + (type string) + (type (func (param "a" string))) + (type $r (record (field "x" (result)) (field "y" string))) + (type $u (variant (case "r" $r) (case "s" string))) + (type $e (result $u (error u32))) + (type (result $u)) + (type (result (error $u))) + (type (result)) + + (type (func (param "a" $e) (result (option $r)))) + + (type (variant + (case "a" string) + (case "b" u32) + (case "c" float32) + (case "d" float64) + )) + + (type $errno (enum "a" "b" "e")) + (type (list $errno)) + (type $oflags (flags "read" "write" "exclusive")) + (type (tuple $oflags $errno $r)) + + ;; primitives in functions + (type (func + (param "a" bool) + (param "b" u8) + (param "c" s8) + (param "d" u16) + (param "e" s16) + (param "f" u32) + (param "g" s32) + (param "h" u64) + (param "i" s64) + (param "j" char) + (param "k" string) + )) + + ;; primitives in types + (type bool) + (type u8) + (type s8) + (type u16) + (type s16) + (type u32) + (type s32) + (type u64) + (type s64) + (type char) + (type string) +) + +(component + (type $empty (func)) + (type (func (param "a" string) (result u32))) + (type (component)) + (core type (module)) + (core type (func)) + (type (instance)) + + (type (component + (import "x" (func (type $empty))) + (import "y" (func)) + (import "z" (component)) + + (type $t (instance)) + + (export "a" (core module)) + (export "b" (instance (type $t))) + )) + + (type (instance + (export "x" (func (type $empty))) + (export "y" (func)) + (export "z" (component)) + + (type $t (instance)) + + (export "a" (core module)) + (export "b" (instance (type $t))) + )) + + (core type (module + (import "" "" (func (param i32))) + (import "" "1" (func (result i32))) + (export "1" (global i32)) + (export "2" (memory 1)) + (export "3" (table 1 funcref)) + )) +) + +;; outer core aliases work +(component $C + (core type $f (func)) + (core type $m (module)) + + (component $C2 + (alias outer $C $f (core type $my_f)) + (import "a" (core module (type $m))) + (import "x" (core module + (alias outer $C2 $my_f (type $my_f)) + (import "" "1" (func (type $my_f))) + )) + ) +) + +;; type exports work +(component $C + (component $C2 + (type string) + (export "x" (type 0)) + ) + (instance (instantiate 0)) + (alias export 0 "x" (type)) + (export "x" (type 0)) +) + +(component + (core module $m (func (export "") (param i32) (result i32) local.get 0)) + (core instance $m (instantiate $m)) + (func (export "i-to-b") (param "a" u32) (result bool) (canon lift (core func $m ""))) + (func (export "i-to-u8") (param "a" u32) (result u8) (canon lift (core func $m ""))) + (func (export "i-to-s8") (param "a" u32) (result s8) (canon lift (core func $m ""))) + (func (export "i-to-u16") (param "a" u32) (result u16) (canon lift (core func $m ""))) + (func (export "i-to-s16") (param "a" u32) (result s16) (canon lift (core func $m ""))) +) +(assert_return (invoke "i-to-b" (u32.const 0)) (bool.const false)) +(assert_return (invoke "i-to-b" (u32.const 1)) (bool.const true)) +(assert_return (invoke "i-to-b" (u32.const 2)) (bool.const true)) +(assert_return (invoke "i-to-u8" (u32.const 0x00)) (u8.const 0)) +(assert_return (invoke "i-to-u8" (u32.const 0x01)) (u8.const 1)) +(assert_return (invoke "i-to-u8" (u32.const 0xf01)) (u8.const 1)) +(assert_return (invoke "i-to-u8" (u32.const 0xf00)) (u8.const 0)) +(assert_return (invoke "i-to-s8" (u32.const 0xffffffff)) (s8.const -1)) +(assert_return (invoke "i-to-s8" (u32.const 127)) (s8.const 127)) +(assert_return (invoke "i-to-u16" (u32.const 0)) (u16.const 0)) +(assert_return (invoke "i-to-u16" (u32.const 1)) (u16.const 1)) +(assert_return (invoke "i-to-u16" (u32.const 0xffffffff)) (u16.const 0xffff)) +(assert_return (invoke "i-to-s16" (u32.const 0)) (s16.const 0)) +(assert_return (invoke "i-to-s16" (u32.const 1)) (s16.const 1)) +(assert_return (invoke "i-to-s16" (u32.const 0xffffffff)) (s16.const -1)) + +(assert_invalid + (component + (type $t1 string) + (type $t2 (list $t1)) + (type $t3 (list $t2)) + (type $t4 (list $t3)) + (type $t5 (list $t4)) + (type $t6 (list $t5)) + (type $t7 (list $t6)) + (type $t8 (list $t7)) + (type $t9 (list $t8)) + (type $t10 (list $t9)) + (type $t11 (list $t10)) + (type $t12 (list $t11)) + (type $t13 (list $t12)) + (type $t14 (list $t13)) + (type $t15 (list $t14)) + (type $t16 (list $t15)) + (type $t17 (list $t16)) + (type $t18 (list $t17)) + (type $t19 (list $t18)) + (type $t20 (list $t19)) + (type $t21 (list $t20)) + (type $t22 (list $t21)) + (type $t23 (list $t22)) + (type $t24 (list $t23)) + (type $t25 (list $t24)) + (type $t26 (list $t25)) + (type $t27 (list $t26)) + (type $t28 (list $t27)) + (type $t29 (list $t28)) + (type $t30 (list $t29)) + (type $t31 (list $t30)) + (type $t32 (list $t31)) + (type $t33 (list $t32)) + (type $t34 (list $t33)) + (type $t35 (list $t34)) + (type $t36 (list $t35)) + (type $t37 (list $t36)) + (type $t38 (list $t37)) + (type $t39 (list $t38)) + (type $t40 (list $t39)) + (type $t41 (list $t40)) + (type $t42 (list $t41)) + (type $t43 (list $t42)) + (type $t44 (list $t43)) + (type $t45 (list $t44)) + (type $t46 (list $t45)) + (type $t47 (list $t46)) + (type $t48 (list $t47)) + (type $t49 (list $t48)) + (type $t50 (list $t49)) + (type $t51 (list $t50)) + (type $t52 (list $t51)) + (type $t53 (list $t52)) + (type $t54 (list $t53)) + (type $t55 (list $t54)) + (type $t56 (list $t55)) + (type $t57 (list $t56)) + (type $t58 (list $t57)) + (type $t59 (list $t58)) + (type $t60 (list $t59)) + (type $t61 (list $t60)) + (type $t62 (list $t61)) + (type $t63 (list $t62)) + (type $t64 (list $t63)) + (type $t65 (list $t64)) + (type $t66 (list $t65)) + (type $t67 (list $t66)) + (type $t68 (list $t67)) + (type $t69 (list $t68)) + (type $t70 (list $t69)) + (type $t71 (list $t70)) + (type $t72 (list $t71)) + (type $t73 (list $t72)) + (type $t74 (list $t73)) + (type $t75 (list $t74)) + (type $t76 (list $t75)) + (type $t77 (list $t76)) + (type $t78 (list $t77)) + (type $t79 (list $t78)) + (type $t80 (list $t79)) + (type $t81 (list $t80)) + (type $t82 (list $t81)) + (type $t83 (list $t82)) + (type $t84 (list $t83)) + (type $t85 (list $t84)) + (type $t86 (list $t85)) + (type $t87 (list $t86)) + (type $t88 (list $t87)) + (type $t89 (list $t88)) + (type $t90 (list $t89)) + (type $t91 (list $t90)) + (type $t92 (list $t91)) + (type $t93 (list $t92)) + (type $t94 (list $t93)) + (type $t95 (list $t94)) + (type $t96 (list $t95)) + (type $t97 (list $t96)) + (type $t98 (list $t97)) + (type $t99 (list $t98)) + (type $t100 (list $t99)) + (type $t101 (list $t100)) + (export "t" (type $t101)) + ) + "type nesting is too deep") + +(component + (type (instance + (export "x" (instance $x + (type $t u32) + (export "y" (type (eq $t))) + )) + (alias export $x "y" (type $t)) + (export "my-y" (type (eq $t))) + )) + + (type (component + (import "x" (instance $x + (type $t u32) + (export "y" (type (eq $t))) + )) + (alias export $x "y" (type $t)) + (export "my-y" (type (eq $t))) + )) +) + +(component + (type $t u32) + (export $t2 "t" (type $t)) + (type $r (record (field "x" $t2))) + (export "r" (type $r)) +) + +(component + (component + (import "x" (instance $i + (type $i u32) + (export "i" (type (eq $i))) + )) + (alias export $i "i" (type $i)) + (export "i" (type $i)) + ) +) + +(component + (type $u u32) + (instance $i + (export "i" (type $u)) + ) + (alias export $i "i" (type $i)) + (export "i" (type $i)) +) + +(component + (component $c + (type $t u32) + (export "t" (type $t)) + ) + (instance $c (instantiate $c)) + (export "i" (type $c "t")) +) + +(component + (component $c + (import "x" (component $c + (type $t u32) + (export "t" (type (eq $t))) + )) + (instance $c (instantiate $c)) + (export "i" (type $c "t")) + ) + + (component $x + (type $t u32) + (export "t" (type $t)) + ) + + (instance $c (instantiate $c (with "x" (component $x)))) +) + +(component + (type $t1 u64) + (import "a" (type $t2 (eq $t1))) + (import "b" (type $t3 (eq $t2))) +) + +(component + (import "a" (instance + (type $t1 u64) + (export "a" (type $t2 (eq $t1))) + (export "b" (type (eq $t2))) + )) +) + +(component + (type (export "x") (component + (type $t' (instance + (export "r" (type (sub resource))) + )) + (export "t" (instance $t (type $t'))) + )) +) + +(component + (type (export "x") (instance + (type $t' (instance + (export "r" (type (sub resource))) + )) + (export "t" (instance $t (type $t'))) + )) +) diff --git a/types/src/main/java/run/endive/cm/types/CoreAlias.java b/types/src/main/java/run/endive/cm/types/CoreAlias.java index 2bf8887..b6c2b96 100644 --- a/types/src/main/java/run/endive/cm/types/CoreAlias.java +++ b/types/src/main/java/run/endive/cm/types/CoreAlias.java @@ -26,7 +26,7 @@ public static Builder builder() { return new Builder(); } - public static class Builder { + public static final class Builder { private CoreSort sort; private CoreOuterAliasTarget target; diff --git a/types/src/main/java/run/endive/cm/types/CoreType.java b/types/src/main/java/run/endive/cm/types/CoreType.java index 3bdd1cf..21b2aa9 100644 --- a/types/src/main/java/run/endive/cm/types/CoreType.java +++ b/types/src/main/java/run/endive/cm/types/CoreType.java @@ -1,11 +1,10 @@ package run.endive.cm.types; +import java.util.Objects; import run.endive.wasm.types.CompType; import run.endive.wasm.types.RecType; import run.endive.wasm.types.SubType; -import java.util.Objects; - public final class CoreType { private final RecType recType; private final SubType subType; @@ -83,9 +82,14 @@ public CoreType build() { @Override public boolean equals(Object o) { - if (!(o instanceof CoreType)) return false; + if (!(o instanceof CoreType)) { + return false; + } CoreType coreType = (CoreType) o; - return Objects.equals(recType, coreType.recType) && Objects.equals(subType, coreType.subType) && Objects.equals(compType, coreType.compType) && Objects.equals(moduleType, coreType.moduleType); + return Objects.equals(recType, coreType.recType) + && Objects.equals(subType, coreType.subType) + && Objects.equals(compType, coreType.compType) + && Objects.equals(moduleType, coreType.moduleType); } @Override @@ -95,11 +99,15 @@ public int hashCode() { @Override public String toString() { - return "CoreType{" + - "recType=" + recType + - ", subType=" + subType + - ", compType=" + compType + - ", moduleType=" + moduleType + - '}'; + return "CoreType{" + + "recType=" + + recType + + ", subType=" + + subType + + ", compType=" + + compType + + ", moduleType=" + + moduleType + + '}'; } } diff --git a/types/src/main/java/run/endive/cm/types/CoreTypeSection.java b/types/src/main/java/run/endive/cm/types/CoreTypeSection.java index c5f7194..f03cc57 100644 --- a/types/src/main/java/run/endive/cm/types/CoreTypeSection.java +++ b/types/src/main/java/run/endive/cm/types/CoreTypeSection.java @@ -43,7 +43,9 @@ public CoreTypeSection build() { @Override public boolean equals(Object o) { - if (!(o instanceof CoreTypeSection)) return false; + if (!(o instanceof CoreTypeSection)) { + return false; + } CoreTypeSection that = (CoreTypeSection) o; return Objects.equals(coreTypes, that.coreTypes); } @@ -55,8 +57,6 @@ public int hashCode() { @Override public String toString() { - return "CoreTypeSection{" + - "coreTypes=" + coreTypes + - '}'; + return "CoreTypeSection{" + "coreTypes=" + coreTypes + '}'; } } diff --git a/types/src/main/java/run/endive/cm/types/ModuleDecl.java b/types/src/main/java/run/endive/cm/types/ModuleDecl.java index 92b57b2..c669e63 100644 --- a/types/src/main/java/run/endive/cm/types/ModuleDecl.java +++ b/types/src/main/java/run/endive/cm/types/ModuleDecl.java @@ -86,9 +86,14 @@ public ModuleDecl build() { @Override public boolean equals(Object o) { - if (!(o instanceof ModuleDecl)) return false; + if (!(o instanceof ModuleDecl)) { + return false; + } ModuleDecl that = (ModuleDecl) o; - return Objects.equals(importDecl, that.importDecl) && Objects.equals(alias, that.alias) && Objects.equals(type, that.type) && Objects.equals(exportDecl, that.exportDecl); + return Objects.equals(importDecl, that.importDecl) + && Objects.equals(alias, that.alias) + && Objects.equals(type, that.type) + && Objects.equals(exportDecl, that.exportDecl); } @Override @@ -98,11 +103,15 @@ public int hashCode() { @Override public String toString() { - return "ModuleDecl{" + - "importDecl=" + importDecl + - ", alias=" + alias + - ", type=" + type + - ", exportDecl=" + exportDecl + - '}'; + return "ModuleDecl{" + + "importDecl=" + + importDecl + + ", alias=" + + alias + + ", type=" + + type + + ", exportDecl=" + + exportDecl + + '}'; } } diff --git a/types/src/main/java/run/endive/cm/types/ModuleType.java b/types/src/main/java/run/endive/cm/types/ModuleType.java index 368e1ee..056f5ec 100644 --- a/types/src/main/java/run/endive/cm/types/ModuleType.java +++ b/types/src/main/java/run/endive/cm/types/ModuleType.java @@ -35,7 +35,9 @@ public ModuleType build() { @Override public boolean equals(Object o) { - if (!(o instanceof ModuleType)) return false; + if (!(o instanceof ModuleType)) { + return false; + } ModuleType that = (ModuleType) o; return Objects.equals(moduleDecls, that.moduleDecls); } @@ -47,8 +49,6 @@ public int hashCode() { @Override public String toString() { - return "ModuleType{" + - "moduleDecls=" + moduleDecls + - '}'; + return "ModuleType{" + "moduleDecls=" + moduleDecls + '}'; } } diff --git a/types/src/main/java/run/endive/cm/types/WasmComponent.java b/types/src/main/java/run/endive/cm/types/WasmComponent.java index b060f6f..b529cac 100644 --- a/types/src/main/java/run/endive/cm/types/WasmComponent.java +++ b/types/src/main/java/run/endive/cm/types/WasmComponent.java @@ -53,7 +53,9 @@ public WasmComponent build() { @Override public boolean equals(Object o) { - if (!(o instanceof WasmComponent)) return false; + if (!(o instanceof WasmComponent)) { + return false; + } WasmComponent that = (WasmComponent) o; return Objects.equals(coreTypeSections, that.coreTypeSections); } @@ -65,8 +67,6 @@ public int hashCode() { @Override public String toString() { - return "WasmComponent{" + - "coreTypeSections=" + coreTypeSections + - '}'; + return "WasmComponent{" + "coreTypeSections=" + coreTypeSections + '}'; } } diff --git a/wasm-tools/pom.xml b/wasm-tools/pom.xml new file mode 100644 index 0000000..455c205 --- /dev/null +++ b/wasm-tools/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + run.endive.cm + endive-cm + 999-SNAPSHOT + + wasm-tools + jar + + Endive CM - wasm-tools Component Commands + Wrappers of wasm-tools component commands for Endive Component Model + + + + io.roastedroot + zerofs + + + run.endive + log + + + run.endive + runtime + + + run.endive + wasi + + + run.endive + wasm + + + run.endive + wasm-tools + + + org.junit.jupiter + junit-jupiter-api + test + + + diff --git a/parser/src/main/java/run/endive/cm/tools/ComponentValidate.java b/wasm-tools/src/main/java/run/endive/cm/tools/ComponentValidate.java similarity index 100% rename from parser/src/main/java/run/endive/cm/tools/ComponentValidate.java rename to wasm-tools/src/main/java/run/endive/cm/tools/ComponentValidate.java diff --git a/parser/src/main/java/run/endive/cm/tools/ComponentValidateException.java b/wasm-tools/src/main/java/run/endive/cm/tools/ComponentValidateException.java similarity index 100% rename from parser/src/main/java/run/endive/cm/tools/ComponentValidateException.java rename to wasm-tools/src/main/java/run/endive/cm/tools/ComponentValidateException.java From 224935d0c1db73c5fbfa4a052bf46571b928d9b7 Mon Sep 17 00:00:00 2001 From: Jeremy Grelle Date: Tue, 23 Jun 2026 12:03:41 -0400 Subject: [PATCH 6/8] Correct spec download script and remove mistakenly added files. --- Readme.md | 10 +- .../spec-tests/async/async-calls-sync.wast | 251 --- .../spec-tests/async/cancel-stream.wast | 202 -- .../spec-tests/async/cancel-subtask.wast | 201 -- .../spec-tests/async/cancellable.wast | 325 --- .../spec-tests/async/closed-stream.wast | 102 - .../spec-tests/async/cross-abi-calls.wast | 519 ----- .../spec-tests/async/cross-task-future.wast | 103 - .../resources/spec-tests/async/deadlock.wast | 73 - .../spec-tests/async/dont-block-start.wast | 50 - .../async/drop-cross-task-borrow.wast | 309 --- .../spec-tests/async/drop-stream.wast | 160 -- .../spec-tests/async/drop-subtask.wast | 140 -- .../spec-tests/async/drop-waitable-set.wast | 84 - .../spec-tests/async/empty-wait.wast | 199 -- .../spec-tests/async/futures-must-write.wast | 118 - .../async/partial-stream-copies.wast | 238 -- .../spec-tests/async/passing-resources.wast | 176 -- .../async/same-component-stream-future.wast | 259 --- .../spec-tests/async/sync-barges-in.wast | 311 --- .../spec-tests/async/sync-streams.wast | 178 -- .../async/trap-if-block-and-sync.wast | 334 --- .../spec-tests/async/trap-if-done.wast | 470 ---- .../async/trap-if-sync-and-waitable-set.wast | 288 --- .../trap-if-transfer-in-waitable-set.wast | 51 - .../spec-tests/async/trap-on-reenter.wast | 110 - .../validate-no-async-abi-for-sync-type.wast | 27 - .../async/validate-no-stream-char.wast | 7 - .../async/wait-during-callback.wast | 77 - .../spec-tests/async/zero-length.wast | 223 -- .../resources/spec-tests/names/kebab.wast | 60 - .../resources/multiple-resources.wast | 170 -- .../spec-tests/validation/implements.wast | 108 - .../spec-tests/values/post-return.wast | 384 ---- .../resources/spec-tests/values/strings.wast | 136 -- .../spec-tests/wasm-tools/adapt.wast | 287 --- .../spec-tests/wasm-tools/alias.wast | 301 --- .../resources/spec-tests/wasm-tools/big.wast | 36 - .../spec-tests/wasm-tools/definedtypes.wast | 123 -- .../spec-tests/wasm-tools/empty.wast | 4 - .../spec-tests/wasm-tools/example.wast | 17 - .../wasm-tools/export-ascription.wast | 44 - .../wasm-tools/export-introduces-alias.wast | 48 - .../spec-tests/wasm-tools/export.wast | 63 - .../resources/spec-tests/wasm-tools/func.wast | 146 -- .../spec-tests/wasm-tools/import.wast | 359 --- .../wasm-tools/imports-exports.wast | 26 - .../spec-tests/wasm-tools/inline-exports.wast | 9 - .../spec-tests/wasm-tools/instance-type.wast | 234 -- .../spec-tests/wasm-tools/instantiate.wast | 976 -------- .../spec-tests/wasm-tools/invalid.wast | 34 - .../resources/spec-tests/wasm-tools/link.wast | 14 - .../wasm-tools/lots-of-aliases.wast | 179 -- .../spec-tests/wasm-tools/lower.wast | 17 - .../spec-tests/wasm-tools/memory64.wast | 55 - .../spec-tests/wasm-tools/module-link.wast | 98 - .../spec-tests/wasm-tools/more-flags.wast | 41 - .../spec-tests/wasm-tools/naming.wast | 127 -- .../spec-tests/wasm-tools/nested-modules.wast | 50 - .../spec-tests/wasm-tools/resources.wast | 1195 ---------- .../resources/spec-tests/wasm-tools/tags.wast | 30 - .../wasm-tools/type-export-restrictions.wast | 504 ----- .../spec-tests/wasm-tools/types.wast | 374 ---- .../spec-tests/wasm-tools/very-nested.wast | 1954 ----------------- .../spec-tests/wasm-tools/virtualize.wast | 119 - .../spec-tests/wasm-tools/wrong-order.wast | 11 - .../spec-tests/wasmtime/adapter.wast | 137 -- .../spec-tests/wasmtime/aliasing.wast | 29 - .../resources/spec-tests/wasmtime/fused.wast | 1391 ------------ .../resources/spec-tests/wasmtime/import.wast | 20 - .../spec-tests/wasmtime/instance.wast | 327 --- .../spec-tests/wasmtime/linking.wast | 18 - .../spec-tests/wasmtime/modules.wast | 479 ---- .../resources/spec-tests/wasmtime/nested.wast | 451 ---- .../spec-tests/wasmtime/resources.wast | 1091 --------- .../spec-tests/wasmtime/restrictions.wast | 22 - .../resources/spec-tests/wasmtime/simple.wast | 42 - .../spec-tests/wasmtime/strings.wast | 110 - .../resources/spec-tests/wasmtime/tags.wast | 14 - .../resources/spec-tests/wasmtime/types.wast | 355 --- ...date-spec-tests.sh => update-spec-tests.sh | 2 +- 81 files changed, 4 insertions(+), 18412 deletions(-) delete mode 100644 src/test/resources/spec-tests/async/async-calls-sync.wast delete mode 100644 src/test/resources/spec-tests/async/cancel-stream.wast delete mode 100644 src/test/resources/spec-tests/async/cancel-subtask.wast delete mode 100644 src/test/resources/spec-tests/async/cancellable.wast delete mode 100644 src/test/resources/spec-tests/async/closed-stream.wast delete mode 100644 src/test/resources/spec-tests/async/cross-abi-calls.wast delete mode 100644 src/test/resources/spec-tests/async/cross-task-future.wast delete mode 100644 src/test/resources/spec-tests/async/deadlock.wast delete mode 100644 src/test/resources/spec-tests/async/dont-block-start.wast delete mode 100644 src/test/resources/spec-tests/async/drop-cross-task-borrow.wast delete mode 100644 src/test/resources/spec-tests/async/drop-stream.wast delete mode 100644 src/test/resources/spec-tests/async/drop-subtask.wast delete mode 100644 src/test/resources/spec-tests/async/drop-waitable-set.wast delete mode 100644 src/test/resources/spec-tests/async/empty-wait.wast delete mode 100644 src/test/resources/spec-tests/async/futures-must-write.wast delete mode 100644 src/test/resources/spec-tests/async/partial-stream-copies.wast delete mode 100644 src/test/resources/spec-tests/async/passing-resources.wast delete mode 100644 src/test/resources/spec-tests/async/same-component-stream-future.wast delete mode 100644 src/test/resources/spec-tests/async/sync-barges-in.wast delete mode 100644 src/test/resources/spec-tests/async/sync-streams.wast delete mode 100644 src/test/resources/spec-tests/async/trap-if-block-and-sync.wast delete mode 100644 src/test/resources/spec-tests/async/trap-if-done.wast delete mode 100644 src/test/resources/spec-tests/async/trap-if-sync-and-waitable-set.wast delete mode 100644 src/test/resources/spec-tests/async/trap-if-transfer-in-waitable-set.wast delete mode 100644 src/test/resources/spec-tests/async/trap-on-reenter.wast delete mode 100644 src/test/resources/spec-tests/async/validate-no-async-abi-for-sync-type.wast delete mode 100644 src/test/resources/spec-tests/async/validate-no-stream-char.wast delete mode 100644 src/test/resources/spec-tests/async/wait-during-callback.wast delete mode 100644 src/test/resources/spec-tests/async/zero-length.wast delete mode 100644 src/test/resources/spec-tests/names/kebab.wast delete mode 100644 src/test/resources/spec-tests/resources/multiple-resources.wast delete mode 100644 src/test/resources/spec-tests/validation/implements.wast delete mode 100644 src/test/resources/spec-tests/values/post-return.wast delete mode 100644 src/test/resources/spec-tests/values/strings.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/adapt.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/alias.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/big.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/definedtypes.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/empty.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/example.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/export-ascription.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/export-introduces-alias.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/export.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/func.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/import.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/imports-exports.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/inline-exports.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/instance-type.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/instantiate.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/invalid.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/link.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/lower.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/memory64.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/module-link.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/more-flags.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/naming.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/nested-modules.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/resources.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/tags.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/types.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/very-nested.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/virtualize.wast delete mode 100644 src/test/resources/spec-tests/wasm-tools/wrong-order.wast delete mode 100644 src/test/resources/spec-tests/wasmtime/adapter.wast delete mode 100644 src/test/resources/spec-tests/wasmtime/aliasing.wast delete mode 100644 src/test/resources/spec-tests/wasmtime/fused.wast delete mode 100644 src/test/resources/spec-tests/wasmtime/import.wast delete mode 100644 src/test/resources/spec-tests/wasmtime/instance.wast delete mode 100644 src/test/resources/spec-tests/wasmtime/linking.wast delete mode 100644 src/test/resources/spec-tests/wasmtime/modules.wast delete mode 100644 src/test/resources/spec-tests/wasmtime/nested.wast delete mode 100644 src/test/resources/spec-tests/wasmtime/resources.wast delete mode 100644 src/test/resources/spec-tests/wasmtime/restrictions.wast delete mode 100644 src/test/resources/spec-tests/wasmtime/simple.wast delete mode 100644 src/test/resources/spec-tests/wasmtime/strings.wast delete mode 100644 src/test/resources/spec-tests/wasmtime/tags.wast delete mode 100644 src/test/resources/spec-tests/wasmtime/types.wast rename parser/update-spec-tests.sh => update-spec-tests.sh (97%) diff --git a/Readme.md b/Readme.md index cd558a5..a658d07 100644 --- a/Readme.md +++ b/Readme.md @@ -69,16 +69,12 @@ mvn -Dquickly Then build endive-cm: The tests of the `parser` module rely upon downloading a local copy of the .wast tests from the Component Model spec -repository. A shell script is provided that fetches the most recent copy of the .wast tests. To download (and update) -the .wast tests: -```shell -cd endive-cm -./parser/update-spec-tests.sh -``` +repository. A shell script is provided that fetches the most recent copy of the .wast tests. -Once the .wast tests have been downloaded, build endive-cm: +To build endive-cm: ```sh cd endive-cm +./update-spec-tests.sh mvn clean install ``` diff --git a/src/test/resources/spec-tests/async/async-calls-sync.wast b/src/test/resources/spec-tests/async/async-calls-sync.wast deleted file mode 100644 index 5172bb4..0000000 --- a/src/test/resources/spec-tests/async/async-calls-sync.wast +++ /dev/null @@ -1,251 +0,0 @@ -;; This test contains 3 components, $AsyncInner, $SyncMiddle and $AsyncOuter, -;; where there are two instances of $SyncMiddle that import a single instance -;; of $AsyncInner, and $AsyncOuter imports all 3 preceding instances. -;; -;; $AsyncOuter.run asynchronously calls $SyncMiddle.sync-func twice concurrently -;; in each instance (4 total calls), hitting the synchronous backpressure case -;; in 2 of the 4 calls. -;; -;; $SyncMiddle.sync-func makes a blocking call to $AsyncInner.blocking-call -;; which is used to emulate a host call that blocks until $AsyncOuter.run -;; calls $AsyncInner.unblock to unblock all the 'blocking-call' calls. -(component - (component $AsyncInner - (core module $CoreAsyncInner - (import "" "context.set" (func $context.set (param i32))) - (import "" "context.get" (func $context.get (result i32))) - (import "" "task.return0" (func $task.return0)) - (import "" "task.return1" (func $task.return1 (param i32))) - - (memory 1) - (global $blocked (mut i32) (i32.const 1)) - (global $counter (mut i32) (i32.const 2)) - - ;; 'blocking-call' cooperatively "spin-waits" until $blocked is 0. - (func $blocking-call (export "blocking-call") (result i32) - (call $context.set (global.get $counter)) - (global.set $counter (i32.add (i32.const 1) (global.get $counter))) - (i32.const 1 (; YIELD ;)) - ) - (func $blocking-call-cb (export "blocking-call-cb") (param i32 i32 i32) (result i32) - (if (i32.eqz (global.get $blocked)) (then - (call $task.return1 (call $context.get)) - (return (i32.const 0 (; EXIT ;))) - )) - (i32.const 1 (; YIELD ;)) - ) - (func $unblock (export "unblock") (result i32) - (global.set $blocked (i32.const 0)) - (call $task.return0) - (i32.const 0 (; EXIT ;)) - ) - (func $unblock-cb (export "unblock-cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (canon task.return (core func $task.return0)) - (canon task.return (result u32) (core func $task.return1)) - (canon context.set i32 0 (core func $context.set)) - (canon context.get i32 0 (core func $context.get)) - (core instance $core_async_inner (instantiate $CoreAsyncInner (with "" (instance - (export "task.return0" (func $task.return0)) - (export "task.return1" (func $task.return1)) - (export "context.set" (func $context.set)) - (export "context.get" (func $context.get)) - )))) - (func (export "blocking-call") async (result u32) (canon lift - (core func $core_async_inner "blocking-call") - async (callback (func $core_async_inner "blocking-call-cb")) - )) - (func (export "unblock") async (canon lift - (core func $core_async_inner "unblock") - async (callback (func $core_async_inner "unblock-cb")) - )) - ) - - (component $SyncMiddle - (import "blocking-call" (func $blocking-call async (result u32))) - (core module $CoreSyncMiddle - (import "" "blocking-call" (func $blocking-call (result i32))) - (func $sync-func (export "sync-func") (result i32) - (call $blocking-call) - ) - ) - (canon lower (func $blocking-call) (core func $blocking-call')) - (core instance $core_sync_middle (instantiate $CoreSyncMiddle (with "" (instance - (export "blocking-call" (func $blocking-call')) - )))) - (func (export "sync-func") async (result u32) (canon lift - (core func $core_sync_middle "sync-func") - )) - ) - - (component $AsyncMiddle - (import "blocking-call" (func $blocking-call async (result u32))) - (core module $CoreSyncMiddle - (import "" "task.return" (func $task.return (param i32))) - (import "" "blocking-call" (func $blocking-call (result i32))) - (func $sync-func (export "sync-func") (result i32) - (call $task.return (call $blocking-call)) - (i32.const 0 (; EXIT ;)) - ) - (func $sync-func-cb (export "sync-func-cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (canon task.return (result u32) (core func $task.return)) - (canon lower (func $blocking-call) (core func $blocking-call')) - (core instance $core_sync_middle (instantiate $CoreSyncMiddle (with "" (instance - (export "task.return" (func $task.return)) - (export "blocking-call" (func $blocking-call')) - )))) - (func (export "sync-func") async (result u32) (canon lift - (core func $core_sync_middle "sync-func") - async (callback (func $core_sync_middle "sync-func-cb")) - )) - ) - - (component $AsyncOuter - (import "unblock" (func $unblock async)) - (import "sync-func1" (func $sync-func1 async (result u32))) - (import "sync-func2" (func $sync-func2 async (result u32))) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CoreAsyncOuter - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "subtask.drop" (func $subtask.drop (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "unblock" (func $unblock)) - (import "" "sync-func1" (func $sync-func1 (param i32) (result i32))) - (import "" "sync-func2" (func $sync-func2 (param i32) (result i32))) - - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - ;; set $remain to the number of tasks to wait to complete - (global $remain (mut i32) (i32.const 4)) - - (func $run (export "run") (result i32) - (local $ret i32) - - ;; call 'sync-func1' and 'sync-func2' asynchronously, both of which will block - ;; (on $AsyncInner.blocking-call). because 'sync-func1/2' are in different instances, - ;; both calls will reach the STARTED state. - (local.set $ret (call $sync-func1 (i32.const 8))) - (if (i32.ne (i32.const 0x21 (; STARTED=1 | (subtask=2 << 4) ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (i32.const 2) (global.get $ws)) - (local.set $ret (call $sync-func2 (i32.const 12))) - (if (i32.ne (i32.const 0x31 (; STARTED=1 | (subtask=3 << 4) ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (i32.const 3) (global.get $ws)) - - ;; now start another pair of 'sync-func1/2' calls, both of which should see auto - ;; backpressure and get stuck in the STARTING state. - (local.set $ret (call $sync-func1 (i32.const 16))) - (if (i32.ne (i32.const 0x40 (; STARTING=0 | (subtask=4 << 4) ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (i32.const 4) (global.get $ws)) - (local.set $ret (call $sync-func2 (i32.const 20))) - (if (i32.ne (i32.const 0x50 (; STARTING=0 | (subtask=5 << 4) ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (i32.const 5) (global.get $ws)) - - ;; unblock all the tasks and start waiting to complete - (call $unblock) - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) - ) - (func $run-cb (export "run-cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - (local $ret i32) - - ;; confirm we only receive SUBTASK events. - (if (i32.ne (local.get $event_code) (i32.const 1 (; SUBTASK ;))) - (then unreachable)) - - ;; if we receive a SUBTASK STARTED event, it should only be for the 3rd or - ;; 4th subtask (at indices 4/5, resp), so keep waiting for completion - (if (i32.eq (local.get $payload) (i32.const 1 (; STARTED ;))) (then - (if (i32.and - (i32.ne (local.get $index) (i32.const 4)) - (i32.ne (local.get $index) (i32.const 5))) - (then unreachable)) - (return (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4)))) - )) - - ;; when we receive a SUBTASK RETURNED event, check the return value is equal to the - ;; subtask index (which we've ensured by having $AsyncInner.$counter start at 2, the - ;; first subtask index. The address of the return buffer is the index*4. - (if (i32.ne (local.get $payload) (i32.const 2 (; RETURNED ;))) - (then unreachable)) - (if (i32.ne (local.get $index) (i32.load (i32.mul (local.get $index) (i32.const 4)))) - (then unreachable)) - - ;; decrement $remain and exit if 0 - (call $subtask.drop (local.get $index)) - (global.set $remain (i32.sub (global.get $remain) (i32.const 1))) - (if (i32.gt_u (global.get $remain) (i32.const 0)) (then - (return (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4)))) - )) - (call $task.return (i32.const 42)) - (i32.const 0 (; EXIT ;)) - ) - ) - (canon task.return (result u32) (core func $task.return)) - (canon subtask.drop (core func $subtask.drop)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon lower (func $unblock) (core func $unblock)) - (canon lower (func $sync-func1) async (memory $memory "mem") (core func $sync-func1')) - (canon lower (func $sync-func2) async (memory $memory "mem") (core func $sync-func2')) - (core instance $em (instantiate $CoreAsyncOuter (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "subtask.drop" (func $subtask.drop)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "unblock" (func $unblock)) - (export "sync-func1" (func $sync-func1')) - (export "sync-func2" (func $sync-func2')) - )))) - (func (export "run") async (result u32) (canon lift - (core func $em "run") - async (callback (func $em "run-cb")) - )) - ) - - ;; run1 uses $SyncMiddle - (instance $async_inner1 (instantiate $AsyncInner)) - (instance $sync_middle11 (instantiate $SyncMiddle - (with "blocking-call" (func $async_inner1 "blocking-call")) - )) - (instance $sync_middle12 (instantiate $SyncMiddle - (with "blocking-call" (func $async_inner1 "blocking-call")) - )) - (instance $async_outer1 (instantiate $AsyncOuter - (with "unblock" (func $async_inner1 "unblock")) - (with "sync-func1" (func $sync_middle11 "sync-func")) - (with "sync-func2" (func $sync_middle12 "sync-func")) - )) - (func (export "run1") (alias export $async_outer1 "run")) - - ;; run2 uses $AsyncMiddle - (instance $async_inner2 (instantiate $AsyncInner)) - (instance $sync_middle21 (instantiate $SyncMiddle - (with "blocking-call" (func $async_inner2 "blocking-call")) - )) - (instance $sync_middle22 (instantiate $AsyncMiddle - (with "blocking-call" (func $async_inner2 "blocking-call")) - )) - (instance $async_outer2 (instantiate $AsyncOuter - (with "unblock" (func $async_inner2 "unblock")) - (with "sync-func1" (func $sync_middle21 "sync-func")) - (with "sync-func2" (func $sync_middle22 "sync-func")) - )) - (func (export "run2") (alias export $async_outer2 "run")) -) -(assert_return (invoke "run1") (u32.const 42)) -(assert_return (invoke "run2") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/cancel-stream.wast b/src/test/resources/spec-tests/async/cancel-stream.wast deleted file mode 100644 index 336b5ac..0000000 --- a/src/test/resources/spec-tests/async/cancel-stream.wast +++ /dev/null @@ -1,202 +0,0 @@ -;; This test contains two components $C and $D that test cancelling reads -;; and writes in the presence and absence of partial reads/writes. -;; -;; $C exports a function 'start-stream' that creates and holds onto a writable -;; stream in the global $sw as well as various operations that operate on $sw. -;; $D calls $C.start-stream to get the readable end and then drives the test. -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - (global $sw (mut i32) (i32.const 0)) - - (func $start-stream (export "start-stream") (result i32) - ;; create a new stream, return the readable end to the caller - (local $ret64 i64) - (local.set $ret64 (call $stream.new)) - (global.set $sw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (i32.wrap_i64 (local.get $ret64)) - ) - - (func $write4 (export "write4") - ;; write 6 bytes into the stream, expecting to rendezvous with a stream.read - (local $ret i32) - (i32.store (i32.const 8) (i32.const 0xabcd)) - (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 4))) - (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - ) - - (func $write4-and-drop (export "write4-and-drop") - (call $write4) - (call $stream.drop-writable (global.get $sw)) - ) - - (func $start-blocking-write (export "start-blocking-write") - (local $ret i32) - - ;; prepare the write buffer - (i64.store (i32.const 8) (i64.const 0x123456789abcdef)) - - ;; start one blocking write and immediately cancel it - (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 8))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $stream.cancel-write (global.get $sw))) - (if (i32.ne (i32.const 0x2 (; CANCELLED ;)) (local.get $ret)) - (then unreachable)) - - ;; start a second blockign write and leave it pending - (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 8))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - ) - - (func $cancel-after-read4 (export "cancel-after-read4") - (local $ret i32) - (local.set $ret (call $stream.cancel-write (global.get $sw))) - (if (i32.ne (i32.const 0x42 (; CANCELLED=2 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - ) - ) - (type $ST (stream u8)) - (canon task.return (result u32) (core func $task.return)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.cancel-write $ST (core func $stream.cancel-write)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "stream.new" (func $stream.new)) - (export "stream.write" (func $stream.write)) - (export "stream.cancel-write" (func $stream.cancel-write)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (func (export "start-stream") async (result (stream u8)) (canon lift (core func $cm "start-stream"))) - (func (export "write4") async (canon lift (core func $cm "write4"))) - (func (export "write4-and-drop") async (canon lift (core func $cm "write4-and-drop"))) - (func (export "start-blocking-write") async (canon lift (core func $cm "start-blocking-write"))) - (func (export "cancel-after-read4") async (canon lift (core func $cm "cancel-after-read4"))) - ) - - (component $D - (import "c" (instance $c - (export "start-stream" (func async (result (stream u8)))) - (export "write4" (func async)) - (export "write4-and-drop" (func async)) - (export "start-blocking-write" (func async)) - (export "cancel-after-read4" (func async)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.cancel-read" (func $stream.cancel-read (param i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "start-stream" (func $start-stream (result i32))) - (import "" "write4" (func $write4)) - (import "" "write4-and-drop" (func $write4-and-drop)) - (import "" "start-blocking-write" (func $start-blocking-write)) - (import "" "cancel-after-read4" (func $cancel-after-read4)) - - (func $run (export "run") (result i32) - (local $ret i32) - (local $sr i32) - - ;; call 'start-stream' to get the stream we'll be working with - (local.set $sr (call $start-stream)) - (if (i32.ne (i32.const 1) (local.get $sr)) - (then unreachable)) - - ;; start read that will block - (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) - (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) - (then unreachable)) - - ;; cancelling it will finish without anything having been written - (local.set $ret (call $stream.cancel-read (local.get $sr))) - (if (i32.ne (i32.const 0x2 (; CANCELLED ;)) (local.get $ret)) - (then unreachable)) - - ;; read, block, call $C to write 4 bytes into the buffer, - ;; then cancel, which should show "4+cancelled" - (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) - (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) - (then unreachable)) - (call $write4) - (local.set $ret (call $stream.cancel-read (local.get $sr))) - (if (i32.ne (i32.const 0x42 (; CANCELLED=2 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0xabcd) (i32.load (i32.const 8))) - (then unreachable)) - - ;; read, block, call $C to write 4 bytes into the buffer and drop, then cancel - (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) - (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) - (then unreachable)) - (call $write4-and-drop) - (local.set $ret (call $stream.cancel-read (local.get $sr))) - (if (i32.ne (i32.const 0x41 (; DROPPED=1 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0xabcd) (i32.load (i32.const 8))) - (then unreachable)) - (call $stream.drop-readable (local.get $sr)) - - ;; get a new $sr - (local.set $sr (call $start-stream)) - (if (i32.ne (i32.const 1) (local.get $sr)) - (then unreachable)) - - ;; start outstanding write in $C, read 4 of it, then call back into $C - ;; which will cancel and see 4 written. - (call $start-blocking-write) - (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 4))) - (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0x89abcdef) (i32.load (i32.const 8))) - (then unreachable)) - (call $cancel-after-read4) - - ;; return 42 to the top-level assert_return - (i32.const 42) - ) - ) - (type $ST (stream u8)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.cancel-read $ST (core func $stream.cancel-read)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon lower (func $c "start-stream") (core func $start-stream')) - (canon lower (func $c "write4") (core func $write4')) - (canon lower (func $c "write4-and-drop") (core func $write4-and-drop')) - (canon lower (func $c "start-blocking-write") (core func $start-blocking-write')) - (canon lower (func $c "cancel-after-read4") (core func $cancel-after-read4')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "stream.read" (func $stream.read)) - (export "stream.cancel-read" (func $stream.cancel-read)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "start-stream" (func $start-stream')) - (export "write4" (func $write4')) - (export "write4-and-drop" (func $write4-and-drop')) - (export "start-blocking-write" (func $start-blocking-write')) - (export "cancel-after-read4" (func $cancel-after-read4')) - )))) - (func (export "run") async (result u32) (canon lift (core func $dm "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "run") (alias export $d "run")) -) -(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/cancel-subtask.wast b/src/test/resources/spec-tests/async/cancel-subtask.wast deleted file mode 100644 index 57a0f33..0000000 --- a/src/test/resources/spec-tests/async/cancel-subtask.wast +++ /dev/null @@ -1,201 +0,0 @@ -;; This test contains two components $C and $D where $D imports and calls $C. -;; $D.run calls $C.f, which blocks on an empty waitable set -;; $D.run then subtask.cancels $C.f, which resumes $C.f which promptly resolves -;; without returning a value. -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.cancel" (func $task.cancel)) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - - ;; $ws is waited on by 'f' - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - (func $f (export "f") (result i32) - ;; wait on $ws which is currently empty, expected to get cancelled - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) - ) - (func $f_cb (export "f_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - ;; confirm that we've received a cancellation request - (if (i32.ne (local.get $event_code) (i32.const 6 (; TASK_CANCELLED ;))) - (then unreachable)) - (if (i32.ne (local.get $index) (i32.const 0)) - (then unreachable)) - (if (i32.ne (local.get $payload) (i32.const 0)) - (then unreachable)) - - ;; finish without returning a value - (call $task.cancel) - (i32.const 0 (; EXIT ;)) - ) - - (func $g (export "g") (param $futr i32) (result i32) - (local $ret i32) - (local $event_code i32) - - ;; perform a future.read which will block, waiting for the caller to write - (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (local.get $futr) (global.get $ws)) - - ;; wait on $ws synchronously, don't expect cancellation - (local.set $event_code (call $waitable-set.wait (global.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) - (then unreachable)) - - ;; finish returning a value - (i32.const 42) - ) - ) - (type $FT (future)) - (canon task.cancel (core func $task.cancel)) - (canon future.read $FT async (memory $memory "mem") (core func $future.read)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.cancel" (func $task.cancel)) - (export "future.read" (func $future.read)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - )))) - (func (export "f") async (result u32) (canon lift - (core func $cm "f") - async (callback (func $cm "f_cb")) - )) - (func (export "g") async (param "fut" $FT) (result u32) (canon lift - (core func $cm "g") - )) - ) - - (component $D - (type $FT (future)) - (import "f" (func $f async (result u32))) - (import "g" (func $g async (param "fut" $FT) (result u32))) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) - (import "" "subtask.drop" (func $subtask.drop (param i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "f" (func $f (param i32) (result i32))) - (import "" "g" (func $g (param i32 i32) (result i32))) - - (func $run (export "run") (result i32) - (local $ret i32) (local $ret64 i64) - (local $retp i32) (local $retp1 i32) (local $retp2 i32) - (local $subtask i32) - (local $event_code i32) - (local $futr i32) (local $futw i32) - (local $ws i32) - - ;; call 'f'; it should block - (local.set $retp (i32.const 4)) - (i32.store (local.get $retp) (i32.const 0xbad0bad0)) - (local.set $ret (call $f (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; cancel 'f'; it should complete without blocking - (local.set $ret (call $subtask.cancel (local.get $subtask))) - (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (local.get $ret)) - (then unreachable)) - - ;; The $retp memory shouldn't have changed - (if (i32.ne (i32.load (local.get $retp)) (i32.const 0xbad0bad0)) - (then unreachable)) - - (call $subtask.drop (local.get $subtask)) - - ;; create future that g will wait on - (local.set $ret64 (call $future.new)) - (local.set $futr (i32.wrap_i64 (local.get $ret64))) - (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - - ;; call 'g'; it should block - (local.set $retp1 (i32.const 4)) - (local.set $retp2 (i32.const 8)) - (i32.store (local.get $retp1) (i32.const 0xbad0bad0)) - (i32.store (local.get $retp2) (i32.const 0xbad0bad0)) - (local.set $ret (call $g (local.get $futr) (local.get $retp1))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; cancel 'g'; it should block - (local.set $ret (call $subtask.cancel (local.get $subtask))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; future.write, unblocking 'g' - (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - ;; wait to see 'g' finish and check its return value - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtask) (local.get $ws)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load (local.get $retp1))) - (then unreachable)) - - ;; return to the top-level assert_return - (i32.const 42) - ) - ) - (canon subtask.cancel async (core func $subtask.cancel)) - (canon subtask.drop (core func $subtask.drop)) - (canon future.new $FT (core func $future.new)) - (canon future.write $FT async (memory $memory "mem") (core func $future.write)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon lower (func $f) async (memory $memory "mem") (core func $f')) - (canon lower (func $g) async (memory $memory "mem") (core func $g')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "subtask.cancel" (func $subtask.cancel)) - (export "subtask.drop" (func $subtask.drop)) - (export "future.new" (func $future.new)) - (export "future.write" (func $future.write)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "f" (func $f')) - (export "g" (func $g')) - )))) - (func (export "run") async (result u32) (canon lift (core func $dm "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D - (with "f" (func $c "f")) - (with "g" (func $c "g")) - )) - (func (export "run") (alias export $d "run")) -) -(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/cancellable.wast b/src/test/resources/spec-tests/async/cancellable.wast deleted file mode 100644 index 2c5614c..0000000 --- a/src/test/resources/spec-tests/async/cancellable.wast +++ /dev/null @@ -1,325 +0,0 @@ -;; This test exercises the 'cancellable' immediate on waitable-set.wait, -;; waitable-set.poll, and thread.yield. -;; -;; Component $C exports five async callback-lifted functions that block in -;; their initial core function (the callbacks are never invoked): -;; wait-cancel: blocks on cancellable waitable-set.wait, expects TASK_CANCELLED -;; yield-cancel: yields with cancellable, caller cancels during yield -;; poll-cancel-pending: blocks on non-cancellable wait, then polls with cancellable -;; yield-cancel-pending: blocks on non-cancellable wait, then yields with cancellable -;; -;; Component $D calls each function and cancels it, verifying the cancel is -;; delivered correctly through the cancellable built-in in each case. -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.cancel" (func $task.cancel)) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait-cancellable" (func $waitable-set.wait-cancellable (param i32 i32) (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "waitable-set.poll-cancellable" (func $waitable-set.poll-cancellable (param i32 i32) (result i32))) - (import "" "thread.yield-cancellable" (func $thread.yield-cancellable (result i32))) - - ;; Test 1: direct cancel delivery through cancellable waitable-set.wait - (func $wait-cancel (export "wait-cancel") (result i32) - (local $event_code i32) - (local $ws i32) - (local.set $ws (call $waitable-set.new)) - ;; wait on empty waitable set with cancellable; blocks until cancelled - (local.set $event_code (call $waitable-set.wait-cancellable (local.get $ws) (i32.const 0))) - (if (i32.ne (local.get $event_code) (i32.const 6 (; TASK_CANCELLED ;))) - (then unreachable)) - (call $task.cancel) - (i32.const 0 (; EXIT ;)) - ) - - ;; Test 2: direct cancel delivery through cancellable thread.yield - (func $yield-cancel (export "yield-cancel") (result i32) - (local $ret i32) - ;; yield with cancellable; suspends with cancellable=true, caller cancels - (local.set $ret (call $thread.yield-cancellable)) - (if (i32.ne (i32.const 1 (; CANCELLED ;)) (local.get $ret)) - (then unreachable)) - (call $task.cancel) - (i32.const 0 (; EXIT ;)) - ) - - ;; Test 3: deferred cancel delivered through cancellable waitable-set.poll - (func $poll-cancel-pending (export "poll-cancel-pending") (param $futr i32) (result i32) - (local $ws i32) - (local $ret i32) - (local $event_code i32) - (local.set $ws (call $waitable-set.new)) - ;; read future - blocks (caller hasn't written yet) - (local.set $ret (call $future.read (local.get $futr) (i32.const 0))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (local.get $futr) (local.get $ws)) - ;; wait WITHOUT cancellable - cancel will be deferred as PENDING_CANCEL - (local.set $event_code (call $waitable-set.wait (local.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) - (then unreachable)) - ;; poll WITH cancellable - delivers the pending cancel - (local.set $event_code (call $waitable-set.poll-cancellable (local.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 6 (; TASK_CANCELLED ;)) (local.get $event_code)) - (then unreachable)) - (call $task.cancel) - (i32.const 0 (; EXIT ;)) - ) - - ;; Test 4: deferred cancel delivered through cancellable thread.yield - (func $yield-cancel-pending (export "yield-cancel-pending") (param $futr i32) (result i32) - (local $ws i32) - (local $ret i32) - (local $event_code i32) - (local.set $ws (call $waitable-set.new)) - ;; read future - blocks (caller hasn't written yet) - (local.set $ret (call $future.read (local.get $futr) (i32.const 0))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (local.get $futr) (local.get $ws)) - ;; wait WITHOUT cancellable - cancel will be deferred as PENDING_CANCEL - (local.set $event_code (call $waitable-set.wait (local.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) - (then unreachable)) - ;; yield WITH cancellable - delivers the pending cancel - (local.set $ret (call $thread.yield-cancellable)) - (if (i32.ne (i32.const 1 (; CANCELLED ;)) (local.get $ret)) - (then unreachable)) - (call $task.cancel) - (i32.const 0 (; EXIT ;)) - ) - - ;; callback that should never be called - (func (export "unreachable-cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (type $FT (future)) - (canon task.cancel (core func $task.cancel)) - (canon future.read $FT async (memory $memory "mem") (core func $future.read)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait cancellable (memory $memory "mem") (core func $waitable-set.wait-cancellable)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon waitable-set.poll cancellable (memory $memory "mem") (core func $waitable-set.poll-cancellable)) - (canon thread.yield cancellable (core func $thread.yield-cancellable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.cancel" (func $task.cancel)) - (export "future.read" (func $future.read)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait-cancellable" (func $waitable-set.wait-cancellable)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "waitable-set.poll-cancellable" (func $waitable-set.poll-cancellable)) - (export "thread.yield-cancellable" (func $thread.yield-cancellable)) - )))) - (func (export "wait-cancel") async (result u32) (canon lift - (core func $cm "wait-cancel") - async (callback (func $cm "unreachable-cb")) - )) - (func (export "yield-cancel") async (result u32) (canon lift - (core func $cm "yield-cancel") - async (callback (func $cm "unreachable-cb")) - )) - (func (export "poll-cancel-pending") async (param "fut" $FT) (result u32) (canon lift - (core func $cm "poll-cancel-pending") - async (callback (func $cm "unreachable-cb")) - )) - (func (export "yield-cancel-pending") async (param "fut" $FT) (result u32) (canon lift - (core func $cm "yield-cancel-pending") - async (callback (func $cm "unreachable-cb")) - )) - ) - - (component $D - (type $FT (future)) - (import "wait-cancel" (func $wait-cancel async (result u32))) - (import "yield-cancel" (func $yield-cancel async (result u32))) - (import "poll-cancel-pending" (func $poll-cancel-pending async (param "fut" $FT) (result u32))) - (import "yield-cancel-pending" (func $yield-cancel-pending async (param "fut" $FT) (result u32))) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) - (import "" "subtask.drop" (func $subtask.drop (param i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "wait-cancel" (func $wait-cancel (param i32) (result i32))) - (import "" "yield-cancel" (func $yield-cancel (param i32) (result i32))) - (import "" "poll-cancel-pending" (func $poll-cancel-pending (param i32 i32) (result i32))) - (import "" "yield-cancel-pending" (func $yield-cancel-pending (param i32 i32) (result i32))) - - (func $run (export "run") (result i32) - (local $ret i32) (local $ret64 i64) - (local $retp i32) (local $retp2 i32) - (local $subtask i32) - (local $event_code i32) - (local $futr i32) (local $futw i32) - (local $ws i32) - - ;; ========================================== - ;; Test 1: waitable-set.wait cancellable - ;; ========================================== - - ;; call wait-cancel; it should block in cancellable wait - (local.set $retp (i32.const 4)) - (local.set $ret (call $wait-cancel (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; cancel; completes immediately (C is in cancellable wait) - (local.set $ret (call $subtask.cancel (local.get $subtask))) - (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (local.get $ret)) - (then unreachable)) - (call $subtask.drop (local.get $subtask)) - - ;; ========================================== - ;; Test 2: thread.yield cancellable - ;; ========================================== - - ;; call yield-cancel; it should suspend in cancellable yield - (local.set $ret (call $yield-cancel (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; cancel; completes immediately (C is in cancellable yield) - (local.set $ret (call $subtask.cancel (local.get $subtask))) - (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (local.get $ret)) - ;; TODO: this currently fails in Wasmtime due to cancellable - ;; thread.yield not being directly resumed by subtask.cancel, but it - ;; seems like it should pass: - (then unreachable)) - (call $subtask.drop (local.get $subtask)) - - ;; ========================================== - ;; Test 3: waitable-set.poll cancellable (pending) - ;; ========================================== - - ;; create future for poll-cancel-pending to read - (local.set $ret64 (call $future.new)) - (local.set $futr (i32.wrap_i64 (local.get $ret64))) - (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - - ;; call poll-cancel-pending; it should block in non-cancellable wait - (local.set $retp (i32.const 4)) - (local.set $retp2 (i32.const 8)) - (local.set $ret (call $poll-cancel-pending (local.get $futr) (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; cancel; blocks because C's wait is not cancellable - (local.set $ret (call $subtask.cancel (local.get $subtask))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; write to future; unblocks C's non-cancellable wait - (local.set $ret (call $future.write (local.get $futw) (i32.const 0))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - ;; wait for subtask to complete - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtask) (local.get $ws)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (i32.load offset=4 (local.get $retp2))) - (then unreachable)) - (call $subtask.drop (local.get $subtask)) - - ;; ========================================== - ;; Test 4: thread.yield cancellable (pending) - ;; ========================================== - - ;; create future for yield-cancel-pending to read - (local.set $ret64 (call $future.new)) - (local.set $futr (i32.wrap_i64 (local.get $ret64))) - (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - - ;; call yield-cancel-pending; it should block in non-cancellable wait - (local.set $ret (call $yield-cancel-pending (local.get $futr) (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; cancel; blocks because C's wait is not cancellable - (local.set $ret (call $subtask.cancel (local.get $subtask))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; write to future; unblocks C's non-cancellable wait - (local.set $ret (call $future.write (local.get $futw) (i32.const 0))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - ;; wait for subtask to complete - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtask) (local.get $ws)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 4 (; CANCELLED_BEFORE_RETURNED ;)) (i32.load offset=4 (local.get $retp2))) - (then unreachable)) - (call $subtask.drop (local.get $subtask)) - - ;; all tests passed - (i32.const 42) - ) - ) - (canon subtask.cancel async (core func $subtask.cancel)) - (canon subtask.drop (core func $subtask.drop)) - (canon future.new $FT (core func $future.new)) - (canon future.write $FT async (memory $memory "mem") (core func $future.write)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon lower (func $wait-cancel) async (memory $memory "mem") (core func $wait-cancel')) - (canon lower (func $yield-cancel) async (memory $memory "mem") (core func $yield-cancel')) - (canon lower (func $poll-cancel-pending) async (memory $memory "mem") (core func $poll-cancel-pending')) - (canon lower (func $yield-cancel-pending) async (memory $memory "mem") (core func $yield-cancel-pending')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "subtask.cancel" (func $subtask.cancel)) - (export "subtask.drop" (func $subtask.drop)) - (export "future.new" (func $future.new)) - (export "future.write" (func $future.write)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "wait-cancel" (func $wait-cancel')) - (export "yield-cancel" (func $yield-cancel')) - (export "poll-cancel-pending" (func $poll-cancel-pending')) - (export "yield-cancel-pending" (func $yield-cancel-pending')) - )))) - (func (export "run") async (result u32) (canon lift (core func $dm "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D - (with "wait-cancel" (func $c "wait-cancel")) - (with "yield-cancel" (func $c "yield-cancel")) - (with "poll-cancel-pending" (func $c "poll-cancel-pending")) - (with "yield-cancel-pending" (func $c "yield-cancel-pending")) - )) - (func (export "run") (alias export $d "run")) -) -(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/closed-stream.wast b/src/test/resources/spec-tests/async/closed-stream.wast deleted file mode 100644 index eb462c8..0000000 --- a/src/test/resources/spec-tests/async/closed-stream.wast +++ /dev/null @@ -1,102 +0,0 @@ -;; This test contains two components $C and $D that test that if the writable side -;; of a stream is dropped, the other side registers a STREAM DROPPED status -;; when attempting to read from the stream. -(component definition $Tester - ;; Creates a stream and keeps a handle to the writable end of it. - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - ;; Store the writable end of a stream - (global $sw (mut i32) (i32.const 0)) - - ;; Create a new stream, return the readable end to the caller - (func $start-stream (export "start-stream") (result i32) - (local $ret64 i64) - (local.set $ret64 (call $stream.new)) - (global.set $sw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (i32.wrap_i64 (local.get $ret64)) - ) - - ;; Drop the writable end of a stream - (func $drop-writable (export "drop-writable") - (call $stream.drop-writable (global.get $sw)) - ) - ) - (type $ST (stream u8)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "stream.new" (func $stream.new)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (func (export "start-stream") (result (stream u8)) (canon lift (core func $cm "start-stream"))) - (func (export "drop-writable") (canon lift (core func $cm "drop-writable"))) - ) - - ;; Gets a readable stream from component $C and calls operations on it. - (component $D - (import "c" (instance $c - (export "start-stream" (func (result (stream u8)))) - (export "drop-writable" (func)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - (import "" "start-stream" (func $start-stream (result i32))) - (import "" "drop-writable" (func $drop-writable)) - - (func (export "read-from-closed-stream") - (local $ret i32) (local $sr i32) - - ;; call 'start-stream' to get the stream we'll be working with - (local.set $sr (call $start-stream)) - (if (i32.ne (i32.const 1) (local.get $sr)) - (then unreachable)) - - ;; drop the writable end and then attempt to read from it - (call $drop-writable) - (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 4))) - (if (i32.ne (i32.const 1 (; DROPPED ;)) (local.get $ret)) - (then unreachable)) - ) - ) - (type $ST (stream u8)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (canon lower (func $c "start-stream") (core func $start-stream')) - (canon lower (func $c "drop-writable") (core func $drop-writable')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-writable" (func $stream.drop-writable)) - (export "start-stream" (func $start-stream')) - (export "drop-writable" (func $drop-writable')) - )))) - (func (export "read-from-closed-stream") (canon lift (core func $core "read-from-closed-stream"))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "read-from-closed-stream") (alias export $d "read-from-closed-stream")) -) - -(component instance $new-tester-instance $Tester) -(invoke "read-from-closed-stream") diff --git a/src/test/resources/spec-tests/async/cross-abi-calls.wast b/src/test/resources/spec-tests/async/cross-abi-calls.wast deleted file mode 100644 index 8f1370b..0000000 --- a/src/test/resources/spec-tests/async/cross-abi-calls.wast +++ /dev/null @@ -1,519 +0,0 @@ -;; This test pairs sync and async-callback calls from $Bottom into $Top, -;; testing different numbers of parameters and results that hit the various -;; flat-vs-heap cases in the spec. -(component definition $C - (component $Top - (core module $Memory - (memory (export "mem") 1) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - i32.const 0 ;; cheat -- there's never more than 1 allocation alive - ) - ) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 0)) - (import "" "task.return0" (func $task.return0)) - (import "" "task.return1" (func $task.return1 (param f64))) - (import "" "task.return16" (func $task.return16 (param i32 i64 f32 f64 i32 i64 f32 f64 i32 i64 f32 f64 i32 i64 f32 f64))) - (import "" "task.return17" (func $task.return17 (param i32))) - (func (export "sync-4-param") (param i32 i64 f32 f64) - (if (i32.ne (i32.const 42) (local.get 0)) - (then unreachable)) - (if (i64.ne (i64.const 43) (local.get 1)) - (then unreachable)) - (if (f32.ne (f32.const 44.4) (local.get 2)) - (then unreachable)) - (if (f64.ne (f64.const 45.5) (local.get 3)) - (then unreachable)) - ) - (func (export "sync-5-param") (param i32 i64 f32 f64 i32) - (if (i32.ne (i32.const -1) (local.get 0)) - (then unreachable)) - (if (i64.ne (i64.const -2) (local.get 1)) - (then unreachable)) - (if (f32.ne (f32.const -3.3) (local.get 2)) - (then unreachable)) - (if (f64.ne (f64.const -4.4) (local.get 3)) - (then unreachable)) - (if (i32.ne (i32.const -5) (local.get 4)) - (then unreachable)) - ) - (func $check-17 (param $ptr i32) - (if (i32.ne (i32.const -1) (i32.load (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -2) (i64.load offset=8 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -3.3) (f32.load offset=16 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -4.4) (f64.load offset=24 (local.get $ptr))) - (then unreachable)) - (if (i32.ne (i32.const -5) (i32.load offset=32 (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -6) (i64.load offset=40 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -7.7) (f32.load offset=48 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -8.8) (f64.load offset=56 (local.get $ptr))) - (then unreachable)) - (if (i32.ne (i32.const -9) (i32.load offset=64 (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -10) (i64.load offset=72 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -11.11) (f32.load offset=80 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -12.12) (f64.load offset=88 (local.get $ptr))) - (then unreachable)) - (if (i32.ne (i32.const -13) (i32.load offset=96 (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -14) (i64.load offset=104 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -15.15) (f32.load offset=112 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -16.16) (f64.load offset=120 (local.get $ptr))) - (then unreachable)) - (if (i32.ne (i32.const -17) (i32.load offset=128 (local.get $ptr))) - (then unreachable)) - ) - (func (export "sync-17-param") (param $ptr i32) - (call $check-17 (local.get $ptr)) - ) - (func (export "sync-1-result") (result f64) - (f64.const -1.1) - ) - (func $setup-16 (param $ptr i32) - (i32.store (local.get $ptr) (i32.const -1)) - (i64.store offset=8 (local.get $ptr) (i64.const -2)) - (f32.store offset=16 (local.get $ptr) (f32.const -3.3)) - (f64.store offset=24 (local.get $ptr) (f64.const -4.4)) - (i32.store offset=32 (local.get $ptr) (i32.const -5)) - (i64.store offset=40 (local.get $ptr) (i64.const -6)) - (f32.store offset=48 (local.get $ptr) (f32.const -7.7)) - (f64.store offset=56 (local.get $ptr) (f64.const -8.8)) - (i32.store offset=64 (local.get $ptr) (i32.const -9)) - (i64.store offset=72 (local.get $ptr) (i64.const -10)) - (f32.store offset=80 (local.get $ptr) (f32.const -11.11)) - (f64.store offset=88 (local.get $ptr) (f64.const -12.12)) - (i32.store offset=96 (local.get $ptr) (i32.const -13)) - (i64.store offset=104 (local.get $ptr) (i64.const -14)) - (f32.store offset=112 (local.get $ptr) (f32.const -15.15)) - (f64.store offset=120 (local.get $ptr) (f64.const -16.16)) - ) - (func $setup-17 (param $ptr i32) - (call $setup-16 (local.get $ptr)) - (i32.store offset=128 (local.get $ptr) (i32.const -17)) - ) - (func (export "sync-16-result") (result i32) - (local $ptr i32) - (call $setup-16 (local.get $ptr)) - (local.get $ptr) - ) - (func (export "sync-17-result") (result i32) - (local $ptr i32) - (call $setup-17 (local.get $ptr)) - (local.get $ptr) - ) - (func (export "async-4-param") (param i32 i64 f32 f64) (result i32) - (if (i32.ne (i32.const 42) (local.get 0)) - (then unreachable)) - (if (i64.ne (i64.const 43) (local.get 1)) - (then unreachable)) - (if (f32.ne (f32.const 44.4) (local.get 2)) - (then unreachable)) - (if (f64.ne (f64.const 45.5) (local.get 3)) - (then unreachable)) - (call $task.return0) - (i32.const 0 (; EXIT ;)) - ) - (func (export "async-5-param") (param i32 i64 f32 f64 i32) (result i32) - (if (i32.ne (i32.const -1) (local.get 0)) - (then unreachable)) - (if (i64.ne (i64.const -2) (local.get 1)) - (then unreachable)) - (if (f32.ne (f32.const -3.3) (local.get 2)) - (then unreachable)) - (if (f64.ne (f64.const -4.4) (local.get 3)) - (then unreachable)) - (if (i32.ne (i32.const -5) (local.get 4)) - (then unreachable)) - (call $task.return0) - (i32.const 0 (; EXIT ;)) - ) - (func (export "async-17-param") (param $ptr i32) (result i32) - (call $check-17 (local.get $ptr)) - (call $task.return0) - (i32.const 0 (; EXIT ;)) - ) - (func (export "async-1-result") (result i32) - (call $task.return1 (f64.const -1.1)) - (i32.const 0 (; EXIT ;)) - ) - (func (export "async-16-result") (result i32) - (call $task.return16 (i32.const -1) (i64.const -2) (f32.const -3.3) (f64.const -4.4) - (i32.const -5) (i64.const -6) (f32.const -7.7) (f64.const -8.8) - (i32.const -9) (i64.const -10) (f32.const -11.11) (f64.const -12.12) - (i32.const -13) (i64.const -14) (f32.const -15.15) (f64.const -16.16)) - (i32.const 0 (; EXIT ;)) - ) - (func (export "async-17-result") (result i32) - (local $ptr i32) - (call $setup-17 (local.get $ptr)) - (call $task.return17 (local.get $ptr)) - (i32.const 0 (; EXIT ;)) - ) - (func (export "unreachable-cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (canon task.return (core func $task.return0)) - (canon task.return (result f64) (core func $task.return1)) - (canon task.return (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)) (core func $task.return16)) - (canon task.return (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)) (memory $memory "mem") (core func $task.return17)) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return0" (func $task.return0)) - (export "task.return1" (func $task.return1)) - (export "task.return16" (func $task.return16)) - (export "task.return17" (func $task.return17)) - )))) - (func (export "sync-4-param") async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) - (canon lift (core func $core "sync-4-param")) - ) - (func (export "sync-5-param") async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) (param "e" u32) - (canon lift (core func $core "sync-5-param")) - ) - (func (export "sync-17-param") async - (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) - (param "e" u32) (param "f" u64) (param "g" f32) (param "h" f64) - (param "i" u32) (param "j" u64) (param "k" f32) (param "l" f64) - (param "m" u32) (param "n" u64) (param "o" f32) (param "p" f64) - (param "q" u32) - (canon lift (core func $core "sync-17-param") (memory $memory "mem") (realloc (func $memory "realloc"))) - ) - (func (export "sync-1-result") async (result f64) - (canon lift (core func $core "sync-1-result")) - ) - (func (export "sync-16-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)) - (canon lift (core func $core "sync-16-result") (memory $memory "mem")) - ) - (func (export "sync-17-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)) - (canon lift (core func $core "sync-17-result") (memory $memory "mem")) - ) - (func (export "async-4-param") async - (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) - (canon lift (core func $core "async-4-param") async (callback (func $core "unreachable-cb"))) - ) - (func (export "async-5-param") async - (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) (param "e" u32) - (canon lift (core func $core "async-5-param") async (callback (func $core "unreachable-cb"))) - ) - (func (export "async-17-param") async - (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) - (param "e" u32) (param "f" u64) (param "g" f32) (param "h" f64) - (param "i" u32) (param "j" u64) (param "k" f32) (param "l" f64) - (param "m" u32) (param "n" u64) (param "o" f32) (param "p" f64) - (param "q" u32) - (canon lift (core func $core "async-17-param") async (callback (func $core "unreachable-cb")) (memory $memory "mem") (realloc (func $memory "realloc"))) - ) - (func (export "async-1-result") async (result f64) - (canon lift (core func $core "async-1-result") async (callback (func $core "unreachable-cb"))) - ) - (func (export "async-16-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)) - (canon lift (core func $core "async-16-result") async (callback (func $core "unreachable-cb"))) - ) - (func (export "async-17-result") async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)) - (canon lift (core func $core "async-17-result") async (callback (func $core "unreachable-cb")) (memory $memory "mem") (realloc (func $memory "realloc"))) - ) - ) - (component $Bottom - (import "func-4-param" (func $func-4-param async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64))) - (import "func-5-param" (func $func-5-param async (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) (param "e" u32))) - (import "func-17-param" (func $func-17-param async - (param "a" u32) (param "b" u64) (param "c" f32) (param "d" f64) - (param "e" u32) (param "f" u64) (param "g" f32) (param "h" f64) - (param "i" u32) (param "j" u64) (param "k" f32) (param "l" f64) - (param "m" u32) (param "n" u64) (param "o" f32) (param "p" f64) - (param "q" u32))) - (import "func-1-result" (func $func-1-result async (result f64))) - (import "func-16-result" (func $func-16-result async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64)))) - (import "func-17-result" (func $func-17-result async (result (tuple u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32 u64 f32 f64 u32)))) - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "sync-4-param" (func $sync-4-param (param i32 i64 f32 f64))) - (import "" "async-4-param" (func $async-4-param (param i32 i64 f32 f64) (result i32))) - (import "" "sync-5-param" (func $sync-5-param (param i32 i64 f32 f64 i32))) - (import "" "async-5-param" (func $async-5-param (param i32) (result i32))) - (import "" "sync-17-param" (func $sync-17-param (param i32))) - (import "" "async-17-param" (func $async-17-param (param i32) (result i32))) - (import "" "sync-1-result" (func $sync-1-result (result f64))) - (import "" "async-1-result" (func $async-1-result (param i32) (result i32))) - (import "" "sync-16-result" (func $sync-16-result (param i32))) - (import "" "async-16-result" (func $async-16-result (param i32) (result i32))) - (import "" "sync-17-result" (func $sync-17-result (param i32))) - (import "" "async-17-result" (func $async-17-result (param i32) (result i32))) - (func (export "call-sync-4-param") (result i32) - (call $sync-4-param (i32.const 42) (i64.const 43) (f32.const 44.4) (f64.const 45.5)) - (i32.const 83) - ) - (func (export "call-async-4-param") (result i32) - (if (i32.ne (call $async-4-param (i32.const 42) (i64.const 43) (f32.const 44.4) (f64.const 45.5)) - (i32.const 2 (; RETURNED ;))) - (then unreachable)) - (i32.const 84) - ) - (func (export "call-sync-5-param") (result i32) - (call $sync-5-param (i32.const -1) (i64.const -2) (f32.const -3.3) (f64.const -4.4) (i32.const -5)) - (i32.const 85) - ) - (func (export "call-async-5-param") (result i32) - (local $ptr i32) - (i32.store (local.get $ptr) (i32.const -1)) - (i64.store offset=8 (local.get $ptr) (i64.const -2)) - (f32.store offset=16 (local.get $ptr) (f32.const -3.3)) - (f64.store offset=24 (local.get $ptr) (f64.const -4.4)) - (i32.store offset=32 (local.get $ptr) (i32.const -5)) - (if (i32.ne (call $async-5-param (local.get $ptr)) (i32.const 2 (; RETURNED ;))) - (then unreachable)) - (i32.const 86) - ) - (func $setup-17 (param $ptr i32) - (i32.store (local.get $ptr) (i32.const -1)) - (i64.store offset=8 (local.get $ptr) (i64.const -2)) - (f32.store offset=16 (local.get $ptr) (f32.const -3.3)) - (f64.store offset=24 (local.get $ptr) (f64.const -4.4)) - (i32.store offset=32 (local.get $ptr) (i32.const -5)) - (i64.store offset=40 (local.get $ptr) (i64.const -6)) - (f32.store offset=48 (local.get $ptr) (f32.const -7.7)) - (f64.store offset=56 (local.get $ptr) (f64.const -8.8)) - (i32.store offset=64 (local.get $ptr) (i32.const -9)) - (i64.store offset=72(local.get $ptr) (i64.const -10)) - (f32.store offset=80 (local.get $ptr) (f32.const -11.11)) - (f64.store offset=88 (local.get $ptr) (f64.const -12.12)) - (i32.store offset=96 (local.get $ptr) (i32.const -13)) - (i64.store offset=104 (local.get $ptr) (i64.const -14)) - (f32.store offset=112 (local.get $ptr) (f32.const -15.15)) - (f64.store offset=120 (local.get $ptr) (f64.const -16.16)) - (i32.store offset=128 (local.get $ptr) (i32.const -17)) - ) - (func (export "call-sync-17-param") (result i32) - (call $setup-17 (i32.const 0)) - (call $sync-17-param (i32.const 0)) - (i32.const 87) - ) - (func (export "call-async-17-param") (result i32) - (call $setup-17 (i32.const 0)) - (if (i32.ne (call $async-17-param (i32.const 0)) (i32.const 2 (; RETURNED ;))) - (then unreachable)) - (i32.const 88) - ) - (func (export "call-sync-1-result") (result i32) - (if (f64.ne (call $sync-1-result) (f64.const -1.1)) - (then unreachable)) - (i32.const 89) - ) - (func (export "call-async-1-result") (result i32) - (local $ptr i32) - (if (i32.ne (call $async-1-result (local.get $ptr)) (i32.const 2 (; RETURNED ;))) - (then unreachable)) - (if (f64.ne (f64.load (local.get $ptr)) (f64.const -1.1)) - (then unreachable)) - (i32.const 90) - ) - (func $check-16 (param $ptr i32) - (if (i32.ne (i32.const -1) (i32.load (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -2) (i64.load offset=8 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -3.3) (f32.load offset=16 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -4.4) (f64.load offset=24 (local.get $ptr))) - (then unreachable)) - (if (i32.ne (i32.const -5) (i32.load offset=32 (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -6) (i64.load offset=40 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -7.7) (f32.load offset=48 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -8.8) (f64.load offset=56 (local.get $ptr))) - (then unreachable)) - (if (i32.ne (i32.const -9) (i32.load offset=64 (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -10) (i64.load offset=72 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -11.11) (f32.load offset=80 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -12.12) (f64.load offset=88 (local.get $ptr))) - (then unreachable)) - (if (i32.ne (i32.const -13) (i32.load offset=96 (local.get $ptr))) - (then unreachable)) - (if (i64.ne (i64.const -14) (i64.load offset=104 (local.get $ptr))) - (then unreachable)) - (if (f32.ne (f32.const -15.15) (f32.load offset=112 (local.get $ptr))) - (then unreachable)) - (if (f64.ne (f64.const -16.16) (f64.load offset=120 (local.get $ptr))) - (then unreachable)) - ) - (func $check-17 (param $ptr i32) - (call $check-16 (local.get $ptr)) - (if (i32.ne (i32.const -17) (i32.load offset=128 (local.get $ptr))) - (then unreachable)) - ) - (func (export "call-sync-16-result") (result i32) - (local $ptr i32) - (call $sync-16-result (local.get $ptr)) - (call $check-16 (local.get $ptr)) - (i32.const 91) - ) - (func (export "call-async-16-result") (result i32) - (local $ptr i32) - (if (i32.ne (call $async-16-result (local.get $ptr)) (i32.const 2 (; RETURNED ;))) - (then unreachable)) - (call $check-16 (local.get $ptr)) - (i32.const 92) - ) - (func (export "call-sync-17-result") (result i32) - (local $ptr i32) - (call $sync-17-result (local.get $ptr)) - (call $check-17 (local.get $ptr)) - (i32.const 93) - ) - (func (export "call-async-17-result") (result i32) - (local $ptr i32) - (if (i32.ne (call $async-17-result (local.get $ptr)) (i32.const 2 (; RETURNED ;))) - (then unreachable)) - (call $check-17 (local.get $ptr)) - (i32.const 94) - ) - ) - (canon lower (func $func-4-param) (core func $sync-4-param)) - (canon lower (func $func-4-param) async (memory $memory "mem") (core func $async-4-param)) - (canon lower (func $func-5-param) (core func $sync-5-param)) - (canon lower (func $func-5-param) async (memory $memory "mem") (core func $async-5-param)) - (canon lower (func $func-17-param) (memory $memory "mem") (core func $sync-17-param)) - (canon lower (func $func-17-param) async (memory $memory "mem") (core func $async-17-param)) - (canon lower (func $func-1-result) (core func $sync-1-result)) - (canon lower (func $func-1-result) async (memory $memory "mem") (core func $async-1-result)) - (canon lower (func $func-16-result) (memory $memory "mem") (core func $sync-16-result)) - (canon lower (func $func-16-result) async (memory $memory "mem") (core func $async-16-result)) - (canon lower (func $func-17-result) (memory $memory "mem") (core func $sync-17-result)) - (canon lower (func $func-17-result) async (memory $memory "mem") (core func $async-17-result)) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "sync-4-param" (func $sync-4-param)) - (export "async-4-param" (func $async-4-param)) - (export "sync-5-param" (func $sync-5-param)) - (export "async-5-param" (func $async-5-param)) - (export "sync-17-param" (func $sync-17-param)) - (export "async-17-param" (func $async-17-param)) - (export "sync-1-result" (func $sync-1-result)) - (export "async-1-result" (func $async-1-result)) - (export "sync-16-result" (func $sync-16-result)) - (export "async-16-result" (func $async-16-result)) - (export "sync-17-result" (func $sync-17-result)) - (export "async-17-result" (func $async-17-result)) - )))) - (func (export "call-sync-4-param") async (result u32) (canon lift (core func $core "call-sync-4-param"))) - (func (export "call-async-4-param") async (result u32) (canon lift (core func $core "call-async-4-param"))) - (func (export "call-sync-5-param") async (result u32) (canon lift (core func $core "call-sync-5-param"))) - (func (export "call-async-5-param") async (result u32) (canon lift (core func $core "call-async-5-param"))) - (func (export "call-sync-17-param") async (result u32) (canon lift (core func $core "call-sync-17-param"))) - (func (export "call-async-17-param") async (result u32) (canon lift (core func $core "call-async-17-param"))) - (func (export "call-sync-1-result") async (result u32) (canon lift (core func $core "call-sync-1-result"))) - (func (export "call-async-1-result") async (result u32) (canon lift (core func $core "call-async-1-result"))) - (func (export "call-sync-16-result") async (result u32) (canon lift (core func $core "call-sync-16-result"))) - (func (export "call-async-16-result") async (result u32) (canon lift (core func $core "call-async-16-result"))) - (func (export "call-sync-17-result") async (result u32) (canon lift (core func $core "call-sync-17-result"))) - (func (export "call-async-17-result") async (result u32) (canon lift (core func $core "call-async-17-result"))) - ) - (instance $top (instantiate $Top)) - (instance $bottom-to-sync (instantiate $Bottom - (with "func-4-param" (func $top "sync-4-param")) - (with "func-5-param" (func $top "sync-5-param")) - (with "func-17-param" (func $top "sync-17-param")) - (with "func-1-result" (func $top "sync-1-result")) - (with "func-16-result" (func $top "sync-16-result")) - (with "func-17-result" (func $top "sync-17-result")) - )) - (instance $bottom-to-async (instantiate $Bottom - (with "func-4-param" (func $top "async-4-param")) - (with "func-5-param" (func $top "async-5-param")) - (with "func-17-param" (func $top "async-17-param")) - (with "func-1-result" (func $top "async-1-result")) - (with "func-16-result" (func $top "async-16-result")) - (with "func-17-result" (func $top "async-17-result")) - )) - (func (export "sync-calls-sync-4-param") (alias export $bottom-to-sync "call-sync-4-param")) - (func (export "sync-calls-async-4-param") (alias export $bottom-to-async "call-sync-4-param")) - (func (export "async-calls-sync-4-param") (alias export $bottom-to-sync "call-async-4-param")) - (func (export "async-calls-async-4-param") (alias export $bottom-to-async "call-async-4-param")) - (func (export "sync-calls-sync-5-param") (alias export $bottom-to-sync "call-sync-5-param")) - (func (export "sync-calls-async-5-param") (alias export $bottom-to-async "call-sync-5-param")) - (func (export "async-calls-sync-5-param") (alias export $bottom-to-sync "call-async-5-param")) - (func (export "async-calls-async-5-param") (alias export $bottom-to-async "call-async-5-param")) - (func (export "sync-calls-sync-17-param") (alias export $bottom-to-sync "call-sync-17-param")) - (func (export "sync-calls-async-17-param") (alias export $bottom-to-async "call-sync-17-param")) - (func (export "async-calls-sync-17-param") (alias export $bottom-to-sync "call-async-17-param")) - (func (export "async-calls-async-17-param") (alias export $bottom-to-async "call-async-17-param")) - (func (export "sync-calls-sync-1-result") (alias export $bottom-to-sync "call-sync-1-result")) - (func (export "sync-calls-async-1-result") (alias export $bottom-to-async "call-sync-1-result")) - (func (export "async-calls-sync-1-result") (alias export $bottom-to-sync "call-async-1-result")) - (func (export "async-calls-async-1-result") (alias export $bottom-to-async "call-async-1-result")) - (func (export "sync-calls-sync-16-result") (alias export $bottom-to-sync "call-sync-16-result")) - (func (export "sync-calls-async-16-result") (alias export $bottom-to-async "call-sync-16-result")) - (func (export "async-calls-sync-16-result") (alias export $bottom-to-sync "call-async-16-result")) - (func (export "async-calls-async-16-result") (alias export $bottom-to-async "call-async-16-result")) - (func (export "sync-calls-sync-17-result") (alias export $bottom-to-sync "call-sync-17-result")) - (func (export "sync-calls-async-17-result") (alias export $bottom-to-async "call-sync-17-result")) - (func (export "async-calls-sync-17-result") (alias export $bottom-to-sync "call-async-17-result")) - (func (export "async-calls-async-17-result") (alias export $bottom-to-async "call-async-17-result")) -) - -(component instance $i $C) -(assert_return (invoke "sync-calls-sync-4-param") (u32.const 83)) -(component instance $i $C) -(assert_return (invoke "sync-calls-async-4-param") (u32.const 83)) -(component instance $i $C) -(assert_return (invoke "async-calls-sync-4-param") (u32.const 84)) -(component instance $i $C) -(assert_return (invoke "async-calls-async-4-param") (u32.const 84)) -(component instance $i $C) -(assert_return (invoke "sync-calls-sync-5-param") (u32.const 85)) -(component instance $i $C) -(assert_return (invoke "sync-calls-async-5-param") (u32.const 85)) -(component instance $i $C) -(assert_return (invoke "async-calls-sync-5-param") (u32.const 86)) -(component instance $i $C) -(assert_return (invoke "async-calls-async-5-param") (u32.const 86)) -(component instance $i $C) -(assert_return (invoke "sync-calls-sync-17-param") (u32.const 87)) -(component instance $i $C) -(assert_return (invoke "sync-calls-async-17-param") (u32.const 87)) -(component instance $i $C) -(assert_return (invoke "async-calls-sync-17-param") (u32.const 88)) -(component instance $i $C) -(assert_return (invoke "async-calls-async-17-param") (u32.const 88)) -(component instance $i $C) -(assert_return (invoke "sync-calls-sync-1-result") (u32.const 89)) -(component instance $i $C) -(assert_return (invoke "sync-calls-async-1-result") (u32.const 89)) -(component instance $i $C) -(assert_return (invoke "async-calls-sync-1-result") (u32.const 90)) -(component instance $i $C) -(assert_return (invoke "async-calls-async-1-result") (u32.const 90)) -(component instance $i $C) -(assert_return (invoke "sync-calls-sync-16-result") (u32.const 91)) -(component instance $i $C) -(assert_return (invoke "sync-calls-async-16-result") (u32.const 91)) -(component instance $i $C) -(assert_return (invoke "async-calls-sync-16-result") (u32.const 92)) -(component instance $i $C) -(assert_return (invoke "async-calls-async-16-result") (u32.const 92)) -(component instance $i $C) -(assert_return (invoke "sync-calls-sync-17-result") (u32.const 93)) -(component instance $i $C) -(assert_return (invoke "sync-calls-async-17-result") (u32.const 93)) -(component instance $i $C) -(assert_return (invoke "async-calls-sync-17-result") (u32.const 94)) -(component instance $i $C) -(assert_return (invoke "async-calls-async-17-result") (u32.const 94)) diff --git a/src/test/resources/spec-tests/async/cross-task-future.wast b/src/test/resources/spec-tests/async/cross-task-future.wast deleted file mode 100644 index 7f76b6e..0000000 --- a/src/test/resources/spec-tests/async/cross-task-future.wast +++ /dev/null @@ -1,103 +0,0 @@ -;; This exercises that future ends are not tied to the task that created them. -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - - (global $futr (mut i32) (i32.const 0)) - (global $futw (mut i32) (i32.const 0)) - - (func $one (export "one") - (local $ret i32) (local $ret64 i64) - (local.set $ret64 (call $future.new)) - (global.set $futr (i32.wrap_i64 (local.get $ret64))) - (global.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - ) - (func $two (export "two") (result i32) - (local $ret i32) (local $ptr i32) - (call $task.return (global.get $futr)) - (local.set $ptr (i32.const 32)) - (i32.store (local.get $ptr) (i32.const 0x42)) - (local.set $ret (call $future.write (global.get $futw) (local.get $ptr))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (i32.const 0 (; EXIT ;)) - ) - (func $two_cb (export "two_cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (type $FT (future u8)) - (canon task.return (result $FT) (core func $task.return)) - (canon future.new $FT (core func $future.new)) - (canon future.write $FT async (memory $memory "mem") (core func $future.write)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "future.new" (func $future.new)) - (export "future.write" (func $future.write)) - )))) - (func (export "one") (canon lift - (core func $cm "one") - )) - (func (export "two") async (result (future u8)) (canon lift - (core func $cm "two") - async (callback (func $cm "two_cb")) - )) - ) - - (component $D - (import "c" (instance $c - (export "one" (func)) - (export "two" (func async (result (future u8)))) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "one" (func $one)) - (import "" "two" (func $two (result i32))) - - (func $run (export "run") (result i32) - (local $ret i32) - (local $retp i32) - (local $futr i32) - - (call $one) - (local.set $futr (call $two)) - (local.set $retp (i32.const 32)) - (local.set $ret (call $future.read (local.get $futr) (local.get $retp))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.load8_u (local.get $retp)) (i32.const 0x42)) - (then unreachable)) - - (i32.const 42) - ) - ) - (type $FT (future u8)) - (canon future.read $FT async (memory $memory "mem") (core func $future.read)) - (canon lower (func $c "one") (core func $one')) - (canon lower (func $c "two") (core func $two')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "future.read" (func $future.read)) - (export "one" (func $one')) - (export "two" (func $two')) - )))) - (func (export "run") async (result u32) (canon lift (core func $dm "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "run") (alias export $d "run")) -) - -(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/deadlock.wast b/src/test/resources/spec-tests/async/deadlock.wast deleted file mode 100644 index 6d50c9f..0000000 --- a/src/test/resources/spec-tests/async/deadlock.wast +++ /dev/null @@ -1,73 +0,0 @@ -;; This test defines components $C and $D where $D imports and calls $C -;; $C.f waits on an empty waitable set -;; $D.g calls $C.f and then waits for it to finish, which fails due to deadlock -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - - (func (export "f") (result i32) - ;; wait on a new empty waitable set - (local $ws i32) - (local.set $ws (call $waitable-set.new)) - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (local.get $ws) (i32.const 4))) - ) - (func (export "cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - unreachable - ) - ) - (canon waitable-set.new (core func $waitable-set.new)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable-set.new" (func $waitable-set.new)) - )))) - (func (export "f") async (result u32) (canon lift - (core func $cm "f") - async (memory $memory "mem") (callback (func $cm "cb")) - )) - ) - - (component $D - (import "f" (func $f async (result u32))) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "f" (func $f (param i32) (result i32))) - - (func (export "g") (result i32) - (local $ws i32) (local $ret i32) (local $subtaski i32) - (local.set $ret (call $f (i32.const 0))) - (local.set $subtaski (i32.shr_u (local.get $ret) (i32.const 4))) - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtaski) (local.get $ws)) - (call $waitable-set.wait (local.get $ws) (i32.const 0)) - unreachable - ) - ) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon lower (func $f) async (memory $memory "mem") (core func $f')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "f" (func $f')) - )))) - (func (export "f") async (result u32) (canon lift (core func $dm "g"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "f" (func $c "f")))) - (func (export "f") (alias export $d "f")) -) -(assert_trap (invoke "f") "wasm trap: deadlock detected: event loop cannot make further progress") diff --git a/src/test/resources/spec-tests/async/dont-block-start.wast b/src/test/resources/spec-tests/async/dont-block-start.wast deleted file mode 100644 index 5fab77f..0000000 --- a/src/test/resources/spec-tests/async/dont-block-start.wast +++ /dev/null @@ -1,50 +0,0 @@ -;; test a few cases where components trap during core module instantiation -;; due to blocking during the (implicitly sync) start function -(assert_trap - (component - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $M - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (func $start - (drop (call $waitable-set.wait (call $waitable-set.new) (i32.const 0))) - ) - (start $start) - ) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (core instance $m (instantiate $M (with "" (instance - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - )))) - ) - "cannot block a synchronous task before returning" -) -(assert_trap - (component - (component $C - (core module $M - (func (export "f") (result i32) unreachable) - (func (export "f_cb") (param i32 i32 i32) (result i32) unreachable) - ) - (core instance $i (instantiate $M)) - (func (export "f") async (canon lift (core func $i "f") async (callback (func $i "f_cb")))) - ) - (component $D - (import "f" (func $f async)) - (core module $M - (import "" "f" (func $f)) - (func $start (call $f)) - (start $start) - ) - (canon lower (func $f) (core func $f')) - (core instance $m (instantiate $M (with "" (instance - (export "f" (func $f')) - )))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "f" (func $c "f")))) - ) - "cannot block a synchronous task before returning" -) diff --git a/src/test/resources/spec-tests/async/drop-cross-task-borrow.wast b/src/test/resources/spec-tests/async/drop-cross-task-borrow.wast deleted file mode 100644 index 139981c..0000000 --- a/src/test/resources/spec-tests/async/drop-cross-task-borrow.wast +++ /dev/null @@ -1,309 +0,0 @@ -;; This test has 3 components $C, $D and $E -;; $C just implements a resource type that's used by $D and $E -;; $E calls async function $D.dont-drop, lending it a handle. -;; $D.dont-drop blocks, waiting on an empty waitable-set -;; $E then calls $D.drop-handle which drops the handle that $D.dont-drop -;; was lent, albeit from the "wrong" task ($D.drop-handle). -;; Then $E calls $D.resume-dont-drop to unblock $D.dont-drop, which -;; will call task.return which should not trap. -(component definition $Test - (component $C - (type $R' (resource (rep i32))) - (canon resource.new $R' (core func $resource.new)) - (core module $CM (func (export "id") (param i32) (result i32) (local.get 0))) - (core instance $cm (instantiate $CM)) - (alias core export $cm "id" (core func $resource.rep)) - (export $R "R" (type $R')) - (func (export "R-new") (param "rep" u32) (result (own $R)) (canon lift (core func $resource.new))) - (func (export "R-rep") (param "self" (borrow $R)) (result u32) (canon lift (core func $resource.rep))) - ) - - (component $D - (import "c" (instance $d - (export "R" (type $R (sub resource))) - (export "R-new" (func (param "rep" u32) (result (own $R)))) - (export "R-rep" (func (param "self" (borrow $R)) (result u32))) - )) - (core module $DM - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "task.return0" (func $task.return0)) - (import "" "task.return1" (func $task.return1 (param i32))) - (import "" "R-rep" (func $R-rep (param i32) (result i32))) - (import "" "R-drop" (func $R-drop (param i32))) - - (global $handle (mut i32) (i32.const 0)) - (global $dont-drop-result (mut i32) (i32.const 0)) - (global $dont-drop-ws (mut i32) (i32.const 0)) - - (func (export "dont-drop") (param $h i32) (result i32) - ;; Stash the given (borrow $R) handle in a global. - (global.set $handle (local.get $h)) - ;; Stash the result of $R-rep in a global for later task.return - (global.set $dont-drop-result (call $R-rep (local.get $h))) - ;; Stash the waitable-set we're waiting on in a global for resume-dont-drop to use - (global.set $dont-drop-ws (call $waitable-set.new)) - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $dont-drop-ws) (i32.const 4))) - ) - (func (export "dont-drop-cb") (param i32 i32 i32) (result i32) - ;; We were resumed by resume-dont-drop - (call $task.return1 (global.get $dont-drop-result)) - (i32.const 0 (; EXIT ;)) - ) - (func (export "drop-handle") (result i32) - ;; Drops the borrowed handle passed to dont-drop - (local $result i32) - (local.set $result (call $R-rep (global.get $handle))) - (call $R-drop (global.get $handle)) - (local.get $result) - ) - (func (export "resume-dont-drop") - ;; Add a waitable with a pending event to dont-drop's waitable-set to - ;; wake it up. - (local $ret i32) (local $ret64 i64) - (local $futw i32) (local $futr i32) - (local.set $ret64 (call $future.new)) - (local.set $futr (i32.wrap_i64 (local.get $ret64))) - (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (local.get $futr) (global.get $dont-drop-ws)) - ) - (func (export "drop-other-and-self") (param $h i32) (result i32) - (local $result i32) - (local.set $result (call $R-rep (global.get $handle))) - (call $R-drop (global.get $handle)) - (call $R-drop (local.get $h)) - (call $task.return1 (local.get $result)) - (i32.const 0 (; EXIT ;)) - ) - (func (export "drop-wrong-one") (param $h i32) (result i32) - (call $R-drop (global.get $handle)) - ;; trap b/c $h wasn't dropped - (call $task.return0) - (i32.const 0 (; EXIT ;)) - ) - (func (export "unreachable-cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (type $FT (future)) - (alias export $d "R" (type $R)) - (canon task.return (core func $task.return0)) - (canon task.return (result u32) (core func $task.return1)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon future.new $FT (core func $future.new)) - (canon future.read $FT async (core func $future.read)) - (canon future.write $FT async (core func $future.write)) - (canon lower (func $d "R-rep") (core func $R-rep)) - (canon resource.drop $R (core func $R-drop)) - (core instance $dm (instantiate $DM (with "" (instance - (export "task.return0" (func $task.return0)) - (export "task.return1" (func $task.return1)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "future.new" (func $future.new)) - (export "future.read" (func $future.read)) - (export "future.write" (func $future.write)) - (export "R-rep" (func $R-rep)) - (export "R-drop" (func $R-drop)) - )))) - (func (export "dont-drop") async (param "self" (borrow $R)) (result u32) - (canon lift (core func $dm "dont-drop") async (callback (func $dm "dont-drop-cb"))) - ) - (func (export "drop-handle") (result u32) - (canon lift (core func $dm "drop-handle")) - ) - (func (export "resume-dont-drop") - (canon lift (core func $dm "resume-dont-drop")) - ) - (func (export "drop-other-and-self") async (param "self" (borrow $R)) (result u32) - (canon lift (core func $dm "drop-other-and-self") async (callback (func $dm "unreachable-cb"))) - ) - (func (export "drop-wrong-one") async (param "self" (borrow $R)) - (canon lift (core func $dm "drop-wrong-one") async (callback (func $dm "unreachable-cb"))) - ) - ) - - (component $E - (import "c" (instance $c - (export "R" (type $R (sub resource))) - (export "R-new" (func (param "rep" u32) (result (own $R)))) - )) - (alias export $c "R" (type $R)) - (import "d" (instance $d - (export "dont-drop" (func async (param "self" (borrow $R)) (result u32))) - (export "drop-handle" (func (result u32))) - (export "resume-dont-drop" (func)) - (export "drop-other-and-self" (func async (param "self" (borrow $R)) (result u32))) - (export "drop-wrong-one" (func async (param "self" (borrow $R)))) - )) - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $EM - (import "" "mem" (memory 1)) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "R-new" (func $R-new (param i32) (result i32))) - (import "" "dont-drop" (func $dont-drop (param i32 i32) (result i32))) - (import "" "drop-handle" (func $drop-handle (result i32))) - (import "" "resume-dont-drop" (func $resume-dont-drop)) - (import "" "drop-other-and-self" (func $drop-other-and-self (param i32) (result i32))) - (import "" "drop-wrong-one" (func $drop-wrong-one (param i32))) - (func (export "drop-other-no-self") (result i32) - (local $ret i32) - (local $retp i32) (local $retp2 i32) - (local $handle i32) - (local $subtask i32) - (local $magic i32) - (local $ws i32) (local $event_code i32) - - ;; Create a resource storing $magic as it's rep - (local.set $magic (i32.const 10)) - (local.set $handle (call $R-new (local.get $magic))) - - ;; Kick off a call to dont-drop that will block - (local.set $retp (i32.const 16)) - (local.set $ret (call $dont-drop (local.get $handle) (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; drop-handle should return the rep of the handle passed to dont-drop - (local.set $ret (call $drop-handle)) - (if (i32.ne (local.get $magic) (local.get $ret)) - (then unreachable)) - - ;; this unblocks $subtask - (call $resume-dont-drop) - - ;; now wait for $subtask to return, so that it can run before the test is over - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtask) (local.get $ws)) - (local.set $retp2 (i32.const 32)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) - (then unreachable)) - - ;; $subtask should return the rep passed to $R-new. - (if (i32.ne (local.get $magic) (i32.load (local.get $retp))) - (then unreachable)) - - i32.const 42 - ) - (func (export "drop-other-and-self") (result i32) - (local $ret i32) - (local $retp i32) (local $retp2 i32) - (local $handle i32) - (local $subtask i32) - (local $magic i32) - (local $ws i32) (local $event_code i32) - - ;; Create a resource storing $magic as it's rep - (local.set $magic (i32.const 11)) - (local.set $handle (call $R-new (local.get $magic))) - - ;; Kick off a call to dont-drop that will block - (local.set $retp (i32.const 16)) - (local.set $ret (call $dont-drop (local.get $handle) (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; This will drop dont-drop's *and* its own borrowed handle - (local.set $ret (call $drop-other-and-self (local.get $handle))) - (if (i32.ne (local.get $magic) (local.get $ret)) - (then unreachable)) - - ;; this unblocks $subtask - (call $resume-dont-drop) - - ;; now wait for $subtask to return, so that it can run before the test is over - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtask) (local.get $ws)) - (local.set $retp2 (i32.const 32)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp2))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) - (then unreachable)) - - ;; $subtask should return the rep passed to $R-new. - (if (i32.ne (local.get $magic) (i32.load (local.get $retp))) - (then unreachable)) - - i32.const 43 - ) - (func (export "drop-other-miss-self") - (local $ret i32) - (local $retp i32) - (local $handle i32) - (local $subtask i32) - - (local.set $handle (call $R-new (i32.const 42))) - - ;; Kick off a call to dont-drop that will block - (local.set $retp (i32.const 16)) - (local.set $ret (call $dont-drop (local.get $handle) (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; Call drop-wrong-one which will drop the above call's borrow, but not its own and trap - (call $drop-wrong-one (local.get $handle)) - ) - ) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon lower (func $c "R-new") (core func $R-new)) - (canon lower (func $d "dont-drop") async (memory $memory "mem") (core func $dont-drop)) - (canon lower (func $d "drop-handle") (core func $drop-handle)) - (canon lower (func $d "resume-dont-drop") (core func $resume-dont-drop)) - (canon lower (func $d "drop-other-and-self") (core func $drop-other-and-self)) - (canon lower (func $d "drop-wrong-one") (core func $drop-wrong-one)) - (core instance $em (instantiate $EM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "R-new" (func $R-new)) - (export "dont-drop" (func $dont-drop)) - (export "drop-handle" (func $drop-handle)) - (export "resume-dont-drop" (func $resume-dont-drop)) - (export "drop-other-and-self" (func $drop-other-and-self)) - (export "drop-wrong-one" (func $drop-wrong-one)) - )))) - (func (export "drop-other-no-self") async (result u32) (canon lift (core func $em "drop-other-no-self"))) - (func (export "drop-other-and-self") async (result u32) (canon lift (core func $em "drop-other-and-self"))) - (func (export "drop-other-miss-self") async (canon lift (core func $em "drop-other-miss-self"))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (instance $e (instantiate $E (with "c" (instance $c)) (with "d" (instance $d)))) - (func (export "drop-other-no-self") (alias export $e "drop-other-no-self")) - (func (export "drop-other-and-self") (alias export $e "drop-other-and-self")) - (func (export "drop-other-miss-self") (alias export $e "drop-other-miss-self")) -) - -(component instance $i $Test) -(assert_return (invoke "drop-other-no-self") (u32.const 42)) -(component instance $i $Test) -(assert_return (invoke "drop-other-and-self") (u32.const 43)) -(component instance $i $Test) -(assert_trap (invoke "drop-other-miss-self") "borrow handles still remain at the end of the call") diff --git a/src/test/resources/spec-tests/async/drop-stream.wast b/src/test/resources/spec-tests/async/drop-stream.wast deleted file mode 100644 index bf7212f..0000000 --- a/src/test/resources/spec-tests/async/drop-stream.wast +++ /dev/null @@ -1,160 +0,0 @@ -;; This test contains two components $C and $D that test that traps occur -;; when closing the readable or writable end of stream while a read or write -;; is pending. In particular, even if a partial copy has happened into the -;; buffer such that waiting/polling for an event *would* produce a STREAM -;; READ/WRITE event, if the event has not been delivered, the operation is -;; still considered pending. -(component definition $Tester - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - (global $sw (mut i32) (i32.const 0)) - - (func $start-stream (export "start-stream") (result i32) - ;; create a new stream, return the readable end to the caller - (local $ret64 i64) - (local.set $ret64 (call $stream.new)) - (global.set $sw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (i32.wrap_i64 (local.get $ret64)) - ) - (func $write4 (export "write4") - ;; write 6 bytes into the stream, expecting to rendezvous with a stream.read - (local $ret i32) - (i32.store (i32.const 8) (i32.const 0x12345678)) - (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 4))) - (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - ) - (func $start-blocking-write (export "start-blocking-write") - (local $ret i32) - - ;; prepare the write buffer - (i64.store (i32.const 8) (i64.const 0x123456789abcdef)) - - ;; start a blocking write - (local.set $ret (call $stream.write (global.get $sw) (i32.const 8) (i32.const 8))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - ) - (func $drop-writable (export "drop-writable") - ;; boom - (call $stream.drop-writable (global.get $sw)) - ) - ) - (type $ST (stream u8)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "stream.new" (func $stream.new)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (func (export "start-stream") (result (stream u8)) (canon lift (core func $cm "start-stream"))) - (func (export "write4") (canon lift (core func $cm "write4"))) - (func (export "start-blocking-write") (canon lift (core func $cm "start-blocking-write"))) - (func (export "drop-writable") (canon lift (core func $cm "drop-writable"))) - ) - (component $D - (import "c" (instance $c - (export "start-stream" (func (result (stream u8)))) - (export "write4" (func)) - (export "start-blocking-write" (func)) - (export "drop-writable" (func)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - (import "" "start-stream" (func $start-stream (result i32))) - (import "" "write4" (func $write4)) - (import "" "start-blocking-write" (func $start-blocking-write)) - (import "" "drop-writable" (func $drop-writable)) - - (func (export "drop-while-reading") - (local $ret i32) (local $sr i32) - - ;; call 'start-stream' to get the stream we'll be working with - (local.set $sr (call $start-stream)) - (if (i32.ne (i32.const 1) (local.get $sr)) - (then unreachable)) - - ;; start a blocking read - (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 100))) - (if (i32.ne (i32.const -1 (; BLOCKED;)) (local.get $ret)) - (then unreachable)) - - ;; write into the buffer, but the read is still in progress since we - ;; haven't received notification yet. - (call $write4) - (if (i32.ne (i32.const 0x12345678) (i32.load (i32.const 8))) - (then unreachable)) - - ;; boom - (call $stream.drop-readable (local.get $sr)) - ) - (func (export "drop-while-writing") - (local $ret i32) (local $sr i32) - - ;; call 'start-stream' to get the stream we'll be working with - (local.set $sr (call $start-stream)) - (if (i32.ne (i32.const 1) (local.get $sr)) - (then unreachable)) - - ;; start a blocking write and partially read from it - (call $start-blocking-write) - (local.set $ret (call $stream.read (local.get $sr) (i32.const 8) (i32.const 4))) - (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0x89abcdef) (i32.load (i32.const 8))) - (then unreachable)) - (call $drop-writable) - ) - ) - (type $ST (stream u8)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (canon lower (func $c "start-stream") (core func $start-stream')) - (canon lower (func $c "write4") (core func $write4')) - (canon lower (func $c "start-blocking-write") (core func $start-blocking-write')) - (canon lower (func $c "drop-writable") (core func $drop-writable')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "stream.drop-writable" (func $stream.drop-writable)) - (export "start-stream" (func $start-stream')) - (export "write4" (func $write4')) - (export "start-blocking-write" (func $start-blocking-write')) - (export "drop-writable" (func $drop-writable')) - )))) - (func (export "drop-while-reading") (canon lift (core func $core "drop-while-reading"))) - (func (export "drop-while-writing") (canon lift (core func $core "drop-while-writing"))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "drop-while-reading") (alias export $d "drop-while-reading")) - (func (export "drop-while-writing") (alias export $d "drop-while-writing")) -) -(component instance $new-tester-instance $Tester) -(assert_trap (invoke "drop-while-reading") "cannot remove busy stream") -(component instance $new-tester-instance $Tester) -(assert_trap (invoke "drop-while-writing") "cannot drop busy stream") diff --git a/src/test/resources/spec-tests/async/drop-subtask.wast b/src/test/resources/spec-tests/async/drop-subtask.wast deleted file mode 100644 index 21eb9fc..0000000 --- a/src/test/resources/spec-tests/async/drop-subtask.wast +++ /dev/null @@ -1,140 +0,0 @@ -;; This test contains two components: $Looper and $Caller. -;; $Caller starts an async subtask for $Looper.loop and then drops these -;; subtasks in both allowed and disallowed cases, testing for success and -;; traps. -(component - (component $Looper - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CoreLooper - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return)) - - (global $done (mut i32) (i32.const 0)) - - (func $loop (export "loop") (result i32) - (i32.const 1 (; YIELD ;)) - ) - (func $loop_cb (export "loop_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - ;; confirm that we've received a cancellation request - (if (i32.ne (local.get $event_code) (i32.const 0 (; NONE ;))) - (then unreachable)) - (if (i32.ne (local.get $index) (i32.const 0)) - (then unreachable)) - (if (i32.ne (local.get $payload) (i32.const 0)) - (then unreachable)) - - (if (i32.eqz (global.get $done)) - (then (return (i32.const 1 (; YIELD ;))))) - (call $task.return) - (i32.const 0 (; EXIT ;)) - ) - - (func $return (export "return") - (global.set $done (i32.const 1)) - ) - ) - (canon task.return (core func $task.return)) - (core instance $core_looper (instantiate $CoreLooper (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - )))) - (func (export "loop") async (canon lift - (core func $core_looper "loop") - async (callback (func $core_looper "loop_cb")) - )) - (func (export "return") async (canon lift - (core func $core_looper "return") - )) - ) - - (component $Caller - (import "looper" (instance $looper - (export "loop" (func async)) - (export "return" (func async)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CoreCaller - (import "" "mem" (memory 1)) - (import "" "subtask.drop" (func $subtask.drop (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "loop" (func $loop (result i32))) - (import "" "return" (func $return)) - - (func $drop-after-return (export "drop-after-return") (result i32) - (local $ret i32) (local $ws i32) (local $subtask i32) - - ;; start 'loop' - (local.set $ret (call $loop)) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; tell 'loop' to stop - (call $return) - - ;; wait for 'loop' to run and return - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtask) (local.get $ws)) - (local.set $ret (call $waitable-set.wait (local.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (i32.const 0))) - (then unreachable)) - (if (i32.ne (i32.const 2 (; RETURNED ;)) (i32.load (i32.const 4))) - (then unreachable)) - - ;; ok to drop - (call $subtask.drop (local.get $subtask)) - (i32.const 42) - ) - - (func $drop-before-return (export "drop-before-return") (result i32) - (local $ret i32) (local $subtask i32) - - ;; start 'loop' - (local.set $ret (call $loop (i32.const 0xdead) (i32.const 0xbeef))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - - ;; this should trap - (call $subtask.drop (local.get $subtask)) - unreachable - ) - ) - (canon subtask.drop (core func $subtask.drop)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon lower (func $looper "loop") async (memory $memory "mem") (core func $loop')) - (canon lower (func $looper "return") (memory $memory "mem") (core func $return')) - (core instance $core_caller (instantiate $CoreCaller (with "" (instance - (export "mem" (memory $memory "mem")) - (export "subtask.drop" (func $subtask.drop)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "loop" (func $loop')) - (export "return" (func $return')) - )))) - (func (export "drop-after-return") async (result u32) (canon lift - (core func $core_caller "drop-after-return") - )) - (func (export "drop-before-return") async (result u32) (canon lift - (core func $core_caller "drop-before-return") - )) - ) - - (instance $looper (instantiate $Looper)) - (instance $caller1 (instantiate $Caller (with "looper" (instance $looper)))) - (instance $caller2 (instantiate $Caller (with "looper" (instance $looper)))) - (func (export "drop-after-return") (alias export $caller1 "drop-after-return")) - (func (export "drop-before-return") (alias export $caller2 "drop-before-return")) -) -(assert_return (invoke "drop-after-return") (u32.const 42)) -(assert_trap (invoke "drop-before-return") "cannot drop a subtask which has not yet resolved") diff --git a/src/test/resources/spec-tests/async/drop-waitable-set.wast b/src/test/resources/spec-tests/async/drop-waitable-set.wast deleted file mode 100644 index 23fff15..0000000 --- a/src/test/resources/spec-tests/async/drop-waitable-set.wast +++ /dev/null @@ -1,84 +0,0 @@ -;; This test contains two components $C and $D -;; $D.run drives the test and first calls $C.wait-on-set, which waits on -;; a waitable-set. Then $D.run calls $C.drop-while-waiting which attempts -;; to drop the same waitable-set, which should trap. -(component - (component $C - (core module $Core - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.drop" (func $waitable-set.drop (param i32))) - - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - (func $wait-on-set (export "wait-on-set") (result i32) - ;; wait on $ws - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) - ) - (func $drop-while-waiting (export "drop-while-waiting") (result i32) - ;; boom - (call $waitable-set.drop (global.get $ws)) - unreachable - ) - (func $unreachable-cb (export "unreachable-cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.drop (core func $waitable-set.drop)) - (core instance $core (instantiate $Core (with "" (instance - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.drop" (func $waitable-set.drop)) - )))) - (func (export "wait-on-set") async (canon lift - (core func $core "wait-on-set") - async (callback (func $core "unreachable-cb")) - )) - (func (export "drop-while-waiting") async (canon lift - (core func $core "drop-while-waiting") - async (callback (func $core "unreachable-cb")) - )) - ) - - (component $D - (import "c" (instance $c - (export "wait-on-set" (func async)) - (export "drop-while-waiting" (func async)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "wait-on-set" (func $wait-on-set (result i32))) - (import "" "drop-while-waiting" (func $drop-while-waiting)) - (func $run (export "run") (result i32) - (local $ret i32) - - ;; start an async call to 'wait-on-set' which blocks, waiting on a - ;; waitable-set. - (local.set $ret (call $wait-on-set)) - (if (i32.ne (i32.const 0x11) (local.get $ret)) - (then unreachable)) - - ;; this call will try to drop the same waitable-set, which should trap. - (call $drop-while-waiting) - unreachable - ) - ) - (canon lower (func $c "wait-on-set") async (memory $memory "mem") (core func $wait-on-set')) - (canon lower (func $c "drop-while-waiting") (core func $drop-while-waiting')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "wait-on-set" (func $wait-on-set')) - (export "drop-while-waiting" (func $drop-while-waiting')) - )))) - (func (export "run") async (result u32) (canon lift (core func $core "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "run") (alias export $d "run")) -) -(assert_trap (invoke "run") "cannot drop waitable set with waiters") diff --git a/src/test/resources/spec-tests/async/empty-wait.wast b/src/test/resources/spec-tests/async/empty-wait.wast deleted file mode 100644 index 8b4d789..0000000 --- a/src/test/resources/spec-tests/async/empty-wait.wast +++ /dev/null @@ -1,199 +0,0 @@ -;; This test has two components $C and $D, where $D imports and calls $C -;; $C exports two functions: 'blocker' and 'unblocker' -;; 'blocker' blocks on an empty waitable set -;; 'unblocker' wakes blocker by adding a resolved future to blocker's waitable set -;; $D calls 'blocker' then 'unblocker', then waits for 'blocker' to finish -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "future.drop-readable" (func $future.drop-readable (param i32))) - (import "" "future.drop-writable" (func $future.drop-writable (param i32))) - - ;; $ws is waited on by 'blocker' and added to by 'unblocker' - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - ;; 'unblocker' initializes $futr with the readable end of a resolved future - (global $futr (mut i32) (i32.const 0)) - - (func $blocker (export "blocker") (result i32) - ;; wait on $ws which is currently empty; 'unblocker' will wake us up - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) - ) - (func $blocker_cb (export "blocker_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - ;; assert that we were in fact woken by 'unblocker' adding $futr to $ws - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (global.get $futr) (local.get $index)) - (then unreachable)) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $payload)) - (then unreachable)) - - (call $future.drop-readable (global.get $futr)) - - ;; return 42 to $D.run - (call $task.return (i32.const 42)) - (i32.const 0) - ) - - (func $unblocker (export "unblocker") (result i32) - (local $ret i32) (local $ret64 i64) - (local $futw i32) - - ;; create a future that will be used to unblock 'blocker', storing r/w ends in $futr/$futw - (local.set $ret64 (call $future.new)) - (global.set $futr (i32.wrap_i64 (local.get $ret64))) - (if (i32.ne (i32.const 2) (global.get $futr)) - (then unreachable)) - (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (if (i32.ne (i32.const 3) (local.get $futw)) - (then unreachable)) - - ;; perform a future.read which will block, and add this future to the waitable-set - ;; being waited on by 'blocker' - (local.set $ret (call $future.read (global.get $futr) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (global.get $futr) (global.get $ws)) - - ;; perform a future.write which will rendezvous with the write and complete - (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - (call $future.drop-writable (local.get $futw)) - - ;; return 43 to $D.run - (call $task.return (i32.const 43)) - (i32.const 0) - ) - (func $unblocker_cb (export "unblocker_cb") (param i32 i32 i32) (result i32) - ;; 'unblocker' doesn't block - unreachable - ) - ) - (type $FT (future)) - (canon task.return (result u32) (core func $task.return)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon future.new $FT (core func $future.new)) - (canon future.read $FT async (core func $future.read)) - (canon future.write $FT async (core func $future.write)) - (canon future.drop-readable $FT (core func $future.drop-readable)) - (canon future.drop-writable $FT (core func $future.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "future.new" (func $future.new)) - (export "future.read" (func $future.read)) - (export "future.write" (func $future.write)) - (export "future.drop-readable" (func $future.drop-readable)) - (export "future.drop-writable" (func $future.drop-writable)) - )))) - (func (export "blocker") async (result u32) (canon lift - (core func $cm "blocker") - async (callback (func $cm "blocker_cb")) - )) - (func (export "unblocker") async (result u32) (canon lift - (core func $cm "unblocker") - async (callback (func $cm "unblocker_cb")) - )) - ) - - (component $D - (import "c" (instance $c - (export "blocker" (func async (result u32))) - (export "unblocker" (func async (result u32))) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "subtask.drop" (func $subtask.drop (param i32))) - (import "" "blocker" (func $blocker (param i32) (result i32))) - (import "" "unblocker" (func $unblocker (param i32) (result i32))) - - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - (func $run (export "run") (result i32) - (local $ret i32) (local $retp1 i32) (local $retp2 i32) - (local $subtask i32) - (local $event_code i32) - - ;; call 'blocker'; it should block - (local.set $retp1 (i32.const 4)) - (local.set $ret (call $blocker (local.get $retp1))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (if (i32.ne (i32.const 2) (local.get $subtask)) - (then unreachable)) - - ;; call 'unblocker' to unblock 'blocker'; it should complete eagerly - (local.set $retp2 (i32.const 8)) - (local.set $ret (call $unblocker (local.get $retp2))) - (if (i32.ne (i32.const 2 (; RETURNED ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 43) (i32.load (local.get $retp2))) - (then unreachable)) - - ;; wait for 'blocker' to be scheduled, run, and return - (call $waitable.join (local.get $subtask) (global.get $ws)) - (local.set $retp2 (i32.const 8)) - (local.set $event_code (call $waitable-set.wait (global.get $ws) (local.get $retp2))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (i32.load offset=4 (local.get $retp2))) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load (local.get $retp1))) - (then unreachable)) - - (call $subtask.drop (local.get $subtask)) - - ;; return 44 to the top-level test harness - (i32.const 44) - ) - ) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon subtask.drop (core func $subtask.drop)) - (canon lower (func $c "blocker") async (memory $memory "mem") (core func $blocker')) - (canon lower (func $c "unblocker") async (memory $memory "mem") (core func $unblocker')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "subtask.drop" (func $subtask.drop)) - (export "blocker" (func $blocker')) - (export "unblocker" (func $unblocker')) - )))) - (func (export "run") async (result u32) (canon lift (core func $dm "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "run") (alias export $d "run")) -) -(assert_return (invoke "run") (u32.const 44)) diff --git a/src/test/resources/spec-tests/async/futures-must-write.wast b/src/test/resources/spec-tests/async/futures-must-write.wast deleted file mode 100644 index ce2446b..0000000 --- a/src/test/resources/spec-tests/async/futures-must-write.wast +++ /dev/null @@ -1,118 +0,0 @@ -;; This test contains two components $C and $D that test that a trap occurs -;; when closing the writable end of a future (in $C) before having written -;; a value while closing the readable end of a future (in $D) before reading -;; a value is fine. -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "future.drop-writable" (func $future.drop-writable (param i32))) - - (global $fw (mut i32) (i32.const 0)) - - (func $start-future (export "start-future") (result i32) - ;; create a new future, return the readable end to the caller - (local $ret64 i64) - (local.set $ret64 (call $future.new)) - (global.set $fw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (i32.wrap_i64 (local.get $ret64)) - ) - (func $attempt-write (export "attempt-write") (result i32) - ;; because the caller already dropped the readable end, this write will eagerly - ;; return DROPPED having written no values. - (local $ret i32) - (local.set $ret (call $future.write (global.get $fw) (i32.const 42))) - (if (i32.ne (i32.const 0x01 (; DROPPED ;)) (local.get $ret)) - (then unreachable)) - - ;; return without trapping - (i32.const 42) - ) - (func $drop-writable (export "drop-writable") - ;; maybe boom - (call $future.drop-writable (global.get $fw)) - ) - ) - (type $FT (future u8)) - (canon future.new $FT (core func $future.new)) - (canon future.write $FT async (memory $memory "mem") (core func $future.write)) - (canon future.drop-writable $FT (core func $future.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "future.new" (func $future.new)) - (export "future.write" (func $future.write)) - (export "future.drop-writable" (func $future.drop-writable)) - )))) - (func (export "start-future") (result (future u8)) (canon lift (core func $cm "start-future"))) - (func (export "attempt-write") (result u32) (canon lift (core func $cm "attempt-write"))) - (func (export "drop-writable") (canon lift (core func $cm "drop-writable"))) - ) - (component $D - (import "c" (instance $c - (export "start-future" (func (result (future u8)))) - (export "attempt-write" (func (result u32))) - (export "drop-writable" (func)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "future.drop-readable" (func $future.drop-readable (param i32))) - (import "" "start-future" (func $start-future (result i32))) - (import "" "attempt-write" (func $attempt-write (result i32))) - (import "" "drop-writable" (func $drop-writable)) - - (func $drop-readable-future-before-read (export "drop-readable-future-before-read") (result i32) - ;; call 'start-future' to get the future we'll be working with - (local $fr i32) - (local.set $fr (call $start-future)) - (if (i32.ne (i32.const 1) (local.get $fr)) - (then unreachable)) - - ;; ok to immediately drop the readable end - (call $future.drop-readable (local.get $fr)) - - ;; the callee will see that we dropped the readable end when it tries to write - (call $attempt-write) - ) - (func $drop-writable-future-before-write (export "drop-writable-future-before-write") - ;; call 'start-future' to get the future we'll be working with - (local $fr i32) - (local.set $fr (call $start-future)) - (if (i32.ne (i32.const 1) (local.get $fr)) - (then unreachable)) - - ;; boom - (call $drop-writable) - ) - ) - (type $FT (future u8)) - (canon future.new $FT (core func $future.new)) - (canon future.drop-readable $FT (core func $future.drop-readable)) - (canon lower (func $c "start-future") (core func $start-future')) - (canon lower (func $c "attempt-write") (core func $attempt-write')) - (canon lower (func $c "drop-writable") (core func $drop-writable')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "future.new" (func $future.new)) - (export "future.drop-readable" (func $future.drop-readable)) - (export "start-future" (func $start-future')) - (export "attempt-write" (func $attempt-write')) - (export "drop-writable" (func $drop-writable')) - )))) - (func (export "drop-readable-future-before-read") (result u32) (canon lift (core func $core "drop-readable-future-before-read"))) - (func (export "drop-writable-future-before-write") (canon lift (core func $core "drop-writable-future-before-write"))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "drop-writable-future-before-write") (alias export $d "drop-writable-future-before-write")) - (func (export "drop-readable-future-before-read") (alias export $d "drop-readable-future-before-read")) -) - -(assert_return (invoke "drop-readable-future-before-read") (u32.const 42)) -(assert_trap (invoke "drop-writable-future-before-write") "cannot drop future write end without first writing a value") diff --git a/src/test/resources/spec-tests/async/partial-stream-copies.wast b/src/test/resources/spec-tests/async/partial-stream-copies.wast deleted file mode 100644 index d70ece2..0000000 --- a/src/test/resources/spec-tests/async/partial-stream-copies.wast +++ /dev/null @@ -1,238 +0,0 @@ -;; This test has two components $C and $D, where $D imports and calls $C.transform -;; $C.transform takes and returns a stream -;; Before $C.transform blocks the first time, it supplies a 12-byte read buffer -;; When $D.run regains control after $C.transform blocks, it can perform multiple -;; successful writes until it fully uses up the 12-byte buffer. -;; ... and that's where I am so far ... -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - ;; $ws is waited on by 'transform' - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - ;; $insr/$outsw are read/written by 'transform' - (global $insr (mut i32) (i32.const 0)) - (global $inbufp (mut i32) (i32.const 0x10)) - (global $outsw (mut i32) (i32.const 0)) - (global $outbufp (mut i32) (i32.const 0x20)) - - (func $transform (export "transform") (param i32) (result i32) - (local $ret i32) (local $ret64 i64) (local $outsr i32) - - ;; check the incoming readable stream end - (global.set $insr (local.get 0)) - (if (i32.ne (i32.const 2) (global.get $insr)) - (then unreachable)) - - ;; create a new stream r/w pair $outsr/$outsw - (local.set $ret64 (call $stream.new)) - (local.set $outsr (i32.wrap_i64 (local.get $ret64))) - (if (i32.ne (i32.const 3) (local.get $outsr)) - (then unreachable)) - (global.set $outsw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (if (i32.ne (i32.const 4) (global.get $outsw)) - (then unreachable)) - - ;; start async read on $insr which will block - (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 12))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; return the readable end of the outgoing stream to the caller - (call $task.return (local.get $outsr)) - - ;; wait for the stream.read/write to complete - (call $waitable.join (global.get $insr) (global.get $ws)) - (call $waitable.join (global.get $outsw) (global.get $ws)) - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) - ) - (func $transform_cb (export "transform_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - (local $ret i32) (local $ret64 i64) - - ;; confirm the read succeeded fully - (if (i32.ne (local.get $event_code) (i32.const 2 (; STREAM_READ ;))) - (then unreachable)) - (if (i32.ne (local.get $index) (global.get $insr)) - (then unreachable)) - (if (i32.ne (local.get $payload) (i32.const 0xc0 (; COMPLETED=0 | (12 << 4) ;))) - (then unreachable)) - (if (i32.ne (i32.const 0x89abcdef) (i32.load offset=0 (global.get $inbufp))) - (then unreachable)) - (if (i32.ne (i32.const 0x01234567) (i32.load offset=4 (global.get $inbufp))) - (then unreachable)) - (if (i32.ne (i32.const 0x89abcdef) (i32.load offset=8 (global.get $inbufp))) - (then unreachable)) - - ;; multiple read calls succeed until 12-byte buffer is consumed - (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 4))) - (if (i32.ne (i32.const 0x40) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0x76543210) (i32.load (global.get $inbufp))) - (then unreachable)) - (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 2))) - (if (i32.ne (i32.const 0x20) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0xba98) (i32.load16_u (global.get $inbufp))) - (then unreachable)) - (local.set $ret (call $stream.read (global.get $insr) (global.get $inbufp) (i32.const 8))) - (if (i32.ne (i32.const 0x60) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0x3210fedc) (i32.load (global.get $inbufp))) - (then unreachable)) - (if (i32.ne (i32.const 0x7654) (i32.load16_u offset=4 (global.get $inbufp))) - (then unreachable)) - - (call $stream.drop-readable (global.get $insr)) - (call $stream.drop-writable (global.get $outsw)) - (return (i32.const 0 (; EXIT ;))) - ) - ) - (type $ST (stream u8)) - (canon task.return (result $ST) (memory $memory "mem") (core func $task.return)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (func (export "transform") async (param "in" (stream u8)) (result (stream u8)) (canon lift - (core func $cm "transform") - async (memory $memory "mem") (callback (func $cm "transform_cb")) - )) - ) - - (component $D - (import "transform" (func $transform async (param "in" (stream u8)) (result (stream u8)))) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - (import "" "transform" (func $transform (param i32 i32) (result i32))) - - (func $run (export "run") (result i32) - (local $ret i32) (local $ret64 i64) (local $retp i32) - (local $insr i32) (local $insw i32) (local $outsr i32) - (local $subtask i32) (local $event_code i32) (local $index i32) (local $payload i32) - (local $ws i32) - - ;; create a new stream r/w pair $insr/$insw - (local.set $ret64 (call $stream.new)) - (local.set $insr (i32.wrap_i64 (local.get $ret64))) - (if (i32.ne (i32.const 1) (local.get $insr)) - (then unreachable)) - (local.set $insw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (if (i32.ne (i32.const 2) (local.get $insw)) - (then unreachable)) - - ;; call 'transform' which will return a readable stream $outsr eagerly - (local.set $retp (i32.const 8)) - (local.set $ret (call $transform (local.get $insr) (local.get $retp))) - (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (local.get $ret)) - (then unreachable)) - (local.set $outsr (i32.load (local.get $retp))) - (if (i32.ne (i32.const 1) (local.get $outsr)) - (then unreachable)) - - ;; multiple write calls succeed until 12-byte buffer is filled - (i64.store (i32.const 16) (i64.const 0x0123456789abcdef)) - (local.set $ret (call $stream.write (local.get $insw) (i32.const 16) (i32.const 8))) - (if (i32.ne (i32.const 0x80) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $stream.write (local.get $insw) (i32.const 16) (i32.const 8))) - (if (i32.ne (i32.const 0x40) (local.get $ret)) - (then unreachable)) - - ;; start a blocking write with a 12-byte buffer - (i64.store (i32.const 16) (i64.const 0xfedcba9876543210)) - (i32.store (i32.const 24) (i32.const 0x76543210)) - (local.set $ret (call $stream.write (local.get $insw) (i32.const 16) (i32.const 12))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; wait for transform to read our write and drop all the streams - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $insw) (local.get $ws)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (i32.const 0))) - (local.set $index (i32.load (i32.const 0))) - (local.set $payload (i32.load (i32.const 4))) - - ;; confirm the write and the dropped stream - (if (i32.ne (local.get $event_code) (i32.const 3 (; STREAM_WRITE ;))) - (then unreachable)) - (if (i32.ne (local.get $index) (local.get $insw)) - (then unreachable)) - (if (i32.ne (local.get $payload) (i32.const 0xc1 (; DROPPED=1 | (12 << 4) ;))) - (then unreachable)) - - (call $stream.drop-writable (local.get $insw)) - (call $stream.drop-readable (local.get $outsr)) - - ;; return 42 to the top-level test harness - (i32.const 42) - ) - ) - (type $ST (stream u8)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (canon lower (func $transform) async (memory $memory "mem") (core func $transform')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "stream.drop-writable" (func $stream.drop-writable)) - (export "transform" (func $transform')) - )))) - (func (export "run") async (result u32) (canon lift (core func $dm "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "transform" (func $c "transform")))) - (func (export "run") (alias export $d "run")) -) -(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/passing-resources.wast b/src/test/resources/spec-tests/async/passing-resources.wast deleted file mode 100644 index d8a7c50..0000000 --- a/src/test/resources/spec-tests/async/passing-resources.wast +++ /dev/null @@ -1,176 +0,0 @@ -;; This test contains two components, $Producer and $Consumer. -;; $Producer.run drives the test and calls $Producer.start-stream to create -;; a stream and attempt to write 2 owned handles. $Producer.run then reads -;; just 1 element. The test finishes by confirming that $Consumer owns the -;; first resource, $Producer (still) owns the second resource, and $Producer -;; traps if it attempts to access the index of the first resource. -(component - (component $Producer - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "resource.new" (func $resource.new (param i32) (result i32))) - (import "" "resource.rep" (func $resource.rep (param i32) (result i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - (global $ws (mut i32) (i32.const 0)) - (global $res1 (mut i32) (i32.const 0)) - (global $res2 (mut i32) (i32.const 0)) - - (func $start-stream (export "start-stream") (result i32) - (local $ret i32) (local $ret64 i64) - (local $rs i32) - - ;; create a new stream, return the readable end to the caller - (local.set $ret64 (call $stream.new)) - (global.set $ws (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $rs (i32.wrap_i64 (local.get $ret64))) - - ;; create two resources and write them into a buffer to pass to stream.write - (global.set $res1 (call $resource.new (i32.const 50))) - (global.set $res2 (call $resource.new (i32.const 51))) - (i32.store (i32.const 8) (global.get $res1)) - (i32.store (i32.const 12) (global.get $res2)) - - ;; start a write which will block - (local.set $ret (call $stream.write (global.get $ws) (i32.const 8) (i32.const 2))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; check that this instance still owns both resources (ownership has not - ;; yet been transferred). - (if (i32.ne (i32.const 50) (call $resource.rep (global.get $res1))) - (then unreachable)) - (if (i32.ne (i32.const 51) (call $resource.rep (global.get $res2))) - (then unreachable)) - - (local.get $rs) - ) - (func $cancel-write (export "cancel-write") - (local $ret i32) - - ;; cancel the write, confirming that the first element was transferred - (local.set $ret (call $stream.cancel-write (global.get $ws))) - (if (i32.ne (i32.const 0x11 (; DROPPED=1 | (1 << 4) ;)) (local.get $ret)) - (then unreachable)) - - ;; we still own $res2 - (if (i32.ne (i32.const 51) (call $resource.rep (global.get $res2))) - (then unreachable)) - - (call $stream.drop-writable (global.get $ws)) - ) - (func $R.foo (export "R.foo") (param $rep i32) (result i32) - (i32.add (local.get $rep) (i32.const 50)) - ) - (func $fail-accessing-res1 (export "fail-accessing-res1") - ;; boom - (call $resource.rep (global.get $res1)) - unreachable - ) - ) - (type $R (resource (rep i32))) - (type $ST (stream (own $R))) - (canon resource.new $R (core func $resource.new)) - (canon resource.rep $R (core func $resource.rep)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.cancel-write $ST (core func $stream.cancel-write)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "resource.new" (func $resource.new)) - (export "resource.rep" (func $resource.rep)) - (export "stream.new" (func $stream.new)) - (export "stream.write" (func $stream.write)) - (export "stream.cancel-write" (func $stream.cancel-write)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (export $R' "R" (type $R)) - (func (export "[method]R.foo") async (param "self" (borrow $R')) (result u32) (canon lift (core func $core "R.foo"))) - (func (export "start-stream") async (result (stream (own $R'))) (canon lift (core func $core "start-stream"))) - (func (export "cancel-write") async (canon lift (core func $core "cancel-write"))) - (func (export "fail-accessing-res1") async (canon lift (core func $core "fail-accessing-res1"))) - ) - - (component $Consumer - (import "producer" (instance $producer - (export "R" (type $R (sub resource))) - (export "[method]R.foo" (func async (param "self" (borrow $R)) (result u32))) - (export "start-stream" (func async (result (stream (own $R))))) - (export "cancel-write" (func async)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "R.foo" (func $R.foo (param i32) (result i32))) - (import "" "start-stream" (func $start-stream (result i32))) - (import "" "cancel-write" (func $cancel-write)) - - (func $run (export "run") (result i32) - (local $ret i32) (local $rs i32) - (local $res1 i32) - - ;; get the readable end of a stream which has a pending write - (local.set $rs (call $start-stream)) - (if (i32.ne (local.get $rs) (i32.const 1)) - (then unreachable)) - - ;; read only 1 (of the 2 pending) elements, which won't block - (i64.store (i32.const 8) (i64.const 0xdeadbeefdeadbeef)) - (local.set $ret (call $stream.read (local.get $rs) (i32.const 8) (i32.const 1))) - (if (i32.ne (i32.const 0x10) (local.get $ret)) - (then unreachable)) - - ;; only 1 handle should have been transferred - (local.set $res1 (i32.load (i32.const 8))) - (if (i32.ne (i32.load (i32.const 12)) (i32.const 0xdeadbeef)) - (then unreachable)) - - ;; check that we got the first resource and it works - (local.set $ret (call $R.foo (local.get $res1))) - (if (i32.ne (i32.const 100) (local.get $ret)) - (then unreachable)) - - ;; drop the stream and then let $C run and assert stuff - (call $stream.drop-readable (local.get $rs)) - (call $cancel-write) - - (i32.const 42) - ) - ) - (alias export $producer "R" (type $R)) - (type $ST (stream (own $R))) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon lower (func $producer "[method]R.foo") (core func $R.foo')) - (canon lower (func $producer "start-stream") (core func $start-stream')) - (canon lower (func $producer "cancel-write") (core func $cancel-write')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "stream.read" (func $stream.read)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "R.foo" (func $R.foo')) - (export "start-stream" (func $start-stream')) - (export "cancel-write" (func $cancel-write')) - )))) - (func (export "run") async (result u32) (canon lift - (core func $core "run") - )) - ) - - (instance $producer (instantiate $Producer)) - (instance $consumer (instantiate $Consumer (with "producer" (instance $producer)))) - (func (export "run") (alias export $consumer "run")) - (func (export "fail-accessing-res1") (alias export $producer "fail-accessing-res1")) -) -(assert_return (invoke "run") (u32.const 42)) -(assert_trap (invoke "fail-accessing-res1") "unknown handle index 3") diff --git a/src/test/resources/spec-tests/async/same-component-stream-future.wast b/src/test/resources/spec-tests/async/same-component-stream-future.wast deleted file mode 100644 index 18d4a14..0000000 --- a/src/test/resources/spec-tests/async/same-component-stream-future.wast +++ /dev/null @@ -1,259 +0,0 @@ -;; This test tests same-component reading/writing of a stream and future -;; from the same component instance (which either traps or succeeds), -;; depending on the element type. - -(component definition $Tester - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $M - (import "" "mem" (memory 1)) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "future.newb" (func $future.newb (result i64))) - (import "" "future.readb" (func $future.readb (param i32 i32) (result i32))) - (import "" "future.writeb" (func $future.writeb (param i32 i32) (result i32))) - (import "" "stream.newb" (func $stream.newb (result i64))) - (import "" "stream.readb" (func $stream.readb (param i32 i32 i32) (result i32))) - (import "" "stream.writeb" (func $stream.writeb (param i32 i32 i32) (result i32))) - (import "" "future.newc" (func $future.newc (result i64))) - (import "" "future.readc" (func $future.readc (param i32 i32) (result i32))) - (import "" "future.writec" (func $future.writec (param i32 i32) (result i32))) - - (func (export "test-empty") (result i32) - (local $ret i32) (local $ret64 i64) - (local $rx i32) (local $tx i32) - - ;; test future reader then writer - (local.set $ret64 (call $future.new)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $future.read (local.get $rx) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $future.write (local.get $tx) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - ;; test future writer than reader - (local.set $ret64 (call $future.new)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $future.write (local.get $tx) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $future.read (local.get $rx) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - ;; test stream reader then writer - (local.set $ret64 (call $stream.new)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $stream.read (local.get $rx) (i32.const 0xdeadbeef) (i32.const 1))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $stream.write (local.get $tx) (i32.const 0xdeadbeef) (i32.const 1))) - (if (i32.ne (i32.const 0x10 (; COMPLETED=0 | (1<<4) ;)) (local.get $ret)) - (then unreachable)) - - ;; test stream writer than reader - (local.set $ret64 (call $stream.new)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $stream.write (local.get $tx) (i32.const 0xdeadbeef) (i32.const 1))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $stream.read (local.get $rx) (i32.const 0xdeadbeef) (i32.const 1))) - (if (i32.ne (i32.const 0x10 (; COMPLETED=0 | (1<<4) ;)) (local.get $ret)) - (then unreachable)) - - (i32.const 42) - ) - - (func $test-stream (param $srcp i32) (param $dstp i32) - (local $ret i32) (local $ret64 i64) - (local $rx i32) (local $tx i32) - - ;; test stream reader then writer - (i64.store (local.get $dstp) (i64.const 0)) - (i64.store (local.get $srcp) (i64.const 0x0123456789abcdef)) - (local.set $ret64 (call $stream.newb)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $stream.readb (local.get $rx) (local.get $dstp) (i32.const 8))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $stream.writeb (local.get $tx) (local.get $srcp) (i32.const 8))) - (if (i32.ne (i32.const 0x80 (; COMPLETED=0 | (8<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i64.ne (i64.load (local.get $dstp)) (i64.const 0x0123456789abcdef)) - (then unreachable)) - - ;; test stream writer than reader - (i64.store (local.get $dstp) (i64.const 0)) - (i64.store (local.get $srcp) (i64.const 0x0123456789abcdef)) - (local.set $ret64 (call $stream.newb)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $stream.writeb (local.get $tx) (local.get $srcp) (i32.const 8))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $stream.readb (local.get $rx) (local.get $dstp) (i32.const 8))) - (if (i32.ne (i32.const 0x80 (; COMPLETED=0 | (8<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i64.ne (i64.load (local.get $dstp)) (i64.const 0x0123456789abcdef)) - (then unreachable)) - ) - - (func (export "test-bytes") (result i32) - (local $ret i32) (local $ret64 i64) - (local $rx i32) (local $tx i32) - (local $dstp i32) (local $srcp i32) - - ;; because pointers must be aligned and futures are single-element, - ;; it's not possible to test the interesting overlap case - (local.set $srcp (i32.const 16)) - (local.set $dstp (i32.const 17)) - (i32.store8 (local.get $dstp) (i32.const 0)) - (i32.store8 (local.get $srcp) (i32.const 42)) - - ;; test future reader then writer - (local.set $ret64 (call $future.newb)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $future.readb (local.get $rx) (local.get $dstp))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $future.writeb (local.get $tx) (local.get $srcp))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.load8_u (local.get $dstp)) (i32.const 42)) - (then unreachable)) - - ;; reset memory and then test future writer than reader - (i32.store8 (local.get $dstp) (i32.const 0)) - (i32.store8 (local.get $srcp) (i32.const 42)) - (local.set $ret64 (call $future.newb)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $future.writeb (local.get $tx) (local.get $srcp))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (call $future.readb (local.get $rx) (local.get $dstp))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.load8_u (local.get $dstp)) (i32.const 42)) - (then unreachable)) - - ;; test a bunch of different overlapping cases - (call $test-stream (i32.const 16) (i32.const 8)) - (call $test-stream (i32.const 16) (i32.const 9)) - (call $test-stream (i32.const 16) (i32.const 10)) - (call $test-stream (i32.const 16) (i32.const 11)) - (call $test-stream (i32.const 16) (i32.const 12)) - (call $test-stream (i32.const 16) (i32.const 13)) - (call $test-stream (i32.const 16) (i32.const 14)) - (call $test-stream (i32.const 16) (i32.const 15)) - (call $test-stream (i32.const 16) (i32.const 16)) - (call $test-stream (i32.const 16) (i32.const 17)) - (call $test-stream (i32.const 16) (i32.const 18)) - (call $test-stream (i32.const 16) (i32.const 19)) - (call $test-stream (i32.const 16) (i32.const 20)) - (call $test-stream (i32.const 16) (i32.const 21)) - (call $test-stream (i32.const 16) (i32.const 22)) - (call $test-stream (i32.const 16) (i32.const 23)) - (call $test-stream (i32.const 16) (i32.const 24)) - - (i32.const 43) - ) - - (func (export "test-no-read-char") - (local $ret i32) (local $ret64 i64) - (local $rx i32) (local $tx i32) - (local.set $ret64 (call $future.newc)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $future.readc (local.get $rx) (i32.const 0))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (call $future.writec (local.get $tx) (i32.const 0)) - unreachable - ) - - (func (export "test-no-write-char") - (local $ret i32) (local $ret64 i64) - (local $rx i32) (local $tx i32) - (local.set $ret64 (call $future.newc)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (local.set $ret (call $future.writec (local.get $tx) (i32.const 0))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (call $future.readc (local.get $rx) (i32.const 0)) - unreachable - ) - ) - (type $FT (future)) - (type $ST (stream)) - (type $FTB (future u8)) - (type $STB (stream u8)) - (type $FTC (future char)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon future.new $FT (core func $future.new)) - (canon future.read $FT async (core func $future.read)) - (canon future.write $FT async (core func $future.write)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST async (core func $stream.read)) - (canon stream.write $ST async (core func $stream.write)) - (canon future.new $FTB (core func $future.newb)) - (canon future.read $FTB async (memory $memory "mem") (core func $future.readb)) - (canon future.write $FTB async (memory $memory "mem") (core func $future.writeb)) - (canon stream.new $STB (core func $stream.newb)) - (canon stream.read $STB async (memory $memory "mem") (core func $stream.readb)) - (canon stream.write $STB async (memory $memory "mem") (core func $stream.writeb)) - (canon future.new $FTC (core func $future.newc)) - (canon future.read $FTC async (memory $memory "mem") (core func $future.readc)) - (canon future.write $FTC async (memory $memory "mem") (core func $future.writec)) - (core instance $m (instantiate $M (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "future.new" (func $future.new)) - (export "future.read" (func $future.read)) - (export "future.write" (func $future.write)) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "future.newb" (func $future.newb)) - (export "future.readb" (func $future.readb)) - (export "future.writeb" (func $future.writeb)) - (export "stream.newb" (func $stream.newb)) - (export "stream.readb" (func $stream.readb)) - (export "stream.writeb" (func $stream.writeb)) - (export "future.newc" (func $future.newc)) - (export "future.readc" (func $future.readc)) - (export "future.writec" (func $future.writec)) - )))) - (func (export "test-empty") (result u32) (canon lift (core func $m "test-empty"))) - (func (export "test-bytes") (result u32) (canon lift (core func $m "test-bytes"))) - (func (export "test-no-read-char") (canon lift (core func $m "test-no-read-char"))) - (func (export "test-no-write-char") (canon lift (core func $m "test-no-write-char"))) -) -(component instance $i $Tester) -(assert_return (invoke "test-empty") (u32.const 42)) -(component instance $i $Tester) -(assert_return (invoke "test-bytes") (u32.const 43)) -(component instance $i $Tester) -(assert_trap (invoke "test-no-read-char") "cannot read from and write to intra-component future") -(component instance $i $Tester) -(assert_trap (invoke "test-no-write-char") "cannot read from and write to intra-component future") diff --git a/src/test/resources/spec-tests/async/sync-barges-in.wast b/src/test/resources/spec-tests/async/sync-barges-in.wast deleted file mode 100644 index 3161f93..0000000 --- a/src/test/resources/spec-tests/async/sync-barges-in.wast +++ /dev/null @@ -1,311 +0,0 @@ -;; This test tests that a blocked previous sync- or async-lifted callee -;; can be synchronously reentered by a sync-typed function without the -;; usual backpressure triggering. The $Tester component has two nested -;; components $C and $D, where $D imports and calls $C. $C contains utilities -;; used by $D to perform all the tests. -(component definition $Tester - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "thread.yield" (func $thread.yield (result i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - - (global $unblock-value (mut i32) (i32.const 0)) - - ;; $ws is waited on by 'blocker' and added to by 'unblocker' - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - (func (export "blocker") - ;; wait on $ws, which is initially empty, but will be populated with - ;; a completed future when "unblocker" synchronously barges in. - (local $ret i32) - (local.set $ret (call $waitable-set.wait (global.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (i32.load (i32.const 4))) - (then unreachable)) - - (call $task.return (global.get $unblock-value)) - ) - - (func (export "blocker-cb") (result i32) - ;; wait on $ws, which is initially empty, but will be populated with - ;; a completed future when "unblocker" synchronously barges in. - (i32.or - (i32.const 2 (; WAIT ;)) - (i32.shl (global.get $ws) (i32.const 4))) - ) - (func (export "blocker-cb-cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $payload)) - (then unreachable)) - - (call $task.return (global.get $unblock-value)) - (i32.const 0 (; EXIT ;)) - ) - - (func $unblocker (export "unblocker") (param $val i32) - (local $ret i32) (local $ret64 i64) - (local $futr i32) (local $futw i32) - - ;; create read/write futures that will be used to unblock 'blocker' - (local.set $ret64 (call $future.new)) - (local.set $futr (i32.wrap_i64 (local.get $ret64))) - (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - - ;; perform a future.read which will block, and add this future to the waitable-set - ;; being waited on by 'blocker' - (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - (call $waitable.join (local.get $futr) (global.get $ws)) - - ;; perform a future.write which will rendezvous with the write and complete - (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - (global.set $unblock-value (local.get $val)) - ) - - (func (export "yielder") - (drop (call $thread.yield)) - (call $task.return (global.get $unblock-value)) - ) - (func (export "yielder-cb") (result i32) - (i32.const 1 (; YIELD ;)) - ) - (func (export "yielder-cb-cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - (if (i32.ne (i32.const 0 (; EVENT_NONE ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (i32.const 0) (local.get $index)) - (then unreachable)) - (if (i32.ne (i32.const 0) (local.get $payload)) - (then unreachable)) - (call $task.return (global.get $unblock-value)) - (i32.const 0 (; EXIT ;)) - ) - (func (export "poker") (param $val i32) - (global.set $unblock-value (local.get $val)) - ) - ) - (type $FT (future)) - (canon task.return (result u32) (core func $task.return)) - (canon thread.yield (core func $thread.yield)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon future.new $FT (core func $future.new)) - (canon future.read $FT async (core func $future.read)) - (canon future.write $FT async (core func $future.write)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "thread.yield" (func $thread.yield)) - (export "task.return" (func $task.return)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "future.new" (func $future.new)) - (export "future.read" (func $future.read)) - (export "future.write" (func $future.write)) - )))) - (type $R (resource (rep i32) (dtor (func $cm "unblocker")))) - (type $S (resource (rep i32) (dtor (func $cm "poker")))) - (canon resource.new $R (core func $new-R)) - (canon resource.new $S (core func $new-S)) - (export $R' "R" (type $R)) - (export $S' "S" (type $S)) - (func (export "new-R") (param "rep" u32) (result (own $R')) (canon lift (core func $new-R))) - (func (export "blocker") async (result u32) (canon lift (core func $cm "blocker") async)) - (func (export "blocker-cb") async (result u32) (canon lift (core func $cm "blocker-cb") async (callback (func $cm "blocker-cb-cb")))) - (func (export "unblocker") (param "val" u32) (canon lift (core func $cm "unblocker"))) - (func (export "new-S") (param "rep" u32) (result (own $S')) (canon lift (core func $new-S))) - (func (export "yielder") async (result u32) (canon lift (core func $cm "yielder") async)) - (func (export "yielder-cb") async (result u32) (canon lift (core func $cm "yielder-cb") async (callback (func $cm "yielder-cb-cb")))) - (func (export "poker") (param "val" u32) (canon lift (core func $cm "poker"))) - ) - (component $D - (import "c" (instance $c - (export "R" (type $R (sub resource))) - (export "new-R" (func (param "rep" u32) (result (own $R)))) - (export "blocker" (func async (result u32))) - (export "blocker-cb" (func async (result u32))) - (export "unblocker" (func (param "val" u32))) - (export "S" (type $S (sub resource))) - (export "new-S" (func (param "rep" u32) (result (own $S)))) - (export "yielder" (func async (result u32))) - (export "yielder-cb" (func async (result u32))) - (export "poker" (func (param "val" u32))) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "subtask.drop" (func $subtask.drop (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.drop" (func $waitable-set.drop (param i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "waitable-set.poll" (func $waitable-set.poll (param i32 i32) (result i32))) - (import "" "new-R" (func $new-R (param i32) (result i32))) - (import "" "drop-R" (func $drop-R (param i32))) - (import "" "blocker" (func $blocker (param i32) (result i32))) - (import "" "blocker-cb" (func $blocker-cb (param i32) (result i32))) - (import "" "unblocker" (func $unblocker (param i32))) - (import "" "new-S" (func $new-S (param i32) (result i32))) - (import "" "drop-S" (func $drop-S (param i32))) - (import "" "yielder" (func $yielder (param i32) (result i32))) - (import "" "yielder-cb" (func $yielder-cb (param i32) (result i32))) - (import "" "poker" (func $poker (param i32))) - - (func $wait-for-return (param $subtask i32) (param $retp i32) (param $expect i32) - (local $outp i32) - (local $ws i32) (local $event_code i32) - - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $subtask) (local.get $ws)) - (local.set $outp (i32.const 32)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $outp))) - (if (i32.ne (i32.const 1 (; SUBTASK ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $subtask) (i32.load (local.get $outp))) - (then unreachable)) - (if (i32.ne (i32.const 2 (; RETURNED=2 ;)) (i32.load offset=4 (local.get $outp))) - (then unreachable)) - (if (i32.ne (local.get $expect) (i32.load (local.get $retp))) - (then unreachable)) - (call $subtask.drop (local.get $subtask)) - (call $waitable-set.drop (local.get $ws)) - ) - - (func (export "run") (result i32) - (local $ret i32) (local $retp i32) - (local $subtask i32) (local $handle i32) - - (local.set $retp (i32.const 8)) - - ;; call $blocker which will block during a synchronous function. - ;; normally calling another function would hit backpressure until - ;; $blocker was done, but calling the sync-typed function $unblocker - ;; barges in synchronously. - (local.set $ret (call $blocker (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $unblocker (i32.const 90)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 90)) - - ;; do it all again, but this time unblock via resource.drop: - (local.set $handle (call $new-R (i32.const 91))) - (local.set $ret (call $blocker (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $drop-R (local.get $handle)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 91)) - - ;; do both of the above again, but for $blocker-cb instead of $blocker - (local.set $ret (call $blocker-cb (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $unblocker (i32.const 92)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 92)) - (local.set $handle (call $new-R (i32.const 93))) - (local.set $ret (call $blocker-cb (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $drop-R (local.get $handle)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 93)) - - ;; now do all the above again, but for 'yielder'/'yielder-cb', which - ;; yield, instead of waiting, using 'poker' to deliver a specific value - (local.set $ret (call $yielder (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $poker (i32.const 94)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 94)) - (local.set $handle (call $new-S (i32.const 95))) - (local.set $ret (call $yielder (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $drop-S (local.get $handle)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 95)) - (local.set $ret (call $yielder-cb (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $poker (i32.const 96)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 96)) - (local.set $handle (call $new-S (i32.const 97))) - (local.set $ret (call $yielder-cb (local.get $retp))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $subtask (i32.shr_u (local.get $ret) (i32.const 4))) - (call $drop-S (local.get $handle)) - (call $wait-for-return (local.get $subtask) (local.get $retp) (i32.const 97)) - - (i32.const 100) - ) - ) - (alias export $c "R" (type $R)) - (alias export $c "S" (type $S)) - (canon resource.drop $R (core func $drop-R')) - (canon resource.drop $S (core func $drop-S')) - (canon subtask.drop (core func $subtask.drop)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.drop (core func $waitable-set.drop)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon waitable-set.poll (memory $memory "mem") (core func $waitable-set.poll)) - (canon lower (func $c "new-R") (core func $new-R')) - (canon lower (func $c "blocker") (memory $memory "mem") async (core func $blocker')) - (canon lower (func $c "blocker-cb") (memory $memory "mem") async (core func $blocker-cb')) - (canon lower (func $c "unblocker") (core func $unblocker')) - (canon lower (func $c "new-S") (core func $new-S')) - (canon lower (func $c "yielder") (memory $memory "mem") async (core func $yielder')) - (canon lower (func $c "yielder-cb") (memory $memory "mem") async (core func $yielder-cb')) - (canon lower (func $c "poker") (core func $poker')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "subtask.drop" (func $subtask.drop)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.drop" (func $waitable-set.drop)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "waitable-set.poll" (func $waitable-set.poll)) - (export "new-R" (func $new-R')) - (export "drop-R" (func $drop-R')) - (export "blocker" (func $blocker')) - (export "blocker-cb" (func $blocker-cb')) - (export "unblocker" (func $unblocker')) - (export "new-S" (func $new-S')) - (export "drop-S" (func $drop-S')) - (export "yielder" (func $yielder')) - (export "yielder-cb" (func $yielder-cb')) - (export "poker" (func $poker')) - )))) - (func (export "run") async (result u32) (canon lift (core func $core "run"))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "run") (alias export $d "run")) -) - -(component instance $i $Tester) -(assert_return (invoke "run") (u32.const 100)) diff --git a/src/test/resources/spec-tests/async/sync-streams.wast b/src/test/resources/spec-tests/async/sync-streams.wast deleted file mode 100644 index 364ba9c..0000000 --- a/src/test/resources/spec-tests/async/sync-streams.wast +++ /dev/null @@ -1,178 +0,0 @@ -;; This test calls sync stream.write in $C.get and sync stream.read in $C.set. -;; Both of these calls block because $C is first to the rendezvous. But since -;; they are synchronous, control flow switches to $D.run which will do -;; a complementary read/write that rendezvous, and then control flow will -;; switch back to $C.get/set where the synchronous read/write will return -;; without blocking. -(component - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.return0" (func $task.return0)) - (import "" "task.return1" (func $task.return1 (param i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - (func (export "get") (result i32) - (local $ret i32) (local $ret64 i64) - (local $tx i32) (local $rx i32) - (local $bufp i32) - - ;; ($rx, $tx) = stream.new - (local.set $ret64 (call $stream.new)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - - ;; return $rx - (call $task.return1 (local.get $rx)) - - ;; (stream.write $tx $bufp 4) will block and, because called - ;; synchronously, switch to the caller who will read and rendezvous - (local.set $bufp (i32.const 16)) - (i32.store (local.get $bufp) (i32.const 0x01234567)) - (local.set $ret (call $stream.write (local.get $tx) (local.get $bufp) (i32.const 4))) - (if (i32.ne (i32.const 0x41 (; DROPPED=1 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - - (call $stream.drop-writable (local.get $tx)) - (return (i32.const 0 (; EXIT ;))) - ) - (func (export "get_cb") (param i32 i32 i32) (result i32) - unreachable - ) - - (func (export "set") (param $rx i32) (result i32) - (local $ret i32) (local $ret64 i64) - (local $bufp i32) - - ;; return immediately so that the caller can just call synchronously - (call $task.return0) - - ;; (stream.read $rx $bufp 4) will block and, because called - ;; synchronously, switch to the caller who will write and rendezvous - (local.set $bufp (i32.const 16)) - (local.set $ret (call $stream.read (local.get $rx) (local.get $bufp) (i32.const 4))) - (if (i32.ne (i32.const 0x41 (; DROPPED=1 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0x89abcdef) (i32.load (local.get $bufp))) - (then unreachable)) - - (call $stream.drop-readable (local.get $rx)) - (return (i32.const 0 (; EXIT ;))) - ) - (func (export "set_cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (type $ST (stream u8)) - (canon task.return (memory $memory "mem") (core func $task.return0)) - (canon task.return (result $ST) (memory $memory "mem") (core func $task.return1)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST (memory $memory "mem") (core func $stream.read)) - (canon stream.write $ST (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return0" (func $task.return0)) - (export "task.return1" (func $task.return1)) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (func (export "get") async (result (stream u8)) (canon lift - (core func $cm "get") - async (memory $memory "mem") (callback (func $cm "get_cb")) - )) - (func (export "set") async (param "in" (stream u8)) (canon lift - (core func $cm "set") - async (memory $memory "mem") (callback (func $cm "set_cb")) - )) - ) - (component $D - (import "get" (func $get async (result (stream u8)))) - (import "set" (func $set async (param "in" (stream u8)))) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - (import "" "get" (func $get (result i32))) - (import "" "set" (func $set (param i32))) - - (func (export "run") (result i32) - (local $ret i32) (local $ret64 i64) - (local $rx i32) (local $tx i32) - (local $bufp i32) - - ;; $rx = $C.get() - (local.set $rx (call $get)) - - ;; (stream.read $rx $bufp 4) will succeed without blocking - (local.set $bufp (i32.const 20)) - (local.set $ret (call $stream.read (local.get $rx) (local.get $bufp) (i32.const 4))) - (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0x01234567) (i32.load (local.get $bufp))) - (then unreachable)) - - (call $stream.drop-readable (local.get $rx)) - - ;; ($rx, $tx) = stream.new - ;; $C.set($rx) - (local.set $ret64 (call $stream.new)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $tx (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (call $set (local.get $rx)) - - ;; (stream.write $tx $bufp 4) will succeed without blocking - (local.set $bufp (i32.const 16)) - (local.set $ret (call $stream.write (local.get $tx) (local.get $bufp) (i32.const 4))) - (if (i32.ne (i32.const 0x40 (; COMPLETED=0 | (4<<4) ;)) (local.get $ret)) - (then unreachable)) - - (call $stream.drop-writable (local.get $tx)) - (i32.const 42) - ) - ) - (type $ST (stream u8)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (canon lower (func $get) (core func $get')) - (canon lower (func $set) (core func $set')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "stream.drop-writable" (func $stream.drop-writable)) - (export "get" (func $get')) - (export "set" (func $set')) - )))) - (func (export "run") async (result u32) (canon lift (core func $dm "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D - (with "get" (func $c "get")) - (with "set" (func $c "set")) - )) - (func (export "run") (alias export $d "run")) -) -(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/trap-if-block-and-sync.wast b/src/test/resources/spec-tests/async/trap-if-block-and-sync.wast deleted file mode 100644 index 14d81ff..0000000 --- a/src/test/resources/spec-tests/async/trap-if-block-and-sync.wast +++ /dev/null @@ -1,334 +0,0 @@ -;; The $Tester component has two nested components $C and $D, where $D imports -;; and calls $C. $C contains utilities used by $D to perform all the tests. -;; Most of the tests trap, $Tester exports 1 function per test and a fresh -;; $Tester is created to run each test. -(component definition $Tester - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (func (export "sync-async-func") - unreachable - ) - (func (export "async-async-func") (result i32) - unreachable - ) - (func (export "async-async-func-cb") (param i32 i32 i32) (result i32) - unreachable - ) - (func (export "sync-blocks-and-traps") - (call $waitable-set.wait (call $waitable-set.new) (i32.const 0xdeadbeef)) - unreachable - ) - ) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (core instance $cm (instantiate $CM (with "" (instance - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - )))) - (func (export "sync-async-func") async (canon lift (core func $cm "sync-async-func"))) - (func (export "async-async-func") async (canon lift (core func $cm "async-async-func") async (callback (func $cm "async-async-func-cb")))) - (func (export "sync-blocks-and-traps") (canon lift (core func $cm "sync-blocks-and-traps"))) - ) - (component $D - (import "c" (instance $c - (export "sync-async-func" (func async)) - (export "async-async-func" (func async)) - (export "sync-blocks-and-traps" (func)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core module $Table - (table (export "__indirect_function_table") 2 funcref)) - (core instance $memory (instantiate $Memory)) - (core instance $table (instantiate $Table)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) - (import "" "thread.yield" (func $thread.yield (result i32))) - ;;(import "" "thread.yield-to" (func $thread.yield-to (param i32) (result i32))) - ;;(import "" "thread.switch-to" (func $thread.switch-to (param i32) (result i32))) - ;;(import "" "thread.resume-later" (func $thread.resume-later (param i32))) - (import "" "thread.index" (func $thread-index (result i32))) - (import "" "thread.suspend" (func $thread.suspend (result i32))) - (import "" "thread.new-indirect" (func $thread.new-indirect (param i32 i32) (result i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "waitable-set.poll" (func $waitable-set.poll (param i32 i32) (result i32))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "stream.cancel-read" (func $stream.cancel-read (param i32) (result i32))) - (import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32))) - (import "" "future.cancel-read" (func $future.cancel-read (param i32) (result i32))) - (import "" "future.cancel-write" (func $future.cancel-write (param i32) (result i32))) - (import "" "await-sync-async-func" (func $await-sync-async-func)) - (import "" "await-async-async-func" (func $await-async-async-func)) - (import "" "sync-blocks-and-traps" (func $sync-blocks-and-traps)) - (import "" "__indirect_function_table" (table $indirect-function-table 2 funcref)) - - (func (export "unreachable-cb") (param i32 i32 i32) (result i32) - unreachable - ) - (func (export "return-42-cb") (param i32 i32 i32) (result i32) - (call $task.return (i32.const 42)) - (i32.const 0 (; EXIT ;)) - ) - - (func (export "trap-if-sync-call-async1") - (call $await-sync-async-func) - ) - (func (export "trap-if-sync-call-async2") - (call $await-async-async-func) - ) - (func (export "trap-if-async-calls-sync-and-blocks") (result i32) - (call $sync-blocks-and-traps) - unreachable - ) - (func (export "trap-if-suspend") - (call $thread.suspend) - unreachable - ) - (func (export "trap-if-wait") - (call $waitable-set.wait (call $waitable-set.new) (i32.const 0xdeadbeef)) - unreachable - ) - (func (export "poll-is-fine") (result i32) - (local $ret i32) - (local.set $ret (call $waitable-set.poll (call $waitable-set.new) (i32.const 0))) - (if (i32.ne (i32.const 0 (; NONE ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 0) (i32.load (i32.const 0))) - (then unreachable)) - (if (i32.ne (i32.const 0) (i32.load (i32.const 4))) - (then unreachable)) - (i32.const 42) - ) - (func (export "trap-if-invalid-callback-code") (param $invalid-code i32) (result i32) - (i32.or - (local.get $invalid-code) - (i32.shl (call $waitable-set.new) (i32.const 4))) - ) - (func (export "yield-is-fine") (result i32) - (drop (call $thread.yield)) - (i32.const 42) - ) - (func (export "yield-is-fine-cb") (result i32) - (i32.or - (i32.const 1 (; YIELD ;)) - (i32.shl (i32.const 0xdead) (i32.const 4))) - ) - (func $thread-start-noop (param i32)) - (elem (table $indirect-function-table) (i32.const 0) func $thread-start-noop) - (func (export "yield-to-is-fine") (result i32) - ;; TODO: rename and reenable - ;;(drop (call $thread.yield-to (call $thread.new-indirect (i32.const 0) (i32.const 0)))) - (i32.const 42) - ) - (func $thread-start-switch-back (param i32) - ;;(drop (call $thread.switch-to (local.get 0))) - ) - (elem (table $indirect-function-table) (i32.const 1) func $thread-start-switch-back) - (func (export "switch-to-is-fine") (result i32) - ;; TODO: rename and reenable - ;;(drop (call $thread.switch-to (call $thread.new-indirect (i32.const 1) (call $thread-index)))) - (i32.const 42) - ) - (func (export "resume-later-is-fine") (result i32) - ;; TODO: rename and reenable - ;;(call $thread.resume-later (call $thread.new-indirect (i32.const 0) (i32.const 0))) - (i32.const 42) - ) - (func (export "trap-if-sync-cancel") - (call $subtask.cancel (i32.const 0xdeadbeef)) - unreachable - ) - (func (export "trap-if-sync-stream-read") - (call $stream.read (i32.const 0xdead) (i32.const 0xbeef) (i32.const 0xdead)) - unreachable - ) - (func (export "trap-if-sync-stream-write") - (call $stream.write (i32.const 0xdead) (i32.const 0xbeef) (i32.const 0xdead)) - unreachable - ) - (func (export "trap-if-sync-future-read") - (call $future.read (i32.const 0xdead) (i32.const 0xdeadbeef)) - unreachable - ) - (func (export "trap-if-sync-future-write") - (call $future.write (i32.const 0xdead) (i32.const 0xdeadbeef)) - unreachable - ) - (func (export "trap-if-sync-stream-cancel-read") - (call $stream.cancel-read (i32.const 0xdead)) - unreachable - ) - (func (export "trap-if-sync-stream-cancel-write") - (call $stream.cancel-write (i32.const 0xdead)) - unreachable - ) - (func (export "trap-if-sync-future-cancel-read") - (call $future.cancel-read (i32.const 0xdead) (i32.const 0xdeadbeef)) - unreachable - ) - (func (export "trap-if-sync-future-cancel-write") - (call $future.cancel-write (i32.const 0xdead) (i32.const 0xdeadbeef)) - unreachable - ) - ) - (type $FT (future u8)) - (type $ST (stream u8)) - (core type $start-func-ty (func (param i32))) - (alias core export $table "__indirect_function_table" (core table $indirect-function-table)) - (core func $thread.new-indirect - (canon thread.new-indirect $start-func-ty (table $indirect-function-table))) - (canon task.return (result u32) (core func $task.return)) - (canon subtask.cancel (core func $subtask.cancel)) - (canon thread.yield (core func $thread.yield)) - (canon thread.suspend (core func $thread.suspend)) - ;;(canon thread.yield-to (core func $thread.yield-to)) - ;;(canon thread.switch-to (core func $thread.switch-to)) - ;;(canon thread.resume-later (core func $thread.resume-later)) - (canon thread.index (core func $thread.index)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon waitable-set.poll (memory $memory "mem") (core func $waitable-set.poll)) - (canon stream.read $ST (memory $memory "mem") (core func $stream.read)) - (canon stream.write $ST (memory $memory "mem") (core func $stream.write)) - (canon future.read $FT (memory $memory "mem") (core func $future.read)) - (canon future.write $FT (memory $memory "mem") (core func $future.write)) - (canon stream.cancel-read $ST (core func $stream.cancel-read)) - (canon stream.cancel-write $ST (core func $stream.cancel-write)) - (canon future.cancel-read $FT (core func $future.cancel-read)) - (canon future.cancel-write $FT (core func $future.cancel-write)) - (canon lower (func $c "sync-async-func") (core func $await-sync-async-func')) - (canon lower (func $c "async-async-func") (core func $await-async-async-func')) - (canon lower (func $c "sync-blocks-and-traps") (core func $sync-blocks-and-traps')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "subtask.cancel" (func $subtask.cancel)) - (export "thread.yield" (func $thread.yield)) - (export "thread.suspend" (func $thread.suspend)) - ;;(export "thread.yield-to" (func $thread.yield-to)) - ;;(export "thread.switch-to" (func $thread.switch-to)) - ;;(export "thread.resume-later" (func $thread.resume-later)) - (export "thread.index" (func $thread.index)) - (export "thread.new-indirect" (func $thread.new-indirect)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "waitable-set.poll" (func $waitable-set.poll)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "future.read" (func $future.read)) - (export "future.write" (func $future.write)) - (export "stream.cancel-read" (func $stream.cancel-read)) - (export "stream.cancel-write" (func $stream.cancel-write)) - (export "future.cancel-read" (func $future.cancel-read)) - (export "future.cancel-write" (func $future.cancel-write)) - (export "await-sync-async-func" (func $await-sync-async-func')) - (export "await-async-async-func" (func $await-async-async-func')) - (export "sync-blocks-and-traps" (func $sync-blocks-and-traps')) - (export "__indirect_function_table" (table $indirect-function-table)) - )))) - (func (export "trap-if-suspend") (canon lift (core func $core "trap-if-suspend"))) - (func (export "trap-if-wait") (canon lift (core func $core "trap-if-wait"))) - (func (export "poll-is-fine") (result u32) (canon lift (core func $core "poll-is-fine"))) - (func (export "trap-if-invalid-callback-code") async (param "invalid-code" u32) (canon lift (core func $core "trap-if-invalid-callback-code") async (callback (func $core "unreachable-cb")))) - (func (export "yield-is-fine") (result u32) (canon lift (core func $core "yield-is-fine"))) - (func (export "yield-is-fine-cb") async (result u32) (canon lift (core func $core "yield-is-fine-cb") async (callback (func $core "return-42-cb")))) - (func (export "yield-to-is-fine") (result u32) (canon lift (core func $core "yield-to-is-fine"))) - (func (export "switch-to-is-fine") (result u32) (canon lift (core func $core "switch-to-is-fine"))) - (func (export "resume-later-is-fine") (result u32) (canon lift (core func $core "resume-later-is-fine"))) - (func (export "trap-if-sync-call-async1") (canon lift (core func $core "trap-if-sync-call-async1"))) - (func (export "trap-if-sync-call-async2") (canon lift (core func $core "trap-if-sync-call-async2"))) - (func (export "trap-if-async-calls-sync-and-blocks") async (canon lift (core func $core "trap-if-async-calls-sync-and-blocks") async (callback (func $core "unreachable-cb")))) - (func (export "trap-if-sync-cancel") (canon lift (core func $core "trap-if-sync-cancel"))) - (func (export "trap-if-sync-stream-read") (canon lift (core func $core "trap-if-sync-stream-read"))) - (func (export "trap-if-sync-stream-write") (canon lift (core func $core "trap-if-sync-stream-write"))) - (func (export "trap-if-sync-future-read") (canon lift (core func $core "trap-if-sync-future-read"))) - (func (export "trap-if-sync-future-write") (canon lift (core func $core "trap-if-sync-future-write"))) - (func (export "trap-if-sync-stream-cancel-read") (canon lift (core func $core "trap-if-sync-stream-cancel-read"))) - (func (export "trap-if-sync-stream-cancel-write") (canon lift (core func $core "trap-if-sync-stream-cancel-write"))) - (func (export "trap-if-sync-future-cancel-read") (canon lift (core func $core "trap-if-sync-future-cancel-read"))) - (func (export "trap-if-sync-future-cancel-write") (canon lift (core func $core "trap-if-sync-future-cancel-write"))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "trap-if-sync-call-async1") (alias export $d "trap-if-sync-call-async1")) - (func (export "trap-if-sync-call-async2") (alias export $d "trap-if-sync-call-async2")) - (func (export "trap-if-async-calls-sync-and-blocks") (alias export $d "trap-if-async-calls-sync-and-blocks")) - (func (export "trap-if-suspend") (alias export $d "trap-if-suspend")) - (func (export "trap-if-wait") (alias export $d "trap-if-wait")) - (func (export "poll-is-fine") (alias export $d "poll-is-fine")) - (func (export "trap-if-invalid-callback-code") (alias export $d "trap-if-invalid-callback-code")) - (func (export "yield-is-fine") (alias export $d "yield-is-fine")) - (func (export "yield-is-fine-cb") (alias export $d "yield-is-fine-cb")) - (func (export "yield-to-is-fine") (alias export $d "yield-to-is-fine")) - (func (export "switch-to-is-fine") (alias export $d "switch-to-is-fine")) - (func (export "resume-later-is-fine") (alias export $d "resume-later-is-fine")) - (func (export "trap-if-sync-cancel") (alias export $d "trap-if-sync-cancel")) - (func (export "trap-if-sync-stream-read") (alias export $d "trap-if-sync-stream-read")) - (func (export "trap-if-sync-stream-write") (alias export $d "trap-if-sync-stream-write")) - (func (export "trap-if-sync-future-read") (alias export $d "trap-if-sync-future-read")) - (func (export "trap-if-sync-future-write") (alias export $d "trap-if-sync-future-write")) - (func (export "trap-if-sync-stream-cancel-read") (alias export $d "trap-if-sync-stream-cancel-read")) - (func (export "trap-if-sync-stream-cancel-write") (alias export $d "trap-if-sync-stream-cancel-write")) - (func (export "trap-if-sync-future-cancel-read") (alias export $d "trap-if-sync-future-cancel-read")) - (func (export "trap-if-sync-future-cancel-write") (alias export $d "trap-if-sync-future-cancel-write")) -) - -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-call-async1") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-call-async2") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-async-calls-sync-and-blocks") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-suspend") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-wait") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_return (invoke "poll-is-fine") (u32.const 42)) -(component instance $i $Tester) -(assert_trap (invoke "trap-if-invalid-callback-code" (u32.const 3)) "unsupported callback code") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-invalid-callback-code" (u32.const 4)) "unsupported callback code") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-invalid-callback-code" (u32.const 15)) "unsupported callback code") -(component instance $i $Tester) -(assert_return (invoke "yield-is-fine") (u32.const 42)) -(component instance $i $Tester) -(assert_return (invoke "yield-is-fine-cb") (u32.const 42)) -(component instance $i $Tester) -(assert_return (invoke "yield-to-is-fine") (u32.const 42)) -(component instance $i $Tester) -(assert_return (invoke "switch-to-is-fine") (u32.const 42)) -(component instance $i $Tester) -(assert_return (invoke "resume-later-is-fine") (u32.const 42)) -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-cancel") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-stream-read") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-stream-write") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-future-read") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-future-write") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-stream-cancel-read") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-stream-cancel-write") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-future-cancel-read") "cannot block a synchronous task before returning") -(component instance $i $Tester) -(assert_trap (invoke "trap-if-sync-future-cancel-write") "cannot block a synchronous task before returning") diff --git a/src/test/resources/spec-tests/async/trap-if-done.wast b/src/test/resources/spec-tests/async/trap-if-done.wast deleted file mode 100644 index 8f84cd3..0000000 --- a/src/test/resources/spec-tests/async/trap-if-done.wast +++ /dev/null @@ -1,470 +0,0 @@ -;; This test has two components $C and $D, where $D imports and calls $C. -;; $C contains utility functions used by $D to create futures/streams, -;; write to them and close them. $D uses these utility functions to test for -;; all the cases where, once a future/stream is "done", further uses of the -;; future/stream trap. -;; -;; $D exports a list of functions, one for each case of trapping. Since traps -;; take out their containing instance, a fresh instance of $Tester is created -;; for each call to a $D export. -;; -;; When testing traps involving the readable end, the exports of $D take a -;; "bool" parameter that toggles whether the trap is triggered by -;; {stream,future}.{read,write} or by lifting, and the top-level commands -;; pass 'false' and 'true'. -(component definition $Tester - (component $C - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "future.drop-writable" (func $future.drop-writable (param i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - (global $writable-end (mut i32) (i32.const 0)) - (global $ws (mut i32) (i32.const 0)) - - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - (func $start-future (export "start-future") (result i32) - ;; create a new future, return the readable end to the caller - (local $ret64 i64) - (local.set $ret64 (call $future.new)) - (global.set $writable-end (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (call $waitable.join (global.get $writable-end) (global.get $ws) ) - (i32.wrap_i64 (local.get $ret64)) - ) - (func $future-write (export "future-write") (result i32) - ;; the caller will assert what they expect the return value to be - (i32.store (i32.const 16) (i32.const 42)) - (call $future.write (global.get $writable-end) (i32.const 16)) - ) - (func $acknowledge-future-write (export "acknowledge-future-write") - ;; confirm we got a FUTURE_WRITE $writable-end COMPLETED event - (local $ret i32) - (local.set $ret (call $waitable-set.wait (global.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 5 (; FUTURE_WRITE ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (global.get $writable-end) (i32.load (i32.const 0))) - (then unreachable)) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (i32.load (i32.const 4))) - (then unreachable)) - ) - (func $future-drop-writable (export "future-drop-writable") - ;; maybe boom - (call $future.drop-writable (global.get $writable-end)) - ) - - (func $start-stream (export "start-stream") (result i32) - ;; create a new stream, return the readable end to the caller - (local $ret64 i64) - (local.set $ret64 (call $stream.new)) - (global.set $writable-end (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (call $waitable.join (global.get $writable-end) (global.get $ws) ) - (i32.wrap_i64 (local.get $ret64)) - ) - (func $stream-write (export "stream-write") (result i32) - ;; the caller will assert what they expect the return value to be - (i32.store (i32.const 16) (i32.const 42)) - (call $stream.write (global.get $writable-end) (i32.const 16) (i32.const 1)) - ) - (func $acknowledge-stream-write (export "acknowledge-stream-write") - ;; confirm we got a STREAM_WRITE $writable-end COMPLETED event - (local $ret i32) - (local.set $ret (call $waitable-set.wait (global.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 3 (; STREAM_WRITE ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (global.get $writable-end) (i32.load (i32.const 0))) - (then unreachable)) - (if (i32.ne (i32.const 0x11 (; DROPPED=1 | (1<<4) ;)) (i32.load (i32.const 4))) - (then unreachable)) - ) - (func $stream-drop-writable (export "stream-drop-writable") - ;; maybe boom - (call $stream.drop-writable (global.get $writable-end)) - ) - ) - (type $FT (future u8)) - (type $ST (stream u8)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon future.new $FT (core func $future.new)) - (canon future.write $FT async (memory $memory "mem") (core func $future.write)) - (canon future.drop-writable $FT (core func $future.drop-writable)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "future.new" (func $future.new)) - (export "future.write" (func $future.write)) - (export "future.drop-writable" (func $future.drop-writable)) - (export "stream.new" (func $stream.new)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (func (export "start-future") async (result (future u8)) (canon lift (core func $cm "start-future"))) - (func (export "future-write") async (result u32) (canon lift (core func $cm "future-write"))) - (func (export "acknowledge-future-write") async (canon lift (core func $cm "acknowledge-future-write"))) - (func (export "future-drop-writable") async (canon lift (core func $cm "future-drop-writable"))) - (func (export "start-stream") async (result (stream u8)) (canon lift (core func $cm "start-stream"))) - (func (export "stream-write") async (result u32) (canon lift (core func $cm "stream-write"))) - (func (export "acknowledge-stream-write") async (canon lift (core func $cm "acknowledge-stream-write"))) - (func (export "stream-drop-writable") async (canon lift (core func $cm "stream-drop-writable"))) - ) - (component $D - (import "c" (instance $c - (export "start-future" (func async (result (future u8)))) - (export "future-write" (func async (result u32))) - (export "acknowledge-future-write" (func async)) - (export "future-drop-writable" (func async)) - (export "start-stream" (func async (result (stream u8)))) - (export "stream-write" (func async (result u32))) - (export "acknowledge-stream-write" (func async)) - (export "stream-drop-writable" (func async)) - )) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $Core - (import "" "mem" (memory 1)) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "future.drop-readable" (func $future.drop-readable (param i32))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "start-future" (func $start-future (result i32))) - (import "" "future-write" (func $future-write (result i32))) - (import "" "acknowledge-future-write" (func $acknowledge-future-write)) - (import "" "future-drop-writable" (func $future-drop-writable)) - (import "" "start-stream" (func $start-stream (result i32))) - (import "" "stream-write" (func $stream-write (result i32))) - (import "" "acknowledge-stream-write" (func $acknowledge-stream-write)) - (import "" "stream-drop-writable" (func $stream-drop-writable)) - - (func $trap-after-future-eager-write (export "trap-after-future-eager-write") - (local $ret i32) - (local $fr i32) - (local.set $fr (call $start-future)) - - ;; start a read on our end so the next write will succeed - (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; calling future.write in $C should succeed eagerly - (local.set $ret (call $future-write)) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) - (then unreachable)) - - ;; calling future.write in $C now should trap - (drop (call $future-write)) - ) - (func $trap-after-future-async-write (export "trap-after-future-async-write") - (local $ret i32) - (local $fr i32) - (local.set $fr (call $start-future)) - - ;; calling future.write in $C should block - (local.set $ret (call $future-write)) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; our future.read should then succeed eagerly - (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) - (then unreachable)) - - ;; let $C see the write completed so the future is 'done' - (call $acknowledge-future-write) - - ;; trying to call future.write again in $C should trap - (drop (call $future-write)) - ) - (func $trap-after-future-reader-dropped (export "trap-after-future-reader-dropped") - (local $ret i32) - (local $fr i32) - (local.set $fr (call $start-future)) - - ;; drop our readable end before writer can write - (call $future.drop-readable (local.get $fr)) - - ;; let $C try to future.write and find out we DROPPED - (local.set $ret (call $future-write)) - (if (i32.ne (i32.const 1 (; DROPPED ;)) (local.get $ret)) - (then unreachable)) - - ;; trying to call future.write again in $C should trap - (drop (call $future-write)) - ) - (func $trap-after-future-eager-read (export "trap-after-future-eager-read") (param $bool i32) (result i32) - (local $ret i32) - (local $fr i32) - (local.set $fr (call $start-future)) - - ;; calling future.write in $C should block - (local.set $ret (call $future-write)) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; our future.read should then succeed eagerly - (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) - (then unreachable)) - - (if (i32.eqz (local.get $bool)) (then - ;; calling future.read again should then trap - (drop (call $future.read (local.get $fr) (i32.const 16))) - ) (else - ;; lifting the future by returning it should also trap - (return (local.get $fr)) - )) - unreachable - ) - (func $trap-after-future-async-read (export "trap-after-future-async-read") (param $bool i32) (result i32) - (local $ret i32) (local $ws i32) - (local $fr i32) - (local.set $fr (call $start-future)) - - ;; read first, so it blocks - (local.set $ret (call $future.read (local.get $fr) (i32.const 16))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; calling future.write in $C should then succeed eagerly - (local.set $ret (call $future-write)) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) - (then unreachable)) - - ;; wait to see that our blocked future.read COMPLETED, producing '42' - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $fr) (local.get $ws)) - (local.set $ret (call $waitable-set.wait (local.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (local.get $fr) (i32.load (i32.const 0))) - (then unreachable)) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (i32.load (i32.const 4))) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load (i32.const 16))) - (then unreachable)) - - (call $waitable.join (local.get $fr) (i32.const 0)) - - (if (i32.eqz (local.get $bool)) (then - ;; calling future.read again should then trap - (drop (call $future.read (local.get $fr) (i32.const 16))) - ) (else - ;; lifting the future by returning it should also trap - (return (local.get $fr)) - )) - unreachable - ) - (func $trap-after-stream-reader-eager-dropped (export "trap-after-stream-reader-eager-dropped") - (local $ret i32) - (local $sr i32) - (local.set $sr (call $start-stream)) - - ;; drop our readable end before writer can write - (call $stream.drop-readable (local.get $sr)) - - ;; let $C try to stream.write and find out we DROPPED - (local.set $ret (call $stream-write)) - (if (i32.ne (i32.const 1 (; DROPPED ;)) (local.get $ret)) - (then unreachable)) - - ;; trying to call stream.write again in $C should trap - (drop (call $stream-write)) - ) - (func $trap-after-stream-reader-async-dropped (export "trap-after-stream-reader-async-dropped") - (local $ret i32) - (local $sr i32) - (local.set $sr (call $start-stream)) - - ;; calling stream.write in $C should block - (local.set $ret (call $stream-write)) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; our stream.read should then succeed eagerly - (local.set $ret (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) - (if (i32.ne (i32.const 0x10 (; COMPLETED=0 | (1<<4) ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (i32.const 42) (i32.load8_u (i32.const 16))) - (then unreachable)) - - ;; then drop our readable end - (call $stream.drop-readable (local.get $sr)) - - ;; let $C see that it's stream.write COMPLETED and wrote 1 elem - (call $acknowledge-stream-write) - - ;; now calling stream.write again in $C will trap - (drop (call $stream-write)) - ) - (func $trap-after-stream-writer-eager-dropped (export "trap-after-stream-writer-eager-dropped") (param $bool i32) (result i32) - (local $ret i32) - (local $sr i32) - (local.set $sr (call $start-stream)) - - ;; immediately drop the writable end - (call $stream-drop-writable) - - ;; calling stream.read will see that the writer dropped - (local.set $ret (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) - (if (i32.ne (i32.const 0x01 (; DROPPED=1 | (0<<4) ;)) (local.get $ret)) - (then unreachable)) - - (if (i32.eqz (local.get $bool)) (then - ;; calling stream.read again should then trap - (drop (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) - ) (else - ;; lifting the stream by returning it should also trap - (return (local.get $sr)) - )) - unreachable - ) - (func $trap-after-stream-writer-async-dropped (export "trap-after-stream-writer-async-dropped") (param $bool i32) (result i32) - (local $ret i32) (local $ws i32) - (local $sr i32) - (local.set $sr (call $start-stream)) - - ;; start a read on our end first which will block - (local.set $ret (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; drop the writable end before writing anything - (call $stream-drop-writable) - - ;; wait to see that our blocked stream.read was DROPPED - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $sr) (local.get $ws)) - (local.set $ret (call $waitable-set.wait (local.get $ws) (i32.const 0))) - (if (i32.ne (i32.const 2 (; STREAM_READ ;)) (local.get $ret)) - (then unreachable)) - (if (i32.ne (local.get $sr) (i32.load (i32.const 0))) - (then unreachable)) - (if (i32.ne (i32.const 0x01 (; DROPPED=1 | (0<<4) ;)) (i32.load (i32.const 4))) - (then unreachable)) - - (if (i32.eqz (local.get $bool)) (then - ;; calling stream.read again should then trap - (drop (call $stream.read (local.get $sr) (i32.const 16) (i32.const 100))) - ) (else - ;; lifting the stream by returning it should also trap - (return (local.get $sr)) - )) - unreachable - ) - ) - (type $FT (future u8)) - (type $ST (stream u8)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon future.new $FT (core func $future.new)) - (canon future.read $FT async (memory $memory "mem") (core func $future.read)) - (canon future.drop-readable $FT (core func $future.drop-readable)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon lower (func $c "start-future") (core func $start-future')) - (canon lower (func $c "future-write") (core func $future-write')) - (canon lower (func $c "acknowledge-future-write") (core func $acknowledge-future-write')) - (canon lower (func $c "future-drop-writable") (core func $future-drop-writable')) - (canon lower (func $c "start-stream") (core func $start-stream')) - (canon lower (func $c "stream-write") (core func $stream-write')) - (canon lower (func $c "acknowledge-stream-write") (core func $acknowledge-stream-write')) - (canon lower (func $c "stream-drop-writable") (core func $stream-drop-writable')) - (core instance $core (instantiate $Core (with "" (instance - (export "mem" (memory $memory "mem")) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "future.new" (func $future.new)) - (export "future.read" (func $future.read)) - (export "future.drop-readable" (func $future.drop-readable)) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "start-future" (func $start-future')) - (export "future-write" (func $future-write')) - (export "acknowledge-future-write" (func $acknowledge-future-write')) - (export "future-drop-writable" (func $future-drop-writable')) - (export "start-stream" (func $start-stream')) - (export "stream-write" (func $stream-write')) - (export "acknowledge-stream-write" (func $acknowledge-stream-write')) - (export "stream-drop-writable" (func $stream-drop-writable')) - )))) - (func (export "trap-after-future-eager-write") async (canon lift (core func $core "trap-after-future-eager-write"))) - (func (export "trap-after-future-async-write") async (canon lift (core func $core "trap-after-future-async-write"))) - (func (export "trap-after-future-reader-dropped") async (canon lift (core func $core "trap-after-future-reader-dropped"))) - (func (export "trap-after-future-eager-read") async (param "bool" bool) (result $FT) (canon lift (core func $core "trap-after-future-eager-read"))) - (func (export "trap-after-future-async-read") async (param "bool" bool) (result $FT) (canon lift (core func $core "trap-after-future-async-read"))) - (func (export "trap-after-stream-reader-eager-dropped") async (canon lift (core func $core "trap-after-stream-reader-eager-dropped"))) - (func (export "trap-after-stream-reader-async-dropped") async (canon lift (core func $core "trap-after-stream-reader-async-dropped"))) - (func (export "trap-after-stream-writer-eager-dropped") async (param "bool" bool) (result $ST) (canon lift (core func $core "trap-after-stream-writer-eager-dropped"))) - (func (export "trap-after-stream-writer-async-dropped") async (param "bool" bool) (result $ST) (canon lift (core func $core "trap-after-stream-writer-async-dropped"))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "trap-after-future-eager-write") (alias export $d "trap-after-future-eager-write")) - (func (export "trap-after-future-async-write") (alias export $d "trap-after-future-async-write")) - (func (export "trap-after-future-reader-dropped") (alias export $d "trap-after-future-reader-dropped")) - (func (export "trap-after-future-eager-read") (alias export $d "trap-after-future-eager-read")) - (func (export "trap-after-future-async-read") (alias export $d "trap-after-future-async-read")) - (func (export "trap-after-stream-reader-eager-dropped") (alias export $d "trap-after-stream-reader-eager-dropped")) - (func (export "trap-after-stream-reader-async-dropped") (alias export $d "trap-after-stream-reader-async-dropped")) - (func (export "trap-after-stream-writer-eager-dropped") (alias export $d "trap-after-stream-writer-eager-dropped")) - (func (export "trap-after-stream-writer-async-dropped") (alias export $d "trap-after-stream-writer-async-dropped")) -) - -(component instance $i1 $Tester) -(assert_trap (invoke "trap-after-future-eager-write") "cannot write to future after previous write succeeded") -(component instance $i2 $Tester) -(assert_trap (invoke "trap-after-future-async-write") "cannot write to future after previous write succeeded") -(component instance $i3 $Tester) -(assert_trap (invoke "trap-after-future-reader-dropped") "cannot write to future after previous write succeeded or readable end dropped") -(component instance $i4.1 $Tester) -(assert_trap (invoke "trap-after-future-eager-read" (bool.const false)) "cannot read from future after previous read succeeded") -(component instance $i4.2 $Tester) -(assert_trap (invoke "trap-after-future-eager-read" (bool.const true)) "cannot lift future after previous read succeeded") -(component instance $i5.1 $Tester) -(assert_trap (invoke "trap-after-future-async-read" (bool.const false)) "cannot read from future after previous read succeeded") -(component instance $i5.2 $Tester) -(assert_trap (invoke "trap-after-future-async-read" (bool.const true)) "cannot lift future after previous read succeeded") -(component instance $i6 $Tester) -(assert_trap (invoke "trap-after-stream-reader-eager-dropped") "cannot write to stream after being notified that the readable end dropped") -(component instance $i7 $Tester) -(assert_trap (invoke "trap-after-stream-reader-async-dropped") "cannot write to stream after being notified that the readable end dropped") -(component instance $i8.1 $Tester) -(assert_trap (invoke "trap-after-stream-writer-eager-dropped" (bool.const false)) "cannot read from stream after being notified that the writable end dropped") -(component instance $i8.2 $Tester) -(assert_trap (invoke "trap-after-stream-writer-eager-dropped" (bool.const true)) "cannot lift stream after being notified that the writable end dropped") -(component instance $i9.1 $Tester) -(assert_trap (invoke "trap-after-stream-writer-async-dropped" (bool.const false)) "cannot read from stream after being notified that the writable end dropped") -(component instance $i9.2 $Tester) -(assert_trap (invoke "trap-after-stream-writer-async-dropped" (bool.const true)) "cannot lift stream after being notified that the writable end dropped") diff --git a/src/test/resources/spec-tests/async/trap-if-sync-and-waitable-set.wast b/src/test/resources/spec-tests/async/trap-if-sync-and-waitable-set.wast deleted file mode 100644 index 2d2d439..0000000 --- a/src/test/resources/spec-tests/async/trap-if-sync-and-waitable-set.wast +++ /dev/null @@ -1,288 +0,0 @@ -;; Tests the trap conditions associated with mixing synchronous and -;; asynchronous waiting on the same waitable. -(component definition $Tester - (component $C - (core module $CM - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (func (export "blocks-forever") (result i32) - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (call $waitable-set.new) (i32.const 4))) - ) - (func (export "blocks-forever-cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (canon waitable-set.new (core func $waitable-set.new)) - (core instance $cm (instantiate $CM (with "" (instance - (export "waitable-set.new" (func $waitable-set.new)) - )))) - (func (export "blocks-forever") async (result u32) (canon lift - (core func $cm "blocks-forever") - async (callback (func $cm "blocks-forever-cb")) - )) - ) - (instance $c (instantiate $C)) - - (core module $MemTable - (table (export "ftbl") 4 funcref) - (memory (export "mem") 1) - ) - (core instance $memTable (instantiate $MemTable)) - - (core module $m - (import "" "thread.new-indirect" (func $thread.new-indirect (param i32 i32) (result i32))) - (import "" "thread.yield-to-suspended" (func $thread.yield-to-suspended (param i32) (result i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "subtask.cancel-sync" (func $subtask.cancel-sync (param i32) (result i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.read-sync" (func $future.read-sync (param i32 i32) (result i32))) - (import "" "future.write-sync" (func $future.write-sync (param i32 i32) (result i32))) - (import "" "future.read-async" (func $future.read-async (param i32 i32) (result i32))) - (import "" "future.write-async" (func $future.write-async (param i32 i32) (result i32))) - (import "" "future.cancel-read-sync" (func $future.cancel-read-sync (param i32) (result i32))) - (import "" "future.cancel-write-sync" (func $future.cancel-write-sync (param i32) (result i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read-sync" (func $stream.read-sync (param i32 i32 i32) (result i32))) - (import "" "stream.write-sync" (func $stream.write-sync (param i32 i32 i32) (result i32))) - (import "" "stream.read-async" (func $stream.read-async (param i32 i32 i32) (result i32))) - (import "" "stream.write-async" (func $stream.write-async (param i32 i32 i32) (result i32))) - (import "" "stream.cancel-read-sync" (func $stream.cancel-read-sync (param i32) (result i32))) - (import "" "stream.cancel-write-sync" (func $stream.cancel-write-sync (param i32) (result i32))) - (import "" "blocks-forever" (func $blocks-forever (param i32) (result i32))) - (import "" "ftbl" (table $ftbl 4 funcref)) - - (func $new-future-rx (result i32) - (i32.wrap_i64 (call $future.new)) - ) - (func $new-future-tx (result i32) - (i32.wrap_i64 (i64.shr_u (call $future.new) (i64.const 32))) - ) - (func $new-stream-rx (result i32) - (i32.wrap_i64 (call $stream.new)) - ) - (func $new-stream-tx (result i32) - (i32.wrap_i64 (i64.shr_u (call $stream.new) (i64.const 32))) - ) - (func $spawn-and-yield (param $idx i32) (param $arg i32) - (drop (call $thread.yield-to-suspended - (call $thread.new-indirect (local.get $idx) (local.get $arg)))) - ) - (func $assert-blocked (param $ret i32) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - ) - - ;; thread-start funcs used by the join-during-sync-* tests: - (func $thread-future-read-sync (param $rx i32) - (drop (call $future.read-sync (local.get $rx) (i32.const 0))) - ) - (elem (table $ftbl) (i32.const 0) func $thread-future-read-sync) - (func $thread-future-write-sync (param $tx i32) - (drop (call $future.write-sync (local.get $tx) (i32.const 0))) - ) - (elem (table $ftbl) (i32.const 1) func $thread-future-write-sync) - (func $thread-stream-read-sync (param $rx i32) - (drop (call $stream.read-sync (local.get $rx) (i32.const 0) (i32.const 4))) - ) - (elem (table $ftbl) (i32.const 2) func $thread-stream-read-sync) - (func $thread-stream-write-sync (param $tx i32) - (drop (call $stream.write-sync (local.get $tx) (i32.const 0) (i32.const 4))) - ) - (elem (table $ftbl) (i32.const 3) func $thread-stream-write-sync) - - (func (export "join-during-sync-future-read") - (local $rx i32) - (local.set $rx (call $new-future-rx)) - (call $spawn-and-yield (i32.const 0) (local.get $rx)) - (call $waitable.join (local.get $rx) (call $waitable-set.new)) - unreachable - ) - (func (export "join-during-sync-future-write") - (local $tx i32) - (local.set $tx (call $new-future-tx)) - (call $spawn-and-yield (i32.const 1) (local.get $tx)) - (call $waitable.join (local.get $tx) (call $waitable-set.new)) - unreachable - ) - (func (export "join-during-sync-stream-read") - (local $rx i32) - (local.set $rx (call $new-stream-rx)) - (call $spawn-and-yield (i32.const 2) (local.get $rx)) - (call $waitable.join (local.get $rx) (call $waitable-set.new)) - unreachable - ) - (func (export "join-during-sync-stream-write") - (local $tx i32) - (local.set $tx (call $new-stream-tx)) - (call $spawn-and-yield (i32.const 3) (local.get $tx)) - (call $waitable.join (local.get $tx) (call $waitable-set.new)) - unreachable - ) - - (func (export "sync-future-read-when-in-set") - (local $rx i32) - (local.set $rx (call $new-future-rx)) - (call $waitable.join (local.get $rx) (call $waitable-set.new)) - (drop (call $future.read-sync (local.get $rx) (i32.const 0))) - unreachable - ) - (func (export "sync-future-write-when-in-set") - (local $tx i32) - (local.set $tx (call $new-future-tx)) - (call $waitable.join (local.get $tx) (call $waitable-set.new)) - (drop (call $future.write-sync (local.get $tx) (i32.const 0))) - unreachable - ) - (func (export "sync-stream-read-when-in-set") - (local $rx i32) - (local.set $rx (call $new-stream-rx)) - (call $waitable.join (local.get $rx) (call $waitable-set.new)) - (drop (call $stream.read-sync (local.get $rx) (i32.const 0) (i32.const 4))) - unreachable - ) - (func (export "sync-stream-write-when-in-set") - (local $tx i32) - (local.set $tx (call $new-stream-tx)) - (call $waitable.join (local.get $tx) (call $waitable-set.new)) - (drop (call $stream.write-sync (local.get $tx) (i32.const 0) (i32.const 4))) - unreachable - ) - (func (export "sync-future-cancel-read-when-in-set") - (local $rx i32) - (local.set $rx (call $new-future-rx)) - (call $assert-blocked (call $future.read-async (local.get $rx) (i32.const 0))) - (call $waitable.join (local.get $rx) (call $waitable-set.new)) - (drop (call $future.cancel-read-sync (local.get $rx))) - unreachable - ) - - (func (export "sync-future-cancel-write-when-in-set") - (local $tx i32) - (local.set $tx (call $new-future-tx)) - (call $assert-blocked (call $future.write-async (local.get $tx) (i32.const 0))) - (call $waitable.join (local.get $tx) (call $waitable-set.new)) - (drop (call $future.cancel-write-sync (local.get $tx))) - unreachable - ) - (func (export "sync-stream-cancel-read-when-in-set") - (local $rx i32) - (local.set $rx (call $new-stream-rx)) - (call $assert-blocked (call $stream.read-async (local.get $rx) (i32.const 0) (i32.const 4))) - (call $waitable.join (local.get $rx) (call $waitable-set.new)) - (drop (call $stream.cancel-read-sync (local.get $rx))) - unreachable - ) - (func (export "sync-stream-cancel-write-when-in-set") - (local $tx i32) - (local.set $tx (call $new-stream-tx)) - (call $assert-blocked (call $stream.write-async (local.get $tx) (i32.const 0) (i32.const 4))) - (call $waitable.join (local.get $tx) (call $waitable-set.new)) - (drop (call $stream.cancel-write-sync (local.get $tx))) - unreachable - ) - - (func (export "sync-subtask-cancel-when-in-set") - (local $ret i32) (local $sub i32) - (local.set $ret (call $blocks-forever (i32.const 0))) - (if (i32.ne (i32.const 1 (; STARTED ;)) (i32.and (local.get $ret) (i32.const 0xf))) - (then unreachable)) - (local.set $sub (i32.shr_u (local.get $ret) (i32.const 4))) - (call $waitable.join (local.get $sub) (call $waitable-set.new)) - (drop (call $subtask.cancel-sync (local.get $sub))) - unreachable - ) - ) - - (core type $start-func-ty (func (param i32))) - (alias core export $memTable "ftbl" (core table $ftbl)) - - (core func $thread.new-indirect (canon thread.new-indirect $start-func-ty (table $ftbl))) - (core func $thread.yield-to-suspended (canon thread.yield-to-suspended)) - (core func $waitable-set.new (canon waitable-set.new)) - (core func $waitable.join (canon waitable.join)) - (core func $subtask.cancel-sync (canon subtask.cancel)) - (type $future (future)) - (type $stream (stream u8)) - (core func $future.new (canon future.new $future)) - (core func $future.read-sync (canon future.read $future (memory $memTable "mem"))) - (core func $future.write-sync (canon future.write $future (memory $memTable "mem"))) - (core func $future.read-async (canon future.read $future async (memory $memTable "mem"))) - (core func $future.write-async (canon future.write $future async (memory $memTable "mem"))) - (core func $future.cancel-read-sync (canon future.cancel-read $future)) - (core func $future.cancel-write-sync (canon future.cancel-write $future)) - (core func $stream.new (canon stream.new $stream)) - (core func $stream.read-sync (canon stream.read $stream (memory $memTable "mem"))) - (core func $stream.write-sync (canon stream.write $stream (memory $memTable "mem"))) - (core func $stream.read-async (canon stream.read $stream async (memory $memTable "mem"))) - (core func $stream.write-async (canon stream.write $stream async (memory $memTable "mem"))) - (core func $stream.cancel-read-sync (canon stream.cancel-read $stream)) - (core func $stream.cancel-write-sync (canon stream.cancel-write $stream)) - (canon lower (func $c "blocks-forever") async (memory $memTable "mem") (core func $blocks-forever)) - - (core instance $m (instantiate $m - (with "" (instance - (export "thread.new-indirect" (func $thread.new-indirect)) - (export "thread.yield-to-suspended" (func $thread.yield-to-suspended)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable.join" (func $waitable.join)) - (export "subtask.cancel-sync" (func $subtask.cancel-sync)) - (export "future.new" (func $future.new)) - (export "future.read-sync" (func $future.read-sync)) - (export "future.write-sync" (func $future.write-sync)) - (export "future.read-async" (func $future.read-async)) - (export "future.write-async" (func $future.write-async)) - (export "future.cancel-read-sync" (func $future.cancel-read-sync)) - (export "future.cancel-write-sync" (func $future.cancel-write-sync)) - (export "stream.new" (func $stream.new)) - (export "stream.read-sync" (func $stream.read-sync)) - (export "stream.write-sync" (func $stream.write-sync)) - (export "stream.read-async" (func $stream.read-async)) - (export "stream.write-async" (func $stream.write-async)) - (export "stream.cancel-read-sync" (func $stream.cancel-read-sync)) - (export "stream.cancel-write-sync" (func $stream.cancel-write-sync)) - (export "blocks-forever" (func $blocks-forever)) - (export "ftbl" (table $ftbl)) - )) - )) - - (func (export "join-during-sync-future-read") async (canon lift (core func $m "join-during-sync-future-read"))) - (func (export "join-during-sync-future-write") async (canon lift (core func $m "join-during-sync-future-write"))) - (func (export "join-during-sync-stream-read") async (canon lift (core func $m "join-during-sync-stream-read"))) - (func (export "join-during-sync-stream-write") async (canon lift (core func $m "join-during-sync-stream-write"))) - (func (export "sync-future-read-when-in-set") async (canon lift (core func $m "sync-future-read-when-in-set"))) - (func (export "sync-future-write-when-in-set") async (canon lift (core func $m "sync-future-write-when-in-set"))) - (func (export "sync-stream-read-when-in-set") async (canon lift (core func $m "sync-stream-read-when-in-set"))) - (func (export "sync-stream-write-when-in-set") async (canon lift (core func $m "sync-stream-write-when-in-set"))) - (func (export "sync-future-cancel-read-when-in-set") async (canon lift (core func $m "sync-future-cancel-read-when-in-set"))) - (func (export "sync-future-cancel-write-when-in-set") async (canon lift (core func $m "sync-future-cancel-write-when-in-set"))) - (func (export "sync-stream-cancel-read-when-in-set") async (canon lift (core func $m "sync-stream-cancel-read-when-in-set"))) - (func (export "sync-stream-cancel-write-when-in-set") async (canon lift (core func $m "sync-stream-cancel-write-when-in-set"))) - (func (export "sync-subtask-cancel-when-in-set") async (canon lift (core func $m "sync-subtask-cancel-when-in-set"))) -) - -(component instance $i $Tester) -(assert_trap (invoke "join-during-sync-future-read") "waitable cannot be used synchronously while added to a waitable set") -(component instance $i $Tester) -(assert_trap (invoke "join-during-sync-future-write") "waitable cannot be used synchronously while added to a waitable set") -(component instance $i $Tester) -(assert_trap (invoke "join-during-sync-stream-read") "waitable cannot be used synchronously while added to a waitable set") -(component instance $i $Tester) -(assert_trap (invoke "join-during-sync-stream-write") "waitable cannot be used synchronously while added to a waitable set") -(component instance $i $Tester) -(assert_trap (invoke "sync-future-read-when-in-set") "waitable cannot be used synchronously while added to a waitable set") -(component instance $i $Tester) -(assert_trap (invoke "sync-future-write-when-in-set") "waitable cannot be used synchronously while added to a waitable set") -(component instance $i $Tester) -(assert_trap (invoke "sync-stream-read-when-in-set") "waitable cannot be used synchronously while added to a waitable set") -(component instance $i $Tester) -(assert_trap (invoke "sync-stream-write-when-in-set") "waitable cannot be used synchronously while added to a waitable set") -(component instance $i $Tester) -(assert_trap (invoke "sync-future-cancel-read-when-in-set") "waitable cannot be used synchronously while added to a waitable set") -(component instance $i $Tester) -(assert_trap (invoke "sync-future-cancel-write-when-in-set") "waitable cannot be used synchronously while added to a waitable set") -(component instance $i $Tester) -(assert_trap (invoke "sync-stream-cancel-read-when-in-set") "waitable cannot be used synchronously while added to a waitable set") -(component instance $i $Tester) -(assert_trap (invoke "sync-stream-cancel-write-when-in-set") "waitable cannot be used synchronously while added to a waitable set") -(component instance $i $Tester) -(assert_trap (invoke "sync-subtask-cancel-when-in-set") "waitable cannot be used synchronously while added to a waitable set") diff --git a/src/test/resources/spec-tests/async/trap-if-transfer-in-waitable-set.wast b/src/test/resources/spec-tests/async/trap-if-transfer-in-waitable-set.wast deleted file mode 100644 index cb2accf..0000000 --- a/src/test/resources/spec-tests/async/trap-if-transfer-in-waitable-set.wast +++ /dev/null @@ -1,51 +0,0 @@ -;; This test contains a single component $Tester which creates a stream and -;; future, joins the readable end into a waitable set, and then attempts to -;; lift the readable end by returning it from an export. Because the readable -;; end is in a waitable set, lifting must trap. - -(component definition $Tester - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $M - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "stream.new" (func $stream.new (result i64))) - - (func $return-future-in-set (export "return-future-in-set") (result i32) - (local $ret64 i64) (local $rx i32) (local $ws i32) - (local.set $ret64 (call $future.new)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $rx) (local.get $ws)) - (local.get $rx) - ) - (func $return-stream-in-set (export "return-stream-in-set") (result i32) - (local $ret64 i64) (local $rx i32) (local $ws i32) - (local.set $ret64 (call $stream.new)) - (local.set $rx (i32.wrap_i64 (local.get $ret64))) - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $rx) (local.get $ws)) - (local.get $rx) - ) - ) - (type $FT (future u8)) - (type $ST (stream u8)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon future.new $FT (core func $future.new)) - (canon stream.new $ST (core func $stream.new)) - (core instance $m (instantiate $M (with "" (instance - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "future.new" (func $future.new)) - (export "stream.new" (func $stream.new)) - )))) - (func (export "return-future-in-set") async (result $FT) (canon lift (core func $m "return-future-in-set"))) - (func (export "return-stream-in-set") async (result $ST) (canon lift (core func $m "return-stream-in-set"))) -) - -(component instance $i1 $Tester) -(assert_trap (invoke "return-future-in-set") "cannot lift future in a waitable set") -(component instance $i2 $Tester) -(assert_trap (invoke "return-stream-in-set") "cannot lift stream in a waitable set") diff --git a/src/test/resources/spec-tests/async/trap-on-reenter.wast b/src/test/resources/spec-tests/async/trap-on-reenter.wast deleted file mode 100644 index f363f6d..0000000 --- a/src/test/resources/spec-tests/async/trap-on-reenter.wast +++ /dev/null @@ -1,110 +0,0 @@ -;; This test creates an asynchronous recursive call stack: -;; $Parent --> $Child --> $Parent -;; That should trap when $Child tries to call $Parent. -(component $Parent - (core module $CoreInner - (memory (export "mem") 1) - (func (export "a") (result i32) - unreachable - ) - (func (export "a-cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (core instance $core_inner (instantiate $CoreInner)) - (func $a async (canon lift - (core func $core_inner "a") - async (callback (func $core_inner "a-cb")) - )) - - (component $Child - (import "a" (func $a async)) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - - (core module $CoreChild - (import "" "a" (func $a (result i32))) - (func (export "b") (result i32) - (i32.const 1 (; YIELD ;)) - ) - (func (export "b-cb") (param i32 i32 i32) (result i32) - (call $a) - unreachable - ) - ) - (canon lower (func $a) async (memory $memory "mem") (core func $a')) - (core instance $core_child (instantiate $CoreChild (with "" (instance - (export "a" (func $a')) - )))) - (func (export "b") async (canon lift - (core func $core_child "b") - async (callback (func $core_child "b-cb")) - )) - ) - (instance $child (instantiate $Child (with "a" (func $a)))) - - (core module $CoreOuter - (import "" "b" (func $b (result i32))) - (func $c (export "c") (result i32) - (i32.const 1 (; YIELD ;)) - ) - (func $c-cb (export "c-cb") (param i32 i32 i32) (result i32) - (call $b) - ) - ) - (canon lower (func $child "b") async (memory $core_inner "mem") (core func $b)) - (core instance $core_outer (instantiate $CoreOuter (with "" (instance - (export "b" (func $b)) - )))) - (func $c (export "c") async (canon lift - (core func $core_outer "c") - async (callback (func $core_outer "c-cb")) - )) -) -(assert_trap (invoke "c") "wasm trap: cannot enter component instance") - -;; also, for now, trap on parent-to-child -(component $Parent - (component $Child - (core module $CoreChild - (func (export "f")) - ) - (core instance $core_child (instantiate $CoreChild)) - (func (export "f") (canon lift (core func $core_child "f"))) - ) - (instance $child (instantiate $Child)) - (canon lower (func $child "f") (core func $f)) - - (core module $CoreOuter - (import "" "f" (func $f)) - (func (export "g") (call $f)) - ) - (core instance $core_outer (instantiate $CoreOuter (with "" (instance (export "f" (func $f)))))) - (func $g (export "g") (canon lift (core func $core_outer "g"))) -) -(assert_trap (invoke "g") "wasm trap: cannot enter component instance") - -;; also, for now, trap on child-to-parent -(component $Parent - (core module $CoreInner - (func (export "f")) - ) - (core instance $core_inner (instantiate $CoreInner)) - (func $f (canon lift (core func $core_inner "f"))) - - (component $Child - (import "f" (func $f)) - (canon lower (func $f) (core func $f')) - (core module $CoreChild - (import "" "f" (func $f)) - (func (export "g") (call $f)) - ) - (core instance $core_child (instantiate $CoreChild (with "" (instance (export "f" (func $f')))))) - (func (export "g") (canon lift (core func $core_child "g"))) - ) - (instance $child (instantiate $Child (with "f" (func $f)))) - (alias export $child "g" (func $g)) - (export "g" (func $g)) -) -(assert_trap (invoke "g") "wasm trap: cannot enter component instance") diff --git a/src/test/resources/spec-tests/async/validate-no-async-abi-for-sync-type.wast b/src/test/resources/spec-tests/async/validate-no-async-abi-for-sync-type.wast deleted file mode 100644 index e319bb4..0000000 --- a/src/test/resources/spec-tests/async/validate-no-async-abi-for-sync-type.wast +++ /dev/null @@ -1,27 +0,0 @@ -(assert_invalid - (component - (core module $M - (func (export "f")) - ) - (core instance $i (instantiate $M)) - (func (export "f") (canon lift (core func $i "f") async)) - ) - "the `async` canonical option requires an async function type") - -(assert_invalid - (component - (core module $M - (func (export "f") (param i32) (result i32) unreachable) - (func (export "f_cb") (param i32 i32 i32) (result i32) unreachable) - ) - (core instance $i (instantiate $M)) - (func (export "f") (canon lift (core func $i "f") async (callback (func $i "f_cb")))) - ) - "the `async` canonical option requires an async function type") - -(assert_invalid - (component - (import "f" (func $f)) - (core func $f' (canon lower (func $f) async)) - ) - "the `async` canonical option requires an async function type") diff --git a/src/test/resources/spec-tests/async/validate-no-stream-char.wast b/src/test/resources/spec-tests/async/validate-no-stream-char.wast deleted file mode 100644 index 30d1408..0000000 --- a/src/test/resources/spec-tests/async/validate-no-stream-char.wast +++ /dev/null @@ -1,7 +0,0 @@ -;; Test that `stream` is rejected as a validation error. -;; This is a temporary limitation; see https://github.com/WebAssembly/component-model/pull/607 -(assert_invalid - (component - (type (stream char)) - ) - "`stream` is not valid") diff --git a/src/test/resources/spec-tests/async/wait-during-callback.wast b/src/test/resources/spec-tests/async/wait-during-callback.wast deleted file mode 100644 index 3f95d5b..0000000 --- a/src/test/resources/spec-tests/async/wait-during-callback.wast +++ /dev/null @@ -1,77 +0,0 @@ -;; This test calls waitable-set.wait from under an async-callback-lifted export. -(component - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CM - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - - (func $run (export "run") (result i32) - (local $ret i32) (local $ret64 i64) - (local $futr i32) (local $futw i32) (local $ws i32) - (local $event_code i32) (local $retp i32) - - ;; create a future pair - (local.set $ret64 (call $future.new)) - (local.set $futr (i32.wrap_i64 (local.get $ret64))) - (local.set $futw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - - ;; start a pending read that will block - (local.set $ret (call $future.read (local.get $futr) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - ;; perform a write to make the above read ready - (local.set $ret (call $future.write (local.get $futw) (i32.const 0xdeadbeef))) - (if (i32.ne (i32.const 0 (; COMPLETED ;)) (local.get $ret)) - (then unreachable)) - - ;; wait on a waitable set containing our now-ready future.read which - ;; should then immediately resolve - (local.set $ws (call $waitable-set.new)) - (call $waitable.join (local.get $futr) (local.get $ws)) - (local.set $retp (i32.const 0)) - (local.set $event_code (call $waitable-set.wait (local.get $ws) (local.get $retp))) - (if (i32.ne (i32.const 4 (; FUTURE_READ ;)) (local.get $event_code)) - (then unreachable)) - (if (i32.ne (local.get $futr) (i32.load (local.get $retp))) - (then unreachable)) - - ;; return 42 - (call $task.return (i32.const 42)) - (i32.const 0 (; EXIT ;)) - ) - (func (export "run_cb") (param i32 i32 i32) (result i32) - unreachable - ) - ) - (type $FT (future)) - (canon task.return (result u32) (core func $task.return)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon future.new $FT (core func $future.new)) - (canon future.read $FT async (core func $future.read)) - (canon future.write $FT async (core func $future.write)) - (core instance $cm (instantiate $CM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "future.new" (func $future.new)) - (export "future.read" (func $future.read)) - (export "future.write" (func $future.write)) - )))) - (func (export "run") async (result u32) (canon lift - (core func $cm "run") - async (callback (func $cm "run_cb")) - )) -) -(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/async/zero-length.wast b/src/test/resources/spec-tests/async/zero-length.wast deleted file mode 100644 index fab7765..0000000 --- a/src/test/resources/spec-tests/async/zero-length.wast +++ /dev/null @@ -1,223 +0,0 @@ -;; This example defines 3 nested components $Producer, $Consumer and $Parent -;; $Parent imports $Consumer and $Producer, calling $Producer.produce, which -;; returns a stream that $Parent passes to $Consumer.consume. -;; $Producer and $Consumer both start by performing 0-length reads/writes to -;; detect when the other side is ready. Once signalled ready, a 4-byte -;; payload is written/read. -(component - (component $Producer - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CoreProducer - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - - ;; $ws is waited on by 'produce' - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - ;; $outsw is written by 'produce' - (global $outsw (mut i32) (i32.const 0)) - (global $outbufp (mut i32) (i32.const 0x20)) - - (global $state (mut i32) (i32.const 0)) - - (func $produce (export "produce") (result i32) - (local $ret i32) (local $ret64 i64) (local $outsr i32) - - ;; create a new stream r/w pair $outsr/$outsw - (local.set $ret64 (call $stream.new)) - (local.set $outsr (i32.wrap_i64 (local.get $ret64))) - (global.set $outsw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - - ;; return the readable end of the stream to the caller - (call $task.return (local.get $outsr)) - - ;; initiate a zero-length write - (local.set $ret (call $stream.write (global.get $outsw) (i32.const 0xdeadbeef) (i32.const 0))) - (if (i32.ne (i32.const -1) (local.get $ret)) - (then unreachable)) - - ;; wait for the stream.write to complete - (call $waitable.join (global.get $outsw) (global.get $ws)) - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) - ) - (func $produce_cb (export "produce_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - (local $ret i32) - - ;; confirm we're getting a write for the stream $outsw - (if (i32.ne (local.get $event_code) (i32.const 3 (; STREAM_WRITE ;))) - (then unreachable)) - (if (i32.ne (local.get $index) (global.get $outsw)) - (then unreachable)) - - ;; the first call to produce_cb: - (if (i32.eq (global.get $state) (i32.const 0)) (then - ;; confirm we're seeing the zero-length write complete - (if (i32.ne (local.get $payload) (i32.const 0 (; COMPLETED=0 | (0 << 4) ;))) - (then unreachable)) - - ;; issue an async non-zero-length write which should block per spec - (i32.store (i32.const 0) (i32.const 0x12345678)) - (local.set $ret (call $stream.write (global.get $outsw) (i32.const 0) (i32.const 4))) - (if (i32.ne (i32.const -1 (; BLOCKED ;)) (local.get $ret)) - (then unreachable)) - - (global.set $state (i32.const 1)) - - ;; wait on $ws - (return (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4)))) - )) - - ;; the second call to produce_cb: - (if (i32.eq (global.get $state) (i32.const 1)) (then - ;; confirm we're seeing the non-zero-length write complete - (if (i32.ne (local.get $payload) (i32.const 0x41 (; DROPPED=1 | (4 << 4) ;))) - (then unreachable)) - - (call $stream.drop-writable (global.get $outsw)) - (return (i32.const 0 (; EXIT ;))) - )) - - unreachable - ) - ) - (type $ST (stream u8)) - (canon task.return (result $ST) (core func $task.return)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.write $ST async (memory $memory "mem") (core func $stream.write)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (core instance $core_producer (instantiate $CoreProducer (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "stream.new" (func $stream.new)) - (export "stream.write" (func $stream.write)) - (export "stream.drop-writable" (func $stream.drop-writable)) - )))) - (func (export "produce") async (result (stream u8)) (canon lift - (core func $core_producer "produce") - async (callback (func $core_producer "produce_cb")) - )) - ) - - (component $Consumer - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (core module $CoreConsumer - (import "" "mem" (memory 1)) - (import "" "task.return" (func $task.return (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - - ;; $ws is waited on by 'consume' - (global $ws (mut i32) (i32.const 0)) - (func $start (global.set $ws (call $waitable-set.new))) - (start $start) - - ;; $insr is read by 'consume' - (global $insr (mut i32) (i32.const 0)) - (global $inbufp (mut i32) (i32.const 0x20)) - - (func $consume (export "consume") (param $insr i32) (result i32) - (local $ret i32) - (global.set $insr (local.get $insr)) - - ;; initiate a zero-length read which will also block (even though there is - ;; a pending write, b/c the pending write is 0-length, per spec) - (local.set $ret (call $stream.read (global.get $insr) (i32.const 0xdeadbeef) (i32.const 0))) - (if (i32.ne (i32.const -1) (local.get $ret)) - (then unreachable)) - - ;; wait for the stream.read to complete - (call $waitable.join (global.get $insr) (global.get $ws)) - (i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4))) - ) - (func $consume_cb (export "consume_cb") (param $event_code i32) (param $index i32) (param $payload i32) (result i32) - (local $ret i32) - - ;; confirm we're seeing the zero-length read complete - (if (i32.ne (local.get $event_code) (i32.const 2 (; STREAM_READ ;))) - (then unreachable)) - (if (i32.ne (local.get $index) (global.get $insr)) - (then unreachable)) - (if (i32.ne (local.get $payload) (i32.const 0 (; COMPLETED=0 | (0 << 4) ;))) - (then unreachable)) - - ;; perform a non-zero-length read which should succeed without blocking - (local.set $ret (call $stream.read (global.get $insr) (i32.const 0) (i32.const 100))) - (if (i32.ne (i32.const 0x40 (; (4 << 4) | COMPLETED=0 ;)) (local.get $ret)) - (then unreachable)) - (local.set $ret (i32.load (i32.const 0))) - (if (i32.ne (i32.const 0x12345678) (local.get $ret)) - (then unreachable)) - - (call $stream.drop-readable (global.get $insr)) - - ;; return 42 to the top-level assert_return - (call $task.return (i32.const 42)) - (i32.const 0 (; EXIT ;)) - ) - ) - (type $ST (stream u8)) - (canon task.return (result u32) (core func $task.return)) - (canon waitable.join (core func $waitable.join)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon stream.read $ST async (memory $memory "mem") (core func $stream.read)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (core instance $core_consumer (instantiate $CoreConsumer (with "" (instance - (export "mem" (memory $memory "mem")) - (export "task.return" (func $task.return)) - (export "waitable.join" (func $waitable.join)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "stream.read" (func $stream.read)) - (export "stream.drop-readable" (func $stream.drop-readable)) - )))) - (func (export "consume") async (param "in" (stream u8)) (result u32) (canon lift - (core func $core_consumer "consume") - async (callback (func $core_consumer "consume_cb")) - )) - ) - - (component $Parent - (import "produce" (func $produce async (result (stream u8)))) - (import "consume" (func $consume async (param "in" (stream u8)) (result u32))) - - (core module $CoreParent - (import "" "produce" (func $produce (result i32))) - (import "" "consume" (func $consume (param i32) (result i32))) - (memory 1) - (func $run (export "run") (result i32) - (call $consume (call $produce)) - ) - ) - - (canon lower (func $produce) (core func $produce')) - (canon lower (func $consume) (core func $consume')) - (core instance $core_parent (instantiate $CoreParent (with "" (instance - (export "produce" (func $produce')) - (export "consume" (func $consume')) - )))) - (func (export "run") async (result u32) (canon lift (core func $core_parent "run"))) - ) - - (instance $producer (instantiate $Producer)) - (instance $consumer (instantiate $Consumer)) - (instance $parent (instantiate $Parent - (with "produce" (func $producer "produce")) - (with "consume" (func $consumer "consume")) - )) - (func (export "run") (alias export $parent "run")) -) -(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/names/kebab.wast b/src/test/resources/spec-tests/names/kebab.wast deleted file mode 100644 index df135f8..0000000 --- a/src/test/resources/spec-tests/names/kebab.wast +++ /dev/null @@ -1,60 +0,0 @@ -(component (component - (import "a" (func)) - (import "a1" (func)) - (import "a-1" (func)) - (import "a-1-b-2-c-3" (func)) - (import "B" (func)) - (import "B1" (func)) - (import "B-1" (func)) - (import "B-1-C-2-D-3" (func)) - (import "a11-B11-123-ABC-abc" (func)) - (import "ns-1-a:b-1-c/D-2" (func)) -)) -(assert_invalid - (component - (import "1" (func))) - "is not in kebab case") -(assert_invalid - (component - (import "1-a" (func))) - "is not in kebab case") -(assert_invalid - (component - (import "" (func))) - "is not in kebab case") -(assert_invalid - (component - (import "a-" (func))) - "is not in kebab case") -(assert_invalid - (component - (import "a--" (func))) - "is not in kebab case") -(assert_invalid - (component - (import "1:a/b" (func))) - "is not in kebab case") -(assert_invalid - (component - (import "A:b/c" (func))) - "is not a valid extern name") -(assert_invalid - (component - (import "1:b/c" (func))) - "is not a valid extern name") -(assert_invalid - (component - (import "ns-A:b/c" (func))) - "is not a valid extern name") -(assert_invalid - (component - (import "ns:A/b" (func))) - "is not a valid extern name") -(assert_invalid - (component - (import "ns:1/a" (func))) - "is not a valid extern name") -(assert_invalid - (component - (import "ns:pkg-A/b" (func))) - "is not a valid extern name") diff --git a/src/test/resources/spec-tests/resources/multiple-resources.wast b/src/test/resources/spec-tests/resources/multiple-resources.wast deleted file mode 100644 index 77549ad..0000000 --- a/src/test/resources/spec-tests/resources/multiple-resources.wast +++ /dev/null @@ -1,170 +0,0 @@ -;; This test has two components $C and $D where $D imports and calls $C -;; $C implements two resource types imported and used by $D -;; $D creates instances of both resource types, uses them and destroys them -(component - (component $C - (core module $Indirect - (table (export "ftbl") 2 funcref) - (type $FT (func (param i32))) - (func (export "R1-dtor") (param i32) - (call_indirect (type $FT) (local.get 0) (i32.const 0)) - ) - (func (export "R2-dtor") (param i32) - (call_indirect (type $FT) (local.get 0) (i32.const 1)) - ) - ) - (core instance $indirect (instantiate $Indirect)) - (type $R1' (resource (rep i32) (dtor (func $indirect "R1-dtor")))) - (type $R2' (resource (rep i32) (dtor (func $indirect "R2-dtor")))) - (export $R1 "R1" (type $R1')) - (export $R2 "R2" (type $R2')) - (canon resource.new $R1' (core func $R1.resource.new)) - (canon resource.new $R2' (core func $R2.resource.new)) - - (core module $CM - (import "" "ftbl" (table 1 funcref)) - (import "" "R1.resource.new" (func $R1.resource.new (param i32) (result i32))) - (import "" "R2.resource.new" (func $R2.resource.new (param i32) (result i32))) - (memory 1) - (global $num-live-R1 (mut i32) (i32.const 0)) - (global $num-live-R2 (mut i32) (i32.const 0)) - - ;; constructors - (func $make-R1 (export "make-R1") (result i32) - (local $h i32) - (global.set $num-live-R1 (i32.add (global.get $num-live-R1) (i32.const 1))) - (call $R1.resource.new (i32.add (i32.const 0x40) (global.get $num-live-R1))) - ) - (func $make-R2 (export "make-R2") (result i32) - (local $h i32) - (global.set $num-live-R2 (i32.add (global.get $num-live-R2) (i32.const 1))) - (call $R2.resource.new (i32.add (i32.const 0x80) (global.get $num-live-R2))) - ) - - ;; accessors - (func $get-rep-R1 (export "get-rep-R1") (param $rep i32) (result i32) - (local.get $rep) - ) - (func $get-rep-R2 (export "get-rep-R2") (param $rep i32) (result i32) - (local.get $rep) - ) - - ;; destructors - (func $R1-dtor (param $rep i32) - (if (i32.or (i32.lt_u (local.get $rep) (i32.const 0x41)) (i32.gt_u (local.get $rep) (i32.const 0x42))) - (then unreachable)) - (if (i32.eqz (global.get $num-live-R1)) - (then unreachable)) - (global.set $num-live-R1 (i32.sub (global.get $num-live-R1) (i32.const 1))) - ) - (func $R2-dtor (param $rep i32) - (if (i32.or (i32.lt_u (local.get $rep) (i32.const 0x81)) (i32.gt_u (local.get $rep) (i32.const 0x82))) - (then unreachable)) - (if (i32.eqz (global.get $num-live-R2)) - (then unreachable)) - (global.set $num-live-R2 (i32.sub (global.get $num-live-R2) (i32.const 1))) - ) - (func $num-live (export "num-live") (result i32) - (i32.add (global.get $num-live-R1) (global.get $num-live-R2)) - ) - (elem (i32.const 0) $R1-dtor $R2-dtor) - ) - (core instance $cm (instantiate $CM (with "" (instance - (export "ftbl" (table $indirect "ftbl")) - (export "R1.resource.new" (func $R1.resource.new)) - (export "R2.resource.new" (func $R2.resource.new)) - )))) - (func $make-R1 (export "make-R1") (result (own $R1)) (canon lift (core func $cm "make-R1"))) - (func $make-R2 (export "make-R2") (result (own $R2)) (canon lift (core func $cm "make-R2"))) - (func $get-rep-R1 (export "get-rep-R1") (param "r" (borrow $R1)) (result u32) (canon lift (core func $cm "get-rep-R1"))) - (func $get-rep-R2 (export "get-rep-R2") (param "r" (borrow $R2)) (result u32) (canon lift (core func $cm "get-rep-R2"))) - (func (export "num-live") (result u32) (canon lift (core func $cm "num-live"))) - ) - - (component $D - (import "c" (instance $c - (export "R1" (type $R1 (sub resource))) - (export "R2" (type $R2 (sub resource))) - (export "make-R1" (func (result (own $R1)))) - (export "make-R2" (func (result (own $R2)))) - (export "get-rep-R1" (func (param "r" (borrow $R1)) (result u32))) - (export "get-rep-R2" (func (param "r" (borrow $R2)) (result u32))) - (export "num-live" (func (result u32))) - )) - (core module $DM - (import "" "R1.resource.drop" (func $R1.resource.drop (param i32))) - (import "" "R2.resource.drop" (func $R2.resource.drop (param i32))) - (import "" "make-R1" (func $make-R1 (result i32))) - (import "" "make-R2" (func $make-R2 (result i32))) - (import "" "get-rep-R1" (func $get-rep-R1 (param i32) (result i32))) - (import "" "get-rep-R2" (func $get-rep-R2 (param i32) (result i32))) - (import "" "num-live" (func $num-live (result i32))) - (memory 1) - - (func $run (export "run") (result i32) - (local $ret i32) - (local $h1 i32) (local $h2 i32) (local $h3 i32) (local $h4 i32) - - ;; create 4 resources - (local.set $h1 (call $make-R1)) - (if (i32.ne (i32.const 1) (local.get $h1)) - (then unreachable)) - (local.set $h2 (call $make-R2)) - (if (i32.ne (i32.const 2) (local.get $h2)) - (then unreachable)) - (local.set $h3 (call $make-R1)) - (if (i32.ne (i32.const 3) (local.get $h3)) - (then unreachable)) - (local.set $h4 (call $make-R2)) - (if (i32.ne (i32.const 4) (local.get $h4)) - (then unreachable)) - (if (i32.ne (i32.const 4) (call $num-live)) - (then unreachable)) - - ;; use and destroy resources - (if (i32.ne (i32.const 0x81) (call $get-rep-R2 (local.get $h2))) - (then unreachable)) - (call $R2.resource.drop (local.get $h2)) - (if (i32.ne (i32.const 0x41) (call $get-rep-R1 (local.get $h1))) - (then unreachable)) - (call $R1.resource.drop (local.get $h1)) - (if (i32.ne (i32.const 0x82) (call $get-rep-R2 (local.get $h4))) - (then unreachable)) - (call $R2.resource.drop (local.get $h4)) - (if (i32.ne (i32.const 0x42) (call $get-rep-R1 (local.get $h3))) - (then unreachable)) - (call $R1.resource.drop (local.get $h3)) - - ;; everything should be destroyed - (if (i32.ne (i32.const 0) (call $num-live)) - (then unreachable)) - - (i32.const 42) - ) - ) - (alias export $c "R1" (type $R1)) - (alias export $c "R2" (type $R2)) - (canon resource.drop $R1 (core func $R1.resource.drop)) - (canon resource.drop $R2 (core func $R2.resource.drop)) - (canon lower (func $c "make-R1") (core func $make-R1')) - (canon lower (func $c "make-R2") (core func $make-R2')) - (canon lower (func $c "get-rep-R1") (core func $get-rep-R1')) - (canon lower (func $c "get-rep-R2") (core func $get-rep-R2')) - (canon lower (func $c "num-live") (core func $num-live')) - (core instance $dm (instantiate $DM (with "" (instance - (export "R1.resource.drop" (func $R1.resource.drop)) - (export "R2.resource.drop" (func $R2.resource.drop)) - (export "make-R1" (func $make-R1')) - (export "make-R2" (func $make-R2')) - (export "get-rep-R1" (func $get-rep-R1')) - (export "get-rep-R2" (func $get-rep-R2')) - (export "num-live" (func $num-live')) - )))) - (func (export "run") (result u32) (canon lift (core func $dm "run"))) - ) - - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "c" (instance $c)))) - (func (export "run") (alias export $d "run")) -) -(assert_return (invoke "run") (u32.const 42)) diff --git a/src/test/resources/spec-tests/validation/implements.wast b/src/test/resources/spec-tests/validation/implements.wast deleted file mode 100644 index 7df0024..0000000 --- a/src/test/resources/spec-tests/validation/implements.wast +++ /dev/null @@ -1,108 +0,0 @@ -;; valid usages of `implements` -(component - (component - (import "a" (implements "a:b/c") (instance)) - (import "b" (implements "a:b/c") (instance)) - (import "c" (implements "a:b/c@1.0.0") (instance)) - (import "my-label" (implements "ns:pkg/iface") (instance)) - (import "a:b/c" (instance)) - (import "a:b/c@1.0.0" (instance)) - - (instance $a) - - (export "a" (implements "a:b/c") (instance $a)) - (export "b" (implements "a:b/c") (instance $a)) - (export "c" (implements "a:b/c@1.0.0") (instance $a)) - (export "my-label" (implements "ns:pkg/iface") (instance $a)) - (export "a:b/c" (instance $a)) - (export "a:b/c@1.0.0" (instance $a)) - ) - - (type (instance - (export "a" (implements "a:b/c") (instance)) - )) - (type (component - (import "a" (implements "a:b/c") (instance)) - (export "a" (implements "a:b/c") (instance)) - )) - - (instance $a) - (instance - (export "a" (implements "a:b/c") (instance $a)) - ) -) - -;; invalid, `not-valid` should be something like `a:b/c` -(assert_invalid - (component (import "a" (implements "not-valid") (instance))) - "must be an interface") - -;; invalid, `""` must be a valid kebab-name. -(assert_invalid - (component (import "a" (implements "") (instance))) - "not a valid name") - -;; invalid, can't import the same plain-name twice. -(assert_invalid - (component - (import "a" (implements "a:b/c") (instance)) - (import "a" (implements "a:b/c") (instance)) - ) - "conflicts with previous name") - -;; invalid, can't import the same plain-name twice. -(assert_invalid - (component - (import "a" (implements "a1:b/c") (instance)) - (import "a" (implements "a2:b/c") (instance)) - ) - "conflicts with previous name") - -;; invalid, can't import the same plain-name twice. -(assert_invalid - (component - (import "a" (implements "a:b/c") (instance)) - (import "a" (implements "a:b/c@1.0.0") (instance)) - ) - "conflicts with previous name") - -;; invalid, can't import the same plain-name twice. -(assert_invalid - (component - (import "a" (instance)) - (import "a" (implements "a:b/c") (instance)) - ) - "conflicts with previous name") - -;; invalid, `implements` can only be used by imports/exports typed as `instance` -(assert_invalid - (component - (import "a" (implements "a:b/c") (func)) - ) - "only instance names can have an `implements`") - -;; invalid, `implements` can only be used by imports/exports named with a -;; plainname. -(assert_invalid - (component - (import "a1:b/c" (implements "a2:b/c") (instance)) - ) - "name `a1:b/c` is not valid with `implements`") - -;; validity checks apply to other locations of `implements`, such as -;; component/instance types and bag-of-exports. -(assert_invalid - (component (type (component (import "a" (implements "not-valid") (instance))))) - "must be an interface") -(assert_invalid - (component (type (component (export "a" (implements "") (instance))))) - "not a valid name") -(assert_invalid - (component (type (instance (export "a" (implements "a:b/c") (func))))) - "only instance names") -(assert_invalid - (component - (instance) - (instance (export "x" (implements "a") (instance 0))) - ) - "must be an interface") diff --git a/src/test/resources/spec-tests/values/post-return.wast b/src/test/resources/spec-tests/values/post-return.wast deleted file mode 100644 index 7bc6d66..0000000 --- a/src/test/resources/spec-tests/values/post-return.wast +++ /dev/null @@ -1,384 +0,0 @@ -;; Tests behavior of built-ins called from inside a post-return function. - -;; built-ins that trap when called from post-return: -(component definition $Tester - (component $C - (core module $CM - (func (export "import")) - ) - (core instance $cm (instantiate $CM)) - (func (export "import") (canon lift (core func $cm "import"))) - ) - (component $D - (import "import" (func $import)) - - (core module $Memory (memory (export "mem") 1)) - (core instance $memory (instantiate $Memory)) - (type $R (resource (rep i32))) - (type $ST (stream u32)) - (type $FT (future u32)) - (canon resource.new $R (core func $resource.new)) - (canon resource.drop $R (core func $resource.drop)) - (canon task.return (core func $task.return)) - (canon task.cancel (core func $task.cancel)) - (canon thread.yield (core func $yield)) - (canon waitable-set.new (core func $waitable-set.new)) - (canon waitable-set.wait (memory $memory "mem") (core func $waitable-set.wait)) - (canon waitable-set.poll (memory $memory "mem") (core func $waitable-set.poll)) - (canon waitable-set.drop (core func $waitable-set.drop)) - (canon waitable.join (core func $waitable.join)) - (canon subtask.cancel (core func $subtask.cancel)) - (canon subtask.drop (core func $subtask.drop)) - (canon stream.new $ST (core func $stream.new)) - (canon stream.read $ST (memory $memory "mem") (core func $stream.read)) - (canon stream.write $ST (memory $memory "mem") (core func $stream.write)) - (canon stream.cancel-read $ST (core func $stream.cancel-read)) - (canon stream.cancel-write $ST (core func $stream.cancel-write)) - (canon stream.drop-readable $ST (core func $stream.drop-readable)) - (canon stream.drop-writable $ST (core func $stream.drop-writable)) - (canon future.new $FT (core func $future.new)) - (canon future.read $FT (memory $memory "mem") (core func $future.read)) - (canon future.write $FT (memory $memory "mem") (core func $future.write)) - (canon future.cancel-read $FT (core func $future.cancel-read)) - (canon future.cancel-write $FT (core func $future.cancel-write)) - (canon future.drop-readable $FT (core func $future.drop-readable)) - (canon future.drop-writable $FT (core func $future.drop-writable)) - (core module $DM - (import "" "mem" (memory 1)) - (import "" "import" (func $import)) - (import "" "resource.new" (func $resource.new (param i32) (result i32))) - (import "" "resource.drop" (func $resource.drop (param i32))) - (import "" "task.return" (func $task.return)) - (import "" "task.cancel" (func $task.cancel)) - (import "" "yield" (func $yield (result i32))) - (import "" "waitable-set.new" (func $waitable-set.new (result i32))) - (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) - (import "" "waitable-set.poll" (func $waitable-set.poll (param i32 i32) (result i32))) - (import "" "waitable-set.drop" (func $waitable-set.drop (param i32))) - (import "" "waitable.join" (func $waitable.join (param i32 i32))) - (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) - (import "" "subtask.drop" (func $subtask.drop (param i32))) - (import "" "stream.new" (func $stream.new (result i64))) - (import "" "stream.read" (func $stream.read (param i32 i32 i32) (result i32))) - (import "" "stream.write" (func $stream.write (param i32 i32 i32) (result i32))) - (import "" "stream.cancel-read" (func $stream.cancel-read (param i32) (result i32))) - (import "" "stream.cancel-write" (func $stream.cancel-write (param i32) (result i32))) - (import "" "stream.drop-readable" (func $stream.drop-readable (param i32))) - (import "" "stream.drop-writable" (func $stream.drop-writable (param i32))) - (import "" "future.new" (func $future.new (result i64))) - (import "" "future.read" (func $future.read (param i32 i32) (result i32))) - (import "" "future.write" (func $future.write (param i32 i32) (result i32))) - (import "" "future.cancel-read" (func $future.cancel-read (param i32) (result i32))) - (import "" "future.cancel-write" (func $future.cancel-write (param i32) (result i32))) - (import "" "future.drop-readable" (func $future.drop-readable (param i32))) - (import "" "future.drop-writable" (func $future.drop-writable (param i32))) - - (func (export "noop")) - (func (export "trap-calling-import") (call $import)) - (func (export "trap-calling-resource-new") (drop (call $resource.new (i32.const 0)))) - (func (export "trap-calling-resource-drop") (call $resource.drop (i32.const 0))) - (func (export "trap-calling-task-return") (call $task.return)) - (func (export "trap-calling-task-cancel") (call $task.cancel)) - (func (export "trap-calling-yield") (drop (call $yield))) - (func (export "trap-calling-waitable-set-new") (drop (call $waitable-set.new))) - (func (export "trap-calling-waitable-set-wait") (drop (call $waitable-set.wait (i32.const 0) (i32.const 0)))) - (func (export "trap-calling-waitable-set-poll") (drop (call $waitable-set.poll (i32.const 0) (i32.const 0)))) - (func (export "trap-calling-waitable-set-drop") (call $waitable-set.drop (i32.const 0))) - (func (export "trap-calling-waitable-join") (call $waitable.join (i32.const 0) (i32.const 0))) - (func (export "trap-calling-subtask-cancel") (drop (call $subtask.cancel (i32.const 0)))) - (func (export "trap-calling-subtask-drop") (call $subtask.drop (i32.const 0))) - (func (export "trap-calling-stream-new") (drop (call $stream.new))) - (func (export "trap-calling-stream-read") (drop (call $stream.read (i32.const 0) (i32.const 0) (i32.const 0)))) - (func (export "trap-calling-stream-write") (drop (call $stream.write (i32.const 0) (i32.const 0) (i32.const 0)))) - (func (export "trap-calling-stream-cancel-read") (drop (call $stream.cancel-read (i32.const 0)))) - (func (export "trap-calling-stream-cancel-write") (drop (call $stream.cancel-write (i32.const 0)))) - (func (export "trap-calling-stream-drop-readable") (call $stream.drop-readable (i32.const 0))) - (func (export "trap-calling-stream-drop-writable") (call $stream.drop-writable (i32.const 0))) - (func (export "trap-calling-future-new") (drop (call $future.new))) - (func (export "trap-calling-future-read") (drop (call $future.read (i32.const 0) (i32.const 0)))) - (func (export "trap-calling-future-write") (drop (call $future.write (i32.const 0) (i32.const 0)))) - (func (export "trap-calling-future-cancel-read") (drop (call $future.cancel-read (i32.const 0)))) - (func (export "trap-calling-future-cancel-write") (drop (call $future.cancel-write (i32.const 0)))) - (func (export "trap-calling-future-drop-readable") (call $future.drop-readable (i32.const 0))) - (func (export "trap-calling-future-drop-writable") (call $future.drop-writable (i32.const 0))) - ) - (canon lower (func $import) (core func $import')) - (core instance $dm (instantiate $DM (with "" (instance - (export "mem" (memory $memory "mem")) - (export "import" (func $import')) - (export "resource.new" (func $resource.new)) - (export "resource.drop" (func $resource.drop)) - (export "task.return" (func $task.return)) - (export "task.cancel" (func $task.cancel)) - (export "yield" (func $yield)) - (export "waitable-set.new" (func $waitable-set.new)) - (export "waitable-set.wait" (func $waitable-set.wait)) - (export "waitable-set.poll" (func $waitable-set.poll)) - (export "waitable-set.drop" (func $waitable-set.drop)) - (export "waitable.join" (func $waitable.join)) - (export "subtask.cancel" (func $subtask.cancel)) - (export "subtask.drop" (func $subtask.drop)) - (export "stream.new" (func $stream.new)) - (export "stream.read" (func $stream.read)) - (export "stream.write" (func $stream.write)) - (export "stream.cancel-read" (func $stream.cancel-read)) - (export "stream.cancel-write" (func $stream.cancel-write)) - (export "stream.drop-readable" (func $stream.drop-readable)) - (export "stream.drop-writable" (func $stream.drop-writable)) - (export "future.new" (func $future.new)) - (export "future.read" (func $future.read)) - (export "future.write" (func $future.write)) - (export "future.cancel-read" (func $future.cancel-read)) - (export "future.cancel-write" (func $future.cancel-write)) - (export "future.drop-readable" (func $future.drop-readable)) - (export "future.drop-writable" (func $future.drop-writable)) - )))) - (func (export "trap-calling-import") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-import")))) - (func (export "trap-calling-resource-new") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-resource-new")))) - (func (export "trap-calling-resource-drop") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-resource-drop")))) - (func (export "trap-calling-task-return") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-task-return")))) - (func (export "trap-calling-task-cancel") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-task-cancel")))) - (func (export "trap-calling-yield") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-yield")))) - (func (export "trap-calling-waitable-set-new") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-waitable-set-new")))) - (func (export "trap-calling-waitable-set-wait") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-waitable-set-wait")))) - (func (export "trap-calling-waitable-set-poll") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-waitable-set-poll")))) - (func (export "trap-calling-waitable-set-drop") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-waitable-set-drop")))) - (func (export "trap-calling-waitable-join") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-waitable-join")))) - (func (export "trap-calling-subtask-cancel") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-subtask-cancel")))) - (func (export "trap-calling-subtask-drop") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-subtask-drop")))) - (func (export "trap-calling-stream-new") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-new")))) - (func (export "trap-calling-stream-read") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-read")))) - (func (export "trap-calling-stream-write") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-write")))) - (func (export "trap-calling-stream-cancel-read") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-cancel-read")))) - (func (export "trap-calling-stream-cancel-write") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-cancel-write")))) - (func (export "trap-calling-stream-drop-readable") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-drop-readable")))) - (func (export "trap-calling-stream-drop-writable") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-stream-drop-writable")))) - (func (export "trap-calling-future-new") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-new")))) - (func (export "trap-calling-future-read") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-read")))) - (func (export "trap-calling-future-write") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-write")))) - (func (export "trap-calling-future-cancel-read") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-cancel-read")))) - (func (export "trap-calling-future-cancel-write") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-cancel-write")))) - (func (export "trap-calling-future-drop-readable") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-drop-readable")))) - (func (export "trap-calling-future-drop-writable") (canon lift (core func $dm "noop") (post-return (func $dm "trap-calling-future-drop-writable")))) - ) - (instance $c (instantiate $C)) - (instance $d (instantiate $D (with "import" (func $c "import")))) - (func (export "trap-calling-import") (alias export $d "trap-calling-import")) - (func (export "trap-calling-resource-new") (alias export $d "trap-calling-resource-new")) - (func (export "trap-calling-resource-drop") (alias export $d "trap-calling-resource-drop")) - (func (export "trap-calling-task-return") (alias export $d "trap-calling-task-return")) - (func (export "trap-calling-task-cancel") (alias export $d "trap-calling-task-cancel")) - (func (export "trap-calling-yield") (alias export $d "trap-calling-yield")) - (func (export "trap-calling-waitable-set-new") (alias export $d "trap-calling-waitable-set-new")) - (func (export "trap-calling-waitable-set-wait") (alias export $d "trap-calling-waitable-set-wait")) - (func (export "trap-calling-waitable-set-poll") (alias export $d "trap-calling-waitable-set-poll")) - (func (export "trap-calling-waitable-set-drop") (alias export $d "trap-calling-waitable-set-drop")) - (func (export "trap-calling-waitable-join") (alias export $d "trap-calling-waitable-join")) - (func (export "trap-calling-subtask-cancel") (alias export $d "trap-calling-subtask-cancel")) - (func (export "trap-calling-subtask-drop") (alias export $d "trap-calling-subtask-drop")) - (func (export "trap-calling-stream-new") (alias export $d "trap-calling-stream-new")) - (func (export "trap-calling-stream-read") (alias export $d "trap-calling-stream-read")) - (func (export "trap-calling-stream-write") (alias export $d "trap-calling-stream-write")) - (func (export "trap-calling-stream-cancel-read") (alias export $d "trap-calling-stream-cancel-read")) - (func (export "trap-calling-stream-cancel-write") (alias export $d "trap-calling-stream-cancel-write")) - (func (export "trap-calling-stream-drop-readable") (alias export $d "trap-calling-stream-drop-readable")) - (func (export "trap-calling-stream-drop-writable") (alias export $d "trap-calling-stream-drop-writable")) - (func (export "trap-calling-future-new") (alias export $d "trap-calling-future-new")) - (func (export "trap-calling-future-read") (alias export $d "trap-calling-future-read")) - (func (export "trap-calling-future-write") (alias export $d "trap-calling-future-write")) - (func (export "trap-calling-future-cancel-read") (alias export $d "trap-calling-future-cancel-read")) - (func (export "trap-calling-future-cancel-write") (alias export $d "trap-calling-future-cancel-write")) - (func (export "trap-calling-future-drop-readable") (alias export $d "trap-calling-future-drop-readable")) - (func (export "trap-calling-future-drop-writable") (alias export $d "trap-calling-future-drop-writable")) -) - -(component instance $i1 $Tester) -(assert_trap (invoke "trap-calling-import") "cannot leave component instance") -(component instance $i2 $Tester) -(assert_trap (invoke "trap-calling-resource-new") "cannot leave component instance") -(component instance $i3 $Tester) -(assert_trap (invoke "trap-calling-resource-drop") "cannot leave component instance") -(component instance $i4 $Tester) -(assert_trap (invoke "trap-calling-task-return") "cannot leave component instance") -(component instance $i5 $Tester) -(assert_trap (invoke "trap-calling-task-cancel") "cannot leave component instance") -(component instance $i6 $Tester) -(assert_trap (invoke "trap-calling-yield") "cannot leave component instance") -(component instance $i7 $Tester) -(assert_trap (invoke "trap-calling-waitable-set-new") "cannot leave component instance") -(component instance $i8 $Tester) -(assert_trap (invoke "trap-calling-waitable-set-wait") "cannot leave component instance") -(component instance $i9 $Tester) -(assert_trap (invoke "trap-calling-waitable-set-poll") "cannot leave component instance") -(component instance $i10 $Tester) -(assert_trap (invoke "trap-calling-waitable-set-drop") "cannot leave component instance") -(component instance $i11 $Tester) -(assert_trap (invoke "trap-calling-waitable-join") "cannot leave component instance") -(component instance $i12 $Tester) -(assert_trap (invoke "trap-calling-subtask-cancel") "cannot leave component instance") -(component instance $i13 $Tester) -(assert_trap (invoke "trap-calling-subtask-drop") "cannot leave component instance") -(component instance $i14 $Tester) -(assert_trap (invoke "trap-calling-stream-new") "cannot leave component instance") -(component instance $i15 $Tester) -(assert_trap (invoke "trap-calling-stream-read") "cannot leave component instance") -(component instance $i16 $Tester) -(assert_trap (invoke "trap-calling-stream-write") "cannot leave component instance") -(component instance $i17 $Tester) -(assert_trap (invoke "trap-calling-stream-cancel-read") "cannot leave component instance") -(component instance $i18 $Tester) -(assert_trap (invoke "trap-calling-stream-cancel-write") "cannot leave component instance") -(component instance $i19 $Tester) -(assert_trap (invoke "trap-calling-stream-drop-readable") "cannot leave component instance") -(component instance $i20 $Tester) -(assert_trap (invoke "trap-calling-stream-drop-writable") "cannot leave component instance") -(component instance $i21 $Tester) -(assert_trap (invoke "trap-calling-future-new") "cannot leave component instance") -(component instance $i22 $Tester) -(assert_trap (invoke "trap-calling-future-read") "cannot leave component instance") -(component instance $i23 $Tester) -(assert_trap (invoke "trap-calling-future-write") "cannot leave component instance") -(component instance $i24 $Tester) -(assert_trap (invoke "trap-calling-future-cancel-read") "cannot leave component instance") -(component instance $i25 $Tester) -(assert_trap (invoke "trap-calling-future-cancel-write") "cannot leave component instance") -(component instance $i26 $Tester) -(assert_trap (invoke "trap-calling-future-drop-readable") "cannot leave component instance") -(component instance $i27 $Tester) -(assert_trap (invoke "trap-calling-future-drop-writable") "cannot leave component instance") - - -;; built-ins that don't trap: -(component - (canon context.get i32 0 (core func $context.get)) - (canon context.set i32 0 (core func $context.set)) - (core module $CM - (import "" "context.get" (func $context.get (result i32))) - (import "" "context.set" (func $context.set (param i32))) - (global $saved (mut i32) (i32.const 0)) - - (func (export "f") (result i32) - (call $context.set (i32.const 42)) - (i32.const 7) - ) - (func (export "f-pr") (param i32) - (global.set $saved (call $context.get)) - (call $context.set (i32.const 99)) - ) - (func (export "check") (result i32) - (global.get $saved) - ) - ) - (core instance $cm (instantiate $CM (with "" (instance - (export "context.get" (func $context.get)) - (export "context.set" (func $context.set)) - )))) - (func (export "f") (result u32) (canon lift - (core func $cm "f") - (post-return (func $cm "f-pr")) - )) - (func (export "check") (result u32) (canon lift - (core func $cm "check") - )) -) -(assert_return (invoke "f") (u32.const 7)) -(assert_return (invoke "check") (u32.const 42)) - - -(component - (type $R (resource (rep i32))) - (canon resource.new $R (core func $resource.new)) - (canon resource.rep $R (core func $resource.rep)) - (core module $CM - (import "" "resource.new" (func $resource.new (param i32) (result i32))) - (import "" "resource.rep" (func $resource.rep (param i32) (result i32))) - - (global $handle (mut i32) (i32.const 0)) - (global $saved-rep (mut i32) (i32.const 0)) - - (func (export "f") (result i32) - (global.set $handle (call $resource.new (i32.const 123))) - (i32.const 5) - ) - (func (export "f-pr") (param i32) - (global.set $saved-rep (call $resource.rep (global.get $handle))) - ) - (func (export "check") (result i32) - (global.get $saved-rep) - ) - ) - (core instance $cm (instantiate $CM (with "" (instance - (export "resource.new" (func $resource.new)) - (export "resource.rep" (func $resource.rep)) - )))) - (func (export "f") (result u32) (canon lift - (core func $cm "f") - (post-return (func $cm "f-pr")) - )) - (func (export "check") (result u32) (canon lift - (core func $cm "check") - )) -) -(assert_return (invoke "f") (u32.const 5)) -(assert_return (invoke "check") (u32.const 123)) - - -(component - (canon backpressure.inc (core func $bp.inc)) - (canon backpressure.dec (core func $bp.dec)) - (core module $CM - (import "" "bp.inc" (func $bp.inc)) - (import "" "bp.dec" (func $bp.dec)) - - (func (export "f") (result i32) - (i32.const 11) - ) - (func (export "f-pr") (param i32) - (call $bp.inc) - (call $bp.dec) - ) - ) - (core instance $cm (instantiate $CM (with "" (instance - (export "bp.inc" (func $bp.inc)) - (export "bp.dec" (func $bp.dec)) - )))) - (func (export "f") (result u32) (canon lift - (core func $cm "f") - (post-return (func $cm "f-pr")) - )) -) -(assert_return (invoke "f") (u32.const 11)) - - -(component - (canon thread.index (core func $thread.index)) - (core module $CM - (import "" "thread.index" (func $thread.index (result i32))) - - (global $body-idx (mut i32) (i32.const -1)) - (global $pr-idx (mut i32) (i32.const -1)) - - (func (export "f") (result i32) - (global.set $body-idx (call $thread.index)) - (i32.const 13) - ) - (func (export "f-pr") (param i32) - (global.set $pr-idx (call $thread.index)) - ) - (func (export "check") (result i32) - (i32.eq (global.get $body-idx) (global.get $pr-idx)) - ) - ) - (core instance $cm (instantiate $CM (with "" (instance - (export "thread.index" (func $thread.index)) - )))) - (func (export "f") (result u32) (canon lift - (core func $cm "f") - (post-return (func $cm "f-pr")) - )) - (func (export "check") (result u32) (canon lift - (core func $cm "check") - )) -) -(assert_return (invoke "f") (u32.const 13)) -(assert_return (invoke "check") (u32.const 1)) diff --git a/src/test/resources/spec-tests/values/strings.wast b/src/test/resources/spec-tests/values/strings.wast deleted file mode 100644 index e838ccd..0000000 --- a/src/test/resources/spec-tests/values/strings.wast +++ /dev/null @@ -1,136 +0,0 @@ -(component - (core module $M - (memory (export "mem") 1) - (func (export "f1") (result i32) - (i32.store (i32.const 0) (i32.const 8)) - (i32.store (i32.const 4) (i32.const 1)) - (i32.store8 (i32.const 8) (i32.const 97)) - (i32.const 0) - ) - (func (export "f2") (result i32) - (i32.store (i32.const 0) (i32.const 8)) - (i32.store (i32.const 4) (i32.const 14)) - (i64.store (i32.const 8) (i64.const 0xb8_ef_ba_98_e2_83_98_e2)) - (i32.store (i32.const 16) (i32.const 0xe3_b6_c3_8f)) - (i32.store16 (i32.const 20) (i32.const 0x84_83)) - (i32.const 0) - ) - ;; TODO: so many cases left to test, everyone feel free to fill in... - ) - (core instance $m (instantiate $M)) - (func (export "f1") (result string) (canon lift (core func $m "f1") (memory $m "mem"))) - (func (export "f2") (result string) (canon lift (core func $m "f2") (memory $m "mem"))) -) -(assert_return (invoke "f1") (str.const "a")) -(assert_return (invoke "f2") (str.const "☃☺️öツ")) - -;; empty string with ptr=0, len=0 -(component - (core module $M - (memory (export "mem") 1) - (func (export "f") (result i32) - (i32.store (i32.const 0) (i32.const 0)) - (i32.store (i32.const 4) (i32.const 0)) - (i32.const 0) - ) - ) - (core instance $m (instantiate $M)) - (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) -) -(assert_return (invoke "f") (str.const "")) - -;; empty string with non-zero in-bounds ptr, len=0 -(component - (core module $M - (memory (export "mem") 1) - (func (export "f") (result i32) - (i32.store (i32.const 0) (i32.const 100)) - (i32.store (i32.const 4) (i32.const 0)) - (i32.const 0) - ) - ) - (core instance $m (instantiate $M)) - (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) -) -(assert_return (invoke "f") (str.const "")) - -;; out-of-bounds pointer traps even with len=0 -(component - (core module $M - (memory (export "mem") 1) - (func (export "f") (result i32) - (i32.store (i32.const 0) (i32.const 0xdeadbeef)) - (i32.store (i32.const 4) (i32.const 0)) - (i32.const 0) - ) - ) - (core instance $m (instantiate $M)) - (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) -) -(assert_trap (invoke "f") "string pointer/length out of bounds of memory") - -;; invalid UTF-8: 0xFF is never valid -(component - (core module $M - (memory (export "mem") 1) - (func (export "f") (result i32) - (i32.store (i32.const 0) (i32.const 8)) - (i32.store (i32.const 4) (i32.const 1)) - (i32.store8 (i32.const 8) (i32.const 0xff)) - (i32.const 0) - ) - ) - (core instance $m (instantiate $M)) - (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) -) -(assert_trap (invoke "f") "invalid utf-8") - -;; truncated multibyte UTF-8: leading byte 0xC3 expects a continuation byte -(component - (core module $M - (memory (export "mem") 1) - (func (export "f") (result i32) - (i32.store (i32.const 0) (i32.const 8)) - (i32.store (i32.const 4) (i32.const 1)) - (i32.store8 (i32.const 8) (i32.const 0xc3)) - (i32.const 0) - ) - ) - (core instance $m (instantiate $M)) - (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) -) -(assert_trap (invoke "f") "incomplete utf-8 byte sequence") - -;; string at end of memory page boundary -(component - (core module $M - (memory (export "mem") 1) - (func (export "f") (result i32) - ;; place "ok" at the very end of the first page (65536 - 2 = 65534) - (i32.store (i32.const 0) (i32.const 65534)) - (i32.store (i32.const 4) (i32.const 2)) - (i32.store8 (i32.const 65534) (i32.const 111)) ;; 'o' - (i32.store8 (i32.const 65535) (i32.const 107)) ;; 'k' - (i32.const 0) - ) - ) - (core instance $m (instantiate $M)) - (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) -) -(assert_return (invoke "f") (str.const "ok")) - -;; string one byte past end of memory traps -(component - (core module $M - (memory (export "mem") 1) - (func (export "f") (result i32) - (i32.store (i32.const 0) (i32.const 65535)) - (i32.store (i32.const 4) (i32.const 2)) - (i32.store8 (i32.const 65535) (i32.const 111)) - (i32.const 0) - ) - ) - (core instance $m (instantiate $M)) - (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) -) -(assert_trap (invoke "f") "string pointer/length out of bounds of memory") diff --git a/src/test/resources/spec-tests/wasm-tools/adapt.wast b/src/test/resources/spec-tests/wasm-tools/adapt.wast deleted file mode 100644 index 8cc76f8..0000000 --- a/src/test/resources/spec-tests/wasm-tools/adapt.wast +++ /dev/null @@ -1,287 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component definition - (import "log" (func $log (param "msg" string))) - (core module $libc - (memory (export "memory") 1) - (func (export "canonical_abi_realloc") (param i32 i32 i32 i32) (result i32) - unreachable) - ) - - (core module $my_module - (import "env" "log-utf8" (func $log_utf8 (param i32 i32))) - (import "env" "log-utf16" (func $log_utf16 (param i32 i32))) - (import "env" "log-compact-utf16" (func $log_compact_utf16 (param i32 i32))) - - (func (export "log-utf8") (param i32 i32) - local.get 0 - local.get 1 - call $log_utf8 - ) - (func (export "log-utf16") (param i32 i32) - local.get 0 - local.get 1 - call $log_utf16 - ) - (func (export "log-compact-utf16") (param i32 i32) - local.get 0 - local.get 1 - call $log_compact_utf16 - ) - ) - - (core instance $libc (instantiate $libc)) - - (alias core export $libc "canonical_abi_realloc" (core func $realloc)) - (alias core export $libc "memory" (core memory $memory)) - (core func $log_lower_utf8 (canon lower (func $log) string-encoding=utf8 (memory $memory) (realloc $realloc))) - (core func $log_lower_utf16 (canon lower (func $log) string-encoding=utf16 (memory $memory) (realloc $realloc))) - (core func $log_lower_compact_utf16 (canon lower (func $log) string-encoding=latin1+utf16 (memory $memory) (realloc $realloc))) - - (core instance $my_instance (instantiate $my_module - (with "libc" (instance $libc)) - (with "env" (instance - (export "log-utf8" (func $log_lower_utf8)) - (export "log-utf16" (func $log_lower_utf16)) - (export "log-compact-utf16" (func $log_lower_compact_utf16)) - )) - )) - - (func (export "log1") (param "msg" string) - (canon lift - (core func $my_instance "log-utf8") - string-encoding=utf8 - (memory $memory) - (realloc $realloc) - ) - ) - (func (export "log2") (param "msg" string) - (canon lift - (core func $my_instance "log-utf16") - string-encoding=utf16 - (memory $memory) - (realloc $realloc) - ) - ) - (func (export "log3") (param "msg" string) - (canon lift - (core func $my_instance "log-compact-utf16") - string-encoding=latin1+utf16 - (memory $memory) - (realloc $realloc) - ) - ) -) - -(assert_invalid - (component - (import "i" (func $f)) - (core func (canon lower (func $f) string-encoding=utf8 string-encoding=utf16)) - ) - "canonical encoding option `utf8` conflicts with option `utf16`") - -(assert_invalid - (component - (import "i" (func $f)) - (core func (canon lower (func $f) string-encoding=utf8 string-encoding=latin1+utf16)) - ) - "canonical encoding option `utf8` conflicts with option `latin1-utf16`") - -(assert_invalid - (component - (import "i" (func $f)) - (core func (canon lower (func $f) string-encoding=utf16 string-encoding=latin1+utf16)) - ) - "canonical encoding option `utf16` conflicts with option `latin1-utf16`") - -(assert_invalid - (component - (import "i" (func $f)) - (core func (canon lower (func $f) (memory 0))) - ) - "memory index out of bounds") - -(assert_invalid - (component - (import "i" (func $f)) - (core module $m (memory (export "memory") 1)) - (core instance $i (instantiate $m)) - (core func (canon lower (func $f) (memory $i "memory") (memory $i "memory"))) - ) - "`memory` is specified more than once") - -(assert_invalid - (component - (core module $m - (func (export "f") (param i32 i32)) - ) - (core instance $i (instantiate $m)) - (func (param "p1" (list u8)) (canon lift (core func $i "f"))) - ) - "canonical option `memory` is required") - -(assert_invalid - (component - (core module $m - (memory (export "m") 1) - (func (export "f") (param i32 i32)) - ) - (core instance $i (instantiate $m)) - (func (param "p1" (list u8)) - (canon lift (core func $i "f") - (memory $i "m") - ) - ) - ) - "canonical option `realloc` is required") - -(assert_invalid - (component - (core module $m - (memory (export "m") 1) - (func (export "f") (param i32 i32)) - (func (export "r") (param i32 i32 i32 i32) (result i32)) - ) - (core instance $i (instantiate $m)) - (func (param "p1" (list u8)) - (canon lift (core func $i "f") - (memory $i "m") - (realloc (func $i "r")) - (realloc (func $i "r")) - ) - ) - ) - "canonical option `realloc` is specified more than once") - -(assert_invalid - (component - (core module $m - (memory (export "m") 1) - (func (export "f") (param i32 i32)) - (func (export "r")) - ) - (core instance $i (instantiate $m)) - (func (param "p1" (list u8)) - (canon lift (core func $i "f") - (memory $i "m") - (realloc (func $i "r")) - ) - ) - ) - "canonical option `realloc` uses a core function with an incorrect signature") - -(assert_invalid - (component - (core module $m - (memory (export "m") 1) - (func (export "f") (result i32)) - (func (export "r") (param i32 i32 i32 i32) (result i32)) - (func (export "p")) - ) - (core instance $i (instantiate $m)) - (func (result string) - (canon lift (core func $i "f") - (memory $i "m") - (realloc (func $i "r")) - (post-return (func $i "p")) - ) - ) - ) - "canonical option `post-return` uses a core function with an incorrect signature") - -(assert_invalid - (component - (core module $m - (memory (export "m") 1) - (func (export "f") (result i32)) - (func (export "r") (param i32 i32 i32 i32) (result i32)) - (func (export "p") (param i32)) - ) - (core instance $i (instantiate $m)) - (func (result string) - (canon lift (core func $i "f") - (memory $i "m") - (realloc (func $i "r")) - (post-return (func $i "p")) - (post-return (func $i "p")) - ) - ) - ) - "canonical option `post-return` is specified more than once") - -(assert_invalid - (component - (import "i" (func $f (param "p1" string))) - (core module $m - (memory (export "m") 1) - (func (export "f") (result i32)) - (func (export "r") (param i32 i32 i32 i32) (result i32)) - (func (export "p") (param i32)) - ) - (core instance $i (instantiate $m)) - (core func - (canon lower (func $f) - (memory $i "m") - (realloc (func $i "r")) - (post-return (func $i "p")) - ) - ) - ) - "canonical option `post-return` cannot be specified for lowerings") - -(component - (core module $m - (memory (export "m") 1) - (func (export "f") (result i32) unreachable) - (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable) - (func (export "p") (param i32)) - ) - (core instance $i (instantiate $m)) - (func (result string) - (canon lift (core func $i "f") - (memory $i "m") - (realloc (func $i "r")) - (post-return (func $i "p")) - ) - ) -) - -(assert_malformed - (component quote - "(core module $m (func (export \"\")))" - "(core instance $i (instantiate $m))" - "(core func (canon lower (func $i \"\")))" - ) - "unknown instance: failed to find name `$i`") - -(assert_invalid - (component - (core module $m (func (export "foo") (param i32))) - (core instance $i (instantiate $m)) - (func (export "foo") (canon lift (core func $i "foo"))) - ) - "lowered parameter types `[]` do not match parameter types `[I32]`") - -(assert_invalid - (component - (core module $m (func (export "foo") (result i32))) - (core instance $i (instantiate $m)) - (func (export "foo") (canon lift (core func $i "foo"))) - ) - "lowered result types `[]` do not match result types `[I32]`") - -(assert_invalid - (component - (type $f string) - (core module $m (func (export "foo"))) - (core instance $i (instantiate $m)) - (func (export "foo") (type $f) (canon lift (core func $i "foo"))) - ) - "not a function type") - -(assert_malformed - (component quote - "(import \"a\" (func $f))" - "(func (export \"foo\") (canon lift (core func $f)))" - ) - "unknown core func: failed to find name `$f`") diff --git a/src/test/resources/spec-tests/wasm-tools/alias.wast b/src/test/resources/spec-tests/wasm-tools/alias.wast deleted file mode 100644 index dd9d1b3..0000000 --- a/src/test/resources/spec-tests/wasm-tools/alias.wast +++ /dev/null @@ -1,301 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component - (component - (import "i" (instance $i - (export "f1" (func)) - (export "f2" (func (param "p1" string))) - )) - (export "run" (func $i "f1")) - ) -) - -(component - (component - (import "i" (component $c - (export "f1" (func)) - (export "f2" (func (param "p1" string))) - )) - (instance $i (instantiate $c)) - (export "run" (func $i "f1")) - ) -) - -(component definition - (import "i" (core module $m - (export "f1" (func $f1)) - (export "f2" (func $f2 (param i32))) - )) - (core instance $i (instantiate $m)) - - (core module $m2 (import "" "" (func))) - - (core instance (instantiate $m2 (with "" (instance (export "" (func $i "f1")))))) -) - -(component definition - (import "a" (core module $libc - (export "memory" (memory 1)) - (export "table" (table 0 funcref)) - (export "func" (func)) - (export "global" (global i32)) - (export "global mut" (global (mut i64))) - )) - (core instance $libc (instantiate $libc)) - (alias core export $libc "memory" (core memory $mem)) - (alias core export $libc "table" (core table $tbl)) - (alias core export $libc "func" (core func $func)) - (alias core export $libc "global" (core global $global)) - (alias core export $libc "global mut" (core global $global_mut)) - - (import "x" (core module $needs_libc - (import "" "memory" (memory 1)) - (import "" "table" (table 0 funcref)) - (import "" "func" (func)) - (import "" "global" (global i32)) - (import "" "global mut" (global (mut i64))) - )) - - (core instance (instantiate $needs_libc (with "" (instance - (export "memory" (memory $mem)) - (export "table" (table $tbl)) - (export "func" (func $func)) - (export "global" (global $global)) - (export "global mut" (global $global_mut)) - )))) -) - -(component - (component - (import "a" (instance $i - (export "a" (func)) - (export "b" (core module)) - (export "c" (instance)) - )) - (export "b" (func $i "a")) - (export "c" (core module $i "b")) - (export "d" (instance $i "c")) - ) -) - - -(component definition - (import "a" (core module $libc - (export "memory" (memory 1)) - (export "table" (table 0 funcref)) - (export "func" (func)) - (export "global" (global i32)) - (export "global mut" (global (mut i64))) - )) - - (import "b" (core module $needs_libc - (import "" "memory" (memory 1)) - (import "" "table" (table 0 funcref)) - (import "" "func" (func)) - (import "" "global" (global i32)) - (import "" "global mut" (global (mut i64))) - )) - - (core instance $libc (instantiate $libc)) - (core instance (instantiate $needs_libc (with "" (instance - (export "memory" (memory $libc "memory")) - (export "table" (table $libc "table")) - (export "func" (func $libc "func")) - (export "global" (global $libc "global")) - (export "global mut" (global $libc "global mut")) - )))) -) - -(assert_invalid - (component - (import "a" (instance (export "a" (func)))) - (export "a" (core module 0 "a")) - ) - "export `a` for instance 0 is not a module") - -(assert_invalid - (component - (component - (component (export "a")) - ) - (instance (instantiate 0)) - (export "a" (core module 0 "a")) - ) - "export `a` for instance 0 is not a module") - -(assert_invalid - (component - (import "a" (core module)) - (core instance (instantiate 0)) - (alias core export 0 "a" (core func)) - ) - "core instance 0 has no export named `a`") - -(assert_invalid - (component - (core module) - (core instance (instantiate 0)) - (alias core export 0 "a" (core func)) - ) - "core instance 0 has no export named `a`") - -(assert_invalid - (component - (import "a" (component)) - (instance (instantiate 0)) - (alias export 0 "a" (func)) - ) - "instance 0 has no export named `a`") - -(assert_invalid - (component - (import "a" (core module $a (export "" (func)))) - (import "b" (core module $b (import "" "" (func (param i32))))) - - (core instance $a (instantiate $a)) - (core instance $b (instantiate $b (with "" (instance $a)))) - ) - "type mismatch") - -;; aliasing various items works - -(component $PARENT - (type $t (func (result string))) - (component - (import "a" (func (type $t))) - ) - (component - (alias outer $PARENT $t (type $my_type)) - (alias outer 0 $my_type (type $my_type_again)) - (import "a" (func (type $my_type_again))) - ) -) - -(component - (type $a (func (result string))) - (component - (type $b (func (result u32))) - (component - (type $c (func (result s32))) - - (component - (import "a" (func $a (type $a))) - (import "b" (func $b (type $b))) - (import "c" (func $c (type $c))) - - (import "d" (component $C - (import "a" (func (result string))) - (import "b" (func (result u32))) - (import "c" (func (result s32))) - )) - - (instance (instantiate $C - (with "a" (func $a)) - (with "b" (func $b)) - (with "c" (func $c)) - )) - ) - ) - ) -) - -;; multiple projections in alias sugar -(component - (component $a - (import "a" (instance $a - (export "a" (instance - (export "a" (instance - (export "a" (instance - (export "a" (func)) - )) - )) - )) - )) - - (import "b" (component $b (import "a" (func)))) - - (instance (instantiate $b - (with "a" (func $a "a" "a" "a" "a")) - )) - ) -) - -;; alias some constructs -(component - (component - (import "a" (instance $foo (export "v" (component)))) - (export "v" (component $foo "v")) - ) -) - -(component definition - (import "a" (instance $foo (export "v" (core module)))) - (export "v" (core module $foo "v")) -) - -(component $C - (core type $t (func)) - (component $C2 - (alias outer $C $t (core type $t2)) - (component - (alias outer $C $t (core type)) - (alias outer $C2 $t2 (core type)) - ) - ) -) - -(component $C - (core module $m) - (alias outer $C $m (core module $target)) - (export "v" (core module $target)) -) - -(component - (component $C - (component $m) - (alias outer $C $m (component $target)) - (export "v" (component $target)) - ) -) - -(assert_invalid - (component (alias outer 100 0 (core type))) - "invalid outer alias count of 100") - -(assert_invalid - (component (alias outer 0 0 (core type))) - "index out of bounds") - -(assert_invalid - (component (alias outer 100 0 (core module))) - "invalid outer alias count of 100") - -(assert_invalid - (component (alias outer 0 0 (core module))) - "index out of bounds") - -(assert_invalid - (component (alias outer 100 0 (component))) - "invalid outer alias count of 100") - -(assert_invalid - (component (alias outer 0 0 (component))) - "index out of bounds") - -(component definition - (import "a" (instance $i - (export "x" (core module)) - )) - ;; inline alias injection sugar works for module references - (core instance (instantiate (module $i "x"))) -) - -(component - (component - (import "a" (instance $i - (export "x" (component)) - )) - ;; inline alias injection sugar works for component references - (instance (instantiate (component $i "x"))) - ) -) diff --git a/src/test/resources/spec-tests/wasm-tools/big.wast b/src/test/resources/spec-tests/wasm-tools/big.wast deleted file mode 100644 index 770df0a..0000000 --- a/src/test/resources/spec-tests/wasm-tools/big.wast +++ /dev/null @@ -1,36 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component definition - (import "wasi-logging" (instance $logging - (export "log" (func (param "msg" string))) - )) - (import "libc" (core module $Libc - (export "memory" (memory 1)) - (export "realloc" (func (param i32 i32 i32 i32) (result i32))) - )) - (core instance $libc (instantiate $Libc)) - (core func $log (canon lower - (func $logging "log") - (memory $libc "memory") (realloc (func $libc "realloc")) - )) - (core module $Main - (import "libc" "memory" (memory 1)) - (import "libc" "realloc" (func (param i32 i32 i32 i32) (result i32))) - (import "wasi-logging" "log" (func $log (param i32 i32))) - (func (export "run") (param i32 i32) (result i32) - (local.get 0) - (local.get 1) - (call $log) - (unreachable) - ) - ) - (core instance $main (instantiate $Main - (with "libc" (instance $libc)) - (with "wasi-logging" (instance (export "log" (func $log)))) - )) - (func $run (param "in" string) (result string) (canon lift - (core func $main "run") - (memory $libc "memory") (realloc (func $libc "realloc")) - )) - (export "run" (func $run)) -) diff --git a/src/test/resources/spec-tests/wasm-tools/definedtypes.wast b/src/test/resources/spec-tests/wasm-tools/definedtypes.wast deleted file mode 100644 index ca24c12..0000000 --- a/src/test/resources/spec-tests/wasm-tools/definedtypes.wast +++ /dev/null @@ -1,123 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component $C - (type $A1 bool) - (type $A2 u8) - (type $A3 s8) - (type $A4 u16) - (type $A5 s16) - (type $A6 u32) - (type $A7 s32) - (type $A8 u64) - (type $A9 s64) - (type $A10a f32) - (type $A11a f64) - (type $A10b float32) - (type $A11b float64) - (type $A12 char) - (type $A13 string) - - (type $A14b (record (field "x" (tuple char)))) - (type $A14c (record (field "x" $A1))) - - (type $A15a (variant (case "x"))) - (type $A15b (variant (case "x" $A1))) - (type $A15c (variant (case $x "x") (case $y "y" string) (case "z" string))) - (type $A15d (variant (case "x") (case "y" string) (case "z" string))) - - (type $A16a (list (tuple u8))) - (type $A16b (list $A3)) - - (type $A17a (tuple u8)) - (type $A17b (tuple $A4)) - - (type $A18b (flags "x")) - - (type $A19b (enum "x")) - - (type $A21a (option (tuple u32))) - (type $A21b (option $A6)) - - (type $A22a (result)) - (type $A22b (result $A7)) - (type $A22c (result (error $A8))) - (type $A22d (result $A9 (error $A10a))) -) - -(assert_malformed - (component quote - "(type $t string)" - "(type $v (variant (case $x \"x\" $t) (case $x \"y\" $t)))" - ) - "duplicate variant case identifier" -) - -(assert_invalid - (component - (type $t (func)) - (type (func (param "t" $t))) - ) - "type index 0 is not a defined type") - -(assert_invalid - (component - (type $t (instance)) - (type (func (result $t))) - ) - "type index 0 is not a defined type") - -(assert_invalid - (component - (type $t (component)) - (type (option $t)) - ) - "type index 0 is not a defined type") - -(assert_invalid - (component (type (option 0))) - "index out of bounds") -(assert_invalid - (component (type (list 0))) - "index out of bounds") -(assert_invalid - (component (type (record (field "x" 0)))) - "index out of bounds") -(assert_invalid - (component (type (variant (case "x" 0)))) - "index out of bounds") -(assert_invalid - (component (type (result 0 (error 1)))) - "index out of bounds") -(assert_invalid - (component (type (tuple 0))) - "index out of bounds") - -(assert_invalid - (component (type (record (field "a-B-c-D" string) (field "A-b-C-d" u8)))) - "record field name `A-b-C-d` conflicts with previous field name `a-B-c-D`") -(assert_invalid - (component (type (variant (case "x" s64) (case "x" s64)))) - "variant case name `x` conflicts with previous case name `x`") -(assert_invalid - (component (type (flags "x" "y" "X"))) - "flag name `X` conflicts with previous flag name `x`") -(assert_invalid - (component (type (enum "x" "y" "X"))) - "enum tag name `X` conflicts with previous tag name `x`") - -(assert_invalid - (component (type (record (field "" s32)))) - "name cannot be empty") -(assert_invalid - (component (type (variant (case "" s32)))) - "name cannot be empty") -(assert_invalid - (component (type (flags ""))) - "name cannot be empty") -(assert_invalid - (component (type (enum ""))) - "name cannot be empty") - -(assert_invalid - (component (type (variant))) - "variant type must have at least one case") diff --git a/src/test/resources/spec-tests/wasm-tools/empty.wast b/src/test/resources/spec-tests/wasm-tools/empty.wast deleted file mode 100644 index 7f22181..0000000 --- a/src/test/resources/spec-tests/wasm-tools/empty.wast +++ /dev/null @@ -1,4 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -;; The most minimal component. -(component) diff --git a/src/test/resources/spec-tests/wasm-tools/example.wast b/src/test/resources/spec-tests/wasm-tools/example.wast deleted file mode 100644 index 9ba429f..0000000 --- a/src/test/resources/spec-tests/wasm-tools/example.wast +++ /dev/null @@ -1,17 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -;; With what's defined so far, we can define the following component: - -(component - (component - (core module (func (export "one") (result i32) (i32.const 1))) - (core module (func (export "two") (result f32) (f32.const 2))) - ) - (core module (func (export "three") (result i64) (i64.const 3))) - (component - (component - (core module (func (export "four") (result f64) (f64.const 4))) - ) - ) - (component) -) diff --git a/src/test/resources/spec-tests/wasm-tools/export-ascription.wast b/src/test/resources/spec-tests/wasm-tools/export-ascription.wast deleted file mode 100644 index ca70736..0000000 --- a/src/test/resources/spec-tests/wasm-tools/export-ascription.wast +++ /dev/null @@ -1,44 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component - (component - (import "f" (func $f)) - (export "f2" (func $f) (func)) - ) -) - -;; subtyping works -(component - (component - (import "f" (instance $i (export "f" (func)))) - (export "f2" (instance $i) (instance)) - ) -) - -;; make sure subtyping works in the right direction -(assert_invalid - (component - (import "f" (instance $i)) - (export "f2" (instance $i) (instance (export "f" (func)))) - ) - "ascribed type of export is not compatible") - -;; make sure the type is actually changed -(assert_invalid - (component - (import "f" (func $f)) - - (component $c - (import "f" (instance $i (export "f" (func)))) - (export "f2" (instance $i) (instance)) - ) - - (instance $c (instantiate $c (with "f" (instance (export "f" (func $f)))))) - - (component $consume - (import "arg" (instance $i (export "f" (func)))) - ) - - (instance (instantiate $consume (with "arg" (instance $c "f2")))) - ) - "missing expected export `f`") diff --git a/src/test/resources/spec-tests/wasm-tools/export-introduces-alias.wast b/src/test/resources/spec-tests/wasm-tools/export-introduces-alias.wast deleted file mode 100644 index 40d33ef..0000000 --- a/src/test/resources/spec-tests/wasm-tools/export-introduces-alias.wast +++ /dev/null @@ -1,48 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component - (component - (import "x" (func $f)) - - (export $g "g" (func $f)) - (export $g2 "g2" (func $g)) - ) -) - -(component - (type (component - (type $t u8) - (import "x" (instance $i (export "t" (type (eq $t))))) - (alias export $i "t" (type $my-t)) - )) -) - -(component - (type (component - (type $t u8) - (import "x" (instance $i - (export "i" (instance - (export "t" (type (eq $t))) - )) - )) - (alias export $i "i" (instance $my-i)) - (alias export $my-i "t" (type $my-t)) - )) -) - -(assert_malformed - (component quote - "(type (instance" - "(type $t u8)" - "(export \"t\" (type $t (eq $t)))" - "))" - ) - "duplicate type identifier") - -(component - (type (instance - (type $t u8) - (export "t" (type $t2 (eq $t))) - (export "t2" (type $t3 (eq $t2))) - )) -) diff --git a/src/test/resources/spec-tests/wasm-tools/export.wast b/src/test/resources/spec-tests/wasm-tools/export.wast deleted file mode 100644 index 73d094c..0000000 --- a/src/test/resources/spec-tests/wasm-tools/export.wast +++ /dev/null @@ -1,63 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_invalid - (component (export "" (instance 0))) - "index out of bounds") - -(assert_invalid - (component (export "" (component 0))) - "index out of bounds") - -(assert_invalid - (component (export "" (core module 0))) - "index out of bounds") - -(assert_invalid - (component (export "" (func 0))) - "index out of bounds") - -(component - (component - (import "a" (instance $i)) - (import "b" (core module $m)) - (import "c" (component $c)) - (import "e" (func $f)) - - (export "f" (instance $i)) - (export "g" (core module $m)) - (export "h" (component $c)) - (export "j" (func $f)) - ) -) - -(component - (component - (import "a" (func)) - (export (interface "wasi:http/types@2.0.0") (func 0)) - ) -) - -;; import/exports can overlap on ids -(component - (component - (import (interface "wasi:http/types@2.0.0") (func)) - (export (interface "wasi:http/types@2.0.0") (func 0)) - ) -) - -;; cannot export some types of strings -(assert_invalid - (component (type (component (export "integrity=" (func))))) - "not a valid export name") -(assert_invalid - (component (type (component (export "url=" (func))))) - "not a valid export name") -(assert_invalid - (component (type (component (export "relative-url=" (func))))) - "not a valid extern name") -(assert_invalid - (component (type (component (export "locked-dep=" (func))))) - "not a valid export name") -(assert_invalid - (component (type (component (export "unlocked-dep=" (func))))) - "not a valid export name") diff --git a/src/test/resources/spec-tests/wasm-tools/func.wast b/src/test/resources/spec-tests/wasm-tools/func.wast deleted file mode 100644 index 4a207f9..0000000 --- a/src/test/resources/spec-tests/wasm-tools/func.wast +++ /dev/null @@ -1,146 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component definition - (import "a" (func (param "foo" string))) - (import "b" (func (param "foo" string) (param "bar" s32) (param "baz" u32))) - (import "c" (func (result (tuple u8)))) -) - -(component definition - (import "a" (func)) - (import "b" (func (param "p1" string))) - (import "c" (func (result u32))) - (import "d" (func (param "p1" bool) (result string))) -) - - -(assert_invalid - (component - (type (func (param "foo" string) (param "FOO" u32))) - ) - "function parameter name `FOO` conflicts with previous parameter name `foo`" -) - -(assert_invalid - (component - (core module $m - (memory (export "memory") 1) - (func (export "foo") (result i32) unreachable) - ) - (core instance $i (instantiate $m)) - - (func (export "tuple") (result (tuple s8 u8)) - (canon lift (core func $i "foo")) - ) - ) - "canonical option `memory` is required" -) - -(component definition - (import "a" (func $log (param "msg" string))) - (core module $libc - (memory (export "memory") 1) - ) - (core instance $libc (instantiate $libc)) - (core func (canon lower (func $log) (memory $libc "memory"))) -) - -(component - (core module $m - (memory (export "memory") 1) - (func (export "ret-list") (result i32) unreachable) - ) - (core instance $i (instantiate $m)) - - (func (export "ret-list") (result (list u8)) - (canon lift (core func $i "ret-list") (memory $i "memory")) - ) -) - -(component - (type $big (func - (param "p1" u32) (param "p2" u32) (param "p3" u32) (param "p4" u32) (param "p5" u32) - (param "p6" u32) (param "p7" u32) (param "p8" u32) (param "p9" u32) (param "p10" u32) - (param "p11" u32) (param "p12" u32) (param "p13" u32) (param "p14" u32) (param "p15" u32) - (param "p16" u32) (param "p17" u32) (param "p18" u32) (param "p19" u32) (param "p20" u32) - )) - - (component $c - (import "big" (func $big (type $big))) - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core func $big (canon lower (func $big) (memory $libc "memory"))) - ) -) - -(assert_invalid - (component - (core module $m - (memory (export "memory") 1) - (func (export "roundtrip") (param i32)) - ) - (core instance $m (instantiate $m)) - - (type $roundtrip (func - (param "p1" u32) (param "p2" u32) (param "p3" u32) (param "p4" u32) (param "p5" u32) - (param "p6" u32) (param "p7" u32) (param "p8" u32) (param "p9" u32) (param "p10" u32) - (param "p11" u32) (param "p12" u32) (param "p13" u32) (param "p14" u32) (param "p15" u32) - (param "p16" u32) (param "p17" u32) (param "p18" u32) (param "p19" u32) (param "p20" u32) - )) - - (func $roundtrip (type $roundtrip) - (canon lift (core func $m "roundtrip") (memory $m "memory")) - ) - (export "roundtrip" (func $roundtrip)) - ) - "canonical option `realloc` is required" -) - -(assert_invalid - (component - (import "a" (func $log (result string))) - (core module $libc - (memory (export "memory") 1) - ) - (core instance $libc (instantiate $libc)) - (core func (canon lower (func $log) (memory $libc "memory"))) - ) - "canonical option `realloc` is required" -) - -(assert_invalid - (component - (core module $m - (memory (export "memory") 1) - (func (export "param-list") (param i32 i32) unreachable) - ) - (core instance $i (instantiate $m)) - - (func (export "param-list") (param "bytes" (list u8)) - (canon lift (core func $i "param-list") (memory $i "memory")) - ) - ) - "canonical option `realloc` is required" -) - -(assert_malformed - (component binary - "\00asm" "\0d\00\01\00" ;; component header - "\07\05" ;; component type section, 5 bytes - "\01" ;; 1 count - "\40" ;; component function type - "\00" ;; 0 parameters - "\01\01" ;; invalid result encoding - ) - "invalid leading byte (0x1) for number of results") - -(assert_malformed - (component binary - "\00asm" "\0d\00\01\00" ;; component header - "\07\05" ;; component type section, 5 bytes - "\01" ;; 1 count - "\40" ;; component function type - "\00" ;; 0 parameters - "\02\00" ;; invalid result encoding - ) - "invalid leading byte (0x2) for component function results") diff --git a/src/test/resources/spec-tests/wasm-tools/import.wast b/src/test/resources/spec-tests/wasm-tools/import.wast deleted file mode 100644 index b226157..0000000 --- a/src/test/resources/spec-tests/wasm-tools/import.wast +++ /dev/null @@ -1,359 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component - (component - (import "a" (func)) - (import "b" (instance)) - (import "c" (instance - (export "a" (func)) - )) - (import "d" (component - (import "a" (core module)) - (export "b" (func)) - )) - (type $t (func)) - (import "e" (type (eq $t))) - ) -) - -(assert_invalid - (component - (type $f (func)) - (import "a" (instance (type $f))) - ) - "type index 0 is not an instance type") - -(assert_invalid - (component - (core type $f (func)) - (import "a" (core module (type $f))) - ) - "core type index 0 is not a module type") - -(assert_invalid - (component - (type $f string) - (import "a" (func (type $f))) - ) - "type index 0 is not a function type") - -;; Disallow duplicate imports for core wasm modules -(assert_invalid - (component - (core type (module - (import "" "" (func)) - (import "" "" (func)) - )) - ) - "duplicate import name `:`") -(assert_invalid - (component - (core module - (import "" "" (func)) - (import "" "" (func)) - ) - ) - "duplicate import name `:`") -(assert_invalid - (component - (core type (module - (import "" "a" (func)) - (import "" "a" (func)) - )) - ) - "duplicate import name `:a`") -(assert_invalid - (component - (core module - (import "" "a" (func)) - (import "" "a" (func)) - ) - ) - "duplicate import name `:a`") - -(assert_invalid - (component - (import "a" (func)) - (import "a" (func)) - ) - "import name `a` conflicts with previous name `a`") - -(assert_invalid - (component - (type (component - (import "a" (func)) - (import "a" (func)) - )) - ) - "import name `a` conflicts with previous name `a`") - -(assert_invalid - (component - (import "a" (func (type 100))) - ) - "type index out of bounds") - -(assert_invalid - (component - (core module $m (func (export ""))) - (core instance $i (instantiate $m)) - (func (type 100) (canon lift (core func $i ""))) - ) - "type index out of bounds") - -(component definition - (import "wasi:http/types" (func)) - (import "wasi:http/types@1.0.0" (func)) - (import "wasi:http/types@2.0.0" (func)) - (import "a-b:c-d/e-f@123456.7890.488" (func)) - (import "a:b/c@1.2.3" (func)) - (import "a:b/c@0.0.0" (func)) - (import "a:b/c@0.0.0+abcd" (func)) - (import "a:b/c@0.0.0+abcd-efg" (func)) - (import "a:b/c@0.0.0-abcd+efg" (func)) - (import "a:b/c@0.0.0-abcd.1.2+efg.4.ee.5" (func)) -) - -(assert_invalid - (component - (import "wasi:http/types" (func)) - (import "wasi:http/types" (func)) - ) - "conflicts with previous name") - -(assert_invalid - (component (import "" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "wasi:" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "wasi:/" (func))) - "not in kebab case") -(assert_invalid - (component (import ":/" (func))) - "not in kebab case") -(assert_invalid - (component (import "wasi/http" (func))) - "`wasi/http` is not in kebab case") -(assert_invalid - (component (import "wasi:http/TyPeS" (func))) - "`TyPeS` is not in kebab case") -(assert_invalid - (component (import "WaSi:http/types" (func))) - "`WaSi` is not in kebab case") -(assert_invalid - (component (import "wasi:HtTp/types" (func))) - "`HtTp` is not in kebab case") -(assert_invalid - (component (import "wasi:http/types@" (func))) - "empty string") -(assert_invalid - (component (import "wasi:http/types@." (func))) - "unexpected character '.'") -(assert_invalid - (component (import "wasi:http/types@1." (func))) - "unexpected end of input") -(assert_invalid - (component (import "wasi:http/types@a.2" (func))) - "unexpected character 'a'") -(assert_invalid - (component (import "wasi:http/types@2.b" (func))) - "unexpected character 'b'") -(assert_invalid - (component (import "wasi:http/types@2.0x0" (func))) - "unexpected character 'x'") -(assert_invalid - (component (import "wasi:http/types@2.0.0+" (func))) - "empty identifier segment") -(assert_invalid - (component (import "wasi:http/types@2.0.0-" (func))) - "empty identifier segment") -(assert_invalid - (component (import "foo:bar:baz/qux" (func))) - "expected `/` after package name") -(assert_invalid - (component (import "foo:bar/baz/qux" (func))) - "trailing characters found: `/qux`") - -(component - (component - (import "a" (func $a)) - (export "a" (func $a)) - ) -) - -(component definition - (import "unlocked-dep=" (func)) - (import "unlocked-dep=" (func)) - (import "unlocked-dep==1.2.3}>" (func)) - (import "unlocked-dep==1.2.3-rc}>" (func)) - (import "unlocked-dep=" (func)) - (import "unlocked-dep=" (func)) - (import "unlocked-dep==1.2.3 <1.2.3}>" (func)) - (import "unlocked-dep==1.2.3-rc <1.2.3}>" (func)) -) - -(assert_invalid - (component (import "unlocked-dep=" (func))) - "expected `<` at ``") -(assert_invalid - (component (import "unlocked-dep=<" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "unlocked-dep=<>" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "unlocked-dep=<:>" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "unlocked-dep=" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "unlocked-dep=<:a>" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "unlocked-dep=" (func))) - "expected `{` at `>`") -(assert_invalid - (component (import "unlocked-dep=" (func))) - "expected `>=` or `<` at start of version range") -(assert_invalid - (component (import "unlocked-dep=" (func))) - "`xyz` is not a valid semver") -(assert_invalid - (component (import "unlocked-dep==2.3.4}>" (func))) - "`1.2.3 >=2.3.4` is not a valid semver") - -(component definition - (import "locked-dep=" (func)) - (import "locked-dep=" (func)) - (import "locked-dep=,integrity=" (func)) - (import "locked-dep=,integrity=" (func)) -) - -(assert_invalid - (component (import "locked-dep=" (func))) - "expected `<` at ``") -(assert_invalid - (component (import "locked-dep=<" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "locked-dep=<:" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "locked-dep=<:>" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "locked-dep=" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "locked-dep=<:a>" (func))) - "`` is not in kebab case") -(assert_invalid - (component (import "locked-dep=` at ``") -(assert_invalid - (component (import "locked-dep=" (func))) - "is not a valid semver") -(assert_invalid - (component (import "locked-dep=` at ``") -(assert_invalid - (component (import "locked-dep=," (func))) - "expected `integrity=<`") -(assert_invalid - (component (import "locked-dep=x" (func))) - "trailing characters found: `x`") - -(component definition - (import "url=<>" (func)) - (import "url=" (func)) - (import "url=,integrity=" (func)) -) - -(assert_invalid - (component (import "url=" (func))) - "expected `<` at ``") -(assert_invalid - (component (import "url=<" (func))) - "failed to find `>`") -(assert_invalid - (component (import "url=<<>" (func))) - "url cannot contain `<`") - -(assert_invalid - (component - (import "relative-url=<>" (func)) - (import "relative-url=" (func)) - (import "relative-url=,integrity=" (func)) - ) - "not a valid extern name") - -(assert_invalid - (component (import "relative-url=" (func))) - "not a valid extern name") -(assert_invalid - (component (import "relative-url=<" (func))) - "not a valid extern name") -(assert_invalid - (component (import "relative-url=<<>" (func))) - "not a valid extern name") - -(component definition - (import "integrity=" (func)) - (import "integrity=" (func)) - (import "integrity=" (func)) - (import "integrity=" (func)) - (import "integrity=< sha512-a sha256-b >" (func)) - (import "integrity=< sha512-a?abcd >" (func)) - (import "integrity=" (func)) - (import "integrity=" (func)) - (import "integrity=" (func)) - (import "integrity=" (func)) -) -(assert_invalid - (component (import "integrity=<>" (func))) - "integrity hash cannot be empty") -(assert_invalid - (component (import "integrity=" (func))) - "expected `-` after hash algorithm") -(assert_invalid - (component (import "integrity=" (func))) - "not valid base64") -(assert_invalid - (component (import "integrity=" (func))) - "not valid base64") -(assert_invalid - (component (import "integrity=" (func))) - "not valid base64") -(assert_invalid - (component (import "integrity=" (func))) - "not valid base64") -(assert_invalid - (component (import "integrity=" (func))) - "not valid base64") -(assert_invalid - (component (import "integrity=" (func))) - "unrecognized hash algorithm") - -;; Prior to WebAssembly/component-model#263 this was a valid component. -;; Specifically the 0x01 prefix byte on the import was valid. Nowadays that's -;; not valid in the spec but it's accepted for backwards compatibility. This -;; tests is here to ensure such compatibility. In the future this test should -;; be changed to `(assert_invalid ...)` -(component definition binary - "\00asm" "\0d\00\01\00" ;; component header - - "\07\05" ;; type section, 5 bytes large - "\01" ;; 1 count - "\40" ;; function - "\00" ;; parameters, 0 count - "\01\00" ;; results, named, 0 count - - "\0a\06" ;; import section, 6 bytes large - "\01" ;; 1 count - "\01" ;; prefix byte of 0x01 (invalid by the spec nowadays) - "\01a" ;; name = "a" - "\01\00" ;; type = func ($type 0) -) diff --git a/src/test/resources/spec-tests/wasm-tools/imports-exports.wast b/src/test/resources/spec-tests/wasm-tools/imports-exports.wast deleted file mode 100644 index e650c8c..0000000 --- a/src/test/resources/spec-tests/wasm-tools/imports-exports.wast +++ /dev/null @@ -1,26 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -;; With what's defined so far, we can define a component that imports, links and exports other components: - -(component - (component - (import "c" (instance $c - (export "f" (func (result string))) - )) - (import "d" (component $D - (import "c" (instance $c - (export "f" (func (result string))) - )) - (export "g" (func (result string))) - )) - (instance $d1 (instantiate $D - (with "c" (instance $c)) - )) - (instance $d2 (instantiate $D - (with "c" (instance - (export "f" (func $d1 "g")) - )) - )) - (export "d2" (instance $d2)) - ) -) diff --git a/src/test/resources/spec-tests/wasm-tools/inline-exports.wast b/src/test/resources/spec-tests/wasm-tools/inline-exports.wast deleted file mode 100644 index 2c3ff56..0000000 --- a/src/test/resources/spec-tests/wasm-tools/inline-exports.wast +++ /dev/null @@ -1,9 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component - (type (export "foo") u8) -) - -(assert_malformed - (component quote "(type (component (type (export \"\") (func))))") - "unexpected token") diff --git a/src/test/resources/spec-tests/wasm-tools/instance-type.wast b/src/test/resources/spec-tests/wasm-tools/instance-type.wast deleted file mode 100644 index 2f4b140..0000000 --- a/src/test/resources/spec-tests/wasm-tools/instance-type.wast +++ /dev/null @@ -1,234 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -;; instances -(component - (type (instance)) - - (type $foo (func)) - - (type $t (func (result string))) - - (core type (module - (type $local_type (func)) - ;; functions - (export "a" (func)) - (export "b" (func $foo)) - (export "c" (func)) - (export "d" (func $foo)) - (export "e" (func (type $local_type))) - (export "f" (func (param i32))) - (export "g" (func (param i32) (result i32 i64))) - (export "h" (func (type $local_type) (result i32))) - - ;; globals - (export "i" (global i32)) - (export "j" (global $foo i32)) - (export "k" (global (mut i32))) - - ;; tables - (export "l" (table 1 funcref)) - (export "m" (table $foo 1 funcref)) - - ;; memory - (export "n" (memory 1)) - (export "o" (memory $foo 1)) - (export "p" (memory 1 2)) - (export "q" (memory 1 2 shared)) - )) - - (type $outer (instance - (type $local_type (func)) - ;; functions - (export "a" (func)) - (export "a2" (func (type $local_type))) - (export "b" (func)) - (export "c" (func)) - (export "d" (func)) - (export "e" (func (type $t))) - (export "f" (func (param "f" string))) - (export "g" (func (param "g" s32) (result u32))) - (export "h" (func (type $t))) - - ;; components - (type $component_type (component)) - (export "c1" (component)) - (export "c2" (component (import "i1" (func)))) - (export "c3" (component (export "e1" (func)))) - (export "c4" (component (type $component_type))) - (export "c5" (component - (type $nested_func_type (func)) - (alias outer $outer $local_type (type $my_type)) - (import "i1" (func (type $nested_func_type))) - (import "i2" (component)) - (export "e1" (func (type $my_type))) - (export "e2" (component)) - )) - )) -) - -;; expand inline types -(component - (type (instance (export "a" (instance)))) -) - -;; reference outer types -(component - (type (instance - (type $t (instance)) - (export "a" (instance (type $t))) - )) - (type $x (instance)) - (type (instance (export "a" (instance (type $x))))) -) - -;; recursive -(component - (type (instance (export "a" (core module - (type $functype (func)) - - (export "a" (func)) - (export "b" (func (type 0))) - (export "c" (func (param i32))) - (export "d" (func (type $functype))) - - ;; globals - (export "e" (global i32)) - (export "f" (global (mut i32))) - - ;; tables - (export "g" (table 1 funcref)) - - ;; memory - (export "h" (memory 1)) - (export "i" (memory 1 2)) - (export "j" (memory 1 2 shared)) - )))) -) - -;; modules -(component - (core type (module)) - - (core type $foo (module)) - - (type $empty (func)) - (type $i (instance)) - - (core type (module - (type $empty (func)) - (import "" "a" (func)) - (import "" "b" (func (type $empty))) - (import "" "c" (func (param i32))) - (import "" "d" (func (param i32) (result i32))) - - (import "" "e" (global i32)) - (import "" "f" (memory 1)) - (import "" "g" (table 1 funcref)) - - (export "a" (func)) - (export "b" (global i32)) - (export "c" (memory 1)) - (export "d" (table 1 funcref)) - - (export "e" (func (type $empty))) - (export "f" (func (param i32))) - )) - - (type (component - (import "a" (func)) - (import "b" (func (type $empty))) - (import "c" (func (param "c" s32))) - (import "d" (func (param "d" s32) (result s32))) - - (import "h" (instance)) - (import "i" (instance (type $i))) - (import "j" (instance - (export "a" (func)) - (export "b" (func (type $empty))) - (export "c" (func (param "c" s32))) - )) - - (import "k" (core module)) - (import "l" (core module - (type $empty (func)) - (import "" "a" (func (type $empty))) - (import "" "b" (func (param i32))) - (export "a" (func (type $empty))) - (export "b" (func (param i32))) - )) - - (export "m" (func)) - (export "n" (func (type $empty))) - (export "o" (func (param "f" s32))) - - (export "p" (instance - (export "a" (func)) - (export "b" (func (type $empty))) - (export "c" (func (param "c" s32))) - )) - - (export "q" (core module - (type $empty (func)) - (import "" "a" (func (type $empty))) - (import "" "b" (func (param i32))) - (export "a" (func (type $empty))) - (export "b" (func (param i32))) - )) - )) -) - -(assert_invalid - (component - (type (instance - (export "a" (func)) - (export "a" (func))))) - "export name `a` conflicts with previous name `a`") - -(assert_invalid - (component - (type $t (func)) - (type (instance - (export "a" (instance (type $t))) - ))) - "type index 0 is not an instance type") - -(assert_invalid - (component - (core type $t (func)) - (type (instance - (export "a" (core module (type $t))) - ))) - "core type index 0 is not a module type") - -(assert_malformed - (component quote - "(type $t (func))" - "(type (instance (export \"a\" (core module (type $t)))))" - ) - "unknown core type") - -(assert_invalid - (component - (type $t (record (field "a" string))) - (type (instance - (export "a" (func (type $t))) - ))) - "type index 0 is not a function type") - -(assert_invalid - (component - (type $t (instance)) - (type (instance - (export "a" (func (type $t))) - ))) - "type index 0 is not a function type") - -(assert_invalid - (component - (type $t (instance)) - (type (instance - (export "a" (instance - (export "a" (func (type $t))) - )) - ))) - "type index 0 is not a function type") diff --git a/src/test/resources/spec-tests/wasm-tools/instantiate.wast b/src/test/resources/spec-tests/wasm-tools/instantiate.wast deleted file mode 100644 index cb99239..0000000 --- a/src/test/resources/spec-tests/wasm-tools/instantiate.wast +++ /dev/null @@ -1,976 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component definition - (import "a" (core module $m)) - (core instance $a (instantiate $m)) -) - -(component - (component - (import "a" (func $i)) - (import "b" (component $c (import "a" (func)))) - (instance (instantiate $c (with "a" (func $i)))) - ) -) - -(component - (component - (import "a" (component $i)) - (import "b" (component $c (import "a" (component)))) - (instance (instantiate $c (with "a" (component $i)))) - ) -) - -(component - (component - (import "a" (core module $i)) - (import "b" (component $c (import "a" (core module)))) - (instance (instantiate $c (with "a" (core module $i)))) - ) -) - -(component - (component - (import "a" (instance $i)) - (import "b" (component $c (import "a" (instance)))) - (instance (instantiate $c (with "a" (instance $i)))) - ) -) - -(component definition - (import "a" (core module $m - (import "" "a" (func)) - (import "" "b" (global i32)) - (import "" "c" (table 1 funcref)) - (import "" "d" (memory 1)) - )) - (import "b" (core module $m2 - (export "a" (func)) - (export "b" (global i32)) - (export "c" (table 1 funcref)) - (export "d" (memory 1)) - )) - (core instance $x (instantiate $m2)) - (core instance (instantiate $m (with "" (instance $x)))) -) - -(component definition - (import "a" (core module $m - (import "" "d" (func)) - (import "" "c" (global i32)) - (import "" "b" (table 1 funcref)) - (import "" "a" (memory 1)) - )) - (import "b" (core module $m2 - (export "a" (func)) - (export "b" (global i32)) - (export "c" (table 1 funcref)) - (export "d" (memory 1)) - )) - (core instance $x (instantiate $m2)) - - (core instance (instantiate $m (with "" (instance - (export "d" (func $x "a")) - (export "c" (global $x "b")) - (export "b" (table $x "c")) - (export "a" (memory $x "d")) - )))) -) - -(component - (component - (import "a" (component $m - (import "a" (instance - (export "a" (core module)) - )) - )) - (import "b" (component $m2 - (export "b" (core module)) - )) - (instance $x (instantiate $m2)) - - (instance (instantiate $m (with "a" (instance - (export "a" (core module $x "b")) - )))) - ) -) - -(component - (component - (import "a" (component $c - (import "a" (core module)) - (import "b" (func)) - (import "c" (component)) - (import "d" (instance)) - )) - (core module $m (import "b")) - (func $f (import "c")) - (component $c2 (import "d")) - (instance $i (import "e")) - - (instance - (instantiate $c - (with "a" (core module $m)) - (with "b" (func $f)) - (with "c" (component $c2)) - (with "d" (instance $i)) - ) - ) - - (core instance $c (instantiate $m)) - (core instance (instantiate $m)) - - ;; inline exports/imports - (type $empty (instance)) - (instance $d (import "g") (type $empty)) - (instance (import "h")) - (instance (import "i") - (export "x" (func))) - (instance (export "j") (export "k") (import "x")) - ) -) - -(assert_invalid - (component - (core instance (instantiate 0)) - ) - "unknown module") -(assert_invalid - (component - (instance (instantiate 0)) - ) - "unknown component") -(assert_invalid - (component - (import "a" (core module)) - (core instance (instantiate 1)) - ) - "unknown module") - -(component - (component - (import "a" (func $f)) - (import "b" (component $c)) - (instance (instantiate $c (with "a" (func $f)))) - ) -) -(assert_invalid - (component - (import "a" (core module $m (import "" "" (func)))) - (core instance (instantiate $m)) - ) - "missing module instantiation argument") -(assert_invalid - (component - (import "a" (component $m (import "a" (func)))) - (instance (instantiate $m)) - ) - "missing import named `a`") - -(assert_invalid - (component - (import "a" (component $m - (import "a" (func)) - )) - (import "b" (component $c)) - (instance $i (instantiate $m (with "a" (component $c)))) - ) - "expected func, found component") - -(assert_invalid - (component - (import "a" (component $m - (import "a" (func)) - )) - (import "b" (func $f (result string))) - (instance $i (instantiate $m (with "a" (func $f)))) - ) - "expected a result, found none") - -(assert_invalid - (component - (import "a" (component $m - (import "a" (func)) - )) - (import "b" (func (param "i" string))) - (instance $i (instantiate $m (with "a" (func 0)))) - ) - "expected 0 parameters, found 1") - -(assert_invalid - (component - (import "a" (component $m - (import "a" (core module - (import "" "" (func)) - )) - )) - (import "b" (core module $i - (import "" "" (global i32)) - )) - (instance $i (instantiate $m (with "a" (core module $i)))) - ) - "type mismatch in import `::`") - -(assert_invalid - (component - (import "a" (component $m - (import "a" (core module)) - )) - (import "b" (core module $i - (import "" "foobar" (global i32)) - )) - (instance $i (instantiate $m (with "a" (core module $i)))) - ) - "missing expected import `::foobar`") -(assert_invalid - (component - (import "a" (component $m - (import "a" (core module (export "x" (func)))) - )) - (import "b" (core module $i)) - (instance $i (instantiate $m (with "a" (core module $i)))) - ) - "missing expected export `x`") - -;; it's ok to give a module with fewer imports -(component - (component - (import "a" (component $m - (import "a" (core module - (import "" "" (global i32)) - (import "" "f" (func)) - )) - )) - (import "b" (core module $i - (import "" "" (global i32)) - )) - (instance $i (instantiate $m (with "a" (core module $i)))) - ) -) - -;; export subsets -(component - (component - (import "a" (component $m - (import "a" (core module - (export "" (func)) - )) - )) - (import "b" (core module $i - (export "" (func)) - (export "a" (func)) - )) - (instance $i (instantiate $m (with "a" (core module $i)))) - ) -) -(component - (component - (import "a" (component $m - (import "a" (instance - (export "a" (func)) - )) - )) - (import "b" (instance $i - (export "a" (func)) - (export "b" (func)) - )) - (instance (instantiate $m (with "a" (instance $i)))) - ) -) - - -;; ============================================================================ -;; core wasm type checking - -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (func)))) - (import "m2" (core module $m2 (export "" (func (param i32))))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "expected: (func)") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (func)))) - (import "m2" (core module $m2 (export "" (func (result i32))))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "expected: (func)") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (global i32)))) - (import "m2" (core module $m2 (export "" (global i64)))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "expected global type i32, found i64") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (table 1 funcref)))) - (import "m2" (core module $m2 (export "" (table 2 externref)))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "expected table element type funcref, found externref") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (table 1 2 funcref)))) - (import "m2" (core module $m2 (export "" (table 2 funcref)))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "mismatch in table limits") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (table 2 2 funcref)))) - (import "m2" (core module $m2 (export "" (table 1 funcref)))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "mismatch in table limits") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (table 2 2 funcref)))) - (import "m2" (core module $m2 (export "" (table 2 3 funcref)))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "mismatch in table limits") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (memory 1 2 shared)))) - (import "m2" (core module $m2 (export "" (memory 1)))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "mismatch in the shared flag for memories") -(assert_invalid - (component - (import "m1" (core module $m1 (import "" "" (memory 1)))) - (import "m2" (core module $m2 (export "" (memory 0)))) - (core instance $i (instantiate $m2)) - (core instance (instantiate $m1 (with "" (instance $i)))) - ) - "mismatch in memory limits") -(assert_invalid - (component - (import "m1" (core module $m1 (export "g" (func)))) - (component $c - (import "m" (core module (export "g" (global i32)))) - ) - (instance (instantiate $c (with "m" (core module $m1)))) - ) - "type mismatch in export `g`") - -(assert_invalid - (component - (core instance (instantiate 0)) - ) - "unknown module") - -(component - (component $m - (core module $sub (export "module") - (func $f (export "") (result i32) - i32.const 5)) - ) - (instance $a (instantiate $m)) - (alias export $a "module" (core module $sub)) - (core instance $b (instantiate $sub)) - - (core module $final - (import "" "" (func $b (result i32))) - (func (export "get") (result i32) - call $b)) - - (core instance (instantiate $final (with "" (instance $b)))) -) - -(assert_invalid - (component (instance $i (export "" (func 0)))) - "function index out of bounds") - -(assert_invalid - (component (instance (export "" (instance 0)))) - "index out of bounds") - -(assert_invalid - (component (instance $i (export "" (component 0)))) - "index out of bounds") - -(assert_invalid - (component (instance (export "" (instance 0)))) - "index out of bounds") - -(assert_invalid - (component (instance $i (export "" (core module 0)))) - "index out of bounds") - -(assert_invalid - (component (core instance (export "" (func 0)))) - "index out of bounds") - -(assert_invalid - (component (core instance (export "" (table 0)))) - "index out of bounds") - -(assert_invalid - (component (core instance (export "" (global 0)))) - "index out of bounds") - -(assert_invalid - (component (core instance (export "" (memory 0)))) - "index out of bounds") - -(assert_invalid - (component - (core module $m) - (core instance $i (instantiate $m)) - (core instance (instantiate $m - (with "" (instance $i)) - (with "" (instance $i)) - )) - ) - "duplicate module instantiation argument named ``" -) - -(assert_invalid - (component - (core module $m (func (export ""))) - (core instance $i (instantiate $m)) - (core instance (instantiate $m - (with "" (instance $i)) - (with "" (instance $i)) - )) - ) - "duplicate module instantiation argument named ``") - -(assert_invalid - (component - (core module $m1 (func (export ""))) - (core module $m2 (import "" "" (global i32))) - (core instance $i (instantiate $m1)) - (core instance (instantiate $m2 - (with "" (instance $i)) - )) - ) - "expected global, found func") - -(assert_invalid - (component - (component $m) - (instance $i (instantiate $m)) - (instance (instantiate $m - (with "a" (instance $i)) - (with "a" (instance $i)) - )) - ) - "instantiation argument `a` conflicts with previous argument `a`") - -(assert_invalid - (component - (component $c (import "a" (func))) - (instance (instantiate $c - (with "a" (component $c)) - )) - ) - "expected func, found component") - -(assert_invalid - (component - (component $c) - (instance (instantiate $c - (with "" (core module 0)) - )) - ) - "index out of bounds") - -(assert_invalid - (component - (component $c) - (instance (instantiate $c - (with "" (instance 0)) - )) - ) - "index out of bounds") - -(assert_invalid - (component - (component $c) - (instance (instantiate $c - (with "" (func 0)) - )) - ) - "index out of bounds") - -(assert_invalid - (component - (component $c) - (instance (instantiate $c - (with "" (component 100)) - )) - ) - "index out of bounds") - -(assert_invalid - (component - (component $c) - (instance - (export "a" (component $c)) - (export "a" (component $c)) - ) - ) - "export name `a` conflicts with previous name `a`") - -(component - (component - (import "a" (instance $i)) - (import "b" (func $f)) - (import "c" (component $c)) - (import "d" (core module $m)) - (instance - (export "a" (instance $i)) - (export "b" (func $f)) - (export "c" (component $c)) - (export "d" (core module $m)) - ) - ) -) - -(component - (core module $m - (func (export "1")) - (memory (export "2") 1) - (table (export "3") 1 funcref) - (global (export "4") i32 i32.const 0) - ) - (core instance $i (instantiate $m)) - (core instance - (export "a" (func $i "1")) - (export "b" (memory $i "2")) - (export "c" (table $i "3")) - (export "d" (global $i "4")) - ) -) - -(assert_invalid - (component - (core module $m (func (export ""))) - (core instance $i (instantiate $m)) - (core instance - (export "" (func $i "")) - (export "" (func $i "")) - ) - ) - "export name `` already defined") - -(assert_invalid - (component - (component $c) - (instance $i (instantiate $c)) - (export "a" (instance $i "a")) - ) - "no export named `a`") - -(assert_invalid - (component - (export "a" (instance 100 "a")) - ) - "index out of bounds") - -(assert_invalid - (component - (import "a" (core module $libc - (export "memory" (memory 1)) - (export "table" (table 0 funcref)) - (export "func" (func)) - (export "global" (global i32)) - (export "global mut" (global (mut i64))) - )) - (core instance $libc (instantiate $libc)) - (alias core export $libc "memory" (core memory $mem)) - (alias core export $libc "table" (core table $tbl)) - (alias core export $libc "func" (core func $func)) - (alias core export $libc "global" (core global $global)) - (alias core export $libc "global mut" (core global $global_mut)) - - (import "x" (core module $needs_libc - (import "" "memory" (memory 1)) - (import "" "table" (table 0 funcref)) - (import "" "func" (func)) - (import "" "global" (global i32)) - (import "" "global mut" (global (mut i64))) - )) - - (core instance - (instantiate $needs_libc - (with "" (instance (export "memory" (memory $mem)))) - ) - ) - ) - "module instantiation argument `` does not export an item named `table`") - -;; Ensure a type can be an instantiation argument -(component - (type (tuple u32 u32)) - (import "a" (type (eq 0))) - (component - (type (tuple u32 u32)) - (import "a" (type (eq 0))) - ) - (instance (instantiate 0 - (with "a" (type 1)) - ) - ) -) - -(assert_invalid - (component - (type $t (tuple string string)) - (import "a" (type $a (eq $t))) - (component $c - (type $t (tuple u32 u32)) - (import "a" (type (eq $t))) - ) - (instance (instantiate $c - (with "a" (type $a)) - ) - ) - ) - "expected primitive `u32` found primitive `string`") - - -;; subtyping for module imports reverses order of imports/exports for the -;; subtyping check -;; -;; Here `C` imports a module, and the module itself imports a table of min size -;; 1. A module import which imports a min-size table of 0, however, is valid to -;; supply for this since it'll already be given at least 1 anyway. -;; -;; Similarly for exports `C` imports a module that exports a table of at least -;; size 1. If it's given a module that exports a larger table that's ok too. -(component - (core module $a - (import "" "" (table 0 funcref)) - (table (export "x") 2 funcref) - ) - (component $C - (import "a" (core module - (import "" "" (table 1 funcref)) - (export "x" (table 1 funcref)) - )) - ) - (instance (instantiate $C (with "a" (core module $a)))) -) - -;; same as above but for memories -(component - (core module $a1 (import "" "" (memory 0))) - (core module $a2 (memory (export "x") 2)) - (component $C - (import "a1" (core module (import "" "" (memory 1)))) - (import "a2" (core module (export "x" (memory 1)))) - ) - (instance (instantiate $C - (with "a1" (core module $a1)) - (with "a2" (core module $a2)) - )) -) - -(assert_invalid - (component - (import "x" (func $x (param "x" u32))) - (import "y" (component $c - (import "x" (func (param "y" u32))) - )) - - (instance (instantiate $c (with "x" (func $x)))) - ) - "expected parameter named `y`, found `x`") -(assert_invalid - (component - (import "x" (func $x (param "x" u32))) - (import "y" (component $c - (import "x" (func (param "x" s32))) - )) - - (instance (instantiate $c (with "x" (func $x)))) - ) - "type mismatch in function parameter `x`") -(assert_invalid - (component - (import "x" (func $x (result u32))) - (import "y" (component $c - (import "x" (func (result s32))) - )) - - (instance (instantiate $c (with "x" (func $x)))) - ) - "type mismatch with result type") - -(assert_invalid - (component - (import "x" (instance $x (export "a" (func)))) - (import "y" (component $c - (import "x" (instance $x (export "a" (component)))) - )) - - (instance (instantiate $c (with "x" (instance $x)))) - ) - "type mismatch in instance export `a`") - -(assert_invalid - (component - (import "y" (component $c - (type $t u32) - (import "x" (type (eq $t))) - )) - - (type $x (record (field "f" u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected primitive, found record") - -(assert_invalid - (component - (import "y" (component $c - (type $t (record (field "f" u32))) - (import "x" (type (eq $t))) - )) - - (type $x u32) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected record, found u32") - -(assert_invalid - (component - (import "y" (component $c - (type $t (record (field "x" u32))) - (import "x" (type (eq $t))) - )) - - (type $f (tuple u8)) - (type $x (record (field "x" $f))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected u32, found tuple") - -(assert_invalid - (component - (import "y" (component $c - (type $f (option s32)) - (type $t (record (field "x" $f))) - (import "x" (type (eq $t))) - )) - - (type $x (record (field "x" u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "type mismatch in record field `x`") - -(assert_invalid - (component - (import "y" (component $c - (type $t (record (field "x" u32))) - (import "x" (type (eq $t))) - )) - - (type $x (record (field "y" u32) (field "z" u64))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected 1 fields, found 2") - -(assert_invalid - (component - (import "y" (component $c - (type $t (record (field "a" u32))) - (import "x" (type (eq $t))) - )) - - (type $x (record (field "b" u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected field name `a`, found `b`") - -(assert_invalid - (component - (import "y" (component $c - (type $t (variant (case "x" u32))) - (import "x" (type (eq $t))) - )) - - (type $x (variant (case "x" u32) (case "y" u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected 1 cases, found 2") - -(assert_invalid - (component - (import "y" (component $c - (type $t (variant (case "x" u32))) - (import "x" (type (eq $t))) - )) - - (type $x (variant (case "y" u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected case named `x`, found `y`") - -(assert_invalid - (component - (import "y" (component $c - (type $t (variant (case "x" u32))) - (import "x" (type (eq $t))) - )) - - (type $x (variant (case "x"))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected case `x` to have a type, found none") - -(assert_invalid - (component - (import "y" (component $c - (type $t (variant (case "x"))) - (import "x" (type (eq $t))) - )) - - (type $x (variant (case "x" u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected case `x` to have no type") - -(assert_invalid - (component - (import "y" (component $c - (type $t (variant (case "x" u32))) - (import "x" (type (eq $t))) - )) - - (type $x (variant (case "x" s32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "type mismatch in variant case `x`") - -(assert_invalid - (component - (import "y" (component $c - (type $t (tuple u8)) - (import "x" (type (eq $t))) - )) - - (type $x (tuple u32 u32)) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected 1 types, found 2") - -(assert_invalid - (component - (import "y" (component $c - (type $t (tuple u8)) - (import "x" (type (eq $t))) - )) - - (type $x (tuple u16)) - (instance (instantiate $c (with "x" (type $x)))) - ) - "type mismatch in tuple field 0") - -(assert_invalid - (component - (import "y" (component $c - (type $t (flags "a")) - (import "x" (type (eq $t))) - )) - - (type $x (flags "x")) - (instance (instantiate $c (with "x" (type $x)))) - ) - "mismatch in flags elements") - -(assert_invalid - (component - (import "y" (component $c - (type $t (enum "a")) - (import "x" (type (eq $t))) - )) - - (type $x (enum "x")) - (instance (instantiate $c (with "x" (type $x)))) - ) - "mismatch in enum elements") - -(assert_invalid - (component - (import "y" (component $c - (type $t (result s32)) - (import "x" (type (eq $t))) - )) - - (type $x (result u32)) - (instance (instantiate $c (with "x" (type $x)))) - ) - "type mismatch in ok variant") - -(assert_invalid - (component - (import "y" (component $c - (type $t (result (error s32))) - (import "x" (type (eq $t))) - )) - - (type $x (result (error u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "type mismatch in err variant") - -(assert_invalid - (component - (import "y" (component $c - (type $t (result)) - (import "x" (type (eq $t))) - )) - - (type $x (result u32)) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected ok type to not be present") - -(assert_invalid - (component - (import "y" (component $c - (type $t (result u32)) - (import "x" (type (eq $t))) - )) - - (type $x (result)) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected ok type, but found none") - -(assert_invalid - (component - (import "y" (component $c - (type $t (result)) - (import "x" (type (eq $t))) - )) - - (type $x (result (error u32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected err type to not be present") - -(assert_invalid - (component - (import "y" (component $c - (type $t (result (error u32))) - (import "x" (type (eq $t))) - )) - - (type $x (result)) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected err type, but found none") diff --git a/src/test/resources/spec-tests/wasm-tools/invalid.wast b/src/test/resources/spec-tests/wasm-tools/invalid.wast deleted file mode 100644 index 267b31f..0000000 --- a/src/test/resources/spec-tests/wasm-tools/invalid.wast +++ /dev/null @@ -1,34 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_invalid - (component - (core type (module - (import "" "" (func (type 1))) - )) - (type (func)) - ) - "type index out of bounds") - -(assert_malformed - (component quote - "(export \"\" (func $foo))" - ) - "unknown func") - -(assert_malformed - (component quote - "(alias outer 100 $foo (type $foo))" - ) - "outer count of `100` is too large") - -(assert_malformed - (component quote - "(alias outer $nonexistent $foo (type $foo))" - ) - "outer component `nonexistent` not found") - -(assert_malformed - (component quote - "(import \"x\" (func $x))" - "(component (export \"x\" (func $x)))") - "outer item `x` is not a module, type, or component") diff --git a/src/test/resources/spec-tests/wasm-tools/link.wast b/src/test/resources/spec-tests/wasm-tools/link.wast deleted file mode 100644 index 7202365..0000000 --- a/src/test/resources/spec-tests/wasm-tools/link.wast +++ /dev/null @@ -1,14 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -;; Based on this, we can link two modules $A and $B together with the following component: - -(component - (core module $A - (func (export "one") (result i32) (i32.const 1)) - ) - (core module $B - (func (import "a" "one") (result i32)) - ) - (core instance $a (instantiate $A)) - (core instance $b (instantiate $B (with "a" (instance $a)))) -) diff --git a/src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast b/src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast deleted file mode 100644 index 32e1a27..0000000 --- a/src/test/resources/spec-tests/wasm-tools/lots-of-aliases.wast +++ /dev/null @@ -1,179 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component - (core module $m - (memory (export "m") 1) - (table (export "t") 1 funcref) - (global (export "g") i32 i32.const 0) - (func (export "f")) - ) - (core instance $i (instantiate $m)) - - ;; 160 memories (4 per row 40 rows) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) - - ;; 160 tables (4 per row 40 rows) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) - - ;; 160 globals (4 per row 40 rows) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) - - ;; 160 functions (4 per row 40 rows) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) - (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) -) diff --git a/src/test/resources/spec-tests/wasm-tools/lower.wast b/src/test/resources/spec-tests/wasm-tools/lower.wast deleted file mode 100644 index 5b9e13b..0000000 --- a/src/test/resources/spec-tests/wasm-tools/lower.wast +++ /dev/null @@ -1,17 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_invalid - (component - (import "f" (func $f (param "x" (list u8)))) - (core func $f (canon lower (func $f) - )) - ) - "canonical option `memory` is required") - -(assert_invalid - (component - (import "f" (func $f (result (list u8)))) - (core func $f (canon lower (func $f) - )) - ) - "canonical option `memory` is required") diff --git a/src/test/resources/spec-tests/wasm-tools/memory64.wast b/src/test/resources/spec-tests/wasm-tools/memory64.wast deleted file mode 100644 index a72eb3b..0000000 --- a/src/test/resources/spec-tests/wasm-tools/memory64.wast +++ /dev/null @@ -1,55 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_invalid - (component - (core module $A - (import "" "" (memory 1))) - (core module $B - (memory (export "") i64 1)) - (core instance $b (instantiate $B)) - (core instance $a (instantiate $A (with "" (instance $b)))) - ) - "mismatch in index type used for memories") - -(assert_invalid - (component - (core module $A - (import "" "" (memory i64 1))) - (core module $B - (memory (export "") 1)) - (core instance $b (instantiate $B)) - (core instance $a (instantiate $A (with "" (instance $b)))) - ) - "mismatch in index type used for memories") - -(component - (core module $A - (memory (export "m") i64 1)) - (core instance $A (instantiate $A)) - (alias core export $A "m" (core memory $m)) - - (core module $B (import "" "" (memory i64 1))) - (core instance (instantiate $B (with "" (instance (export "" (memory $m)))))) -) - -(component - (core module $A - (table (export "m") i64 1 funcref)) - (core instance $A (instantiate $A)) - (alias core export $A "m" (core table $m)) - - (core module $B (import "" "" (table i64 1 funcref))) - (core instance (instantiate $B (with "" (instance (export "" (table $m)))))) -) - -(component - (import "x" (func $x (param "x" string))) - (core module $A - (memory (export "m") i64 1) - (func (export "realloc") (param i64 i64 i64 i64) (result i64) unreachable) - ) - (core instance $A (instantiate $A)) - (alias core export $A "m" (core memory $m)) - (core func $realloc (alias core export $A "realloc")) - (core func (canon lower (func $x) (memory $m) (realloc (func $realloc)))) -) diff --git a/src/test/resources/spec-tests/wasm-tools/module-link.wast b/src/test/resources/spec-tests/wasm-tools/module-link.wast deleted file mode 100644 index 119da23..0000000 --- a/src/test/resources/spec-tests/wasm-tools/module-link.wast +++ /dev/null @@ -1,98 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component - (type $Wasi (instance)) - (component $B) - (component $B_wrap - (import "wasi" (instance $wasi (type $Wasi))) - (instance $b (instantiate $B)) - ) -) - -(component - (type $Wasi (instance)) - (import "wasi" (instance $wasi (type $Wasi))) - - (component $A - (type $Wasi (instance)) - (import "wasi" (instance (type $Wasi))) - - (core module $m - (func (export "a")) - ) - - (core instance $i (instantiate $m)) - (func (export "a") - (canon lift (core func $i "a")) - ) - ) - - (component $B - (type $Wasi (instance)) - (import "wasi" (instance $wasi (type $Wasi))) - (import "a1-x" (component $A - (import "wasi" (instance (type $Wasi))) - (export "a" (func)) - )) - (instance $a (instantiate $A (with "wasi" (instance $wasi)))) - - (core func $lower (canon lower (func $a "a"))) - (core module $b - (import "a" "a" (func)) - (func (export "b")) - ) - (core instance $b (instantiate $b - (with "a" (instance (export "a" (func $lower)))) - )) - (func (export "b") - (canon lift (core func $b "b")) - ) - ) - (component $B_wrap - (type $Wasi (instance)) - (import "wasi" (instance $wasi (type $Wasi))) - (instance $b (instantiate $B - (with "wasi" (instance $wasi)) - (with "a1-x" (component $A))) - ) - (export "b" (func $b "b")) - ) - - (component $C - (type $Wasi (instance)) - (import "wasi" (instance $wasi (type $Wasi))) - (import "b1-x" (component $B - (import "wasi" (instance $wasi (type $Wasi))) - (export "b" (func)) - )) - (instance $b (instantiate $B (with "wasi" (instance $wasi)))) - (export "c" (func $b "b")) - ) - (component $C_wrap - (type $Wasi (instance)) - (import "wasi" (instance $wasi (type $Wasi))) - (instance $c (instantiate $C - (with "wasi" (instance $wasi)) - (with "b1-x" (component $B_wrap)) - )) - (export "c" (func $c "c")) - ) - - (component $D - (type $Wasi (instance)) - (import "wasi" (instance $wasi (type $Wasi))) - (import "c1-x" (component $C - (import "wasi" (instance $wasi (type $Wasi))) - (export "c" (func)) - )) - (instance $c (instantiate $C (with "wasi" (instance $wasi)))) - (export "d" (func $c "c")) - ) - - (instance $d (instantiate $D - (with "wasi" (instance $wasi)) - (with "c1-x" (component $C_wrap)) - )) - - (export "d" (func $d "d")) -) diff --git a/src/test/resources/spec-tests/wasm-tools/more-flags.wast b/src/test/resources/spec-tests/wasm-tools/more-flags.wast deleted file mode 100644 index ebcced0..0000000 --- a/src/test/resources/spec-tests/wasm-tools/more-flags.wast +++ /dev/null @@ -1,41 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_invalid - (component - (type (flags - "f1" - "f2" - "f3" - "f4" - "f5" - "f6" - "f7" - "f8" - "f9" - "f10" - "f11" - "f12" - "f13" - "f14" - "f15" - "f16" - "f17" - "f18" - "f19" - "f20" - "f21" - "f22" - "f23" - "f24" - "f25" - "f26" - "f27" - "f28" - "f29" - "f30" - "f31" - "f32" - "f33" - )) - ) - "cannot have more than 32 flags") diff --git a/src/test/resources/spec-tests/wasm-tools/naming.wast b/src/test/resources/spec-tests/wasm-tools/naming.wast deleted file mode 100644 index 5decf55..0000000 --- a/src/test/resources/spec-tests/wasm-tools/naming.wast +++ /dev/null @@ -1,127 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component definition - (func (import "a")) - (component) - (instance (instantiate 0 (with "NotKebab-Case" (func 0)))) -) - -(assert_invalid - (component - (import "f" (func)) - (instance (export "1" (func 0))) - ) - "`1` is not in kebab case" -) - -(assert_invalid - (component - (instance) - (alias export 0 "Xml" (func)) - ) - "instance 0 has no export named `Xml`" -) - -(component definition - (type (flags "a-1-c")) -) - -(assert_invalid - (component - (type (enum "NevEr")) - ) - "enum tag name `NevEr` is not in kebab case" -) - -(assert_invalid - (component - (type (record (field "GoNnA" string))) - ) - "record field name `GoNnA` is not in kebab case" -) - -(assert_invalid - (component - (type (variant (case "GIVe" string))) - ) - "variant case name `GIVe` is not in kebab case" -) - - -(assert_invalid - (component - (type (func (param "yOu" string))) - ) - "function parameter name `yOu` is not in kebab case" -) - -(assert_invalid - (component - (type (component (export "NevEr" (func)))) - ) - "`NevEr` is not in kebab case" -) - -(assert_invalid - (component - (type (component (import "GonnA" (func)))) - ) - "`GonnA` is not in kebab case" -) - -(assert_invalid - (component - (type (instance (export "lET" (func)))) - ) - "`lET` is not in kebab case" -) - -(assert_invalid - (component - (instance (export "YoU")) - ) - "`YoU` is not in kebab case" -) - -(assert_invalid - (component - (instance (import "DOWn")) - ) - "`DOWn` is not in kebab case" -) - -(assert_invalid - (component - (instance (import "A:b/c")) - ) - "character `A` is not lowercase in package name/namespace" -) -(assert_invalid - (component - (instance (import "a:B/c")) - ) - "character `B` is not lowercase in package name/namespace" -) -(component - (instance (import "a:b/c")) - (instance (import "a1:b1/c")) -) - -(component definition - (import "a" (type $a (sub resource))) - (import "[constructor]a" (func (result (own $a)))) -) - -(assert_invalid - (component - (import "a" (type $a (sub resource))) - (import "[method]a.a" (func (param "self" (borrow $a)))) - ) - "import name `[method]a.a` conflicts with previous name `a`") - -(assert_invalid - (component - (import "a" (type $a (sub resource))) - (import "[static]a.a" (func)) - ) - "import name `[static]a.a` conflicts with previous name `a`") diff --git a/src/test/resources/spec-tests/wasm-tools/nested-modules.wast b/src/test/resources/spec-tests/wasm-tools/nested-modules.wast deleted file mode 100644 index 5e629ea..0000000 --- a/src/test/resources/spec-tests/wasm-tools/nested-modules.wast +++ /dev/null @@ -1,50 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component definition - (import "i1" (core module)) - - (core module) - (core module) - - (core module (export "x")) - - (component - (core module) - ) - - (component - (core module $m) - (import "a" (func (param "p" string))) - (export "b" (core module $m)) - ) -) - -;; does the `import` use the type annotation specified later? -(component definition - (import "a" (core module)) - (core type (module)) -) - -;; be sure to typecheck nested modules -(assert_invalid - (component - (core module - (func - i32.add) - ) - ) - "type mismatch") - -;; interleave module definitions with imports/aliases and ensure that we -;; typecheck the module code section correctly -(component definition - (core module - (func (export "")) - ) - (import "a" (core module)) - (core module - (func (export "") (result i32) i32.const 5) - ) - (import "b" (instance (export "a" (core module)))) - (alias export 0 "a" (core module)) -) diff --git a/src/test/resources/spec-tests/wasm-tools/resources.wast b/src/test/resources/spec-tests/wasm-tools/resources.wast deleted file mode 100644 index 14509c5..0000000 --- a/src/test/resources/spec-tests/wasm-tools/resources.wast +++ /dev/null @@ -1,1195 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component - (type $x (resource (rep i32))) -) - -(component - (type $x (resource (rep i32))) - - (core func (canon resource.new $x)) - (core func (canon resource.rep $x)) - (core func (canon resource.drop $x)) -) - -(component definition - (import "x" (type $x (sub resource))) - - (core func (canon resource.drop $x)) -) - -(component - (core module $m - (func (export "dtor") (param i32)) - ) - (core instance $m (instantiate $m)) - (type $x (resource (rep i32) (dtor (func $m "dtor")))) - (core func (canon resource.new $x)) -) - -(component - (type $x (resource (rep i32))) - (core func $f1 (canon resource.new $x)) - (core func $f2 (canon resource.rep $x)) - (core func $f3 (canon resource.drop $x)) - - (core module $m - (import "" "f1" (func (param i32) (result i32))) - (import "" "f2" (func (param i32) (result i32))) - (import "" "f3" (func (param i32))) - ) - - (core instance (instantiate $m - (with "" (instance - (export "f1" (func $f1)) - (export "f2" (func $f2)) - (export "f3" (func $f3)) - )) - )) -) - -(assert_invalid - (component - (type $x (resource (rep i64))) - ) - "resources can only be represented by `i32`") - -(assert_invalid - (component - (type $x (own 100)) - ) - "type index out of bounds") - -(assert_invalid - (component - (type $x (borrow 100)) - ) - "type index out of bounds") - -(assert_invalid - (component - (type $t u8) - (type $x (borrow $t)) - ) - "not a resource type") - -(assert_invalid - (component - (type $t u8) - (type $x (own $t)) - ) - "not a resource type") - -(assert_invalid - (component - (import "x" (type $x (sub resource))) - (core func (canon resource.new $x)) - ) - "not a local resource") - -(assert_invalid - (component - (import "x" (type $x (sub resource))) - (core func (canon resource.rep $x)) - ) - "not a local resource") - -(assert_invalid - (component - (type $t (tuple u32)) - (core func (canon resource.drop $t)) - ) - "not a resource type") - -(assert_invalid - (component - (core func (canon resource.drop 100)) - ) - "type index out of bounds") - -(assert_invalid - (component - (type (component)) - (core func (canon resource.drop 0)) - ) - "not a resource type") - -(assert_invalid - (component - (type (component)) - (core func (canon resource.new 0)) - ) - "not a resource type") - -(assert_invalid - (component - (core module $m - (func (export "dtor")) - ) - (core instance $m (instantiate $m)) - (type $x (resource (rep i32) (dtor (func $m "dtor")))) - (core func (canon resource.new $x)) - ) - "wrong signature for a destructor") - -(assert_invalid - (component - (type (resource (rep i32) (dtor (func 100)))) - ) - "function index out of bounds") - -(assert_invalid - (component - (import "x" (type $x (sub resource))) - (import "y" (type $y (sub resource))) - (import "z" (func $z (param "x" (own $x)) (param "y" (own $y)))) - - (component $c - (import "x" (type $x (sub resource))) - (import "z" (func (param "x" (own $x)) (param "y" (own $x)))) - ) - - (instance (instantiate $c (with "x" (type $x)) (with "z" (func $z)))) - ) - "resource types are not the same") - -(component - (type (component - (import "x" (type $x (sub resource))) - (export "y" (type (eq $x))) - (export "z" (type (sub resource))) - )) -) - -(assert_invalid - (component - (type (component - (type $x (resource (rep i32))) - )) - ) - "resources can only be defined within a concrete component") - -(assert_invalid - (component - (type (instance - (type $x (resource (rep i32))) - )) - ) - "resources can only be defined within a concrete component") - -(component - (type (component - (import "x" (instance $i - (export "t" (type $t (sub resource))) - (export "f" (func (result (own $t)))) - )) - (alias export $i "t" (type $t)) - (export "f" (func (result (own $t)))) - )) -) - -(component definition - (import "fancy-fs" (instance $fancy-fs - (export "fs" (instance $fs - (export "file" (type (sub resource))) - )) - (alias export $fs "file" (type $file)) - (export "fancy-op" (func (param "f" (borrow $file)))) - )) -) - -(component $C - (type $T (list (tuple string bool))) - (type $U (option $T)) - (type $G (func (param "x" (list $T)) (result $U))) - (type $D (component - (alias outer $C $T (type $C_T)) - (type $L (list $C_T)) - (import "f" (func (param "x" $L) (result (list u8)))) - (import "g" (func (type $G))) - (export "g2" (func (type $G))) - (export "h" (func (result $U))) - (import "T" (type $T (sub resource))) - (import "i" (func (param "x" (list (own $T))))) - (export "T2" (type $T' (eq $T))) - (export "U" (type $U' (sub resource))) - (export "j" (func (param "x" (borrow $T')) (result (own $U')))) - )) -) - -(component definition - (import "T1" (type $T1 (sub resource))) - (import "T2" (type $T2 (sub resource))) -) - -(component definition $C - (import "T1" (type $T1 (sub resource))) - (import "T2" (type $T2 (sub resource))) - (import "T3" (type $T3 (eq $T2))) - (type $ListT1 (list (own $T1))) - (type $ListT2 (list (own $T2))) - (type $ListT3 (list (own $T3))) -) - -(component definition - (import "T" (type $T (sub resource))) - (import "U" (type $U (sub resource))) - (type $Own1 (own $T)) - (type $Own2 (own $T)) - (type $Own3 (own $U)) - (type $ListOwn1 (list $Own1)) - (type $ListOwn2 (list $Own2)) - (type $ListOwn3 (list $Own3)) - (type $Borrow1 (borrow $T)) - (type $Borrow2 (borrow $T)) - (type $Borrow3 (borrow $U)) - (type $ListBorrow1 (list $Borrow1)) - (type $ListBorrow2 (list $Borrow2)) - (type $ListBorrow3 (list $Borrow3)) -) - -(component - (component - (import "C" (component $C - (export "T1" (type (sub resource))) - (export "T2" (type $T2 (sub resource))) - (export "T3" (type (eq $T2))) - )) - (instance $c (instantiate $C)) - (alias export $c "T1" (type $T1)) - (alias export $c "T2" (type $T2)) - (alias export $c "T3" (type $T3)) - ) -) - -(component - (component $C - (type $r1 (export "r1") (resource (rep i32))) - (type $r2 (export "r2") (resource (rep i32))) - ) - (instance $c1 (instantiate $C)) - (instance $c2 (instantiate $C)) - (alias export $c1 "r1" (type $c1r1)) - (alias export $c1 "r2" (type $c1r2)) - (alias export $c2 "r1" (type $c2r1)) - (alias export $c2 "r2" (type $c2r2)) -) - -(component - (type $r (resource (rep i32))) - (export "r1" (type $r)) - (export "r2" (type $r)) -) - -(component - (type (component - (export "r1" (type (sub resource))) - (export "r2" (type (sub resource))) - )) -) - -(component - (type $r (resource (rep i32))) - (export $r1 "r1" (type $r)) - (export "r2" (type $r1)) -) - -(component - (type (component - (export "r1" (type $r1 (sub resource))) - (export "r2" (type (eq $r1))) - )) -) - -(component - (component $P - (import "C1" (component $C1 - (import "T" (type $T (sub resource))) - (export "foo" (func (param "t" (own $T)))) - )) - (import "C2" (component $C2 - (import "T" (type $T (sub resource))) - (import "foo" (func (param "t" (own $T)))) - )) - (type $R (resource (rep i32))) - (instance $c1 (instantiate $C1 (with "T" (type $R)))) - (instance $c2 (instantiate $C2 - (with "T" (type $R)) - (with "foo" (func $c1 "foo")) - )) - ) -) - -(component - (component - (import "C1" (component $C1 - (import "T1" (type $T1 (sub resource))) - (import "T2" (type $T2 (sub resource))) - (export "foo" (func (param "t" (tuple (own $T1) (own $T2))))) - )) - (import "C2" (component $C2 - (import "T" (type $T (sub resource))) - (export "foo" (func (param "t" (tuple (own $T) (own $T))))) - )) - (type $R (resource (rep i32))) - (instance $c1 (instantiate $C1 - (with "T1" (type $R)) - (with "T2" (type $R)) - )) - (instance $c2 (instantiate $C2 - (with "T" (type $R)) - (with "foo" (func $c1 "foo")) - )) - ) -) - -(assert_invalid - (component - (component $C - (type $R (resource (rep i32))) - (export "R" (type $R)) - ) - (instance $c (instantiate $C)) - (alias export $c "R" (type $R)) - (core func (canon resource.rep $R)) - ) - "not a local resource") - -(component - (component $C - (type $R (resource (rep i32))) - (export "R" (type $R)) - ) - (instance $c (instantiate $C)) - (alias export $c "R" (type $R)) - (core func (canon resource.drop $R)) -) - -(component - (component $C1 - (import "X" (type (sub resource))) - ) - (component $C2 - (import "C1" (component - (import "X" (type (sub resource))) - )) - ) - (instance $c (instantiate $C2 (with "C1" (component $C1)))) -) - -(component - (component $C1 - (import "X" (type $X (sub resource))) - (import "f" (func $f (result (own $X)))) - (export "g" (func $f)) - ) - (component $C2 - (import "C1" (component - (import "X" (type $X (sub resource))) - (import "f" (func (result (own $X)))) - (export "g" (func (result (own $X)))) - )) - ) - (instance $c (instantiate $C2 (with "C1" (component $C1)))) -) - -(component - (component $C1 - (type $X' (resource (rep i32))) - (export $X "X" (type $X')) - - (core func $f (canon resource.drop $X)) - (func (export "f") (param "X" (own $X)) (canon lift (core func $f))) - ) - (instance $c1 (instantiate $C1)) - - (component $C2 - (import "X" (type $X (sub resource))) - (import "f" (func (param "X" (own $X)))) - ) - (instance $c2 (instantiate $C2 - (with "X" (type $c1 "X")) - (with "f" (func $c1 "f")) - )) -) - -(assert_invalid - (component - (component $C1 - (type $X' (resource (rep i32))) - (export $X "X" (type $X')) - - (core func $f (canon resource.drop $X)) - (func (export "f") (param "X" (own $X)) (canon lift (core func $f))) - ) - (instance $c1 (instantiate $C1)) - (instance $c2 (instantiate $C1)) - - (component $C2 - (import "X" (type $X (sub resource))) - (import "f" (func (param "X" (own $X)))) - ) - (instance $c3 (instantiate $C2 - (with "X" (type $c1 "X")) - (with "f" (func $c2 "f")) - )) - ) - "resource types are not the same") - -(component - (component $C1 - (type $X (resource (rep i32))) - (export $X1 "X1" (type $X)) - (export $X2 "X2" (type $X)) - - (core func $f (canon resource.drop $X)) - (func (export "f1") (param "X" (own $X1)) (canon lift (core func $f))) - (func (export "f2") (param "X" (own $X2)) (canon lift (core func $f))) - ) - (instance $c1 (instantiate $C1)) - - (component $C2 - (import "X" (type $X (sub resource))) - (import "f" (func (param "X" (own $X)))) - ) - (instance $c2 (instantiate $C2 - (with "X" (type $c1 "X1")) - (with "f" (func $c1 "f1")) - )) - (instance $c3 (instantiate $C2 - (with "X" (type $c1 "X2")) - (with "f" (func $c1 "f2")) - )) -) - -(component - (component $C1 - (type $X (resource (rep i32))) - (export $X1 "X1" (type $X)) - (export $X2 "X2" (type $X)) - - (core func $f (canon resource.drop $X)) - (func (export "f1") (param "X" (own $X1)) (canon lift (core func $f))) - (func (export "f2") (param "X" (own $X2)) (canon lift (core func $f))) - ) - (instance $c1 (instantiate $C1)) - - (component $C2 - (import "X" (type $X (sub resource))) - (import "f" (func (param "X" (own $X)))) - ) - (instance $c2 (instantiate $C2 - (with "X" (type $c1 "X1")) - (with "f" (func $c1 "f2")) - )) - (instance $c3 (instantiate $C2 - (with "X" (type $c1 "X2")) - (with "f" (func $c1 "f1")) - )) -) - -(assert_invalid - (component - (component $c - (import "x" (type (sub resource))) - ) - (type $x u32) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected resource, found defined type") - -(assert_invalid - (component - (component $c - (type $t u32) - (import "x" (type (eq $t))) - ) - (type $x (resource (rep i32))) - (instance (instantiate $c (with "x" (type $x)))) - ) - "expected defined type, found resource") - -(assert_invalid - (component - (component $c - (import "x1" (type $x1 (sub resource))) - (import "x2" (type $x2 (eq $x1))) - ) - (type $x1 (resource (rep i32))) - (type $x2 (resource (rep i32))) - (instance (instantiate $c - (with "x1" (type $x1)) - (with "x2" (type $x2)) - )) - ) - "resource types are not the same") - -(component - (type $x (resource (rep i32))) - (component $c - (import "x" (type $t (sub resource))) - (export "y" (type $t)) - ) - (instance $c (instantiate $c (with "x" (type $x)))) - - (alias export $c "y" (type $x2)) - (core func (canon resource.rep $x2)) - -) - -(assert_invalid - (component - (type $r (resource (rep i32))) - (import "x" (func (result (own $r)))) - ) - "func not valid to be used as import") - -(assert_invalid - (component - (type (component - (export "x" (type $x (sub resource))) - (import "f" (func (result (own $x)))) - )) - ) - "func not valid to be used as import") - -(assert_invalid - (component - (type $r (resource (rep i32))) - - (core func $f (canon resource.drop $r)) - (func (export "f") (param "x" (own $r)) - (canon lift (core func $f))) - ) - "func not valid to be used as export") - -;; direct exports count as "explicit in" for resources -(component - (type $r' (resource (rep i32))) - (export $r "r" (type $r')) - - (core func $f (canon resource.drop $r)) - (func (export "f") (param "x" (own $r)) - (canon lift (core func $f))) -) - -;; instances-as-a-bundle count as "explicit in" for resources -(component - (type $r' (resource (rep i32))) - (instance $i' - (export "r" (type $r')) - ) - (export $i "i" (instance $i')) - (alias export $i "r" (type $r)) - - (core func $f (canon resource.drop $r)) - (func (export "f") (param "x" (own $r)) - (canon lift (core func $f))) -) - -;; Transitive bundles count for "explicit in" -(component - (type $r' (resource (rep i32))) - (instance $i' - (export "r" (type $r')) - ) - (instance $i2' - (export "i" (instance $i')) - ) - (export $i2 "i2" (instance $i2')) - (alias export $i2 "i" (instance $i)) - (alias export $i "r" (type $r)) - - (core func $f (canon resource.drop $r)) - (func (export "f") (param "x" (own $r)) - (canon lift (core func $f))) -) - -;; Component instantiations count for "explicit in" -(component - (type $r' (resource (rep i32))) - (component $C - (import "x" (type $x (sub resource))) - (export "y" (type $x)) - ) - (instance $c' (instantiate $C (with "x" (type $r')))) - (export $c "c" (instance $c')) - (alias export $c "y" (type $r)) - - (core func $f (canon resource.drop $r)) - (func (export "f") (param "x" (own $r)) - (canon lift (core func $f))) -) - -;; Make sure threading things around is valid for "explicit in" -(component - (type $r' (resource (rep i32))) - (component $C - (import "x" (type $x (sub resource))) - (export "y" (type $x)) - ) - (instance $c (instantiate $C (with "x" (type $r')))) - (instance $i (export "x" (type $c "y"))) - - (component $C2 - (import "x" (instance $i - (export "i1" (instance - (export "i2" (type (sub resource))) - )) - )) - (export "y" (type $i "i1" "i2")) - ) - - (instance $i2 (export "i2" (type $i "x"))) - (instance $i1 (export "i1" (instance $i2))) - (instance $c2 (instantiate $C2 - (with "x" (instance $i1)) - )) - (export $r "x" (type $c2 "y")) - - (core func $f (canon resource.drop $r)) - (func (export "f") (param "x" (own $r)) - (canon lift (core func $f))) -) - -;; Importing-and-exporting instances through instantiation counts for "explicit -;; in" -(component - (type $r' (resource (rep i32))) - (component $C - (import "x" (instance $x (export "t" (type (sub resource))))) - (export "y" (instance $x)) - ) - (instance $c' (instantiate $C - (with "x" (instance - (export "t" (type $r')) - )) - )) - (export $c "c" (instance $c')) - (alias export $c "y" (instance $y)) - (alias export $y "t" (type $r)) - - (core func $f (canon resource.drop $r)) - (func (export "f") (param "x" (own $r)) - (canon lift (core func $f))) -) - -(component definition - (type $i (instance - (export "r" (type $r (sub resource))) - (export "f" (func (result (own $r)))) - )) - (import "i1" (instance $i1 (type $i))) - (import "i2" (instance $i2 (type $i))) - - (component $c - (import "r" (type $t (sub resource))) - (import "f" (func (result (own $t)))) - ) - (instance (instantiate $c - (with "r" (type $i1 "r")) - (with "f" (func $i1 "f")) - )) - (instance (instantiate $c - (with "r" (type $i2 "r")) - (with "f" (func $i2 "f")) - )) -) - - -(assert_invalid - (component - (type $i (instance - (export "r" (type $r (sub resource))) - (export "f" (func (result (own $r)))) - )) - (import "i1" (instance $i1 (type $i))) - (import "i2" (instance $i2 (type $i))) - - (component $c - (import "r" (type $t (sub resource))) - (import "f" (func (result (own $t)))) - ) - (instance (instantiate $c - (with "r" (type $i1 "r")) - (with "f" (func $i2 "f")) - )) - ) - "resource types are not the same") - -;; substitution works -(component - (type $t (resource (rep i32))) - (component $c - (import "x" (type $t (sub resource))) - (export "y" (type $t)) - ) - (instance $c1 (instantiate $c (with "x" (type $t)))) - (instance $c2 (instantiate $c (with "x" (type $t)))) - - (component $c2 - (import "x1" (type $t (sub resource))) - (import "x2" (type (eq $t))) - (import "x3" (type (eq $t))) - ) - (instance (instantiate $c2 - (with "x1" (type $t)) - (with "x2" (type $c1 "y")) - (with "x3" (type $c2 "y")) - )) -) - -;; must supply a resource to instantiation -(assert_invalid - (component - (component $c - (import "x" (type (sub resource))) - ) - (instance (instantiate $c)) - ) - "missing import named `x`") -(assert_invalid - (component - (type $x (resource (rep i32))) - (component $c - (import "x" (type (sub resource))) - (import "y" (type (sub resource))) - ) - (instance (instantiate $c (with "x" (type $x)))) - ) - "missing import named `y`") - -;; supply the wrong resource -(assert_invalid - (component - (type $x (resource (rep i32))) - (type $y (resource (rep i32))) - (component $c - (import "x" (type $t (sub resource))) - (import "y" (type (eq $t))) - ) - (instance (instantiate $c - (with "x" (type $x)) - (with "y" (type $y)) - )) - ) - "resource types are not the same") - -;; aliasing outer resources is ok -(component $A - (type $C (component - (import "x" (type $x (sub resource))) - - (type $y (component - (alias outer $C $x (type $my-x)) - (import "x" (type (eq $my-x))) - )) - - (import "y" (component (type $y))) - (export "z" (component (type $y))) - )) - - (type $t (resource (rep i32))) - - (alias outer $A $t (type $other-t)) - - (type (instance (export "t" (type (eq $t))))) - (type (component (export "t" (type (eq $t))))) - (type (component (import "t" (type (eq $t))))) -) - -;; aliasing beyond components, however, is not ok -(assert_invalid - (component $A - (type $t (resource (rep i32))) - (component (alias outer $A $t (type $foo))) - ) - "refers to resources not defined in the current component") -(assert_invalid - (component $A - (type $t (resource (rep i32))) - (type $u (record (field "x" (own $t)))) - (component (alias outer $A $u (type $foo))) - ) - "refers to resources not defined in the current component") -(assert_invalid - (component $A - (type $t (resource (rep i32))) - (type $u (borrow $t)) - (component (alias outer $A $u (type $foo))) - ) - "refers to resources not defined in the current component") -(assert_invalid - (component $A - (type $t (resource (rep i32))) - (type $u (component (export "a" (type (eq $t))))) - (component (alias outer $A $u (type $foo))) - ) - "refers to resources not defined in the current component") -(assert_invalid - (component $A - (type $t (resource (rep i32))) - (type $u (component (import "a" (type (eq $t))))) - (component (alias outer $A $u (type $foo))) - ) - "refers to resources not defined in the current component") - -(assert_invalid - (component - (component $X - (type $t (resource (rep i32))) - (export "t" (type $t)) - ) - (component $F - (import "x" (component (export "t" (type $t (sub resource))))) - ) - (instance $x1 (instantiate $X)) - (instance $f1 (instantiate $F (with "x" (instance $x1)))) - ) - "expected component, found instance") - -;; Show that two instantiations of the same component produce unique exported -;; resource types. -(assert_invalid - (component - (component $F - (type $t1 (resource (rep i32))) - (export "t1" (type $t1)) - ) - (instance $f1 (instantiate $F)) - (instance $f2 (instantiate $F)) - (alias export $f1 "t1" (type $t1)) - (alias export $f2 "t1" (type $t2)) - (component $T - (import "x" (type $x (sub resource))) - (import "y" (type (eq $x))) - ) - (instance $test - (instantiate $T (with "x" (type $t1)) (with "y" (type $t2)))) - ) - "type mismatch for import `y`") - -;; Show that re-exporting imported resources from an imported component doesn't -;; change the identity of that resource. -(component - (component $X - (type $t (resource (rep i32))) - (export "t" (type $t)) - ) - (component $F - (import "x" (instance $i (export "t" (type $t (sub resource))))) - (alias export $i "t" (type $t)) - (export "t" (type $t)) - ) - (instance $x1 (instantiate $X)) - (instance $f1 (instantiate $F (with "x" (instance $x1)))) - (instance $f2 (instantiate $F (with "x" (instance $x1)))) - (alias export $f1 "t" (type $t1)) - (alias export $f2 "t" (type $t2)) - (component $T - (import "x" (type $x (sub resource))) - (import "y" (type (eq $x))) - ) - (instance $test - (instantiate $T (with "x" (type $t1)) (with "y" (type $t2)))) -) - -(assert_invalid - (component (import "[static]" (func))) - "failed to find `.` character") - -;; validation of `[constructor]foo` -(assert_invalid - (component (import "[constructor]" (func))) - "not in kebab case") -(assert_invalid - (component (import "[constructor]a" (func))) - "should return one value") -(assert_invalid - (component (import "[constructor]a" (func (result u32)))) - "should return `(own $T)`") -(assert_invalid - (component - (import "b" (type $a (sub resource))) - (import "[constructor]a" (func (result (own $a))))) - "import name `[constructor]a` is not valid") -(assert_invalid - (component - (import "b" (type $a (sub resource))) - (import "[constructor]a" (func (result (own $a))))) - "function does not match expected resource name `b`") -(assert_invalid - (component - (import "b" (type $a (sub resource))) - (import "[constructor]a" (func (result (result(own $a)))))) - "function does not match expected resource name `b`") -(component definition - (import "a" (type $a (sub resource))) - (import "[constructor]a" (func (result (own $a))))) -(component definition - (import "a" (type $a (sub resource))) - (import "[constructor]a" (func (result (result (own $a)))))) -(component definition - (import "a" (type $a (sub resource))) - (import "[constructor]a" (func (result (result (own $a) (error string)))))) -(component definition - (import "a" (type $a (sub resource))) - (import "[constructor]a" (func (param "x" u32) (result (own $a))))) -(assert_invalid - (component - (import "a" (type $a (sub resource))) - (import "[constructor]a" (func (result string)))) - "function should return `(own $T)` or `(result (own $T))`") -(assert_invalid - (component - (import "a" (type $a (sub resource))) - (import "[constructor]a" (func (result (result string))))) - "function should return `(own $T)` or `(result (own $T))`") - -;; validation of `[method]a.b` -(assert_invalid - (component (import "[method]" (func))) - "failed to find `.` character") -(assert_invalid - (component (import "[method]a" (func))) - "failed to find `.` character") -(assert_invalid - (component (import "[method]a." (func))) - "not in kebab case") -(assert_invalid - (component (import "[method].a" (func))) - "not in kebab case") -(assert_invalid - (component (import "[method]a.b.c" (func))) - "not in kebab case") -(assert_invalid - (component (import "[method]a.b" (instance))) - "is not a func") -(assert_invalid - (component (import "[method]a.b" (func))) - "should have at least one argument") -(assert_invalid - (component (import "[method]a.b" (func (param "x" u32)))) - "should have a first argument called `self`") -(assert_invalid - (component (import "[method]a.b" (func (param "self" u32)))) - "should take a first argument of `(borrow $T)`") -(assert_invalid - (component - (import "b" (type $T (sub resource))) - (import "[method]a.b" (func (param "self" (borrow $T))))) - "does not match expected resource name") -(component definition - (import "a" (type $T (sub resource))) - (import "[method]a.b" (func (param "self" (borrow $T))))) - -;; validation of `[static]a.b` -(assert_invalid - (component (import "[static]" (func))) - "failed to find `.` character") -(assert_invalid - (component (import "[static]a" (func))) - "failed to find `.` character") -(assert_invalid - (component (import "[static]a." (func))) - "not in kebab case") -(assert_invalid - (component (import "[static].a" (func))) - "not in kebab case") -(assert_invalid - (component (import "[static]a.b.c" (func))) - "not in kebab case") -(assert_invalid - (component (import "[static]a.b" (instance))) - "is not a func") -(assert_invalid - (component (import "[static]a.b" (func))) - "static resource name is not known in this context") - -(component definition - (import "a" (type (sub resource))) - (import "[static]a.b" (func))) - -;; exports/imports are disjoint -(assert_invalid - (component - (import "b" (type $T (sub resource))) - (import "f" (func $f (param "self" (borrow $T)))) - (export "[method]b.foo" (func $f)) - ) - "resource used in function does not have a name in this context") - -(component - (component - (import "b" (type $T (sub resource))) - (import "f" (func $f (param "self" (borrow $T)))) - (export $c "c" (type $T)) - (export "[method]c.foo" (func $f) (func (param "self" (borrow $c)))) - ) -) - -;; imports aren't transitive -(assert_invalid - (component - (import "i" (instance $i - (export "t" (type (sub resource))) - )) - (alias export $i "t" (type $t)) - (import "[method]t.foo" (func (param "self" (borrow $t)))) - ) - "resource used in function does not have a name in this context") - -;; validation happens in a type context -(assert_invalid - (component - (type (component - (import "b" (type $T (sub resource))) - (import "[constructor]a" (func (result (own $T)))) - )) - ) - "function does not match expected resource name `b`") - -;; bag-of-exports validation -(assert_invalid - (component - (type $T (resource (rep i32))) - (core module $m (func (export "a") (result i32) unreachable)) - (core instance $i (instantiate $m)) - (func $f (result (own $T)) (canon lift (core func $i "a"))) - (instance - (export "a" (type $T)) - (export "[constructor]a" (func $f)) - ) - ) - "resource used in function does not have a name in this context") - -(component - (component $C) - (instance (instantiate $C (with "this is not kebab case" (component $C)))) -) - -;; Test that unused arguments to instantiation are not validated to have -;; appropriate types with respect to kebab naming conventions which require -;; functions/interfaces/etc. -(component - (component $C) - (instance (instantiate $C (with "[method]foo.bar" (component $C)))) -) - -;; thread a resource through a few layers -(component - (component $C - (import "in" (type $r (sub resource))) - (export "out" (type $r)) - ) - - (type $r (resource (rep i32))) - - (instance $c1 (instantiate $C (with "in" (type $r)))) - (instance $c2 (instantiate $C (with "in" (type $c1 "out")))) - (instance $c3 (instantiate $C (with "in" (type $c2 "out")))) - (instance $c4 (instantiate $C (with "in" (type $c3 "out")))) - (instance $c5 (instantiate $C (with "in" (type $c4 "out")))) - - (component $C2 - (import "in1" (type $r (sub resource))) - (import "in2" (type (eq $r))) - (import "in3" (type (eq $r))) - (import "in4" (type (eq $r))) - (import "in5" (type (eq $r))) - (import "in6" (type (eq $r))) - ) - - (instance (instantiate $C2 - (with "in1" (type $r)) - (with "in2" (type $c1 "out")) - (with "in3" (type $c2 "out")) - (with "in4" (type $c3 "out")) - (with "in5" (type $c4 "out")) - (with "in6" (type $c5 "out")) - )) -) - -;; exporting an instance type "freshens" resources -(assert_invalid - (component - (import "x" (instance $i - (type $i (instance - (export "r" (type (sub resource))) - )) - (export "a" (instance (type $i))) - (export "b" (instance (type $i))) - )) - - (component $C - (import "x" (type $x (sub resource))) - (import "y" (type (eq $x))) - ) - (instance (instantiate $C - (with "x" (type $i "a" "r")) - (with "y" (type $i "b" "r")) - )) - ) - "resource types are not the same") - -(component - (type (export "x") (component - (type $t' (instance - (export "r" (type (sub resource))) - )) - (export "t" (instance $t (type $t'))) - (alias export $t "r" (type $r)) - (type $t2' (instance - (export "r2" (type (eq $r))) - (export "r" (type (sub resource))) - )) - (export "t2" (instance (type $t2'))) - )) -) - -(component - (type (component - (type (instance - (export "bar" (type (sub resource))) - (export "[static]bar.a" (func)) - )) - (export "x" (instance (type 0))) - )) -) - -(assert_invalid - (component - (type $r (resource (rep i32))) - (type (func (result (borrow $r)))) - ) - "function result cannot contain a `borrow` type") -(assert_invalid - (component - (type $r (resource (rep i32))) - (type (func (result (list (borrow $r))))) - ) - "function result cannot contain a `borrow` type") -(assert_invalid - (component - (type $r (resource (rep i32))) - (type (func (result (option (borrow $r))))) - ) - "function result cannot contain a `borrow` type") -(assert_invalid - (component - (type $r (resource (rep i32))) - (type $t (record (field "f" (borrow $r)))) - (type (func (result (option (list $t))))) - ) - "function result cannot contain a `borrow` type") - -;; forms of canon builtins -(component - (type $r (resource (rep i32))) - (core func (canon resource.new $r)) - (canon resource.new $r (core func)) - (core func (canon resource.drop $r)) - (canon resource.drop $r (core func)) - (core func (canon resource.rep $r)) - (canon resource.rep $r (core func)) -) diff --git a/src/test/resources/spec-tests/wasm-tools/tags.wast b/src/test/resources/spec-tests/wasm-tools/tags.wast deleted file mode 100644 index 5c70d3a..0000000 --- a/src/test/resources/spec-tests/wasm-tools/tags.wast +++ /dev/null @@ -1,30 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_invalid - (component - (core module $m (func (export ""))) - (core instance $i (instantiate $m)) - (alias core export $i "" (core tag $t)) - ) - "export `` for core instance 0 is not a tag") - -(component - (core module $m (tag (export ""))) - (core instance $i (instantiate $m)) - (alias core export $i "" (core tag $t)) -) - -(component - (core module $m (tag (export ""))) - (core instance $i (instantiate $m)) - (core instance - (export "" (tag $i "")))) - -(assert_invalid - (component - (core module $m (func (export ""))) - (core instance $i (instantiate $m)) - (core instance - (export "" (tag 0))) - ) - "unknown tag 0") diff --git a/src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast b/src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast deleted file mode 100644 index d2971f8..0000000 --- a/src/test/resources/spec-tests/wasm-tools/type-export-restrictions.wast +++ /dev/null @@ -1,504 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -;; Test that unnamed types in various types are all detected - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (record (field "f" $t))) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (list $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (tuple $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (variant (case "c" $t))) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (option $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (result $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -;; Test that various types are all flagged as "requires a name" - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (list $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (enum "a")) - (type $f (list $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (flags "a")) - (type $f (list $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (variant (case "a"))) - (type $f (list $t)) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (resource (rep i32))) - (type $f (list (own $t))) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -;; Some types don't need names -(component - (type $t1 (tuple (tuple u32))) - (export "t1" (type $t1)) - - (type $t2 (option (tuple (list u8) (result (list u32) (error (option string)))))) - (export "t2" (type $t2)) - - (type $t3 u32) - (export "t3" (type $t3)) -) - -(component - (type $t' (record (field "f" u32))) - (export $t "t" (type $t')) - (type $t2 (record (field "x" $t))) - (export "t2" (type $t2)) -) - -;; imports are validated as well -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $t2 (record (field "f" $t))) - (import "x" (type (eq $t2))) - ) - "type not valid to be used as import") -(component - (type $t (record (field "f" u32))) - (import "t" (type $t' (eq $t))) - (type $t2 (record (field "f" $t'))) - (import "x" (type (eq $t2))) -) -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $t2 (record (field "f" $t))) - (import "x" (func (param "x" $t2))) - ) - "func not valid to be used as import") - -(assert_invalid - (component - (type $t (resource (rep i32))) - (export "t" (type $t)) - (type $f (list (own $t))) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -;; validate within the type context -(assert_invalid - (component - (type (component - (type $t (record (field "f" u32))) - (export "f" (func (param "x" $t))) - )) - ) - "func not valid to be used as export") -(assert_invalid - (component - (type (component - (type $t (record (field "f" u32))) - (type $f (record (field "t" $t))) - (export "f" (type (eq $f))) - )) - ) - "type not valid to be used as export") - -;; instances of unexported types is ok -(component - (type $t (record (field "f" u32))) - (type $f (record (field "t" $t))) - (instance - (export "f" (type $f)) - ) -) -;; .. but exporting them is not -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (record (field "t" $t))) - (instance $i - (export "f" (type $f)) - ) - (export "i" (instance $i)) - ) - "instance not valid to be used as export") - -;; Can't export a lifted function with unexported types -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (record (field "t" $t))) - - (core module $m (func $f (export "f") (param i32))) - (core instance $i (instantiate $m)) - (func $f (param "f" $f) (canon lift (core func $i "f"))) - (export "f" (func $f)) - ) - "func not valid to be used as export") - -;; Unexported instances don't work -(assert_invalid - (component - (type $t' (record (field "f" u32))) - (instance $i - (export "t" (type $t')) - ) - (alias export $i "t" (type $t)) - - (core module $m (func $f (export "f") (param i32))) - (core instance $i (instantiate $m)) - (func $f (param "f" $t) (canon lift (core func $i "f"))) - (export "f" (func $f)) - ) - "func not valid to be used as export") - -;; Even through a component it doesn't work -(assert_invalid - (component - (component $C - (type $t (record (field "f" u32))) - (export "t" (type $t)) - ) - (instance $i (instantiate $C)) - (alias export $i "t" (type $t)) - - (core module $m (func $f (export "f") (param i32))) - (core instance $i (instantiate $m)) - (func $f (param "f" $t) (canon lift (core func $i "f"))) - (export "f" (func $f)) - ) - "func not valid to be used as export") - -;; through exported instances is ok though -(component - (type $t' (record (field "f" u32))) - (instance $i' - (export "t" (type $t')) - ) - (export $i "i" (instance $i')) - (alias export $i "t" (type $t)) - - (core module $m (func $f (export "f") (param i32))) - (core instance $i (instantiate $m)) - (func $f (param "f" $t) (canon lift (core func $i "f"))) - (export "f" (func $f)) -) -(component - (component $C - (type $t (record (field "f" u32))) - (export "t" (type $t)) - ) - (instance $i' (instantiate $C)) - (export $i "i" (instance $i')) - (alias export $i "t" (type $t)) - - (core module $m (func $f (export "f") (param i32))) - (core instance $i (instantiate $m)) - (func $f (param "f" $t) (canon lift (core func $i "f"))) - (export "f" (func $f)) -) - -;; a type-ascribed export which is otherwise invalid can become valid -(component - (type $t (record (field "f" u32))) - - (core module $m (func (export "f") (param i32))) - (core instance $i (instantiate $m)) - (func $f (param "x" $t) (canon lift (core func $i "f"))) - - (export $t' "t" (type $t)) - (export "f" (func $f) (func (param "x" $t'))) -) - -;; imports can't reference exports -(assert_invalid - (component - (type $t1 (record (field "f" u32))) - (export $t2 "t1" (type $t1)) - (import "i" (func (result $t2))) - ) - "func not valid to be used as import") - -;; exports can reference imports -(component - (type $t1 (record (field "f" u32))) - (import "t1" (type $t2 (eq $t1))) - (export "e-t1" (type $t2)) -) -(component - (component - (type $t1 (record (field "f" u32))) - (import "t1" (type $t2 (eq $t1))) - (import "i" (func $f (result $t2))) - - (export "e-i" (func $f)) - ) -) - -;; outer aliases don't work for imports/exports -(assert_invalid - (component - (type $t1 (record (field "f" u32))) - (import "t1" (type $t2 (eq $t1))) - (component - (import "i" (func $f (result $t2))) - ) - ) - "func not valid to be used as import") -(assert_invalid - (component - (type $t1 (record (field "f" u32))) - (export $t2 "t1" (type $t1)) - (component - (core module $m (func (export "f") (result i32) unreachable)) - (core instance $i (instantiate $m)) - (func $f (export "i") (result $t2) (canon lift (core func $i "f"))) - ) - ) - "func not valid to be used as export") - -;; outer aliases work for components, modules, and resources -(component - (type $c (component)) - (type (component - (import "c" (component (type $c))) - )) - (component - (import "c" (component (type $c))) - ) - (type $i (instance)) - (type (component - (import "c" (instance (type $i))) - )) - - (type $r (resource (rep i32))) - (type (component - (import "r" (type (eq $r))) - )) -) - -;; reexport of an import is fine -(component - (component - (import "r" (func $r)) - (export "r2" (func $r)) - ) -) -(component - (type $t (record (field "f" u32))) - (import "r" (type $r (eq $t))) - (export "r2" (type $r)) -) -(component - (import "r" (instance $r)) - (export "r2" (instance $r)) -) -(component definition - (import "r" (type $r (sub resource))) - (export "r2" (type $r)) -) - -;; bag of exports cannot be exported by carrying through context that's not -;; otherwise exported -(assert_invalid - (component - (component $A - (type $t (record (field "f" u32))) - (export $t2 "t" (type $t)) - (core module $m (func (export "f") (result i32) unreachable)) - (core instance $i (instantiate $m)) - (func $f (result $t2) (canon lift (core func $i "f"))) - - (instance (export "i") - (export "f" (func $f)) - ) - ) - - (instance $a (instantiate $A)) - ;; this component only exports `f`, not the record type that is the result - ;; of `f`, so it should be invalid. - (export "a" (instance $a "i")) - ) - "instance not valid to be used as export") - -;; instance types can be "temporarily invalid", but not if they're attached -;; to a concrete component -(component - (type (instance - (type $t (record (field "f" u32))) - (export "f" (func (param "x" $t))) - )) -) -(assert_invalid - (component - (type $i (instance - (type $t (record (field "f" u32))) - (type $f (record (field "t" $t))) - (export "f" (type (eq $f))) - )) - (import "f" (instance (type $i))) - ) - "instance not valid to be used as import") - -;; allow for one import to refer to another -(component definition $C - (import "foo" (instance $i - (type $baz' (record (field "f" u32))) - (export "baz" (type $baz (eq $baz'))) - (type $bar' (record (field "baz" $baz))) - (export "bar" (type $bar (eq $bar'))) - )) - (alias export $i "bar" (type $bar)) - (import "bar" (instance - (alias outer $C $bar (type $bar')) - (export "bar" (type $bar (eq $bar'))) - (export "a" (func $f (result $bar))) - )) -) - -;; allow for one import to refer to another -(component - (type $r' (record (field "f" u32))) - (import "r" (type $r (eq $r'))) - (component $C - (type $r' (record (field "f" u32))) - (import "r" (type $r (eq $r'))) - (type $r2' (record (field "r" $r))) - (export "r2" (type $r2')) - ) - (instance $c (instantiate $C (with "r" (type $r)))) - (export "r2" (type $c "r2")) -) - -;; types are validated when they are exported -(assert_invalid - (component - (type $i (instance - (type $t (record (field "f" u32))) - (type $f (record (field "t" $t))) - (export "f" (type (eq $f))) - )) - (import "f" (type (eq $i))) - ) - "type not valid to be used as import") -(assert_invalid - (component - (type $i (instance - (type $t (record (field "f" u32))) - (type $f (record (field "t" $t))) - (export "f" (type (eq $f))) - )) - (export "f" (type $i)) - ) - "type not valid to be used as export") - -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (func (result $t))) - (import "f" (type (eq $f))) - ) - "type not valid to be used as import") -(assert_invalid - (component - (type $t (record (field "f" u32))) - (type $f (func (result $t))) - (export "f" (type $f)) - ) - "type not valid to be used as export") - -(component - (type (;0;) - (instance - (type (;0;) (enum "qux")) - (export (;1;) "baz" (type (eq 0))) - (type (;2;) (record (field "bar" 1) )) - (export (;3;) "foo" (type (eq 2))) - ) - ) - (import (interface "demo:component/types") (instance (;0;) (type 0))) - (component - (type (;0;) - (instance - (type (;0;) (enum "qux")) - (export (;1;) "baz" (type (eq 0))) - (type (;2;) (record (field "bar" 1) )) - (export (;3;) "foo" (type (eq 2))) - ) - ) - (import (interface "demo:component/types") (instance (;0;) (type 0))) - (component (;0;) - (type (;0;) (enum "qux")) - (import "import-type-baz" (type (;1;) (eq 0))) - (type (;2;) (record (field "bar" 1) )) - (import "import-type-bar" (type (;3;) (eq 2))) - (export (;4;) "foo" (type 3)) - ) - (instance (;1;) (instantiate 0 - (with "import-type-baz" (type 0 "baz")) - (with "import-type-bar" (type 0 "foo")) - ) - ) - (export (;0;) (interface "demo:component/types") (instance 1)) - ) - (instance (instantiate 0 (with "demo:component/types" (instance 0)))) - (export (interface "demo:component/types") (instance 1 "demo:component/types")) -) diff --git a/src/test/resources/spec-tests/wasm-tools/types.wast b/src/test/resources/spec-tests/wasm-tools/types.wast deleted file mode 100644 index 5df1ec9..0000000 --- a/src/test/resources/spec-tests/wasm-tools/types.wast +++ /dev/null @@ -1,374 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_invalid - (component - (type $t (instance)) - (import "a" (func (type $t))) - ) - "type index 0 is not a function type") - -(assert_invalid - (component - (core type $t (func)) - (import "a" (core module (type $t))) - ) - "core type index 0 is not a module type") - -(assert_invalid - (component - (type $t (func)) - (import "a" (instance (type $t))) - ) - "type index 0 is not an instance type") - -(assert_invalid - (component - (type $t (func)) - (type (component - (import "a" (instance (type $t))) - )) - ) - "type index 0 is not an instance type") - -(assert_invalid - (component - (core type $t (func)) - (type (component - (import "a" (core module (type $t))) - )) - ) - "core type index 0 is not a module type") - -(assert_invalid - (component - (type $t (instance)) - (type (component - (import "a" (func (type $t))) - )) - ) - "type index 0 is not a function type") - -(assert_invalid - (component - (export "a" (core module 0)) - ) - "module index out of bounds") - -(assert_invalid - (component - (export "a" (instance 0)) - ) - "instance index out of bounds") - -(assert_invalid - (component - (core type (module - (export "a" (func (type 0))) - )) - ) - "type index out of bounds") - -(assert_invalid - (component - (core type (module - (export "a" (func)) - (export "a" (func)) - )) - ) - "export name `a` already defined") - -(assert_invalid - (component - (core type (module - (import "" "" (func)) - (import "" "" (func)) - )) - ) - "duplicate import name") - -(assert_invalid - (component - (core type (module - (import "" "" (memory 70000)) - )) - ) - "memory size must be at most") - -(assert_invalid - (component - (type (component - (export "a" (func (type 0))) - )) - ) - "type index out of bounds") - -(assert_invalid - (component - (type (component - (export "a" (func)) - (export "A" (func)) - )) - ) - "export name `A` conflicts with previous name `a`") - -(assert_invalid - (component - (type (component - (import "A" (func)) - (import "a" (func)) - )) - ) - "import name `a` conflicts with previous name `A`") - -(assert_malformed - (component quote - "(component $c (core type $t (module (alias outer $c $t (type)))))" - ) - "unknown core type") - -(assert_invalid - (component - (core type (module - (alias outer 1 0 (type)) - )) - ) - "type index out of bounds") - -(component $c - (core type $f (func)) - (core type $t (module - (alias outer $c $f (type)) - )) -) - -(assert_malformed - (component quote - "(component $c (type $t (component (alias outer $c $t (type)))))" - ) - "unknown type") - -(assert_invalid - (component - (type (component - (alias outer 1 0 (type)) - )) - ) - "type index out of bounds") - -(assert_invalid - (component $c - (type $f (func)) - (type $t (component - (alias outer 100 0 (type)) - )) - ) - "invalid outer alias count of 100") - -(assert_invalid - (component $c - (type $f (func)) - (type $t (component - (core type (module - (export "" (func)) - (export "" (func)) - )) - )) - ) - "name `` already defined") - -(assert_invalid - (component - (type (instance - (export "" (func (type 0))) - )) - ) - "type index out of bounds") - -(assert_invalid - (component - (type (instance - (export "foo-BAR-baz" (func)) - (export "FOO-bar-BAZ" (func)) - )) - ) - "export name `FOO-bar-BAZ` conflicts with previous name `foo-BAR-baz`") - -(assert_malformed - (component quote - "(component $c (type $t (instance (alias outer $c $t (type)))))" - ) - "unknown type") - -(assert_invalid - (component - (type (instance - (alias outer 1 0 (type)) - )) - ) - "type index out of bounds") - -(assert_invalid - (component $c - (type $f (func)) - (type $t (instance - (alias outer 100 0 (type)) - )) - ) - "invalid outer alias count of 100") - -(assert_invalid - (component $c - (type $f (func)) - (type $t (instance - (core type (module - (export "" (func)) - (export "" (func)) - )) - )) - ) - "name `` already defined") - -(assert_invalid - (component $c - (type $f (func (param "" string))) - ) - "function parameter name cannot be empty") - -(component - (type $t (func (result (tuple (list u8) u32)))) -) - -(component $C - (core type $t (func)) - (core type (module - (alias outer $C $t (type $a)) - (import "" "" (func (type $a))) - )) -) - -(component $C - (component $C2 - (core type $t (func)) - (core type (module - (alias outer $C2 $t (type $a)) - (import "" "" (func (type $a))) - )) - ) -) - -(component $C - (core type $t (func)) - (component $C2 - (core type (module - (alias outer $C $t (type $a)) - (import "" "" (func (type $a))) - )) - ) -) - -(component - (type (instance - (type string) - (export "a" (type (eq 0))) - )) -) - -(component - (type (component - (type string) - (import "a" (type (eq 0))) - (export "b" (type (eq 0))) - )) -) - -(assert_invalid - (component - (type (variant)) - ) - "variant type must have at least one case") - -(assert_invalid - (component - (type (enum)) - ) - "enum type must have at least one variant") - -(assert_invalid - (component - (type (record)) - ) - "record type must have at least one field") - -(assert_invalid - (component - (type (flags)) - ) - "flags must have at least one entry") - -(assert_invalid - (component - (type (tuple)) - ) - "tuple type must have at least one type") - -(component $c - (core type $f (func)) - (component $c2 - (core type $t (module - (alias outer $c $f (type)) - )) - ) -) - -(assert_invalid - (component - (type (flags - "f1" - "f2" - "f3" - "f4" - "f5" - "f6" - "f7" - "f8" - "f9" - "f10" - "f11" - "f12" - "f13" - "f14" - "f15" - "f16" - "f17" - "f18" - "f19" - "f20" - "f21" - "f22" - "f23" - "f24" - "f25" - "f26" - "f27" - "f28" - "f29" - "f30" - "f31" - "f32" - "f33" - )) - ) - "cannot have more than 32 flags") - -(assert_invalid - (component - (core type $t (module)) - (core type (func (param (ref $t)))) - ) - "type index 0 is a module type") - -(assert_invalid - (component - (core type (func (param (ref 100)))) - ) - "type index out of bounds") diff --git a/src/test/resources/spec-tests/wasm-tools/very-nested.wast b/src/test/resources/spec-tests/wasm-tools/very-nested.wast deleted file mode 100644 index 42c5aed..0000000 --- a/src/test/resources/spec-tests/wasm-tools/very-nested.wast +++ /dev/null @@ -1,1954 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_invalid - (component $$esl - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "00AGG554M******+*****e 4$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "anonmm-x23foinas-ASDOJASD") - ) - (component - (export "c t.****0*********") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "agds-ASF-TT-yy") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "0+AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00A$qq") - ) - (component - (export "c t.*************") - (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "15AG:GG!le*$$qq") - ) - (component - (export "c t.*") - (component - (export "c 3@EGGGG$qq**") - (export "bsdew2-sdbsdb") - ) - (component - (export "c t.********)*eleo &m Nx2GGGGle*$$qq") - ) - (component - (export "c 1.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "0*************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "00AGG554M******+*****e 4$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "anonmm-x23foinas-ASDOJASD") - ) - (component - (export "c t.****0*********") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "agds-ASF-TT-yy") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "0+AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00A$qq") - ) - (component - (export "c t.*************") - (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "15AG:GG!le*$$qq") - ) - (component - (export "c .t*") - (component - (export "c 3@EGGGG$qq**") - (export "bsdew2-sdbsdb") - ) - (component - (export "c t.********)*eleo &m Nx2GGGGle*$$qq") - ) - (component - (export "c 1.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle '$$qq") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c *****") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "00AGG554M******+*****e 4$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "anonmm-x23foinas-ASDOJASD") - ) - (component - (export "c t.****0*********") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "agds-ASF-TT-yy") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "0+AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00A$qq") - ) - (component - (export "c t.*************") - (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "15AG:GG!le*$$qq") - ) - (component - (export "c t.*") - (component - (export "c 3@EGGGG$qq**") - (export "bsdew2-sdbsdb") - ) - (component - (export "c t.********)*eleo &m Nx2GGGGle*$$qq") - ) - (component - (export "c 1.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "0*************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "00AGG554M******+*****e 4$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "anonmm-x23foinas-ASDOJASD") - ) - (component - (export "c t.****0*********") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "agds-ASF-TT-yy") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "0+AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00A$qq") - ) - (component - (export "c t.*************") - (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "15AG:GG!le*$$qq") - ) - (component - (export "c .t*") - (component - (export "c 3@EGGGG$qq**") - (export "bsdew2-sdbsdb") - ) - (component - (export "c t.********)*eleo &m Nx2GGGGle*$$qq") - ) - (component - (export "c 1.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "sdg-q12") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "jsjsjs") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle '$$qq") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 1.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E***0AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle '$$qq") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 1.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E**************777777777777777777777777777777777777777777777777777777777777771.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E***0AG") - (component - (export "c 3@EGG*****+*****e $$qq") - ) - (component - (export "q**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c=t.*************") - (export "00AG") - (component - (export "alskgn-mbnaj4-a33i5nf") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "afhinds-T39OIDN-f1jsj11") - (import "sf-gqo3ngin23ogin13g-bvcad") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle '$$qq") - ) - (component - (export "q") - ) - (component - (export "b 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 0.*************") - (export "00AGGWGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*********GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E************[******") - (import "bsdew2-sdbsdb") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") - (import "00e*$$qq") - ) - (component - (export "EGG-y-GG-qq") - (export "00AGGG.Gle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "bsdew2-sdbsdb") - ) - (component - (export "c 1.*************") - (export "00AGGGGle A*$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") - (export "dojgn-ejs9-nd188") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - (component - (export "q") - ) - (component - (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") - ) - (component - (export "q") - ) - (component - (export "c 3@E*******************") - (import "00CGGGGle*$$qq") - ) - (component - (export "c t.*************") - (export "00AGGGGle *$$qq") - ) - (component) - ) - ) - "conflicts with previous name") - -(assert_invalid - (component - (type $m0 (component)) - (type $m1 (component - (import "i1" (component (type $m0))) - (import "i2" (component (type $m0))) - (import "i3" (component (type $m0))) - (import "i4" (component (type $m0))) - (import "i5" (component (type $m0))) - (import "i6" (component (type $m0))) - (import "i7" (component (type $m0))) - (import "i8" (component (type $m0))) - (import "i9" (component (type $m0))) - (import "i10" (component (type $m0))) - )) - (type $m2 (component - (import "i1" (component (type $m1))) - (import "i2" (component (type $m1))) - (import "i3" (component (type $m1))) - (import "i4" (component (type $m1))) - (import "i5" (component (type $m1))) - (import "i6" (component (type $m1))) - (import "i7" (component (type $m1))) - (import "i8" (component (type $m1))) - (import "i9" (component (type $m1))) - (import "i10" (component (type $m1))) - )) - (type $m3 (component - (import "i1" (component (type $m2))) - (import "i2" (component (type $m2))) - (import "i3" (component (type $m2))) - (import "i4" (component (type $m2))) - (import "i5" (component (type $m2))) - (import "i6" (component (type $m2))) - (import "i7" (component (type $m2))) - (import "i8" (component (type $m2))) - (import "i9" (component (type $m2))) - (import "i10" (component (type $m2))) - )) - (type $m4 (component - (import "i1" (component (type $m3))) - (import "i2" (component (type $m3))) - (import "i3" (component (type $m3))) - (import "i4" (component (type $m3))) - (import "i5" (component (type $m3))) - (import "i6" (component (type $m3))) - (import "i7" (component (type $m3))) - (import "i8" (component (type $m3))) - (import "i9" (component (type $m3))) - (import "i10" (component (type $m3))) - )) - (type $m5 (component - (import "i1" (component (type $m4))) - (import "i2" (component (type $m4))) - (import "i3" (component (type $m4))) - (import "i4" (component (type $m4))) - (import "i5" (component (type $m4))) - (import "i6" (component (type $m4))) - (import "i7" (component (type $m4))) - (import "i8" (component (type $m4))) - (import "i9" (component (type $m4))) - (import "i10" (component (type $m4))) - )) - (type $m6 (component - (import "i1" (component (type $m5))) - (import "i2" (component (type $m5))) - (import "i3" (component (type $m5))) - (import "i4" (component (type $m5))) - (import "i5" (component (type $m5))) - (import "i6" (component (type $m5))) - (import "i7" (component (type $m5))) - (import "i8" (component (type $m5))) - (import "i9" (component (type $m5))) - (import "i10" (component (type $m5))) - )) - (type $m7 (component - (import "i1" (component (type $m6))) - (import "i2" (component (type $m6))) - (import "i3" (component (type $m6))) - (import "i4" (component (type $m6))) - (import "i5" (component (type $m6))) - (import "i6" (component (type $m6))) - (import "i7" (component (type $m6))) - (import "i8" (component (type $m6))) - (import "i9" (component (type $m6))) - (import "i10" (component (type $m6))) - )) - (type $m8 (component - (import "i1" (component (type $m7))) - (import "i2" (component (type $m7))) - (import "i3" (component (type $m7))) - (import "i4" (component (type $m7))) - (import "i5" (component (type $m7))) - (import "i6" (component (type $m7))) - (import "i7" (component (type $m7))) - (import "i8" (component (type $m7))) - (import "i9" (component (type $m7))) - (import "i10" (component (type $m7))) - )) - (type $m9 (component - (import "i1" (component (type $m8))) - (import "i2" (component (type $m8))) - (import "i3" (component (type $m8))) - (import "i4" (component (type $m8))) - (import "i5" (component (type $m8))) - (import "i6" (component (type $m8))) - (import "i7" (component (type $m8))) - (import "i8" (component (type $m8))) - (import "i9" (component (type $m8))) - (import "i10" (component (type $m8))) - )) - - (type $m (component - (import "a" (component (type $m9))) - )) - (import "a" (component $a (type $m9))) - (import "b" (component $b (type $m))) - (instance (instantiate $b (with "a" (component $a)))) - ) - "effective type size exceeds the limit") - -(assert_invalid - (component - (component $m0) - (component $m1 - (instance (export "e0") (instantiate $m0)) - (instance (export "e1") (instantiate $m0)) - (instance (export "e2") (instantiate $m0)) - (instance (export "e3") (instantiate $m0)) - (instance (export "e4") (instantiate $m0)) - (instance (export "e5") (instantiate $m0)) - (instance (export "e6") (instantiate $m0)) - (instance (export "e7") (instantiate $m0)) - (instance (export "e8") (instantiate $m0)) - (instance (export "e9") (instantiate $m0)) - ) - (component $m2 - (instance (export "e0") (instantiate $m1)) - (instance (export "e1") (instantiate $m1)) - (instance (export "e2") (instantiate $m1)) - (instance (export "e3") (instantiate $m1)) - (instance (export "e4") (instantiate $m1)) - (instance (export "e5") (instantiate $m1)) - (instance (export "e6") (instantiate $m1)) - (instance (export "e7") (instantiate $m1)) - (instance (export "e8") (instantiate $m1)) - (instance (export "e9") (instantiate $m1)) - ) - (component $m3 - (instance (export "e0") (instantiate $m2)) - (instance (export "e1") (instantiate $m2)) - (instance (export "e2") (instantiate $m2)) - (instance (export "e3") (instantiate $m2)) - (instance (export "e4") (instantiate $m2)) - (instance (export "e5") (instantiate $m2)) - (instance (export "e6") (instantiate $m2)) - (instance (export "e7") (instantiate $m2)) - (instance (export "e8") (instantiate $m2)) - (instance (export "e9") (instantiate $m2)) - ) - (component $m4 - (instance (export "e0") (instantiate $m3)) - (instance (export "e1") (instantiate $m3)) - (instance (export "e2") (instantiate $m3)) - (instance (export "e3") (instantiate $m3)) - (instance (export "e4") (instantiate $m3)) - (instance (export "e5") (instantiate $m3)) - (instance (export "e6") (instantiate $m3)) - (instance (export "e7") (instantiate $m3)) - (instance (export "e8") (instantiate $m3)) - (instance (export "e9") (instantiate $m3)) - ) - (component $m5 - (instance (export "e0") (instantiate $m4)) - (instance (export "e1") (instantiate $m4)) - (instance (export "e2") (instantiate $m4)) - (instance (export "e3") (instantiate $m4)) - (instance (export "e4") (instantiate $m4)) - (instance (export "e5") (instantiate $m4)) - (instance (export "e6") (instantiate $m4)) - (instance (export "e7") (instantiate $m4)) - (instance (export "e8") (instantiate $m4)) - (instance (export "e9") (instantiate $m4)) - ) - (component $m6 - (instance (export "e0") (instantiate $m5)) - (instance (export "e1") (instantiate $m5)) - (instance (export "e2") (instantiate $m5)) - (instance (export "e3") (instantiate $m5)) - (instance (export "e4") (instantiate $m5)) - (instance (export "e5") (instantiate $m5)) - (instance (export "e6") (instantiate $m5)) - (instance (export "e7") (instantiate $m5)) - (instance (export "e8") (instantiate $m5)) - (instance (export "e9") (instantiate $m5)) - ) - (component $m7 - (instance (export "e0") (instantiate $m6)) - (instance (export "e1") (instantiate $m6)) - (instance (export "e2") (instantiate $m6)) - (instance (export "e3") (instantiate $m6)) - (instance (export "e4") (instantiate $m6)) - (instance (export "e5") (instantiate $m6)) - (instance (export "e6") (instantiate $m6)) - (instance (export "e7") (instantiate $m6)) - (instance (export "e8") (instantiate $m6)) - (instance (export "e9") (instantiate $m6)) - ) - ) - "effective type size exceeds the limit") - -(assert_invalid - (component - ;; size(t0) == 1 - (type $t0 (flags "x")) - - ;; size(t1) == 10 - (type $t1 (record - (field "f0" $t0) - (field "f1" $t0) - (field "f2" $t0) - (field "f3" $t0) - (field "f4" $t0) - (field "f5" $t0) - (field "f6" $t0) - (field "f7" $t0) - (field "f8" $t0) - (field "f9" $t0) - )) - - ;; size(t2) == 100 - (type $t2 (record - (field "f0" $t1) - (field "f1" $t1) - (field "f2" $t1) - (field "f3" $t1) - (field "f4" $t1) - (field "f5" $t1) - (field "f6" $t1) - (field "f7" $t1) - (field "f8" $t1) - (field "f9" $t1) - )) - - ;; size(t3) == 1000 - (type $t3 (record - (field "f0" $t2) - (field "f1" $t2) - (field "f2" $t2) - (field "f3" $t2) - (field "f4" $t2) - (field "f5" $t2) - (field "f6" $t2) - (field "f7" $t2) - (field "f8" $t2) - (field "f9" $t2) - )) - - ;; size(t4) == 10000 - (type $t4 (record - (field "f0" $t3) - (field "f1" $t3) - (field "f2" $t3) - (field "f3" $t3) - (field "f4" $t3) - (field "f5" $t3) - (field "f6" $t3) - (field "f7" $t3) - (field "f8" $t3) - (field "f9" $t3) - )) - - ;; size(t5) == 100000 - (type $t5 (record - (field "f0" $t4) - (field "f1" $t4) - (field "f2" $t4) - (field "f3" $t4) - (field "f4" $t4) - (field "f5" $t4) - (field "f6" $t4) - (field "f7" $t4) - (field "f8" $t4) - (field "f9" $t4) - )) - - (type $f (func - (param "a" $t5) - (param "b" $t5) - (param "c" $t5) - (param "d" $t5) - (param "e" $t5) - (param "f" $t5) - (param "g" $t5) - (param "h" $t5) - (param "i" $t5) - (param "j" $t5) - )) - ) - "effective type size exceeds the limit") - -(assert_malformed - (component quote - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - "(component(component(component(component(component(component(component" - ) - "nesting too deep") diff --git a/src/test/resources/spec-tests/wasm-tools/virtualize.wast b/src/test/resources/spec-tests/wasm-tools/virtualize.wast deleted file mode 100644 index d60b73b..0000000 --- a/src/test/resources/spec-tests/wasm-tools/virtualize.wast +++ /dev/null @@ -1,119 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(component - (core module $libc - (memory (export "mem") 0) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - unreachable - ) - ) - (core instance $libc (instantiate $libc)) - - (component $child - (import "wasi-file" (instance $wasi-file - (export "read" (func (param "count" u32) (result (list u8)))) - (export "write" (func (param "bytes" (list u8)) (result u32))) - )) - - (core instance $libc (instantiate $libc)) - - (core module $m - (import "wasi-file" "read" (func $read (param i32 i32))) - (func $play (export "play") - unreachable - ) - ) - - (core func $wasi_file_read - (canon lower (func $wasi-file "read") - (memory $libc "mem") - (realloc (func $libc "realloc")) - ) - ) - - (core instance $i (instantiate $m - (with "wasi-file" (instance - (export "read" (func $wasi_file_read)) - )) - )) - - (func (export "play") - (canon lift (core func $i "play")) - ) - ) - - (component $virtualize - (import "wasi-file" (instance $wasi-file - (export "read" (func (param "len" u32) (result (list u8)))) - (export "write" (func (param "buf" (list u8)) (result u32))) - )) - (export "read" (func $wasi-file "read")) - (export "write" (func $wasi-file "write")) - ) - - (component - (type $WasiFile (instance - (export "read" (func (param "len" u32) (result (list u8)))) - (export "write" (func (param "buf" (list u8)) (result u32))) - )) - (import "wasi-file" (instance $real-wasi (type $WasiFile))) - (import "virtualize" (component $VIRTUALIZE - (import "wasi-file" (instance (type $WasiFile))) - (export "read" (func (param "len" u32) (result (list u8)))) - (export "write" (func (param "buf" (list u8)) (result u32))) - )) - (import "child" (component $CHILD - (import "wasi-file" (instance (type $WasiFile))) - (export "play" (func)) - ) - ) - - (instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi-file" (instance $real-wasi)))) - (instance $child (instantiate $CHILD (with "wasi-file" (instance $virt-wasi)))) - - (export "work" (func $child "play")) - ) - - (component - (type $WasiFile (instance - (export "read" (func (param "len" u32) (result (list u8)))) - (export "write" (func (param "buf" (list u8)) (result u32))) - )) - (import "wasi-file" (instance $real-wasi (type $WasiFile))) - - (core instance $libc (instantiate $libc)) - - (core module $CHILD - (import "wasi-file" "read" (func $wasi-file (param i32 i32))) - (func $play (export "play") - unreachable - ) - ) - - (core module $VIRTUALIZE - (import "wasi-file" "read" (func (param i32 i32))) - (func (export "read") (param i32 i32) - unreachable - ) - (func (export "write") (param i32 i32 i32) - unreachable - ) - ) - - (core func $real-wasi-read - (canon lower (func $real-wasi "read") - (memory $libc "mem") - (realloc (func $libc "realloc")) - ) - ) - - (core instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi-file" (instance (export "read" (func $real-wasi-read)))))) - (core instance $child (instantiate $CHILD (with "wasi-file" (instance $virt-wasi)))) - (func (export "work") - (canon lift (core func $child "play") - (memory $libc "mem") - (realloc (func $libc "realloc")) - ) - ) - ) -) diff --git a/src/test/resources/spec-tests/wasm-tools/wrong-order.wast b/src/test/resources/spec-tests/wasm-tools/wrong-order.wast deleted file mode 100644 index 098fc41..0000000 --- a/src/test/resources/spec-tests/wasm-tools/wrong-order.wast +++ /dev/null @@ -1,11 +0,0 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % - -(assert_malformed - (module binary - "\00asm\01\00\00\00" - - "\01\01\00" ;; type section, 1 byte, 0 entries - "\0b\01\00" ;; data section, 1 byte, 0 entries - "\01\01\00" ;; type section, 1 byte, 0 entries - ) - "section out of order") diff --git a/src/test/resources/spec-tests/wasmtime/adapter.wast b/src/test/resources/spec-tests/wasmtime/adapter.wast deleted file mode 100644 index 8432d58..0000000 --- a/src/test/resources/spec-tests/wasmtime/adapter.wast +++ /dev/null @@ -1,137 +0,0 @@ -;;! multi_memory = true - -;; basic function lifting -(component - (core module $m - (func (export "")) - ) - (core instance $i (instantiate $m)) - - (func (export "thunk") - (canon lift (core func $i "")) - ) -) - -;; use an aliased type -(component $c - (core module $m - (func (export "")) - ) - (core instance $i (instantiate $m)) - - (type $to_alias (func)) - (alias outer $c $to_alias (type $alias)) - - (func (export "thunk") (type $alias) - (canon lift (core func $i "")) - ) -) - -;; test out some various canonical abi -(component $c - (core module $m - (func (export "") (param i32 i32)) - (memory (export "memory") 1) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - unreachable) - ) - (core instance $i (instantiate $m)) - - (func (export "thunk") (param "a" string) - (canon lift - (core func $i "") - (memory $i "memory") - (realloc (func $i "realloc")) - ) - ) - - (func (export "thunk8") (param "a" string) - (canon lift - (core func $i "") - string-encoding=utf8 - (memory $i "memory") - (realloc (func $i "realloc")) - ) - ) - - (func (export "thunk16") (param "a" string) - (canon lift - (core func $i "") - string-encoding=utf16 - (memory $i "memory") - (realloc (func $i "realloc")) - ) - ) - - (func (export "thunklatin16") (param "a" string) - (canon lift - (core func $i "") - string-encoding=latin1+utf16 - (memory $i "memory") - (realloc (func $i "realloc")) - ) - ) -) - -;; lower something then immediately lift it -(component $c - (import "host-return-two" (func $f (result u32))) - - (core func $f_lower - (canon lower (func $f)) - ) - (func $f2 (result s32) - (canon lift (core func $f_lower)) - ) - (export "f" (func $f2)) -) - -;; valid, but odd -(component - (core module $m (func (export ""))) - (core instance $m (instantiate $m)) - - (func $f1 (canon lift (core func $m ""))) - (core func $f2 (canon lower (func $f1))) -) -(assert_trap - (component - (core module $m (func (export ""))) - (core instance $m (instantiate $m)) - - (func $f1 (canon lift (core func $m ""))) - (core func $f2 (canon lower (func $f1))) - - (core module $m2 - (import "" "" (func $f)) - (func $start - call $f) - (start $start) - ) - (core instance (instantiate $m2 - (with "" (instance (export "" (func $f2)))) - )) - ) - "cannot enter component instance") - -;; fiddling with 0-sized lists -(component $c - (core module $m - (func (export "x") (param i32 i32)) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - i32.const -1) - (memory (export "memory") 0) - ) - (core instance $m (instantiate $m)) - (type $t' (result)) - (export $t "t" (type $t')) - (func $f (param "a" (list $t)) - (canon lift - (core func $m "x") - (realloc (func $m "realloc")) - (memory $m "memory") - ) - ) - (export "empty-list" (func $f)) -) -(assert_trap (invoke "empty-list" (list.const)) "realloc return: beyond end of memory") diff --git a/src/test/resources/spec-tests/wasmtime/aliasing.wast b/src/test/resources/spec-tests/wasmtime/aliasing.wast deleted file mode 100644 index ad18f93..0000000 --- a/src/test/resources/spec-tests/wasmtime/aliasing.wast +++ /dev/null @@ -1,29 +0,0 @@ -(component - (component - (component - (component) - (instance (instantiate 0)) - (export "a" (instance 0)) - ) - (instance (instantiate 0)) - (export "a" (instance 0)) - ) - - (instance (instantiate 0)) ;; instance 0 - (alias export 0 "a" (instance)) ;; instance 1 - (export "a" (instance 1)) ;; instance 2 - (alias export 2 "a" (instance)) ;; instance 3 - (export "inner-a" (instance 3)) ;; instance 4 -) - -(component - (component - (core module) - (export "a" (core module 0)) - ) - - (instance (instantiate 0)) - (alias export 0 "a" (core module)) ;; module 0 - (export "a" (core module 0)) ;; module 1 - (core instance (instantiate 1)) -) diff --git a/src/test/resources/spec-tests/wasmtime/fused.wast b/src/test/resources/spec-tests/wasmtime/fused.wast deleted file mode 100644 index 87fe846..0000000 --- a/src/test/resources/spec-tests/wasmtime/fused.wast +++ /dev/null @@ -1,1391 +0,0 @@ -;;! multi_memory = true - -;; smoke test with no arguments and no results -(component - (component $a - (core module $m - (func (export "")) - ) - (core instance $m (instantiate $m)) - (func (export "foo") (canon lift (core func $m ""))) - ) - (instance $a (instantiate $a)) - - (component $c - (import "a" (instance $a - (export "foo" (func)) - )) - - (core func $foo (canon lower (func $a "foo"))) - (core module $m2 - (import "" "" (func)) - (start 0) - ) - (core instance $m2 (instantiate $m2 (with "" (instance (export "" (func $foo)))))) - ) - - (instance $c (instantiate $c (with "a" (instance $a)))) -) - -;; boolean parameters -(component - (component $a - (core module $m - (func (export "assert_true") (param i32) - local.get 0 - i32.const 1 - i32.eq - i32.eqz - if unreachable end - ) - (func (export "assert_false") (param i32) - local.get 0 - if unreachable end - ) - (func (export "ret-bool") (param i32) (result i32) - local.get 0 - ) - ) - (core instance $m (instantiate $m)) - (func (export "assert-true") (param "a" bool) (canon lift (core func $m "assert_true"))) - (func (export "assert-false") (param "a" bool) (canon lift (core func $m "assert_false"))) - (func (export "ret-bool") (param "a" u32) (result bool) (canon lift (core func $m "ret-bool"))) - ) - (instance $a (instantiate $a)) - - (component $c - (import "a" (instance $a - (export "assert-true" (func (param "a" bool))) - (export "assert-false" (func (param "a" bool))) - (export "ret-bool" (func (param "a" u32) (result bool))) - )) - - (core func $assert_true (canon lower (func $a "assert-true"))) - (core func $assert_false (canon lower (func $a "assert-false"))) - (core func $ret_bool (canon lower (func $a "ret-bool"))) - - (core module $m2 - (import "" "assert-true" (func $assert_true (param i32))) - (import "" "assert-false" (func $assert_false (param i32))) - (import "" "ret-bool" (func $ret_bool (param i32) (result i32))) - - (func $start - (call $assert_true (i32.const 1)) - (call $assert_true (i32.const 2)) - (call $assert_true (i32.const -1)) - (call $assert_false (i32.const 0)) - - (if (i32.ne (call $ret_bool (i32.const 1)) (i32.const 1)) - (then (unreachable))) - (if (i32.ne (call $ret_bool (i32.const 2)) (i32.const 1)) - (then (unreachable))) - (if (i32.ne (call $ret_bool (i32.const -1)) (i32.const 1)) - (then (unreachable))) - (if (i32.ne (call $ret_bool (i32.const 0)) (i32.const 0)) - (then (unreachable))) - ) - (start $start) - ) - (core instance $m2 (instantiate $m2 - (with "" (instance - (export "assert-true" (func $assert_true)) - (export "assert-false" (func $assert_false)) - (export "ret-bool" (func $ret_bool)) - )) - )) - ) - - (instance $c (instantiate $c (with "a" (instance $a)))) -) - -;; lots of parameters and results -(component - (component $a - (type $roundtrip (func - ;; 20 u32 params - (param "a1" u32) (param "a2" u32) (param "a3" u32) (param "a4" u32) (param "a5" u32) - (param "a6" u32) (param "a7" u32) (param "a8" u32) (param "a9" u32) (param "a10" u32) - (param "a11" u32) (param "a12" u32) (param "a13" u32) (param "a14" u32) (param "a15" u32) - (param "a16" u32) (param "a17" u32) (param "a18" u32) (param "a19" u32) (param "a20" u32) - - ;; 10 u32 results - (result (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) - )) - - (core module $m - (memory (export "memory") 1) - (func (export "roundtrip") (param $src i32) (result i32) - (local $dst i32) - (if (i32.ne (local.get $src) (i32.const 16)) - (then (unreachable))) - - (if (i32.ne (i32.load offset=0 (local.get $src)) (i32.const 1)) (then (unreachable))) - (if (i32.ne (i32.load offset=4 (local.get $src)) (i32.const 2)) (then (unreachable))) - (if (i32.ne (i32.load offset=8 (local.get $src)) (i32.const 3)) (then (unreachable))) - (if (i32.ne (i32.load offset=12 (local.get $src)) (i32.const 4)) (then (unreachable))) - (if (i32.ne (i32.load offset=16 (local.get $src)) (i32.const 5)) (then (unreachable))) - (if (i32.ne (i32.load offset=20 (local.get $src)) (i32.const 6)) (then (unreachable))) - (if (i32.ne (i32.load offset=24 (local.get $src)) (i32.const 7)) (then (unreachable))) - (if (i32.ne (i32.load offset=28 (local.get $src)) (i32.const 8)) (then (unreachable))) - (if (i32.ne (i32.load offset=32 (local.get $src)) (i32.const 9)) (then (unreachable))) - (if (i32.ne (i32.load offset=36 (local.get $src)) (i32.const 10)) (then (unreachable))) - (if (i32.ne (i32.load offset=40 (local.get $src)) (i32.const 11)) (then (unreachable))) - (if (i32.ne (i32.load offset=44 (local.get $src)) (i32.const 12)) (then (unreachable))) - (if (i32.ne (i32.load offset=48 (local.get $src)) (i32.const 13)) (then (unreachable))) - (if (i32.ne (i32.load offset=52 (local.get $src)) (i32.const 14)) (then (unreachable))) - (if (i32.ne (i32.load offset=56 (local.get $src)) (i32.const 15)) (then (unreachable))) - (if (i32.ne (i32.load offset=60 (local.get $src)) (i32.const 16)) (then (unreachable))) - (if (i32.ne (i32.load offset=64 (local.get $src)) (i32.const 17)) (then (unreachable))) - (if (i32.ne (i32.load offset=68 (local.get $src)) (i32.const 18)) (then (unreachable))) - (if (i32.ne (i32.load offset=72 (local.get $src)) (i32.const 19)) (then (unreachable))) - (if (i32.ne (i32.load offset=76 (local.get $src)) (i32.const 20)) (then (unreachable))) - - (local.set $dst (i32.const 500)) - - (i32.store offset=0 (local.get $dst) (i32.const 21)) - (i32.store offset=4 (local.get $dst) (i32.const 22)) - (i32.store offset=8 (local.get $dst) (i32.const 23)) - (i32.store offset=12 (local.get $dst) (i32.const 24)) - (i32.store offset=16 (local.get $dst) (i32.const 25)) - (i32.store offset=20 (local.get $dst) (i32.const 26)) - (i32.store offset=24 (local.get $dst) (i32.const 27)) - (i32.store offset=28 (local.get $dst) (i32.const 28)) - (i32.store offset=32 (local.get $dst) (i32.const 29)) - (i32.store offset=36 (local.get $dst) (i32.const 30)) - - local.get $dst - ) - - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - i32.const 16) - ) - (core instance $m (instantiate $m)) - - (func (export "roundtrip") (type $roundtrip) - (canon lift (core func $m "roundtrip") (memory $m "memory") - (realloc (func $m "realloc"))) - ) - ) - (instance $a (instantiate $a)) - - (component $c - (type $roundtrip (func - ;; 20 u32 params - (param "a1" u32) (param "a2" u32) (param "a3" u32) (param "a4" u32) (param "a5" u32) - (param "a6" u32) (param "a7" u32) (param "a8" u32) (param "a9" u32) (param "a10" u32) - (param "a11" u32) (param "a12" u32) (param "a13" u32) (param "a14" u32) (param "a15" u32) - (param "a16" u32) (param "a17" u32) (param "a18" u32) (param "a19" u32) (param "a20" u32) - - ;; 10 u32 results - (result (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) - )) - - (import "a" (instance $a - (export "roundtrip" (func (type $roundtrip))) - )) - - (core module $libc - (memory (export "memory") 1) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) - ) - (core instance $libc (instantiate $libc)) - (core func $roundtrip - (canon lower (func $a "roundtrip") - (memory $libc "memory") - (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary - ) - ) - - (core module $m2 - (import "libc" "memory" (memory 1)) - (import "" "roundtrip" (func $roundtrip (param i32 i32))) - - (func $start - (local $addr i32) - (local $retaddr i32) - - (local.set $addr (i32.const 100)) - (call $store_many (i32.const 20) (local.get $addr)) - - (local.set $retaddr (i32.const 200)) - (call $roundtrip (local.get $addr) (local.get $retaddr)) - - (if (i32.ne (i32.load offset=0 (local.get $retaddr)) (i32.const 21)) (then (unreachable))) - (if (i32.ne (i32.load offset=4 (local.get $retaddr)) (i32.const 22)) (then (unreachable))) - (if (i32.ne (i32.load offset=8 (local.get $retaddr)) (i32.const 23)) (then (unreachable))) - (if (i32.ne (i32.load offset=12 (local.get $retaddr)) (i32.const 24)) (then (unreachable))) - (if (i32.ne (i32.load offset=16 (local.get $retaddr)) (i32.const 25)) (then (unreachable))) - (if (i32.ne (i32.load offset=20 (local.get $retaddr)) (i32.const 26)) (then (unreachable))) - (if (i32.ne (i32.load offset=24 (local.get $retaddr)) (i32.const 27)) (then (unreachable))) - (if (i32.ne (i32.load offset=28 (local.get $retaddr)) (i32.const 28)) (then (unreachable))) - (if (i32.ne (i32.load offset=32 (local.get $retaddr)) (i32.const 29)) (then (unreachable))) - (if (i32.ne (i32.load offset=36 (local.get $retaddr)) (i32.const 30)) (then (unreachable))) - ) - - (func $store_many (param $amt i32) (param $addr i32) - (local $c i32) - (loop $loop - (local.set $c (i32.add (local.get $c) (i32.const 1))) - (i32.store (local.get $addr) (local.get $c)) - (local.set $addr (i32.add (local.get $addr) (i32.const 4))) - - (if (i32.ne (local.get $amt) (local.get $c)) (then (br $loop))) - ) - ) - (start $start) - ) - (core instance $m2 (instantiate $m2 - (with "libc" (instance $libc)) - (with "" (instance (export "roundtrip" (func $roundtrip)))) - )) - ) - - (instance $c (instantiate $c (with "a" (instance $a)))) -) - -;; this will require multiple adapter modules to get generated -(component - (component $c0 - (core module $root (func (export "") (result i32) - i32.const 0 - )) - (core instance $root (instantiate $root)) - (func (export "thunk") (result u32) (canon lift (core func $root ""))) - ) - (instance $c0 (instantiate $c0)) - - (component $c - (import "thunk" (instance $thunk - (export "thunk" (func (result u32))) - )) - (core func $import (canon lower (func $thunk "thunk"))) - (core module $reexport - (import "" "" (func $thunk (result i32))) - (func (export "thunk") (result i32) - call $thunk - i32.const 1 - i32.add) - ) - (core instance $reexport (instantiate $reexport - (with "" (instance - (export "" (func $import)) - )) - )) - (func $export (export "thunk") (result u32) - (canon lift (core func $reexport "thunk")) - ) - ) - - (instance $c1 (instantiate $c (with "thunk" (instance $c0)))) - (instance $c2 (instantiate $c (with "thunk" (instance $c1)))) - (instance $c3 (instantiate $c (with "thunk" (instance $c2)))) - (instance $c4 (instantiate $c (with "thunk" (instance $c3)))) - (instance $c5 (instantiate $c (with "thunk" (instance $c4)))) - (instance $c6 (instantiate $c (with "thunk" (instance $c5)))) - - (component $verify - (import "thunk" (instance $thunk - (export "thunk" (func (result u32))) - )) - (core func $thunk (canon lower (func $thunk "thunk"))) - (core module $verify - (import "" "" (func $thunk (result i32))) - - (func $start - call $thunk - i32.const 6 - i32.ne - if unreachable end - ) - (start $start) - ) - (core instance (instantiate $verify - (with "" (instance - (export "" (func $thunk)) - )) - )) - ) - (instance (instantiate $verify (with "thunk" (instance $c6)))) -) - -;; Fancy case of an adapter using an adapter. Note that this is silly and -;; doesn't actually make any sense at runtime, we just shouldn't panic on a -;; valid component. -(component - (type $tuple20 (tuple - u32 u32 u32 u32 u32 - u32 u32 u32 u32 u32 - u32 u32 u32 u32 u32 - u32 u32 u32 u32 u32)) - - (component $realloc - (core module $realloc - (memory (export "memory") 1) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - unreachable) - ) - (core instance $realloc (instantiate $realloc)) - (func $realloc (param "a" (tuple u32 u32 u32 u32)) (result u32) - (canon lift (core func $realloc "realloc")) - ) - (export "realloc" (func $realloc)) - ) - (instance $realloc (instantiate $realloc)) - (core func $realloc (canon lower (func $realloc "realloc"))) - - (core module $m - (memory (export "memory") 1) - (func (export "foo") (param i32)) - ) - (core instance $m (instantiate $m)) - (func $foo (param "a" $tuple20) - (canon lift - (core func $m "foo") - (memory $m "memory") - (realloc (func $realloc)) - ) - ) - - (component $c - (import "foo" (func $foo (param "a" $tuple20))) - - (core module $libc - (memory (export "memory") 1) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - unreachable) - ) - (core instance $libc (instantiate $libc)) - (core func $foo - (canon lower (func $foo) - (memory $libc "memory") - (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary - ) - ) - (core module $something - (import "" "foo" (func (param i32))) - ) - (core instance (instantiate $something - (with "" (instance - (export "foo" (func $foo)) - )) - )) - ) - (instance (instantiate $c - (with "foo" (func $foo)) - )) -) - -;; Don't panic or otherwise create extraneous adapter modules when the same -;; adapter is used twice for a module's argument. -(component - (core module $m - (func (export "foo") (param)) - ) - (core instance $m (instantiate $m)) - (func $foo (canon lift (core func $m "foo"))) - - (component $c - (import "foo" (func $foo)) - (core func $foo (canon lower (func $foo))) - - (core module $something - (import "" "a" (func)) - (import "" "b" (func)) - ) - (core instance (instantiate $something - (with "" (instance - (export "a" (func $foo)) - (export "b" (func $foo)) - )) - )) - ) - (instance (instantiate $c (with "foo" (func $foo)))) -) - -;; post-return should get invoked by the generated adapter, if specified -(component - (component $a - (core module $m - (global $post_called (mut i32) (i32.const 0)) - (func (export "foo") - ;; assert `foo-post` not called yet - global.get $post_called - i32.const 1 - i32.eq - if unreachable end - ) - (func (export "foo-post") - ;; assert `foo-post` not called before - global.get $post_called - i32.const 1 - i32.eq - if unreachable end - ;; ... then flag as called - i32.const 1 - global.set $post_called - ) - (func (export "assert-post") - global.get $post_called - i32.const 1 - i32.ne - if unreachable end - ) - ) - (core instance $m (instantiate $m)) - (func (export "foo") (canon lift (core func $m "foo") (post-return (func $m "foo-post")))) - (func (export "assert-post") (canon lift (core func $m "assert-post"))) - ) - (instance $a (instantiate $a)) - - (component $c - (import "a" (instance $a - (export "foo" (func)) - (export "assert-post" (func)) - )) - (core func $foo (canon lower (func $a "foo"))) - (core func $assert_post (canon lower (func $a "assert-post"))) - - (core module $something - (import "" "foo" (func $foo)) - (import "" "assert-post" (func $assert_post)) - - (func $start - call $foo - call $assert_post - ) - (start $start) - ) - (core instance (instantiate $something - (with "" (instance - (export "foo" (func $foo)) - (export "assert-post" (func $assert_post)) - )) - )) - ) - (instance (instantiate $c (with "a" (instance $a)))) -) - -;; post-return passes the results -(component - (component $a - (core module $m - (func (export "foo") (result i32) i32.const 100) - (func (export "foo-post") (param i32) - (if (i32.ne (local.get 0) (i32.const 100)) (then (unreachable)))) - ) - (core instance $m (instantiate $m)) - (func (export "foo") (result u32) - (canon lift (core func $m "foo") (post-return (func $m "foo-post")))) - ) - (instance $a (instantiate $a)) - - (component $c - (import "a" (instance $a - (export "foo" (func (result u32))) - )) - (core func $foo (canon lower (func $a "foo"))) - - (core module $something - (import "" "foo" (func $foo (result i32))) - (func $start - (if (i32.ne (call $foo) (i32.const 100)) (then (unreachable)))) - (start $start) - ) - (core instance (instantiate $something - (with "" (instance - (export "foo" (func $foo)) - )) - )) - ) - (instance (instantiate $c (with "a" (instance $a)))) -) - -;; callee retptr misaligned -(assert_trap - (component - (component $c1 - (core module $m - (memory (export "memory") 1) - (func (export "r") (result i32) i32.const 1) - ) - (core instance $m (instantiate $m)) - (func (export "r") (result (tuple u32 u32)) - (canon lift (core func $m "r") (memory $m "memory")) - ) - ) - (component $c2 - (import "r" (func $r (result (tuple u32 u32)))) - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core func $r (canon lower (func $r) (memory $libc "memory"))) - - (core module $m - (import "" "r" (func $r (param i32))) - (func $start - i32.const 4 - call $r - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance (export "r" (func $r)))) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) - ) - "unaligned pointer") - -;; caller retptr misaligned -(assert_trap - (component - (component $c1 - (core module $m - (memory (export "memory") 1) - (func (export "r") (result i32) i32.const 0) - ) - (core instance $m (instantiate $m)) - (func (export "r") (result (tuple u32 u32)) - (canon lift (core func $m "r") (memory $m "memory")) - ) - ) - (component $c2 - (import "r" (func $r (result (tuple u32 u32)))) - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core func $r (canon lower (func $r) (memory $libc "memory"))) - - (core module $m - (import "" "r" (func $r (param i32))) - (func $start - i32.const 1 - call $r - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance (export "r" (func $r)))) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) - ) - "unaligned pointer") - -;; callee argptr misaligned -(assert_trap - (component - (type $big (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) - - (component $c1 - (core module $m - (memory (export "memory") 1) - (func (export "r") (param i32)) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - i32.const 1) - ) - (core instance $m (instantiate $m)) - (func (export "r") (param "a" $big) - (canon lift (core func $m "r") (memory $m "memory") (realloc (func $m "realloc"))) - ) - ) - (component $c2 - (import "r" (func $r (param "a" $big))) - (core module $libc - (memory (export "memory") 1) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) - ) - (core instance $libc (instantiate $libc)) - (core func $r - (canon lower (func $r) - (memory $libc "memory") - (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary - ) - ) - - (core module $m - (import "" "r" (func $r (param i32))) - (func $start - i32.const 4 - call $r - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance (export "r" (func $r)))) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) - ) - "unaligned pointer") - -;; caller argptr misaligned -(assert_trap - (component - (type $big (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) - - (component $c1 - (core module $m - (memory (export "memory") 1) - (func (export "r") (param i32)) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - i32.const 4) - ) - (core instance $m (instantiate $m)) - (func (export "r") (param "a" $big) - (canon lift (core func $m "r") (memory $m "memory") (realloc (func $m "realloc"))) - ) - ) - (component $c2 - (import "r" (func $r (param "a" $big))) - (core module $libc - (memory (export "memory") 1) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) - ) - (core instance $libc (instantiate $libc)) - (core func $r - (canon lower (func $r) - (memory $libc "memory") - (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary - ) - ) - - - (core module $m - (import "" "r" (func $r (param i32))) - (func $start - i32.const 1 - call $r - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance (export "r" (func $r)))) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) - ) - "unaligned pointer") - -;; simple variant translation -(component - (component $c1 - (type $a' (variant (case "x"))) - (export $a "a" (type $a')) - (type $b' (variant (case "y"))) - (export $b "b" (type $b')) - - (core module $m - (func (export "r") (param i32) (result i32) - (if (i32.ne (local.get 0) (i32.const 0)) (then (unreachable))) - i32.const 0 - ) - ) - (core instance $m (instantiate $m)) - (func (export "r") (param "a" $a) (result $b) (canon lift (core func $m "r"))) - ) - (component $c2 - (type $a' (variant (case "x"))) - (import "a" (type $a (eq $a'))) - (type $b' (variant (case "y"))) - (import "b" (type $b (eq $b'))) - - (import "r" (func $r (param "a" $a) (result $b))) - (core func $r (canon lower (func $r))) - - (core module $m - (import "" "r" (func $r (param i32) (result i32))) - (func $start - i32.const 0 - call $r - i32.const 0 - i32.ne - if unreachable end - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance (export "r" (func $r)))) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 - (with "a" (type $c1 "a")) - (with "b" (type $c1 "b")) - (with "r" (func $c1 "r")) - )) -) - -;; invalid variant discriminant in a parameter -(assert_trap - (component - (component $c1 - (type $a' (variant (case "x"))) - (export $a "a" (type $a')) - (core module $m - (func (export "r") (param i32)) - ) - (core instance $m (instantiate $m)) - (func (export "r") (param "a" $a) (canon lift (core func $m "r"))) - ) - (component $c2 - (type $a' (variant (case "x"))) - (import "a" (type $a (eq $a'))) - (import "r" (func $r (param "a" $a))) - (core func $r (canon lower (func $r))) - - (core module $m - (import "" "r" (func $r (param i32))) - (func $start - i32.const 1 - call $r - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance (export "r" (func $r)))) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 - (with "a" (type $c1 "a")) - (with "r" (func $c1 "r")) - )) - ) - "invalid variant discriminant") - -;; invalid variant discriminant in a result -(assert_trap - (component - (component $c1 - (type $a' (variant (case "x"))) - (export $a "a" (type $a')) - (core module $m - (func (export "r") (result i32) i32.const 1) - ) - (core instance $m (instantiate $m)) - (func (export "r") (result $a) (canon lift (core func $m "r"))) - ) - (component $c2 - (type $a' (variant (case "x"))) - (import "a" (type $a (eq $a'))) - (import "r" (func $r (result $a))) - (core func $r (canon lower (func $r))) - - (core module $m - (import "" "r" (func $r (result i32))) - (func $start call $r drop) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance (export "r" (func $r)))) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 - (with "a" (type $c1 "a")) - (with "r" (func $c1 "r")) - )) - ) - "invalid variant discriminant") - - -;; extra bits are chopped off -(component - (component $c1 - (core module $m - (func (export "u") (param i32) - (if (i32.ne (local.get 0) (i32.const 0)) (then (unreachable))) - ) - (func (export "s") (param i32) - (if (i32.ne (local.get 0) (i32.const -1)) (then (unreachable))) - ) - ) - (core instance $m (instantiate $m)) - (func (export "u8") (param "a" u8) (canon lift (core func $m "u"))) - (func (export "u16") (param "a" u16) (canon lift (core func $m "u"))) - (func (export "s8") (param "a" s8) (canon lift (core func $m "s"))) - (func (export "s16") (param "a" s16) (canon lift (core func $m "s"))) - ) - (component $c2 - (import "a" (instance $i - (export "u8" (func (param "a" u8))) - (export "s8" (func (param "a" s8))) - (export "u16" (func (param "a" u16))) - (export "s16" (func (param "a" s16))) - )) - - (core func $u8 (canon lower (func $i "u8"))) - (core func $s8 (canon lower (func $i "s8"))) - (core func $u16 (canon lower (func $i "u16"))) - (core func $s16 (canon lower (func $i "s16"))) - - (core module $m - (import "" "u8" (func $u8 (param i32))) - (import "" "s8" (func $s8 (param i32))) - (import "" "u16" (func $u16 (param i32))) - (import "" "s16" (func $s16 (param i32))) - - (func $start - (call $u8 (i32.const 0)) - (call $u8 (i32.const 0xff00)) - (call $s8 (i32.const -1)) - (call $s8 (i32.const 0xff)) - (call $s8 (i32.const 0xffff)) - - (call $u16 (i32.const 0)) - (call $u16 (i32.const 0xff0000)) - (call $s16 (i32.const -1)) - (call $s16 (i32.const 0xffff)) - (call $s16 (i32.const 0xffffff)) - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "u8" (func $u8)) - (export "s8" (func $s8)) - (export "u16" (func $u16)) - (export "s16" (func $s16)) - )) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) -) - -;; translation of locals between different types -(component - (component $c1 - (type $a' (variant (case "a" u8) (case "b" float32))) - (type $b' (variant (case "a" u16) (case "b" s64))) - (type $c' (variant (case "a" u64) (case "b" float64))) - (type $d' (variant (case "a" float32) (case "b" float64))) - (type $e' (variant (case "a" float32) (case "b" s64))) - (export $a "t-a" (type $a')) - (export $b "t-b" (type $b')) - (export $c "t-c" (type $c')) - (export $d "t-d" (type $d')) - (export $e "t-e" (type $e')) - - (type $func_a (func (param "x" bool) (param "a" $a))) - (type $func_b (func (param "x" bool) (param "b" $b))) - (type $func_c (func (param "x" bool) (param "c" $c))) - (type $func_d (func (param "x" bool) (param "d" $d))) - (type $func_e (func (param "x" bool) (param "e" $d))) - - (core module $m - (func (export "a") (param i32 i32 i32) - (i32.eqz (local.get 0)) - if - (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) - (if (i32.ne (local.get 2) (i32.const 2)) (then (unreachable))) - else - (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) - (if (f32.ne (f32.reinterpret_i32 (local.get 2)) (f32.const 3)) (then (unreachable))) - end - ) - (func (export "b") (param i32 i32 i64) - (i32.eqz (local.get 0)) - if - (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) - (if (i64.ne (local.get 2) (i64.const 4)) (then (unreachable))) - else - (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) - (if (i64.ne (local.get 2) (i64.const 5)) (then (unreachable))) - end - ) - (func (export "c") (param i32 i32 i64) - (i32.eqz (local.get 0)) - if - (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) - (if (i64.ne (local.get 2) (i64.const 6)) (then (unreachable))) - else - (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) - (if (f64.ne (f64.reinterpret_i64 (local.get 2)) (f64.const 7)) (then (unreachable))) - end - ) - (func (export "d") (param i32 i32 i64) - (i32.eqz (local.get 0)) - if - (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) - (if (f32.ne (f32.reinterpret_i32 (i32.wrap_i64 (local.get 2))) (f32.const 8)) (then (unreachable))) - else - (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) - (if (f64.ne (f64.reinterpret_i64 (local.get 2)) (f64.const 9)) (then (unreachable))) - end - ) - (func (export "e") (param i32 i32 i64) - (i32.eqz (local.get 0)) - if - (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) - (if (f32.ne (f32.reinterpret_i32 (i32.wrap_i64 (local.get 2))) (f32.const 10)) (then (unreachable))) - else - (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) - (if (i64.ne (local.get 2) (i64.const 11)) (then (unreachable))) - end - ) - ) - (core instance $m (instantiate $m)) - (func (export "a") (type $func_a) (canon lift (core func $m "a"))) - (func (export "b") (type $func_b) (canon lift (core func $m "b"))) - (func (export "c") (type $func_c) (canon lift (core func $m "c"))) - (func (export "d") (type $func_d) (canon lift (core func $m "d"))) - (func (export "e") (type $func_e) (canon lift (core func $m "e"))) - ) - (component $c2 - (import "a" (instance $i - (type $a' (variant (case "a" u8) (case "b" float32))) - (type $b' (variant (case "a" u16) (case "b" s64))) - (type $c' (variant (case "a" u64) (case "b" float64))) - (type $d' (variant (case "a" float32) (case "b" float64))) - (type $e' (variant (case "a" float32) (case "b" s64))) - (export "t-a" (type $a (eq $a'))) - (export "t-b" (type $b (eq $b'))) - (export "t-c" (type $c (eq $c'))) - (export "t-d" (type $d (eq $d'))) - (export "t-e" (type $e (eq $e'))) - (type $func_a (func (param "x" bool) (param "a" $a))) - (type $func_b (func (param "x" bool) (param "b" $b))) - (type $func_c (func (param "x" bool) (param "c" $c))) - (type $func_d (func (param "x" bool) (param "d" $d))) - (type $func_e (func (param "x" bool) (param "e" $d))) - - (export "a" (func (type $func_a))) - (export "b" (func (type $func_b))) - (export "c" (func (type $func_c))) - (export "d" (func (type $func_d))) - (export "e" (func (type $func_e))) - )) - - (core func $a (canon lower (func $i "a"))) - (core func $b (canon lower (func $i "b"))) - (core func $c (canon lower (func $i "c"))) - (core func $d (canon lower (func $i "d"))) - (core func $e (canon lower (func $i "e"))) - - (core module $m - (import "" "a" (func $a (param i32 i32 i32))) - (import "" "b" (func $b (param i32 i32 i64))) - (import "" "c" (func $c (param i32 i32 i64))) - (import "" "d" (func $d (param i32 i32 i64))) - (import "" "e" (func $e (param i32 i32 i64))) - - (func $start - ;; upper bits should get masked - (call $a (i32.const 0) (i32.const 0) (i32.const 0xff_02)) - (call $a (i32.const 1) (i32.const 1) (i32.reinterpret_f32 (f32.const 3))) - - ;; upper bits should get masked - (call $b (i32.const 0) (i32.const 0) (i64.const 0xff_00_04)) - (call $b (i32.const 1) (i32.const 1) (i64.const 5)) - - (call $c (i32.const 0) (i32.const 0) (i64.const 6)) - (call $c (i32.const 1) (i32.const 1) (i64.reinterpret_f64 (f64.const 7))) - - (call $d (i32.const 0) (i32.const 0) (i64.extend_i32_u (i32.reinterpret_f32 (f32.const 8)))) - (call $d (i32.const 1) (i32.const 1) (i64.reinterpret_f64 (f64.const 9))) - - (call $e (i32.const 0) (i32.const 0) (i64.extend_i32_u (i32.reinterpret_f32 (f32.const 10)))) - (call $e (i32.const 1) (i32.const 1) (i64.const 11)) - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "a" (func $a)) - (export "b" (func $b)) - (export "c" (func $c)) - (export "d" (func $d)) - (export "e" (func $e)) - )) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) -) - -;; different size variants -(component - (component $c1 - (type $a' (variant - (case "a") - (case "b" float32) - (case "c" (tuple float32 u32)) - (case "d" (tuple float32 u64 u8)) - )) - (export $a "t-a" (type $a')) - - (core module $m - (func (export "a") (param i32 i32 f32 i64 i32) - (if (i32.eq (local.get 0) (i32.const 0)) - (then (block - (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) - (if (f32.ne (local.get 2) (f32.const 0)) (then (unreachable))) - (if (i64.ne (local.get 3) (i64.const 0)) (then (unreachable))) - (if (i32.ne (local.get 4) (i32.const 0)) (then (unreachable))) - )) - ) - (if (i32.eq (local.get 0) (i32.const 1)) - (then (block - (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) - (if (f32.ne (local.get 2) (f32.const 1)) (then (unreachable))) - (if (i64.ne (local.get 3) (i64.const 0)) (then (unreachable))) - (if (i32.ne (local.get 4) (i32.const 0)) (then (unreachable))) - )) - ) - (if (i32.eq (local.get 0) (i32.const 2)) - (then (block - (if (i32.ne (local.get 1) (i32.const 2)) (then (unreachable))) - (if (f32.ne (local.get 2) (f32.const 2)) (then (unreachable))) - (if (i64.ne (local.get 3) (i64.const 2)) (then (unreachable))) - (if (i32.ne (local.get 4) (i32.const 0)) (then (unreachable))) - )) - ) - (if (i32.eq (local.get 0) (i32.const 3)) - (then (block - (if (i32.ne (local.get 1) (i32.const 3)) (then (unreachable))) - (if (f32.ne (local.get 2) (f32.const 3)) (then (unreachable))) - (if (i64.ne (local.get 3) (i64.const 3)) (then (unreachable))) - (if (i32.ne (local.get 4) (i32.const 3)) (then (unreachable))) - )) - ) - (if (i32.gt_u (local.get 0) (i32.const 3)) - (then (unreachable))) - ) - ) - (core instance $m (instantiate $m)) - (func (export "a") (param "x" u8) (param "a" $a) (canon lift (core func $m "a"))) - ) - (component $c2 - (import "a" (instance $i - (type $a' (variant - (case "a") - (case "b" float32) - (case "c" (tuple float32 u32)) - (case "d" (tuple float32 u64 u8)) - )) - (export "t-a" (type $a (eq $a'))) - (export "a" (func (param "x" u8) (param "a" $a))) - )) - - (core func $a (canon lower (func $i "a"))) - - (core module $m - (import "" "a" (func $a (param i32 i32 f32 i64 i32))) - - (func $start - ;; variant a - (call $a - (i32.const 0) - (i32.const 0) - (f32.const 0) - (i64.const 0) - (i32.const 0)) - ;; variant b - (call $a - (i32.const 1) - (i32.const 1) - (f32.const 1) - (i64.const 0) - (i32.const 0)) - ;; variant c - (call $a - (i32.const 2) - (i32.const 2) - (f32.const 2) - (i64.const 2) - (i32.const 0)) - ;; variant d - (call $a - (i32.const 3) - (i32.const 3) - (f32.const 3) - (i64.const 3) - (i32.const 3)) - ) - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "a" (func $a)) - )) - )) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) -) - -;; roundtrip some valid chars -(component - (component $c1 - (core module $m - (func (export "a") (param i32) (result i32) local.get 0) - ) - (core instance $m (instantiate $m)) - (func (export "a") (param "a" char) (result char) (canon lift (core func $m "a"))) - ) - (component $c2 - (import "a" (instance $i - (export "a" (func (param "a" char) (result char))) - )) - - (core func $a (canon lower (func $i "a"))) - - (core module $m - (import "" "a" (func $a (param i32) (result i32))) - - (func $start - (call $roundtrip (i32.const 0)) - (call $roundtrip (i32.const 0xab)) - (call $roundtrip (i32.const 0xd7ff)) - (call $roundtrip (i32.const 0xe000)) - (call $roundtrip (i32.const 0x10ffff)) - ) - (func $roundtrip (export "roundtrip") (param i32) - local.get 0 - call $a - local.get 0 - i32.ne - if unreachable end - ) - (start $start) - ) - (core instance $m (instantiate $m - (with "" (instance - (export "a" (func $a)) - )) - )) - - (func (export "roundtrip") (param "a" char) (canon lift (core func $m "roundtrip"))) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) - - (export "roundtrip" (func $c2 "roundtrip")) -) - -(assert_return (invoke "roundtrip" (char.const "x"))) -(assert_return (invoke "roundtrip" (char.const "⛳"))) -(assert_return (invoke "roundtrip" (char.const "🍰"))) - -;; invalid chars -(assert_trap - (component - (component $c1 - (core module $m (func (export "a") (param i32))) - (core instance $m (instantiate $m)) - (func (export "a") (param "a" char) (canon lift (core func $m "a"))) - ) - (component $c2 - (import "a" (instance $i (export "a" (func (param "a" char))))) - (core func $a (canon lower (func $i "a"))) - (core module $m - (import "" "a" (func $a (param i32))) - (func $start (call $a (i32.const 0xd800))) - (start $start) - ) - (core instance (instantiate $m (with "" (instance (export "a" (func $a)))))) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) - ) - "invalid `char` bit pattern") -(assert_trap - (component - (component $c1 - (core module $m (func (export "a") (param i32))) - (core instance $m (instantiate $m)) - (func (export "a") (param "a" char) (canon lift (core func $m "a"))) - ) - (component $c2 - (import "a" (instance $i (export "a" (func (param "a" char))))) - (core func $a (canon lower (func $i "a"))) - (core module $m - (import "" "a" (func $a (param i32))) - (func $start (call $a (i32.const 0xdfff))) - (start $start) - ) - (core instance (instantiate $m (with "" (instance (export "a" (func $a)))))) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) - ) - "invalid `char` bit pattern") -(assert_trap - (component - (component $c1 - (core module $m (func (export "a") (param i32))) - (core instance $m (instantiate $m)) - (func (export "a") (param "a" char) (canon lift (core func $m "a"))) - ) - (component $c2 - (import "a" (instance $i (export "a" (func (param "a" char))))) - (core func $a (canon lower (func $i "a"))) - (core module $m - (import "" "a" (func $a (param i32))) - (func $start (call $a (i32.const 0x110000))) - (start $start) - ) - (core instance (instantiate $m (with "" (instance (export "a" (func $a)))))) - ) - (instance $c1 (instantiate $c1)) - (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) - ) - "invalid `char` bit pattern") - -;; test that flags get their upper bits all masked off -(component - (type $f1' (flags "f1")) - (type $f8' (flags "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8")) - (type $f9' (flags "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" "f9")) - (type $f16' (flags - "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" - "g1" "g2" "g3" "g4" "g5" "g6" "g7" "g8" - )) - (type $f17' (flags - "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" - "g1" "g2" "g3" "g4" "g5" "g6" "g7" "g8" - "g9" - )) - (type $f32' (flags - "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" - "g1" "g2" "g3" "g4" "g5" "g6" "g7" "g8" - "h1" "h2" "h3" "h4" "h5" "h6" "h7" "h8" - "i1" "i2" "i3" "i4" "i5" "i6" "i7" "i8" - )) - - (component $c1 - (export $f1 "t-f1" (type $f1')) - (export $f8 "t-f8" (type $f8')) - (export $f9 "t-f9" (type $f9')) - (export $f16 "t-f16" (type $f16')) - (export $f17 "t-f17" (type $f17')) - (export $f32 "t-f32" (type $f32')) - (core module $m - (func (export "f1") (param i32) - (if (i32.ne (local.get 0) (i32.const 0x1)) (then (unreachable))) - ) - (func (export "f8") (param i32) - (if (i32.ne (local.get 0) (i32.const 0x11)) (then (unreachable))) - ) - (func (export "f9") (param i32) - (if (i32.ne (local.get 0) (i32.const 0x111)) (then (unreachable))) - ) - (func (export "f16") (param i32) - (if (i32.ne (local.get 0) (i32.const 0x1111)) (then (unreachable))) - ) - (func (export "f17") (param i32) - (if (i32.ne (local.get 0) (i32.const 0x11111)) (then (unreachable))) - ) - (func (export "f32") (param i32) - (if (i32.ne (local.get 0) (i32.const 0x11111111)) (then (unreachable))) - ) - ) - (core instance $m (instantiate $m)) - (func (export "f1") (param "a" $f1) (canon lift (core func $m "f1"))) - (func (export "f8") (param "a" $f8) (canon lift (core func $m "f8"))) - (func (export "f9") (param "a" $f9) (canon lift (core func $m "f9"))) - (func (export "f16") (param "a" $f16) (canon lift (core func $m "f16"))) - (func (export "f17") (param "a" $f17) (canon lift (core func $m "f17"))) - (func (export "f32") (param "a" $f32) (canon lift (core func $m "f32"))) - ) - (instance $c1 (instantiate $c1)) - - (component $c2 - (import "a" (instance $i - (export "t-f1" (type $f1 (eq $f1'))) - (export "t-f8" (type $f8 (eq $f8'))) - (export "t-f9" (type $f9 (eq $f9'))) - (export "t-f16" (type $f16 (eq $f16'))) - (export "t-f17" (type $f17 (eq $f17'))) - (export "t-f32" (type $f32 (eq $f32'))) - (export "f1" (func (param "a" $f1))) - (export "f8" (func (param "a" $f8))) - (export "f9" (func (param "a" $f9))) - (export "f16" (func (param "a" $f16))) - (export "f17" (func (param "a" $f17))) - (export "f32" (func (param "a" $f32))) - )) - (core func $f1 (canon lower (func $i "f1"))) - (core func $f8 (canon lower (func $i "f8"))) - (core func $f9 (canon lower (func $i "f9"))) - (core func $f16 (canon lower (func $i "f16"))) - (core func $f17 (canon lower (func $i "f17"))) - (core func $f32 (canon lower (func $i "f32"))) - - (core module $m - (import "" "f1" (func $f1 (param i32))) - (import "" "f8" (func $f8 (param i32))) - (import "" "f9" (func $f9 (param i32))) - (import "" "f16" (func $f16 (param i32))) - (import "" "f17" (func $f17 (param i32))) - (import "" "f32" (func $f32 (param i32))) - - (func $start - (call $f1 (i32.const 0xffffff01)) - (call $f8 (i32.const 0xffffff11)) - (call $f9 (i32.const 0xffffff11)) - (call $f16 (i32.const 0xffff1111)) - (call $f17 (i32.const 0xffff1111)) - (call $f32 (i32.const 0x11111111)) - ) - - (start $start) - ) - (core instance $m (instantiate $m - (with "" (instance - (export "f1" (func $f1)) - (export "f8" (func $f8)) - (export "f9" (func $f9)) - (export "f16" (func $f16)) - (export "f17" (func $f17)) - (export "f32" (func $f32)) - )) - )) - ) - (instance (instantiate $c2 (with "a" (instance $c1)))) -) - -;; Adapters are used slightly out-of-order here to stress the internals of -;; dependencies between adapters. -(component - (core module $m - (func (export "execute")) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) - (memory (export "memory") 1) - ) - - (component $root - (core instance $m (instantiate $m)) - (func (export "execute") - (canon lift (core func $m "execute")) - ) - ) - (component $c - (import "backend" (instance $i - (export "execute" (func)) - )) - (core module $shim2 (import "" "0" (func))) - (core instance $m (instantiate $m)) - - ;; This adapter, when fused with itself on the second instantiation of this - ;; component, will depended on the prior instance `$m` so it which means - ;; that the adapter module containing this must be placed in the right - ;; location. - (core func $execute - (canon lower (func $i "execute") (memory $m "memory") (realloc (func $m "realloc"))) - ) - (core instance (instantiate $shim2 - (with "" (instance - (export "0" (func $execute)) - )) - )) - (func (export "execute") (canon lift (core func $m "execute"))) - ) - (instance $root (instantiate $root)) - (instance $c1 (instantiate $c (with "backend" (instance $root)))) - (instance $c2 (instantiate $c (with "backend" (instance $c1)))) -) diff --git a/src/test/resources/spec-tests/wasmtime/import.wast b/src/test/resources/spec-tests/wasmtime/import.wast deleted file mode 100644 index 20688ef..0000000 --- a/src/test/resources/spec-tests/wasmtime/import.wast +++ /dev/null @@ -1,20 +0,0 @@ -(assert_invalid - (component - (import "host-return-two" (func $f (result u32))) - (export "x" (func $f))) - "component export `x` is a reexport of an imported function which is not implemented") - -(assert_unlinkable - (component - (import "host-return-two" (instance)) - ) - "expected instance found func") - -;; empty instances don't need to be supplied by the host, even recursively -;; empty instances. -(component - (import "not-provided-by-the-host" (instance)) - (import "not-provided-by-the-host2" (instance - (export "x" (instance)) - )) -) diff --git a/src/test/resources/spec-tests/wasmtime/instance.wast b/src/test/resources/spec-tests/wasmtime/instance.wast deleted file mode 100644 index 4216cdc..0000000 --- a/src/test/resources/spec-tests/wasmtime/instance.wast +++ /dev/null @@ -1,327 +0,0 @@ -(component - (core module $m) - (core instance (instantiate $m)) -) - -(component - (core module $m - (func (export "")) - ) - (core instance $i (instantiate $m)) - - (core module $m2 - (func (import "" "")) - ) - (core instance (instantiate $m2 (with "" (instance $i)))) -) - -(component - (core module $m - (func (export "a")) - ) - (core instance $i (instantiate $m)) - - (core module $m2 - (func (import "" "b")) - ) - (core instance (instantiate $m2 - (with "" (instance (export "b" (func $i "a")))) - )) -) - -;; all kinds of imports for core wasm modules, and register a start function on -;; one module to ensure that everything is correct -(component - (core module $m - (func (export "a")) - (table (export "b") 1 funcref) - (memory (export "c") 1) - (global (export "d") i32 i32.const 1) - ) - (core instance $i (instantiate $m)) - - (core module $m2 - (import "" "a" (func $f)) - (import "" "b" (table 1 funcref)) - (import "" "c" (memory 1)) - (import "" "d" (global $g i32)) - - (func $start - global.get $g - i32.const 1 - i32.ne - if - unreachable - end - - call $f - ) - - (start $start) - - (data (i32.const 0) "hello") - (elem (i32.const 0) $start) - ) - (core instance (instantiate $m2 - (with "" (instance $i)) - )) -) - -;; Test to see if a component with a type export can be instantiated. -(component - (type string) - (export "a" (type 0)) -) - -;; double-check the start function runs by ensuring that a trap shows up and it -;; sees the wrong value for the global import -(assert_trap - (component - (core module $m - (global (export "g") i32 i32.const 1) - ) - (core instance $i (instantiate $m)) - - (core module $m2 - (import "" "g" (global $g i32)) - - (func $start - global.get $g - i32.const 0 - i32.ne - if - unreachable - end - ) - - (start $start) - ) - (core instance (instantiate $m2 (with "" (instance $i)))) - ) - "unreachable") - -;; shuffle around imports to get to what the target core wasm module needs -(component - (core module $m - (func (export "1")) - (table (export "2") 1 funcref) - (memory (export "3") 1) - (global (export "4") i32 i32.const 1) - ) - (core instance $i (instantiate $m)) - - (core module $m2 - (import "" "a" (func $f)) - (import "" "b" (table 1 funcref)) - (import "" "c" (memory 1)) - (import "" "d" (global $g i32)) - ) - (core instance (instantiate $m2 - (with "" (instance - (export "a" (func $i "1")) - (export "b" (table $i "2")) - (export "c" (memory $i "3")) - (export "d" (global $i "4")) - )) - )) -) - -;; indirect references through a synthetic instance -(component - (core module $m - (func (export "a")) - (table (export "b") 1 funcref) - (memory (export "c") 1) - (global (export "d") i32 i32.const 1) - ) - (core instance $i (instantiate $m)) - (core instance $i2 - (export "a1" (func $i "a")) - (export "a2" (table $i "b")) - (export "a3" (memory $i "c")) - (export "a4" (global $i "d")) - ) - - (core module $m2 - (import "" "1" (func $f)) - (import "" "2" (table 1 funcref)) - (import "" "3" (memory 1)) - (import "" "4" (global $g i32)) - ) - (core instance (instantiate $m2 - (with "" (instance - (export "1" (func $i2 "a1")) - (export "2" (table $i2 "a2")) - (export "3" (memory $i2 "a3")) - (export "4" (global $i2 "a4")) - )) - )) -) - -(component - (import "host" (instance $i (export "return-three" (func (result u32))))) - - (core module $m - (import "host" "return-three" (func $three (result i32))) - (func $start - call $three - i32.const 3 - i32.ne - if unreachable end - ) - (start $start) - ) - (core func $three_lower - (canon lower (func $i "return-three")) - ) - (core instance (instantiate $m - (with "host" (instance (export "return-three" (func $three_lower)))) - )) -) - -(component - (import "host" (instance $i - (type $x' (record (field "x" u32))) - (export "x" (type $x (eq $x'))) - (type $rec' (record (field "x" $x) (field "y" string))) - (export "rec" (type $rec (eq $rec'))) - (export "some-record" (type (eq $rec))))) -) - -(component - (import "host" (instance $i - (export "nested" (instance - (export "return-four" (func (result u32))) - )) - )) - - (core module $m - (import "host" "return-three" (func $three (result i32))) - (func $start - call $three - i32.const 4 - i32.ne - if unreachable end - ) - (start $start) - ) - (core func $three_lower - (canon lower (func $i "nested" "return-four")) - ) - (core instance (instantiate $m - (with "host" (instance (export "return-three" (func $three_lower)))) - )) -) - -(component - (import "host" (instance $i - (export "simple-module" (core module)) - )) - - (core instance (instantiate (module $i "simple-module"))) -) - -(component - (import "host" (instance $i - (export "simple-module" (core module - (export "f" (func (result i32))) - (export "g" (global i32)) - )) - )) - - (core instance $i (instantiate (module $i "simple-module"))) - (core module $verify - (import "host" "f" (func $f (result i32))) - (import "host" "g" (global $g i32)) - - (func $start - call $f - i32.const 101 - i32.ne - if unreachable end - - global.get $g - i32.const 100 - i32.ne - if unreachable end - ) - (start $start) - ) - - (core instance (instantiate $verify (with "host" (instance $i)))) -) - -;; export an instance -(component - (core module $m) - (instance $i (export "m" (core module $m))) - (export "i" (instance $i)) -) -(component - (component $c) - (instance $i (instantiate $c)) - (export "i" (instance $i)) -) -(component - (import "host" (instance $i)) - (export "i" (instance $i)) -) - - -(component definition $C1 - (type $r1 (resource (rep i32))) - (export "r" (type $r1)) -) -(component definition $C2 - (type $r1 (resource (rep i32))) - (export "r" (type $r1)) -) - -(component instance $I1 $C1) -(component instance $I2 $C1) -(component instance $I3 $C2) -(component instance $I4 $C2) - -;; all instances have different resource types -(assert_unlinkable - (component - (import "I1" (instance $i1 (export "r" (type (sub resource))))) - (alias export $i1 "r" (type $r)) - (import "I2" (instance $i2 (export "r" (type (eq $r))))) - ) - "mismatched resource types") -(assert_unlinkable - (component - (import "I1" (instance $i1 (export "r" (type (sub resource))))) - (alias export $i1 "r" (type $r)) - (import "I3" (instance $i2 (export "r" (type (eq $r))))) - ) - "mismatched resource types") -(assert_unlinkable - (component - (import "I1" (instance $i1 (export "r" (type (sub resource))))) - (alias export $i1 "r" (type $r)) - (import "I4" (instance $i2 (export "r" (type (eq $r))))) - ) - "mismatched resource types") -(assert_unlinkable - (component - (import "I2" (instance $i1 (export "r" (type (sub resource))))) - (alias export $i1 "r" (type $r)) - (import "I3" (instance $i2 (export "r" (type (eq $r))))) - ) - "mismatched resource types") -(assert_unlinkable - (component - (import "I2" (instance $i1 (export "r" (type (sub resource))))) - (alias export $i1 "r" (type $r)) - (import "I4" (instance $i2 (export "r" (type (eq $r))))) - ) - "mismatched resource types") -(assert_unlinkable - (component - (import "I3" (instance $i1 (export "r" (type (sub resource))))) - (alias export $i1 "r" (type $r)) - (import "I4" (instance $i2 (export "r" (type (eq $r))))) - ) - "mismatched resource types") diff --git a/src/test/resources/spec-tests/wasmtime/linking.wast b/src/test/resources/spec-tests/wasmtime/linking.wast deleted file mode 100644 index 966926f..0000000 --- a/src/test/resources/spec-tests/wasmtime/linking.wast +++ /dev/null @@ -1,18 +0,0 @@ -(assert_unlinkable - (component - (import "undefined-name" (core module)) - ) - "was not found") -(component $i) -(component - (import "i" (instance)) -) -(assert_unlinkable - (component (import "i" (core module))) - "expected module found instance") -(assert_unlinkable - (component (import "i" (func))) - "expected function found instance") -(assert_unlinkable - (component (import "i" (instance (export "x" (func))))) - "was not found") diff --git a/src/test/resources/spec-tests/wasmtime/modules.wast b/src/test/resources/spec-tests/wasmtime/modules.wast deleted file mode 100644 index 6014f94..0000000 --- a/src/test/resources/spec-tests/wasmtime/modules.wast +++ /dev/null @@ -1,479 +0,0 @@ -;;! reference_types = true - -(component $foo - (core module (export "a-module")) -) - -;; the above instance can be imported into this component -(component - (import "foo" (instance - (export "a-module" (core module)) - )) -) - -;; specifying extra imports is ok -(component - (import "foo" (instance - (export "a-module" (core module - (import "foo" "bar" (func)) - )) - )) -) - -;; specifying extra exports is not ok -(assert_unlinkable - (component - (import "foo" (instance - (export "a-module" (core module - (export "the-export" (func)) - )) - )) - ) - "module export `the-export` not defined") - -(component $foo - (core module (export "a-module") - (import "env" "something" (func)) - ) -) - -;; imports must be specified -(assert_unlinkable - (component - (import "foo" (instance - (export "a-module" (core module)) - )) - ) - "module import `env::something` not defined") - -(component - (import "foo" (instance - (export "a-module" (core module - (import "env" "something" (func)) - )) - )) -) - -;; extra imports still ok -(component - (import "foo" (instance - (export "a-module" (core module - (import "env" "something" (func)) - (import "env" "other" (global i32)) - )) - )) -) - -(component $foo - (core module (export "a-module") - (func (export "f")) - ) -) - -;; dropping exports is ok -(component - (import "foo" (instance - (export "a-module" (core module)) - )) -) - -(component - (import "foo" (instance - (export "a-module" (core module - (export "f" (func)) - )) - )) -) - -(assert_unlinkable - (component - (import "foo" (instance - (export "a-module" (core module - (export "f" (func (param i32))) - )) - )) - ) - "expected type `(func (param i32))`, found type `(func)`") - -(assert_unlinkable - (component - (import "foo" (instance - (export "a-module" (core module - (export "f" (global i32)) - )) - )) - ) - "expected global found func") - -(component $foo - (core module (export "m") - (func (export "f")) - (table (export "t") 1 funcref) - (memory (export "m") 1) - (global (export "g") i32 i32.const 0) - ) -) - -;; wrong class of item -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "f" (global i32)))) - )) - ) - "expected global found func") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "t" (func)))) - )) - ) - "expected func found table") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "m" (func)))) - )) - ) - "expected func found memory") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "g" (func)))) - )) - ) - "expected func found global") - -;; wrong item type -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "f" (func (param i32))))) - )) - ) - "export `f` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "t" (table 1 externref)))) - )) - ) - "export `t` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "t" (table 2 funcref)))) - )) - ) - "export `t` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "m" (memory 2)))) - )) - ) - "export `m` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "g" (global f32)))) - )) - ) - "export `g` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (export "g" (global (mut i32))))) - )) - ) - "export `g` has the wrong type") - -;; subtyping ok -(component - (import "foo" (instance - (export "m" (core module - (export "t" (table 0 funcref)) - (export "m" (memory 0)) - )) - )) -) - -(component $foo - (core module (export "f") (func (import "" ""))) - (core module (export "t") (table (import "" "") 1 funcref)) - (core module (export "m") (memory (import "" "") 1)) - (core module (export "g") (global (import "" "") i32)) -) - -;; wrong class of item -(assert_unlinkable - (component - (import "foo" (instance - (export "f" (core module (import "" "" (global i32)))) - )) - ) - "expected func found global") -(assert_unlinkable - (component - (import "foo" (instance - (export "t" (core module (import "" "" (func)))) - )) - ) - "expected table found func") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (import "" "" (func)))) - )) - ) - "expected memory found func") -(assert_unlinkable - (component - (import "foo" (instance - (export "g" (core module (import "" "" (func)))) - )) - ) - "expected global found func") - -;; wrong item type -(assert_unlinkable - (component - (import "foo" (instance - (export "f" (core module (import "" "" (func (param i32))))) - )) - ) - "module import `::` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "t" (core module (import "" "" (table 1 externref)))) - )) - ) - "module import `::` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "t" (core module (import "" "" (table 0 funcref)))) - )) - ) - "module import `::` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "m" (core module (import "" "" (memory 0)))) - )) - ) - "module import `::` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "g" (core module (import "" "" (global f32)))) - )) - ) - "module import `::` has the wrong type") -(assert_unlinkable - (component - (import "foo" (instance - (export "g" (core module (import "" "" (global (mut i32))))) - )) - ) - "module import `::` has the wrong type") - -;; subtyping ok, but in the opposite direction of imports -(component - (import "foo" (instance - (export "t" (core module (import "" "" (table 2 funcref)))) - (export "m" (core module (import "" "" (memory 2)))) - )) -) - -;; An instance can reexport a module, define a module, and everything can be -;; used by something else -(component $src - (core module (export "m") - (global (export "g") i32 i32.const 2) - ) -) - -(component $reexport - (core module $m1 - (global (export "g") i32 i32.const 1) - ) - (import "src" (instance $src - (export "m" (core module (export "g" (global i32)))) - )) - - (core module $m3 - (global (export "g") i32 i32.const 3) - ) - - (export "m1" (core module $m1)) - (export "m2" (core module $src "m")) - (export "m3" (core module $m3)) -) - -(component - (core type $modulety (module (export "g" (global i32)))) - (import "reexport" (instance $reexport - (export "m1" (core module (type $modulety))) - (export "m2" (core module (type $modulety))) - (export "m3" (core module (type $modulety))) - )) - - (core module $assert_ok - (import "m1" "g" (global $m1 i32)) - (import "m2" "g" (global $m2 i32)) - (import "m3" "g" (global $m3 i32)) - - (func $assert_ok - block - global.get $m1 - i32.const 1 - i32.eq - br_if 0 - unreachable - end - block - global.get $m2 - i32.const 2 - i32.eq - br_if 0 - unreachable - end - block - global.get $m3 - i32.const 3 - i32.eq - br_if 0 - unreachable - end - ) - - (start $assert_ok) - ) - - (core instance $m1 (instantiate (module $reexport "m1"))) - (core instance $m2 (instantiate (module $reexport "m2"))) - (core instance $m3 (instantiate (module $reexport "m3"))) - - (core instance (instantiate $assert_ok - (with "m1" (instance $m1)) - (with "m2" (instance $m2)) - (with "m3" (instance $m3)) - )) -) - -;; order of imports and exports can be shuffled between definition site and -;; use-site -(component $provider - (core module (export "m") - (import "" "1" (global $i1 i32)) - (import "" "2" (global $i2 i32)) - (import "" "3" (global $i3 i32)) - (import "" "4" (global $i4 i32)) - - (global $g1 i32 i32.const 100) - (global $g2 i32 i32.const 101) - (global $g3 i32 i32.const 102) - (global $g4 i32 i32.const 103) - - (func $assert_imports - (block - global.get $i1 - i32.const 1 - i32.eq - br_if 0 - unreachable) - (block - global.get $i2 - i32.const 2 - i32.eq - br_if 0 - unreachable) - (block - global.get $i3 - i32.const 3 - i32.eq - br_if 0 - unreachable) - (block - global.get $i4 - i32.const 4 - i32.eq - br_if 0 - unreachable) - ) - - (start $assert_imports) - - (export "g1" (global $g1)) - (export "g2" (global $g2)) - (export "g3" (global $g3)) - (export "g4" (global $g4)) - ) -) - -(component - (import "provider" (instance $provider - (export "m" (core module - (import "" "4" (global i32)) - (import "" "3" (global i32)) - (import "" "2" (global i32)) - (import "" "1" (global i32)) - - (export "g4" (global i32)) - (export "g3" (global i32)) - (export "g2" (global i32)) - (export "g1" (global i32)) - )) - )) - - (core module $imports - (global (export "1") i32 (i32.const 1)) - (global (export "3") i32 (i32.const 3)) - (global (export "2") i32 (i32.const 2)) - (global (export "4") i32 (i32.const 4)) - ) - (core instance $imports (instantiate $imports)) - (core instance $m (instantiate (module $provider "m") - (with "" (instance $imports)) - )) - - (core module $import_globals - (import "" "g4" (global $g4 i32)) - (import "" "g3" (global $g3 i32)) - (import "" "g2" (global $g2 i32)) - (import "" "g1" (global $g1 i32)) - - (func $assert_imports - (block - global.get $g1 - i32.const 100 - i32.eq - br_if 0 - unreachable) - (block - global.get $g2 - i32.const 101 - i32.eq - br_if 0 - unreachable) - (block - global.get $g3 - i32.const 102 - i32.eq - br_if 0 - unreachable) - (block - global.get $g4 - i32.const 103 - i32.eq - br_if 0 - unreachable) - ) - - (start $assert_imports) - ) - - (core instance (instantiate $import_globals (with "" (instance $m)))) -) diff --git a/src/test/resources/spec-tests/wasmtime/nested.wast b/src/test/resources/spec-tests/wasmtime/nested.wast deleted file mode 100644 index 8cb4c38..0000000 --- a/src/test/resources/spec-tests/wasmtime/nested.wast +++ /dev/null @@ -1,451 +0,0 @@ -;; simple nested component -(component - (component) -) - -;; simple nested component with a nested module -(component - (component - (core module) - ) -) - -;; simple instantiation of a nested component -(component - (component $c) - (instance (instantiate $c)) - (instance (instantiate $c - (with "x" (component $c)) - )) -) - -;; instantiate a module during a nested component, and also instantiate it -;; as an export of the nested component -(component - (component $c - (core module $m) - (core instance (instantiate $m)) - (export "m" (core module $m)) - ) - (instance $i (instantiate $c)) - (core instance $i (instantiate (module $i "m"))) -) - -;; instantiate an inner exported module with two different modules and -;; verify imports match -(component - (component $c - (core module $m - (import "" "g" (global $g i32)) - (import "" "f" (func $f (result i32))) - - (func $start - call $f - global.get $g - i32.ne - if unreachable end) - - (start $start) - ) - - (core module $m2 - (global (export "g") i32 i32.const 1) - (func (export "f") (result i32) i32.const 1) - ) - (core instance $i2 (instantiate $m2)) - (core instance (instantiate $m (with "" (instance $i2)))) - - (export "m" (core module $m)) - ) - (instance $i (instantiate $c)) - (core module $m2 - (global (export "g") i32 i32.const 5) - (func (export "f") (result i32) i32.const 5) - ) - (core instance $i2 (instantiate $m2)) - (core instance (instantiate (module $i "m") (with "" (instance $i2)))) -) - -;; instantiate an inner component with a module import -(component - (component $c - (import "m" (core module $m - (export "g" (global i32)) - )) - - (core instance $i (instantiate $m)) - - (core module $verify - (import "" "g" (global $g i32)) - - (func $start - global.get $g - i32.const 2 - i32.ne - if unreachable end - ) - - (start $start) - ) - (core instance (instantiate $verify (with "" (instance $i)))) - ) - - (core module $m - (global (export "g") i32 (i32.const 2)) - ) - (instance (instantiate $c (with "m" (core module $m)))) -) - -;; instantiate an inner component with a module import that itself has imports -(component - (component $c - (import "m" (core module $m - (import "" "g" (global i32)) - )) - (core module $m2 - (global (export "g") i32 i32.const 2100) - ) - (core instance $m2 (instantiate $m2)) - (core instance (instantiate $m (with "" (instance $m2)))) - ) - - (core module $verify - (import "" "g" (global $g i32)) - - (func $start - global.get $g - i32.const 2100 - i32.ne - if unreachable end - ) - - (start $start) - ) - (instance (instantiate $c (with "m" (core module $verify)))) -) - -;; instantiate an inner component with an export from the outer component -(component $c - (core module (export "m") - (import "" "g1" (global $g1 i32)) - (import "" "g2" (global $g2 i32)) - - (func $start - global.get $g1 - i32.const 10000 - i32.ne - if unreachable end - - global.get $g2 - i32.const 20000 - i32.ne - if unreachable end - ) - - (start $start) - ) -) - -(component - (import "c" (instance $i - (export "m" (core module - (import "" "g2" (global i32)) - (import "" "g1" (global i32)) - )) - )) - - (component $c - (import "m" (core module $verify - (import "" "g2" (global i32)) - (import "" "g1" (global i32)) - )) - - (core module $m - (global (export "g1") i32 i32.const 10000) - (global (export "g2") i32 i32.const 20000) - ) - (core instance $m (instantiate $m)) - (core instance (instantiate $verify (with "" (instance $m)))) - ) - - (instance (instantiate $c (with "m" (core module $i "m")))) -) - -;; instantiate a reexported module -(component - (core module $m - (global (export "g") i32 i32.const 7) - ) - (component $c - (import "i" (instance $i - (export "m" (core module - (import "" "" (func)) - (export "g" (global i32)) - )) - )) - - (export "m" (core module $i "m")) - ) - - (instance $c (instantiate $c (with "i" (instance (export "m" (core module $m)))))) - (core module $dummy - (func (export "")) - ) - (core instance $dummy (instantiate $dummy)) - - (core instance $m (instantiate (module $c "m") (with "" (instance $dummy)))) - - (core module $verify - (import "" "g" (global i32)) - (func $start - global.get 0 - i32.const 7 - i32.ne - if unreachable end - ) - - (start $start) - ) - (core instance (instantiate $verify (with "" (instance $m)))) -) - -;; module must be found through a few layers of imports -(component $c - (core module (export "m") - (global (export "g") i32 i32.const 101) - ) -) - -(component - (import "c" (instance $i - (export "m" (core module - (export "g" (global i32)) - )) - )) - (component $c1 - (import "c" (instance $i - (export "m" (core module - (export "g" (global i32)) - )) - )) - (core module $verify - (import "" "g" (global i32)) - (func $start - global.get 0 - i32.const 101 - i32.ne - if unreachable end - ) - - (start $start) - ) - (core instance $m (instantiate (module $i "m"))) - (core instance (instantiate $verify (with "" (instance $m)))) - ) - (instance (instantiate $c1 (with "c" (instance $i)))) -) - -;; instantiate outer alias to self -(component $C - (core module $m) - (alias outer $C $m (core module $other_m)) - (core instance (instantiate $other_m)) -) - -(component $C - (component $m) - (alias outer $C $m (component $other_m)) - (instance (instantiate $other_m)) -) - - -;; closing over an outer alias which is actually an argument to some -;; instantiation -(component - (component $c - (import "c" (core module $c - (export "a" (global i32)) - )) - - (component (export "c2") - (export "m" (core module $c)) - ) - ) - - (core module $m1 (global (export "a") i32 i32.const 1)) - (core module $m2 (global (export "a") i32 i32.const 2)) - - (instance $c1 (instantiate $c (with "c" (core module $m1)))) - (instance $c2 (instantiate $c (with "c" (core module $m2)))) - - (instance $m1_container (instantiate (component $c1 "c2"))) - (instance $m2_container (instantiate (component $c2 "c2"))) - - (core instance $core1 (instantiate (module $m1_container "m"))) - (core instance $core2 (instantiate (module $m2_container "m"))) - - (core module $verify - (import "core1" "a" (global $a i32)) - (import "core2" "a" (global $b i32)) - - (func $start - global.get $a - i32.const 1 - i32.ne - if unreachable end - - global.get $b - i32.const 2 - i32.ne - if unreachable end - ) - - (start $start) - ) - (core instance (instantiate $verify - (with "core1" (instance $core1)) - (with "core2" (instance $core2)) - )) -) - -;; simple importing of a component -(component - (component $C) - (component $other - (import "x" (component $c)) - (instance (instantiate $c)) - ) - (instance (instantiate $other (with "x" (component $C)))) -) - -;; deep nesting -(component $C - (core module $m - (global (export "g") i32 (i32.const 1)) - ) - (component $c - (core module (export "m") - (global (export "g") i32 (i32.const 2)) - ) - ) - - (component $c1 - (component $c2 (export "a") - (component $c3 (export "a") - (alias outer $C $m (core module $my_module)) - (alias outer $C $c (component $my_component)) - - (export "m" (core module $my_module)) - (export "c" (component $my_component)) - ) - ) - ) - - (instance $i1 (instantiate $c1)) - (instance $i2 (instantiate (component $i1 "a"))) - (instance $i3 (instantiate (component $i2 "a"))) - - (core instance $m1 (instantiate (module $i3 "m"))) - (instance $c (instantiate (component $i3 "c"))) - (core instance $m2 (instantiate (module $c "m"))) - - (core module $verify - (import "m1" "g" (global $m1 i32)) - (import "m2" "g" (global $m2 i32)) - - (func $start - global.get $m1 - i32.const 1 - i32.ne - if unreachable end - - global.get $m2 - i32.const 2 - i32.ne - if unreachable end - ) - (start $start) - ) - (core instance (instantiate $verify (with "m1" (instance $m1)) (with "m2" (instance $m2)))) -) - -;; Try threading through component instantiation arguments as various forms of -;; instances. -(component - (component $c - (core module $m (export "m")) - (component $c (export "c") - (core module (export "m")) - ) - (instance $i (instantiate $c)) - (instance $i2 - (export "m" (core module $m)) - (export "c" (component $c)) - (export "i" (instance $i)) - ) - (export "i" (instance $i)) - (export "i2" (instance $i2)) - ) - (instance $i (instantiate $c)) - - (component $another - (import "host" (instance - (export "m" (core module)) - (export "c" (component)) - (export "i" (instance)) - )) - ) - (instance (instantiate $another (with "host" (instance $i)))) - (instance (instantiate $another (with "host" (instance $i "i2")))) - - (instance $reexport - (export "c" (component $i "c")) - (export "m" (core module $i "m")) - (export "i" (instance $i "i")) - ) - (instance (instantiate $another (with "host" (instance $reexport)))) -) - -;; thread host functions around -(component - (import "host-return-two" (func $import (result u32))) - - ;; thread the host function through an instance - (component $c - (import "a" (func $f (result u32))) - (export "f" (func $f)) - ) - (instance $c (instantiate $c (with "a" (func $import)))) - (alias export $c "f" (func $import2)) - - ;; thread the host function into a nested component - (component $c2 - (import "host" (instance $i (export "return-two" (func (result u32))))) - - (core module $m - (import "host" "return-two" (func $host (result i32))) - (func $start - call $host - i32.const 2 - i32.ne - if unreachable end - ) - (start $start) - ) - - (core func $return_two - (canon lower (func $i "return-two")) - ) - (core instance (instantiate $m - (with "host" (instance - (export "return-two" (func $return_two)) - )) - )) - ) - - (instance (instantiate $c2 - (with "host" (instance - (export "return-two" (func $import2)) - )) - )) -) diff --git a/src/test/resources/spec-tests/wasmtime/resources.wast b/src/test/resources/spec-tests/wasmtime/resources.wast deleted file mode 100644 index 28e68ad..0000000 --- a/src/test/resources/spec-tests/wasmtime/resources.wast +++ /dev/null @@ -1,1091 +0,0 @@ -;; bare bones "intrinsics work" -(component - (type $r (resource (rep i32))) - (core func $rep (canon resource.rep $r)) - (core func $new (canon resource.new $r)) - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "rep" (func $rep (param i32) (result i32))) - (import "" "new" (func $new (param i32) (result i32))) - (import "" "drop" (func $drop (param i32))) - - (func $start - (local $r i32) - (local.set $r (call $new (i32.const 100))) - - (if (i32.ne (local.get $r) (i32.const 1)) (then (unreachable))) - (if (i32.ne (call $rep (local.get $r)) (i32.const 100)) (then (unreachable))) - - (call $drop (local.get $r)) - ) - - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "rep" (func $rep)) - (export "new" (func $new)) - (export "drop" (func $drop)) - )) - )) -) - -;; cannot call `resource.drop` on a nonexistent resource -(component - (type $r (resource (rep i32))) - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "drop" (func $drop (param i32))) - - (func (export "r") - (call $drop (i32.const 0)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - )) - )) - - (func (export "r") (canon lift (core func $i "r"))) -) -(assert_trap (invoke "r") "unknown handle index 0") - -;; cannot call `resource.rep` on a nonexistent resource -(component - (type $r (resource (rep i32))) - (core func $rep (canon resource.rep $r)) - - (core module $m - (import "" "rep" (func $rep (param i32) (result i32))) - - (func (export "r") - (drop (call $rep (i32.const 0))) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "rep" (func $rep)) - )) - )) - - (func (export "r") (canon lift (core func $i "r"))) -) -(assert_trap (invoke "r") "unknown handle index 0") - -;; index reuse behavior of handles -(component - (type $r (resource (rep i32))) - (core func $rep (canon resource.rep $r)) - (core func $new (canon resource.new $r)) - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "rep" (func $rep (param i32) (result i32))) - (import "" "new" (func $new (param i32) (result i32))) - (import "" "drop" (func $drop (param i32))) - - (func $start - (local $r1 i32) - (local $r2 i32) - (local $r3 i32) - (local $r4 i32) - - ;; resources assigned sequentially - (local.set $r1 (call $new (i32.const 100))) - (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) - - (local.set $r2 (call $new (i32.const 200))) - (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) - - (local.set $r3 (call $new (i32.const 300))) - (if (i32.ne (local.get $r3) (i32.const 3)) (then (unreachable))) - - ;; representations all look good - (if (i32.ne (call $rep (local.get $r1)) (i32.const 100)) (then (unreachable))) - (if (i32.ne (call $rep (local.get $r2)) (i32.const 200)) (then (unreachable))) - (if (i32.ne (call $rep (local.get $r3)) (i32.const 300)) (then (unreachable))) - - ;; reallocate r2 - (call $drop (local.get $r2)) - (local.set $r2 (call $new (i32.const 400))) - - ;; should have reused index 3 - (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) - - ;; representations all look good - (if (i32.ne (call $rep (local.get $r1)) (i32.const 100)) (then (unreachable))) - (if (i32.ne (call $rep (local.get $r2)) (i32.const 400)) (then (unreachable))) - (if (i32.ne (call $rep (local.get $r3)) (i32.const 300)) (then (unreachable))) - - ;; deallocate, then reallocate - (call $drop (local.get $r1)) - (call $drop (local.get $r2)) - (call $drop (local.get $r3)) - - (local.set $r1 (call $new (i32.const 500))) - (local.set $r2 (call $new (i32.const 600))) - (local.set $r3 (call $new (i32.const 700))) - - ;; representations all look good - (if (i32.ne (call $rep (local.get $r1)) (i32.const 500)) (then (unreachable))) - (if (i32.ne (call $rep (local.get $r2)) (i32.const 600)) (then (unreachable))) - (if (i32.ne (call $rep (local.get $r3)) (i32.const 700)) (then (unreachable))) - - ;; indices should be lifo - (if (i32.ne (local.get $r1) (i32.const 3)) (then (unreachable))) - (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) - (if (i32.ne (local.get $r3) (i32.const 1)) (then (unreachable))) - - ;; bump one more time - (local.set $r4 (call $new (i32.const 800))) - (if (i32.ne (local.get $r4) (i32.const 4)) (then (unreachable))) - - ;; deallocate everything - (call $drop (local.get $r1)) - (call $drop (local.get $r2)) - (call $drop (local.get $r3)) - (call $drop (local.get $r4)) - ) - - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "rep" (func $rep)) - (export "new" (func $new)) - (export "drop" (func $drop)) - )) - )) -) - -(assert_unlinkable - (component - (import "host" (instance - (export "missing" (type (sub resource))) - )) - ) - "was not found") -(assert_unlinkable - (component - (import "host" (instance - (export "return-three" (type (sub resource))) - )) - ) - "expected resource found func") - -;; all resources can be uniquely imported -(component - (import "host" (instance - (export "resource1" (type (sub resource))) - (export "resource2" (type (sub resource))) - (export "resource1-again" (type (sub resource))) - )) -) - -;; equality constraints also work -(component - (import "host" (instance - (export "resource1" (type $r1 (sub resource))) - (export "resource2" (type (sub resource))) - (export "resource1-again" (type (eq $r1))) - )) -) - -;; equality constraints are checked if resources are supplied -(assert_unlinkable - (component - (import "host" (instance - (export "resource1" (type (sub resource))) - (export "resource2" (type $r1 (sub resource))) - (export "resource1-again" (type (eq $r1))) - )) - ) - "mismatched resource types") - -;; equality constraints mean that types don't need to be supplied -(component - (import "host" (instance - (export "resource1" (type $r1 (sub resource))) - (export "resource2" (type (sub resource))) - (export "this-name-is-not-provided-in-the-wast-harness" (type (eq $r1))) - )) -) - -;; simple properties of handles -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32))) - )) - (alias export $host "resource1" (type $r)) - (alias export $host "[constructor]resource1" (func $ctor)) - (alias export $host "[static]resource1.assert" (func $assert)) - - (core func $drop (canon resource.drop $r)) - (core func $ctor (canon lower (func $ctor))) - (core func $assert (canon lower (func $assert))) - - (core module $m - (import "" "drop" (func $drop (param i32))) - (import "" "ctor" (func $ctor (param i32) (result i32))) - (import "" "assert" (func $assert (param i32 i32))) - - (func $start - (local $r1 i32) - (local $r2 i32) - (local.set $r1 (call $ctor (i32.const 100))) - (local.set $r2 (call $ctor (i32.const 200))) - - ;; assert r1/r2 are sequential - (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) - (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) - - ;; reallocate r1 and it should be reassigned the same index - (call $drop (local.get $r1)) - (local.set $r1 (call $ctor (i32.const 300))) - (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) - - ;; internal values should match - (call $assert (local.get $r1) (i32.const 300)) - (call $assert (local.get $r2) (i32.const 200)) - ) - - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - (export "ctor" (func $ctor)) - (export "assert" (func $assert)) - )) - )) -) - -;; Using an index that has never been valid is a trap -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32))) - )) - (alias export $host "resource1" (type $r)) - (alias export $host "[static]resource1.assert" (func $assert)) - (core func $assert (canon lower (func $assert))) - - (core module $m - (import "" "assert" (func $assert (param i32 i32))) - - (func (export "f") - (call $assert (i32.const 0) (i32.const 0)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "assert" (func $assert)) - )) - )) - - (func (export "f") (canon lift (core func $i "f"))) -) - -(assert_trap (invoke "f") "unknown handle index") - -;; Using an index which was previously valid but no longer valid is also a trap. -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32))) - )) - (alias export $host "[constructor]resource1" (func $ctor)) - (alias export $host "[static]resource1.assert" (func $assert)) - - (core func $assert (canon lower (func $assert))) - (core func $ctor (canon lower (func $ctor))) - - (core module $m - (import "" "assert" (func $assert (param i32 i32))) - (import "" "ctor" (func $ctor (param i32) (result i32))) - - (global $handle (mut i32) i32.const 0) - - (func (export "f") - (global.set $handle (call $ctor (i32.const 100))) - (call $assert (global.get $handle) (i32.const 100)) - ) - - (func (export "f2") - (call $assert (global.get $handle) (i32.const 100)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "assert" (func $assert)) - (export "ctor" (func $ctor)) - )) - )) - - (func (export "f") (canon lift (core func $i "f"))) - (func (export "f2") (canon lift (core func $i "f2"))) -) - -(assert_return (invoke "f")) -(assert_trap (invoke "f2") "unknown handle index") - -;; Also invalid to pass a previously valid handle to the drop intrinsic -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - )) - (alias export $host "resource1" (type $r)) - (alias export $host "[constructor]resource1" (func $ctor)) - - (core func $drop (canon resource.drop $r)) - (core func $ctor (canon lower (func $ctor))) - - (core module $m - (import "" "drop" (func $drop (param i32))) - (import "" "ctor" (func $ctor (param i32) (result i32))) - - (global $handle (mut i32) i32.const 0) - - (func (export "f") - (global.set $handle (call $ctor (i32.const 100))) - (call $drop (global.get $handle)) - ) - - (func (export "f2") - (call $drop (global.get $handle)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "ctor" (func $ctor)) - (export "drop" (func $drop)) - )) - )) - - (func (export "f") (canon lift (core func $i "f"))) - (func (export "f2") (canon lift (core func $i "f2"))) -) - -(assert_return (invoke "f")) -(assert_trap (invoke "f2") "unknown handle index") - -;; If an inner component instantiates a resource then an outer component -;; should not implicitly have access to that resource. -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - )) - - ;; an inner component which upon instantiation will invoke the constructor, - ;; assert that it's zero, and then forget about it. - (component $inner - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - )) - (alias export $host "[constructor]resource1" (func $ctor)) - - (core func $ctor (canon lower (func $ctor))) - - (core module $m - (import "" "ctor" (func $ctor (param i32) (result i32))) - - (func $start - (if (i32.ne (call $ctor (i32.const 100)) (i32.const 0)) (then (unreachable))) - ) - ) - (core instance $i (instantiate $m - (with "" (instance (export "ctor" (func $ctor)))) - )) - ) - (instance $i (instantiate $inner (with "host" (instance $host)))) - - ;; the rest of this component which is a single function that invokes `drop` - ;; for index 0. The index 0 should be valid within the above component, but - ;; it is not valid within this component - (alias export $host "resource1" (type $r)) - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "drop" (func $drop (param i32))) - - (func (export "f") - (call $drop (i32.const 0)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - )) - )) - - (func (export "f") (canon lift (core func $i "f"))) -) - -(assert_trap (invoke "f") "unknown handle index") - -;; Same as the above test, but for resources defined within a component -(component - (component $inner - (type $r (resource (rep i32))) - - (core func $ctor (canon resource.new $r)) - - (core module $m - (import "" "ctor" (func $ctor (param i32) (result i32))) - - (func $start - (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) - ) - (start $start) - ) - (core instance $i (instantiate $m - (with "" (instance (export "ctor" (func $ctor)))) - )) - (export "r" (type $r)) - ) - (instance $i (instantiate $inner)) - - ;; the rest of this component which is a single function that invokes `drop` - ;; for index 1. The index 1 should be valid within the above component, but - ;; it is not valid within this component - (alias export $i "r" (type $r)) - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "drop" (func $drop (param i32))) - - (func (export "f") - (call $drop (i32.const 1)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - )) - )) - - (func (export "f") (canon lift (core func $i "f"))) -) - -(assert_trap (invoke "f") "unknown handle index 1") - -;; Each instantiation of a component generates a unique resource type, so -;; allocating in one component and deallocating in another should fail. -(component - (component $inner - (type $r (resource (rep i32))) - - (core func $ctor (canon resource.new $r)) - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "ctor" (func $ctor (param i32) (result i32))) - (import "" "drop" (func $drop (param i32))) - - (func (export "alloc") - (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) - ) - (func (export "dealloc") - (call $drop (i32.const 1)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "ctor" (func $ctor)) - (export "drop" (func $drop)) - )) - )) - (func (export "alloc") (canon lift (core func $i "alloc"))) - (func (export "dealloc") (canon lift (core func $i "dealloc"))) - ) - (instance $i1 (instantiate $inner)) - (instance $i2 (instantiate $inner)) - - (alias export $i1 "alloc" (func $alloc_in_1)) - (alias export $i1 "dealloc" (func $dealloc_in_1)) - (alias export $i2 "alloc" (func $alloc_in_2)) - (alias export $i2 "dealloc" (func $dealloc_in_2)) - - (export "alloc-in1" (func $alloc_in_1)) - (export "dealloc-in1" (func $dealloc_in_1)) - (export "alloc-in2" (func $alloc_in_2)) - (export "dealloc-in2" (func $dealloc_in_2)) -) - -(assert_return (invoke "alloc-in1")) -(assert_return (invoke "dealloc-in1")) -(assert_return (invoke "alloc-in1")) -(assert_return (invoke "alloc-in2")) -(assert_return (invoke "dealloc-in2")) -(assert_trap (invoke "dealloc-in2") "unknown handle index") - -;; Same as above, but the same host resource type is imported into a -;; component that is instantiated twice. Each component instance should -;; receive different tables tracking resources so a resource allocated in one -;; should not be visible in the other. -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - )) - (alias export $host "resource1" (type $r)) - (alias export $host "[constructor]resource1" (func $ctor)) - - (component $inner - (import "r" (type $r (sub resource))) - (import "[constructor]r" (func $ctor (param "r" u32) (result (own $r)))) - - (core func $ctor (canon lower (func $ctor))) - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "ctor" (func $ctor (param i32) (result i32))) - (import "" "drop" (func $drop (param i32))) - - (func (export "alloc") - (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) - ) - (func (export "dealloc") - (call $drop (i32.const 1)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "ctor" (func $ctor)) - (export "drop" (func $drop)) - )) - )) - (func (export "alloc") (canon lift (core func $i "alloc"))) - (func (export "dealloc") (canon lift (core func $i "dealloc"))) - ) - (instance $i1 (instantiate $inner - (with "r" (type $r)) - (with "[constructor]r" (func $ctor)) - )) - (instance $i2 (instantiate $inner - (with "r" (type $r)) - (with "[constructor]r" (func $ctor)) - )) - - (alias export $i1 "alloc" (func $alloc_in_1)) - (alias export $i1 "dealloc" (func $dealloc_in_1)) - (alias export $i2 "alloc" (func $alloc_in_2)) - (alias export $i2 "dealloc" (func $dealloc_in_2)) - - (export "alloc-in1" (func $alloc_in_1)) - (export "dealloc-in1" (func $dealloc_in_1)) - (export "alloc-in2" (func $alloc_in_2)) - (export "dealloc-in2" (func $dealloc_in_2)) -) - -(assert_return (invoke "alloc-in1")) -(assert_return (invoke "dealloc-in1")) -(assert_return (invoke "alloc-in1")) -(assert_return (invoke "alloc-in2")) -(assert_return (invoke "dealloc-in2")) -(assert_trap (invoke "dealloc-in2") "unknown handle index") - -;; Multiple copies of intrinsics all work -(component - (type $r (resource (rep i32))) - - (core func $new1 (canon resource.new $r)) - (core func $new2 (canon resource.new $r)) - (core func $drop1 (canon resource.drop $r)) - (core func $drop2 (canon resource.drop $r)) - - (core module $m - (import "" "new1" (func $new1 (param i32) (result i32))) - (import "" "new2" (func $new2 (param i32) (result i32))) - (import "" "drop1" (func $drop1 (param i32))) - (import "" "drop2" (func $drop2 (param i32))) - - (func $start - ;; 2x2 matrix of pairing new/drop - (call $drop1 (call $new1 (i32.const 101))) - (call $drop2 (call $new1 (i32.const 102))) - (call $drop1 (call $new2 (i32.const 103))) - (call $drop2 (call $new2 (i32.const 104))) - - ;; should be referencing the same namespace - (if (i32.ne (call $new1 (i32.const 105)) (i32.const 1)) (then (unreachable))) - (if (i32.ne (call $new2 (i32.const 105)) (i32.const 2)) (then (unreachable))) - - ;; use different drops out of order - (call $drop2 (i32.const 1)) - (call $drop1 (i32.const 2)) - ) - - (start $start) - ) - - (core instance (instantiate $m - (with "" (instance - (export "new1" (func $new1)) - (export "new2" (func $new2)) - (export "drop1" (func $drop1)) - (export "drop2" (func $drop2)) - )) - )) -) - -;; u32::MAX isn't special in some weird way, it's just probably always invalid -;; because that's a lot of handles. -(component - (type $r (resource (rep i32))) - - (core func $drop (canon resource.drop $r)) - - (core module $m - (import "" "drop" (func $drop (param i32))) - - (func (export "f") - (call $drop (i32.const 0xffffffff)) - ) - ) - - (core instance $i (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - )) - )) - (func (export "f") (canon lift (core func $i "f"))) -) -(assert_trap (invoke "f") "unknown handle index") - -;; Test behavior of running a destructor for local resources -(component - (core module $m1 - (global $drops (mut i32) i32.const 0) - (global $last_drop (mut i32) i32.const -1) - - (func (export "dtor") (param i32) - (global.set $drops (i32.add (global.get $drops) (i32.const 1))) - (global.set $last_drop (local.get 0)) - ) - (func (export "drops") (result i32) global.get $drops) - (func (export "last-drop") (result i32) global.get $last_drop) - ) - (core instance $i1 (instantiate $m1)) - - (type $r1 (resource (rep i32))) - (type $r2 (resource (rep i32) (dtor (func $i1 "dtor")))) - - (core func $drop1 (canon resource.drop $r1)) - (core func $drop2 (canon resource.drop $r2)) - (core func $new1 (canon resource.new $r1)) - (core func $new2 (canon resource.new $r2)) - - (core module $m2 - (import "" "drop1" (func $drop1 (param i32))) - (import "" "drop2" (func $drop2 (param i32))) - (import "" "new1" (func $new1 (param i32) (result i32))) - (import "" "new2" (func $new2 (param i32) (result i32))) - (import "i1" "drops" (func $drops (result i32))) - (import "i1" "last-drop" (func $last-drop (result i32))) - - (func $start - (local $r1 i32) - (local $r2 i32) - - (local.set $r1 (call $new1 (i32.const 100))) - (local.set $r2 (call $new2 (i32.const 200))) - - ;; indexes start at 2 and while they have distinct types they should be - ;; within the same table. - (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) - (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) - - ;; nothing should be dropped yet - (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) - (if (i32.ne (call $last-drop) (i32.const -1)) (then (unreachable))) - - ;; dropping a resource without a destructor is ok, but shouldn't tamper - ;; with anything. - (call $drop1 (local.get $r1)) - (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) - (if (i32.ne (call $last-drop) (i32.const -1)) (then (unreachable))) - - ;; drop r2 which should record a drop and additionally record the private - ;; representation value which was dropped - (call $drop2 (local.get $r2)) - (if (i32.ne (call $drops) (i32.const 1)) (then (unreachable))) - (if (i32.ne (call $last-drop) (i32.const 200)) (then (unreachable))) - - ;; do it all over again - (local.set $r2 (call $new2 (i32.const 300))) - (call $drop2 (local.get $r2)) - (if (i32.ne (call $drops) (i32.const 2)) (then (unreachable))) - (if (i32.ne (call $last-drop) (i32.const 300)) (then (unreachable))) - ) - - (start $start) - ) - - (core instance $i2 (instantiate $m2 - (with "" (instance - (export "drop1" (func $drop1)) - (export "drop2" (func $drop2)) - (export "new1" (func $new1)) - (export "new2" (func $new2)) - )) - (with "i1" (instance $i1)) - )) -) - -;; Test dropping a host resource -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - (export "[static]resource1.last-drop" (func (result u32))) - (export "[static]resource1.drops" (func (result u32))) - )) - - (alias export $host "resource1" (type $r)) - (alias export $host "[constructor]resource1" (func $ctor)) - (alias export $host "[static]resource1.last-drop" (func $last-drop)) - (alias export $host "[static]resource1.drops" (func $drops)) - - (core func $drop (canon resource.drop $r)) - (core func $ctor (canon lower (func $ctor))) - (core func $last-drop (canon lower (func $last-drop))) - (core func $drops (canon lower (func $drops))) - - (core module $m - (import "" "drop" (func $drop (param i32))) - (import "" "ctor" (func $ctor (param i32) (result i32))) - (import "" "last-drop" (func $last-drop (result i32))) - (import "" "drops" (func $raw-drops (result i32))) - - (global $init-drop-cnt (mut i32) i32.const 0) - - (func $drops (result i32) - (i32.sub (call $raw-drops) (global.get $init-drop-cnt)) - ) - - (func $start - (local $r1 i32) - (global.set $init-drop-cnt (call $raw-drops)) - - (local.set $r1 (call $ctor (i32.const 100))) - - ;; should be no drops yet - (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) - - ;; should count a drop - (call $drop (local.get $r1)) - (if (i32.ne (call $drops) (i32.const 1)) (then (unreachable))) - (if (i32.ne (call $last-drop) (i32.const 100)) (then (unreachable))) - - ;; do it again to be sure - (local.set $r1 (call $ctor (i32.const 200))) - (call $drop (local.get $r1)) - (if (i32.ne (call $drops) (i32.const 2)) (then (unreachable))) - (if (i32.ne (call $last-drop) (i32.const 200)) (then (unreachable))) - ) - - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - (export "ctor" (func $ctor)) - (export "last-drop" (func $last-drop)) - (export "drops" (func $drops)) - )) - )) -) - -;; Test some bare-bones basics of borrowed resources -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - (export "[method]resource1.simple" (func (param "self" (borrow $r)) (param "rep" u32))) - (export "[method]resource1.take-borrow" (func (param "self" (borrow $r)) (param "b" (borrow $r)))) - (export "[method]resource1.take-own" (func (param "self" (borrow $r)) (param "b" (own $r)))) - )) - - (alias export $host "resource1" (type $r)) - (alias export $host "[constructor]resource1" (func $ctor)) - (alias export $host "[method]resource1.simple" (func $simple)) - (alias export $host "[method]resource1.take-borrow" (func $take-borrow)) - (alias export $host "[method]resource1.take-own" (func $take-own)) - - (core func $drop (canon resource.drop $r)) - (core func $ctor (canon lower (func $ctor))) - (core func $simple (canon lower (func $simple))) - (core func $take-own (canon lower (func $take-own))) - (core func $take-borrow (canon lower (func $take-borrow))) - - (core module $m - (import "" "drop" (func $drop (param i32))) - (import "" "ctor" (func $ctor (param i32) (result i32))) - (import "" "simple" (func $simple (param i32 i32))) - (import "" "take-own" (func $take-own (param i32 i32))) - (import "" "take-borrow" (func $take-borrow (param i32 i32))) - - - (func $start - (local $r1 i32) - (local $r2 i32) - (local.set $r1 (call $ctor (i32.const 100))) - (local.set $r2 (call $ctor (i32.const 200))) - - (call $simple (local.get $r1) (i32.const 100)) - (call $simple (local.get $r1) (i32.const 100)) - (call $simple (local.get $r2) (i32.const 200)) - (call $simple (local.get $r1) (i32.const 100)) - (call $simple (local.get $r2) (i32.const 200)) - (call $simple (local.get $r2) (i32.const 200)) - - (call $drop (local.get $r1)) - (call $drop (local.get $r2)) - - - (local.set $r1 (call $ctor (i32.const 200))) - (local.set $r2 (call $ctor (i32.const 300))) - (call $take-borrow (local.get $r1) (local.get $r2)) - (call $take-borrow (local.get $r2) (local.get $r1)) - (call $take-borrow (local.get $r1) (local.get $r1)) - (call $take-borrow (local.get $r2) (local.get $r2)) - - (call $take-own (local.get $r1) (call $ctor (i32.const 400))) - (call $take-own (local.get $r2) (call $ctor (i32.const 500))) - (call $take-own (local.get $r2) (local.get $r1)) - (call $drop (local.get $r2)) - - ;; table should be empty at this point, so a fresh allocation should get - ;; index 2 - (if (i32.ne (call $ctor (i32.const 600)) (i32.const 1)) (then (unreachable))) - ) - - (start $start) - ) - (core instance (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - (export "ctor" (func $ctor)) - (export "simple" (func $simple)) - (export "take-own" (func $take-own)) - (export "take-borrow" (func $take-borrow)) - )) - )) -) - -;; Cannot pass out an owned resource when it's borrowed by the same call -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) - (export "[method]resource1.take-own" (func (param "self" (borrow $r)) (param "b" (own $r)))) - )) - - (alias export $host "resource1" (type $r)) - (alias export $host "[constructor]resource1" (func $ctor)) - (alias export $host "[method]resource1.take-own" (func $take-own)) - - (core func $drop (canon resource.drop $r)) - (core func $ctor (canon lower (func $ctor))) - (core func $take-own (canon lower (func $take-own))) - - (core module $m - (import "" "drop" (func $drop (param i32))) - (import "" "ctor" (func $ctor (param i32) (result i32))) - (import "" "take-own" (func $take-own (param i32 i32))) - - - (func (export "f") - (local $r i32) - (local.set $r (call $ctor (i32.const 100))) - (call $take-own (local.get $r) (local.get $r)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - (export "ctor" (func $ctor)) - (export "take-own" (func $take-own)) - )) - )) - - (func (export "f") (canon lift (core func $i "f"))) -) - -(assert_trap (invoke "f") "cannot remove owned resource while borrowed") - -;; Borrows must actually exist -(component - (import "host" (instance $host - (export "resource1" (type $r (sub resource))) - (export "[method]resource1.simple" (func (param "self" (borrow $r)) (param "b" u32))) - )) - - (alias export $host "resource1" (type $r)) - (alias export $host "[method]resource1.simple" (func $simple)) - - (core func $drop (canon resource.drop $r)) - (core func $simple (canon lower (func $simple))) - - (core module $m - (import "" "drop" (func $drop (param i32))) - (import "" "simple" (func $simple (param i32 i32))) - - - (func (export "f") - (call $simple (i32.const 0) (i32.const 0)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "drop" (func $drop)) - (export "simple" (func $simple)) - )) - )) - - (func (export "f") (canon lift (core func $i "f"))) -) - -(assert_trap (invoke "f") "unknown handle index 0") - -(component - (component $A - (type $t' (resource (rep i32))) - (export $t "t" (type $t')) - - (core func $ctor (canon resource.new $t)) - (core func $dtor (canon resource.drop $t)) - (core func $rep (canon resource.rep $t)) - - (core module $m - (import "" "dtor" (func $dtor (param i32))) - (import "" "rep" (func $rep (param i32) (result i32))) - - (func (export "[method]t.assert") (param i32 i32) - (if (i32.ne (local.get 0) (local.get 1)) (then (unreachable))) - ) - (func (export "[static]t.assert-own") (param i32 i32) - (if (i32.ne (call $rep (local.get 0)) (local.get 1)) (then (unreachable))) - (call $dtor (local.get 0)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "dtor" (func $dtor)) - (export "rep" (func $rep)) - )) - )) - (func (export "[constructor]t") (param "x" u32) (result (own $t)) - (canon lift (core func $ctor))) - (func (export "[method]t.assert") (param "self" (borrow $t)) (param "x" u32) - (canon lift (core func $i "[method]t.assert"))) - (func (export "[static]t.assert-own") (param "self" (own $t)) (param "x" u32) - (canon lift (core func $i "[static]t.assert-own"))) - ) - (instance $a (instantiate $A)) - - (component $B - (import "a" (instance $i - (export "t" (type $t (sub resource))) - (export "[constructor]t" (func (param "x" u32) (result (own $t)))) - (export "[method]t.assert" (func (param "self" (borrow $t)) (param "x" u32))) - (export "[static]t.assert-own" (func (param "self" (own $t)) (param "x" u32))) - )) - - (alias export $i "t" (type $t)) - (alias export $i "[constructor]t" (func $ctor)) - (alias export $i "[method]t.assert" (func $assert-borrow)) - (alias export $i "[static]t.assert-own" (func $assert-own)) - - (core func $ctor (canon lower (func $ctor))) - (core func $dtor (canon resource.drop $t)) - (core func $assert-own (canon lower (func $assert-own))) - (core func $assert-borrow (canon lower (func $assert-borrow))) - - (core module $m - (import "" "ctor" (func $ctor (param i32) (result i32))) - (import "" "dtor" (func $dtor (param i32))) - (import "" "assert-own" (func $assert-own (param i32 i32))) - (import "" "assert-borrow" (func $assert-borrow (param i32 i32))) - - (func (export "f") - (local $r1 i32) - (local $r2 i32) - - (local.set $r1 (call $ctor (i32.const 100))) - (local.set $r2 (call $ctor (i32.const 200))) - - (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) - (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) - - (call $assert-borrow (local.get $r2) (i32.const 200)) - (call $assert-borrow (local.get $r1) (i32.const 100)) - - (call $assert-own (local.get $r2) (i32.const 200)) - (call $dtor (local.get $r1)) - ) - ) - (core instance $i (instantiate $m - (with "" (instance - (export "ctor" (func $ctor)) - (export "dtor" (func $dtor)) - (export "assert-own" (func $assert-own)) - (export "assert-borrow" (func $assert-borrow)) - )) - )) - (func (export "f") (canon lift (core func $i "f"))) - ) - (instance $b (instantiate $B (with "a" (instance $a)))) - (export "f" (func $b "f")) -) - -(assert_return (invoke "f")) - -;; Test destructor behavior when using the wrong resource type -(component definition $C - (type $r1 (resource (rep i32))) - (type $r2 (resource (rep i32))) - - (core func $drop1 (canon resource.drop $r1)) - (core func $drop2 (canon resource.drop $r2)) - (core func $new1 (canon resource.new $r1)) - (core func $new2 (canon resource.new $r2)) - - (core module $m2 - (import "" "drop1" (func $drop1 (param i32))) - (import "" "drop2" (func $drop2 (param i32))) - (import "" "new1" (func $new1 (param i32) (result i32))) - (import "" "new2" (func $new2 (param i32) (result i32))) - - (func (export "drop-r1-as-r2") (call $drop2 (call $new1 (i32.const 100)))) - (func (export "return-r1-as-r2") (result i32) (call $new1 (i32.const 100))) - ) - - (core instance $i2 (instantiate $m2 - (with "" (instance - (export "drop1" (func $drop1)) - (export "drop2" (func $drop2)) - (export "new1" (func $new1)) - (export "new2" (func $new2)) - )) - )) - - (export $r2' "r2" (type $r2)) - (func (export "drop-r1-as-r2") (canon lift (core func $i2 "drop-r1-as-r2"))) - (func (export "return-r1-as-r2") (result (own $r2')) (canon lift (core func $i2 "return-r1-as-r2"))) -) - -(component instance $C1 $C) -(assert_trap (invoke "drop-r1-as-r2") "handle index 1 used with the wrong type, expected guest-defined resource but found a different guest-defined resource") -(component instance $C1 $C) -(assert_trap (invoke "return-r1-as-r2") "handle index 1 used with the wrong type, expected guest-defined resource but found a different guest-defined resource") diff --git a/src/test/resources/spec-tests/wasmtime/restrictions.wast b/src/test/resources/spec-tests/wasmtime/restrictions.wast deleted file mode 100644 index 9bd53e7..0000000 --- a/src/test/resources/spec-tests/wasmtime/restrictions.wast +++ /dev/null @@ -1,22 +0,0 @@ -(assert_invalid - (component (import "x" (component))) - "root-level component imports are not supported") - -(assert_invalid - (component (component (export "x"))) - "exporting a component from the root component is not supported") - -(assert_invalid - (component - (import "f" (func $f)) - (export "f" (func $f)) - ) - "component export `f` is a reexport of an imported function which is not implemented") - -(assert_invalid - (component - (import "x" (component - (export "x" (type (sub resource))) - )) - ) - "root-level component imports are not supported") diff --git a/src/test/resources/spec-tests/wasmtime/simple.wast b/src/test/resources/spec-tests/wasmtime/simple.wast deleted file mode 100644 index 7bf2ab1..0000000 --- a/src/test/resources/spec-tests/wasmtime/simple.wast +++ /dev/null @@ -1,42 +0,0 @@ -(component) - -(component - (core module) -) - -(component - (core module) - (core module) - (core module) -) - -(component - (core module - (func (export "a") (result i32) i32.const 0) - (func (export "b") (result i64) i64.const 0) - ) - (core module - (func (export "c") (result f32) f32.const 0) - (func (export "d") (result f64) f64.const 0) - ) -) - -(assert_invalid - (component - (import "a" (component)) - ) - "root-level component imports are not supported") - -(assert_invalid - (component - (component (export "a")) - ) - "exporting a component from the root component is not supported") - -(component - (core module $m (func (export ""))) - (core instance $m (instantiate $m)) - (func (export "a") (canon lift (core func $m ""))) -) - -(assert_return (invoke "a")) diff --git a/src/test/resources/spec-tests/wasmtime/strings.wast b/src/test/resources/spec-tests/wasmtime/strings.wast deleted file mode 100644 index 943fd31..0000000 --- a/src/test/resources/spec-tests/wasmtime/strings.wast +++ /dev/null @@ -1,110 +0,0 @@ -;;! multi_memory = true - -;; unaligned utf16 string -(assert_trap - (component - (component $c - (core module $m - (func (export "") (param i32 i32)) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 0) - (memory (export "memory") 1) - ) - (core instance $m (instantiate $m)) - (func (export "a") (param "a" string) - (canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory")) - ) - ) - - (component $c2 - (import "a" (func $f (param "a" string))) - (core module $libc - (memory (export "memory") 1) - ) - (core instance $libc (instantiate $libc)) - (core func $f (canon lower (func $f) string-encoding=utf16 (memory $libc "memory"))) - (core module $m - (import "" "" (func $f (param i32 i32))) - - (func $start (call $f (i32.const 1) (i32.const 0))) - (start $start) - ) - (core instance (instantiate $m (with "" (instance (export "" (func $f)))))) - ) - - (instance $c (instantiate $c)) - (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) - ) - "unaligned pointer") - -;; unaligned latin1+utf16 string, even with the latin1 encoding -(assert_trap - (component - (component $c - (core module $m - (func (export "") (param i32 i32)) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 0) - (memory (export "memory") 1) - ) - (core instance $m (instantiate $m)) - (func (export "a") (param "a" string) - (canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory")) - ) - ) - - (component $c2 - (import "a" (func $f (param "a" string))) - (core module $libc - (memory (export "memory") 1) - ) - (core instance $libc (instantiate $libc)) - (core func $f (canon lower (func $f) string-encoding=latin1+utf16 (memory $libc "memory"))) - (core module $m - (import "" "" (func $f (param i32 i32))) - - (func $start (call $f (i32.const 1) (i32.const 0))) - (start $start) - ) - (core instance (instantiate $m (with "" (instance (export "" (func $f)))))) - ) - - (instance $c (instantiate $c)) - (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) - ) - "unaligned pointer") - -;; out of bounds utf8->utf8 string -(assert_trap - (component - (component $c - (core module $m - (func (export "") (param i32 i32)) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 0) - (memory (export "memory") 1) - ) - (core instance $m (instantiate $m)) - (func (export "a") (param "a" string) - (canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory") - string-encoding=utf8) - ) - ) - - (component $c2 - (import "a" (func $f (param "a" string))) - (core module $libc - (memory (export "memory") 1) - ) - (core instance $libc (instantiate $libc)) - (core func $f (canon lower (func $f) string-encoding=utf8 (memory $libc "memory"))) - (core module $m - (import "" "" (func $f (param i32 i32))) - - (func $start (call $f (i32.const 0x8000_0000) (i32.const 1))) - (start $start) - ) - (core instance (instantiate $m (with "" (instance (export "" (func $f)))))) - ) - - (instance $c (instantiate $c)) - (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) - ) - "string content out-of-bounds") diff --git a/src/test/resources/spec-tests/wasmtime/tags.wast b/src/test/resources/spec-tests/wasmtime/tags.wast deleted file mode 100644 index cac1fde..0000000 --- a/src/test/resources/spec-tests/wasmtime/tags.wast +++ /dev/null @@ -1,14 +0,0 @@ -;;! exceptions = true - -(component - (core module $a (tag (export "t"))) - (core module $b (import "a" "t" (tag))) - - (core instance $a (instantiate $a)) - (core instance (instantiate $b (with "a" (instance $a)))) - (core instance (instantiate $b - (with "a" (instance - (export "t" (tag $a "t")) - )) - )) -) diff --git a/src/test/resources/spec-tests/wasmtime/types.wast b/src/test/resources/spec-tests/wasmtime/types.wast deleted file mode 100644 index 9596ebe..0000000 --- a/src/test/resources/spec-tests/wasmtime/types.wast +++ /dev/null @@ -1,355 +0,0 @@ -(component - (type string) - (type (func (param "a" string))) - (type $r (record (field "x" (result)) (field "y" string))) - (type $u (variant (case "r" $r) (case "s" string))) - (type $e (result $u (error u32))) - (type (result $u)) - (type (result (error $u))) - (type (result)) - - (type (func (param "a" $e) (result (option $r)))) - - (type (variant - (case "a" string) - (case "b" u32) - (case "c" float32) - (case "d" float64) - )) - - (type $errno (enum "a" "b" "e")) - (type (list $errno)) - (type $oflags (flags "read" "write" "exclusive")) - (type (tuple $oflags $errno $r)) - - ;; primitives in functions - (type (func - (param "a" bool) - (param "b" u8) - (param "c" s8) - (param "d" u16) - (param "e" s16) - (param "f" u32) - (param "g" s32) - (param "h" u64) - (param "i" s64) - (param "j" char) - (param "k" string) - )) - - ;; primitives in types - (type bool) - (type u8) - (type s8) - (type u16) - (type s16) - (type u32) - (type s32) - (type u64) - (type s64) - (type char) - (type string) -) - -(component - (type $empty (func)) - (type (func (param "a" string) (result u32))) - (type (component)) - (core type (module)) - (core type (func)) - (type (instance)) - - (type (component - (import "x" (func (type $empty))) - (import "y" (func)) - (import "z" (component)) - - (type $t (instance)) - - (export "a" (core module)) - (export "b" (instance (type $t))) - )) - - (type (instance - (export "x" (func (type $empty))) - (export "y" (func)) - (export "z" (component)) - - (type $t (instance)) - - (export "a" (core module)) - (export "b" (instance (type $t))) - )) - - (core type (module - (import "" "" (func (param i32))) - (import "" "1" (func (result i32))) - (export "1" (global i32)) - (export "2" (memory 1)) - (export "3" (table 1 funcref)) - )) -) - -;; outer core aliases work -(component $C - (core type $f (func)) - (core type $m (module)) - - (component $C2 - (alias outer $C $f (core type $my_f)) - (import "a" (core module (type $m))) - (import "x" (core module - (alias outer $C2 $my_f (type $my_f)) - (import "" "1" (func (type $my_f))) - )) - ) -) - -;; type exports work -(component $C - (component $C2 - (type string) - (export "x" (type 0)) - ) - (instance (instantiate 0)) - (alias export 0 "x" (type)) - (export "x" (type 0)) -) - -(component - (core module $m (func (export "") (param i32) (result i32) local.get 0)) - (core instance $m (instantiate $m)) - (func (export "i-to-b") (param "a" u32) (result bool) (canon lift (core func $m ""))) - (func (export "i-to-u8") (param "a" u32) (result u8) (canon lift (core func $m ""))) - (func (export "i-to-s8") (param "a" u32) (result s8) (canon lift (core func $m ""))) - (func (export "i-to-u16") (param "a" u32) (result u16) (canon lift (core func $m ""))) - (func (export "i-to-s16") (param "a" u32) (result s16) (canon lift (core func $m ""))) -) -(assert_return (invoke "i-to-b" (u32.const 0)) (bool.const false)) -(assert_return (invoke "i-to-b" (u32.const 1)) (bool.const true)) -(assert_return (invoke "i-to-b" (u32.const 2)) (bool.const true)) -(assert_return (invoke "i-to-u8" (u32.const 0x00)) (u8.const 0)) -(assert_return (invoke "i-to-u8" (u32.const 0x01)) (u8.const 1)) -(assert_return (invoke "i-to-u8" (u32.const 0xf01)) (u8.const 1)) -(assert_return (invoke "i-to-u8" (u32.const 0xf00)) (u8.const 0)) -(assert_return (invoke "i-to-s8" (u32.const 0xffffffff)) (s8.const -1)) -(assert_return (invoke "i-to-s8" (u32.const 127)) (s8.const 127)) -(assert_return (invoke "i-to-u16" (u32.const 0)) (u16.const 0)) -(assert_return (invoke "i-to-u16" (u32.const 1)) (u16.const 1)) -(assert_return (invoke "i-to-u16" (u32.const 0xffffffff)) (u16.const 0xffff)) -(assert_return (invoke "i-to-s16" (u32.const 0)) (s16.const 0)) -(assert_return (invoke "i-to-s16" (u32.const 1)) (s16.const 1)) -(assert_return (invoke "i-to-s16" (u32.const 0xffffffff)) (s16.const -1)) - -(assert_invalid - (component - (type $t1 string) - (type $t2 (list $t1)) - (type $t3 (list $t2)) - (type $t4 (list $t3)) - (type $t5 (list $t4)) - (type $t6 (list $t5)) - (type $t7 (list $t6)) - (type $t8 (list $t7)) - (type $t9 (list $t8)) - (type $t10 (list $t9)) - (type $t11 (list $t10)) - (type $t12 (list $t11)) - (type $t13 (list $t12)) - (type $t14 (list $t13)) - (type $t15 (list $t14)) - (type $t16 (list $t15)) - (type $t17 (list $t16)) - (type $t18 (list $t17)) - (type $t19 (list $t18)) - (type $t20 (list $t19)) - (type $t21 (list $t20)) - (type $t22 (list $t21)) - (type $t23 (list $t22)) - (type $t24 (list $t23)) - (type $t25 (list $t24)) - (type $t26 (list $t25)) - (type $t27 (list $t26)) - (type $t28 (list $t27)) - (type $t29 (list $t28)) - (type $t30 (list $t29)) - (type $t31 (list $t30)) - (type $t32 (list $t31)) - (type $t33 (list $t32)) - (type $t34 (list $t33)) - (type $t35 (list $t34)) - (type $t36 (list $t35)) - (type $t37 (list $t36)) - (type $t38 (list $t37)) - (type $t39 (list $t38)) - (type $t40 (list $t39)) - (type $t41 (list $t40)) - (type $t42 (list $t41)) - (type $t43 (list $t42)) - (type $t44 (list $t43)) - (type $t45 (list $t44)) - (type $t46 (list $t45)) - (type $t47 (list $t46)) - (type $t48 (list $t47)) - (type $t49 (list $t48)) - (type $t50 (list $t49)) - (type $t51 (list $t50)) - (type $t52 (list $t51)) - (type $t53 (list $t52)) - (type $t54 (list $t53)) - (type $t55 (list $t54)) - (type $t56 (list $t55)) - (type $t57 (list $t56)) - (type $t58 (list $t57)) - (type $t59 (list $t58)) - (type $t60 (list $t59)) - (type $t61 (list $t60)) - (type $t62 (list $t61)) - (type $t63 (list $t62)) - (type $t64 (list $t63)) - (type $t65 (list $t64)) - (type $t66 (list $t65)) - (type $t67 (list $t66)) - (type $t68 (list $t67)) - (type $t69 (list $t68)) - (type $t70 (list $t69)) - (type $t71 (list $t70)) - (type $t72 (list $t71)) - (type $t73 (list $t72)) - (type $t74 (list $t73)) - (type $t75 (list $t74)) - (type $t76 (list $t75)) - (type $t77 (list $t76)) - (type $t78 (list $t77)) - (type $t79 (list $t78)) - (type $t80 (list $t79)) - (type $t81 (list $t80)) - (type $t82 (list $t81)) - (type $t83 (list $t82)) - (type $t84 (list $t83)) - (type $t85 (list $t84)) - (type $t86 (list $t85)) - (type $t87 (list $t86)) - (type $t88 (list $t87)) - (type $t89 (list $t88)) - (type $t90 (list $t89)) - (type $t91 (list $t90)) - (type $t92 (list $t91)) - (type $t93 (list $t92)) - (type $t94 (list $t93)) - (type $t95 (list $t94)) - (type $t96 (list $t95)) - (type $t97 (list $t96)) - (type $t98 (list $t97)) - (type $t99 (list $t98)) - (type $t100 (list $t99)) - (type $t101 (list $t100)) - (export "t" (type $t101)) - ) - "type nesting is too deep") - -(component - (type (instance - (export "x" (instance $x - (type $t u32) - (export "y" (type (eq $t))) - )) - (alias export $x "y" (type $t)) - (export "my-y" (type (eq $t))) - )) - - (type (component - (import "x" (instance $x - (type $t u32) - (export "y" (type (eq $t))) - )) - (alias export $x "y" (type $t)) - (export "my-y" (type (eq $t))) - )) -) - -(component - (type $t u32) - (export $t2 "t" (type $t)) - (type $r (record (field "x" $t2))) - (export "r" (type $r)) -) - -(component - (component - (import "x" (instance $i - (type $i u32) - (export "i" (type (eq $i))) - )) - (alias export $i "i" (type $i)) - (export "i" (type $i)) - ) -) - -(component - (type $u u32) - (instance $i - (export "i" (type $u)) - ) - (alias export $i "i" (type $i)) - (export "i" (type $i)) -) - -(component - (component $c - (type $t u32) - (export "t" (type $t)) - ) - (instance $c (instantiate $c)) - (export "i" (type $c "t")) -) - -(component - (component $c - (import "x" (component $c - (type $t u32) - (export "t" (type (eq $t))) - )) - (instance $c (instantiate $c)) - (export "i" (type $c "t")) - ) - - (component $x - (type $t u32) - (export "t" (type $t)) - ) - - (instance $c (instantiate $c (with "x" (component $x)))) -) - -(component - (type $t1 u64) - (import "a" (type $t2 (eq $t1))) - (import "b" (type $t3 (eq $t2))) -) - -(component - (import "a" (instance - (type $t1 u64) - (export "a" (type $t2 (eq $t1))) - (export "b" (type (eq $t2))) - )) -) - -(component - (type (export "x") (component - (type $t' (instance - (export "r" (type (sub resource))) - )) - (export "t" (instance $t (type $t'))) - )) -) - -(component - (type (export "x") (instance - (type $t' (instance - (export "r" (type (sub resource))) - )) - (export "t" (instance $t (type $t'))) - )) -) diff --git a/parser/update-spec-tests.sh b/update-spec-tests.sh similarity index 97% rename from parser/update-spec-tests.sh rename to update-spec-tests.sh index b4b0038..80da18a 100755 --- a/parser/update-spec-tests.sh +++ b/update-spec-tests.sh @@ -4,7 +4,7 @@ set -euo pipefail REPO="WebAssembly/component-model" BRANCH="main" REMOTE_TEST_DIR="test" -LOCAL_TEST_DIR="src/test/resources/spec-tests" +LOCAL_TEST_DIR="parser/src/test/resources/spec-tests" API_BASE="https://api.github.com/repos/${REPO}/contents" RAW_BASE="https://raw.githubusercontent.com/${REPO}/${BRANCH}" From cd762528a7bf72ec1a5a5a4e2bb8a6994fb4f596 Mon Sep 17 00:00:00 2001 From: andreatp Date: Wed, 24 Jun 2026 12:07:39 +0100 Subject: [PATCH 7/8] fix CI workflow --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cad6358..6b8ee8d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,6 +33,8 @@ jobs: git clone --depth 1 https://github.com/bytecodealliance/endive.git /tmp/endive cd /tmp/endive mvn -B -Dquickly install + - name: Prepare wast files + run: ./update-spec-tests.sh - name: Build and test run: mvn -B install - name: Publish Test Report From f2a94361814596c59047b79e37f71c658109c148 Mon Sep 17 00:00:00 2001 From: andreatp Date: Wed, 24 Jun 2026 12:20:23 +0100 Subject: [PATCH 8/8] Decouple parser from wasm-tools and fix Java 17 build Move ComponentValidate.validate() from ComponentParser into the test harness so the parser has no runtime dependency on wasm-tools. Move wasm-tools-related dependencies to test scope. Move checkstyle plugin to a java21 profile since checkstyle 13.x requires Java 21+. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/ci.yml | 2 +- parser/pom.xml | 54 ++++++++++--------- .../run/endive/cm/parser/ComponentParser.java | 8 --- .../run/endive/cm/parser/JsonFromWast.java | 21 ++++---- .../java/run/endive/cm/parser/WastTests.java | 15 +++--- pom.xml | 11 ++++ 6 files changed, 60 insertions(+), 51 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6b8ee8d..362998d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: strategy: fail-fast: false matrix: - java-version: [11, 21] + java-version: [11, 25] steps: - uses: actions/checkout@v7 - name: Set up Java diff --git a/parser/pom.xml b/parser/pom.xml index cce28c4..9d4be98 100644 --- a/parser/pom.xml +++ b/parser/pom.xml @@ -13,43 +13,24 @@ Binary parser for Endive Component Model - - io.roastedroot - zerofs - - - run.endive - log - - - run.endive - runtime - - - run.endive - wasi - run.endive wasm - - run.endive - wasm-tools - run.endive.cm types - - run.endive.cm - wasm-tools - com.fasterxml.jackson.core jackson-databind test + + io.roastedroot + zerofs + test + org.assertj assertj-core @@ -65,6 +46,31 @@ junit-jupiter-params test + + run.endive + log + test + + + run.endive + runtime + test + + + run.endive + wasi + test + + + run.endive + wasm-tools + test + + + run.endive.cm + wasm-tools + test + diff --git a/parser/src/main/java/run/endive/cm/parser/ComponentParser.java b/parser/src/main/java/run/endive/cm/parser/ComponentParser.java index b877fc2..8212a75 100644 --- a/parser/src/main/java/run/endive/cm/parser/ComponentParser.java +++ b/parser/src/main/java/run/endive/cm/parser/ComponentParser.java @@ -11,7 +11,6 @@ import java.nio.ByteOrder; import java.util.Arrays; import java.util.function.Supplier; -import run.endive.cm.tools.ComponentValidate; import run.endive.cm.types.CoreAlias; import run.endive.cm.types.CoreExportDecl; import run.endive.cm.types.CoreImportDecl; @@ -83,13 +82,6 @@ public WasmComponent parse(Supplier inputStreamSupplier) { private void parse(InputStream in, ComponentParserListener listener) { requireNonNull(listener, "listener"); - ComponentValidate.validate(in); - try { - in.reset(); - } catch (IOException e) { - throw new RuntimeException(e); - } - var buffer = readByteBuffer(in); byte[] magic = new byte[4]; diff --git a/parser/src/test/java/run/endive/cm/parser/JsonFromWast.java b/parser/src/test/java/run/endive/cm/parser/JsonFromWast.java index 5611328..9809fd9 100644 --- a/parser/src/test/java/run/endive/cm/parser/JsonFromWast.java +++ b/parser/src/test/java/run/endive/cm/parser/JsonFromWast.java @@ -2,6 +2,16 @@ import io.roastedroot.zerofs.Configuration; import io.roastedroot.zerofs.ZeroFs; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; import run.endive.cm.tools.ComponentValidateException; import run.endive.log.Logger; import run.endive.log.SystemLogger; @@ -14,17 +24,6 @@ import run.endive.wasi.WasiPreview1; import run.endive.wasm.WasmModule; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystem; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - public final class JsonFromWast { private JsonFromWast() {} diff --git a/parser/src/test/java/run/endive/cm/parser/WastTests.java b/parser/src/test/java/run/endive/cm/parser/WastTests.java index 6f25994..519651d 100644 --- a/parser/src/test/java/run/endive/cm/parser/WastTests.java +++ b/parser/src/test/java/run/endive/cm/parser/WastTests.java @@ -16,6 +16,7 @@ import java.util.List; import java.util.Map; import java.util.stream.IntStream; +import run.endive.cm.tools.ComponentValidate; import run.endive.cm.tools.ComponentValidateException; import run.endive.cm.types.WasmComponent; @@ -86,13 +87,13 @@ void execute( default WasmComponent parseComponent(Path location, String filename) throws CommandException { var filePath = location.resolve(filename); - try (var in = new ByteArrayInputStream(Files.readAllBytes(filePath))) { - try { - var parser = ComponentParser.builder().build(); - return parser.parse(() -> in); - } catch (UnsupportedOperationException e) { - throw new CommandException(filePath, e); - } + try { + byte[] bytes = Files.readAllBytes(filePath); + ComponentValidate.validate(new ByteArrayInputStream(bytes)); + var parser = ComponentParser.builder().build(); + return parser.parse(() -> new ByteArrayInputStream(bytes)); + } catch (UnsupportedOperationException e) { + throw new CommandException(filePath, e); } catch (IOException e) { throw new CommandException(filePath, e); } diff --git a/pom.xml b/pom.xml index dd41c87..3620b06 100644 --- a/pom.xml +++ b/pom.xml @@ -238,6 +238,17 @@ + + + + + + java21 + + [21,) + + + org.apache.maven.plugins maven-checkstyle-plugin