mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 15:12:12 +00:00
Initial loader that unifies utils and demangle
This commit is contained in:
parent
d678807286
commit
98a0aa863d
@ -1,39 +0,0 @@
|
|||||||
 demangle
|
|
||||||
======================
|
|
||||||
|
|
||||||
Demangles AssemblyScript module exports to a friendly object structure compatible with WebIDL and TypeScript definitions.
|
|
||||||
|
|
||||||
Usage
|
|
||||||
-----
|
|
||||||
|
|
||||||
```js
|
|
||||||
var module = require("@assemblyscript/demangle")(myWasmModule.instance.exports);
|
|
||||||
// use module as defined in the .d.ts
|
|
||||||
```
|
|
||||||
|
|
||||||
Converting a memory offset (`this` value) to a class instance, i.e. where a class instance is returned by a WebAssembly function:
|
|
||||||
|
|
||||||
```js
|
|
||||||
|
|
||||||
var thisValue = wasmFunctionReturningAClassInstance();
|
|
||||||
var myClass = MyClass.wrap(thisValue);
|
|
||||||
```
|
|
||||||
|
|
||||||
Converting a class instance to a memory offset (`this` value), i.e. where calling a WebAssembly function that expects a class instance:
|
|
||||||
|
|
||||||
```js
|
|
||||||
var thisValue = myClass.this;
|
|
||||||
wasmFunctionExpectingAClassInstance(thisValue);
|
|
||||||
```
|
|
||||||
|
|
||||||
How does it work?
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
AssemblyScript modules expose their exported elements by their internal name, which is a JSDoc-style fully qualified name indicating layers of nesting, and this module is able to recreate the original object structure from those names.
|
|
||||||
|
|
||||||
* A `.` seperates a parent from a static child
|
|
||||||
* A `#` separates a parent from an instance child
|
|
||||||
* The `get:` prefix indicates a getter
|
|
||||||
* The `set:` prefix indicates a setter
|
|
||||||
|
|
||||||
Note that the compiler generates implicit getters and setters for instance fields for convenience. Support for instance members is achieved by generating wrappers that prepend the `this` value (offset of the instance in memory returned by the constructor) as the first argument when calling an instance method, getter or setter.
|
|
@ -1,58 +0,0 @@
|
|||||||
module.exports = demangle;
|
|
||||||
|
|
||||||
/** Demangles AssemblyScript module exports to a friendly object structure. */
|
|
||||||
function demangle(exports) {
|
|
||||||
var root = {};
|
|
||||||
for (let internalName in exports) {
|
|
||||||
if (!exports.hasOwnProperty(internalName)) continue;
|
|
||||||
let elem = exports[internalName];
|
|
||||||
let parts = internalName.split(".");
|
|
||||||
let curr = root;
|
|
||||||
while (parts.length > 1) {
|
|
||||||
let part = parts.shift();
|
|
||||||
if (!curr.hasOwnProperty(part)) curr[part] = {};
|
|
||||||
curr = curr[part];
|
|
||||||
}
|
|
||||||
let name = parts[0];
|
|
||||||
let hash = name.indexOf("#");
|
|
||||||
if (hash >= 0) {
|
|
||||||
let className = name.substring(0, hash);
|
|
||||||
let classElem = curr[className];
|
|
||||||
if (typeof classElem === "undefined" || !classElem.prototype) {
|
|
||||||
let ctor = function(...args) {
|
|
||||||
return ctor.wrap(ctor.prototype.constructor(...args));
|
|
||||||
};
|
|
||||||
ctor.prototype = {};
|
|
||||||
ctor.wrap = function(thisValue) {
|
|
||||||
return Object.create(ctor.prototype, { "this": { value: thisValue, writable: false } });
|
|
||||||
};
|
|
||||||
if (classElem) Object.getOwnPropertyNames(classElem).forEach(name =>
|
|
||||||
Object.defineProperty(ctor, name, Object.getOwnPropertyDescriptor(classElem, name))
|
|
||||||
);
|
|
||||||
curr[className] = ctor;
|
|
||||||
}
|
|
||||||
name = name.substring(hash + 1);
|
|
||||||
curr = curr[className].prototype;
|
|
||||||
if (/^(get|set):/.test(name)) {
|
|
||||||
if (!curr.hasOwnProperty(name = name.substring(4))) {
|
|
||||||
let getter = exports[internalName.replace("set:", "get:")];
|
|
||||||
let setter = exports[internalName.replace("get:", "set:")];
|
|
||||||
Object.defineProperty(curr, name, {
|
|
||||||
get: function() { return getter(this.this); },
|
|
||||||
set: function(value) { setter(this.this, value); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else curr[name] = function(...args) { return elem(this.this, ...args); };
|
|
||||||
} else {
|
|
||||||
if (/^(get|set):/.test(name)) {
|
|
||||||
if (!curr.hasOwnProperty(name = name.substring(4))) {
|
|
||||||
Object.defineProperty(curr, name, {
|
|
||||||
get: exports[internalName.replace("set:", "get:")],
|
|
||||||
set: exports[internalName.replace("get:", "set:")]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else curr[name] = elem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return root;
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
var assert = require("assert");
|
|
||||||
var inspect = require("util").inspect;
|
|
||||||
var demangle = require("..");
|
|
||||||
|
|
||||||
var __this = 8;
|
|
||||||
var __usualDoors = 3;
|
|
||||||
var __doors = -1;
|
|
||||||
|
|
||||||
var exports = demangle({
|
|
||||||
"vroom": function() { console.log("vroom", arguments); },
|
|
||||||
"Car.MAX_DOORS": 5,
|
|
||||||
"Car.get:usualDoors": function() { console.log("Car#get:usualDoors", arguments); return __usualDoors; },
|
|
||||||
"Car.set:usualDoors": function(value) { console.log("Car#set:usualDoors", arguments); __usualDoors = value; },
|
|
||||||
"Car#constructor": function(this_, doors) { console.log("Car#constructor", arguments); __doors = doors; return __this; },
|
|
||||||
"Car#openDoors": function(this_) { console.log("Car#openDoors", arguments); return true; },
|
|
||||||
"Car#get:doors": function(this_) { console.log("Car#get:doors", arguments); return __doors; },
|
|
||||||
"Car#set:doors": function(this_, value) { console.log("Car#set:doors", arguments); __doors = value; }
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(inspect(exports, true));
|
|
||||||
|
|
||||||
exports.vroom(1, 2, 3);
|
|
||||||
|
|
||||||
var Car = exports.Car;
|
|
||||||
|
|
||||||
assert(Car.usualDoors == 3);
|
|
||||||
exports.Car.usualDoors = exports.Car.usualDoors + 2;
|
|
||||||
assert(Car.usualDoors == 5);
|
|
||||||
|
|
||||||
var car = new exports.Car(2);
|
|
||||||
|
|
||||||
assert(car.this == 8);
|
|
||||||
|
|
||||||
assert(car.openDoors() == true);
|
|
||||||
assert(car.doors == 2);
|
|
||||||
car.doors = car.doors + 2;
|
|
||||||
assert(car.doors == 4);
|
|
||||||
|
|
||||||
console.log(inspect(car, true));
|
|
||||||
|
|
||||||
var wrappedCar = exports.Car.wrap(16);
|
|
||||||
|
|
||||||
assert(wrappedCar.this == 16);
|
|
||||||
|
|
||||||
console.log(inspect(wrappedCar, true));
|
|
132
lib/loader/README.md
Normal file
132
lib/loader/README.md
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
 loader
|
||||||
|
======================
|
||||||
|
|
||||||
|
A convenient loader for AssemblyScript modules. Demangles module exports to a friendly object structure compatible with WebIDL and TypeScript definitions and provides some useful utility to read/write data from/to memory.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
```js
|
||||||
|
const loader = require("@assemblyscript/loader");
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
API
|
||||||
|
---
|
||||||
|
|
||||||
|
* **instantiate**<`T`>(module: `WebAssembly.Module`, imports?: `WasmImports`): `ASModule<T>`<br />
|
||||||
|
Instantiates an AssemblyScript module using the specified imports.
|
||||||
|
|
||||||
|
* **instantiateBuffer**<`T`>(buffer: `Uint8Array`, imports?: `WasmImports`): `ASModule<T>`<br />
|
||||||
|
Instantiates an AssemblyScript module from a buffer using the specified imports.
|
||||||
|
|
||||||
|
* **instantiateStreaming**<`T`>(response: `Response`, imports?: `WasmImports`): `Promise<ASModule<T>>`<br />
|
||||||
|
Instantiates an AssemblyScript module from a response using the sspecified imports.
|
||||||
|
|
||||||
|
* **demangle**<`T`>(exports: `WasmExports`): `T`<br />
|
||||||
|
Demangles an AssemblyScript module's exports to a friendly object structure. You usually don't have to call this manually as instantiation does this implicitly.
|
||||||
|
|
||||||
|
**Note:** `T` above can either be omitted if the structure of the module is unknown, or can reference a `.d.ts` as produced by the compiler with the `-d` option.
|
||||||
|
|
||||||
|
Instances of `ASModule` are automatically populated with some useful utility:
|
||||||
|
|
||||||
|
* **I8**: `Int8Array`<br />
|
||||||
|
An 8-bit signed integer view on the memory.
|
||||||
|
|
||||||
|
* **U8**: `Uint8Array`<br />
|
||||||
|
An 8-bit unsigned integer view on the memory.
|
||||||
|
|
||||||
|
* **I16**: `Int16Array`<br />
|
||||||
|
A 16-bit signed integer view on the memory.
|
||||||
|
|
||||||
|
* **U16**: `Uint16Array`<br />
|
||||||
|
A 16-bit unsigned integer view on the memory.
|
||||||
|
|
||||||
|
* **I32**: `Int32Array`<br />
|
||||||
|
A 32-bit signed integer view on the memory.
|
||||||
|
|
||||||
|
* **U32**: `Uint32Array`<br />
|
||||||
|
A 32-bit unsigned integer view on the memory.
|
||||||
|
|
||||||
|
* **F32**: `Float32Array`<br />
|
||||||
|
A 32-bit float view on the memory.
|
||||||
|
|
||||||
|
* **F64**: `Float64Array`<br />
|
||||||
|
A 64-bit float view on the memory.
|
||||||
|
|
||||||
|
* **newString**(str: `string`): `number`<br />
|
||||||
|
Allocates a new string in the module's memory and returns its pointer. Requires `allocate_memory` to be exported from your module's entry file, i.e.:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import "allocator/tlsf";
|
||||||
|
export { allocate_memory, free_memory };
|
||||||
|
```
|
||||||
|
|
||||||
|
* **getString**(ptr: `number`): `string`<br />
|
||||||
|
Gets a string from the module's memory by its pointer.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
|
||||||
|
### Instantiating a module
|
||||||
|
|
||||||
|
```js
|
||||||
|
// From a module provided as a buffer, i.e. as returned by fs.readFileSync
|
||||||
|
const myModule = loader.instatiateBuffer(fs.readFileSync("myModule.wasm"), myImports);
|
||||||
|
|
||||||
|
// From a response object, i.e. as returned by window.fetch
|
||||||
|
const myModule = await loader.instantiateStreaming(fetch("myModule.wasm"), myImports);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Reading/writing basic values to/from memory
|
||||||
|
|
||||||
|
```js
|
||||||
|
var ptrToInt8 = ...;
|
||||||
|
var value = myModule.U16[ptrToInt8]; // alignment of log2(1)=0
|
||||||
|
|
||||||
|
var ptrToInt16 = ...;
|
||||||
|
var value = myModule.U16[ptrToInt16 >>> 1]; // alignment of log2(2)=1
|
||||||
|
|
||||||
|
var ptrToInt32 = ...;
|
||||||
|
var value = myModule.U32[ptrToInt32 >>> 2]; // alignment of log2(4)=2
|
||||||
|
|
||||||
|
var ptrToFloat32 = ...;
|
||||||
|
var value = myModule.F32[ptrToFloat32 >>> 2]; // alignment of log2(4)=2
|
||||||
|
|
||||||
|
var ptrToFloat64 = ...;
|
||||||
|
var value = myModule.F64[ptrToFloat64 >>> 3]; // alignment of log2(8)=3
|
||||||
|
|
||||||
|
// Likewise, for writing
|
||||||
|
myModule.U16[ptrToInt8] = newValue;
|
||||||
|
myModule.U16[ptrToInt16 >>> 1] = newValue;
|
||||||
|
myModule.U32[ptrToInt32 >>> 2] = newValue;
|
||||||
|
myModule.F32[ptrToFloat32 >>> 2] = newValue;
|
||||||
|
myModule.F64[ptrToFloat64 >>> 3] = newValue;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** Make sure to reference the views as shown above as these will automatically be updated when the module's memory grows.
|
||||||
|
|
||||||
|
### Allocating/obtaining strings to/from memory
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Allocating a string, i.e. to be passed to an export expecting one
|
||||||
|
var str = "Hello world!";
|
||||||
|
var ptr = module.newString(str);
|
||||||
|
|
||||||
|
// Disposing a string that is no longer needed (requires free_memory to be exported)
|
||||||
|
module.free_memory(ptr);
|
||||||
|
|
||||||
|
// Obtaining a string, i.e. as returned by an export
|
||||||
|
var ptrToString = ...;
|
||||||
|
var str = module.getString(ptrToString);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usage with TypeScript definitions produced by the compiler
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import MyModule from "myModule"; // pointing at the d.ts
|
||||||
|
|
||||||
|
const myModule = loader.instatiateBuffer<MyModule>(fs.readFileSync("myModule.wasm"), myImports);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Hint:** You can produce a `.d.ts` for your module with the `-d` option on the command line.
|
47
lib/loader/index.d.ts
vendored
Normal file
47
lib/loader/index.d.ts
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import "@types/webassembly-js-api";
|
||||||
|
|
||||||
|
/** WebAssembly imports with two levels of nesting. */
|
||||||
|
interface ImportsObject {
|
||||||
|
[key: string]: {},
|
||||||
|
env: {
|
||||||
|
memory?: WebAssembly.Memory,
|
||||||
|
table?: WebAssembly.Table,
|
||||||
|
abort?: (msg: number, file: number, line: number, column: number) => void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Utility mixed in by the loader. */
|
||||||
|
interface ASUtil {
|
||||||
|
/** An 8-bit signed integer view on the memory. */
|
||||||
|
readonly I8: Uint8Array,
|
||||||
|
/** An 8-bit unsigned integer view on the memory. */
|
||||||
|
readonly U8: Uint8Array,
|
||||||
|
/** A 16-bit signed integer view on the memory. */
|
||||||
|
readonly I16: Uint16Array,
|
||||||
|
/** A 16-bit unsigned integer view on the memory. */
|
||||||
|
readonly U16: Uint16Array,
|
||||||
|
/** A 32-bit signed integer view on the memory. */
|
||||||
|
readonly I32: Uint32Array,
|
||||||
|
/** A 32-bit unsigned integer view on the memory. */
|
||||||
|
readonly U32: Uint32Array,
|
||||||
|
/** A 32-bit float view on the memory. */
|
||||||
|
readonly F32: Float32Array,
|
||||||
|
/** A 64-bit float view on the memory. */
|
||||||
|
readonly F64: Float64Array,
|
||||||
|
/** Allocates a new string in the module's memory and returns its pointer. */
|
||||||
|
newString(str: string): number;
|
||||||
|
/** Gets a string from the module's memory by its pointer. */
|
||||||
|
getString(ptr: number): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Instantiates an AssemblyScript module using the specified imports. */
|
||||||
|
export declare function instantiate<T extends {}>(module: WebAssembly.Module, imports?: ImportsObject): ASUtil & T;
|
||||||
|
|
||||||
|
/** Instantiates an AssemblyScript module from a buffer using the specified imports. */
|
||||||
|
export declare function instantiateBuffer<T extends {}>(buffer: Uint8Array, imports?: ImportsObject): ASUtil & T;
|
||||||
|
|
||||||
|
/** Instantiates an AssemblyScript module from a response using the sspecified imports. */
|
||||||
|
export declare function instantiateStreaming<T extends {}>(response: Response, imports?: ImportsObject): Promise<ASUtil & T>;
|
||||||
|
|
||||||
|
/** Demangles an AssemblyScript module's exports to a friendly object structure. */
|
||||||
|
export declare function demangle<T extends {}>(exports: {}): T;
|
163
lib/loader/index.js
Normal file
163
lib/loader/index.js
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
/** Instantiates an AssemblyScript module using the specified imports. */
|
||||||
|
function instantiate(module, imports) {
|
||||||
|
|
||||||
|
// Set up the imports object
|
||||||
|
if (!imports) imports = {};
|
||||||
|
if (!imports.env) imports.env = {};
|
||||||
|
if (!imports.env.abort) imports.env.abort = function(mesg, file, line, colm) {
|
||||||
|
mesg = mem ? getString(mesg) : "";
|
||||||
|
file = mem ? getString(file) : "<instantiate>";
|
||||||
|
throw Error("abort: " + mesg + " at " + file + ":" + line + ":" + colm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instantiate the module and obtain its (flat) exports
|
||||||
|
var instance = new WebAssembly.Instance(module, imports);
|
||||||
|
var exports = instance.exports;
|
||||||
|
|
||||||
|
// Provide views for all sorts of basic values
|
||||||
|
var mem, I8, U8, I16, U16, I32, U32, F32, F64;
|
||||||
|
|
||||||
|
/** Updates memory views if memory has grown meanwhile. */
|
||||||
|
function checkMem() {
|
||||||
|
// see: https://github.com/WebAssembly/design/issues/1210
|
||||||
|
if (mem !== exports.memory.buffer) {
|
||||||
|
mem = exports.memory.buffer;
|
||||||
|
I8 = new Int8Array(mem);
|
||||||
|
U8 = new Uint8Array(mem);
|
||||||
|
I16 = new Int16Array(mem);
|
||||||
|
U16 = new Uint16Array(mem);
|
||||||
|
I32 = new Int32Array(mem);
|
||||||
|
U32 = new Uint32Array(mem);
|
||||||
|
F32 = new Float32Array(mem);
|
||||||
|
F64 = new Float64Array(mem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkMem();
|
||||||
|
|
||||||
|
/** Allocates a new string in the module's memory and returns its pointer. */
|
||||||
|
function newString(str) {
|
||||||
|
var dataLength = str.length;
|
||||||
|
var ptr = exports.allocate_memory(4 + (dataLength << 1));
|
||||||
|
var dataOffset = (4 + ptr) >>> 1;
|
||||||
|
checkMem();
|
||||||
|
U32[ptr >>> 2] = dataLength;
|
||||||
|
for (let i = 0; i < dataLength; ++i) U16[dataOffset + i] = str.charCodeAt(i);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets a string from the module's memory by its pointer. */
|
||||||
|
function getString(ptr) {
|
||||||
|
checkMem();
|
||||||
|
var dataLength = U32[ptr >>> 2];
|
||||||
|
var dataOffset = (ptr + 4) >>> 1;
|
||||||
|
var dataRemain = dataLength;
|
||||||
|
var parts = [];
|
||||||
|
const chunkSize = 1024;
|
||||||
|
while (dataRemain > chunkSize) {
|
||||||
|
let last = U16[dataOffset + chunkSize - 1];
|
||||||
|
let size = last >= 0xD800 && last < 0xDC00 ? chunkSize - 1 : chunkSize;
|
||||||
|
let part = U16.subarray(dataOffset, dataOffset += size);
|
||||||
|
parts.push(String.fromCharCode.apply(String, part));
|
||||||
|
dataRemain -= size;
|
||||||
|
}
|
||||||
|
return parts.join("") + String.fromCharCode.apply(String, U16.subarray(dataOffset, dataOffset + dataRemain));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demangle exports and provide the usual utility on the prototype
|
||||||
|
return demangle(exports, {
|
||||||
|
get I8() { checkMem(); return I8; },
|
||||||
|
get U8() { checkMem(); return U8; },
|
||||||
|
get I16() { checkMem(); return I16; },
|
||||||
|
get U16() { checkMem(); return U16; },
|
||||||
|
get I32() { checkMem(); return I32; },
|
||||||
|
get U32() { checkMem(); return U32; },
|
||||||
|
get F32() { checkMem(); return F32; },
|
||||||
|
get F64() { checkMem(); return F64; },
|
||||||
|
newString,
|
||||||
|
getString
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.instantiate = instantiate;
|
||||||
|
|
||||||
|
/** Instantiates an AssemblyScript module from a buffer using the specified imports. */
|
||||||
|
function instantiateBuffer(buffer, imports) {
|
||||||
|
var module = new WebAssembly.Module(buffer);
|
||||||
|
return instantiate(module, imports);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.instantiateBuffer = instantiateBuffer;
|
||||||
|
|
||||||
|
/** Instantiates an AssemblyScript module from a response using the specified imports. */
|
||||||
|
async function instantiateStreaming(response, imports) {
|
||||||
|
var module = await WebAssembly.compileStreaming(response);
|
||||||
|
return instantiate(module, imports);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.instantiateStreaming = instantiateStreaming;
|
||||||
|
|
||||||
|
/** Demangles an AssemblyScript module's exports to a friendly object structure. */
|
||||||
|
function demangle(exports, baseModule) {
|
||||||
|
var module = baseModule ? Object.create(baseModule) : {};
|
||||||
|
function hasOwnProperty(elem, prop) {
|
||||||
|
return Object.prototype.hasOwnProperty.call(elem, prop);
|
||||||
|
}
|
||||||
|
for (let internalName in exports) {
|
||||||
|
if (!hasOwnProperty(exports, internalName)) continue;
|
||||||
|
let elem = exports[internalName];
|
||||||
|
let parts = internalName.split(".");
|
||||||
|
let curr = module;
|
||||||
|
while (parts.length > 1) {
|
||||||
|
let part = parts.shift();
|
||||||
|
if (!hasOwnProperty(curr, part)) curr[part] = {};
|
||||||
|
curr = curr[part];
|
||||||
|
}
|
||||||
|
let name = parts[0];
|
||||||
|
let hash = name.indexOf("#");
|
||||||
|
if (hash >= 0) {
|
||||||
|
let className = name.substring(0, hash);
|
||||||
|
let classElem = curr[className];
|
||||||
|
if (typeof classElem === "undefined" || !classElem.prototype) {
|
||||||
|
let ctor = function(...args) {
|
||||||
|
return ctor.wrap(ctor.prototype.constructor(...args));
|
||||||
|
};
|
||||||
|
ctor.prototype = {};
|
||||||
|
ctor.wrap = function(thisValue) {
|
||||||
|
return Object.create(ctor.prototype, { "this": { value: thisValue, writable: false } });
|
||||||
|
};
|
||||||
|
if (classElem) Object.getOwnPropertyNames(classElem).forEach(name =>
|
||||||
|
Object.defineProperty(ctor, name, Object.getOwnPropertyDescriptor(classElem, name))
|
||||||
|
);
|
||||||
|
curr[className] = ctor;
|
||||||
|
}
|
||||||
|
name = name.substring(hash + 1);
|
||||||
|
curr = curr[className].prototype;
|
||||||
|
if (/^(get|set):/.test(name)) {
|
||||||
|
if (!hasOwnProperty(curr, name = name.substring(4))) {
|
||||||
|
let getter = exports[internalName.replace("set:", "get:")];
|
||||||
|
let setter = exports[internalName.replace("get:", "set:")];
|
||||||
|
Object.defineProperty(curr, name, {
|
||||||
|
get: function() { return getter(this.this); },
|
||||||
|
set: function(value) { setter(this.this, value); },
|
||||||
|
enumerable: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else curr[name] = function(...args) { return elem(this.this, ...args); };
|
||||||
|
} else {
|
||||||
|
if (/^(get|set):/.test(name)) {
|
||||||
|
if (!hasOwnProperty(curr, name = name.substring(4))) {
|
||||||
|
Object.defineProperty(curr, name, {
|
||||||
|
get: exports[internalName.replace("set:", "get:")],
|
||||||
|
set: exports[internalName.replace("get:", "set:")],
|
||||||
|
enumerable: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else curr[name] = elem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.demangle = demangle;
|
@ -1,13 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "@assemblyscript/demangle",
|
"name": "@assemblyscript/loader",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
"types": "index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node tests"
|
"test": "node tests"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
"index.d.ts",
|
||||||
"index.js",
|
"index.js",
|
||||||
"package.json",
|
"package.json",
|
||||||
"README.md"
|
"README.md"
|
||||||
]
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@types/webassembly-js-api": "0.0.1"
|
||||||
|
}
|
||||||
}
|
}
|
46
lib/loader/tests/assembly/index.ts
Normal file
46
lib/loader/tests/assembly/index.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import "allocator/arena";
|
||||||
|
|
||||||
|
export const COLOR: string = "red";
|
||||||
|
|
||||||
|
export function strlen(str: string): i32 {
|
||||||
|
return str.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace math {
|
||||||
|
export function add(a: i32, b: i32): i32 {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Car {
|
||||||
|
static readonly MAX_DOORS: i32 = 5;
|
||||||
|
static usualDoors: i32 = 3;
|
||||||
|
|
||||||
|
numDoors: i32;
|
||||||
|
private doorsOpen: bool = false;
|
||||||
|
|
||||||
|
get isDoorsOpen(): bool { return this.doorsOpen; }
|
||||||
|
set isDoorsOpen(value: bool) { this.doorsOpen = value; }
|
||||||
|
|
||||||
|
constructor(numDoors: i32) {
|
||||||
|
this.numDoors = numDoors;
|
||||||
|
}
|
||||||
|
|
||||||
|
openDoors(): bool {
|
||||||
|
if (this.doorsOpen) return false;
|
||||||
|
this.doorsOpen = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeDoors(): bool {
|
||||||
|
if (!this.doorsOpen) return false;
|
||||||
|
this.doorsOpen = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void {
|
||||||
|
free_memory(changetype<usize>(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { allocate_memory, free_memory };
|
BIN
lib/loader/tests/build/untouched.wasm
Normal file
BIN
lib/loader/tests/build/untouched.wasm
Normal file
Binary file not shown.
34
lib/loader/tests/index.js
Normal file
34
lib/loader/tests/index.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
var fs = require("fs");
|
||||||
|
var assert = require("assert");
|
||||||
|
var inspect = require("util").inspect;
|
||||||
|
|
||||||
|
var loader = require("..");
|
||||||
|
var buffer = fs.readFileSync(__dirname + "/build/untouched.wasm");
|
||||||
|
var module = loader.instantiateBuffer(buffer, {});
|
||||||
|
|
||||||
|
console.log(inspect(module, true, 100, true));
|
||||||
|
|
||||||
|
// should inherit the usual utility
|
||||||
|
var proto = Object.getPrototypeOf(module);
|
||||||
|
assert(proto.I8 instanceof Int8Array);
|
||||||
|
assert(proto.U8 instanceof Uint8Array);
|
||||||
|
assert(proto.I16 instanceof Int16Array);
|
||||||
|
assert(proto.U16 instanceof Uint16Array);
|
||||||
|
assert(proto.I32 instanceof Int32Array);
|
||||||
|
assert(proto.U32 instanceof Uint32Array);
|
||||||
|
assert(proto.F32 instanceof Float32Array);
|
||||||
|
assert(proto.F64 instanceof Float64Array);
|
||||||
|
assert(typeof proto.newString === "function");
|
||||||
|
assert(typeof proto.getString === "function");
|
||||||
|
|
||||||
|
// should export memory
|
||||||
|
assert(module.memory instanceof WebAssembly.Memory);
|
||||||
|
|
||||||
|
// should be able to get an exported string
|
||||||
|
assert.strictEqual(module.getString(module.COLOR), "red");
|
||||||
|
|
||||||
|
// should be able to allocate and work with a new string
|
||||||
|
var str = "Hello world!𤭢";
|
||||||
|
var ptr = module.newString(str);
|
||||||
|
assert.strictEqual(module.getString(ptr), str);
|
||||||
|
assert.strictEqual(module.strlen(ptr), str.length);
|
@ -1,17 +0,0 @@
|
|||||||
 utils
|
|
||||||
=================
|
|
||||||
|
|
||||||
Utilities for working with [AssemblyScript](http://assemblyscript.org) modules.
|
|
||||||
|
|
||||||
Usage
|
|
||||||
-----
|
|
||||||
|
|
||||||
```js
|
|
||||||
import utils from "@assemblyscript/utils";
|
|
||||||
|
|
||||||
var myModule = ...;
|
|
||||||
|
|
||||||
var helpers = utils(myModule);
|
|
||||||
|
|
||||||
var str = helpers.string(myModule.exportReturningAString());
|
|
||||||
```
|
|
@ -1,103 +0,0 @@
|
|||||||
function utils(module) {
|
|
||||||
|
|
||||||
var i8,
|
|
||||||
u8 = new Uint8Array(0),
|
|
||||||
i16,
|
|
||||||
u16,
|
|
||||||
i32,
|
|
||||||
u32,
|
|
||||||
f32,
|
|
||||||
f64;
|
|
||||||
|
|
||||||
function maybeUpdate() {
|
|
||||||
var mem = module.memory.buffer;
|
|
||||||
if (mem.byteLength === u8.length)
|
|
||||||
return;
|
|
||||||
i8 = Int8Array(mem);
|
|
||||||
u8 = Uint8Array(mem);
|
|
||||||
i16 = Int16Array(mem);
|
|
||||||
u16 = Uint16Array(mem);
|
|
||||||
i32 = Int32Array(mem);
|
|
||||||
u32 = Uint32Array(mem);
|
|
||||||
f32 = Float32Array(mem);
|
|
||||||
f64 = Float64Array(mem);
|
|
||||||
}
|
|
||||||
|
|
||||||
var helpers = {
|
|
||||||
|
|
||||||
i8: function(ptr) {
|
|
||||||
maybeUpdate();
|
|
||||||
return i8[ptr];
|
|
||||||
},
|
|
||||||
|
|
||||||
u8: function(ptr) {
|
|
||||||
maybeUpdate();
|
|
||||||
return u8[ptr];
|
|
||||||
},
|
|
||||||
|
|
||||||
i16: function(ptr) {
|
|
||||||
maybeUpdate();
|
|
||||||
return i16[ptr >>> 1];
|
|
||||||
},
|
|
||||||
|
|
||||||
u16: function(ptr) {
|
|
||||||
maybeUpdate();
|
|
||||||
return u16[ptr >>> 1];
|
|
||||||
},
|
|
||||||
|
|
||||||
i32: function(ptr) {
|
|
||||||
maybeUpdate();
|
|
||||||
return i32[ptr >>> 2];
|
|
||||||
},
|
|
||||||
|
|
||||||
u32: function(ptr) {
|
|
||||||
maybeUpdate();
|
|
||||||
return u32[ptr >>> 2];
|
|
||||||
},
|
|
||||||
|
|
||||||
i64: function(ptr) {
|
|
||||||
maybeUpdate();
|
|
||||||
return {
|
|
||||||
low: i32[ptr >>> 2],
|
|
||||||
high: i32[(ptr >>> 2) + 1]
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
u64: function(ptr) {
|
|
||||||
maybeUpdate();
|
|
||||||
return {
|
|
||||||
low: u32[ptr >>> 2],
|
|
||||||
high: u32[(ptr >>> 2) + 1]
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
bool: function(ptr) {
|
|
||||||
maybeUpdate();
|
|
||||||
return u8[ptr] === 1;
|
|
||||||
},
|
|
||||||
|
|
||||||
f32: function(ptr) {
|
|
||||||
maybeUpdate();
|
|
||||||
return f32[ptr >>> 2];
|
|
||||||
},
|
|
||||||
|
|
||||||
f64: function(ptr) {
|
|
||||||
maybeUpdate();
|
|
||||||
return f64[ptr >>> 3];
|
|
||||||
},
|
|
||||||
|
|
||||||
string: function(ptr) {
|
|
||||||
maybeUpdate();
|
|
||||||
var len = u32[ptr >>> 2];
|
|
||||||
var off = (ptr >>> 1) + 2;
|
|
||||||
return String.fromCharCode.apply(String, u16.subarray(off, off + len));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return helpers;
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.defineProperties(module.exports = utils, {
|
|
||||||
__esModule: { value: true },
|
|
||||||
default: { value: utils }
|
|
||||||
});
|
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@assemblyscript/utils",
|
|
||||||
"version": "0.5.0",
|
|
||||||
"description": "Utilities for working with AssemblyScript modules.",
|
|
||||||
"license": "Apache-2.0"
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user