aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/common/whwasmutil.js
diff options
context:
space:
mode:
authorstephan <stephan@noemail.net>2022-12-25 12:51:53 +0000
committerstephan <stephan@noemail.net>2022-12-25 12:51:53 +0000
commit485229e14774ef12d31a815b05aee047739086dd (patch)
tree9a4c603d034c7b21e7eda4f58a8c8d3190d64062 /ext/wasm/common/whwasmutil.js
parent75c04ba89cee1bb6b7b2b599eeacfbd063c84703 (diff)
downloadsqlite-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.js77
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);