1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-10-24 09:53:10 +03:00

Generic cleanups and simplifications in JS code.

FossilOrigin-Name: 074cf4e6c1775900204bb0d920111ee19601d5c63690e79e988e7fe6b040a647
This commit is contained in:
stephan
2025-09-21 17:55:23 +00:00
parent 128ae8ea3f
commit 5b71447e8e
7 changed files with 292 additions and 275 deletions

View File

@@ -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
#

View File

@@ -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();

View File

@@ -19,34 +19,29 @@
handler.
*/
'use strict';
if('undefined' !== typeof Module){ // presumably an Emscripten build
if( 'undefined' !== typeof Module ){ // presumably an Emscripten build
try{
/**
The WASM-environment-specific configuration pieces
for sqlite3ApiBootstrap().
The WASM-environment-dependent configuration 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 */
}
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");
}
SABC.wasmPtrIR = 'number'===(typeof SABC.exports.sqlite3_libversion())
? 'i32' :'i64';
/**
For current (2022-08-22) purposes, automatically call
@@ -59,19 +54,16 @@ if('undefined' !== typeof Module){ // presumably an Emscripten build
able to provide the necessary configuration state.
*/
//console.warn("globalThis.sqlite3ApiConfig = ",globalThis.sqlite3ApiConfig);
try{
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. */;
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",

View File

@@ -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

View File

@@ -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,11 +283,9 @@ 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))
});
/** Set up target.ptr... */
{
const __ptr = Object.create(null);
Object.defineProperty(target, 'ptr', {
enumerable: true,
get: ()=>__ptr,
@@ -283,7 +298,20 @@ globalThis.WhWasmUtilInstaller = function(target){
set: ()=>toss("ptr["+name+"] is read-only.")
});
return f;
})( 'null', __NullPtr )( 'size', __ptrSize )( 'ir', __ptrIR );
})(
'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);
if(target.bigIntEnabled){
cache.HEAP64 = new BigInt64Array(b); cache.HEAP64U = new BigUint64Array(b);
}
cache.HEAP32F = new Float32Array(b); cache.HEAP64F = new Float64Array(b);
if(target.bigIntEnabled){
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.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);
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'));
.set(null, xResult.get('null'))
;
{ /* Copy xArg[...] handlers to xResult[...] for cases which have
/* 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)));
}
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);

View File

@@ -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.

View File

@@ -1 +1 @@
2cd8ba740f9b14dc1408b62632c603076b070dc412bf7cbfb3b525f0c4912371
074cf4e6c1775900204bb0d920111ee19601d5c63690e79e988e7fe6b040a647