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 # disables certain features if BigInt is not enabled and such builds
# _are not tested_ on any regular basis. # _are not tested_ on any regular basis.
emcc.WASM_BIGINT ?= 1 emcc.WASM_BIGINT ?= 1
emcc.MEMORY64 ?= 1 emcc.MEMORY64 ?= 0
######################################################################## ########################################################################
# https://emscripten.org/docs/tools_reference/settings_reference.html#memory64 # https://emscripten.org/docs/tools_reference/settings_reference.html#memory64
# #

View File

@@ -68,7 +68,10 @@ const toExportForESM =
const s = EmscriptenModule.sqlite3; const s = EmscriptenModule.sqlite3;
s.scriptInfo = initModuleState; s.scriptInfo = initModuleState;
//console.warn("sqlite3.scriptInfo =",s.scriptInfo); //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; const f = s.asyncPostInit;
delete s.asyncPostInit; delete s.asyncPostInit;
const rv = f(); const rv = f();

View File

@@ -19,59 +19,51 @@
handler. handler.
*/ */
'use strict'; 'use strict';
if('undefined' !== typeof Module){ // presumably an Emscripten build 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 */
}
);
/** 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");
}
/**
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{ 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. */
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);
Module.sqlite3 = globalThis.sqlite3ApiBootstrap(SABC) Module.sqlite3 = globalThis.sqlite3ApiBootstrap(SABC)
/* Our customized sqlite3InitModule() in extern-post-js.js needs /* Our customized sqlite3InitModule() in extern-post-js.js needs
this to be able to pass the sqlite3 object off to the this to be able to pass the sqlite3 object off to the
client. */; client. */;
delete globalThis.sqlite3ApiBootstrap;
delete globalThis.sqlite3ApiConfig;
}catch(e){ }catch(e){
console.error("sqlite3ApiBootstrap() error:",e); console.error("sqlite3ApiBootstrap() error:",e);
throw e; throw e;
}finally{
delete globalThis.sqlite3ApiBootstrap;
delete globalThis.sqlite3ApiConfig;
} }
}else{ }else{
console.warn("This is not running in an Emscripten module context, so", console.warn("This is not running in an Emscripten module context, so",
"globalThis.sqlite3ApiBootstrap() is _not_ being called due to lack", "globalThis.sqlite3ApiBootstrap() is _not_ being called due to lack",

View File

@@ -49,8 +49,8 @@
- `exports`[^1]: the "exports" object for the current WASM - `exports`[^1]: the "exports" object for the current WASM
environment. In an Emscripten-based build, this should be set to environment. In an Emscripten-based build, this should be set to
`Module['asm']` (versions <=3.1.43) or `wasmExports` (versions `Module['asm']` (versions <=3.1.43) or `Module['wasmExports']`
>=3.1.44). (versions >=3.1.44).
- `memory`[^1]: optional WebAssembly.Memory object, defaulting to - `memory`[^1]: optional WebAssembly.Memory object, defaulting to
`exports.memory`. In Emscripten environments this should be set `exports.memory`. In Emscripten environments this should be set
@@ -58,6 +58,10 @@
left undefined/falsy to default to `exports.memory` when using left undefined/falsy to default to `exports.memory` when using
WASM-exported memory. 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 - `bigIntEnabled`: true if BigInt support is enabled. Defaults to
true if `globalThis.BigInt64Array` is available, else false. Some APIs true if `globalThis.BigInt64Array` is available, else false. Some APIs
will throw exceptions if called without BigInt support, as BigInt 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 // If any of these config options are functions, replace them with
// the result of calling that function. They must not be async. // the result of calling that function. They must not be async.
'exports', 'memory', 'wasmfsOpfsDir' 'exports', 'memory', 'functionTable', 'wasmfsOpfsDir'
].forEach((k)=>{ ].forEach((k)=>{
if('function' === typeof config[k]){ if('function' === typeof config[k]){
config[k] = config[k](); config[k] = config[k]();
@@ -851,19 +855,14 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
environment via whwashutil.js. environment via whwashutil.js.
*/ */
Object.assign(wasm, { 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 The WASM IR (Intermediate Representation) value for
pointer-type values. It MUST refer to a value type of the pointer-type values. If set then it MUST be one of 'i32' or
size described by this.pointerSize. 'i64' (else an exception will be thrown). If it's not set, it
will default to 'i32'.
*/ */
pointerIR: config.wasmPtrIR, pointerIR: config.wasmPtrIR,
/** /**
True if BigInt support was enabled via (e.g.) the True if BigInt support was enabled via (e.g.) the
Emscripten -sWASM_BIGINT flag, else false. When Emscripten -sWASM_BIGINT flag, else false. When
@@ -872,6 +871,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
impedance mismatches. impedance mismatches.
*/ */
bigIntEnabled: !!config.bigIntEnabled, bigIntEnabled: !!config.bigIntEnabled,
/** /**
The symbols exported by the WASM environment. The symbols exported by the WASM environment.
*/ */
@@ -890,6 +890,12 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
"in either config.exports.memory (exported)", "in either config.exports.memory (exported)",
"or config.memory (imported)."), "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 The API's primary point of access to the WASM-side memory
allocator. Works like sqlite3_malloc() but throws a 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. catch exceptions and convert them to appropriate error codes.
For cases where non-throwing allocation is required, use For cases where non-throwing allocation is required, use
this.alloc.impl(), which is direct binding of the this.alloc.impl(), which is the unadulterated WASM-exported
underlying C-level allocator. counterpart of this wrapper.
Design note: this function is not named "malloc" primarily Design note: this function is not named "malloc" primarily
because Emscripten uses that name and we wanted to avoid any because Emscripten uses that name and we wanted to avoid any
@@ -971,10 +977,9 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
srcTypedArray = new Uint8Array(srcTypedArray); srcTypedArray = new Uint8Array(srcTypedArray);
} }
affirmBindableTypedArray(srcTypedArray); affirmBindableTypedArray(srcTypedArray);
const heap = wasm.heapForSize(srcTypedArray.constructor);
const pRet = wasm.alloc(srcTypedArray.byteLength || 1); const pRet = wasm.alloc(srcTypedArray.byteLength || 1);
wasm.heapForSize(srcTypedArray.constructor).set( heap.set(srcTypedArray.byteLength ? srcTypedArray : [0], Number(pRet));
srcTypedArray.byteLength ? srcTypedArray : [0], Number(pRet)
);
return pRet; return pRet;
}; };
@@ -1045,7 +1050,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
rv[1] = m ? (f._rxInt.test(m[2]) ? +m[2] : m[2]) : true; 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; let i = 0, k;
while((k = capi.sqlite3_compileoption_get(i++))){ while((k = capi.sqlite3_compileoption_get(i++))){
f._opt(k,ov); f._opt(k,ov);
@@ -1053,7 +1058,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
} }
return f._result = rc; return f._result = rc;
}else if(Array.isArray(optName)){ }else if(Array.isArray(optName)){
const rc = {}; const rc = Object.create(null);
optName.forEach((v)=>{ optName.forEach((v)=>{
rc[v] = capi.sqlite3_compileoption_used(v); rc[v] = capi.sqlite3_compileoption_used(v);
}); });
@@ -1116,6 +1121,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
environment if passed an illegal value. environment if passed an illegal value.
*/ */
restore: wasm.exports.sqlite3__wasm_pstack_restore, restore: wasm.exports.sqlite3__wasm_pstack_restore,
/** /**
Attempts to allocate the given number of bytes from the Attempts to allocate the given number of bytes from the
pstack. On success, it zeroes out a block of memory of 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, || WasmAllocError.toss("Could not allocate",n,
"bytes from the pstack."); "bytes from the pstack.");
}, },
/** /**
alloc()'s n chunks, each sz bytes, as a single memory block and alloc()'s n chunks, each sz bytes, as a single memory block and
returns the addresses as an array of n element, each holding returns the addresses as an array of n element, each holding
@@ -1153,7 +1160,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
Example: 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){ 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)); for(; i < n; ++i, offset += sz) rc.push(wasm.ptr.add(mem, offset));
return rc; return rc;
}, },
/** /**
A convenience wrapper for allocChunks() which sizes each chunk A convenience wrapper for allocChunks() which sizes each chunk
as either 8 bytes (safePtrSize is truthy) or wasm.ptr.size (if as either 8 bytes (safePtrSize is truthy) or wasm.ptr.size (if
@@ -1201,19 +1209,19 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
*/ */
call: function(f){ call: function(f){
const stackPos = wasm.pstack.pointer; const stackPos = wasm.pstack.pointer;
try{ return f(sqlite3) } finally{ try{ return f(sqlite3) }
wasm.pstack.restore(stackPos); finally{ wasm.pstack.restore(stackPos); }
}
} }
})/*wasm.pstack*/; })/*wasm.pstack*/;
Object.defineProperties(wasm.pstack, { Object.defineProperties(wasm.pstack, {
/** /**
sqlite3.wasm.pstack.pointer resolves to the current pstack Resolves to the current pstack position pointer either as a
position pointer. This value is intended _only_ to be saved Number (32-bit WASM) or BigInt (64-bit WASM). This value is
for passing to restore(). Writing to this memory, without intended _only_ to be saved for passing to restore(). Writing
first reserving it via wasm.pstack.alloc() and friends, leads to this memory, without first reserving it via
to undefined results. wasm.pstack.alloc() and friends, leads to undefined results.
*/ */
pointer: { pointer: {
configurable: false, iterable: true, writeable: false, 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. //clearer or would just lead to confusion or misuse is unclear.
//set: wasm.exports.sqlite3__wasm_pstack_restore //set: wasm.exports.sqlite3__wasm_pstack_restore
}, },
/** /**
sqlite3.wasm.pstack.quota to the total number of bytes Resolves to the total number of bytes available in the pstack
available in the pstack, including any space which is currently allocator, including any space which is currently
allocated. This value is a compile-time constant. allocated. This value is a compile-time constant.
*/ */
quota: { quota: {
configurable: false, iterable: true, writeable: false, configurable: false, iterable: true, writeable: false,
get: wasm.exports.sqlite3__wasm_pstack_quota get: wasm.exports.sqlite3__wasm_pstack_quota
}, },
/** /**
sqlite3.wasm.pstack.remaining resolves to the amount of space Resolves to the number of bytes remaining in the pstack
remaining in the pstack. allocator.
*/ */
remaining: { remaining: {
configurable: false, iterable: true, writeable: false, configurable: false, iterable: true, writeable: false,
@@ -1404,7 +1414,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
capi.sqlite3_js_db_export = function(pDb, schema=0){ capi.sqlite3_js_db_export = function(pDb, schema=0){
pDb = wasm.xWrap.testConvertArg('sqlite3*', pDb); pDb = wasm.xWrap.testConvertArg('sqlite3*', pDb);
if(!pDb) toss3('Invalid sqlite3* argument.'); 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(); const scope = wasm.scopedAllocPush();
let pOut; let pOut;
try{ try{
@@ -2093,9 +2103,9 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
Ideally this function is called as part of the Promise chain Ideally this function is called as part of the Promise chain
which handles the loading and bootstrapping of the API. If not which handles the loading and bootstrapping of the API. If not
then it must be called by client-level code, which must not use 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 subsequent calls. The current build setup precludes that
possibility, so it's only a hypothetical problem if/when this possibility, so it's only a hypothetical problem if/when this
function ever needs to be invoked by clients. function ever needs to be invoked by clients.
@@ -2164,26 +2174,26 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
sqlite3ApiBootstrap.sqlite3 = sqlite3; sqlite3ApiBootstrap.sqlite3 = sqlite3;
return sqlite3; return sqlite3;
}/*sqlite3ApiBootstrap()*/; }/*sqlite3ApiBootstrap()*/;
/** /**
globalThis.sqlite3ApiBootstrap.initializers is an internal detail used by globalThis.sqlite3ApiBootstrap.initializers is an internal detail
the various pieces of the sqlite3 API's amalgamation process. It used by the various pieces of the sqlite3 API's amalgamation
must not be modified by client code except when plugging such code process. It must not be modified by client code except when plugging
into the amalgamation process. such code into the amalgamation process.
Each component of the amalgamation is expected to append a function Each component of the amalgamation is expected to append a function
to this array. When sqlite3ApiBootstrap() is called for the first to this array. When sqlite3ApiBootstrap() is called for the first
time, each such function will be called (in their appended order) time, each such function will be called (in their appended order)
and passed the sqlite3 namespace object, into which they can install and passed the sqlite3 namespace object, into which they can install
their features (noting that most will also require that certain their features. At the end of that process, this array is deleted.
features alread have been installed). 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 some pieces. e.g. sqlite3.capi and sqlite3.wasm cannot be fully
utilized until the whwasmutil.js part is plugged in via utilized until the whwasmutil.js part is plugged in via
sqlite3-api-glue.js. sqlite3-api-glue.js.
*/ */
globalThis.sqlite3ApiBootstrap.initializers = []; globalThis.sqlite3ApiBootstrap.initializers = [];
/** /**
globalThis.sqlite3ApiBootstrap.initializersAsync is an internal detail globalThis.sqlite3ApiBootstrap.initializersAsync is an internal detail
used by the sqlite3 API's amalgamation process. It must not be used by the sqlite3 API's amalgamation process. It must not be
@@ -2206,6 +2216,7 @@ globalThis.sqlite3ApiBootstrap.initializers = [];
this list. this list.
*/ */
globalThis.sqlite3ApiBootstrap.initializersAsync = []; globalThis.sqlite3ApiBootstrap.initializersAsync = [];
/** /**
Client code may assign sqlite3ApiBootstrap.defaultConfig an Client code may assign sqlite3ApiBootstrap.defaultConfig an
object-type value before calling sqlite3ApiBootstrap() (without object-type value before calling sqlite3ApiBootstrap() (without
@@ -2216,6 +2227,7 @@ globalThis.sqlite3ApiBootstrap.initializersAsync = [];
global-scope symbol. global-scope symbol.
*/ */
globalThis.sqlite3ApiBootstrap.defaultConfig = Object.create(null); globalThis.sqlite3ApiBootstrap.defaultConfig = Object.create(null);
/** /**
Placeholder: gets installed by the first call to Placeholder: gets installed by the first call to
globalThis.sqlite3ApiBootstrap(). However, it is recommended that the 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, The primary goal of this function is to replace, where possible,
Emscripten-generated glue code with equivalent utility code which Emscripten-generated glue code with equivalent utility code which
can be used in arbitrary WASM environments built with toolchains can be used in arbitrary WASM environments built with toolchains
other than Emscripten. As of this writing, this code is capable of other than Emscripten. To that end, it populates the given object
acting as a replacement for Emscripten's generated glue code with various WASM-specific APIs. These APIs work with both 32- and
_except_ that the latter installs handlers for Emscripten-provided 64-bit WASM builds.
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.
Forewarning: this API explicitly targets only browser environments. Forewarning: this API explicitly targets only browser environments.
If a given non-browser environment has the capabilities needed for If a given non-browser environment has the capabilities needed for
@@ -50,8 +46,9 @@
delete globalThis.WhWasmUtilInstaller; delete globalThis.WhWasmUtilInstaller;
``` ```
The `target` object then holds the APIs. It may have certain The `target` object then holds the APIs. The caller may set certain
properties set to configure it, as documented below. properties on it, before calling this, to configure it, as
documented below.
The global-scope symbol for this function is intended only to The global-scope symbol for this function is intended only to
provide an easy way to make it available to 3rd-party scripts and provide an easy way to make it available to 3rd-party scripts and
@@ -98,9 +95,11 @@
How to install... How to install...
Passing an object to this function will install the functionality Passing an object to this function will install this library's
into that object. Afterwards, client code "should" delete the global functionality into that object. It returns its argument.
symbol.
After installation, client code "should" delete this function's
global symbol (if any).
This code requires that the target object have the following This code requires that the target object have the following
properties, though they needn't be available until the first time 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 require that the table be able to grow but it will throw if its
`installFunction()` is called and the table cannot grow. `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 In order to simplify downstream usage, if `target.exports` is not
set when this is called then a property access interceptor set when this is called then a property access interceptor
(read-only, configurable, enumerable) gets installed as `exports` (read-only, configurable, enumerable) gets installed as `exports`
@@ -167,7 +172,9 @@
- `pointerIR`: an IR-format string for the WASM environment's - `pointerIR`: an IR-format string for the WASM environment's
pointer size. If set it must be either 'i32' or 'i64'. If not 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 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 - `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 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 After calling this, the pointerIR and pointerSize properties are
replaced with a read-only Object member named target.ptr. It 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 - `add(...args)` = performs "pointer arithmetic" (`wasmPtr+offset`
in 64-bit builds). Adds up all of its arguments and returns does not work in 64-bit builds unless all operands are of type
either a Number or BigInt, depending on this.size. 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: Design notes:
- It should probably take a config object and return the - This function should probably take a config object and return the
target. The current approach seemed better at the time. newly-created (or config-provided) target. The current approach
seemed better at the time.
*/ */
globalThis.WhWasmUtilInstaller = function(target){ globalThis.WhWasmUtilInstaller = function(target){
'use strict'; 'use strict';
@@ -230,19 +246,20 @@ globalThis.WhWasmUtilInstaller = function(target){
toss("Invalid pointerSize:",__ptrSize); 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 If target.ptr.ir==='i32' then this is equivalent to
Number(v) else it's equivalent to BigInt(v||0). 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. Why? Because Number(null)===0, but BigInt(null) throws.
*/ */
const __asPtrType = (4===__ptrSize) const __asPtrType = (4===__ptrSize) ? Number : (v)=>__BigInt(v||0);
? 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 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 Expects any number of numeric arguments, each one of either type
Number or BigInt. It sums them up (from an implicit starting 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 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 This is a workaround for not being able to mix Number/BigInt in
addition/subtraction expressions (which we frequently need for addition/subtraction expressions (which we frequently need for
@@ -266,24 +283,35 @@ globalThis.WhWasmUtilInstaller = function(target){
return rc; return rc;
}; };
const __ptr = Object.assign(Object.create(null),{ /** Set up target.ptr... */
coerce: __asPtrType, {
add: __ptrAdd, const __ptr = Object.create(null);
addn: (4===__ptrIR) ? __ptrAdd : (...args)=>Number(__ptrAdd(...args)) Object.defineProperty(target, 'ptr', {
});
Object.defineProperty(target, 'ptr', {
enumerable: true,
get: ()=>__ptr,
set: ()=>toss("The ptr property is read-only.")
});
(function f(name, val){
Object.defineProperty(__ptr, name, {
enumerable: true, enumerable: true,
get: ()=>val, get: ()=>__ptr,
set: ()=>toss("ptr["+name+"] is read-only.") set: ()=>toss("The ptr property is read-only.")
}); });
return f; (function f(name, val){
})( 'null', __NullPtr )( 'size', __ptrSize )( 'ir', __ptrIR ); 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){ if(!target.exports){
Object.defineProperty(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.HEAP8 = new Int8Array(b); cache.HEAP8U = new Uint8Array(b);
cache.HEAP16 = new Int16Array(b); cache.HEAP16U = new Uint16Array(b); cache.HEAP16 = new Int16Array(b); cache.HEAP16U = new Uint16Array(b);
cache.HEAP32 = new Int32Array(b); cache.HEAP32U = new Uint32Array(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); 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; cache.heapSize = b.byteLength;
return cache; return cache;
}; };
@@ -432,17 +464,23 @@ globalThis.WhWasmUtilInstaller = function(target){
"or (if BigInt is enabled) 64."); "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(){ target.functionTable = __funcTable
return target.exports.__indirect_function_table; ? ()=>__funcTable
: ()=>target.exports.__indirect_function_table
/** -----------------^^^^^ "seems" to be a standardized export name. /** -----------------^^^^^ "seems" to be a standardized export name.
From Emscripten release notes from 2020-09-10: From Emscripten release notes from 2020-09-10:
- Use `__indirect_function_table` as the import name for the - Use `__indirect_function_table` as the import name for the
table, which is what LLVM does. 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 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 - Emscripten: `"x..."`, where the first x is a letter representing
the result type and subsequent letters represent the argument the result type and subsequent letters represent the argument
types. Functions with no arguments have only a single types. Functions with no arguments have only a single
letter. See below. letter.
- Jaccwabyt: `"x(...)"` where `x` is the letter representing the - Jaccwabyt: `"x(...)"` where `x` is the letter representing the
result type and letters in the parens (if any) represent the result type and letters in the parens (if any) represent the
argument types. Functions with no arguments use `x()`. See argument types. Functions with no arguments use `x()`.
below.
Supported letters: Supported letters:
- `i` = int32 - `i` = int32
- `p` = int32 or int64 ("pointer") - `p` = int32 or int64 ("pointer"), depending on target.ptr.size
- `j` = int64 - `j` = int64
- `f` = float32 - `f` = float32
- `d` = float64 - `d` = float64
@@ -503,15 +540,17 @@ globalThis.WhWasmUtilInstaller = function(target){
call-local functions and superfluous temporary arrays. */ call-local functions and superfluous temporary arrays. */
if(!f._){/*static init...*/ if(!f._){/*static init...*/
f._ = { f._ = {
// Map of signature letters to type IR values /* Map of signature letters to type IR values */
sigTypes: Object.assign(Object.create(null),{ sigTypes: Object.assign(Object.create(null),{
i: 'i32', p: __ptrIR, P: __ptrIR, s: __ptrIR, i: 'i32', p: __ptrIR, P: __ptrIR, s: __ptrIR,
j: 'i64', f: 'f32', d: 'f64' 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),{ typeCodes: Object.assign(Object.create(null),{
f64: 0x7c, f32: 0x7d, i64: 0x7e, i32: 0x7f f64: 0x7c, f32: 0x7d, i64: 0x7e, i32: 0x7f
}), }),
/** Encodes n, which must be <2^14 (16384), into target array /** Encodes n, which must be <2^14 (16384), into target array
tgt, as a little-endian value, using the given method tgt, as a little-endian value, using the given method
('push' or 'unshift'). */ ('push' or 'unshift'). */
@@ -519,22 +558,29 @@ globalThis.WhWasmUtilInstaller = function(target){
if(n<128) tgt[method](n); if(n<128) tgt[method](n);
else tgt[method]( (n % 128) | 128, n>>7); else tgt[method]( (n % 128) | 128, n>>7);
}, },
/** Intentionally-lax pattern for Jaccwabyt-format function /** Intentionally-lax pattern for Jaccwabyt-format function
pointer signatures, the intent of which is simply to pointer signatures, the intent of which is simply to
distinguish them from Emscripten-format signatures. The distinguish them from Emscripten-format signatures. The
downstream checks are less lax. */ downstream checks are less lax. */
rxJSig: /^(\w)\((\w*)\)$/, rxJSig: /^(\w)\((\w*)\)$/,
/** Returns the parameter-value part of the given signature /** Returns the parameter-value part of the given signature
string. */ string. */
sigParams: (sig)=>{ sigParams: (sig)=>{
const m = f._.rxJSig.exec(sig); const m = f._.rxJSig.exec(sig);
return m ? m[2] : sig.substr(1); return m ? m[2] : sig.substr(1);
}, },
/** Returns the IR value for the given letter or throws /** Returns the IR value for the given letter or throws
if the letter is invalid. */ if the letter is invalid. */
letterType: (x)=>f._.sigTypes[x] || toss("Invalid signature letter:",x), 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 /** Returns an object describing the result type and parameter
type(s) of the given function signature, or throws if the type(s) of the given function signature, or throws if the
signature is invalid. */ signature is invalid. */
@@ -548,11 +594,6 @@ globalThis.WhWasmUtilInstaller = function(target){
} }
return rc; 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*/ }/*static init*/
if('string'===typeof func){ if('string'===typeof func){
@@ -611,7 +652,7 @@ globalThis.WhWasmUtilInstaller = function(target){
"or (signature,function)."); "or (signature,function).");
} }
const ft = target.functionTable(); const ft = target.functionTable();
const oldLen = ft.length; const oldLen = __asPtrType(ft.length);
let ptr; let ptr;
while(cache.freeFuncIndexes.length){ while(cache.freeFuncIndexes.length){
ptr = cache.freeFuncIndexes.pop(); ptr = cache.freeFuncIndexes.pop();
@@ -660,8 +701,8 @@ globalThis.WhWasmUtilInstaller = function(target){
available slot of this.functionTable(), and returns the available slot of this.functionTable(), and returns the
function's index in that table (which acts as a pointer to that function's index in that table (which acts as a pointer to that
function). The returned pointer can be passed to function). The returned pointer can be passed to
uninstallFunction() to uninstall it and free up the table slot for uninstallFunction() to uninstall it and free up the table slot
reuse. for reuse.
If passed (string,function) arguments then it treats the first If passed (string,function) arguments then it treats the first
argument as the signature and second as the function. argument as the signature and second as the function.
@@ -672,9 +713,8 @@ globalThis.WhWasmUtilInstaller = function(target){
This function will propagate an exception if This function will propagate an exception if
WebAssembly.Table.grow() throws or this.jsFuncToWasm() throws. WebAssembly.Table.grow() throws or this.jsFuncToWasm() throws.
The former case can happen in an Emscripten-compiled The former case can happen in an Emscripten-compiled environment
environment when building without Emscripten's when building without Emscripten's `-sALLOW_TABLE_GROWTH` flag.
`-sALLOW_TABLE_GROWTH` flag.
Sidebar: this function differs from Emscripten's addFunction() Sidebar: this function differs from Emscripten's addFunction()
_primarily_ in that it does not share that function's _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 '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 'double': case 'f64': rc = Number(c.HEAP64F[Number(ptr/*tag:64bit*/)>>3]); break;
case 'i64': case 'i64':
if(target.bigIntEnabled){ if(c.HEAP64){
rc = BigInt(c.HEAP64[Number(ptr/*tag:64bit*/)>>3]); rc = __BigInt(c.HEAP64[Number(ptr/*tag:64bit*/)>>3]);
break; break;
} }
/* fallthru */ /* fallthru */
@@ -840,7 +880,7 @@ globalThis.WhWasmUtilInstaller = function(target){
case 'double': case 'f64': c.HEAP64F[Number(p/*tag:64bit*/)>>3] = value; continue; case 'double': case 'f64': c.HEAP64F[Number(p/*tag:64bit*/)>>3] = value; continue;
case 'i64': case 'i64':
if(c.HEAP64){ if(c.HEAP64){
c.HEAP64[Number(p/*tag:64bit*/)>>3] = BigInt(value); c.HEAP64[Number(p/*tag:64bit*/)>>3] = __BigInt(value);
continue; continue;
} }
/* fallthru */ /* fallthru */
@@ -936,9 +976,7 @@ globalThis.WhWasmUtilInstaller = function(target){
isPtr32() or the as-yet-hypothetical isPtr64(), depending on a isPtr32() or the as-yet-hypothetical isPtr64(), depending on a
configuration option. configuration option.
*/ */
target.isPtr = ('i32'==__ptrIR) target.isPtr = (4===__ptrSize) ? target.isPtr32 : target.isPtr64;
? target.isPtr32
: target.isPtr64;
/** /**
Expects ptr to be a pointer into the WASM heap memory which Expects ptr to be a pointer into the WASM heap memory which
@@ -955,7 +993,7 @@ globalThis.WhWasmUtilInstaller = function(target){
const h = heapWrappers().HEAP8U; const h = heapWrappers().HEAP8U;
let pos = ptr; let pos = ptr;
for( ; h[pos] !== 0; ++pos ){} for( ; h[pos] !== 0; ++pos ){}
return pos - ptr; return Number(pos - ptr);
}; };
/** Internal helper to use in operations which need to distinguish /** Internal helper to use in operations which need to distinguish
@@ -1137,31 +1175,6 @@ globalThis.WhWasmUtilInstaller = function(target){
*/ */
target.jstrToUintArray = (str, addNul=false)=>{ target.jstrToUintArray = (str, addNul=false)=>{
return cache.utf8Encoder.encode(addNul ? (str+"\0") : str); 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)=>{ const __affirmAlloc = (obj,funcName)=>{
@@ -1175,19 +1188,17 @@ globalThis.WhWasmUtilInstaller = function(target){
const __allocCStr = function(jstr, returnWithLength, allocator, funcName){ const __allocCStr = function(jstr, returnWithLength, allocator, funcName){
__affirmAlloc(target, funcName); __affirmAlloc(target, funcName);
if('string'!==typeof jstr) return null; if('string'!==typeof jstr) return null;
if(0){/* older impl, possibly more widely compatible? */ const u = cache.utf8Encoder.encode(jstr),
const n = target.jstrlen(jstr), ptr = allocator(u.length+1);
ptr = allocator(n+1); let toFree = ptr;
target.jstrcpy(jstr, target.heap8u(), ptr, n+1, true); try{
return returnWithLength ? [ptr, n] : ptr; const heap = heapWrappers().HEAP8U;
}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);
heap.set(u, Number(ptr)); heap.set(u, Number(ptr));
heap[__ptrAdd(ptr, u.length)] = 0; heap[__ptrAdd(ptr, u.length)] = 0;
toFree = __NullPtr;
return returnWithLength ? [ptr, u.length] : ptr; return returnWithLength ? [ptr, u.length] : ptr;
}finally{
if( toFree ) target.dealloc(toFree);
} }
}; };
@@ -1328,7 +1339,8 @@ globalThis.WhWasmUtilInstaller = function(target){
*/ */
target.scopedAllocCString = target.scopedAllocCString =
(jstr, returnWithLength=false)=>__allocCStr(jstr, returnWithLength, (jstr, returnWithLength=false)=>__allocCStr(jstr, returnWithLength,
target.scopedAlloc, 'scopedAllocCString()'); target.scopedAlloc,
'scopedAllocCString()');
// impl for allocMainArgv() and scopedAllocMainArgv(). // impl for allocMainArgv() and scopedAllocMainArgv().
const __allocMainArgv = function(isScoped, list){ const __allocMainArgv = function(isScoped, list){
@@ -1520,23 +1532,10 @@ globalThis.WhWasmUtilInstaller = function(target){
/** Scope-local convenience aliases. */ /** Scope-local convenience aliases. */
const xArg = cache.xWrap.convert.arg, xResult = cache.xWrap.convert.result; const xArg = cache.xWrap.convert.arg, xResult = cache.xWrap.convert.result;
if(target.bigIntEnabled){
xArg.set('i64', (i)=>BigInt(i || 0));
}
const __xArgPtr = __asPtrType; 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 xArg
.set('i64', (i)=>__BigInt(i || 0))
.set('i32', (i)=>i|0)
.set('i16', (i)=>((i | 0) & 0xFFFF)) .set('i16', (i)=>((i | 0) & 0xFFFF))
.set('i8', (i)=>((i | 0) & 0xFF)) .set('i8', (i)=>((i | 0) & 0xFF))
.set('f32', (i)=>Number(i).valueOf()) .set('f32', (i)=>Number(i).valueOf())
@@ -1547,26 +1546,30 @@ globalThis.WhWasmUtilInstaller = function(target){
.set('null', (i)=>i) .set('null', (i)=>i)
.set(null, xArg.get('null')) .set(null, xArg.get('null'))
.set('**', __xArgPtr) .set('**', __xArgPtr)
.set('*', __xArgPtr); .set('*', __xArgPtr)
;
xResult.set('*', __xArgPtr) xResult.set('*', __xArgPtr)
.set('pointer', __xArgPtr) .set('pointer', __xArgPtr)
.set('number', (v)=>Number(v)) .set('number', (v)=>Number(v))
.set('void', (v)=>undefined) .set('void', (v)=>undefined)
.set(undefined, xResult.get('void'))
.set('null', (v)=>v) .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 identical semantics. Also add pointer-style variants of those
xArg entries to both xArg and xResult. */ xArg entries to both xArg and xResult. */
const copyToResult = ['i8', 'i16', 'i32', 'int', for(const t of [
'f32', 'float', 'f64', 'double']; 'i8', 'i16', 'i32', 'i64', 'int',
if(target.bigIntEnabled) copyToResult.push('i64'); 'f32', 'float', 'f64', 'double'
const adaptPtr = xArg.get(__ptrIR); ]){
for(const t of copyToResult){ xArg.set(t+'*', __xArgPtr);
xArg.set(t+'*', adaptPtr); xResult.set(t+'*', __xArgPtr);
xResult.set(t+'*', adaptPtr); xResult.set(
xResult.set(t, (xArg.get(t) || toss("Missing arg converter:",t))); 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 backfire? We handle that at the client level in sqlite3 with a
custom argument converter. custom argument converter.
*/ */
const __xArgString = function(v){ const __xArgString = (v)=>{
if('string'===typeof v) return target.scopedAllocCString(v); return ('string'===typeof v)
return __asPtrType(v); ? target.scopedAllocCString(v)
: __asPtrType(v);
}; };
xArg.set('string', __xArgString) xArg.set('string', __xArgString)
.set('utf8', __xArgString) .set('utf8', __xArgString)
.set('pointer', __xArgString); // (much later: why did we do this?) .set('pointer', __xArgString)
//xArg.set('*', __xArgString); ;
xResult.set('string', (i)=>target.cstrToJs(i)) xResult
.set('string', (i)=>target.cstrToJs(i))
.set('utf8', xResult.get('string')) .set('utf8', xResult.get('string'))
.set('string:dealloc', (i)=>{ .set('string:dealloc', (i)=>{
try { return i ? target.cstrToJs(i) : null } try { return i ? target.cstrToJs(i) : null }
@@ -1705,18 +1711,19 @@ globalThis.WhWasmUtilInstaller = function(target){
- contextKey (function): is only used if bindScope is 'context' - contextKey (function): is only used if bindScope is 'context'
or if bindScope is not set and this function is, in which case or if bindScope is not set and this function is, in which case
'context' is assumed. This function gets bound to this object, a bindScope of 'context' is assumed. This function gets bound
so its "this" is this object. It gets passed (argv,argIndex), to this object, so its "this" is this object. It gets passed
where argIndex is the index of _this_ function pointer in its (argv,argIndex), where argIndex is the index of _this_ function
_wrapping_ function's arguments and argv is the _current_ in its _wrapping_ function's arguments, and argv is the
still-being-xWrap()-processed args array. All arguments to the _current_ still-being-xWrap()-processed args array. (Got all
left of argIndex will have been processed by xWrap() by the that?) When thisFunc(argv,argIndex) is called by xWrap(), all
time this is called. argv[argIndex] will be the value the user arguments in argv to the left of argIndex will have been
passed in to the xWrap()'d function for the argument this processed by xWrap() by the time this is called. argv[argIndex]
FuncPtrAdapter is mapped to. Arguments to the right of will be the value the user passed in to the xWrap()'d function
argv[argIndex] will not yet have been converted before this is for the argument this FuncPtrAdapter is mapped to. Arguments to
called. The function must return a key which uniquely the right of argv[argIndex] will not yet have been converted
identifies this function mapping context for _this_ 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), FuncPtrAdapter instance (other instances are not considered),
taking into account that C functions often take some sort of taking into account that C functions often take some sort of
state object as one or more of their arguments. As an example, 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 same arity as the being-wrapped function (as defined by its
`length` property) and it will throw if that is not the case. `length` property) and it will throw if that is not the case.
Similarly, the created wrapper will throw if passed a differing 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 Type names are symbolic names which map the arguments to an
adapter function to convert, if needed, the value before passing adapter function to convert, if needed, the value before passing
it on to WASM or to convert a return result from WASM. The list 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 - `i8`, `i16`, `i32` (args and results): all integer conversions
which convert their argument to an integer and truncate it to which convert their argument to an integer and truncate it to
@@ -2043,8 +2052,8 @@ globalThis.WhWasmUtilInstaller = function(target){
is treated like `*`. is treated like `*`.
- `i64` (args and results): passes the value to BigInt() to - `i64` (args and results): passes the value to BigInt() to
convert it to an int64. Only available if bigIntEnabled is convert it to an int64. This conversion will if bigIntEnabled
true. is falsy.
- `f32` (`float`), `f64` (`double`) (args and results): pass - `f32` (`float`), `f64` (`double`) (args and results): pass
their argument to Number(). i.e. the adapter does not currently 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); const xf = fIsFunc ? fArg : target.xGet(fArg);
if(fIsFunc) fArg = xf.name || 'unnamed function'; if(fIsFunc) fArg = xf.name || 'unnamed function';
if(argTypes.length!==xf.length) __argcMismatch(fArg, xf.length); 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. */ /* Func taking no args with an as-is return. We don't need a wrapper. */
return xf; return xf;
} }
/*Verify the arg type conversions are valid...*/; /*Verify the arg type conversions are valid...*/;
if(undefined!==resultType && null!==resultType) __xResultAdapterCheck(resultType); __xResultAdapterCheck(resultType);
for(const t of argTypes){ for(const t of argTypes){
if(t instanceof AbstractArgAdapter) xArg.set(t, (...args)=>t.convertArg(...args)); if(t instanceof AbstractArgAdapter) xArg.set(t, (...args)=>t.convertArg(...args));
else __xArgAdapterCheck(t); else __xArgAdapterCheck(t);

View File

@@ -1,5 +1,5 @@
C Rename\swasm\sconfig\sentry\spointerSizeof\sto\spointerSize\sfor\sconsistency\swith\swasm.ptr.size. C Generic\scleanups\sand\ssimplifications\sin\sJS\scode.
D 2025-09-21T14:25:29.590 D 2025-09-21T17:55:23.130
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea 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/sqlite3session.h 7404723606074fcb2afdc6b72c206072cdb2b7d8ba097ca1559174a80bc26f7a
F ext/session/test_session.c 8766b5973a6323934cb51248f621c3dc87ad2a98f023c3cc280d79e7d78d36fb F ext/session/test_session.c 8766b5973a6323934cb51248f621c3dc87ad2a98f023c3cc280d79e7d78d36fb
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c 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-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a
F ext/wasm/README.md 66ace67ae98a45e4116f2ca5425b716887bcee4d64febee804ff6398e1ae9ec7 F ext/wasm/README.md 66ace67ae98a45e4116f2ca5425b716887bcee4d64febee804ff6398e1ae9ec7
F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff 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_FUNCTIONS.sqlite3-see fb29e62082a658f0d81102488414d422c393c4b20cc2f685b216bc566237957b
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287 F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
F ext/wasm/api/README.md 7f029c5fe83b3493931d2fb915e2febd3536267d538a56408a6fef284ea38d29 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/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41
F ext/wasm/api/post-js-footer.js 365405929f41ca0e6d389ed8a8da3f3c93e11d3ef43a90ae151e37fa9f75bf41 F ext/wasm/api/post-js-footer.js 365405929f41ca0e6d389ed8a8da3f3c93e11d3ef43a90ae151e37fa9f75bf41
F ext/wasm/api/post-js-header.js 53740d824e5d9027eb1e6fd59e216abbd2136740ce260ea5f0699ff2acb0a701 F ext/wasm/api/post-js-header.js 53740d824e5d9027eb1e6fd59e216abbd2136740ce260ea5f0699ff2acb0a701
F ext/wasm/api/pre-js.c-pp.js 58f823de197e2c10d76179aa05410a593b7ae03e1ece983bb42ffd818e8857e1 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-glue.c-pp.js 5fb52fb190519e2d9cd8507c5f6c7a9827c80aa254f16ec682e1d2c26ccd0fbd
F ext/wasm/api/sqlite3-api-oo1.c-pp.js 831ce373495f6a5d9230f31a1e09e8995e317828926e736d58c9e7091c6b1d07 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-api-worker1.c-pp.js 760191cd13416e6f5adfd9fcc8a97fed5645c9e0a5fbac213a2d4ce2d79a4334
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89 F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 9654b565b346dc609b75d15337f20acfa7af7d9d558da1afeb9b6d8eaa404966 F ext/wasm/api/sqlite3-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/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51
F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15 F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15
F ext/wasm/common/testing.css e97549bab24126c24e0daabfe2de9bb478fb0a69fdb2ddd0a73a992c091aad6f 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/config.make.in c424ae1cc3c89274520ad312509d36c4daa34a3fce5d0c688e5f8f4365e1049a
F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed
F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508 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-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 8ac12e1f5144380d4ecc8b27a1f62dcda0e5a86409ae7149f62c33caeea19a23 P 2cd8ba740f9b14dc1408b62632c603076b070dc412bf7cbfb3b525f0c4912371
R 44fa8ad18d4fc24a2afae6ef2b8a9f7f R 25f70763d7952a028a3fd18d711e95fa
U stephan U stephan
Z 6539d526d80f87ce2c0b68bf1d9a5a52 Z ac93091de705f89e3c49ed92d286b8f4
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

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