aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/common/whwasmutil.js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/wasm/common/whwasmutil.js')
-rw-r--r--ext/wasm/common/whwasmutil.js188
1 files changed, 114 insertions, 74 deletions
diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js
index 5a1d425ca..42f602d00 100644
--- a/ext/wasm/common/whwasmutil.js
+++ b/ext/wasm/common/whwasmutil.js
@@ -212,9 +212,10 @@ self.WhWasmUtilInstaller = function(target){
that will certainly change.
*/
const ptrIR = target.pointerIR || 'i32';
- const ptrSizeof = ('i32'===ptrIR ? 4
- : ('i64'===ptrIR
- ? 8 : toss("Unhandled ptrSizeof:",ptrIR)));
+ const ptrSizeof = target.ptrSizeof =
+ ('i32'===ptrIR ? 4
+ : ('i64'===ptrIR
+ ? 8 : toss("Unhandled ptrSizeof:",ptrIR)));
/** Stores various cached state. */
const cache = Object.create(null);
/** Previously-recorded size of cache.memory.buffer, noted so that
@@ -326,7 +327,7 @@ self.WhWasmUtilInstaller = function(target){
if(c.HEAP64) return unsigned ? c.HEAP64U : c.HEAP64;
break;
default:
- if(this.bigIntEnabled){
+ if(target.bigIntEnabled){
if(n===self['BigUint64Array']) return c.HEAP64U;
else if(n===self['BigInt64Array']) return c.HEAP64;
break;
@@ -334,7 +335,7 @@ self.WhWasmUtilInstaller = function(target){
}
toss("Invalid heapForSize() size: expecting 8, 16, 32,",
"or (if BigInt is enabled) 64.");
- }.bind(target);
+ };
/**
Returns the WASM-exported "indirect function table."
@@ -346,16 +347,16 @@ self.WhWasmUtilInstaller = function(target){
- Use `__indirect_function_table` as the import name for the
table, which is what LLVM does.
*/
- }.bind(target);
+ };
/**
Given a function pointer, returns the WASM function table entry
if found, else returns a falsy value.
*/
target.functionEntry = function(fptr){
- const ft = this.functionTable();
+ const ft = target.functionTable();
return fptr < ft.length ? ft.get(fptr) : undefined;
- }.bind(target);
+ };
/**
Creates a WASM function which wraps the given JS function and
@@ -504,7 +505,7 @@ self.WhWasmUtilInstaller = function(target){
https://github.com/emscripten-core/emscripten/issues/17323
*/
target.installFunction = function f(func, sig){
- const ft = this.functionTable();
+ const ft = target.functionTable();
const oldLen = ft.length;
let ptr;
while(cache.freeFuncIndexes.length){
@@ -532,13 +533,13 @@ self.WhWasmUtilInstaller = function(target){
}
// It's not a WASM-exported function, so compile one...
try {
- ft.set(ptr, this.jsFuncToWasm(func, sig));
+ ft.set(ptr, target.jsFuncToWasm(func, sig));
}catch(e){
if(ptr===oldLen) cache.freeFuncIndexes.push(oldLen);
throw e;
}
return ptr;
- }.bind(target);
+ };
/**
Requires a pointer value previously returned from
@@ -551,12 +552,12 @@ self.WhWasmUtilInstaller = function(target){
*/
target.uninstallFunction = function(ptr){
const fi = cache.freeFuncIndexes;
- const ft = this.functionTable();
+ const ft = target.functionTable();
fi.push(ptr);
const rc = ft.get(ptr);
ft.set(ptr, null);
return rc;
- }.bind(target);
+ };
/**
Given a WASM heap memory address and a data type name in the form
@@ -614,14 +615,14 @@ self.WhWasmUtilInstaller = function(target){
case 'i16': return c.HEAP16[ptr>>1];
case 'i32': return c.HEAP32[ptr>>2];
case 'i64':
- if(this.bigIntEnabled) return BigInt(c.HEAP64[ptr>>3]);
+ if(target.bigIntEnabled) return BigInt(c.HEAP64[ptr>>3]);
break;
case 'float': case 'f32': return c.HEAP32F[ptr>>2];
case 'double': case 'f64': return Number(c.HEAP64F[ptr>>3]);
default: break;
}
toss('Invalid type for getMemValue():',type);
- }.bind(target);
+ };
/**
The counterpart of getMemValue(), this sets a numeric value at
@@ -654,6 +655,15 @@ self.WhWasmUtilInstaller = function(target){
toss('Invalid type for setMemValue(): ' + type);
};
+
+ /** Convenience form of getMemValue() intended for fetching
+ pointer-to-pointer values. */
+ target.getPtrValue = (ptr)=>target.getMemValue(ptr, ptrIR);
+
+ /** Convenience form of setMemValue() intended for setting
+ pointer-to-pointer values. */
+ target.setPtrValue = (ptr, value)=>target.setMemValue(ptr, value, ptrIR);
+
/**
Expects ptr to be a pointer into the WASM heap memory which
refers to a NUL-terminated C-style string encoded as UTF-8.
@@ -669,6 +679,18 @@ self.WhWasmUtilInstaller = function(target){
return pos - ptr;
};
+ /** Internal helper to use in operations which need to distinguish
+ between SharedArrayBuffer heap memory and non-shared heap. */
+ const __SAB = ('undefined'===typeof SharedArrayBuffer)
+ ? function(){} : SharedArrayBuffer;
+ const __utf8Decode = function(arrayBuffer, begin, end){
+ return cache.utf8Decoder.decode(
+ (arrayBuffer.buffer instanceof __SAB)
+ ? arrayBuffer.slice(begin, end)
+ : arrayBuffer.subarray(begin, end)
+ );
+ };
+
/**
Expects ptr to be a pointer into the WASM heap memory which
refers to a NUL-terminated C-style string encoded as UTF-8. This
@@ -677,13 +699,9 @@ self.WhWasmUtilInstaller = function(target){
ptr is falsy, `null` is returned.
*/
target.cstringToJs = function(ptr){
- const n = this.cstrlen(ptr);
- if(null===n) return n;
- return n
- ? cache.utf8Decoder.decode(
- new Uint8Array(heapWrappers().HEAP8U.buffer, ptr, n)
- ) : "";
- }.bind(target);
+ const n = target.cstrlen(ptr);
+ return n ? __utf8Decode(heapWrappers().HEAP8U, ptr, ptr+n) : (null===n ? n : "");
+ };
/**
Given a JS string, this function returns its UTF-8 length in
@@ -811,16 +829,16 @@ self.WhWasmUtilInstaller = function(target){
*/
target.cstrncpy = function(tgtPtr, srcPtr, n){
if(!tgtPtr || !srcPtr) toss("cstrncpy() does not accept NULL strings.");
- if(n<0) n = this.cstrlen(strPtr)+1;
+ if(n<0) n = target.cstrlen(strPtr)+1;
else if(!(n>0)) return 0;
- const heap = this.heap8u();
+ const heap = target.heap8u();
let i = 0, ch;
for(; i < n && (ch = heap[srcPtr+i]); ++i){
heap[tgtPtr+i] = ch;
}
if(i<n) heap[tgtPtr + i++] = 0;
return i;
- }.bind(target);
+ };
/**
For the given JS string, returns a Uint8Array of its contents
@@ -865,13 +883,13 @@ self.WhWasmUtilInstaller = function(target){
};
const __allocCStr = function(jstr, returnWithLength, allocator, funcName){
- __affirmAlloc(this, funcName);
+ __affirmAlloc(target, funcName);
if('string'!==typeof jstr) return null;
- const n = this.jstrlen(jstr),
+ const n = target.jstrlen(jstr),
ptr = allocator(n+1);
- this.jstrcpy(jstr, this.heap8u(), ptr, n+1, true);
+ target.jstrcpy(jstr, target.heap8u(), ptr, n+1, true);
return returnWithLength ? [ptr, n] : ptr;
- }.bind(target);
+ };
/**
Uses target.alloc() to allocate enough memory for jstrlen(jstr)+1
@@ -924,11 +942,11 @@ self.WhWasmUtilInstaller = function(target){
alloc levels are currently active.
*/
target.scopedAllocPush = function(){
- __affirmAlloc(this, 'scopedAllocPush');
+ __affirmAlloc(target, 'scopedAllocPush');
const a = [];
cache.scopedAlloc.push(a);
return a;
- }.bind(target);
+ };
/**
Cleans up all allocations made using scopedAlloc() in the context
@@ -953,15 +971,15 @@ self.WhWasmUtilInstaller = function(target){
trivial code that may be a non-issue.
*/
target.scopedAllocPop = function(state){
- __affirmAlloc(this, 'scopedAllocPop');
+ __affirmAlloc(target, 'scopedAllocPop');
const n = arguments.length
? cache.scopedAlloc.indexOf(state)
: cache.scopedAlloc.length-1;
if(n<0) toss("Invalid state object for scopedAllocPop().");
if(0===arguments.length) state = cache.scopedAlloc[n];
cache.scopedAlloc.splice(n,1);
- for(let p; (p = state.pop()); ) this.dealloc(p);
- }.bind(target);
+ for(let p; (p = state.pop()); ) target.dealloc(p);
+ };
/**
Allocates n bytes of memory using this.alloc() and records that
@@ -983,10 +1001,10 @@ self.WhWasmUtilInstaller = function(target){
if(!cache.scopedAlloc.length){
toss("No scopedAllocPush() scope is active.");
}
- const p = this.alloc(n);
+ const p = target.alloc(n);
cache.scopedAlloc[cache.scopedAlloc.length-1].push(p);
return p;
- }.bind(target);
+ };
Object.defineProperty(target.scopedAlloc, 'level', {
configurable: false, enumerable: false,
@@ -1005,6 +1023,29 @@ self.WhWasmUtilInstaller = function(target){
target.scopedAlloc, 'scopedAllocCString()');
/**
+ Creates an array, using scopedAlloc(), suitable for passing to a
+ C-level main() routine. The input is a collection with a length
+ property and a forEach() method. A block of memory list.length
+ entries long is allocated and each pointer-sized block of that
+ memory is populated with a scopedAllocCString() conversion of the
+ (''+value) of each element. Returns a pointer to the start of the
+ list, suitable for passing as the 2nd argument to a C-style
+ main() function.
+
+ Throws if list.length is falsy or scopedAllocPush() is not active.
+ */
+ target.scopedAllocMainArgv = function(list){
+ if(!list.length) toss("Cannot allocate empty array.");
+ const pList = target.scopedAlloc(list.length * target.ptrSizeof);
+ let i = 0;
+ list.forEach((e)=>{
+ target.setPtrValue(pList + (target.ptrSizeof * i++),
+ target.scopedAllocCString(""+e));
+ });
+ return pList;
+ };
+
+ /**
Wraps function call func() in a scopedAllocPush() and
scopedAllocPop() block, such that all calls to scopedAlloc() and
friends from within that call will have their memory freed
@@ -1013,15 +1054,15 @@ self.WhWasmUtilInstaller = function(target){
result of calling func().
*/
target.scopedAllocCall = function(func){
- this.scopedAllocPush();
- try{ return func() } finally{ this.scopedAllocPop() }
- }.bind(target);
+ target.scopedAllocPush();
+ try{ return func() } finally{ target.scopedAllocPop() }
+ };
/** Internal impl for allocPtr() and scopedAllocPtr(). */
const __allocPtr = function(howMany, method){
- __affirmAlloc(this, method);
- let m = this[method](howMany * ptrSizeof);
- this.setMemValue(m, 0, ptrIR)
+ __affirmAlloc(target, method);
+ let m = target[method](howMany * ptrSizeof);
+ target.setMemValue(m, 0, ptrIR)
if(1===howMany){
return m;
}
@@ -1029,10 +1070,10 @@ self.WhWasmUtilInstaller = function(target){
for(let i = 1; i < howMany; ++i){
m += ptrSizeof;
a[i] = m;
- this.setMemValue(m, 0, ptrIR);
+ target.setMemValue(m, 0, ptrIR);
}
return a;
- }.bind(target);
+ };
/**
Allocates a single chunk of memory capable of holding `howMany`
@@ -1070,11 +1111,11 @@ self.WhWasmUtilInstaller = function(target){
/**
Looks up a WASM-exported function named fname from
- target.exports. If found, it is called, passed all remaining
+ target.exports. If found, it is called, passed all remaining
arguments, and its return value is returned to xCall's caller. If
not found, an exception is thrown. This function does no
- conversion of argument or return types, but see xWrap()
- and xCallWrapped() for variants which do.
+ conversion of argument or return types, but see xWrap() and
+ xCallWrapped() for variants which do.
As a special case, if passed only 1 argument after the name and
that argument in an Array, that array's entries become the
@@ -1082,7 +1123,7 @@ self.WhWasmUtilInstaller = function(target){
not legal to pass an Array object to a WASM function.)
*/
target.xCall = function(fname, ...args){
- const f = this.xGet(fname);
+ const f = target.xGet(fname);
if(!(f instanceof Function)) toss("Exported symbol",fname,"is not a function.");
if(f.length!==args.length) __argcMismatch(fname,f.length)
/* This is arguably over-pedantic but we want to help clients keep
@@ -1090,7 +1131,7 @@ self.WhWasmUtilInstaller = function(target){
return (2===arguments.length && Array.isArray(arguments[1]))
? f.apply(null, arguments[1])
: f.apply(null, args);
- }.bind(target);
+ };
/**
State for use with xWrap()
@@ -1164,19 +1205,19 @@ self.WhWasmUtilInstaller = function(target){
*/
xcv.arg['func-ptr'] = function(v){
if(!(v instanceof Function)) return xcv.arg[ptrIR];
- const f = this.jsFuncToWasm(v, WHAT_SIGNATURE);
- }.bind(target);
+ const f = target.jsFuncToWasm(v, WHAT_SIGNATURE);
+ };
}
- const __xArgAdapter =
+ const __xArgAdapterCheck =
(t)=>xcv.arg[t] || toss("Argument adapter not found:",t);
- const __xResultAdapter =
+ const __xResultAdapterCheck =
(t)=>xcv.result[t] || toss("Result adapter not found:",t);
- cache.xWrap.convertArg = (t,v)=>__xArgAdapter(t)(v);
+ cache.xWrap.convertArg = (t,v)=>__xArgAdapterCheck(t)(v);
cache.xWrap.convertResult =
- (t,v)=>(null===t ? v : (t ? __xResultAdapter(t)(v) : undefined));
+ (t,v)=>(null===t ? v : (t ? __xResultAdapterCheck(t)(v) : undefined));
/**
Creates a wrapper for the WASM-exported function fname. Uses
@@ -1310,34 +1351,32 @@ self.WhWasmUtilInstaller = function(target){
if(3===arguments.length && Array.isArray(arguments[2])){
argTypes = arguments[2];
}
- const xf = this.xGet(fname);
- if(argTypes.length!==xf.length) __argcMismatch(fname, xf.length)
+ const xf = target.xGet(fname);
+ if(argTypes.length!==xf.length) __argcMismatch(fname, xf.length);
if((null===resultType) && 0===xf.length){
/* Func taking no args with an as-is return. We don't need a wrapper. */
return xf;
}
/*Verify the arg type conversions are valid...*/;
- if(undefined!==resultType && null!==resultType) __xResultAdapter(resultType);
- argTypes.forEach(__xArgAdapter)
+ if(undefined!==resultType && null!==resultType) __xResultAdapterCheck(resultType);
+ argTypes.forEach(__xArgAdapterCheck);
if(0===xf.length){
// No args to convert, so we can create a simpler wrapper...
- return function(){
- return (arguments.length
- ? __argcMismatch(fname, xf.length)
- : cache.xWrap.convertResult(resultType, xf.call(null)));
- };
+ return (...args)=>(args.length
+ ? __argcMismatch(fname, xf.length)
+ : cache.xWrap.convertResult(resultType, xf.call(null)));
}
return function(...args){
if(args.length!==xf.length) __argcMismatch(fname, xf.length);
- const scope = this.scopedAllocPush();
+ const scope = target.scopedAllocPush();
try{
const rc = xf.apply(null,args.map((v,i)=>cache.xWrap.convertArg(argTypes[i], v)));
return cache.xWrap.convertResult(resultType, rc);
}finally{
- this.scopedAllocPop(scope);
+ target.scopedAllocPop(scope);
}
- }.bind(this);
- }.bind(target)/*xWrap()*/;
+ };
+ }/*xWrap()*/;
/** Internal impl for xWrap.resultAdapter() and argAdaptor(). */
const __xAdapter = function(func, argc, typeName, adapter, modeName, xcvPart){
@@ -1441,9 +1480,9 @@ self.WhWasmUtilInstaller = function(target){
*/
target.xCallWrapped = function(fname, resultType, argTypes, ...args){
if(Array.isArray(arguments[3])) args = arguments[3];
- return this.xWrap(fname, resultType, argTypes||[]).apply(null, args||[]);
- }.bind(target);
-
+ return target.xWrap(fname, resultType, argTypes||[]).apply(null, args||[]);
+ };
+
return target;
};
@@ -1522,10 +1561,11 @@ self.WhWasmUtilInstaller.yawl = function(config){
|| toss("Missing 'memory' object!");
}
if(!tgt.alloc && arg.instance.exports.malloc){
+ const exports = arg.instance.exports;
tgt.alloc = function(n){
- return this(n) || toss("Allocation of",n,"bytes failed.");
- }.bind(arg.instance.exports.malloc);
- tgt.dealloc = function(m){this(m)}.bind(arg.instance.exports.free);
+ return exports.malloc(n) || toss("Allocation of",n,"bytes failed.");
+ };
+ tgt.dealloc = function(m){exports.free(m)};
}
wui(tgt);
}