Assemblyscript: Calling `new Array` causes module load error "module is not an object or function"

Created on 26 Aug 2018  路  4Comments  路  Source: AssemblyScript/assemblyscript

To reproduce:

  • Go to a new empty directory.
  • asinit .
  • Change index.ts to:
import "allocator/tlsf";

export function add(a: i32, b: i32): i32 {
    new Array<i32>(a);
    return a + b;
}
  • npm run asbuild
  • node index.js causes an error: TypeError: WebAssembly Instantiation: Import #0 module="env" error: module is not an object or function
question

Most helpful comment

Yeah, asbuild script needs update. For now you can use this code for index.js:

const fs = require("fs");
const compiled = new WebAssembly.Module(fs.readFileSync(__dirname + "/build/optimized.wasm"));
const imports = {
  env: {
    abort(msgPtr, filePtr, line, column) {
      throw new Error(`index.ts: abort at [${ line }:${ column }]`);
    }
  }
};
Object.defineProperty(module, "exports", {
  get: () => new WebAssembly.Instance(compiled, imports).exports
});

All 4 comments

Yeah, asbuild script needs update. For now you can use this code for index.js:

const fs = require("fs");
const compiled = new WebAssembly.Module(fs.readFileSync(__dirname + "/build/optimized.wasm"));
const imports = {
  env: {
    abort(msgPtr, filePtr, line, column) {
      throw new Error(`index.ts: abort at [${ line }:${ column }]`);
    }
  }
};
Object.defineProperty(module, "exports", {
  get: () => new WebAssembly.Instance(compiled, imports).exports
});

This is more a question than an issue, but what's the recommended way to handle unmanaged (heap-allocated but not garbage-collected) objects?
The best I've figured out so far is this:

@unmanaged
class Point {
    x: f64;
    y: f64;

    public sum(): f64 {
        return this.x + this.y;
    }
}
function alloc_point(x: f64, y: f64): Point {
    let p = changetype<Point>(memory.allocate(sizeof<f64>() + sizeof<f64>())); // sizeof<Point> is size of pointer...
    p.x = x;
    p.y = y;
    return p;
}
function free_point(p: Point): void {
    memory.free(changetype<usize>(p));
}

export function test(a: f64, b: f64): f64 {
    let p = alloc_point(a, b);
    let res = p.sum();
    free_point(p);
    return res;
}

The disadvantage is that I need to write alloc_X and free_X functions for every type (requires casts if there are readonly or private members). It would be nice to have emplacement and destructors like in c++ so we could have unique_ptr and arrays that store their elements by-value instead of storing pointers. Is there an issue already open similar to this?

Note that emplacement-style signatures can be typed in typescript:

type CtrParams<Ctr> = Ctr extends new (...args: infer P) => unknown ? P : never;
type CtrReturn<Ctr> = Ctr extends new (...args: any[]) => infer T ? T : never;

class Point { constructor(readonly a: number, readonly b: number) {} }

declare class ByValueArray<TCtr> {
    emplace(...params: CtrParams<TCtr>): CtrReturn<TCtr>;
}
let v = new ByValueArray<typeof Point>();
let p: Point = v.emplace(1, 2);

You could use:

function alloc<T>(): T {
  return changetype<T>(memory.allocate(offsetof<T>()));
}

function free<T>(obj: T): void {
  memory.free(changetype<usize>(obj));
}
var p = alloc<Point>();
...
free(p);

Here, offsetof<Point>() returns the size of a Point structure with all fields layed out.

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dcodeIO picture dcodeIO  路  4Comments

MaxGraey picture MaxGraey  路  3Comments

DanielMazurkiewicz picture DanielMazurkiewicz  路  4Comments

evgenykuzyakov picture evgenykuzyakov  路  3Comments

lastmjs picture lastmjs  路  4Comments