Skip to content

Commit 4683599

Browse files
committed
Improve loader function table handling
1 parent c4d7764 commit 4683599

File tree

5 files changed

+33
-20
lines changed

5 files changed

+33
-20
lines changed

lib/loader/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,13 @@ Instances are automatically populated with useful utility:
8383
* **freeArray**(ptr: `number`): `void`<br />
8484
Frees a typed array in the module's memory. Must not be accessed anymore afterwards.
8585

86+
* **getFunction**(ptr: `number`): `function`<br />
87+
Gets a function by its pointer.
88+
89+
* **newFunction**(fn: `function`): `number`<br />
90+
Creates a new function in the module's table and returns its pointer. Note that only actual
91+
WebAssembly functions, i.e. as exported by the module, are supported.
92+
8693
<sup>1</sup> This feature has not yet landed in any VM as of this writing.
8794

8895
Examples

lib/loader/index.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ interface ASUtil {
6666
freeArray(ptr: number): void;
6767
/** Gets a function by its pointer. */
6868
getFunction<R = any>(ptr: number): (...args: any[]) => R;
69+
/**
70+
* Creates a new function in the module's table and returns its pointer. Note that only actual
71+
* WebAssembly functions, i.e. as exported by the module, are supported.
72+
*/
73+
newFunction(fn: (...args: any[]) => any): number;
6974
}
7075

7176
/** Instantiates an AssemblyScript module using the specified imports. */

lib/loader/index.js

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,12 @@ function postInstantiate(baseModule, instance) {
155155

156156
baseModule.freeArray = freeArray;
157157

158-
/** Creates a new function in the module's table and returns its pointer. */
158+
/**
159+
* Creates a new function in the module's table and returns its pointer. Note that only actual
160+
* WebAssembly functions, i.e. as exported by the module, are supported.
161+
*/
159162
function newFunction(fn) {
163+
if (typeof fn.original === "function") fn = fn.original;
160164
var index = table.length;
161165
table.grow(1);
162166
table.set(index, fn);
@@ -167,11 +171,7 @@ function postInstantiate(baseModule, instance) {
167171

168172
/** Gets a function by its pointer. */
169173
function getFunction(ptr) {
170-
var fn = table.get(ptr);
171-
return (...args) => {
172-
setargc(args.length);
173-
return fn(...args);
174-
};
174+
return wrapFunction(table.get(ptr), setargc);
175175
}
176176

177177
baseModule.getFunction = getFunction;
@@ -191,6 +191,18 @@ function postInstantiate(baseModule, instance) {
191191
}));
192192
}
193193

194+
/** Wraps a WebAssembly function while also taking care of variable arguments. */
195+
function wrapFunction(fn, setargc) {
196+
var wrap = (...args) => {
197+
setargc(args.length);
198+
return fn(...args);
199+
}
200+
// adding a function to the table with `newFunction` is limited to actual WebAssembly functions,
201+
// hence we can't use the wrapper and instead need to provide a reference to the original
202+
wrap.original = fn;
203+
return wrap;
204+
}
205+
194206
/** Instantiates an AssemblyScript module using the specified imports. */
195207
function instantiate(module, imports) {
196208
return postInstantiate(
@@ -266,7 +278,7 @@ function demangle(exports, baseModule) {
266278
});
267279
}
268280
} else {
269-
curr[name] = wrapFunction(elem);
281+
curr[name] = wrapFunction(elem, setargc);
270282
}
271283
} else {
272284
if (/^(get|set):/.test(name)) {
@@ -278,24 +290,13 @@ function demangle(exports, baseModule) {
278290
});
279291
}
280292
} else if (typeof elem === "function") {
281-
curr[name] = wrapFunction(elem);
293+
curr[name] = wrapFunction(elem, setargc);
282294
} else {
283295
curr[name] = elem;
284296
}
285297
}
286298
}
287299

288-
function wrapFunction(fn) {
289-
var ret = function(...args) {
290-
setargc(args.length);
291-
return fn(...args);
292-
};
293-
// adding a function to the table with `newFunction` is limited to actual exported WebAssembly
294-
// functions, hence we can't use the wrapper for that and instead need to pass a workaround:
295-
ret.constructor = fn;
296-
return ret;
297-
}
298-
299300
return module;
300301
}
301302

72 Bytes
Binary file not shown.

lib/loader/tests/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,5 @@ assert.strictEqual(fn(2, 3), 5);
5757
assert.strictEqual(fn(2), 4);
5858

5959
// should be able to create a new function and call it from WASM
60-
ptr = module.newFunction(module.varadd.constructor); // must be an actual exported wasm function
60+
ptr = module.newFunction(module.varadd);
6161
assert.strictEqual(module.calladd(ptr, 2, 3), 5);

0 commit comments

Comments
 (0)