From: stephan Date: Sat, 15 Nov 2025 11:30:45 +0000 (+0000) Subject: Generic internal JS cleanups towards improving portability of sqlite3-api.js to other... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=987870a6a062d8c5a659ee280a30f1043b0d568c;p=thirdparty%2Fsqlite.git Generic internal JS cleanups towards improving portability of sqlite3-api.js to other build systems. FossilOrigin-Name: 5bc37e5c2fcd83fd0bc40234144072363f1cbf7d811a15b74a0991e397a35eb8 --- diff --git a/ext/wasm/api/post-js-header.js b/ext/wasm/api/post-js-header.js index 105859dc16..3458408234 100644 --- a/ext/wasm/api/post-js-header.js +++ b/ext/wasm/api/post-js-header.js @@ -8,9 +8,11 @@ Running this function will bootstrap the library and return a Promise to the sqlite3 namespace object. + + In the canonical builds, this gets called by extern-post-js.c-pp.js */ Module.runSQLite3PostLoadInit = async function( - sqlite3InitScriptInfo /* populated by extern-post-js.c-pp.js */, + sqlite3InitScriptInfo, EmscriptenModule/*the Emscripten-style module object*/, sqlite3IsUnderTest ){ diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index b6f9e01c00..d63bd14a83 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -27,13 +27,14 @@ /** sqlite3ApiBootstrap() is the only global symbol persistently exposed by this API. It is intended to be called one time at the - end of the API amalgamation process, passed configuration details - for the current environment, and then optionally be removed from - the global object using `delete globalThis.sqlite3ApiBootstrap`. + end of the API amalgamation process and passed configuration details + for the current environment. This function is not intended for client-level use. It is intended for use in creating bundles configured for specific WASM - environments. + environments. That said, the "sqlite3-api.js" intermediary build + file aims to be suitable for dropping in to custom builds, and it + exposes only this function. This function expects a configuration object, intended to abstract away details specific to any given WASM environment, primarily so @@ -93,9 +94,10 @@ can be replaced with (e.g.) empty functions to squelch all such output. - - `wasmfsOpfsDir`[^1]: Specifies the "mount point" of the OPFS-backed - filesystem in WASMFS-capable builds. - + - `wasmfsOpfsDir`[^1]: Specifies the "mount point" of the + OPFS-backed filesystem in WASMFS-capable builds. This is only + used in WASMFS-capable builds of the library (which the canonical + builds do not include). [^1] = This property may optionally be a function, in which case this function calls that function to fetch the value, @@ -125,7 +127,8 @@ Both sqlite3ApiBootstrap.defaultConfig and globalThis.sqlite3ApiConfig get deleted by sqlite3ApiBootstrap() because any changes to them made after that point would have no - useful effect. + useful effect. This function also deletes itself from globalThis + when it's called. This function returns a Promise to the sqlite3 namespace object, which resolves after the async pieces of the library init are @@ -177,14 +180,6 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( } }); - /** - Eliminate any confusion about whether these config objects may - be used after library initialization by eliminating the outward-facing - objects... - */ - delete globalThis.sqlite3ApiConfig; - delete sqlite3ApiBootstrap.defaultConfig; - /** The main sqlite3 binding API gets installed into this object, mimicking the C API as closely as we can. The numerous members @@ -796,7 +791,8 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( /** wasm.X properties which are used for configuring the wasm - environment via whwashutil.js. + environment via whwashutil.js. This object gets fleshed out with + a number of WASM-specific utilities, in sqlite3-api-glue.c-pp.js. */ Object.assign(wasm, { @@ -809,8 +805,9 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( /** When Emscripten compiles with `-sIMPORTED_MEMORY`, it initializes the heap and imports it into wasm, as opposed to - the other way around. In this case, the memory is not - available via this.exports.memory. + the other way around. In this case, the memory is not available + via this.exports.memory so the client must pass it in via + config.memory. */ memory: config.memory || config.exports['memory'] @@ -956,7 +953,11 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( }; wasm.realloc.impl = wasm.exports[keyRealloc]; wasm.dealloc = function f(m){ - f.impl(wasm.ptr.coerce(m)/*tag:64bit*/); + f.impl(wasm.ptr.coerce(m)/*tag:64bit*/) + /* This coerce() is the reason we have to set wasm.pointerSize before + calling WhWasmUtilInstaller(). If we don't, that code will call + into this very early in its init, before wasm.ptr has been set up, + resulting in a null deref here. */; }; wasm.dealloc.impl = wasm.exports[keyDealloc]; } @@ -1027,18 +1028,18 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( }/*compileOptionUsed()*/; /** - sqlite3.wasm.pstack (pseudo-stack) holds a special-case intended - solely for short-lived, small data. In practice, it's primarily - used to allocate output pointers. It mus not be used for any - memory which needs to outlive the scope in which it's obtained - from pstack. + sqlite3.wasm.pstack (pseudo-stack) holds a special-case allocator + intended solely for short-lived, small data. In practice, it's + primarily used to allocate output pointers. It must not be used + for any memory which needs to outlive the scope in which it's + obtained from pstack. The library guarantees only that a minimum of 2kb are available in this allocator, and it may provide more (it's a build-time value). pstack.quota and pstack.remaining can be used to get the total resp. remaining amount of memory. - It has only a single intended usage: + It has only a single intended usage pattern: ``` const stackPos = pstack.pointer; @@ -1055,13 +1056,11 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( ``` This allocator is much faster than a general-purpose one but is - limited to usage patterns like the one shown above. + limited to usage patterns like the one shown above (which are + pretty common when using sqlite3.capi). - It operates from a static range of memory which lives outside of - space managed by Emscripten's stack-management, so does not - collide with Emscripten-provided stack allocation APIs. The - memory lives in the WASM heap and can be used with routines such - as wasm.poke() and wasm.heap8u().slice(). + The memory lives in the WASM heap and can be used with routines + such as wasm.poke() and wasm.heap8u().slice(). */ wasm.pstack = Object.assign(Object.create(null),{ /** @@ -1135,7 +1134,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( argument: if it's 1, it returns a single pointer value. If it's more than 1, it returns the same as allocChunks(). - When a returned pointers will refer to a 64-bit value, e.g. a + When a returned pointer will refer to a 64-bit value, e.g. a double or int64, and that value must be written or fetched, e.g. using wasm.poke() or wasm.peek(), it is important that the pointer in question be aligned to an 8-byte @@ -1203,6 +1202,9 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( } })/*wasm.pstack properties*/; + /** + Docs: https://sqlite.org/wasm/doc/trunk/api-c-style.md#sqlite3_randomness + */ capi.sqlite3_randomness = (...args)=>{ if(1===args.length && util.isTypedArray(args[0]) @@ -1237,8 +1239,6 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( wasm.exports.sqlite3_randomness(...args); }; - /** State for sqlite3_wasmfs_opfs_dir(). */ - let __wasmfsOpfsDir = undefined; /** If the wasm environment has a WASMFS/OPFS-backed persistent storage directory, its path is returned by this function. If it @@ -1262,7 +1262,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( WASMFS capability requires a custom build. */ capi.sqlite3_wasmfs_opfs_dir = function(){ - if(undefined !== __wasmfsOpfsDir) return __wasmfsOpfsDir; + if(undefined !== this.dir) return this.dir; // If we have no OPFS, there is no persistent dir const pdir = config.wasmfsOpfsDir; if(!pdir @@ -1270,21 +1270,21 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( || !globalThis.FileSystemDirectoryHandle || !globalThis.FileSystemFileHandle || !wasm.exports.sqlite3__wasm_init_wasmfs){ - return __wasmfsOpfsDir = ""; + return this.dir = ""; } try{ if(pdir && 0===wasm.xCallWrapped( 'sqlite3__wasm_init_wasmfs', 'i32', ['string'], pdir )){ - return __wasmfsOpfsDir = pdir; + return this.dir = pdir; }else{ - return __wasmfsOpfsDir = ""; + return this.dir = ""; } }catch(e){ // sqlite3__wasm_init_wasmfs() is not available - return __wasmfsOpfsDir = ""; + return this.dir = ""; } - }; + }.bind(Object.create(null)); /** Returns true if sqlite3.capi.sqlite3_wasmfs_opfs_dir() is a @@ -1340,7 +1340,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( */ capi.sqlite3_js_vfs_list = function(){ const rc = []; - let pVfs = capi.sqlite3_vfs_find(wasm.ptr.coerce(0)); + let pVfs = capi.sqlite3_vfs_find(wasm.ptr.null); while(pVfs){ const oVfs = new capi.sqlite3_vfs(pVfs); rc.push(wasm.cstrToJs(oVfs.$zName)); @@ -2068,8 +2068,8 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( */ asyncPostInit: async function ff(){ if(ff.isReady instanceof Promise) return ff.isReady; - let lia = sqlite3ApiBootstrap.initializersAsync; - delete sqlite3ApiBootstrap.initializersAsync; + let lia = this.initializersAsync; + delete this.initializersAsync; const postInit = async ()=>{ if(!sqlite3.__isUnderTest){ /* Delete references to internal-only APIs which are used by @@ -2094,7 +2094,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( let p = Promise.resolve(sqlite3); while(lia.length) p = p.then(lia.shift()); return ff.isReady = p.catch(catcher); - }, + }.bind(sqlite3ApiBootstrap), /** scriptInfo ideally gets injected into this object by the infrastructure which assembles the JS/WASM module. It contains @@ -2121,15 +2121,23 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( } delete sqlite3ApiBootstrap.initializers; sqlite3ApiBootstrap.sqlite3 = sqlite3; - delete globalThis.sqlite3ApiBootstrap; - delete globalThis.sqlite3ApiConfig; - sqlite3InitScriptInfo.debugModule( - "sqlite3ApiBootstrap() complete", sqlite3 - ); - sqlite3.scriptInfo /* used by some async init code */ = - sqlite3InitScriptInfo /* from post-js-header.js */; - if( (sqlite3.__isUnderTest = sqlite3IsUnderTest /* from post-js-header.js */) ){ - sqlite3.config.emscripten = EmscriptenModule; + if( 'undefined'!==typeof sqlite3InitScriptInfo/* from post-js-header.js */ ){ + sqlite3InitScriptInfo.debugModule( + "sqlite3ApiBootstrap() complete", sqlite3 + ); + sqlite3.scriptInfo + /* Used by some async init code. As of 2025-11-15 this is still + in use by the OPFS VFS for locating its worker. In non-Emscripten + builds, this would need to be injected in somewhere to get + that VFS loading. */ = sqlite3InitScriptInfo; + } + sqlite3.__isUnderTest = + ('undefined'===typeof sqlite3IsUnderTest /* from post-js-header.js */) + ? false : !!sqlite3IsUnderTest; + if( sqlite3.__isUnderTest ){ + if( 'undefined'!==typeof EmscriptenModule ){ + sqlite3.config.emscripten = EmscriptenModule; + } /* The problem with exposing these pieces (in non-testing runs) via sqlite3.wasm is that it exposes non-SQLite pieces to the @@ -2143,7 +2151,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( imports into WASM from its JS glue, but it's not SQLite-related. */ - const iw = sqlite3InitScriptInfo.instantiateWasm; + const iw = sqlite3.scriptInfo?.instantiateWasm; if( iw ){ /* Metadata injected by the custom Module.instantiateWasm() in pre-js.c-pp.js. */ @@ -2152,6 +2160,15 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( sqlite3.wasm.imports = iw.imports; } } + + /** + Eliminate any confusion about whether these config objects may + be used after library initialization by eliminating the outward-facing + objects... + */ + delete globalThis.sqlite3ApiConfig; + delete globalThis.sqlite3ApiBootstrap; + delete sqlite3ApiBootstrap.defaultConfig; return sqlite3.asyncPostInit().then((s)=>{ sqlite3InitScriptInfo.debugModule( "sqlite3.asyncPostInit() complete", sqlite3 diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index 0662ca4873..d93a652163 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -1441,7 +1441,7 @@ installOpfsVfs.defaultProxyUri = globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ try{ let proxyJs = installOpfsVfs.defaultProxyUri; - if(sqlite3.scriptInfo.sqlite3Dir){ + if( sqlite3?.scriptInfo?.sqlite3Dir ){ installOpfsVfs.defaultProxyUri = sqlite3.scriptInfo.sqlite3Dir + proxyJs; //sqlite3.config.warn("installOpfsVfs.defaultProxyUri =",installOpfsVfs.defaultProxyUri); diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c index 96fa4704bf..866215aa06 100644 --- a/ext/wasm/api/sqlite3-wasm.c +++ b/ext/wasm/api/sqlite3-wasm.c @@ -136,8 +136,8 @@ /* ** If SQLITE_WASM_BARE_BONES is defined, undefine most of the ENABLE ** macros. This will, when using the canonical makefile, also elide -** any C functions from the WASM exports which are listed in -** ./EXPORT_FUNCTIONS.sqlite3-extras. +** any C functions from the WASM exports: see +** ./EXPORTED_FUNCTIONS.c-pp. */ #ifdef SQLITE_WASM_BARE_BONES # undef SQLITE_ENABLE_COLUMN_METADATA diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js index aadcf1f8b0..0d75675ca5 100644 --- a/ext/wasm/common/whwasmutil.js +++ b/ext/wasm/common/whwasmutil.js @@ -667,12 +667,14 @@ globalThis.WhWasmUtilInstaller = function(target){ const ft = target.functionTable(); const oldLen = __asPtrType(ft.length); let ptr; - while(cache.freeFuncIndexes.length){ - ptr = cache.freeFuncIndexes.pop(); - if(ft.get(ptr)){ /* Table was modified via a different API */ + while( (ptr = cache.freeFuncIndexes.pop()) ){ + if(ft.get(ptr)){ + /* freeFuncIndexes's entry is stale. Table was modified via a + different API */ ptr = null; continue; }else{ + /* This index is free. We'll re-use it. */ break; } } @@ -763,10 +765,9 @@ globalThis.WhWasmUtilInstaller = function(target){ has no side effects and returns undefined. */ target.uninstallFunction = function(ptr){ - if(!ptr && 0!==ptr) return undefined; - const fi = cache.freeFuncIndexes; + if(!ptr && __NullPtr!==ptr) return undefined; const ft = target.functionTable(); - fi.push(ptr); + cache.freeFuncIndexes.push(ptr); const rc = ft.get(ptr); ft.set(ptr, null); return rc; diff --git a/manifest b/manifest index 9a79620920..6def0d68a7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Move\ssqlite3-api-cleanup.js\sinto\spost-js-footer.js\sto\sremove\sthe\sfinal\sdirect\sEmscripten\sdependency\sfrom\sthe\sintermediary\sbuild\sproduct\ssqlite3-api.js\s(the\swhole\slibrary,\swaiting\sto\sbe\sbootstrapped).\sThis\sis\spartly\sin\sresponse\sto\s[forum:4b7d45433731d2e0|forum\spost\s4b7d45433731d2e0],\swhich\sdemonstrates\sa\spotential\suse\scase\sfor\sa\sstandalone\ssqlite3-api.js.\sThis\sis\sa\sbuild/doc\schange,\snot\sa\sfunctional\sone. -D 2025-11-15T09:19:03.391 +C Generic\sinternal\sJS\scleanups\stowards\simproving\sportability\sof\ssqlite3-api.js\sto\sother\sbuild\ssystems. +D 2025-11-15T11:30:45.653 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -588,26 +588,26 @@ F ext/wasm/api/README.md aae128e14711dafac29e7b645ff1b6be42305b73f74b1303d840135 F ext/wasm/api/extern-post-js.c-pp.js 4b310c9891886e7c1ea4e2419966ff45dfeda825b897fdaa4119332509f7e3d1 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/post-js-footer.js ef03962507ee0b5ad0bacd725502aea2e434cc214c666205a9745d2c89eb5c76 -F ext/wasm/api/post-js-header.js ef5b0ddbefba75c2ac92a44856f4e7e05150cea4df24d73282131ac0889e71f6 +F ext/wasm/api/post-js-header.js ce89f70db32efc31d45f188161cd62ff69218ea5329b8e1c872c9d32d5a2a9ed F ext/wasm/api/pre-js.c-pp.js ad2546290e0c8ce5ca2081bff6e85cc25eeb904a3303921f1184290a7ff1b32f F ext/wasm/api/sqlite3-api-glue.c-pp.js 79a54b54ca6324d28e31e19b56bbaebb7d2cc4b3079066e7e901333fa5047c53 F ext/wasm/api/sqlite3-api-oo1.c-pp.js 31dbfd470c91ffd96d77399b749bab6b69e3ba9074188833f97ac13f087cf07b -F ext/wasm/api/sqlite3-api-prologue.js a69eba98746c3dfbe54a9b0d653573d69103f47dd3bce7c68be8e5e6766ac2a0 +F ext/wasm/api/sqlite3-api-prologue.js a7cab3e8f78d5a93d7173657677fef18265f48d4e0b1e1755740f734a69cae6d F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938 F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89 F ext/wasm/api/sqlite3-opfs-async-proxy.js 9654b565b346dc609b75d15337f20acfa7af7d9d558da1afeb9b6d8eaa404966 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 26cb41d5a62f46a106b6371eb00fef02de3cdbfaa51338ba087a45f53028e0d0 -F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js af8ab2ac27f503e8255baf377085aeb0aff2f630f9d47f01d1a8a550784ffa9d +F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js aa330fa0e8ef35cbd92eb0d52e05fbaa07e61540c5cb164e693c82428ce1d763 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 9097074724172e31e56ce20ccd7482259cf72a76124213cbc9469d757676da86 -F ext/wasm/api/sqlite3-wasm.c 2d1cbe498f7b0fb64b11451eda481f458df74d6258baea635513e637fcbb8b1a +F ext/wasm/api/sqlite3-wasm.c 03451f8335f4ba8ea9a79dfc170560b1ee5376de64ff49c1a114274ccf50ab3d F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bda1c75bd674a92a0e27cc2f3d46dbbf21e422413f8046814515a0bd7409328a F ext/wasm/api/sqlite3-worker1.c-pp.js 802d69ead8c38dc1be52c83afbfc77e757da8a91a2e159e7ed3ecda8b8dba2e7 F ext/wasm/c-pp-lite.c 943be1a36774d58385dca32de36fc18d4f432fe79f7aa35e6c85dd6a6b825bd0 F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51 F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15 F ext/wasm/common/testing.css e97549bab24126c24e0daabfe2de9bb478fb0a69fdb2ddd0a73a992c091aad6f -F ext/wasm/common/whwasmutil.js b4fd73fac162406e67f276647ff8bae51881e15eebdf4b725aeb2b10ab1e056a +F ext/wasm/common/whwasmutil.js 804409dec98458f732b23e6e86788934ac6dec002107435cc4055355585d1c15 F ext/wasm/config.make.in c424ae1cc3c89274520ad312509d36c4daa34a3fce5d0c688e5f8f4365e1049a F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508 @@ -2166,8 +2166,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P c1e9791fbf9e4c2ca6f9f031ea2c26d8b4bfb4d54850a53853f2b2d9620792ef -R bb1eac7c46bbc299ec2a5148cd54f884 +P 2fcbd8e17d8f1dd7e9d45168805dba718777e46803d9375a4212296d3d0cd89c +R e4f44e14b3ab780c48274752ccab89fd U stephan -Z b71c372c7945ebd8247fbe33ca972302 +Z 9dfb861fa283e975d7b9ba4a36839625 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e180680089..77232b97c9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2fcbd8e17d8f1dd7e9d45168805dba718777e46803d9375a4212296d3d0cd89c +5bc37e5c2fcd83fd0bc40234144072363f1cbf7d811a15b74a0991e397a35eb8