aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/common/whwasmutil.js
diff options
context:
space:
mode:
authorstephan <stephan@noemail.net>2022-12-25 14:13:52 +0000
committerstephan <stephan@noemail.net>2022-12-25 14:13:52 +0000
commit04071524ae6e4e86a1c670a9432b016b40889100 (patch)
tree87dd2dbdceb356b962846e42418fdae44266dfda /ext/wasm/common/whwasmutil.js
parentbb769f0b4a025761fa2f5150582cf7736cb14345 (diff)
parent7015aa9f4957c3131c8bc814c81c4c5d2dea8f89 (diff)
downloadsqlite-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.js130
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);