mirror of
https://github.com/sqlite/sqlite.git
synced 2025-12-20 01:22:32 +03:00
Reworking of JS internals to support binding of nested C structs (like sqlite3_index_constraint and friends) and allow some of the automated JS/C conversions to be plugged in at the struct-binding level, simplifying how struct members, in particular function pointers, can be used from JS.
FossilOrigin-Name: bb4fd5b789cebf2b224c29023fea3e620a86fb36730c36c0d85d9f35880bf643
This commit is contained in:
@@ -55,12 +55,7 @@ try{
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Figure out if this is a 32- or 64-bit WASM build. */
|
sqlite3InitScriptInfo.debugModule("Bootstrapping lib config", bootstrapConfig);
|
||||||
bootstrapConfig.wasmPtrIR =
|
|
||||||
'number'===(typeof bootstrapConfig.exports.sqlite3_libversion())
|
|
||||||
? 'i32' :'i64';
|
|
||||||
const sIMS = sqlite3InitScriptInfo;
|
|
||||||
sIMS.debugModule("Bootstrapping lib config", sIMS);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
For purposes of the Emscripten build, call sqlite3ApiBootstrap().
|
For purposes of the Emscripten build, call sqlite3ApiBootstrap().
|
||||||
|
|||||||
@@ -799,22 +799,6 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
|||||||
environment via whwashutil.js.
|
environment via whwashutil.js.
|
||||||
*/
|
*/
|
||||||
Object.assign(wasm, {
|
Object.assign(wasm, {
|
||||||
/**
|
|
||||||
The WASM IR (Intermediate Representation) value for
|
|
||||||
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
|
|
||||||
enabled, certain 64-bit sqlite3 APIs are enabled which
|
|
||||||
are not otherwise enabled due to JS/WASM int64
|
|
||||||
impedance mismatches.
|
|
||||||
*/
|
|
||||||
bigIntEnabled: !!config.bigIntEnabled,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The symbols exported by the WASM environment.
|
The symbols exported by the WASM environment.
|
||||||
@@ -834,6 +818,29 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
|||||||
"in either config.exports.memory (exported)",
|
"in either config.exports.memory (exported)",
|
||||||
"or config.memory (imported)."),
|
"or config.memory (imported)."),
|
||||||
|
|
||||||
|
/**
|
||||||
|
The WASM pointer size. If set then it MUST be one of 4 or 8 and
|
||||||
|
it MUST correspond to the WASM environment's pointer size. We
|
||||||
|
figure out the size by calling some un-JS-wrapped WASM function
|
||||||
|
which returns a pointer-type value. If that value is a BigInt,
|
||||||
|
it's 64-bit, else it's 32-bit. The pieces which populate
|
||||||
|
sqlite3.wasm (whwasmutil.js) can figure this out _if_ they can
|
||||||
|
allocate, but we have a chicken/egg situation there which makes
|
||||||
|
it illegal for that code to invoke wasm.dealloc() at the time
|
||||||
|
it would be needed. So we need to configure it ahead of time
|
||||||
|
(here) instead.
|
||||||
|
*/
|
||||||
|
pointerSize: ('number'===typeof config.exports.sqlite3_libversion()) ? 4 : 8,
|
||||||
|
|
||||||
|
/**
|
||||||
|
True if BigInt support was enabled via (e.g.) the
|
||||||
|
Emscripten -sWASM_BIGINT flag, else false. When
|
||||||
|
enabled, certain 64-bit sqlite3 APIs are enabled which
|
||||||
|
are not otherwise enabled due to JS/WASM int64
|
||||||
|
impedance mismatches.
|
||||||
|
*/
|
||||||
|
bigIntEnabled: !!config.bigIntEnabled,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
WebAssembly.Table object holding the indirect function call
|
WebAssembly.Table object holding the indirect function call
|
||||||
table. Defaults to exports.__indirect_function_table.
|
table. Defaults to exports.__indirect_function_table.
|
||||||
|
|||||||
@@ -227,6 +227,14 @@ globalThis.WhWasmUtilInstaller = function(target){
|
|||||||
all args with a space between each. */
|
all args with a space between each. */
|
||||||
const toss = (...args)=>{throw new Error(args.join(' '))};
|
const toss = (...args)=>{throw new Error(args.join(' '))};
|
||||||
|
|
||||||
|
if( !target.pointerSize && !target.pointerIR
|
||||||
|
&& target.alloc && target.dealloc ){
|
||||||
|
/* Try to determine the pointer size by allocating. */
|
||||||
|
const ptr = target.alloc(1);
|
||||||
|
target.pointerSize = ('bigint'===typeof ptr ? 8 : 4);
|
||||||
|
target.dealloc(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
As of 2025-09-21, this library works with 64-bit WASM modules
|
As of 2025-09-21, this library works with 64-bit WASM modules
|
||||||
built with Emscripten's -sMEMORY64=1.
|
built with Emscripten's -sMEMORY64=1.
|
||||||
@@ -996,12 +1004,12 @@ globalThis.WhWasmUtilInstaller = function(target){
|
|||||||
target.heap8u().
|
target.heap8u().
|
||||||
*/
|
*/
|
||||||
target.cstrlen = function(ptr){
|
target.cstrlen = function(ptr){
|
||||||
if(!ptr || !target.isPtr(ptr)) return null;
|
if(!ptr || !target.isPtr/*64*/(ptr)) return null;
|
||||||
ptr = Number(ptr) /*tag:64bit*/;
|
ptr = Number(ptr) /*tag:64bit*/;
|
||||||
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 Number(pos - ptr);
|
return pos - ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Internal helper to use in operations which need to distinguish
|
/** Internal helper to use in operations which need to distinguish
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
|||||||
|
|
||||||
if(!(config.heap instanceof WebAssembly.Memory)
|
if(!(config.heap instanceof WebAssembly.Memory)
|
||||||
&& !(config.heap instanceof Function)){
|
&& !(config.heap instanceof Function)){
|
||||||
toss("config.heap must be WebAssembly.Memory instance or a function.");
|
toss("config.heap must be WebAssembly.Memory instance or a function which returns one.");
|
||||||
}
|
}
|
||||||
['alloc','dealloc'].forEach(function(k){
|
['alloc','dealloc'].forEach(function(k){
|
||||||
(config[k] instanceof Function) ||
|
(config[k] instanceof Function) ||
|
||||||
@@ -48,14 +48,19 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
|||||||
memberSuffix = (config.memberSuffix || ""),
|
memberSuffix = (config.memberSuffix || ""),
|
||||||
BigInt = globalThis['BigInt'],
|
BigInt = globalThis['BigInt'],
|
||||||
BigInt64Array = globalThis['BigInt64Array'],
|
BigInt64Array = globalThis['BigInt64Array'],
|
||||||
bigIntEnabled = config.bigIntEnabled ?? !!BigInt64Array,
|
bigIntEnabled = config.bigIntEnabled ?? !!BigInt64Array;
|
||||||
ptrIR = config.pointerIR
|
|
||||||
|| config.ptrIR/*deprecated*/
|
//console.warn("config",config);
|
||||||
|| 'i32',
|
let ptr = alloc(1);
|
||||||
/* Undocumented (on purpose) config options: */
|
const ptrIR = config.pointerIR
|
||||||
ptrSize = config.ptrSize/*deprecated*/
|
|| config.ptrIR/*deprecated*/
|
||||||
|| ('i32'===ptrIR ? 4 : 8)
|
|| ('bigint'===typeof ptr ? 'i64' : 'i32');
|
||||||
;
|
/* Undocumented (on purpose) config options: */
|
||||||
|
const ptrSize = config.ptrSize/*deprecated*/
|
||||||
|
|| ('i32'===ptrIR ? 4 : 8);
|
||||||
|
dealloc(ptr);
|
||||||
|
ptr = undefined;
|
||||||
|
//console.warn("ptrIR =",ptrIR,"ptrSize =",ptrSize);
|
||||||
|
|
||||||
if(ptrIR!=='i32' && ptrIR!=='i64') toss("Invalid pointer representation:",ptrIR);
|
if(ptrIR!=='i32' && ptrIR!=='i64') toss("Invalid pointer representation:",ptrIR);
|
||||||
if(ptrSize!==4 && ptrSize!==8) toss("Invalid pointer size:",ptrSize);
|
if(ptrSize!==4 && ptrSize!==8) toss("Invalid pointer size:",ptrSize);
|
||||||
@@ -136,11 +141,11 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
|||||||
/** True if SIG s looks like a function signature, else
|
/** True if SIG s looks like a function signature, else
|
||||||
false. */
|
false. */
|
||||||
const isFuncSig = (s)=>'('===s[1];
|
const isFuncSig = (s)=>'('===s[1];
|
||||||
/** True if SIG s is-a pointer signature. */
|
/** True if SIG s is-a pointer-type signature. */
|
||||||
const isPtrSig = (s)=>'p'===s || 'P'===s;
|
const isPtrSig = (s)=>'p'===s || 'P'===s || 's'===s;
|
||||||
const isAutoPtrSig = (s)=>'P'===s /*EXPERIMENTAL*/;
|
const isAutoPtrSig = (s)=>'P'===s /*EXPERIMENTAL*/;
|
||||||
/** Returns p if SIG s is a function SIG, else returns s[0]. */
|
/** Returns p if SIG s is a function SIG, else returns s[0]. */
|
||||||
const sigLetter = (s)=>isFuncSig(s) ? 'p' : s[0];
|
const sigLetter = (s)=>s ? (isFuncSig(s) ? 'p' : s[0]) : undefined;
|
||||||
/** Returns the WASM IR form of the Emscripten-conventional letter
|
/** Returns the WASM IR form of the Emscripten-conventional letter
|
||||||
at SIG s[0]. Throws for an unknown SIG. */
|
at SIG s[0]. Throws for an unknown SIG. */
|
||||||
const sigIR = function(s){
|
const sigIR = function(s){
|
||||||
@@ -154,6 +159,19 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
|||||||
}
|
}
|
||||||
toss("Unhandled signature IR:",s);
|
toss("Unhandled signature IR:",s);
|
||||||
};
|
};
|
||||||
|
/** Returns the WASM sizeof of the Emscripten-conventional letter
|
||||||
|
at SIG s[0]. Throws for an unknown SIG. */
|
||||||
|
const sigSize = function(s){
|
||||||
|
switch(sigLetter(s)){
|
||||||
|
case 'c': case 'C': return 1;
|
||||||
|
case 'i': return 4;
|
||||||
|
case 'p': case 'P': case 's': return ptrSize;
|
||||||
|
case 'j': return 8;
|
||||||
|
case 'f': return 4;
|
||||||
|
case 'd': return 8;
|
||||||
|
}
|
||||||
|
toss("Unhandled signature sizeof:",s);
|
||||||
|
};
|
||||||
|
|
||||||
const affirmBigIntArray = BigInt64Array
|
const affirmBigIntArray = BigInt64Array
|
||||||
? ()=>true : ()=>toss('BigInt64Array is not available.');
|
? ()=>true : ()=>toss('BigInt64Array is not available.');
|
||||||
@@ -232,11 +250,22 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
|||||||
accessible via boundObject.pointer, which is gated behind a
|
accessible via boundObject.pointer, which is gated behind a
|
||||||
property interceptor, but are not exposed anywhere else in the
|
property interceptor, but are not exposed anywhere else in the
|
||||||
object.
|
object.
|
||||||
|
|
||||||
|
This approach means we cannot proxy arrays, or any type which
|
||||||
|
might be realloced, as that pointer could change out from under
|
||||||
|
us. That's not an issue for nested structs, but it might be for a
|
||||||
|
struct they're embedded in. In the case of nested structs we
|
||||||
|
"could" record their top-most parent object and their offset into
|
||||||
|
that object, instead of storing the pointer itself. We could that
|
||||||
|
by allowing a function instead of a pointer in this map, that
|
||||||
|
function returning the (lazily-calculated) address. Hmm.
|
||||||
*/
|
*/
|
||||||
const __instancePointerMap = new WeakMap();
|
const __instancePointerMap = new WeakMap();
|
||||||
|
|
||||||
|
const getInstancePtr = (obj)=>__instancePointerMap.get(obj);
|
||||||
|
|
||||||
/** Property name for the pointer-is-external marker. */
|
/** Property name for the pointer-is-external marker. */
|
||||||
const xPtrPropName = '(pointer-is-external)';
|
const xPtrPropName = Symbol('(pointer-is-external)');
|
||||||
|
|
||||||
const __isPtr32 = (ptr)=>('number'===typeof ptr && (ptr===(ptr|0)) && ptr>=0);
|
const __isPtr32 = (ptr)=>('number'===typeof ptr && (ptr===(ptr|0)) && ptr>=0);
|
||||||
const __isPtr64 = (ptr)=>(
|
const __isPtr64 = (ptr)=>(
|
||||||
@@ -252,7 +281,7 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
|||||||
/** Frees the obj.pointer memory and clears the pointer
|
/** Frees the obj.pointer memory and clears the pointer
|
||||||
property. */
|
property. */
|
||||||
const __freeStruct = function(ctor, obj, m){
|
const __freeStruct = function(ctor, obj, m){
|
||||||
if(!m) m = __instancePointerMap.get(obj);
|
if(!m) m = getInstancePtr(obj);
|
||||||
if(m) {
|
if(m) {
|
||||||
__instancePointerMap.delete(obj);
|
__instancePointerMap.delete(obj);
|
||||||
if(Array.isArray(obj.ondispose)){
|
if(Array.isArray(obj.ondispose)){
|
||||||
@@ -283,7 +312,12 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
|||||||
ctor.structName,"instance:",
|
ctor.structName,"instance:",
|
||||||
ctor.structInfo.sizeof,"bytes @"+m);
|
ctor.structInfo.sizeof,"bytes @"+m);
|
||||||
}
|
}
|
||||||
if(!obj[xPtrPropName]) dealloc(m);
|
if(!obj[xPtrPropName]){
|
||||||
|
if( ctor.structInfo.zeroOnFree ){
|
||||||
|
heap().fill(0, Number(m), Number(m)+ctor.structInfo.sizeof);
|
||||||
|
}
|
||||||
|
dealloc(m);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -324,8 +358,69 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
|||||||
: null;
|
: null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** True if sig looks like an emscripten/jaccwabyt
|
||||||
|
type signature, else false. */
|
||||||
|
const looksLikeASig = function f(sig){
|
||||||
|
f.rxSig1 ??= /^[ipPsjfdcC]$/;
|
||||||
|
f.rxSig2 ??= /^[vipPsjfdcC]\([ipPsjfdcC]*\)$/;
|
||||||
|
return f.rxSig1.test(sig) || f.rxSig2.test(sig);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Returns a pair of adaptor maps (objects) in a length-3
|
||||||
|
array specific to the given object. */
|
||||||
|
const __adaptorsFor = function(who){
|
||||||
|
let x = this.get(who);
|
||||||
|
if( !x ){
|
||||||
|
x = [ Object.create(null), Object.create(null), Object.create(null) ];
|
||||||
|
this.set(who, x);
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}.bind(new WeakMap);
|
||||||
|
|
||||||
|
/** Code de-duplifier for __adaptGet(), __adaptSet(), and
|
||||||
|
__adaptStruct(). */
|
||||||
|
const __adaptor = function(who, which, key, proxy){
|
||||||
|
const a = __adaptorsFor(who)[which];
|
||||||
|
if(3===arguments.length) return a[key];
|
||||||
|
if( proxy ) return a[key] = proxy;
|
||||||
|
return delete a[key];
|
||||||
|
};
|
||||||
|
|
||||||
|
const noopAdapter = (x)=>x;
|
||||||
|
|
||||||
|
// StructBinder::adaptGet()
|
||||||
|
const __adaptGet = function(key, ...args){
|
||||||
|
/*if( looksLikeASig(key) ){
|
||||||
|
toss("Getter adaptor's name (",key,") collides with a data type signature.");
|
||||||
|
}*/
|
||||||
|
return __adaptor(this, 0, key, ...args);
|
||||||
|
};
|
||||||
|
|
||||||
|
// StructBinder::adaptSet()
|
||||||
|
const __adaptSet = function(key, ...args){
|
||||||
|
if( looksLikeASig(key) ){
|
||||||
|
toss("Setter adaptor's name (",key,") collides with a data type signature.");
|
||||||
|
}
|
||||||
|
return __adaptor(this, 1, key, ...args);
|
||||||
|
};
|
||||||
|
|
||||||
|
// StructBinder::adaptStruct()
|
||||||
|
const __adaptStruct = function(key, ...args){
|
||||||
|
return __adaptor(this, 2, key, ...args);
|
||||||
|
};
|
||||||
|
|
||||||
|
const __adaptStruct2 = function(who,key){
|
||||||
|
const si = ('string'===typeof key)
|
||||||
|
? __adaptor(who, 2, key) : key;
|
||||||
|
if( 'object'!==typeof si ){
|
||||||
|
toss("Invalid struct mapping object. Arg =",key,JSON.stringify(si));
|
||||||
|
}
|
||||||
|
return si;
|
||||||
|
};
|
||||||
|
|
||||||
const __memberKey = (k)=>memberPrefix + k + memberSuffix;
|
const __memberKey = (k)=>memberPrefix + k + memberSuffix;
|
||||||
const __memberKeyProp = rop(__memberKey);
|
const __memberKeyProp = rop(__memberKey);
|
||||||
|
//const __adaptGetProp = rop(__adaptGet);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Looks up a struct member in structInfo.members. Throws if found
|
Looks up a struct member in structInfo.members. Throws if found
|
||||||
@@ -342,7 +437,8 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
|||||||
if(v.key===memberName){ m = v; break; }
|
if(v.key===memberName){ m = v; break; }
|
||||||
}
|
}
|
||||||
if(!m && tossIfNotFound){
|
if(!m && tossIfNotFound){
|
||||||
toss(sPropName(structInfo.name,memberName),'is not a mapped struct member.');
|
toss(sPropName(structInfo.name || structInfo.structName, memberName),
|
||||||
|
'is not a mapped struct member.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
@@ -361,7 +457,7 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
|||||||
|
|
||||||
const __ptrPropDescriptor = {
|
const __ptrPropDescriptor = {
|
||||||
configurable: false, enumerable: false,
|
configurable: false, enumerable: false,
|
||||||
get: function(){return __instancePointerMap.get(this)},
|
get: function(){return getInstancePtr(this)},
|
||||||
set: ()=>toss("Cannot assign the 'pointer' property of a struct.")
|
set: ()=>toss("Cannot assign the 'pointer' property of a struct.")
|
||||||
// Reminder: leaving `set` undefined makes assignments
|
// Reminder: leaving `set` undefined makes assignments
|
||||||
// to the property _silently_ do nothing. Current unit tests
|
// to the property _silently_ do nothing. Current unit tests
|
||||||
@@ -558,78 +654,176 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Pass this a StructBinder-generated prototype, and the struct
|
If struct description object si has a getter proxy, return it (a
|
||||||
member description object. It will define property accessors for
|
function), else return undefined.
|
||||||
proto[memberKey] which read from/write to memory in
|
|
||||||
this.pointer. It modifies descr to make certain downstream
|
|
||||||
operations much simpler.
|
|
||||||
*/
|
*/
|
||||||
const makeMemberWrapper = function f(ctor,name, descr){
|
const memberGetterProxy = function(si){
|
||||||
|
return si.get || (si.adaptGet
|
||||||
|
? StructBinder.adaptGet(si.adaptGet)
|
||||||
|
: undefined);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
If struct description object si has a setter proxy, return it (a
|
||||||
|
function), else return undefined.
|
||||||
|
*/
|
||||||
|
const memberSetterProxy = function(si){
|
||||||
|
return si.set || (si.adaptSet
|
||||||
|
? StructBinder.adaptSet(si.adaptSet)
|
||||||
|
: undefined);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
To be called by makeMemberWrapper() when si has a 'members'
|
||||||
|
member, i.e. is an embedded struct. This function sets up that
|
||||||
|
struct like any other and also sets up property accessor for
|
||||||
|
ctor.memberKey(name) which returns an instance of that new
|
||||||
|
StructType when the member is accessed. That instance wraps the
|
||||||
|
memory of the member's part of the containing C struct instance.
|
||||||
|
|
||||||
|
That is, if struct Foo has member bar which is an inner struct
|
||||||
|
then:
|
||||||
|
|
||||||
|
const f = new Foo;
|
||||||
|
const b = f.bar;
|
||||||
|
assert( b is-a StructType object );
|
||||||
|
assert( b.pointer === f.b.pointer );
|
||||||
|
|
||||||
|
b will be disposed of when f() is. Calling b.dispose() will not
|
||||||
|
do any permanent harm, as the wrapper object will be recreated
|
||||||
|
when accessing f.bar, pointing to the same memory in f.
|
||||||
|
|
||||||
|
The si.zeroOnFree flag has no effect on embedded structs because
|
||||||
|
they wrap "external" memory, so do not own it, and are thus never
|
||||||
|
freed, as such.
|
||||||
|
*/
|
||||||
|
const makeMemberStructWrapper = function callee(ctor, name, si){
|
||||||
|
/**
|
||||||
|
Where we store inner-struct member proxies. Keys are a
|
||||||
|
combination of the parent object's pointer address and the
|
||||||
|
property's name. The values are StructType instances.
|
||||||
|
*/
|
||||||
|
const __innerStructs = (callee.innerStructs ??= new Map());
|
||||||
|
const key = ctor.memberKey(name);
|
||||||
|
if( undefined!==si.signature ){
|
||||||
|
toss("'signature' cannot be used on an embedded struct (",
|
||||||
|
ctor.structName,".",key,").");
|
||||||
|
}
|
||||||
|
if( memberSetterProxy(si) ){
|
||||||
|
toss("'set' and 'adaptSet' are not permitted for nested struct members.");
|
||||||
|
}
|
||||||
|
//console.warn("si =",ctor.structName, name, JSON.stringify(si,' '));
|
||||||
|
si.structName ??= ctor.structName+'::'+name;
|
||||||
|
si.key = key;
|
||||||
|
si.name = name;
|
||||||
|
si.constructor = this.call(this, si.structName, si);
|
||||||
|
//console.warn("si.constructor =",si.constructor);
|
||||||
|
//console.warn("si =",si,"ctor=",ctor);
|
||||||
|
const getterProxy = memberGetterProxy(si);
|
||||||
|
const prop = Object.assign(Object.create(null),{
|
||||||
|
configurable: false,
|
||||||
|
enumerable: false,
|
||||||
|
set: __propThrowOnSet(ctor/*not si.constructor*/.structName, key),
|
||||||
|
get: function(){
|
||||||
|
const dbg = si.constructor.prototype.debugFlags.__flags;
|
||||||
|
const p = this.pointer;
|
||||||
|
const k = p+'.'+key;
|
||||||
|
let s = __innerStructs.get(k);
|
||||||
|
if(dbg.getter){ log("debug.getter: k =",k); }
|
||||||
|
if( !s ){
|
||||||
|
s = new si.constructor(__ptrAdd(p, si.offset));
|
||||||
|
__innerStructs.set(k, s);
|
||||||
|
this.addOnDispose(()=>s.dispose());
|
||||||
|
s.addOnDispose(()=>__innerStructs.delete(k));
|
||||||
|
//console.warn("Created",k,"proxy");
|
||||||
|
}
|
||||||
|
if(getterProxy) s = getterProxy.apply(this,[s,key]);
|
||||||
|
if(dbg.getter) log("debug.getter: result =",s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.defineProperty(ctor.prototype, key, prop);
|
||||||
|
}/*makeMemberStructWrapper()*/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Pass this a StructBinderImpl-generated constructor, a member
|
||||||
|
property name, and the struct member description object. It will
|
||||||
|
define property accessors for proto[memberKey] which read
|
||||||
|
from/write to memory in this.pointer. It modifies si to make
|
||||||
|
certain downstream operations simpler.
|
||||||
|
*/
|
||||||
|
const makeMemberWrapper = function f(ctor, name, si){
|
||||||
|
si = __adaptStruct2(this, si);
|
||||||
|
if( si.members ){
|
||||||
|
return makeMemberStructWrapper.call(this, ctor, name, si);
|
||||||
|
}
|
||||||
|
|
||||||
if(!f._){
|
if(!f._){
|
||||||
/*cache all available getters/setters/set-wrappers for
|
/* Cache all available getters/setters/set-wrappers for
|
||||||
direct reuse in each accessor function. */
|
direct reuse in each accessor function. */
|
||||||
f._ = {getters: {}, setters: {}, sw:{}};
|
f._ = {getters: {}, setters: {}, sw:{}};
|
||||||
const a = ['i','c','C','p','P','s','f','d','v()'];
|
const a = ['i','c','C','p','P','s','f','d','v()'];
|
||||||
if(bigIntEnabled) a.push('j');
|
if(bigIntEnabled) a.push('j');
|
||||||
a.forEach(function(v){
|
a.forEach(function(v){
|
||||||
//const ir = sigIR(v);
|
|
||||||
f._.getters[v] = sigDVGetter(v) /* DataView[MethodName] values for GETTERS */;
|
f._.getters[v] = sigDVGetter(v) /* DataView[MethodName] values for GETTERS */;
|
||||||
f._.setters[v] = sigDVSetter(v) /* DataView[MethodName] values for SETTERS */;
|
f._.setters[v] = sigDVSetter(v) /* DataView[MethodName] values for SETTERS */;
|
||||||
f._.sw[v] = sigDVSetWrapper(v) /* BigInt or Number ctor to wrap around values
|
f._.sw[v] = sigDVSetWrapper(v) /* BigInt or Number ctor to wrap around values
|
||||||
for conversion */;
|
for conversion */;
|
||||||
});
|
});
|
||||||
const rxSig1 = /^[ipPsjfdcC]$/,
|
|
||||||
rxSig2 = /^[vipPsjfdcC]\([ipPsjfdcC]*\)$/;
|
|
||||||
f.sigCheck = function(obj, name, key,sig){
|
f.sigCheck = function(obj, name, key,sig){
|
||||||
if(Object.prototype.hasOwnProperty.call(obj, key)){
|
if(Object.prototype.hasOwnProperty.call(obj, key)){
|
||||||
toss(obj.structName,'already has a property named',key+'.');
|
toss(obj.structName,'already has a property named',key+'.');
|
||||||
}
|
}
|
||||||
rxSig1.test(sig) || rxSig2.test(sig)
|
looksLikeASig(sig)
|
||||||
|| toss("Malformed signature for",
|
|| toss("Malformed signature for",
|
||||||
sPropName(obj.structName,name)+":",sig);
|
sPropName(obj.structName,name)+":",sig);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const key = ctor.memberKey(name);
|
const key = ctor.memberKey(name);
|
||||||
f.sigCheck(ctor.prototype, name, key, descr.signature);
|
f.sigCheck(ctor.prototype, name, key, si.signature);
|
||||||
descr.key = key;
|
si.key = key;
|
||||||
descr.name = name;
|
si.name = name;
|
||||||
const sigGlyph = sigLetter(descr.signature);
|
const sigGlyph = sigLetter(si.signature);
|
||||||
const xPropName = sPropName(ctor.prototype.structName,key);
|
const xPropName = sPropName(ctor.prototype.structName,key);
|
||||||
const dbg = ctor.prototype.debugFlags.__flags;
|
const dbg = ctor.prototype.debugFlags.__flags;
|
||||||
/*
|
/*
|
||||||
TODO?: set prototype of descr to an object which can set/fetch
|
TODO?: set prototype of si to an object which can set/fetch
|
||||||
its preferred representation, e.g. conversion to string or mapped
|
its preferred representation, e.g. conversion to string or mapped
|
||||||
function. Advantage: we can avoid doing that via if/else if/else
|
function. Advantage: we can avoid doing that via if/else if/else
|
||||||
in the get/set methods.
|
in the get/set methods.
|
||||||
*/
|
*/
|
||||||
|
const getterProxy = memberGetterProxy(si);
|
||||||
const prop = Object.create(null);
|
const prop = Object.create(null);
|
||||||
prop.configurable = false;
|
prop.configurable = false;
|
||||||
prop.enumerable = false;
|
prop.enumerable = false;
|
||||||
prop.get = function(){
|
prop.get = function(){
|
||||||
if(dbg.getter){
|
if(dbg.getter){
|
||||||
log("debug.getter:",f._.getters[sigGlyph],"for", sigIR(sigGlyph),
|
log("debug.getter:",f._.getters[sigGlyph],"for", sigIR(sigGlyph),
|
||||||
xPropName,'@', this.pointer,'+',descr.offset,'sz',descr.sizeof);
|
xPropName,'@', this.pointer,'+',si.offset,'sz',si.sizeof);
|
||||||
}
|
}
|
||||||
let rc = (
|
let rc = (
|
||||||
new DataView(heap().buffer, Number(this.pointer) + descr.offset, descr.sizeof)
|
new DataView(heap().buffer, Number(this.pointer) + si.offset, si.sizeof)
|
||||||
)[f._.getters[sigGlyph]](0, isLittleEndian);
|
)[f._.getters[sigGlyph]](0, isLittleEndian);
|
||||||
|
if(getterProxy) rc = getterProxy.apply(this,[rc,key]);
|
||||||
if(dbg.getter) log("debug.getter:",xPropName,"result =",rc);
|
if(dbg.getter) log("debug.getter:",xPropName,"result =",rc);
|
||||||
return rc;
|
return rc;
|
||||||
};
|
};
|
||||||
if(descr.readOnly){
|
if(si.readOnly){
|
||||||
prop.set = __propThrowOnSet(ctor.prototype.structName,key);
|
prop.set = __propThrowOnSet(ctor.prototype.structName,key);
|
||||||
}else{
|
}else{
|
||||||
|
const setterProxy = memberSetterProxy(si);
|
||||||
prop.set = function(v){
|
prop.set = function(v){
|
||||||
if(dbg.setter){
|
if(dbg.setter){
|
||||||
log("debug.setter:",f._.setters[sigGlyph],"for", sigIR(sigGlyph),
|
log("debug.setter:",f._.setters[sigGlyph],"for", sigIR(sigGlyph),
|
||||||
xPropName,'@', this.pointer,'+',descr.offset,'sz',descr.sizeof, v);
|
xPropName,'@', this.pointer,'+',si.offset,'sz',si.sizeof, v);
|
||||||
}
|
}
|
||||||
if(!this.pointer){
|
if(!this.pointer){
|
||||||
toss("Cannot set struct property on disposed instance.");
|
toss("Cannot set native property on a disposed struct instance.");
|
||||||
}
|
}
|
||||||
if(null===v) v = __NullPtr;
|
if( setterProxy ) v = setterProxy.apply(this,[v]);
|
||||||
else while(!__isPtr(v)){
|
if( null===v || undefined===v ) v = __NullPtr;
|
||||||
if(isAutoPtrSig(descr.signature) && (v instanceof StructType)){
|
else while( isPtrSig(si.signature) && !__isPtr(v) ){
|
||||||
|
if(isAutoPtrSig(si.signature) && (v instanceof StructType)){
|
||||||
// It's a struct instance: let's store its pointer value!
|
// It's a struct instance: let's store its pointer value!
|
||||||
v = v.pointer || __NullPtr;
|
v = v.pointer || __NullPtr;
|
||||||
if(dbg.setter) log("debug.setter:",xPropName,"resolved to",v);
|
if(dbg.setter) log("debug.setter:",xPropName,"resolved to",v);
|
||||||
@@ -638,66 +832,45 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
|||||||
toss("Invalid value for pointer-type",xPropName+'.');
|
toss("Invalid value for pointer-type",xPropName+'.');
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
new DataView(heap().buffer, Number(this.pointer) + descr.offset,
|
new DataView(heap().buffer, Number(this.pointer) + si.offset,
|
||||||
descr.sizeof)
|
si.sizeof)
|
||||||
)[f._.setters[sigGlyph]](0, f._.sw[sigGlyph](v), isLittleEndian);
|
)[f._.setters[sigGlyph]](0, f._.sw[sigGlyph](v), isLittleEndian);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Object.defineProperty(ctor.prototype, key, prop);
|
Object.defineProperty(ctor.prototype, key, prop);
|
||||||
}/*makeMemberWrapper*/;
|
}/*makeMemberWrapper()*/;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The main factory function which will be returned to the
|
The main factory function which will be returned to the
|
||||||
caller.
|
caller. The third argument is structly for internal use.
|
||||||
|
|
||||||
|
This level of indirection is to avoid that clients can pass a
|
||||||
|
third argument to this, as that's only for internal use.
|
||||||
|
|
||||||
|
internalOpt options:
|
||||||
|
|
||||||
|
- None right now. This is for potential use in recursion.
|
||||||
|
|
||||||
|
Usages:
|
||||||
|
|
||||||
|
StructBinder(string, obj [,optObj]);
|
||||||
|
StructBinder(obj);
|
||||||
*/
|
*/
|
||||||
const StructBinder = function StructBinder(structName, structInfo){
|
const StructBinderImpl = function StructBinderImpl(
|
||||||
if(1===arguments.length){
|
structName, si, opt = Object.create(null)
|
||||||
structInfo = structName;
|
){
|
||||||
structName = structInfo.name;
|
/**
|
||||||
}else if(!structInfo.name){
|
StructCtor is the eventual return value of this function. We
|
||||||
structInfo.name = structName;
|
need to populate this early on so that we can do some trickery
|
||||||
}
|
in feeding it through recursion.
|
||||||
if(!structName) toss("Struct name is required.");
|
*/
|
||||||
let lastMember = false;
|
|
||||||
Object.keys(structInfo.members).forEach((k)=>{
|
|
||||||
// Sanity checks of sizeof/offset info...
|
|
||||||
const m = structInfo.members[k];
|
|
||||||
if(!m.sizeof) toss(structName,"member",k,"is missing sizeof.");
|
|
||||||
else if(m.sizeof===1){
|
|
||||||
(m.signature === 'c' || m.signature === 'C') ||
|
|
||||||
toss("Unexpected sizeof==1 member",
|
|
||||||
sPropName(structInfo.name,k),
|
|
||||||
"with signature",m.signature);
|
|
||||||
}else{
|
|
||||||
// sizes and offsets of size-1 members may be odd values, but
|
|
||||||
// others may not.
|
|
||||||
if(0!==(m.sizeof%4)){
|
|
||||||
console.warn("Invalid struct member description =",m,"from",structInfo);
|
|
||||||
toss(structName,"member",k,"sizeof is not aligned. sizeof="+m.sizeof);
|
|
||||||
}
|
|
||||||
if(0!==(m.offset%4)){
|
|
||||||
console.warn("Invalid struct member description =",m,"from",structInfo);
|
|
||||||
toss(structName,"member",k,"offset is not aligned. offset="+m.offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!lastMember || lastMember.offset < m.offset) lastMember = m;
|
|
||||||
});
|
|
||||||
if(!lastMember) toss("No member property descriptions found.");
|
|
||||||
else if(structInfo.sizeof < lastMember.offset+lastMember.sizeof){
|
|
||||||
toss("Invalid struct config:",structName,
|
|
||||||
"max member offset ("+lastMember.offset+") ",
|
|
||||||
"extends past end of struct (sizeof="+structInfo.sizeof+").");
|
|
||||||
}
|
|
||||||
const debugFlags = rop(SBF.__makeDebugFlags(StructBinder.debugFlags));
|
|
||||||
/** Constructor for the StructCtor. */
|
|
||||||
const zeroAsPtr = __asPtrType(0);
|
|
||||||
const StructCtor = function StructCtor(externalMemory){
|
const StructCtor = function StructCtor(externalMemory){
|
||||||
externalMemory = __asPtrType(externalMemory);
|
externalMemory = __asPtrType(externalMemory);
|
||||||
//console.warn("externalMemory",externalMemory,arguments[0]);
|
//console.warn("externalMemory",externalMemory,arguments[0]);
|
||||||
if(!(this instanceof StructCtor)){
|
if(!(this instanceof StructCtor)){
|
||||||
toss("The",structName,"constructor may only be called via 'new'.");
|
toss("The",structName,"constructor may only be called via 'new'.");
|
||||||
}else if(arguments.length){
|
}else if(arguments.length){
|
||||||
if(Number.isNaN(externalMemory) || externalMemory<=zeroAsPtr){
|
if( !__isPtr(externalMemory) ){
|
||||||
toss("Invalid pointer value",arguments[0],"for",structName,"constructor.");
|
toss("Invalid pointer value",arguments[0],"for",structName,"constructor.");
|
||||||
}
|
}
|
||||||
__allocStruct(StructCtor, this, externalMemory);
|
__allocStruct(StructCtor, this, externalMemory);
|
||||||
@@ -705,31 +878,127 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
|||||||
__allocStruct(StructCtor, this);
|
__allocStruct(StructCtor, this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const self = this;
|
||||||
|
/**
|
||||||
|
"Convert" struct description x to a struct description, if
|
||||||
|
needed.
|
||||||
|
*/
|
||||||
|
const ads = (x)=>{
|
||||||
|
//console.warn("looksLikeASig(",x,") =",looksLikeASig(x));
|
||||||
|
return (('string'===typeof x) && looksLikeASig(x))
|
||||||
|
? {signature: x} : __adaptStruct2(self,x);
|
||||||
|
};
|
||||||
|
if(1===arguments.length){
|
||||||
|
si = ads(structName);
|
||||||
|
structName = si.structName || si.name;
|
||||||
|
}else if(2===arguments.length){
|
||||||
|
si = ads(si);
|
||||||
|
si.name ??= structName;
|
||||||
|
}else{
|
||||||
|
si = ads(si);
|
||||||
|
}
|
||||||
|
structName ??= si.structName;
|
||||||
|
//console.warn("arguments =",JSON.stringify(arguments));
|
||||||
|
structName ??= opt.structName;
|
||||||
|
if( !structName ) toss("One of 'name' or 'structName' are required.");
|
||||||
|
if( si.adapt ){
|
||||||
|
Object.keys(si.adapt.struct||{}).forEach((k)=>{
|
||||||
|
__adaptStruct.call(StructBinderImpl, k, si.adapt.struct[k]);
|
||||||
|
});
|
||||||
|
Object.keys(si.adapt.set||{}).forEach((k)=>{
|
||||||
|
__adaptSet.call(StructBinderImpl, k, si.adapt.set[k]);
|
||||||
|
});
|
||||||
|
Object.keys(si.adapt.get||{}).forEach((k)=>{
|
||||||
|
__adaptGet.call(StructBinderImpl, k, si.adapt.get[k]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if(!si.members && !si.sizeof){
|
||||||
|
si.sizeof = sigSize(si.signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
const debugFlags = rop(SBF.__makeDebugFlags(StructBinder.debugFlags));
|
||||||
Object.defineProperties(StructCtor,{
|
Object.defineProperties(StructCtor,{
|
||||||
debugFlags: debugFlags,
|
debugFlags: debugFlags,
|
||||||
isA: rop((v)=>v instanceof StructCtor),
|
isA: rop((v)=>v instanceof StructCtor),
|
||||||
memberKey: __memberKeyProp,
|
memberKey: __memberKeyProp,
|
||||||
memberKeys: __structMemberKeys,
|
memberKeys: __structMemberKeys,
|
||||||
methodInfoForKey: rop(function(mKey){
|
//methodInfoForKey: rop(function(mKey){/*???*/}),
|
||||||
}),
|
structInfo: rop(si),
|
||||||
structInfo: rop(structInfo),
|
|
||||||
structName: rop(structName)
|
structName: rop(structName)
|
||||||
});
|
});
|
||||||
StructCtor.prototype = new StructType(structName, structInfo, rop);
|
StructCtor.prototype = new StructType(structName, si, rop);
|
||||||
Object.defineProperties(StructCtor.prototype,{
|
Object.defineProperties(StructCtor.prototype,{
|
||||||
debugFlags: debugFlags,
|
debugFlags: debugFlags,
|
||||||
constructor: rop(StructCtor)
|
constructor: rop(StructCtor)
|
||||||
/*if we assign StructCtor.prototype and don't do
|
/*if we assign StructCtor.prototype and don't do
|
||||||
this then StructCtor!==instance.constructor!*/
|
this then StructCtor!==instance.constructor*/
|
||||||
});
|
});
|
||||||
Object.keys(structInfo.members).forEach(
|
|
||||||
(name)=>makeMemberWrapper(StructCtor, name, structInfo.members[name])
|
|
||||||
);
|
let lastMember = false;
|
||||||
|
let offset = 0;
|
||||||
|
//console.warn(structName,"si =",si);
|
||||||
|
si.offset ??= 0;
|
||||||
|
Object.keys(si.members || {}).forEach((k)=>{
|
||||||
|
// Sanity checks of sizeof/offset info...
|
||||||
|
let m = ads(si.members[k]);
|
||||||
|
if(!m.members && !m.sizeof){
|
||||||
|
/* ^^^^ fixme: we need to recursively collect all sizeofs
|
||||||
|
before updating that. */
|
||||||
|
m.sizeof = sigSize(m.signature);
|
||||||
|
if(!m.sizeof){
|
||||||
|
toss(sPropName(structName,k), "is missing a sizeof property.",m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( undefined===m.offset ){
|
||||||
|
m.offset = offset;
|
||||||
|
}
|
||||||
|
si.members[k] = m;
|
||||||
|
if(!lastMember || lastMember.offset < m.offset) lastMember = m;
|
||||||
|
makeMemberWrapper.call(self, StructCtor, k, m)
|
||||||
|
offset += m.sizeof;
|
||||||
|
//console.warn("offset",sPropName(structName,k),offset);
|
||||||
|
});
|
||||||
|
|
||||||
|
if( !lastMember ) toss("No member property descriptions found.");
|
||||||
|
if( !si.sizeof ) si.sizeof = offset;
|
||||||
|
if(si.sizeof===1){
|
||||||
|
(si.signature === 'c' || si.signature === 'C') ||
|
||||||
|
toss("Unexpected sizeof==1 member",
|
||||||
|
sPropName(structName,k),
|
||||||
|
"with signature",si.signature);
|
||||||
|
}else{
|
||||||
|
// sizes and offsets of size-1 members may be odd values, but
|
||||||
|
// others may not.
|
||||||
|
if(0!==(si.sizeof%4)){
|
||||||
|
console.warn("Invalid struct member description",si);
|
||||||
|
toss(structName,"sizeof is not aligned. sizeof="+si.sizeof);
|
||||||
|
}
|
||||||
|
if(0!==(si.offset%4)){
|
||||||
|
console.warn("Invalid struct member description",si);
|
||||||
|
toss(structName,"offset is not aligned. offset="+si.offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( si.sizeof < offset ){
|
||||||
|
console.warn("Suspect struct description:",si,"offset =",offset);
|
||||||
|
toss("Mismatch in the calculated vs. the provided sizeof/offset info.",
|
||||||
|
"Expected sizeof",offset,"but got",si.sizeof,"for",si);
|
||||||
|
}
|
||||||
return StructCtor;
|
return StructCtor;
|
||||||
|
}/*StructBinderImpl*/;
|
||||||
|
|
||||||
|
const StructBinder = function StructBinder(structName, structInfo){
|
||||||
|
return (1==arguments.length)
|
||||||
|
? StructBinderImpl.call(StructBinder, structName)
|
||||||
|
: StructBinderImpl.call(StructBinder, structName, structInfo);
|
||||||
};
|
};
|
||||||
StructBinder.StructType = StructType;
|
StructBinder.StructType = StructType;
|
||||||
StructBinder.config = config;
|
StructBinder.config = config;
|
||||||
StructBinder.allocCString = __allocCString;
|
StructBinder.allocCString = __allocCString;
|
||||||
|
StructBinder.adaptGet = __adaptGet;
|
||||||
|
StructBinder.adaptSet = __adaptSet;
|
||||||
|
StructBinder.adaptStruct = __adaptStruct;
|
||||||
if(!StructBinder.debugFlags){
|
if(!StructBinder.debugFlags){
|
||||||
StructBinder.debugFlags = SBF.__makeDebugFlags(SBF.debugFlags);
|
StructBinder.debugFlags = SBF.__makeDebugFlags(SBF.debugFlags);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ const BuildDefs oBuildDefs = {
|
|||||||
" -DSQLITE_SPEEDTEST1_WASM"
|
" -DSQLITE_SPEEDTEST1_WASM"
|
||||||
" $(SQLITE_OPT)"
|
" $(SQLITE_OPT)"
|
||||||
" -USQLITE_WASM_BARE_BONES"
|
" -USQLITE_WASM_BARE_BONES"
|
||||||
" -USQLITE_C -DSQLITE_C=$(sqlite3.c)"
|
" -USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c)"
|
||||||
" $(speedtest1.exit-runtime0)"
|
" $(speedtest1.exit-runtime0)"
|
||||||
" $(speedtest1.c.in)"
|
" $(speedtest1.c.in)"
|
||||||
" -lm",
|
" -lm",
|
||||||
@@ -312,7 +312,7 @@ const BuildDefs oBuildDefs = {
|
|||||||
" -DSQLITE_SPEEDTEST1_WASM"
|
" -DSQLITE_SPEEDTEST1_WASM"
|
||||||
" $(SQLITE_OPT)"
|
" $(SQLITE_OPT)"
|
||||||
" -USQLITE_WASM_BARE_BONES"
|
" -USQLITE_WASM_BARE_BONES"
|
||||||
" -USQLITE_C -DSQLITE_C=$(sqlite3.c)"
|
" -USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c)"
|
||||||
" $(speedtest1.exit-runtime0)"
|
" $(speedtest1.exit-runtime0)"
|
||||||
" $(speedtest1.c.in)"
|
" $(speedtest1.c.in)"
|
||||||
" -lm",
|
" -lm",
|
||||||
|
|||||||
@@ -1027,7 +1027,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
|||||||
let ptr = k1.pointer;
|
let ptr = k1.pointer;
|
||||||
k1.dispose();
|
k1.dispose();
|
||||||
T.assert(undefined === k1.pointer).
|
T.assert(undefined === k1.pointer).
|
||||||
mustThrowMatching(()=>{k1.$pP=1}, /disposed instance/);
|
mustThrowMatching(()=>{k1.$pP=1}, /disposed struct instance/);
|
||||||
}finally{
|
}finally{
|
||||||
k1.dispose();
|
k1.dispose();
|
||||||
k2.dispose();
|
k2.dispose();
|
||||||
|
|||||||
24
manifest
24
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Fix\sthe\s".www"\scommand\sof\sthe\sCLI\sso\sthat\sit\sworks\son\sunix\ssystems\swith\nnewer\sweb\sbrowsers\sthat\sdo\snot\sallow\saccess\sto\sfiles\sin\s/tmp.
|
C Reworking\sof\sJS\sinternals\sto\ssupport\sbinding\sof\snested\sC\sstructs\s(like\ssqlite3_index_constraint\sand\sfriends)\sand\sallow\ssome\sof\sthe\sautomated\sJS/C\sconversions\sto\sbe\splugged\sin\sat\sthe\sstruct-binding\slevel,\ssimplifying\show\sstruct\smembers,\sin\sparticular\sfunction\spointers,\scan\sbe\sused\sfrom\sJS.
|
||||||
D 2025-11-10T01:46:06.786
|
D 2025-11-10T07:41:54.187
|
||||||
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
|
||||||
@@ -590,10 +590,10 @@ F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e
|
|||||||
F ext/wasm/api/post-js-footer.js 5bd7170b5e8ce7b62102702bbcf47ef7b3b49cd56ed40c043fd990aa715b74ee
|
F ext/wasm/api/post-js-footer.js 5bd7170b5e8ce7b62102702bbcf47ef7b3b49cd56ed40c043fd990aa715b74ee
|
||||||
F ext/wasm/api/post-js-header.js 79d078aec33d93b640a19c574b504d88bb2446432f38e2fbb3bb8e36da436e70
|
F ext/wasm/api/post-js-header.js 79d078aec33d93b640a19c574b504d88bb2446432f38e2fbb3bb8e36da436e70
|
||||||
F ext/wasm/api/pre-js.c-pp.js a876c6399dff29b6fe9e434036beb89889164cc872334e184291723ecc7cb072
|
F ext/wasm/api/pre-js.c-pp.js a876c6399dff29b6fe9e434036beb89889164cc872334e184291723ecc7cb072
|
||||||
F ext/wasm/api/sqlite3-api-cleanup.js a3d6b9e449aefbb8bba283c2ba9477e2333a0eeb94a7a26b5bf952736f65a6dd
|
F ext/wasm/api/sqlite3-api-cleanup.js 79b54a566291e17c0c3e165c6c4969c48ec17cd297755180151af65ac616dfa0
|
||||||
F ext/wasm/api/sqlite3-api-glue.c-pp.js 79a54b54ca6324d28e31e19b56bbaebb7d2cc4b3079066e7e901333fa5047c53
|
F ext/wasm/api/sqlite3-api-glue.c-pp.js 79a54b54ca6324d28e31e19b56bbaebb7d2cc4b3079066e7e901333fa5047c53
|
||||||
F ext/wasm/api/sqlite3-api-oo1.c-pp.js 31dbfd470c91ffd96d77399b749bab6b69e3ba9074188833f97ac13f087cf07b
|
F ext/wasm/api/sqlite3-api-oo1.c-pp.js 31dbfd470c91ffd96d77399b749bab6b69e3ba9074188833f97ac13f087cf07b
|
||||||
F ext/wasm/api/sqlite3-api-prologue.js 307583ff39a978c897c4ef4ce53fe231dce5c73dc84785969c81c1ab5960a293
|
F ext/wasm/api/sqlite3-api-prologue.js b6b2fd1720c484e168705909862442b4524a1e61e16b4549a5725dd28c3cecc2
|
||||||
F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938
|
F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938
|
||||||
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
|
F ext/wasm/api/sqlite3-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
|
||||||
@@ -608,7 +608,7 @@ F ext/wasm/c-pp-lite.c 8fa0148e73782a86274db688c4730e2962cd675af329490493adddaf3
|
|||||||
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 0d539324097fc83b953e9844267359ba0fd02286caa784ea2f597ced279ea640
|
F ext/wasm/common/whwasmutil.js b4fd73fac162406e67f276647ff8bae51881e15eebdf4b725aeb2b10ab1e056a
|
||||||
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
|
||||||
@@ -625,10 +625,10 @@ F ext/wasm/fiddle/fiddle.js 84fd75967e0af8b69d3dd849818342227d0f81d13db92e0dcbc6
|
|||||||
F ext/wasm/fiddle/index.html a27b8127ef9ecf19612da93b2a6a73bdb3777b5c56b5450bb7200a94bc108ff9
|
F ext/wasm/fiddle/index.html a27b8127ef9ecf19612da93b2a6a73bdb3777b5c56b5450bb7200a94bc108ff9
|
||||||
F ext/wasm/index-dist.html db23748044e286773f2768eec287669501703b5d5f72755e8db73607dc54d290
|
F ext/wasm/index-dist.html db23748044e286773f2768eec287669501703b5d5f72755e8db73607dc54d290
|
||||||
F ext/wasm/index.html 54e27db740695ab2cb296e02d42c4c66b3f11b65797340d19fa6590f5b287da1
|
F ext/wasm/index.html 54e27db740695ab2cb296e02d42c4c66b3f11b65797340d19fa6590f5b287da1
|
||||||
F ext/wasm/jaccwabyt/jaccwabyt.js bbac67bc7a79dca34afe6215fd16b27768d84e22273507206f888c117e2ede7d
|
F ext/wasm/jaccwabyt/jaccwabyt.js 1e734c624205cdf621f322972dfb0fc8013d573a5882f57492a6830e5ec23e17
|
||||||
F ext/wasm/jaccwabyt/jaccwabyt.md 167fc0b624c9bc2c477846e336de9403842d81b1a24fc4d3b24317cb9eba734f
|
F ext/wasm/jaccwabyt/jaccwabyt.md 167fc0b624c9bc2c477846e336de9403842d81b1a24fc4d3b24317cb9eba734f
|
||||||
F ext/wasm/mkdist.sh 64d53f469c823ed311f6696f69cec9093f745e467334b34f5ceabdf9de3c5b28 x
|
F ext/wasm/mkdist.sh 64d53f469c823ed311f6696f69cec9093f745e467334b34f5ceabdf9de3c5b28 x
|
||||||
F ext/wasm/mkwasmbuilds.c 5e194df8763c8e5b2de070575a5f1bc7d7fb862f03c09d3cb9c56e0fa57b7e77
|
F ext/wasm/mkwasmbuilds.c 1b53c4d2a1350c19a96a8cdfbda6a39baea9d2142bfe0cbef0ccb0e898787f47
|
||||||
F ext/wasm/module-symbols.html e54f42112e0aac2a31f850ab33e7f2630a2ea4f63496f484a12469a2501e07e2
|
F ext/wasm/module-symbols.html e54f42112e0aac2a31f850ab33e7f2630a2ea4f63496f484a12469a2501e07e2
|
||||||
F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96
|
F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96
|
||||||
F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63
|
F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63
|
||||||
@@ -644,7 +644,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
|
|||||||
F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c
|
F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c
|
||||||
F ext/wasm/tester1-worker.c-pp.html 0e432ec2c0d99cd470484337066e8d27e7aee4641d97115338f7d962bf7b081a
|
F ext/wasm/tester1-worker.c-pp.html 0e432ec2c0d99cd470484337066e8d27e7aee4641d97115338f7d962bf7b081a
|
||||||
F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb
|
F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb
|
||||||
F ext/wasm/tester1.c-pp.js 56a7889415b996f684765aff07d35ac8a31343201f887ac61d7dd14678d9f0f0
|
F ext/wasm/tester1.c-pp.js 2c255093205a0dac9dae7475030665c2c9d6dccc857de68ee7daf49aa82e6de8
|
||||||
F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e
|
F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e
|
||||||
F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88
|
F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88
|
||||||
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
|
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
|
||||||
@@ -2167,8 +2167,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd
|
|||||||
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
||||||
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
|
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
|
||||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||||
P a1f9c977b83fab11c54710070dbedfaea47195050946db74075bdd3ade97a4c8
|
P 2f918c14bac28c567cc854b3d41dcdd59191a118bb5fdea9373945fe860161f5
|
||||||
R 433947701e1e8d1dbfecf3626f6f1737
|
R ec4a247d32a2beb55a1852fe7b3a7b07
|
||||||
U drh
|
U stephan
|
||||||
Z bf0d9abc0630918a2bdb7897b1798077
|
Z 6d1537ab535678201b3302bce4da7f8d
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2f918c14bac28c567cc854b3d41dcdd59191a118bb5fdea9373945fe860161f5
|
bb4fd5b789cebf2b224c29023fea3e620a86fb36730c36c0d85d9f35880bf643
|
||||||
|
|||||||
Reference in New Issue
Block a user