From: stephan Date: Thu, 15 Dec 2022 02:28:55 +0000 (+0000) Subject: Internal refactoring of how sqlite3.wasm.xWrap() handles JS-to-C function pointer... X-Git-Tag: version-3.41.0~241 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=73b471964b872eaa99a4f3d7243fbfa9497fbe0c;p=thirdparty%2Fsqlite.git Internal refactoring of how sqlite3.wasm.xWrap() handles JS-to-C function pointer conversions, to enable similar conversions to be added more easily. FossilOrigin-Name: 10cfe3fae6f680d3ecc3b0afbbf628ce91e34e3757b19dd27c231f0daf44232a --- diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js index 972b4a2e08..5488f26c94 100644 --- a/ext/wasm/api/sqlite3-api-glue.js +++ b/ext/wasm/api/sqlite3-api-glue.js @@ -138,7 +138,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ the range of supported argument types. */ [ "sqlite3_progress_handler", undefined, [ - "sqlite3*", "int", wasm.xWrap.FuncPtrAdapter({ + "sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({ name: 'xProgressHandler', signature: 'i(p)', bindScope: 'context', @@ -180,7 +180,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ "**", "**", "*", "*", "*"], ["sqlite3_total_changes", "int", "sqlite3*"], ["sqlite3_trace_v2", "int", "sqlite3*", "int", - wasm.xWrap.FuncPtrAdapter({ + new wasm.xWrap.FuncPtrAdapter({ name: 'sqlite3_trace_v2::callback', signature: 'i(ippp)', contextKey: (argIndex, argv)=>'sqlite3@'+argv[0] @@ -469,14 +469,14 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 'sqlite3*','string','int','*', new wasm.xWrap.FuncPtrAdapter({ /* int(*xCompare)(void*,int,const void*,int,const void*) */ - name: 'xCompare', + name: 'sqlite3_create_collation_v2::xCompare', signature: 'i(pipip)', bindScope: 'context', contextKey: __collationContextKey }), new wasm.xWrap.FuncPtrAdapter({ /* void(*xDestroy(void*) */ - name: 'xDestroy', + name: 'sqlite3_create_collation_v2::xDestroy', signature: 'v(p)', bindScope: 'context', contextKey: __collationContextKey diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js index a662d5a1ed..82d10dff11 100644 --- a/ext/wasm/common/whwasmutil.js +++ b/ext/wasm/common/whwasmutil.js @@ -1473,8 +1473,40 @@ self.WhWasmUtilInstaller = function(target){ } /** - EXPERIMENTAL! DO NOT USE IN CLIENT CODE! + Internal-use-only base class for FuncPtrAdapter and potentially + additional stateful argument adapter classes. + + Note that its main interface (convertArg()) is strictly + internal, not to be exposed to client code, as it may still + need re-shaping. Only the constructors of concrete subclasses + should be exposed to clients, and those in such a way that + does not hinder internal redesign of the convertArg() + interface. + */ + const AbstractArgAdapter = class { + constructor(opt){ + this.name = opt.name; + } + /** + Gets called via xWrap() to "convert" v to whatever type + this specific class supports. + argIndex is the argv index of _this_ argument in the + being-xWrap()'d call. argv is the current argument list + undergoing xWrap() argument conversion. argv entries to the + left of argIndex will have already undergone transformation and + those to the right will not have (they will have the values the + client-level code passed in, awaiting conversion). The RHS + indexes must never be relied upon for anything because their + types are indeterminate, whereas the LHS values will be + WASM-compatible values by the time this is called. + */ + convertArg(v,argIndex,argv){ + toss("AbstractArgAdapter must be subclassed."); + } + }; + + /** An attempt at adding function pointer conversion support to xWrap(). This type is recognized by xWrap() as a proxy for converting a JS function to a C-side function, either @@ -1482,7 +1514,7 @@ self.WhWasmUtilInstaller = function(target){ or semi-contextual, where it may keep track of a single binding for a given context and uninstall the binding if it's replaced. - Requires an options object with these properties: + The constructor requires an options object with these properties: - name (optional): string describing the function binding. This is solely for debugging and error-reporting purposes. If not @@ -1514,17 +1546,18 @@ self.WhWasmUtilInstaller = function(target){ context. This mode is the default if bindScope is _not_ set but a property named contextKey (described below) is. - - contextKey (function): is only used if bindScope is not set or - is 'context'. 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 + - 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 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 @@ -1547,74 +1580,65 @@ self.WhWasmUtilInstaller = function(target){ The constructor only saves the above state for later, and does not actually bind any functions. Its convertArg() method is called via xWrap() to perform any bindings. - - If this is called like a function, instead of a constructor, - it behaves as if it were called like a constructor. */ - xArg.FuncPtrAdapter = function ctor(opt) { - if(!(this instanceof xArg.FuncPtrAdapter)){ - return new xArg.FuncPtrAdapter(opt); - } - this.signature = opt.signature; - if(!opt.bindScope && (opt.contextKey instanceof Function)){ - opt.bindScope = 'context'; - }else if(ctor.bindScopes.indexOf(opt.bindScope)<0){ - toss("Invalid options.bindScope ("+opt.bindMod+") for FuncPtrAdapter. "+ - "Expecting one of: ("+ctor.bindScopes.join(', ')+')'); + xArg.FuncPtrAdapter = class FuncPtrAdapter extends AbstractArgAdapter { + constructor(opt) { + super(opt); + this.signature = opt.signature; + if(!opt.bindScope && (opt.contextKey instanceof Function)){ + opt.bindScope = 'context'; + }else if(FuncPtrAdapter.bindScopes.indexOf(opt.bindScope)<0){ + toss("Invalid options.bindScope ("+opt.bindMod+") for FuncPtrAdapter. "+ + "Expecting one of: ("+FuncPtrAdapter.bindScopes.join(', ')+')'); + } + this.bindScope = opt.bindScope; + if(opt.contextKey) this.contextKey = opt.contextKey /*else inherit one*/; + this.isTransient = 'transient'===this.bindScope; + this.isContext = 'context'===this.bindScope; + if( ('singleton'===this.bindScope) ) this.singleton = []; + else this.singleton = undefined; + //console.warn("FuncPtrAdapter()",opt,this); } - this.bindScope = opt.bindScope; - this.name = opt.name || ''; - if(opt.contextKey) this.contextKey = opt.contextKey /*else inherit one*/; - this.isTransient = 'transient'===this.bindScope; - this.isContext = 'context'===this.bindScope; - if( ('singleton'===this.bindScope) ) this.singleton = []; - else this.singleton = undefined; - //console.warn("FuncPtrAdapter()",opt,this); - }; - xArg.FuncPtrAdapter.bindScopes = [ - 'transient', 'context', 'singleton' - ]; - xArg.FuncPtrAdapter.prototype = { + + static bindScopes = [ + 'transient', 'context', 'singleton' + ]; + /* Dummy impl. Overwritten per-instance as needed. */ - contextKey: function(argIndex,argv){ + contextKey(argIndex,argv){ return this; - }, + } + /* Returns this objects mapping for the given context key, in the form of an an array, creating the mapping if needed. The key may be anything suitable for use in a Map. */ - contextMap: function(key){ + contextMap(key){ const cm = (this.__cmap || (this.__cmap = new Map)); let rc = cm.get(key); if(undefined===rc) cm.set(key, (rc = [])); return rc; - }, + } + /** Gets called via xWrap() to "convert" v to a WASM-bound function pointer. If v is one of (a pointer, null, undefined) then (v||0) is returned and any earlier function installed by this - mapping _might_, depending on how it's bound, be - uninstalled. If v is not one of those types, it must be a - Function, for which it creates (if needed) a WASM function - binding and returns the WASM pointer to that binding. If this - instance is not in 'transient' mode, it will remember the - binding for at least the next call, to avoid recreating the - function binding unnecessarily. + mapping _might_, depending on how it's bound, be uninstalled. + If v is not one of those types, it must be a Function, for + which it creates (if needed) a WASM function binding and + returns the WASM pointer to that binding. If this instance is + not in 'transient' mode, it will remember the binding for at + least the next call, to avoid recreating the function binding + unnecessarily. If it's passed a pointer(ish) value for v, it does _not_ perform any function binding, so this object's bindMode is irrelevant for such cases. - argIndex is the argv index of _this_ argument in the - being-xWrap()'d call. argv is the current argument list - undergoing xWrap() argument conversion. argv entries to the - left of argIndex will have already undergone transformation and - those to the right will not have (they will have the values the - client-level code passed in, awaiting conversion). The RHS - indexes must never be relied upon for anything because their - types are indeterminate, whereas the LHS values will be - WASM-compatible values by the time this is called. + See the parent class's convertArg() docs for details on what + exactly the 2nd and 3rd arguments are. */ - convertArg: function(v,argIndex,argv){ + convertArg(v,argIndex,argv){ //console.warn("FuncPtrAdapter.convertArg()",this.signature,this.transient,v); let pair = this.singleton; if(!pair && this.isContext){ @@ -1650,7 +1674,7 @@ self.WhWasmUtilInstaller = function(target){ this.signature+"."); } }/*convertArg()*/ - }/*FuncPtrAdapter.prototype*/; + }/*FuncPtrAdapter*/; const __xArgAdapterCheck = (t)=>xArg.get(t) || toss("Argument adapter not found:",t); @@ -1823,7 +1847,7 @@ self.WhWasmUtilInstaller = function(target){ /*Verify the arg type conversions are valid...*/; if(undefined!==resultType && null!==resultType) __xResultAdapterCheck(resultType); for(const t of argTypes){ - if(t instanceof xArg.FuncPtrAdapter) xArg.set(t, (...args)=>t.convertArg(...args)); + if(t instanceof AbstractArgAdapter) xArg.set(t, (...args)=>t.convertArg(...args)); else __xArgAdapterCheck(t); } const cxw = cache.xWrap; @@ -1842,9 +1866,9 @@ 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 FuncPtrAdapter, and + 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 FuncPtrAdapter.convertArgs() gets its 2nd+ + 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. diff --git a/manifest b/manifest index f082e70724..be0d20aa97 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\san\sunnecessary/obsolete\sEmscripten-specific\sexport. -D 2022-12-15T02:26:13.244 +C Internal\srefactoring\sof\show\ssqlite3.wasm.xWrap()\shandles\sJS-to-C\sfunction\spointer\sconversions,\sto\senable\ssimilar\sconversions\sto\sbe\sadded\smore\seasily. +D 2022-12-15T02:28:55.691 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -503,7 +503,7 @@ F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08 F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62 F ext/wasm/api/pre-js.c-pp.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f9e91c1d5f F ext/wasm/api/sqlite3-api-cleanup.js 680d5ccfff54459db136a49b2199d9f879c8405d9c99af1dda0cc5e7c29056f4 -F ext/wasm/api/sqlite3-api-glue.js a8010bf3fa184886d1e9e76b0d0d1e290b5fa25130510644a59e91a18f779ef4 +F ext/wasm/api/sqlite3-api-glue.js 2e1087b870290a3a613d59ed626bde1f6da7c9c211cd36e41df1ee8b2932b508 F ext/wasm/api/sqlite3-api-oo1.js c0c4ccc269cccee657ffd03f094da7e270e1367b7928926b3730d543555a12a6 F ext/wasm/api/sqlite3-api-prologue.js 86eb4488f2be85e68c23ebcfad0834c24b6075e1645c67890cc4163c462efac1 F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f @@ -521,7 +521,7 @@ F ext/wasm/c-pp.c 92285f7bce67ed7b7020b40fde8ed0982c442b63dc33df9dfd4b658d4a6c07 F ext/wasm/common/SqliteTestUtil.js d8bf97ecb0705a2299765c8fc9e11b1a5ac7f10988bbf375a6558b7ca287067b F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15 F ext/wasm/common/testing.css 0ff15602a3ab2bad8aef2c3bd120c7ee3fd1c2054ad2ace7e214187ae68d926f -F ext/wasm/common/whwasmutil.js 8bec2460dfb515986faf854c011b7ae4f2cc1b2a128d9afa74ca57ee6057bdaa +F ext/wasm/common/whwasmutil.js e8934d24518f99a8995e2da5a4f308d36c13bea90d36a0396585e2debba94d57 F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508 F ext/wasm/demo-123.js ebae30756585bca655b4ab2553ec9236a87c23ad24fc8652115dcedb06d28df6 @@ -2067,8 +2067,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c1d5261b222bbf94c20e558089f3d2eae6a88b6d739225ee4f7d0338e0e59994 -R 918e16f92d23cc300804b300dc026e25 +P fa278022afd6dd6e499d26f74a8359f3e9973e1680772059ce331b64e77ec582 +R e784d3c7094c47f7ba465262d6340c12 U stephan -Z e5f6c496f6861a48778111a469988478 +Z 0c197c6d7ed7bd2414c2cff61c07cad7 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a6b0edf399..8b8fca451a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fa278022afd6dd6e499d26f74a8359f3e9973e1680772059ce331b64e77ec582 \ No newline at end of file +10cfe3fae6f680d3ecc3b0afbbf628ce91e34e3757b19dd27c231f0daf44232a \ No newline at end of file