mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-01 06:27:03 +03:00
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
This commit is contained in:
@ -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);
|
||||
|
Reference in New Issue
Block a user