diff options
author | stephan <stephan@noemail.net> | 2022-12-25 12:51:53 +0000 |
---|---|---|
committer | stephan <stephan@noemail.net> | 2022-12-25 12:51:53 +0000 |
commit | 485229e14774ef12d31a815b05aee047739086dd (patch) | |
tree | 9a4c603d034c7b21e7eda4f58a8c8d3190d64062 /ext/wasm/common/whwasmutil.js | |
parent | 75c04ba89cee1bb6b7b2b599eeacfbd063c84703 (diff) | |
download | sqlite-485229e14774ef12d31a815b05aee047739086dd.tar.gz sqlite-485229e14774ef12d31a815b05aee047739086dd.zip |
Enhance sqlite3.wasm.xWrap.FuncPtrAdapter to be able to handle sqlite3_create_function() and friends and reimplement those bindings to use this feature (this will also simplify certain session API bindings). Interal API changes only with no client-side breakage.
FossilOrigin-Name: 7f9ace1b11a6703031790af9cf08ab25df25850a86e6ca2a7aeaefd8aa395e6d
Diffstat (limited to 'ext/wasm/common/whwasmutil.js')
-rw-r--r-- | ext/wasm/common/whwasmutil.js | 77 |
1 files changed, 49 insertions, 28 deletions
diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js index de7500a02..26c44cf1a 100644 --- a/ext/wasm/common/whwasmutil.js +++ b/ext/wasm/common/whwasmutil.js @@ -1496,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."); } }; @@ -1541,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 @@ -1570,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 @@ -1598,6 +1612,8 @@ 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 bindScopes = [ @@ -1605,7 +1621,7 @@ self.WhWasmUtilInstaller = function(target){ ]; /* Dummy impl. Overwritten per-instance as needed. */ - contextKey(argIndex,argv){ + contextKey(argv,argIndex){ return this; } @@ -1638,14 +1654,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 */ @@ -1660,10 +1678,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{ @@ -1897,17 +1915,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); |