diff options
author | stephan <stephan@noemail.net> | 2022-12-25 14:13:52 +0000 |
---|---|---|
committer | stephan <stephan@noemail.net> | 2022-12-25 14:13:52 +0000 |
commit | 04071524ae6e4e86a1c670a9432b016b40889100 (patch) | |
tree | 87dd2dbdceb356b962846e42418fdae44266dfda /ext/wasm/common/whwasmutil.js | |
parent | bb769f0b4a025761fa2f5150582cf7736cb14345 (diff) | |
parent | 7015aa9f4957c3131c8bc814c81c4c5d2dea8f89 (diff) | |
download | sqlite-04071524ae6e4e86a1c670a9432b016b40889100.tar.gz sqlite-04071524ae6e4e86a1c670a9432b016b40889100.zip |
Merge trunk into wasm-session-api branch.
FossilOrigin-Name: 7f8f1acd82be7dc2eb2147d96299b1b443e86774dfe0b0a8d32669a0500fc9c6
Diffstat (limited to 'ext/wasm/common/whwasmutil.js')
-rw-r--r-- | ext/wasm/common/whwasmutil.js | 130 |
1 files changed, 81 insertions, 49 deletions
diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js index 5d6569d8e..c296a946b 100644 --- a/ext/wasm/common/whwasmutil.js +++ b/ext/wasm/common/whwasmutil.js @@ -1406,7 +1406,8 @@ self.WhWasmUtilInstaller = function(target){ .set('int', xArg.get('i32')) .set('null', (i)=>i) .set(null, xArg.get('null')) - .set('**', __xArgPtr); + .set('**', __xArgPtr) + .set('*', __xArgPtr); xResult.set('*', __xArgPtr) .set('pointer', __xArgPtr) .set('number', (v)=>Number(v)) @@ -1448,23 +1449,23 @@ self.WhWasmUtilInstaller = function(target){ if('string'===typeof v) return target.scopedAllocCString(v); return v ? __xArgPtr(v) : null; }; - xArg.set('string', __xArgString); - xArg.set('utf8', __xArgString); - xArg.set('pointer', __xArgString); - xArg.set('*', __xArgString); - - xResult.set('string', (i)=>target.cstrToJs(i)); - xResult.set('utf8', xResult.get('string')); - xResult.set('string:dealloc', (i)=>{ - try { return i ? target.cstrToJs(i) : null } - finally{ target.dealloc(i) } - }); - xResult.set('utf8:dealloc', xResult.get('string:dealloc')); - xResult.set('json', (i)=>JSON.parse(target.cstrToJs(i))); - xResult.set('json:dealloc', (i)=>{ - try{ return i ? JSON.parse(target.cstrToJs(i)) : null } - finally{ target.dealloc(i) } - }); + xArg.set('string', __xArgString) + .set('utf8', __xArgString) + .set('pointer', __xArgString); + //xArg.set('*', __xArgString); + + xResult.set('string', (i)=>target.cstrToJs(i)) + .set('utf8', xResult.get('string')) + .set('string:dealloc', (i)=>{ + try { return i ? target.cstrToJs(i) : null } + finally{ target.dealloc(i) } + }) + .set('utf8:dealloc', xResult.get('string:dealloc')) + .set('json', (i)=>JSON.parse(target.cstrToJs(i))) + .set('json:dealloc', (i)=>{ + try{ return i ? JSON.parse(target.cstrToJs(i)) : null } + finally{ target.dealloc(i) } + }); /** Internal-use-only base class for FuncPtrAdapter and potentially @@ -1495,7 +1496,7 @@ self.WhWasmUtilInstaller = function(target){ types are indeterminate, whereas the LHS values will be WASM-compatible values by the time this is called. */ - convertArg(v,argIndex,argv){ + convertArg(v,argv,argIndex){ toss("AbstractArgAdapter must be subclassed."); } }; @@ -1540,24 +1541,38 @@ self.WhWasmUtilInstaller = function(target){ context. This mode is the default if bindScope is _not_ set but a property named contextKey (described below) is. + - callProxy (function): if set, this must be a function which + will act as a proxy for any "converted" JS function. It is + passed the being-converted function value and must return + either that function or a function which acts on its + behalf. The returned function will be the one which gets + installed into the WASM function table. The proxy must perform + any required argument conversion (noting that it will be called + from C code, so will receive C-format arguments) before passing + them on to the being-converted function. Whether or not the + proxy itself must return a value depends on the context. If it + does, it must be a WASM-friendly value, as it will be returning + from a call made from native code. + - contextKey (function): is only used if bindScope is 'context' or if bindScope is not set and this function is, in which case - 'context' is assumed. This function gets passed - (argIndex,argv), where argIndex is the index of _this_ function - pointer in its _wrapping_ function's arguments and argv is the - _current_ still-being-xWrap()-processed args array. All - arguments to the left of argIndex will have been processed by - xWrap() by the time this is called. argv[argIndex] will be the - value the user passed in to the xWrap()'d function for the - argument this FuncPtrAdapter is mapped to. Arguments to the - right of argv[argIndex] will not yet have been converted before - this is called. The function must return a key which uniquely + 'context' is assumed. This function gets bound to this object, + so its "this" is this object. It gets passed (argv,argIndex), + where argIndex is the index of _this_ function pointer in its + _wrapping_ function's arguments and argv is the _current_ + still-being-xWrap()-processed args array. All arguments to the + left of argIndex will have been processed by xWrap() by the + time this is called. argv[argIndex] will be the value the user + passed in to the xWrap()'d function for the argument this + FuncPtrAdapter is mapped to. Arguments to the right of + argv[argIndex] will not yet have been converted before this is + called. The function must return a key which uniquely identifies this function mapping context for _this_ FuncPtrAdapter instance (other instances are not considered), taking into account that C functions often take some sort of state object as one or more of their arguments. As an example, if the xWrap()'d function takes `(int,T*,functionPtr,X*)` and - this FuncPtrAdapter is the argv[2]nd arg, contextKey(2,argv) + this FuncPtrAdapter is the argv[2]nd arg, contextKey(argv,2) might return 'T@'+argv[1], or even just argv[1]. Note, however, that the (X*) argument will not yet have been processed by the time this is called and should not be used as @@ -1569,7 +1584,7 @@ self.WhWasmUtilInstaller = function(target){ use their pointers in the key because most C-strings in this constellation are transient. - Yes, that ^^^ is a bit awkward, but it's what we have. + Yes, that ^^^ is quite awkward, but it's what we have. The constructor only saves the above state for later, and does not actually bind any functions. Its convertArg() method is @@ -1593,6 +1608,11 @@ self.WhWasmUtilInstaller = function(target){ xArg.FuncPtrAdapter = class FuncPtrAdapter extends AbstractArgAdapter { constructor(opt) { super(opt); + if(xArg.FuncPtrAdapter.warnOnUse){ + console.warn('xArg.FuncPtrAdapter is an internal-only API', + 'and is not intended to be invoked from', + 'client-level code. Invoked with:',opt); + } this.signature = opt.signature; if(!opt.bindScope && (opt.contextKey instanceof Function)){ opt.bindScope = 'context'; @@ -1607,14 +1627,18 @@ self.WhWasmUtilInstaller = function(target){ if( ('singleton'===this.bindScope) ) this.singleton = []; else this.singleton = undefined; //console.warn("FuncPtrAdapter()",opt,this); + this.callProxy = (opt.callProxy instanceof Function) + ? opt.callProxy : undefined; } + static warnOnUse = false; + static bindScopes = [ 'transient', 'context', 'singleton' ]; /* Dummy impl. Overwritten per-instance as needed. */ - contextKey(argIndex,argv){ + contextKey(argv,argIndex){ return this; } @@ -1647,14 +1671,16 @@ self.WhWasmUtilInstaller = function(target){ See the parent class's convertArg() docs for details on what exactly the 2nd and 3rd arguments are. */ - convertArg(v,argIndex,argv){ + convertArg(v,argv,argIndex){ //console.warn("FuncPtrAdapter.convertArg()",this.signature,this.transient,v); let pair = this.singleton; if(!pair && this.isContext){ - pair = this.contextMap(this.contextKey(argIndex, argv)); + pair = this.contextMap(this.contextKey(argv,argIndex)); } if(pair && pair[0]===v) return pair[1]; if(v instanceof Function){ + /* Install a WASM binding and return its pointer. */ + if(this.callProxy) v = this.callProxy(v); const fp = __installFunction(v, this.signature, this.isTransient); if(pair){ /* Replace existing stashed mapping */ @@ -1669,10 +1695,10 @@ self.WhWasmUtilInstaller = function(target){ }else if(target.isPtr(v) || null===v || undefined===v){ if(pair && pair[1] && pair[1]!==v){ /* uninstall stashed mapping and replace stashed mapping with v. */ - //console.warn("FuncPtrAdapter is uninstalling function", this.contextKey(argIndex,argv),v); + //console.warn("FuncPtrAdapter is uninstalling function", this.contextKey(argv,argIndex),v); try{target.uninstallFunction(pair[1])} catch(e){/*ignored*/} - pair[0] = pair[1] = (v || 0); + pair[0] = pair[1] = (v | 0); } return v || 0; }else{ @@ -1758,10 +1784,13 @@ self.WhWasmUtilInstaller = function(target){ - `N*` (args): a type name in the form `N*`, where N is a numeric type name, is treated the same as WASM pointer. - - `*` and `pointer` (args): have multple semantics. They - behave exactly as described below for `string` args. + - `*` and `pointer` (args): are assumed to be WASM pointer values + and are returned coerced to an appropriately-sized pointer + value (i32 or i64). Non-numeric values will coerce to 0 and + out-of-range values will have undefined results (just as with + any pointer misuse). - - `*` and `pointer` (results): are aliases for the current + - `*` and `pointer` (results): aliases for the current WASM pointer numeric type. - `**` (args): is simply a descriptive alias for the WASM pointer @@ -1903,17 +1932,20 @@ self.WhWasmUtilInstaller = function(target){ The public interface of argument adapters is that they take ONE argument and return a (possibly) converted result for it. The passing-on of arguments after the first is an - internal impl. detail for the sake of AbstractArgAdapter, and - not to be relied on or documented for other cases. The fact - that this is how AbstractArgAdapter.convertArgs() gets its 2nd+ - arguments, and how FuncPtrAdapter.contextKey() gets its - args, is also an implementation detail and subject to - change. i.e. the public interface of 1 argument is stable. - The fact that any arguments may be passed in after that one, - and what those arguments are, is _not_ part of the public - interface and is _not_ stable. + internal implementation detail for the sake of + AbstractArgAdapter, and not to be relied on or documented + for other cases. The fact that this is how + AbstractArgAdapter.convertArgs() gets its 2nd+ arguments, + and how FuncPtrAdapter.contextKey() gets its args, is also + an implementation detail and subject to change. i.e. the + public interface of 1 argument is stable. The fact that any + arguments may be passed in after that one, and what those + arguments are, is _not_ part of the public interface and is + _not_ stable. */ - for(const i in args) args[i] = cxw.convertArgNoCheck(argTypes[i], args[i], i, args); + for(const i in args) args[i] = cxw.convertArgNoCheck( + argTypes[i], args[i], args, i + ); return cxw.convertResultNoCheck(resultType, xf.apply(null,args)); }finally{ target.scopedAllocPop(scope); |