From: stephan Date: Sun, 21 Sep 2025 17:55:23 +0000 (+0000) Subject: Generic cleanups and simplifications in JS code. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5b71447e8e98bf72fea934d9ef0b6242d37d55c5;p=thirdparty%2Fsqlite.git Generic cleanups and simplifications in JS code. FossilOrigin-Name: 074cf4e6c1775900204bb0d920111ee19601d5c63690e79e988e7fe6b040a647 --- diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile index 394cba69d3..164464fb5f 100644 --- a/ext/wasm/GNUmakefile +++ b/ext/wasm/GNUmakefile @@ -443,7 +443,7 @@ cflags.common = -I. -I$(dir $(sqlite3.c)) # disables certain features if BigInt is not enabled and such builds # _are not tested_ on any regular basis. emcc.WASM_BIGINT ?= 1 -emcc.MEMORY64 ?= 1 +emcc.MEMORY64 ?= 0 ######################################################################## # https://emscripten.org/docs/tools_reference/settings_reference.html#memory64 # diff --git a/ext/wasm/api/extern-post-js.c-pp.js b/ext/wasm/api/extern-post-js.c-pp.js index 04b140fa6e..3710c367a7 100644 --- a/ext/wasm/api/extern-post-js.c-pp.js +++ b/ext/wasm/api/extern-post-js.c-pp.js @@ -68,7 +68,10 @@ const toExportForESM = const s = EmscriptenModule.sqlite3; s.scriptInfo = initModuleState; //console.warn("sqlite3.scriptInfo =",s.scriptInfo); - if(ff.__isUnderTest) s.__isUnderTest = true; + if(ff.__isUnderTest){ + s.__isUnderTest = true; + s.emscripten = EmscriptenModule; + } const f = s.asyncPostInit; delete s.asyncPostInit; const rv = f(); diff --git a/ext/wasm/api/sqlite3-api-cleanup.js b/ext/wasm/api/sqlite3-api-cleanup.js index e2f0794fde..c04664379a 100644 --- a/ext/wasm/api/sqlite3-api-cleanup.js +++ b/ext/wasm/api/sqlite3-api-cleanup.js @@ -19,59 +19,51 @@ handler. */ 'use strict'; -if('undefined' !== typeof Module){ // presumably an Emscripten build - /** - The WASM-environment-specific configuration pieces - for sqlite3ApiBootstrap(). - */ - const SABC = Object.assign( - 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 */ - } - ); +if( 'undefined' !== typeof Module ){ // presumably an Emscripten build + try{ + /** + The WASM-environment-dependent configuration for + sqlite3ApiBootstrap(). + */ + const SABC = Object.assign( + Object.create(null), + globalThis.sqlite3ApiConfig || {}, { + memory: ('undefined'!==typeof wasmMemory) + ? wasmMemory + : Module['wasmMemory'], + exports: ('undefined'!==typeof wasmExports) + ? wasmExports /* emscripten >=3.1.44 */ + : (Object.prototype.hasOwnProperty.call(Module,'wasmExports') + ? Module['wasmExports'] + : Module['asm']/* emscripten <=3.1.43 */) + }, + ); - /** Figure out if this is a 32- or 64-bit WASM build. */ - switch( typeof SABC.exports.sqlite3_libversion() ){ - case 'number': - SABC.wasmPtrIR = 'i32'; - SABC.wasmPtrSize = 4; - break; - case 'bigint': - SABC.wasmPtrIR = 'i64'; - SABC.wasmPtrSize = 8; - break; - default: - throw new Error("Cannot determine whether this is a 32- or 64-bit build"); - } + /** Figure out if this is a 32- or 64-bit WASM build. */ + SABC.wasmPtrIR = 'number'===(typeof SABC.exports.sqlite3_libversion()) + ? 'i32' :'i64'; - /** - For current (2022-08-22) purposes, automatically call - sqlite3ApiBootstrap(). That decision will be revisited at some - point, as we really want client code to be able to call this to - configure certain parts. Clients may modify - globalThis.sqlite3ApiBootstrap.defaultConfig to tweak the default - configuration used by a no-args call to sqlite3ApiBootstrap(), - but must have first loaded their WASM module in order to be - able to provide the necessary configuration state. - */ - //console.warn("globalThis.sqlite3ApiConfig = ",globalThis.sqlite3ApiConfig); - try{ + /** + For current (2022-08-22) purposes, automatically call + sqlite3ApiBootstrap(). That decision will be revisited at some + point, as we really want client code to be able to call this to + configure certain parts. Clients may modify + globalThis.sqlite3ApiBootstrap.defaultConfig to tweak the default + configuration used by a no-args call to sqlite3ApiBootstrap(), + but must have first loaded their WASM module in order to be + able to provide the necessary configuration state. + */ + //console.warn("globalThis.sqlite3ApiConfig = ",globalThis.sqlite3ApiConfig); 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. */; + /* Our customized sqlite3InitModule() in extern-post-js.js needs + this to be able to pass the sqlite3 object off to the + client. */; + delete globalThis.sqlite3ApiBootstrap; + delete globalThis.sqlite3ApiConfig; }catch(e){ console.error("sqlite3ApiBootstrap() error:",e); throw e; - }finally{ - delete globalThis.sqlite3ApiBootstrap; - delete globalThis.sqlite3ApiConfig; } - }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-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index b91b62307c..42d232cce8 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -49,8 +49,8 @@ - `exports`[^1]: the "exports" object for the current WASM environment. In an Emscripten-based build, this should be set to - `Module['asm']` (versions <=3.1.43) or `wasmExports` (versions - >=3.1.44). + `Module['asm']` (versions <=3.1.43) or `Module['wasmExports']` + (versions >=3.1.44). - `memory`[^1]: optional WebAssembly.Memory object, defaulting to `exports.memory`. In Emscripten environments this should be set @@ -58,6 +58,10 @@ left undefined/falsy to default to `exports.memory` when using WASM-exported memory. + - `functionTable`[^1]: optional WebAssembly.Table object holding + the indirect function table. If not set then the table is assumed + to be in `exports.__indirect_function_table`. + - `bigIntEnabled`: true if BigInt support is enabled. Defaults to true if `globalThis.BigInt64Array` is available, else false. Some APIs will throw exceptions if called without BigInt support, as BigInt @@ -162,7 +166,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( [ // If any of these config options are functions, replace them with // the result of calling that function. They must not be async. - 'exports', 'memory', 'wasmfsOpfsDir' + 'exports', 'memory', 'functionTable', 'wasmfsOpfsDir' ].forEach((k)=>{ if('function' === typeof config[k]){ config[k] = config[k](); @@ -851,19 +855,14 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( environment via whwashutil.js. */ Object.assign(wasm, { - /** - Emscripten APIs have a deep-seated assumption that all pointers - are 32 bits. We'll remain optimistic that that won't always be - the case and will use this constant in places where we might - otherwise use a hard-coded 4. - */ - pointerSize: config.wasmPtrSize, /** The WASM IR (Intermediate Representation) value for - pointer-type values. It MUST refer to a value type of the - size described by this.pointerSize. + pointer-type values. If set then it MUST be one of 'i32' or + 'i64' (else an exception will be thrown). If it's not set, it + will default to 'i32'. */ pointerIR: config.wasmPtrIR, + /** True if BigInt support was enabled via (e.g.) the Emscripten -sWASM_BIGINT flag, else false. When @@ -872,6 +871,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( impedance mismatches. */ bigIntEnabled: !!config.bigIntEnabled, + /** The symbols exported by the WASM environment. */ @@ -890,6 +890,12 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( "in either config.exports.memory (exported)", "or config.memory (imported)."), + /** + WebAssembly.Table object holding the indirect function call + table. Defaults to exports.__indirect_function_table. + */ + functionTable: config.functionTable, + /** The API's primary point of access to the WASM-side memory allocator. Works like sqlite3_malloc() but throws a @@ -908,8 +914,8 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( catch exceptions and convert them to appropriate error codes. For cases where non-throwing allocation is required, use - this.alloc.impl(), which is direct binding of the - underlying C-level allocator. + this.alloc.impl(), which is the unadulterated WASM-exported + counterpart of this wrapper. Design note: this function is not named "malloc" primarily because Emscripten uses that name and we wanted to avoid any @@ -971,10 +977,9 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( srcTypedArray = new Uint8Array(srcTypedArray); } affirmBindableTypedArray(srcTypedArray); + const heap = wasm.heapForSize(srcTypedArray.constructor); const pRet = wasm.alloc(srcTypedArray.byteLength || 1); - wasm.heapForSize(srcTypedArray.constructor).set( - srcTypedArray.byteLength ? srcTypedArray : [0], Number(pRet) - ); + heap.set(srcTypedArray.byteLength ? srcTypedArray : [0], Number(pRet)); return pRet; }; @@ -1045,7 +1050,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( rv[1] = m ? (f._rxInt.test(m[2]) ? +m[2] : m[2]) : true; }; } - const rc = {}, ov = [0,0]; + const rc = Object.create(null), ov = [0,0]; let i = 0, k; while((k = capi.sqlite3_compileoption_get(i++))){ f._opt(k,ov); @@ -1053,7 +1058,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( } return f._result = rc; }else if(Array.isArray(optName)){ - const rc = {}; + const rc = Object.create(null); optName.forEach((v)=>{ rc[v] = capi.sqlite3_compileoption_used(v); }); @@ -1116,6 +1121,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( environment if passed an illegal value. */ restore: wasm.exports.sqlite3__wasm_pstack_restore, + /** Attempts to allocate the given number of bytes from the pstack. On success, it zeroes out a block of memory of the @@ -1141,6 +1147,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( || WasmAllocError.toss("Could not allocate",n, "bytes from the pstack."); }, + /** alloc()'s n chunks, each sz bytes, as a single memory block and returns the addresses as an array of n element, each holding @@ -1153,7 +1160,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( Example: ``` - const [p1, p2, p3] = wasm.pstack.allocChunks(3,4); + const [p1, p2, p3] = wasm.pstack.allocChunks(3, wasm.ptr.size); ``` */ allocChunks: function(n,sz){ @@ -1166,6 +1173,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( for(; i < n; ++i, offset += sz) rc.push(wasm.ptr.add(mem, offset)); return rc; }, + /** A convenience wrapper for allocChunks() which sizes each chunk as either 8 bytes (safePtrSize is truthy) or wasm.ptr.size (if @@ -1201,19 +1209,19 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( */ call: function(f){ const stackPos = wasm.pstack.pointer; - try{ return f(sqlite3) } finally{ - wasm.pstack.restore(stackPos); - } + try{ return f(sqlite3) } + finally{ wasm.pstack.restore(stackPos); } } })/*wasm.pstack*/; + Object.defineProperties(wasm.pstack, { /** - sqlite3.wasm.pstack.pointer resolves to the current pstack - position pointer. This value is intended _only_ to be saved - for passing to restore(). Writing to this memory, without - first reserving it via wasm.pstack.alloc() and friends, leads - to undefined results. + Resolves to the current pstack position pointer either as a + Number (32-bit WASM) or BigInt (64-bit WASM). This value is + intended _only_ to be saved for passing to restore(). Writing + to this memory, without first reserving it via + wasm.pstack.alloc() and friends, leads to undefined results. */ pointer: { configurable: false, iterable: true, writeable: false, @@ -1222,18 +1230,20 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( //clearer or would just lead to confusion or misuse is unclear. //set: wasm.exports.sqlite3__wasm_pstack_restore }, + /** - sqlite3.wasm.pstack.quota to the total number of bytes - available in the pstack, including any space which is currently + Resolves to the total number of bytes available in the pstack + allocator, including any space which is currently allocated. This value is a compile-time constant. */ quota: { configurable: false, iterable: true, writeable: false, get: wasm.exports.sqlite3__wasm_pstack_quota }, + /** - sqlite3.wasm.pstack.remaining resolves to the amount of space - remaining in the pstack. + Resolves to the number of bytes remaining in the pstack + allocator. */ remaining: { configurable: false, iterable: true, writeable: false, @@ -1404,7 +1414,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( capi.sqlite3_js_db_export = function(pDb, schema=0){ pDb = wasm.xWrap.testConvertArg('sqlite3*', pDb); if(!pDb) toss3('Invalid sqlite3* argument.'); - if(!wasm.bigIntEnabled) toss3('BigInt64 support is not enabled.'); + if(!wasm.bigIntEnabled) toss3('BigInt support is not enabled.'); const scope = wasm.scopedAllocPush(); let pOut; try{ @@ -2093,9 +2103,9 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( Ideally this function is called as part of the Promise chain which handles the loading and bootstrapping of the API. If not then it must be called by client-level code, which must not use - the library until the returned promise resolves. + the library until the returned Promise resolves. - If called multiple times it will return the same promise on + If called multiple times it will return the same Promise on subsequent calls. The current build setup precludes that possibility, so it's only a hypothetical problem if/when this function ever needs to be invoked by clients. @@ -2164,26 +2174,26 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( sqlite3ApiBootstrap.sqlite3 = sqlite3; return sqlite3; }/*sqlite3ApiBootstrap()*/; + /** - globalThis.sqlite3ApiBootstrap.initializers is an internal detail used by - the various pieces of the sqlite3 API's amalgamation process. It - must not be modified by client code except when plugging such code - into the amalgamation process. + globalThis.sqlite3ApiBootstrap.initializers is an internal detail + used by the various pieces of the sqlite3 API's amalgamation + process. It must not be modified by client code except when plugging + such code into the amalgamation process. Each component of the amalgamation is expected to append a function to this array. When sqlite3ApiBootstrap() is called for the first time, each such function will be called (in their appended order) and passed the sqlite3 namespace object, into which they can install - their features (noting that most will also require that certain - features alread have been installed). At the end of that process, - this array is deleted. + their features. At the end of that process, this array is deleted. - Note that the order of insertion into this array is significant for + The order of insertion into this array is significant for some pieces. e.g. sqlite3.capi and sqlite3.wasm cannot be fully utilized until the whwasmutil.js part is plugged in via sqlite3-api-glue.js. */ globalThis.sqlite3ApiBootstrap.initializers = []; + /** globalThis.sqlite3ApiBootstrap.initializersAsync is an internal detail used by the sqlite3 API's amalgamation process. It must not be @@ -2206,6 +2216,7 @@ globalThis.sqlite3ApiBootstrap.initializers = []; this list. */ globalThis.sqlite3ApiBootstrap.initializersAsync = []; + /** Client code may assign sqlite3ApiBootstrap.defaultConfig an object-type value before calling sqlite3ApiBootstrap() (without @@ -2216,6 +2227,7 @@ globalThis.sqlite3ApiBootstrap.initializersAsync = []; global-scope symbol. */ globalThis.sqlite3ApiBootstrap.defaultConfig = Object.create(null); + /** Placeholder: gets installed by the first call to globalThis.sqlite3ApiBootstrap(). However, it is recommended that the diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js index ded954fe83..57fbe9f16e 100644 --- a/ext/wasm/common/whwasmutil.js +++ b/ext/wasm/common/whwasmutil.js @@ -28,13 +28,9 @@ The primary goal of this function is to replace, where possible, Emscripten-generated glue code with equivalent utility code which can be used in arbitrary WASM environments built with toolchains - other than Emscripten. As of this writing, this code is capable of - acting as a replacement for Emscripten's generated glue code - _except_ that the latter installs handlers for Emscripten-provided - APIs such as its "FS" (virtual filesystem) API. Loading of such - things still requires using Emscripten's glue, but the post-load - utility APIs provided by this code are still usable as replacements - for their Emscripten counterparts. + other than Emscripten. To that end, it populates the given object + with various WASM-specific APIs. These APIs work with both 32- and + 64-bit WASM builds. Forewarning: this API explicitly targets only browser environments. If a given non-browser environment has the capabilities needed for @@ -50,8 +46,9 @@ delete globalThis.WhWasmUtilInstaller; ``` - The `target` object then holds the APIs. It may have certain - properties set to configure it, as documented below. + The `target` object then holds the APIs. The caller may set certain + properties on it, before calling this, to configure it, as + documented below. The global-scope symbol for this function is intended only to provide an easy way to make it available to 3rd-party scripts and @@ -98,9 +95,11 @@ How to install... - Passing an object to this function will install the functionality - into that object. Afterwards, client code "should" delete the global - symbol. + Passing an object to this function will install this library's + functionality into that object. It returns its argument. + + After installation, client code "should" delete this function's + global symbol (if any). This code requires that the target object have the following properties, though they needn't be available until the first time @@ -126,6 +125,12 @@ require that the table be able to grow but it will throw if its `installFunction()` is called and the table cannot grow. + - `functionTable`: WebAssembly.Table object holding the indirect + function call table. If not set then + `exports.__indirect_function_table` is assumed. Achtung: this + property gets replaced by a function with the same name (because + this API used that name before this config option was added). + In order to simplify downstream usage, if `target.exports` is not set when this is called then a property access interceptor (read-only, configurable, enumerable) gets installed as `exports` @@ -167,7 +172,9 @@ - `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 gets set to whatever this code thinks the pointer size - is. Modifying it after this call has no effect. + is. Modifying it after this call has no effect. A reliable + way to get this value is (typeof X()), where X is a function + from target.exports which returns an innocuous pointer. - `pointerSize`: if set, it must be one of 4 or 8 and must correspond to the value of `pointerIR`. If not set, it gets set @@ -180,26 +187,35 @@ After calling this, the pointerIR and pointerSize properties are replaced with a read-only Object member named target.ptr. It - contains the following read-only properties: + contains the following read-only helper methods and properties to + assist in using WASM pointers without having to know what type they + are: - - .size = pointerSize + - `size` = pointerSize - - .ir = pointerIR + - `ir` = pointerIR - - .null = a "null" pointer of type Number or BigInt. + - `null` = a "null" pointer of type Number or BigInt. Equivalent to + one of Number(0) or BigInt(0). This value compares === to + WASM NULL pointers. - - .coerce = a function which behaves like target.asPtrType() + - `coerce(arg)` = equivalent to one of Number(arg) or BigInt(arg||0). - - .add = a substitute for pointer arithmetic (which does not work - in 64-bit builds). Adds up all of its arguments and returns - either a Number or BigInt, depending on this.size. + - `add(...args)` = performs "pointer arithmetic" (`wasmPtr+offset` + does not work in 64-bit builds unless all operands are of type + BigInt). Adds up all of its arguments, accounting for whether + each is a Number of BigInt, and returns either a Number or + BigInt. - - .addn = like .add() but returns its result as a Number. + - `addn(...args)` = like `add()` but always returns its result as a + Number. Equivalent to Number(add(...)). + ------------------------------------------------------------ Design notes: - - It should probably take a config object and return the - target. The current approach seemed better at the time. + - This function should probably take a config object and return the + newly-created (or config-provided) target. The current approach + seemed better at the time. */ globalThis.WhWasmUtilInstaller = function(target){ 'use strict'; @@ -230,19 +246,20 @@ globalThis.WhWasmUtilInstaller = function(target){ toss("Invalid pointerSize:",__ptrSize); } + /** Either BigInt or, if !target.bigIntEnabled, a function which + throws complaining that BigInt is not enabled. */ + const __BigInt = target.bigIntEnabled + ? BigInt + : (v)=>toss("BigInt support is disabled in this build."); + /** - If target.ptr.ir=='i32' then this is equivalent to - Number(v) else it's equivalent to BigInt(v||0). + If target.ptr.ir==='i32' then this is equivalent to + Number(v) else it's equivalent to BigInt(v||0), throwing + if BigInt support is disabled. Why? Because Number(null)===0, but BigInt(null) throws. */ - const __asPtrType = (4===__ptrSize) - ? Number - : (target.bigIntEnabled - ? ((v)=>BigInt(v || 0)) - : toss("Missing BigInt support")); - - target.asPtrType = __asPtrType; + const __asPtrType = (4===__ptrSize) ? Number : (v)=>__BigInt(v||0); /** The number 0 as either type Number or BigInt, depending on @@ -254,7 +271,7 @@ globalThis.WhWasmUtilInstaller = function(target){ Expects any number of numeric arguments, each one of either type Number or BigInt. It sums them up (from an implicit starting point of 0 or 0n) and returns them as a number of the same type - which target.asPtrType() uses. + which target.ptr.coerce() uses. This is a workaround for not being able to mix Number/BigInt in addition/subtraction expressions (which we frequently need for @@ -266,24 +283,35 @@ globalThis.WhWasmUtilInstaller = function(target){ return rc; }; - const __ptr = Object.assign(Object.create(null),{ - coerce: __asPtrType, - add: __ptrAdd, - addn: (4===__ptrIR) ? __ptrAdd : (...args)=>Number(__ptrAdd(...args)) - }); - Object.defineProperty(target, 'ptr', { - enumerable: true, - get: ()=>__ptr, - set: ()=>toss("The ptr property is read-only.") - }); - (function f(name, val){ - Object.defineProperty(__ptr, name, { + /** Set up target.ptr... */ + { + const __ptr = Object.create(null); + Object.defineProperty(target, 'ptr', { enumerable: true, - get: ()=>val, - set: ()=>toss("ptr["+name+"] is read-only.") + get: ()=>__ptr, + set: ()=>toss("The ptr property is read-only.") }); - return f; - })( 'null', __NullPtr )( 'size', __ptrSize )( 'ir', __ptrIR ); + (function f(name, val){ + Object.defineProperty(__ptr, name, { + enumerable: true, + get: ()=>val, + set: ()=>toss("ptr["+name+"] is read-only.") + }); + return f; + })( + 'null', __NullPtr + )( + 'size', __ptrSize + )( + 'ir', __ptrIR + )( + 'coerce', __asPtrType + )( + 'add', __ptrAdd + )( + 'addn', (4===__ptrIR) ? __ptrAdd : (...args)=>Number(__ptrAdd(...args)) + ); + } if(!target.exports){ Object.defineProperty(target, 'exports', { @@ -355,10 +383,14 @@ globalThis.WhWasmUtilInstaller = function(target){ cache.HEAP8 = new Int8Array(b); cache.HEAP8U = new Uint8Array(b); cache.HEAP16 = new Int16Array(b); cache.HEAP16U = new Uint16Array(b); cache.HEAP32 = new Int32Array(b); cache.HEAP32U = new Uint32Array(b); + cache.HEAP32F = new Float32Array(b); cache.HEAP64F = new Float64Array(b); if(target.bigIntEnabled){ - cache.HEAP64 = new BigInt64Array(b); cache.HEAP64U = new BigUint64Array(b); + if( 'undefined'!==typeof BigInt64Array ){ + cache.HEAP64 = new BigInt64Array(b); cache.HEAP64U = new BigUint64Array(b); + }else{ + toss("BigInt support is enabled, but the BigInt64Array type is missing."); + } } - cache.HEAP32F = new Float32Array(b); cache.HEAP64F = new Float64Array(b); cache.heapSize = b.byteLength; return cache; }; @@ -432,17 +464,23 @@ globalThis.WhWasmUtilInstaller = function(target){ "or (if BigInt is enabled) 64."); }; + const __funcTable = target.functionTable; + delete target.functionTable; + /** - Returns the WASM-exported "indirect function table." + Returns the WASM-exported "indirect function table". */ - target.functionTable = function(){ - return target.exports.__indirect_function_table; + target.functionTable = __funcTable + ? ()=>__funcTable + : ()=>target.exports.__indirect_function_table /** -----------------^^^^^ "seems" to be a standardized export name. From Emscripten release notes from 2020-09-10: - Use `__indirect_function_table` as the import name for the table, which is what LLVM does. - */ - }; + + We must delay access to target.exports until after the library + is bootstrapped. + */; /** Given a function pointer, returns the WASM function table entry @@ -467,17 +505,16 @@ globalThis.WhWasmUtilInstaller = function(target){ - Emscripten: `"x..."`, where the first x is a letter representing the result type and subsequent letters represent the argument types. Functions with no arguments have only a single - letter. See below. + letter. - Jaccwabyt: `"x(...)"` where `x` is the letter representing the result type and letters in the parens (if any) represent the - argument types. Functions with no arguments use `x()`. See - below. + argument types. Functions with no arguments use `x()`. Supported letters: - `i` = int32 - - `p` = int32 or int64 ("pointer") + - `p` = int32 or int64 ("pointer"), depending on target.ptr.size - `j` = int64 - `f` = float32 - `d` = float64 @@ -503,15 +540,17 @@ globalThis.WhWasmUtilInstaller = function(target){ call-local functions and superfluous temporary arrays. */ if(!f._){/*static init...*/ f._ = { - // Map of signature letters to type IR values + /* Map of signature letters to type IR values */ sigTypes: Object.assign(Object.create(null),{ i: 'i32', p: __ptrIR, P: __ptrIR, s: __ptrIR, j: 'i64', f: 'f32', d: 'f64' }), - // Map of type IR values to WASM type code values + + /* Map of type IR values to WASM type code values */ typeCodes: Object.assign(Object.create(null),{ f64: 0x7c, f32: 0x7d, i64: 0x7e, i32: 0x7f }), + /** Encodes n, which must be <2^14 (16384), into target array tgt, as a little-endian value, using the given method ('push' or 'unshift'). */ @@ -519,22 +558,29 @@ globalThis.WhWasmUtilInstaller = function(target){ if(n<128) tgt[method](n); else tgt[method]( (n % 128) | 128, n>>7); }, + /** Intentionally-lax pattern for Jaccwabyt-format function pointer signatures, the intent of which is simply to distinguish them from Emscripten-format signatures. The downstream checks are less lax. */ rxJSig: /^(\w)\((\w*)\)$/, + /** Returns the parameter-value part of the given signature string. */ sigParams: (sig)=>{ const m = f._.rxJSig.exec(sig); return m ? m[2] : sig.substr(1); }, + /** Returns the IR value for the given letter or throws if the letter is invalid. */ - letterType: (x)=>f._.sigTypes[x] || toss("Invalid signature letter:",x), + /** Pushes the WASM data type code for the given signature + letter to the given target array. Throws if letter is + invalid. */ + pushSigType: (dest, letter)=>dest.push(f._.typeCodes[f._.letterType(letter)]) + /** Returns an object describing the result type and parameter type(s) of the given function signature, or throws if the signature is invalid. */ @@ -548,11 +594,6 @@ globalThis.WhWasmUtilInstaller = function(target){ } return rc; },************/ - /** Pushes the WASM data type code for the given signature - letter to the given target array. Throws if letter is - invalid. */ - - pushSigType: (dest, letter)=>dest.push(f._.typeCodes[f._.letterType(letter)]) }; }/*static init*/ if('string'===typeof func){ @@ -611,7 +652,7 @@ globalThis.WhWasmUtilInstaller = function(target){ "or (signature,function)."); } const ft = target.functionTable(); - const oldLen = ft.length; + const oldLen = __asPtrType(ft.length); let ptr; while(cache.freeFuncIndexes.length){ ptr = cache.freeFuncIndexes.pop(); @@ -660,8 +701,8 @@ globalThis.WhWasmUtilInstaller = function(target){ available slot of this.functionTable(), and returns the function's index in that table (which acts as a pointer to that function). The returned pointer can be passed to - uninstallFunction() to uninstall it and free up the table slot for - reuse. + uninstallFunction() to uninstall it and free up the table slot + for reuse. If passed (string,function) arguments then it treats the first argument as the signature and second as the function. @@ -672,9 +713,8 @@ globalThis.WhWasmUtilInstaller = function(target){ This function will propagate an exception if WebAssembly.Table.grow() throws or this.jsFuncToWasm() throws. - The former case can happen in an Emscripten-compiled - environment when building without Emscripten's - `-sALLOW_TABLE_GROWTH` flag. + The former case can happen in an Emscripten-compiled environment + when building without Emscripten's `-sALLOW_TABLE_GROWTH` flag. Sidebar: this function differs from Emscripten's addFunction() _primarily_ in that it does not share that function's @@ -796,8 +836,8 @@ globalThis.WhWasmUtilInstaller = function(target){ case 'float': case 'f32': rc = c.HEAP32F[Number(ptr/*tag:64bit*/)>>2]; break; case 'double': case 'f64': rc = Number(c.HEAP64F[Number(ptr/*tag:64bit*/)>>3]); break; case 'i64': - if(target.bigIntEnabled){ - rc = BigInt(c.HEAP64[Number(ptr/*tag:64bit*/)>>3]); + if(c.HEAP64){ + rc = __BigInt(c.HEAP64[Number(ptr/*tag:64bit*/)>>3]); break; } /* fallthru */ @@ -840,7 +880,7 @@ globalThis.WhWasmUtilInstaller = function(target){ case 'double': case 'f64': c.HEAP64F[Number(p/*tag:64bit*/)>>3] = value; continue; case 'i64': if(c.HEAP64){ - c.HEAP64[Number(p/*tag:64bit*/)>>3] = BigInt(value); + c.HEAP64[Number(p/*tag:64bit*/)>>3] = __BigInt(value); continue; } /* fallthru */ @@ -936,9 +976,7 @@ globalThis.WhWasmUtilInstaller = function(target){ isPtr32() or the as-yet-hypothetical isPtr64(), depending on a configuration option. */ - target.isPtr = ('i32'==__ptrIR) - ? target.isPtr32 - : target.isPtr64; + target.isPtr = (4===__ptrSize) ? target.isPtr32 : target.isPtr64; /** Expects ptr to be a pointer into the WASM heap memory which @@ -955,7 +993,7 @@ globalThis.WhWasmUtilInstaller = function(target){ const h = heapWrappers().HEAP8U; let pos = ptr; for( ; h[pos] !== 0; ++pos ){} - return pos - ptr; + return Number(pos - ptr); }; /** Internal helper to use in operations which need to distinguish @@ -1137,31 +1175,6 @@ globalThis.WhWasmUtilInstaller = function(target){ */ target.jstrToUintArray = (str, addNul=false)=>{ return cache.utf8Encoder.encode(addNul ? (str+"\0") : str); - // Or the hard way... - /** Attribution: derived from Emscripten's stringToUTF8Array() */ - //const a = [], max = str.length; - //let i = 0, pos = 0; - //for(; i < max; ++i){ - // let u = str.charCodeAt(i); - // if(u>=0xd800 && u<=0xdfff){ - // u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF); - // } - // if(u<=0x7f) a[pos++] = u; - // else if(u<=0x7ff){ - // a[pos++] = 0xC0 | (u >> 6); - // a[pos++] = 0x80 | (u & 63); - // }else if(u<=0xffff){ - // a[pos++] = 0xe0 | (u >> 12); - // a[pos++] = 0x80 | ((u >> 6) & 63); - // a[pos++] = 0x80 | (u & 63); - // }else{ - // a[pos++] = 0xf0 | (u >> 18); - // a[pos++] = 0x80 | ((u >> 12) & 63); - // a[pos++] = 0x80 | ((u >> 6) & 63); - // a[pos++] = 0x80 | (u & 63); - // } - // } - // return new Uint8Array(a); }; const __affirmAlloc = (obj,funcName)=>{ @@ -1175,19 +1188,17 @@ globalThis.WhWasmUtilInstaller = function(target){ const __allocCStr = function(jstr, returnWithLength, allocator, funcName){ __affirmAlloc(target, funcName); if('string'!==typeof jstr) return null; - if(0){/* older impl, possibly more widely compatible? */ - const n = target.jstrlen(jstr), - ptr = allocator(n+1); - target.jstrcpy(jstr, target.heap8u(), ptr, n+1, true); - return returnWithLength ? [ptr, n] : ptr; - }else{/* newer, (probably) faster and (certainly) simpler impl */ - const u = cache.utf8Encoder.encode(jstr), - ptr = allocator(u.length+1), - heap = heapWrappers().HEAP8U; - //console.warn("ptr =",ptr); + const u = cache.utf8Encoder.encode(jstr), + ptr = allocator(u.length+1); + let toFree = ptr; + try{ + const heap = heapWrappers().HEAP8U; heap.set(u, Number(ptr)); heap[__ptrAdd(ptr, u.length)] = 0; + toFree = __NullPtr; return returnWithLength ? [ptr, u.length] : ptr; + }finally{ + if( toFree ) target.dealloc(toFree); } }; @@ -1328,7 +1339,8 @@ globalThis.WhWasmUtilInstaller = function(target){ */ target.scopedAllocCString = (jstr, returnWithLength=false)=>__allocCStr(jstr, returnWithLength, - target.scopedAlloc, 'scopedAllocCString()'); + target.scopedAlloc, + 'scopedAllocCString()'); // impl for allocMainArgv() and scopedAllocMainArgv(). const __allocMainArgv = function(isScoped, list){ @@ -1520,23 +1532,10 @@ globalThis.WhWasmUtilInstaller = function(target){ /** Scope-local convenience aliases. */ const xArg = cache.xWrap.convert.arg, xResult = cache.xWrap.convert.result; - if(target.bigIntEnabled){ - xArg.set('i64', (i)=>BigInt(i || 0)); - } const __xArgPtr = __asPtrType; - 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. Or, more cryptically, a - function signature mismatch error without much context to track - it down. */ - : (i)=>i|0 - ); xArg + .set('i64', (i)=>__BigInt(i || 0)) + .set('i32', (i)=>i|0) .set('i16', (i)=>((i | 0) & 0xFFFF)) .set('i8', (i)=>((i | 0) & 0xFF)) .set('f32', (i)=>Number(i).valueOf()) @@ -1547,26 +1546,30 @@ globalThis.WhWasmUtilInstaller = function(target){ .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)) .set('void', (v)=>undefined) + .set(undefined, xResult.get('void')) .set('null', (v)=>v) - .set(null, xResult.get('null')); - - { /* Copy xArg[...] handlers to xResult[...] for cases which have - identical semantics. Also add pointer-style variants of those - xArg entries to both xArg and xResult. */ - const copyToResult = ['i8', 'i16', 'i32', 'int', - 'f32', 'float', 'f64', 'double']; - if(target.bigIntEnabled) copyToResult.push('i64'); - const adaptPtr = xArg.get(__ptrIR); - for(const t of copyToResult){ - xArg.set(t+'*', adaptPtr); - xResult.set(t+'*', adaptPtr); - xResult.set(t, (xArg.get(t) || toss("Missing arg converter:",t))); - } + .set(null, xResult.get('null')) + ; + + /* Copy xArg[...] handlers to xResult[...] for cases which have + identical semantics. Also add pointer-style variants of those + xArg entries to both xArg and xResult. */ + for(const t of [ + 'i8', 'i16', 'i32', 'i64', 'int', + 'f32', 'float', 'f64', 'double' + ]){ + xArg.set(t+'*', __xArgPtr); + xResult.set(t+'*', __xArgPtr); + xResult.set( + t, xArg.get(t) + || toss("Maintenance required: missing arg converter for",t) + ); } /** @@ -1587,16 +1590,19 @@ globalThis.WhWasmUtilInstaller = function(target){ backfire? We handle that at the client level in sqlite3 with a custom argument converter. */ - const __xArgString = function(v){ - if('string'===typeof v) return target.scopedAllocCString(v); - return __asPtrType(v); + const __xArgString = (v)=>{ + return ('string'===typeof v) + ? target.scopedAllocCString(v) + : __asPtrType(v); }; + xArg.set('string', __xArgString) .set('utf8', __xArgString) - .set('pointer', __xArgString); - //xArg.set('*', __xArgString); + // (much later: why did we do this?) .set('pointer', __xArgString) + ; - xResult.set('string', (i)=>target.cstrToJs(i)) + xResult + .set('string', (i)=>target.cstrToJs(i)) .set('utf8', xResult.get('string')) .set('string:dealloc', (i)=>{ try { return i ? target.cstrToJs(i) : null } @@ -1705,18 +1711,19 @@ globalThis.WhWasmUtilInstaller = function(target){ - 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 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_ + a bindScope of '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 + in its _wrapping_ function's arguments, and argv is the + _current_ still-being-xWrap()-processed args array. (Got all + that?) When thisFunc(argv,argIndex) is called by xWrap(), all + arguments in argv 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, @@ -2011,12 +2018,14 @@ globalThis.WhWasmUtilInstaller = function(target){ same arity as the being-wrapped function (as defined by its `length` property) and it will throw if that is not the case. Similarly, the created wrapper will throw if passed a differing - argument count. + argument count. The intent of that strictness is to help catch + coding errors in using JS-bound WASM functions earlier rather + than laer. Type names are symbolic names which map the arguments to an adapter function to convert, if needed, the value before passing it on to WASM or to convert a return result from WASM. The list - of built-in names: + of pre-defined names: - `i8`, `i16`, `i32` (args and results): all integer conversions which convert their argument to an integer and truncate it to @@ -2043,8 +2052,8 @@ globalThis.WhWasmUtilInstaller = function(target){ is treated like `*`. - `i64` (args and results): passes the value to BigInt() to - convert it to an int64. Only available if bigIntEnabled is - true. + convert it to an int64. This conversion will if bigIntEnabled + is falsy. - `f32` (`float`), `f64` (`double`) (args and results): pass their argument to Number(). i.e. the adapter does not currently @@ -2151,12 +2160,13 @@ globalThis.WhWasmUtilInstaller = function(target){ const xf = fIsFunc ? fArg : target.xGet(fArg); if(fIsFunc) fArg = xf.name || 'unnamed function'; if(argTypes.length!==xf.length) __argcMismatch(fArg, xf.length); - if((null===resultType) && 0===xf.length){ + if( 0===xf.length + && (null===resultType || 'null'===resultType) ){ /* Func taking no args with an as-is return. We don't need a wrapper. */ return xf; } /*Verify the arg type conversions are valid...*/; - if(undefined!==resultType && null!==resultType) __xResultAdapterCheck(resultType); + __xResultAdapterCheck(resultType); for(const t of argTypes){ if(t instanceof AbstractArgAdapter) xArg.set(t, (...args)=>t.convertArg(...args)); else __xArgAdapterCheck(t); diff --git a/manifest b/manifest index ef78a3d897..70ae974f36 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Rename\swasm\sconfig\sentry\spointerSizeof\sto\spointerSize\sfor\sconsistency\swith\swasm.ptr.size. -D 2025-09-21T14:25:29.590 +C Generic\scleanups\sand\ssimplifications\sin\sJS\scode. +D 2025-09-21T17:55:23.130 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -578,7 +578,7 @@ F ext/session/sqlite3session.c 9cd47bfefb23c114b7a5d9ee5822d941398902f30516bf0dd F ext/session/sqlite3session.h 7404723606074fcb2afdc6b72c206072cdb2b7d8ba097ca1559174a80bc26f7a F ext/session/test_session.c 8766b5973a6323934cb51248f621c3dc87ad2a98f023c3cc280d79e7d78d36fb F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c -F ext/wasm/GNUmakefile 66dcdb324e598d3acb995936779b0d6ab21eaccf9cbad15c2355bcaca83cef5a +F ext/wasm/GNUmakefile 2ec39c303c9d50fd25db97a986565c09cbbea7b08e61977b1b5c8a079adddc5e F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a F ext/wasm/README.md 66ace67ae98a45e4116f2ca5425b716887bcee4d64febee804ff6398e1ae9ec7 F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff @@ -591,15 +591,15 @@ F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-extras cb4fa8842c875b6ee99381523792975 F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see fb29e62082a658f0d81102488414d422c393c4b20cc2f685b216bc566237957b F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287 F ext/wasm/api/README.md 7f029c5fe83b3493931d2fb915e2febd3536267d538a56408a6fef284ea38d29 -F ext/wasm/api/extern-post-js.c-pp.js 88300aaf4cdb516f53ca3448dc19514a4182921ad9744e7b8fb8c2e3590ebb5e +F ext/wasm/api/extern-post-js.c-pp.js 9c3760a5991bf46ec628d713e11db71230f07c079bfe0f05ef30177a8e025385 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 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 a9f94c70f377c22f36679ebe07c6d647c2217a9fb4cc61dcf5634258a590a219 +F ext/wasm/api/sqlite3-api-cleanup.js d4f1a5e665afaf84015f6ef0ddd766f638cb28501c4569b1d4b527c4b5a2b9a4 F ext/wasm/api/sqlite3-api-glue.c-pp.js 5fb52fb190519e2d9cd8507c5f6c7a9827c80aa254f16ec682e1d2c26ccd0fbd F ext/wasm/api/sqlite3-api-oo1.c-pp.js 831ce373495f6a5d9230f31a1e09e8995e317828926e736d58c9e7091c6b1d07 -F ext/wasm/api/sqlite3-api-prologue.js c91e3bf9994050faa119bd13e18ff5d9eee006d30ea970f282ef39059451f6eb +F ext/wasm/api/sqlite3-api-prologue.js bdf8e553c2142916fd7a2382e1becfed7a5755da95f585f632336634e5728448 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 705cd1876f454b3fbc4d6880e5447f325fbf85558f9215ba058805dd8e6656c6 +F ext/wasm/common/whwasmutil.js a2c7482ee0c07087a4a6878830a38acefacb0ee4399fab25073b8a3ce99cfacd F ext/wasm/config.make.in c424ae1cc3c89274520ad312509d36c4daa34a3fce5d0c688e5f8f4365e1049a F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508 @@ -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 8ac12e1f5144380d4ecc8b27a1f62dcda0e5a86409ae7149f62c33caeea19a23 -R 44fa8ad18d4fc24a2afae6ef2b8a9f7f +P 2cd8ba740f9b14dc1408b62632c603076b070dc412bf7cbfb3b525f0c4912371 +R 25f70763d7952a028a3fd18d711e95fa U stephan -Z 6539d526d80f87ce2c0b68bf1d9a5a52 +Z ac93091de705f89e3c49ed92d286b8f4 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c76dd6e2b4..875a32eb95 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2cd8ba740f9b14dc1408b62632c603076b070dc412bf7cbfb3b525f0c4912371 +074cf4e6c1775900204bb0d920111ee19601d5c63690e79e988e7fe6b040a647