From a2daecfc8cf963fc6a016436e8cab4261c526efa Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 20 Sep 2025 15:16:55 +0000 Subject: [PATCH] Further work on 64-bit WASM builds. It now gets through just shy of half of tester1.js. FossilOrigin-Name: c8deed31365898e1379d577298fc80ef08a5531999d5b54a9f14337febed0260 --- ext/wasm/api/sqlite3-api-cleanup.js | 31 +++-- ext/wasm/api/sqlite3-api-glue.c-pp.js | 41 +++--- ext/wasm/api/sqlite3-api-oo1.c-pp.js | 29 ++-- ext/wasm/api/sqlite3-api-prologue.js | 35 +++-- ext/wasm/common/whwasmutil.js | 193 ++++++++++++++++---------- ext/wasm/tester1.c-pp.js | 25 ++-- manifest | 22 +-- manifest.uuid | 2 +- 8 files changed, 224 insertions(+), 154 deletions(-) diff --git a/ext/wasm/api/sqlite3-api-cleanup.js b/ext/wasm/api/sqlite3-api-cleanup.js index 7fb29e6487..57aa335123 100644 --- a/ext/wasm/api/sqlite3-api-cleanup.js +++ b/ext/wasm/api/sqlite3-api-cleanup.js @@ -21,16 +21,28 @@ 'use strict'; if('undefined' !== typeof Module){ // presumably an Emscripten build /** - Install a suitable default configuration for sqlite3ApiBootstrap(). + The WASM-environment-specific configuration pieces + for sqlite3ApiBootstrap(). */ const SABC = Object.assign( - Object.create(null), { + Object.create(null), + globalThis.sqlite3ApiConfig || {}, + { exports: ('undefined'===typeof wasmExports) ? Module['asm']/* emscripten <=3.1.43 */ : wasmExports /* emscripten >=3.1.44 */, - memory: Module.wasmMemory /* gets set if built with -sIMPORTED_MEMORY */ - }, - globalThis.sqlite3ApiConfig || {} + memory: Module.wasmMemory /* gets set if built with -sIMPORTED_MEMORY */, +//#if sMEMORY64=1 + wasmPtrSizeof: 8, + wasmPtrIR: 'i64', +//#elif sMEMORY64=2 + wasmPtrSizeof: 8/*???*/, + wasmPtrIR: 'i64'/*???*/, +//#else + wasmPtrSizeof: 4, + wasmPtrIR: 'i32', +//#endif + } ); /** @@ -44,10 +56,11 @@ if('undefined' !== typeof Module){ // presumably an Emscripten build able to provide the necessary configuration state. */ //console.warn("globalThis.sqlite3ApiConfig = ",globalThis.sqlite3ApiConfig); - globalThis.sqlite3ApiConfig = SABC; - let sqlite3; try{ - sqlite3 = globalThis.sqlite3ApiBootstrap(); + Module.sqlite3 = globalThis.sqlite3ApiBootstrap(SABC) + /* Our customized sqlite3InitModule() in extern-post-js.js needs + this to be able to pass the sqlite3 object off to the + client. */; }catch(e){ console.error("sqlite3ApiBootstrap() error:",e); throw e; @@ -56,8 +69,6 @@ if('undefined' !== typeof Module){ // presumably an Emscripten build delete globalThis.sqlite3ApiConfig; } - Module.sqlite3 = sqlite3 /* Needed for customized sqlite3InitModule() to be able to - pass the sqlite3 object off to the client. */; }else{ console.warn("This is not running in an Emscripten module context, so", "globalThis.sqlite3ApiBootstrap() is _not_ being called due to lack", diff --git a/ext/wasm/api/sqlite3-api-glue.c-pp.js b/ext/wasm/api/sqlite3-api-glue.c-pp.js index fa0f1ae491..09f757bdea 100644 --- a/ext/wasm/api/sqlite3-api-glue.c-pp.js +++ b/ext/wasm/api/sqlite3-api-glue.c-pp.js @@ -21,13 +21,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 'use strict'; const toss = (...args)=>{throw new Error(args.join(' '))}; const capi = sqlite3.capi, wasm = sqlite3.wasm, util = sqlite3.util; -//#if sMEMORY64=1 - wasm.pointerIR = 'i64'; -//#elif sMEMORY64=2 - wasm.pointerIR = 'i64'/*???*/; -//#else - wasm.pointerIR = 'i32'; -//#endif globalThis.WhWasmUtilInstaller(wasm); delete globalThis.WhWasmUtilInstaller; @@ -1099,7 +1092,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ wasm.uninstallFunction() any WASM function bindings it has installed for pDb. */ - const closeArgs = [pDb]; for(const name of [ 'sqlite3_busy_handler', 'sqlite3_commit_hook', @@ -1119,15 +1111,19 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ /* assume it was built without this API */ continue; } + const closeArgs = [pDb]; closeArgs.length = x.length/*==argument count*/ || 1 /* Recall that: (A) undefined entries translate to 0 when passed to WASM and (B) Safari wraps wasm.exports.* in nullary functions so x.length is 0 there. */; + //console.debug(closeArgs, name,"()", capi[name]); + //wasm.xWrap.debug = true; try{ capi[name](...closeArgs) } catch(e){ /* This "cannot happen" unless something is well and truly sideways. */ sqlite3.config.warn("close-time call of",name+"(",closeArgs,") threw:",e); } + //wasm.xWrap.debug = false; } const m = __dbCleanupMap(pDb, 0); if(!m) return; @@ -1475,9 +1471,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ Helper for string:flexible conversions which requires a byte-length counterpart argument. Passed a value and its ostensible length, this function returns [V,N], where V is - either v or a transformed copy of v and N is either n (if v is - a WASM pointer), -1 (if v is a string or Array), or the byte - length of v (if it's a byte array or ArrayBuffer). + either v or a transformed copy of v and N is either Number(n) + (if v is a WASM pointer), -1 (if v is a string or Array), or + the byte length of v (if it's a byte array or ArrayBuffer). */ const __flexiString = (v,n)=>{ if('string'===typeof v){ @@ -1490,7 +1486,13 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ }else if(Array.isArray(v)){ v = v.join(""); n = -1; - } + }/*else if( 'bigint'===typeof n ){ + // tag:64-bit A workaround for when a stray BigInt, possibly + // calculated via a pointer range, gets passed in here. This + // has been seen to happen in sqlite3_prepare_v3() via + // oo1.DB.exec(). + n = Number(n); + }*/ return [v, n]; }; @@ -1531,13 +1533,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ } const [xSql, xSqlLen] = __flexiString(sql, sqlLen); switch(typeof xSql){ - case 'string': return __prepare.basic(pDb, xSql, xSqlLen, prepFlags, ppStmt, null); - case 'number': return __prepare.full(pDb, xSql, xSqlLen, prepFlags, ppStmt, pzTail); - default: - return util.sqlite3__wasm_db_error( - pDb, capi.SQLITE_MISUSE, - "Invalid SQL argument type for sqlite3_prepare_v2/v3()." - ); + case 'string': return __prepare.basic(pDb, xSql, xSqlLen, prepFlags, ppStmt, null); + case (typeof wasm.NullPtr): + return __prepare.full(pDb, xSql, xSqlLen, prepFlags, ppStmt, pzTail); + default: + return util.sqlite3__wasm_db_error( + pDb, capi.SQLITE_MISUSE, + "Invalid SQL argument type for sqlite3_prepare_v2/v3(). typeof="+(typeof xSql) + ); } }; diff --git a/ext/wasm/api/sqlite3-api-oo1.c-pp.js b/ext/wasm/api/sqlite3-api-oo1.c-pp.js index a0fac358fa..4dfd0a933f 100644 --- a/ext/wasm/api/sqlite3-api-oo1.c-pp.js +++ b/ext/wasm/api/sqlite3-api-oo1.c-pp.js @@ -1051,14 +1051,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ let sqlByteLen = isTA ? arg.sql.byteLength : wasm.jstrlen(arg.sql); const ppStmt = wasm.scopedAlloc( /* output (sqlite3_stmt**) arg and pzTail */ - (2 * wasm.ptrSizeof) + (sqlByteLen + 1/* SQL + NUL */) + (2 * wasm.pointerSizeof) + (sqlByteLen + 1/* SQL + NUL */) ); - const pzTail = ppStmt + wasm.ptrSizeof /* final arg to sqlite3_prepare_v2() */; - let pSql = pzTail + wasm.ptrSizeof; - const pSqlEnd = pSql + sqlByteLen; + const pzTail = wasm.ptrAdd(ppStmt, wasm.pointerSizeof) /* final arg to sqlite3_prepare_v2() */; + let pSql = wasm.ptrAdd(pzTail, wasm.pointerSizeof); + const pSqlEnd = wasm.ptrAdd(pSql, sqlByteLen); if(isTA) wasm.heap8().set(arg.sql, pSql); else wasm.jstrcpy(arg.sql, wasm.heap8(), pSql, sqlByteLen, false); - wasm.poke(pSql + sqlByteLen, 0/*NUL terminator*/); + wasm.poke(wasm.ptrAdd(pSql, sqlByteLen), 0/*NUL terminator*/); while(pSql && wasm.peek(pSql, 'i8') /* Maintenance reminder:^^^ _must_ be 'i8' or else we will very likely cause an endless loop. What that's @@ -1073,7 +1073,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ )); const pStmt = wasm.peekPtr(ppStmt); pSql = wasm.peekPtr(pzTail); - sqlByteLen = pSqlEnd - pSql; + sqlByteLen = Number(wasm.ptrAdd(pSqlEnd,-pSql)); if(!pStmt) continue; if(saveSql) saveSql.push(capi.sqlite3_sql(pStmt).trim()); stmt = new Stmt(this, pStmt, BindTypes); @@ -2091,15 +2091,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ const n = capi.sqlite3_column_bytes(this.pointer, ndx), ptr = capi.sqlite3_column_blob(this.pointer, ndx), rc = new Uint8Array(n); - //heap = n ? wasm.heap8() : false; - if(n) rc.set(wasm.heap8u().slice(ptr, ptr+n), 0); - //for(let i = 0; i < n; ++i) rc[i] = heap[ptr + i]; - if(n && this.db._blobXfer instanceof Array){ - /* This is an optimization soley for the - Worker-based API. These values will be - transfered to the main thread directly - instead of being copied. */ - this.db._blobXfer.push(rc.buffer); + if(n){ + rc.set(wasm.heap8u().slice(Number(ptr), Number(ptr)+n), 0); + if(this.db._blobXfer instanceof Array){ + /* This is an optimization soley for the Worker1 API. It + will transfer these to the main thread directly + instead of copying them. */ + this.db._blobXfer.push(rc.buffer); + } } return rc; } diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index 733782dd12..a14f7692d5 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -150,18 +150,23 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( it becomes significant with, e.g., sqlite3_deserialize() and certain wasm.xWrap.resultAdapter()s. */ - useStdAlloc: false + useStdAlloc: false, + /* + sqlite3-api-cleanup.js sets wasmPtrSizeof and wasmPtrIR + */ + wasmPtrSizeof: 4, + wasmPtrIR: 'i32' }, apiConfig || {}); Object.assign(config, { allocExportName: config.useStdAlloc ? 'malloc' : 'sqlite3_malloc', deallocExportName: config.useStdAlloc ? 'free' : 'sqlite3_free', reallocExportName: config.useStdAlloc ? 'realloc' : 'sqlite3_realloc' - }, config); + }); [ // If any of these config options are functions, replace them with - // the result of calling that function... + // the result of calling that function. They must not be async. 'exports', 'memory', 'wasmfsOpfsDir' ].forEach((k)=>{ if('function' === typeof config[k]){ @@ -846,6 +851,10 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( } }/*util*/; + /** + wasm.X properties which are used for configuring the wasm + environment via whwashutil.js. + */ Object.assign(wasm, { /** Emscripten APIs have a deep-seated assumption that all pointers @@ -853,13 +862,13 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( the case and will use this constant in places where we might otherwise use a hard-coded 4. */ - ptrSizeof: config.wasmPtrSizeof || 4, + pointerSizeof: config.wasmPtrSizeof, /** The WASM IR (Intermediate Representation) value for pointer-type values. It MUST refer to a value type of the - size described by this.ptrSizeof. + size described by this.pointerSizeof. */ - ptrIR: config.wasmPtrIR || "i32", + pointerIR: config.wasmPtrIR, /** True if BigInt support was enabled via (e.g.) the Emscripten -sWASM_BIGINT flag, else false. When @@ -1156,14 +1165,14 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( WasmAllocError.toss("Invalid size value for allocChunks(",arguments[1],")"); } const mem = wasm.pstack.alloc(n * sz); - const rc = []; - let i = 0, offset = 0; + const rc = [mem]; + let i = 1, offset = sz; for(; i < n; ++i, offset += sz) rc.push(wasm.ptrAdd(mem, offset)); return rc; }, /** A convenience wrapper for allocChunks() which sizes each chunk - as either 8 bytes (safePtrSize is truthy) or wasm.ptrSizeof (if + as either 8 bytes (safePtrSize is truthy) or wasm.pointerSizeof (if safePtrSize is falsy). How it returns its result differs depending on its first @@ -1182,8 +1191,8 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( */ allocPtr: (n=1,safePtrSize=true)=>{ return 1===n - ? wasm.pstack.alloc(safePtrSize ? 8 : wasm.ptrSizeof) - : wasm.pstack.allocChunks(n, safePtrSize ? 8 : wasm.ptrSizeof); + ? wasm.pstack.alloc(safePtrSize ? 8 : wasm.pointerSizeof) + : wasm.pstack.allocChunks(n, safePtrSize ? 8 : wasm.pointerSizeof); }, /** @@ -1403,7 +1412,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( const scope = wasm.scopedAllocPush(); let pOut; try{ - const pSize = wasm.scopedAlloc(8/*i64*/ + wasm.ptrSizeof); + const pSize = wasm.scopedAlloc(8/*i64*/ + wasm.pointerSizeof); const ppOut = pSize + 8; /** Maintenance reminder, since this cost a full hour of grief @@ -1853,7 +1862,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( do not. */ tgt.push(capi.sqlite3_value_to_js( - wasm.peekPtr(pArgv + (wasm.ptrSizeof * i)), + wasm.peekPtr(pArgv + (wasm.pointerSizeof * i)), throwIfCannotConvert )); } diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js index 155e1f2dee..6f9edb9b5b 100644 --- a/ext/wasm/common/whwasmutil.js +++ b/ext/wasm/common/whwasmutil.js @@ -14,6 +14,10 @@ https://fossil.wanderinghorse.net/r/jaccwabyt + More specifically: + + https://fossil.wanderinghorse.net/r/jaccwabyt/file/common/whwasmutil.js + and SQLite: https://sqlite.org @@ -32,11 +36,11 @@ utility APIs provided by this code are still usable as replacements for their Emscripten counterparts. - Forewarning: this API explicitly targets only browser - environments. If a given non-browser environment has the - capabilities needed for a given feature (e.g. TextEncoder), great, - but it does not go out of its way to account for them and does not - provide compatibility crutches for them. + Forewarning: this API explicitly targets only browser environments. + If a given non-browser environment has the capabilities needed for + a given feature (e.g. TextEncoder), great, but it does not go out + of its way to account for them and does not provide compatibility + crutches for them. Intended usage: @@ -162,20 +166,22 @@ - `pointerIR`: an IR-format string for the WASM environment's pointer size. If set it must be either 'i32' or 'i64'. If not - set, it defaults to whatever this code thinks the pointer size + set, it gets set to whatever this code thinks the pointer size is. Modifying it after this call has no effect. - target.pointerSizeof gets set to either 4 or 8, depending on - this option. - - This code is developed and maintained in conjunction with the - Jaccwabyt project: + - `pointerSizeof`: if set, it must be one of 4 or 8 and must + correspond to the value of `pointerIR`. If not set, it gets set + to whatever this code thinks the pointer size is (4 unless + `pointerIR` is 'i64'). If `pointerSizeof` is set but `pointerIR` + is not, `pointerIR` gets set appropriately, and vice versa. - https://fossil.wanderinghorse.net/r/jaccwabyt + When building with Emscripten's -sMEMORY64=1, `pointerIR` must be + set to 'i64' and/or `pointerSizeof` must be set to 8. - More specifically: + Design notes: - https://fossil.wanderinghorse.net/r/jaccwabyt/file/common/whwasmutil.js + - It should probably take a config object and return the + target. The current approach seemed better at the time. */ globalThis.WhWasmUtilInstaller = function(target){ 'use strict'; @@ -187,12 +193,53 @@ globalThis.WhWasmUtilInstaller = function(target){ all args with a space between each. */ const toss = (...args)=>{throw new Error(args.join(' '))}; - if(!target.exports){ - Object.defineProperty(target, 'exports', { - enumerable: true, configurable: true, - get: ()=>(target.instance && target.instance.exports) - }); + /** + Pointers in WASM are currently assumed to be 32-bit, but someday + that will certainly change. + + 2025-09-19: work has started in getting this library to work with + Emscripten's -sMEMORY64=1. + */ + if( target.pointerSizeof && !target.pointerIR ){ + target.pointerIR = (4===target.pointerSizeof ? 'i32' : 'i64'); + } + const ptrIR = (target.pointerIR ??= 'i32'); + const ptrSizeof = (target.pointerSizeof ??= + ('i32'===ptrIR ? 4 : ('i64'===ptrIR ? 8 : 0))); + + if( 'i32'!==ptrIR && 'i64'!==ptrIR ){ + toss("Invalid pointerIR:",ptrIR); } + if( 8!==ptrSizeof && 4!==ptrSizeof ){ + toss("Invalid pointerSizeof:",ptrSizeof); + } + + /** + If target.pointerIR=='i32' then this is equivalent to + Number(v) else it's equivalent to BigInt(v||0). + + Why? Because Number(null)===0, but BigInt(null) throws. + */ + const __asPtrType = (4===ptrSizeof) + ? Number + : (target.bigIntEnabled + ? ((v)=>BigInt(v || 0)) + : toss("Missing BigInt support")); + + target.asPtrType = __asPtrType; + + /** + The number 0 as either type Number or BigInt, depending on + target.pointerIR. + */ + const __NullPtr = __asPtrType(0); + + target.NullPtr = __NullPtr; + + /** + The typeof X value for target.NullPtr + */ + //target.pointerTypeof = typeof __NullPtr; /********* alloc()/dealloc() auto-install... @@ -223,30 +270,6 @@ globalThis.WhWasmUtilInstaller = function(target){ } }*******/ - /** - Pointers in WASM are currently assumed to be 32-bit, but someday - that will certainly change. - */ - const ptrIR = target.pointerIR || (target.pointerIR = 'i32'); - const ptrSizeof = target.pointerSizeof = - ('i32'===ptrIR ? 4 - : ('i64'===ptrIR - ? 8 : toss("Unhandled pointerIR:",ptrIR))); - - /** - If target.pointerIR=='i32' then this is equivalent to - Number(v) else it's equivalent to BigInt(v||0). - - Why? Because Number(null)===0, but BigInt(null) throws. - */ - const __asPtrType = ('i32'==ptrIR) - ? Number - : (target.bigIntEnabled - ? ((v)=>BigInt(v || 0)) - : toss("Missing BigInt support")); - - target.asPtrType = __asPtrType; - /** Expects any number of numeric arguments, each one of either type Number or BigInt. It sums them up (from an implicit starting @@ -267,13 +290,13 @@ globalThis.WhWasmUtilInstaller = function(target){ target.ptrAdd = __ptrAdd; - /** - The number 0 as either type Number or BigInt, depending on - target.pointerIR. - */ - const __NullPtr = __asPtrType(0); - target.NullPtr = __NullPtr; + if(!target.exports){ + Object.defineProperty(target, 'exports', { + enumerable: true, configurable: true, + get: ()=>(target?.instance?.exports) + }); + } /** Stores various cached state. */ const cache = Object.create(null); @@ -898,12 +921,11 @@ globalThis.WhWasmUtilInstaller = function(target){ */ target.isPtr32 = (ptr)=>('number'===typeof ptr && (ptr===(ptr|0)) && ptr>=0); - /* UNTESTED */ target.isPtr64 = (ptr)=>{ if( 'bigint'===typeof ptr ){ return ptr >= 0; } - return ('number'===typeof ptr && (ptr===(ptr|0)) && ptr>=0); + return ('number'===typeof ptr && ptr>=0 && (ptr===(ptr|0))); }; /** @@ -1034,6 +1056,8 @@ globalThis.WhWasmUtilInstaller = function(target){ if(!tgt || (!(tgt instanceof Int8Array) && !(tgt instanceof Uint8Array))){ toss("jstrcpy() target must be an Int8Array or Uint8Array."); } + maxBytes = Number(maxBytes)/*tag:64bit*/; + offset = Number(offset)/*tag:64bit*/; if(maxBytes<0) maxBytes = tgt.length - offset; if(!(maxBytes>0) || !(offset>=0)) return 0; let i = 0, max = jstr.length; @@ -1498,7 +1522,17 @@ globalThis.WhWasmUtilInstaller = function(target){ xArg.set('i64', (i)=>BigInt(i || 0)); } const __xArgPtr = __asPtrType; - xArg.set('i32', (i)=>(i | 0) ) + xArg.set( + 'i32', + 0 + ? (i)=>Number(i) | 0 + /* This Number(i) is unsatisfying but it enables i32-type args which + are inadvertently passed a BigInt (which is easy to do) to + play along instead of causing an exception about lack of implicit + conversions from BigInt to Number. */ + : (i)=>i|0 + ); + xArg .set('i16', (i)=>((i | 0) & 0xFFFF)) .set('i8', (i)=>((i | 0) & 0xFF)) .set('f32', (i)=>Number(i).valueOf()) @@ -1796,13 +1830,19 @@ globalThis.WhWasmUtilInstaller = function(target){ exactly the 2nd and 3rd arguments are. */ convertArg(v,argv,argIndex){ - //FuncPtrAdapter.debugOut("FuncPtrAdapter.convertArg()",this.name,this.signature,this.transient,v); let pair = this.singleton; if(!pair && this.isContext){ pair = this.contextMap(this.contextKey(argv,argIndex)); //FuncPtrAdapter.debugOut(this.name, this.signature, "contextKey() =",this.contextKey(argv,argIndex), pair); } - if(pair && pair[0]===v){ + if( 0 ){ + FuncPtrAdapter.debugOut("FuncPtrAdapter.convertArg()",this.name, + 'signature =',this.signature, + 'transient ?=',this.transient, + 'pair =',pair, + 'v =',v); + } + if(pair && 2===pair.length && pair[0]===v){ /* We have already handled this function. */ return pair[1]; } @@ -1838,23 +1878,22 @@ globalThis.WhWasmUtilInstaller = function(target){ } catch(e){/*ignored*/} } - pair[0] = arguments[0]/*the original v*/; + pair[0] = arguments[0] || __NullPtr/*the original v*/; pair[1] = fp; } return fp; }else if(target.isPtr(v) || null===v || undefined===v){ - //FuncPtrAdapter.debugOut("FuncPtrAdapter.convertArg()",this.name,this.signature,this.transient,v,pair); if(pair && pair[1] && pair[1]!==v){ /* uninstall stashed mapping and replace stashed mapping with v. */ if(FuncPtrAdapter.debugFuncInstall){ FuncPtrAdapter.debugOut("FuncPtrAdapter uninstalling", this, this.contextKey(argv,argIndex), '@'+pair[1], v); } - try{ cache.scopedAlloc.pushPtr(pair[1]); } + try{cache.scopedAlloc.pushPtr(pair[1]);/*see notes above*/} catch(e){/*ignored*/} - pair[0] = pair[1] = (v | 0); + pair[0] = pair[1] = (v || __NullPtr); } - return v || 0; + return v || __NullPtr; }else{ throw new TypeError("Invalid FuncPtrAdapter argument type. "+ "Expecting a function pointer or a "+ @@ -2150,6 +2189,9 @@ globalThis.WhWasmUtilInstaller = function(target){ https://sqlite.org/forum/forumpost/b549992634b55104 */ let i = 0; + if( callee.debug ){ + console.debug("xWrap() preparing: resultType ",resultType, 'xf',xf,"argTypes",argTypes,"args",args); + } for(; i < args.length; ++i) args[i] = cxw.convertArgNoCheck( argTypes[i], args[i], args, i ); @@ -2327,28 +2369,26 @@ globalThis.WhWasmUtilInstaller = function(target){ - `uri`: required URI of the WASM file to load. - - `onload(loadResult,config)`: optional callback. The first - argument is the result object from - WebAssembly.instantiate[Streaming](). The 2nd is the config - object passed to this function. Described in more detail below. + - `onload(loadResult)`: optional callback. Its argument is an + object described in more detail below. - `imports`: optional imports object for - WebAssembly.instantiate[Streaming](). The default is an empty set - of imports. If the module requires any imports, this object + WebAssembly.instantiate[Streaming](). The default is an empty + set of imports. If the module requires any imports, this object must include them. - `wasmUtilTarget`: optional object suitable for passing to WhWasmUtilInstaller(). If set, it gets passed to that function - after the promise resolves. This function sets several properties - on it before passing it on to that function (which sets many - more): + before the returned promise resolves. This function sets several + properties on it before passing it on to that function (which + sets many more): - `module`, `instance`: the properties from the instantiate[Streaming]() result. - If `instance.exports.memory` is _not_ set then it requires that `config.imports.env.memory` be set (else it throws), and - assigns that to `target.memory`. + assigns that to `wasmUtilTarget.memory`. - If `wasmUtilTarget.alloc` is not set and `instance.exports.malloc` is, it installs @@ -2357,14 +2397,15 @@ globalThis.WhWasmUtilInstaller = function(target){ It returns a function which, when called, initiates loading of the module and returns a Promise. When that Promise resolves, it calls - the `config.onload` callback (if set) and passes it - `(loadResult,config)`, where `loadResult` is the result of - WebAssembly.instantiate[Streaming](): an object in the form: + the `config.onload` callback (if set) and passes it `(loadResult)`, + where `loadResult` is derived from the result of + WebAssembly.instantiate[Streaming](), an object in the form: ``` { module: a WebAssembly.Module, - instance: a WebAssembly.Instance + instance: a WebAssembly.Instance, + config: the config arg to this function } ``` @@ -2392,8 +2433,7 @@ globalThis.WhWasmUtilInstaller.yawl = function(config){ (exported from WASM) or tgt.memory (JS-provided memory imported into WASM). */ - tgt.memory = (config.imports && config.imports.env - && config.imports.env.memory) + tgt.memory = config?.imports?.env?.memory || toss("Missing 'memory' object!"); } if(!tgt.alloc && arg.instance.exports.malloc){ @@ -2405,7 +2445,8 @@ globalThis.WhWasmUtilInstaller.yawl = function(config){ } wui(tgt); } - if(config.onload) config.onload(arg,config); + arg.config = config; + if(config.onload) config.onload(arg); return arg /* for any then() handler attached to yetAnotherWasmLoader()'s return value */; }; diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index 8497f5bb5c..0576f25ce6 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -1084,7 +1084,9 @@ globalThis.sqlite3InitModule = sqlite3InitModule; T.assert(P.pointer === stack); try { const [p1, p2, p3] = P.allocChunks(3,'i32'); - T.assert(P.pointer == Number(stack)-16/*always rounded to multiple of 8*/) + let sPos = wasm.ptrAdd(stack,-16)/*pstack alloc always rounds to multiple of 8*/; + T.assert(P.pointer === sPos) + .assert(p1 === sPos) .assert(p2 == Number(p1) + 4) .assert(p3 == Number(p2) + 4); T.mustThrowMatching(()=>P.allocChunks(1024, 1024 * 16), @@ -1096,12 +1098,16 @@ globalThis.sqlite3InitModule = sqlite3InitModule; T.assert(P.pointer === stack); try { let [p1, p2, p3] = P.allocPtr(3,false); - let sPos = Number(stack)-16/*always rounded to multiple of 8*/; - T.assert(P.pointer == sPos) - .assert(p2 == Number(p1) + 4) - .assert(p3 == Number(p2) + 4); + let sPos = wasm.ptrAdd(stack, + -(4===wasm.pointerSizeof + ? 16/*pstack alloc always rounds to multiple of 8*/ + : 24)); + T.assert(P.pointer === p1) + .assert(p1 === sPos) + .assert(p2 == Number(p1) + wasm.pointerSizeof) + .assert(p3 == Number(p2) + wasm.pointerSizeof); [p1, p2, p3] = P.allocPtr(3); - T.assert(P.pointer == sPos-24/*3 x 8 bytes*/) + T.assert(P.pointer === wasm.ptrAdd(sPos, -24)/*3 x 8 bytes*/) .assert(p2 == Number(p1) + 8) .assert(p3 == Number(p2) + 8); p1 = P.allocPtr(); @@ -1119,8 +1125,8 @@ globalThis.sqlite3InitModule = sqlite3InitModule; try{ const n = 520; const p = wasm.pstack.alloc(n); - T.assert(0===wasm.peek8(p)) - .assert(0===wasm.peek8(wasm.ptrAdd(p,n,-1))); + T.assert(0==wasm.peek8(p)) + .assert(0==wasm.peek8(wasm.ptrAdd(p,n,-1))); T.assert(undefined === capi.sqlite3_randomness(n - 10, p)); let j, check = 0; const heap = wasm.heap8u(); @@ -1275,7 +1281,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule; const stack = wasm.pstack.pointer; try { const ppOut = wasm.pstack.allocPtr(); - T.assert( 0===wasm.peekPtr(ppOut) ); + T.assert( 0==wasm.peekPtr(ppOut) ); let rc = capi.sqlite3_open_v2( ":memory:", ppOut, capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE, @@ -1488,6 +1494,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule; const db = this.db; let list = []; this.progressHandlerCount = 0; + //wasm.xWrap.debug = true; let rc = db.exec({ sql:['CREATE TABLE t(a,b);', // ^^^ using TEMP TABLE breaks the db export test diff --git a/manifest b/manifest index 668b96ac78..3f8fd94de1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Get\sthe\swasm\stests\srunning\sin\sa\s64-bit\sbuild\sup\sthrough\s(but\snot\sincluding)\sthe\soo1\sbits. -D 2025-09-20T11:09:20.368 +C Further\swork\son\s64-bit\sWASM\sbuilds.\sIt\snow\sgets\sthrough\sjust\sshy\sof\shalf\sof\stester1.js. +D 2025-09-20T15:16:55.119 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -596,10 +596,10 @@ F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e F ext/wasm/api/post-js-footer.js 365405929f41ca0e6d389ed8a8da3f3c93e11d3ef43a90ae151e37fa9f75bf41 F ext/wasm/api/post-js-header.js 53740d824e5d9027eb1e6fd59e216abbd2136740ce260ea5f0699ff2acb0a701 F ext/wasm/api/pre-js.c-pp.js 58f823de197e2c10d76179aa05410a593b7ae03e1ece983bb42ffd818e8857e1 -F ext/wasm/api/sqlite3-api-cleanup.js 3ac1786e461ada63033143be8c3b00b26b939540661f3e839515bb92f2e35359 -F ext/wasm/api/sqlite3-api-glue.c-pp.js c6a4271411caf9b0ff434436766fcd226e22cad484949fc207045d13ba960354 -F ext/wasm/api/sqlite3-api-oo1.c-pp.js dc8573267f0dd49ae314a295c0dbe86de921f6d6beabbb7a447029ca1ea4e1d9 -F ext/wasm/api/sqlite3-api-prologue.js 5812f5acb0eb17ce04cbea554fa33236acfcbe5eaaa6ddc04eb6454141040a98 +F ext/wasm/api/sqlite3-api-cleanup.js 6341cb85c931044647ad4b12654a178c81f5a8fbeccdf4dc4f258e5a390d2241 +F ext/wasm/api/sqlite3-api-glue.c-pp.js 8d399c686b068427b4c9e51d68d9fc1f632ee9c89a1c49d3e2919744d68c622a +F ext/wasm/api/sqlite3-api-oo1.c-pp.js c40857ef457c1243d40dd92602e362e7431500936b0358263e8caa115436e705 +F ext/wasm/api/sqlite3-api-prologue.js 1f3aa229e225f8f93e6011d64c7ecd1ac2e4a70b94d8f78f493e1a7dbb236e47 F ext/wasm/api/sqlite3-api-worker1.c-pp.js 760191cd13416e6f5adfd9fcc8a97fed5645c9e0a5fbac213a2d4ce2d79a4334 F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89 F ext/wasm/api/sqlite3-opfs-async-proxy.js 9654b565b346dc609b75d15337f20acfa7af7d9d558da1afeb9b6d8eaa404966 @@ -618,7 +618,7 @@ F ext/wasm/c-pp.c cca55c5b55ebd8d29916adbedb0e40baa12caa9a2e8429f812683c308f9b0e 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 1475e140bbd48d67e385603ce3e4bef7ca00d8ee3ec896d40cf4f55c7336b0c3 +F ext/wasm/common/whwasmutil.js 1b4b0b38b590221bad5d9d807b1d30127626ddc05f616182f01423ac8fcce089 F ext/wasm/config.make.in c424ae1cc3c89274520ad312509d36c4daa34a3fce5d0c688e5f8f4365e1049a F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508 @@ -655,7 +655,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2 -F ext/wasm/tester1.c-pp.js 827de6ae0b069709762afb58c452b769bbab092c6c7c850e5aab9581d82aff45 +F ext/wasm/tester1.c-pp.js 7f32d79407cce016cde0e884e364d5fb04addeb7cb7f43b30169cdd938589634 F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88 F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 @@ -2175,8 +2175,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 1e3b003ff99d2788d93e179504b711cb78846605774bf472589440d0136f20fa -R 5e413c78ac49f5649b20125a76a68b9e +P a5af46174a05e1414370884d1a99827af9286a60eff1c8ae1551e7fad3903f7a +R 2adec1131b74b3b8137161b75e6957cf U stephan -Z 40da1eb0811159ac3f90712f37f01328 +Z 0d524ac36a249cd8e25e154440f46d24 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index ffeb3900e4..bf1f911915 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a5af46174a05e1414370884d1a99827af9286a60eff1c8ae1551e7fad3903f7a +c8deed31365898e1379d577298fc80ef08a5531999d5b54a9f14337febed0260 -- 2.47.3