Skip to content

Error when calling js from wasm,error:WebAssembly Instantiation: Import #0 module="module" error: module is not an object or function #384

Closed

Description

@evanyuanvip

According to this #158, I tried it, but I was given an error. My code is:

declare namespace console {
   function logi(val: i32): void;
}
@external("env", "logf")
declare function logf(val: f64): void;
console.logi(123);
logf(1e10);
export function add(a: i32, b: i32): i32 {
  return a + b;
}
var importObject = {
	env: {
	    // import as @external("env", "logf")
	    logf(value) {
	      console.log("logf: " + value);
	    },
	    abort(msg, file, line, column) {
	      console.error("abort called at main.ts:" + line + ":" + column);
	    }
	},
	  console: {
	    // import as console.logi
	    logi(value) {
	      console.log("logi: " + value);
	    }
	}
}

fetch('dist/module.optimized.wasm')
    .then(res => res.arrayBuffer())
    .then(bytes => new WebAssembly.Instance(new WebAssembly.Module(bytes),importObject))
    .then(mod => {
    	console.log(mod.exports.add(503,100));
    });
(module
 (type $iv (func (param i32)))
 (type $Fv (func (param f64)))
 (type $iii (func (param i32 i32) (result i32)))
 (type $v (func))
 (import "module" "console.logi" (func $assembly/module/console.logi (param i32)))
 (import "env" "logf" (func $assembly/module/logf (param f64)))
 (memory $0 0)
 (table $0 1 anyfunc)
 (elem (i32.const 0) $null)
 (export "memory" (memory $0))
 (export "table" (table $0))
 (export "add" (func $assembly/module/add))
 (start $start)
 (func $assembly/module/add (; 2 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
  get_local $0
  get_local $1
  i32.add
 )
 (func $start (; 3 ;) (type $v)
  i32.const 123
  call $assembly/module/console.logi
  f64.const 1e10
  call $assembly/module/logf
 )
 (func $null (; 4 ;) (type $v)
  nop
 )
)
"scripts": {
    "build": "npm run build:untouched && npm run build:optimized",
    "build:untouched": "asc assembly/module.ts -t dist/module.untouched.wat -b dist/module.untouched.wasm --validate --sourceMap --measure",
    "build:optimized": "asc assembly/module.ts -t dist/module.optimized.wat -b dist/module.optimized.wasm --validate --sourceMap --measure --optimize"
  }

Activity

  1. dcodeIO commented on Dec 20, 2018

    @dcodeIO
    Member

    According to your code, the JS side expects an import named module with a property console.logi. This changed recently to use the enclosing file name without extension as the default module name (here: module.ts -> module), so it might be that the documentation isn't up to date.

  2. evanyuanvip commented on Dec 21, 2018

    @evanyuanvip
    Author

    According to your code, the JS side expects an import named module with a property console.logi. This changed recently to use the enclosing file name without extension as the default module name (here: module.ts -> module), so it might be that the documentation isn't up to date.

    Can you give me a simple example?

  3. goldenratio commented on Jan 4, 2019

    @goldenratio

    @evanyuanvip you need to include module in your importObject also env.memory and env.table

    Example:

    const importObj = {
      module: {},
      env: {
        memory: new WebAssembly.Memory({ initial: 256 }),
        table: new WebAssembly.Table({ initial: 0, element: 'anyfunc' })
      }
    };
    
    

    source: https://gist.github.com/kripken/59c67556dc03bb6d57052fedef1e61ab#file-hello_world-html-L24

    Demo: https://github.com/goldenratio/wasm-helloworld

  4. evanyuanvip commented on Jan 7, 2019

    @evanyuanvip
    Author

    @goldenratio Thank you !

  5. dcodeIO commented on Feb 7, 2019

    @dcodeIO
    Member

    Closing this issue for now as it hasn't received any replies recently. Feel free to reopen it if necessary!

  6. torch2424 commented on Feb 28, 2019

    @torch2424
    Contributor

    @dcodeIO So if you get the chance, I think this still has some weird behavior. I know have to do this in wasmboy: https://github.com/torch2424/wasmboy/blob/80441371e2da5ecec3d7e0b6fb4d53e08aa008ca/core/portable/importObject.js

    As it would complain with Import #0 module="index" .... And I can't get namespaces working, even if I add them under index. I don't mind this, but I just wanted to let you know 😄

  7. dcodeIO commented on Feb 28, 2019

    @dcodeIO
    Member

    This works for me

    declare namespace console {
      @external("console", "log")
      export function log(): void;
    }

    but it seems that @external on namespaces does nothing currently. That the issue here?

  8. torch2424 commented on Feb 28, 2019

    @torch2424
    Contributor

    Ahh, I didn't try declaring both the namespace, and exporting the log. I'll try that once I get the chance 👍

  9. trusktr commented on May 27, 2019

    @trusktr
    Member

    I'm trying the example from #158, and I too get the error. I'm not sure how to fix it. I tried adding module: {} as mentioned above in #384 (comment), but the error remains the same.

    So in JS I have

    	await WebAssembly.instantiateStreaming(response, {
    		module: {},
    		console: {
    			logi() {
    				return 4
    			},
    		},
    	})

    then in AS I have

    declare namespace console {
    	function logi(): i32
    }
    
    // this is exported so it can be called on the JS side.
    export function mul(a: i32, b: i32): i32 {
    	return a * b + console.logi()
    }

    But it at runtime it says

    Uncaught (in promise) TypeError: WebAssembly.instantiate(): Import #0 module="index" error: module is not an object or function
    

    How do we make it work?

  10. trusktr commented on May 27, 2019

    @trusktr
    Member

    Okay, my file is called index.ts, so I changed module: {} to index: {}, and got passed that error.

    But now I get

    Uncaught (in promise) LinkError: WebAssembly.instantiate(): Import #0 module="index" function="console.logi" error: function import requires a callable
    

    What did I do wrong?

  11. trusktr commented on May 27, 2019

    @trusktr
    Member

    The only way I can get it to work is by putting stuff in env, then using the form

    @external("env", "getFour")
    declare function getFour(): i32;

    but I'd like to avoid the non-standard syntax (decorators only allowed on classes).

  12. trusktr commented on May 27, 2019

    @trusktr
    Member

    The reason I'm trying to use the namespace technique is that I wanted to write portable code, and decorators are only allowed on functions.

    But I found a workaround: I put the imports with the @external decorators in a separate file. I have the following structure:

    project
      |-- index.ts
      |-- imports.ts
      |-- mul.ts
    

    And here's the AS files:

    // index.ts
    import {mul} from './mul'
    export {mul}
    // this file import things passed in from JS, and exports them for use by other
    // AS modules.
    
    @external("env", "getFour")
    declare function getFour(): i32
    
    export {getFour}
    import {getFour} from './imports'
    
    // this is exported so it can be called on the JS side.
    export function mul(a: i32, b: i32): i32 {
    	return a * b + getFour()
    }

    Then in JS supply getFour:

    const {mul} = 	(await WebAssembly.instantiateStreaming(response, {
    	env: {
    		// this is called by `assert()`ions in the AssemblyScript.
    		// Useful for debugging.
    		abort(...args) {
    			console.log(...args)
    		},
    		
    		getFour() {
    			return 4
    		},
    	},
    })).instance.exports
    
    mul(3,5) // it works

    So, the mul code can import the getFour function, regardless of where it actually comes from.

    Now we can at least have a better time writing portable code, because if we want to run this outside of AssemblyScript, then we can supply an alternative source for the ./imports module (f.e. using Webpack, or a CommonJS module that we place alongside the tsc output, etc). So at least the mul file is portable.

  13. dcodeIO commented on May 27, 2019

    @dcodeIO
    Member

    Internally, we usually have a file env.ts that we import from, containing the declares. This way, the module name will be env.

  14. trusktr commented on May 27, 2019

    @trusktr
    Member

    @dcodeIO Thanks, that's good to know. How do we get the declare namespace version working?

  15. dcodeIO commented on May 27, 2019

    @dcodeIO
    Member

    I think in

    declare namespace console {
    	function logi(): i32 // it's missing an export here
    }
  16. torch2424 commented on May 28, 2019

    @torch2424
    Contributor

    Just in case it helps someone, this is my current importObject, that is passed during Wasm Instantiation.

  17. anubhavgupta commented on Aug 29, 2020

    @anubhavgupta

    This works:

    // assemblyScript file
    declare namespace console {
      function log(str: string): void;
    } 
    export function add(a: i32, b: i32): i32 {
      console.log("AnubhavGupta");
      return a + b;
    }
    // JS file
        await loader.instantiate(buffer,{
            index: {
                "console.log": (val) => console.log("log:", val)
            }
        });
  18. torch2424 commented on Aug 31, 2020

    @torch2424
    Contributor

    Ah, so if anyone else comes across this, this is because imports are namespaced per their filename. So importing console in index.ts, means console needs to be inside an index object in the imports.

    For example see the docs: https://www.assemblyscript.org/exports-and-imports.html#imports

    And if you don't want this behavior, and want control on how things are declared in the import object, see the custom naming in the docs: https://www.assemblyscript.org/exports-and-imports.html#imports

    For more general information on WebAssembly Imports in AssemblyScript, see: https://wasmbyexample.dev/examples/importing-javascript-functions-into-webassembly/importing-javascript-functions-into-webassembly.assemblyscript.en-us.html?programmingLanguage=assemblyscript

  19. trusktr commented on Feb 7, 2021

    @trusktr
    Member

    What if two AS files have the same name, but they are at different paths in the file system?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions