Skip to content

env module isn't imported, using moduleImports and --importMemory together #2823

Open
@a-skua

Description

@a-skua

Bug description

moduleImpors(cases where @external or declare are used) together with the --importMemory flag, the glue code does not include the imports of the env module.

e.g. build assembly/index.ts with the following settings in asconfig.json.

{
  "targets": {
    "release": {
      "outFile": "build/release.wasm",
      "textFile": "build/release.wat",
      "sourceMap": true,
      "converge": false,
      "noAssert": true
    }
  },
  "options": {
    "bindings": "raw",
    "runtime": "minimal",
    "importMemory": true
  }
}
@external("app", "add")
declare function add(a: i32, b: i32): i32;

export function run(): void {
  add(1, 2);
}

Wasm expects imports for app.add and env.memory, but in the actual generated build/release.js, only the app module is imported, and the import for the env module is missing.

(module
 (type $0 (func (param i32 i32) (result i32)))
 (type $1 (func))
 (import "env" "memory" (memory $0 0))
 (import "app" "add" (func $assembly/index/add (param i32 i32) (result i32)))
 (table $0 1 1 funcref)
 (elem $0 (i32.const 1))
 (export "run" (func $assembly/index/run))
 (export "memory" (memory $0))
 (func $assembly/index/run
  i32.const 1
  i32.const 2
  call $assembly/index/add
  drop
 )
)
export async function instantiate(module, imports = {}) {
  const __module0 = imports.app;
  const adaptedImports = {
    app: __module0,
  };
  const { exports } = await WebAssembly.instantiate(module, adaptedImports);
  return exports;
}

While changing app.add to env.add can circumvent this issue, the desired outcome is to control the size of the memory from outside Wasm.
So, the expectation is for code similar to the following to be generated.

export async function instantiate(module, imports = {}) {
  const __module0 = imports.app;
  const adaptedImports = {
    app: __module0,
+   env: Object.assign(Object.create(globalThis), imports.env || {}),
  };
  const { exports } = await WebAssembly.instantiate(module, adaptedImports);
  return exports;
}

Steps to reproduce

asconfig.json

{
  "targets": {
    "release": {
      "outFile": "build/release.wasm",
      "textFile": "build/release.wat",
      "sourceMap": true,
      "converge": false,
      "noAssert": true
    }
  },
  "options": {
    "bindings": "raw",
    "runtime": "minimal",
    "importMemory": true
  }
}

assembly/index.ts

@external("app", "add")
declare function add(a: i32, b: i32): i32;

export function run(): void {
  add(1, 2);
}

index.js

import { instantiate } from "./build/release.js";
const exports = await instantiate(await WebAssembly.compileStreaming(fetch(new URL("./build/release.wasm", import.meta.url))), {
  app: {
    add(a: number, b: number) {
      return a + b;
    },
  },
  env: {
    memory: new WebAssembly.Memory({
      initial: 1,
      maximum: 1,
    }),
  },
});

exports.run();

Caution

error: Uncaught (in promise) TypeError: WebAssembly.instantiate(): Import #1 module="env": module is not an object or function
  const { exports } = await WebAssembly.instantiate(module, adaptedImports);
                                        ^

AssemblyScript version

v0.27.24

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions