From e1774479727bd2093f7bfcf38fd52a28eca6ff04 Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 5 Dec 2022 05:30:03 +0000 Subject: [PATCH 01/22] Initial infrastructure for adding virtual table/table-valued function support to WASM. FossilOrigin-Name: c202d7a0398b9aabc2babba5c4c91a313f32bbf37549d419775642bb4aa3936a --- ext/wasm/api/sqlite3-api-glue.js | 48 ++++++--- ext/wasm/api/sqlite3-wasm.c | 164 ++++++++++++++++++++++++++++++- ext/wasm/common/whwasmutil.js | 26 +++-- ext/wasm/jaccwabyt/jaccwabyt.js | 40 +++++--- ext/wasm/jaccwabyt/jaccwabyt.md | 30 +++--- manifest | 26 ++--- manifest.uuid | 2 +- 7 files changed, 269 insertions(+), 67 deletions(-) diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js index ac1e9fd6d6..eddcfddd1e 100644 --- a/ext/wasm/api/sqlite3-api-glue.js +++ b/ext/wasm/api/sqlite3-api-glue.js @@ -603,13 +603,16 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ } wasm.ctype = JSON.parse(wasm.cstringToJs(cJson)); //console.debug('wasm.ctype length =',wasm.cstrlen(cJson)); - for(const t of ['access', 'blobFinalizers', 'dataTypes', - 'encodings', 'fcntl', 'flock', 'ioCap', - 'limits', - 'openFlags', 'prepareFlags', 'resultCodes', - 'serialize', 'syncFlags', 'trace', 'udfFlags', - 'version' - ]){ + const defineGroups = ['access', 'blobFinalizers', 'dataTypes', + 'encodings', 'fcntl', 'flock', 'ioCap', + 'limits', + 'openFlags', 'prepareFlags', 'resultCodes', + 'serialize', 'syncFlags', 'trace', 'udfFlags', + 'version' ]; + if(wasm.bigIntEnabled){ + defineGroups.push('vtab'); + } + for(const t of defineGroups){ for(const e of Object.entries(wasm.ctype[t])){ // ^^^ [k,v] there triggers a buggy code transformation via // one of the Emscripten-driven optimizers. @@ -629,19 +632,33 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ capi.sqlite3_js_rc_str = (rc)=>__rcMap[rc]; /* Bind all registered C-side structs... */ const notThese = Object.assign(Object.create(null),{ - // Structs NOT to register - WasmTestStruct: true - }); - if(!util.isUIThread()){ + // For each struct to NOT register, map its name to false: + WasmTestStruct: true, /* We remove the kvvfs VFS from Worker threads below. */ - notThese.sqlite3_kvvfs_methods = true; - } + sqlite3_kvvfs_methods: !util.isUIThread(), + sqlite3_index_info: !wasm.bigIntEnabled, + sqlite3_index_constraint: !wasm.bigIntEnabled, + sqlite3_index_orderby: !wasm.bigIntEnabled, + sqlite3_index_constraint_usage: !wasm.bigIntEnabled + }); for(const s of wasm.ctype.structs){ if(!notThese[s.name]){ capi[s.name] = sqlite3.StructBinder(s); } } - }/*end C constant imports*/ + if(capi.sqlite3_index_info){ + /* Move these inner structs into sqlite3_index_info. Binding + ** them to WASM requires that we create global-scope structs to + ** model them with, but those are no longer needed after we've + ** passed them to StructBinder. */ + for(const k of ['sqlite3_index_constraint', + 'sqlite3_index_orderby', + 'sqlite3_index_constraint_usage']){ + capi.sqlite3_index_info[k] = capi[k]; + delete capi[k]; + } + } + }/*end C constant and struct imports*/ const pKvvfs = capi.sqlite3_vfs_find("kvvfs"); if( pKvvfs ){/* kvvfs-specific glue */ @@ -652,8 +669,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ delete capi.sqlite3_kvvfs_methods; const kvvfsMakeKey = wasm.exports.sqlite3_wasm_kvvfsMakeKeyOnPstack, - pstack = wasm.pstack, - pAllocRaw = wasm.exports.sqlite3_wasm_pstack_alloc; + pstack = wasm.pstack; const kvvfsStorage = (zClass)=> ((115/*=='s'*/===wasm.getMemValue(zClass)) diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c index f6499243a6..dc5dff62a7 100644 --- a/ext/wasm/api/sqlite3-wasm.c +++ b/ext/wasm/api/sqlite3-wasm.c @@ -368,7 +368,7 @@ void sqlite3_wasm_test_struct(WasmTestStruct * s){ */ SQLITE_WASM_KEEP const char * sqlite3_wasm_enum_json(void){ - static char aBuffer[1024 * 12] = {0} /* where the JSON goes */; + static char aBuffer[1024 * 16] = {0} /* where the JSON goes */; int n = 0, nChildren = 0, nStruct = 0 /* output counters for figuring out where commas go */; char * zPos = &aBuffer[1] /* skip first byte for now to help protect @@ -410,6 +410,14 @@ const char * sqlite3_wasm_enum_json(void){ DefInt(SQLITE_ACCESS_READ)/*docs say this is unused*/; } _DefGroup; +#if 0 + /* TODO? Authorizer... */ + DefGroup(authorizer){ + DefInt(SQLITE_DENY); + DefInt(SQLITE_IGNORE); + } _DefGroup; +#endif + DefGroup(blobFinalizers) { /* SQLITE_STATIC/TRANSIENT need to be handled explicitly as ** integers to avoid casting-related warnings. */ @@ -681,7 +689,28 @@ const char * sqlite3_wasm_enum_json(void){ DefStr(SQLITE_VERSION); DefStr(SQLITE_SOURCE_ID); } _DefGroup; - + + DefGroup(vtab) { + DefInt(SQLITE_INDEX_SCAN_UNIQUE); + DefInt(SQLITE_INDEX_CONSTRAINT_EQ); + DefInt(SQLITE_INDEX_CONSTRAINT_GT); + DefInt(SQLITE_INDEX_CONSTRAINT_LE); + DefInt(SQLITE_INDEX_CONSTRAINT_LT); + DefInt(SQLITE_INDEX_CONSTRAINT_GE); + DefInt(SQLITE_INDEX_CONSTRAINT_MATCH); + DefInt(SQLITE_INDEX_CONSTRAINT_LIKE); + DefInt(SQLITE_INDEX_CONSTRAINT_GLOB); + DefInt(SQLITE_INDEX_CONSTRAINT_REGEXP); + DefInt(SQLITE_INDEX_CONSTRAINT_NE); + DefInt(SQLITE_INDEX_CONSTRAINT_ISNOT); + DefInt(SQLITE_INDEX_CONSTRAINT_ISNOTNULL); + DefInt(SQLITE_INDEX_CONSTRAINT_ISNULL); + DefInt(SQLITE_INDEX_CONSTRAINT_IS); + DefInt(SQLITE_INDEX_CONSTRAINT_LIMIT); + DefInt(SQLITE_INDEX_CONSTRAINT_OFFSET); + DefInt(SQLITE_INDEX_CONSTRAINT_FUNCTION); + } _DefGroup; + #undef DefGroup #undef DefStr #undef DefInt @@ -793,6 +822,137 @@ const char * sqlite3_wasm_enum_json(void){ } _StructBinder; #undef CurrentStruct + +#define CurrentStruct sqlite3_vtab + StructBinder { + M(pModule, "p"); + M(nRef, "i"); + M(zErrMsg, "p"); + } _StructBinder; +#undef CurrentStruct + +#define CurrentStruct sqlite3_vtab_cursor + StructBinder { + M(pVtab, "p"); + } _StructBinder; +#undef CurrentStruct + +#define CurrentStruct sqlite3_module + StructBinder { + M(iVersion, "i"); + M(xCreate, "i(ppippp)"); + M(xConnect, "i(ppippp)"); + M(xBestIndex, "i(pp)"); + M(xDisconnect, "i(p)"); + M(xDestroy, "i(p)"); + M(xOpen, "i(pp)"); + M(xClose, "i(p)"); + M(xFilter, "i(pisip)"); + M(xNext, "i(p)"); + M(xEof, "i(p)"); + M(xColumn, "i(ppi)"); + M(xRowid, "i(pp)"); + M(xUpdate, "i(pipp)"); + M(xBegin, "i(p)"); + M(xSync, "i(p)"); + M(xCommit, "i(p)"); + M(xRollback, "i(p)"); + M(xFindFunction, "i(pispp)"); + M(xRename, "i(ps)"); + // ^^^ v1. v2+ follows... + M(xSavepoint, "i(pi)"); + M(xRelease, "i(pi)"); + M(xRollbackTo, "i(pi)"); + // ^^^ v2. v3+ follows... + M(xShadowName, "i(s)"); + } _StructBinder; +#undef CurrentStruct + /* + module/vtab todos: + + - sqlite3_create_module() + - sqlite3_create_module_v2() + - sqlite3_drop_modules() + - sqlite3_declare_vtab() + - sqlite3_overload_function() + */ + + /** + ** Workaround: in order to map the various inner structs from + ** sqlite3_index_info, we have to uplift those into constructs we + ** can access by type name. These structs _must_ match their + ** in-sqlite3_index_info counterparts byte for byte. + */ + typedef struct { + int iColumn; + unsigned char op; + unsigned char usable; + int iTermOffset; + } sqlite3_index_constraint; + typedef struct { + int iColumn; + unsigned char desc; + } sqlite3_index_orderby; + typedef struct { + int argvIndex; + unsigned char omit; + } sqlite3_index_constraint_usage; + { /* Validate that the above struct sizeof()s match + ** expectations. We could improve upon this by + ** checking the offsetof() for each member. */ + const sqlite3_index_info siiCheck; +#define IndexSzCheck(T,M) \ + (sizeof(T) == sizeof(*siiCheck.M)) + if(!IndexSzCheck(sqlite3_index_constraint,aConstraint) + || !IndexSzCheck(sqlite3_index_orderby,aOrderBy) + || !IndexSzCheck(sqlite3_index_constraint_usage,aConstraintUsage)){ + assert(!"sizeof mismatch in sqlite3_index_... struct(s)"); + return 0; + } +#undef IndexSzCheck + } + +#define CurrentStruct sqlite3_index_constraint + StructBinder { + M(iColumn, "i"); + M(op, "C"); + M(usable, "C"); + M(iTermOffset, "i"); + } _StructBinder; +#undef CurrentStruct + +#define CurrentStruct sqlite3_index_orderby + StructBinder { + M(iColumn, "i"); + M(desc, "C"); + } _StructBinder; +#undef CurrentStruct + +#define CurrentStruct sqlite3_index_constraint_usage + StructBinder { + M(argvIndex, "i"); + M(omit, "C"); + } _StructBinder; +#undef CurrentStruct + +#define CurrentStruct sqlite3_index_info + StructBinder { + M(nConstraint, "i"); + M(aConstraint, "p"); + M(nOrderBy, "i"); + M(aOrderBy, "p"); + M(aConstraintUsage, "p"); + M(idxNum, "i"); + M(idxStr, "p"); + M(needToFreeIdxStr, "i"); + M(orderByConsumed, "i"); + M(estimatedCost, "d"); + M(estimatedRows, "j"); + M(idxFlags, "i"); + M(colUsed, "j"); + } _StructBinder; +#undef CurrentStruct + #if SQLITE_WASM_TESTS #define CurrentStruct WasmTestStruct StructBinder { diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js index 8cb4833247..84d829daba 100644 --- a/ext/wasm/common/whwasmutil.js +++ b/ext/wasm/common/whwasmutil.js @@ -1081,10 +1081,9 @@ self.WhWasmUtilInstaller = function(target){ // impl for allocMainArgv() and scopedAllocMainArgv(). const __allocMainArgv = function(isScoped, list){ - if(!list.length) toss("Cannot allocate empty array."); const pList = target[ isScoped ? 'scopedAlloc' : 'alloc' - ](list.length * target.ptrSizeof); + ]((list.length + 1) * target.ptrSizeof); let i = 0; list.forEach((e)=>{ target.setPtrValue(pList + (target.ptrSizeof * i++), @@ -1092,26 +1091,33 @@ self.WhWasmUtilInstaller = function(target){ isScoped ? 'scopedAllocCString' : 'allocCString' ](""+e)); }); + target.setPtrValue(pList + (target.ptrSizeof * i), 0); return pList; }; /** Creates an array, using scopedAlloc(), suitable for passing to a C-level main() routine. The input is a collection with a length - property and a forEach() method. A block of memory list.length - entries long is allocated and each pointer-sized block of that - memory is populated with a scopedAllocCString() conversion of the - (""+value) of each element. Returns a pointer to the start of the - list, suitable for passing as the 2nd argument to a C-style - main() function. + property and a forEach() method. A block of memory + (list.length+1) entries long is allocated and each pointer-sized + block of that memory is populated with a scopedAllocCString() + conversion of the (""+value) of each element, with the exception + that the final entry is a NULL pointer. Returns a pointer to the + start of the list, suitable for passing as the 2nd argument to a + C-style main() function. - Throws if list.length is falsy or scopedAllocPush() is not active. + Throws if scopedAllocPush() is not active. + + Design note: the returned array is allocated with an extra NULL + pointer entry to accommodate certain APIs, but client code which + does not need that functionality should treat the returned array + as list.length entries long. */ target.scopedAllocMainArgv = (list)=>__allocMainArgv(true, list); /** Identical to scopedAllocMainArgv() but uses alloc() instead of - scopedAllocMainArgv + scopedAlloc(). */ target.allocMainArgv = (list)=>__allocMainArgv(false, list); diff --git a/ext/wasm/jaccwabyt/jaccwabyt.js b/ext/wasm/jaccwabyt/jaccwabyt.js index dee7258c51..81b4c1bd4f 100644 --- a/ext/wasm/jaccwabyt/jaccwabyt.js +++ b/ext/wasm/jaccwabyt/jaccwabyt.js @@ -121,6 +121,7 @@ self.Jaccwabyt = function StructBinderFactory(config){ at SIG s[0]. Throws for an unknown SIG. */ const sigIR = function(s){ switch(sigLetter(s)){ + case 'c': case 'C': return 'i8'; case 'i': return 'i32'; case 'p': case 'P': case 's': return ptrIR; case 'j': return 'i64'; @@ -133,6 +134,7 @@ self.Jaccwabyt = function StructBinderFactory(config){ unknown SIG. */ const sigSizeof = function(s){ switch(sigLetter(s)){ + case 'c': case 'C': return 1; case 'i': return 4; case 'p': case 'P': case 's': return ptrSizeof; case 'j': return 8; @@ -168,6 +170,8 @@ self.Jaccwabyt = function StructBinderFactory(config){ break; } case 'i': return 'getInt32'; + case 'c': return 'getInt8'; + case 'C': return 'getUint8'; case 'j': return affirmBigIntArray() && 'getBigInt64'; case 'f': return 'getFloat32'; case 'd': return 'getFloat64'; @@ -186,6 +190,8 @@ self.Jaccwabyt = function StructBinderFactory(config){ break; } case 'i': return 'setInt32'; + case 'c': return 'setInt8'; + case 'C': return 'setUint8'; case 'j': return affirmBigIntArray() && 'setBigInt64'; case 'f': return 'setFloat32'; case 'd': return 'setFloat64'; @@ -199,7 +205,7 @@ self.Jaccwabyt = function StructBinderFactory(config){ */ const sigDVSetWrapper = function(s){ switch(sigLetter(s)) { - case 'i': case 'f': case 'd': return Number; + case 'i': case 'f': case 'c': case 'C': case 'd': return Number; case 'j': return affirmBigIntArray() && BigInt; case 'p': case 'P': case 's': switch(ptrSizeof){ @@ -361,7 +367,7 @@ self.Jaccwabyt = function StructBinderFactory(config){ framework's native format or in Emscripten format. */ const __memberSignature = function f(obj,memberName,emscriptenFormat=false){ - if(!f._) f._ = (x)=>x.replace(/[^vipPsjrd]/g,"").replace(/[pPs]/g,'i'); + if(!f._) f._ = (x)=>x.replace(/[^vipPsjrdcC]/g,"").replace(/[pPscC]/g,'i'); const m = __lookupMember(obj.structInfo, memberName, true); return emscriptenFormat ? f._(m.signature) : m.signature; }; @@ -570,7 +576,7 @@ self.Jaccwabyt = function StructBinderFactory(config){ /*cache all available getters/setters/set-wrappers for direct reuse in each accessor function. */ f._ = {getters: {}, setters: {}, sw:{}}; - const a = ['i','p','P','s','f','d','v()']; + const a = ['i','c','C','p','P','s','f','d','v()']; if(bigIntEnabled) a.push('j'); a.forEach(function(v){ //const ir = sigIR(v); @@ -579,8 +585,8 @@ self.Jaccwabyt = function StructBinderFactory(config){ f._.sw[v] = sigDVSetWrapper(v) /* BigInt or Number ctor to wrap around values for conversion */; }); - const rxSig1 = /^[ipPsjfd]$/, - rxSig2 = /^[vipPsjfd]\([ipPsjfd]*\)$/; + const rxSig1 = /^[ipPsjfdcC]$/, + rxSig2 = /^[vipPsjfdcC]\([ipPsjfdcC]*\)$/; f.sigCheck = function(obj, name, key,sig){ if(Object.prototype.hasOwnProperty.call(obj, key)){ toss(obj.structName,'already has a property named',key+'.'); @@ -594,7 +600,6 @@ self.Jaccwabyt = function StructBinderFactory(config){ f.sigCheck(ctor.prototype, name, key, descr.signature); descr.key = key; descr.name = name; - const sizeOf = sigSizeof(descr.signature); const sigGlyph = sigLetter(descr.signature); const xPropName = sPropName(ctor.prototype.structName,key); const dbg = ctor.prototype.debugFlags.__flags; @@ -610,10 +615,10 @@ self.Jaccwabyt = function StructBinderFactory(config){ prop.get = function(){ if(dbg.getter){ log("debug.getter:",f._.getters[sigGlyph],"for", sigIR(sigGlyph), - xPropName,'@', this.pointer,'+',descr.offset,'sz',sizeOf); + xPropName,'@', this.pointer,'+',descr.offset,'sz',descr.sizeof); } let rc = ( - new DataView(heap().buffer, this.pointer + descr.offset, sizeOf) + new DataView(heap().buffer, this.pointer + descr.offset, descr.sizeof) )[f._.getters[sigGlyph]](0, isLittleEndian); if(dbg.getter) log("debug.getter:",xPropName,"result =",rc); if(rc && isAutoPtrSig(descr.signature)){ @@ -628,7 +633,7 @@ self.Jaccwabyt = function StructBinderFactory(config){ prop.set = function(v){ if(dbg.setter){ log("debug.setter:",f._.setters[sigGlyph],"for", sigIR(sigGlyph), - xPropName,'@', this.pointer,'+',descr.offset,'sz',sizeOf, v); + xPropName,'@', this.pointer,'+',descr.offset,'sz',descr.sizeof, v); } if(!this.pointer){ toss("Cannot set struct property on disposed instance."); @@ -644,7 +649,7 @@ self.Jaccwabyt = function StructBinderFactory(config){ toss("Invalid value for pointer-type",xPropName+'.'); } ( - new DataView(heap().buffer, this.pointer + descr.offset, sizeOf) + new DataView(heap().buffer, this.pointer + descr.offset, descr.sizeof) )[f._.setters[sigGlyph]](0, f._.sw[sigGlyph](v), isLittleEndian); }; } @@ -665,13 +670,18 @@ self.Jaccwabyt = function StructBinderFactory(config){ 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(0!==(m.sizeof%4)){ - toss(structName,"member",k,"sizeof is not aligned."); - } - else if(0!==(m.offset%4)){ - toss(structName,"member",k,"offset is not aligned."); + else if(m.sizeof>1){ // offsets of size-1 members may be odd values. + if(0!==(m.sizeof%4)){ + console.warn("Invalid struct description =",m,"from",structInfo.members); + toss(structName,"member",k,"sizeof is not aligned. sizeof="+m.sizeof); + } + if(0!==(m.offset%4)){ + console.warn("Invalid struct description =",m,"from",structInfo.members); + toss(structName,"member",k,"offset is not aligned. offset="+m.offset); + } } if(!lastMember || lastMember.offset < m.offset) lastMember = m; }); diff --git a/ext/wasm/jaccwabyt/jaccwabyt.md b/ext/wasm/jaccwabyt/jaccwabyt.md index edcba260a7..73f6bfa947 100644 --- a/ext/wasm/jaccwabyt/jaccwabyt.md +++ b/ext/wasm/jaccwabyt/jaccwabyt.md @@ -281,21 +281,29 @@ supported letters are: signature entry. - **`f`** = `float` (4 bytes) - **`d`** = `double` (8 bytes) -- **`p`** = `int32` (but see below!) +- **`c`** = `int8` (char - see notes below!) +- **`C`** = `int8` (unsigned char - see notes below!) +- **`p`** = `int32` (see notes below!) - **`P`** = Like `p` but with extra handling. Described below. -- **`s`** = like `int32` but is a _hint_ that it's a pointer to a string - so that _some_ (very limited) contexts may treat it as such, noting - such algorithms must, for lack of information to the contrary, - assume both that the encoding is UTF-8 and that the pointer's member - is NUL-terminated. If that is _not_ the case for a given string - member, do not use `s`: use `i` or `p` instead and do any string - handling yourself. +- **`s`** = like `int32` but is a _hint_ that it's a pointer to a + string so that _some_ (very limited) contexts may treat it as such, + noting that such algorithms must, for lack of information to the + contrary, assume both that the encoding is UTF-8 and that the + pointer's member is NUL-terminated. If that is _not_ the case for a + given string member, do not use `s`: use `i` or `p` instead and do + any string handling yourself. Noting that: - All of these types are numeric. Attempting to set any struct-bound property to a non-numeric value will trigger an exception except in cases explicitly noted otherwise. +- "Char" types: WASM does not define an `int8` type, nor does it + distinguish between signed and unsigned. This API treats `c` as + `int8` and `C` as `uint8` for purposes of getting and setting values + when using the `DataView` class. It is _not_ recommended that client + code use these types in new WASM-capable code, but they were added + for the sake of binding some immutable legacy code to WASM. > Sidebar: Emscripten's public docs do not mention `p`, but their generated code includes `p` as an alias for `i`, presumably to mean @@ -317,12 +325,12 @@ Signatures in the form `x(...)` denote function-pointer members and form `x()`. For function-type signatures, the strings are formulated such that they can be passed to Emscripten's `addFunction()` after stripping out the `(` and `)` characters. For good measure, to match -the public Emscripten docs, `p` should also be replaced with `i`. In -JavaScript that might look like: +the public Emscripten docs, `p`, `c`, and `C`, should also be replaced +with `i`. In JavaScript that might look like: > ``` -signature.replace(/[^vipPsjfd]/g,'').replace(/[pPs]/g,'i'); +signature.replace(/[^vipPsjfdcC]/g,'').replace(/[pPscC]/g,'i'); ``` diff --git a/manifest b/manifest index 27a4331f16..7d4a4ffa9e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\squery\splanner\scost\sestimates.\s\sFix\sfor\sticket\s[e8b674241947eb3b]. -D 2022-12-05T02:52:37.959 +C Initial\sinfrastructure\sfor\sadding\svirtual\stable/table-valued\sfunction\ssupport\sto\sWASM. +D 2022-12-05T05:30:03.152 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -503,7 +503,7 @@ F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08 F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62 F ext/wasm/api/pre-js.c-pp.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f9e91c1d5f F ext/wasm/api/sqlite3-api-cleanup.js 680d5ccfff54459db136a49b2199d9f879c8405d9c99af1dda0cc5e7c29056f4 -F ext/wasm/api/sqlite3-api-glue.js 6fe39964605fda3b699f69365eed565b5172d29cab2c49bc057a43f9a93f9f36 +F ext/wasm/api/sqlite3-api-glue.js 6028d0c3e6f475a513040a45612238b749ec6c155181d5bd029d66577ab4d0d6 F ext/wasm/api/sqlite3-api-oo1.js 91a7d7b9203fb0f031e6ba380a644a7f871e1798b388de399c01ed4087bac9e0 F ext/wasm/api/sqlite3-api-prologue.js 697a5989ad52a9ba7bc60b5436589bd05885ee2201d84c38c5e9af3876af3ba4 F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f @@ -512,7 +512,7 @@ F ext/wasm/api/sqlite3-opfs-async-proxy.js f79dd8d98ef3e0b55c10bb2bee7a3840fa967 F ext/wasm/api/sqlite3-vfs-helper.js 4ad4faf02e1524bf0296be8452c00b5708dce6faf649468d0377e26a0b299263 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 29d6487a26b2fb6a471cde52c37ffee7c27ed6a91914b308c247e0706f454ffb F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 -F ext/wasm/api/sqlite3-wasm.c b0babf8435f31d21f28454fb81433aa538c68b23d0a4a251f0666fdec4e71f59 +F ext/wasm/api/sqlite3-wasm.c 5120fb3419aba02d20cbe1e645b58dae5faeaaae8ccd46b8931ae04d311df9e5 F ext/wasm/api/sqlite3-worker1-promiser.js 0c7a9826dbf82a5ed4e4f7bf7816e825a52aff253afbf3350431f5773faf0e4b F ext/wasm/api/sqlite3-worker1.js 1e54ea3d540161bcfb2100368a2fc0cad871a207b8336afee1c445715851ec54 F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8 @@ -521,7 +521,7 @@ F ext/wasm/c-pp.c 92285f7bce67ed7b7020b40fde8ed0982c442b63dc33df9dfd4b658d4a6c07 F ext/wasm/common/SqliteTestUtil.js d8bf97ecb0705a2299765c8fc9e11b1a5ac7f10988bbf375a6558b7ca287067b F ext/wasm/common/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f F ext/wasm/common/testing.css 35889709547d89a6109ff83b25c11bbc91d8dd43aab8722e428655ca98880a06 -F ext/wasm/common/whwasmutil.js c1bc5715cd96728929cc31d788b16152ccbd6b2e111d2e88fbc9725247e67b4f +F ext/wasm/common/whwasmutil.js 1bc1c973662db7d52763512e67c2369fdbfe9e8bae33069ac89f4fbe40d678b2 F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508 F ext/wasm/demo-123.js ebae30756585bca655b4ab2553ec9236a87c23ad24fc8652115dcedb06d28df6 @@ -539,8 +539,8 @@ F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5 F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2 F ext/wasm/index-dist.html c806b6005145b71d64240606e9c6e0bf56878ee8829c66fe7486cebf34b0e6b1 F ext/wasm/index.html f151b7c7b5cfdc066567d556acd168e769efd4e982286dc5f849a5ee69ecd0ff -F ext/wasm/jaccwabyt/jaccwabyt.js 95f573de1826474c9605dda620ee622fcb1673ae74f191eb324c0853aa4dcb66 -F ext/wasm/jaccwabyt/jaccwabyt.md 9aa6951b529a8b29f578ec8f0355713c39584c92cf1708f63ba0cf917cb5b68e +F ext/wasm/jaccwabyt/jaccwabyt.js 7c41784c442aa67f0e86e7c14aa51b3a28e3b21eb579c71c16af3c988fbf966f +F ext/wasm/jaccwabyt/jaccwabyt.md 50df3ccb7a773634000496a2ccb805dd25cf8cd963696a7deec3209a68c6093b F ext/wasm/module-symbols.html 980680c8acfa3c8ae6a5aa223512d1b8e78040ced20f8ba2c382129bc73ec028 F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06 F ext/wasm/scratchpad-wasmfs-main.js 4c140457f4d6da9d646a49addd91edb6e9ad1643c6c48e3258b5bce24725dc18 @@ -2065,9 +2065,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P cefc032473ac5ad244c0b6402c541b2f76c0c65a041bda03bfbe7c0e2c11fac2 df3818997b822743ac407dde45c5fd75845ca40f461e31350d86963dffec6cd6 -R 3c93957174c9bb89beba8a6d7c9fdaab -T +closed df3818997b822743ac407dde45c5fd75845ca40f461e31350d86963dffec6cd6 -U drh -Z 2d83b2d52ce6d0637e1b84504b86ac00 +P 1b779afa3ed2f35a110e460fc6ed13cba744db85b9924149ab028b100d1e1e12 +R b429259a443dd7b0ac8ceede26128588 +T *branch * wasm-vtab +T *sym-wasm-vtab * +T -sym-trunk * Cancelled\sby\sbranch. +U stephan +Z bd980b10d448d088ee0cbb8238fc2a43 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 452c8ac5d7..f70604b10c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1b779afa3ed2f35a110e460fc6ed13cba744db85b9924149ab028b100d1e1e12 \ No newline at end of file +c202d7a0398b9aabc2babba5c4c91a313f32bbf37549d419775642bb4aa3936a \ No newline at end of file From 864c3c029b869e5bfc58fcdf35f883e38c2cfa0d Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 5 Dec 2022 05:45:00 +0000 Subject: [PATCH 02/22] Remove some dead code. Improve some error checks and comments. FossilOrigin-Name: 6712fbe46a97867cea309f78a274edbb6bd166a505b41e18a580306da0e063db --- ext/wasm/api/sqlite3-api-glue.js | 5 ++-- ext/wasm/jaccwabyt/jaccwabyt.js | 42 ++++++++++---------------------- manifest | 17 ++++++------- manifest.uuid | 2 +- 4 files changed, 24 insertions(+), 42 deletions(-) diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js index eddcfddd1e..582b0c0a30 100644 --- a/ext/wasm/api/sqlite3-api-glue.js +++ b/ext/wasm/api/sqlite3-api-glue.js @@ -632,10 +632,11 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ capi.sqlite3_js_rc_str = (rc)=>__rcMap[rc]; /* Bind all registered C-side structs... */ const notThese = Object.assign(Object.create(null),{ - // For each struct to NOT register, map its name to false: + // For each struct to NOT register, map its name to true: WasmTestStruct: true, - /* We remove the kvvfs VFS from Worker threads below. */ + /* We unregister the kvvfs VFS from Worker threads below. */ sqlite3_kvvfs_methods: !util.isUIThread(), + /* sqlite3_index_info and friends require int64: */ sqlite3_index_info: !wasm.bigIntEnabled, sqlite3_index_constraint: !wasm.bigIntEnabled, sqlite3_index_orderby: !wasm.bigIntEnabled, diff --git a/ext/wasm/jaccwabyt/jaccwabyt.js b/ext/wasm/jaccwabyt/jaccwabyt.js index 81b4c1bd4f..7c8d42b331 100644 --- a/ext/wasm/jaccwabyt/jaccwabyt.js +++ b/ext/wasm/jaccwabyt/jaccwabyt.js @@ -130,34 +130,9 @@ self.Jaccwabyt = function StructBinderFactory(config){ } toss("Unhandled signature IR:",s); }; - /** Returns the sizeof value for the given SIG. Throws for an - unknown SIG. */ - const sigSizeof = function(s){ - switch(sigLetter(s)){ - case 'c': case 'C': return 1; - case 'i': return 4; - case 'p': case 'P': case 's': return ptrSizeof; - case 'j': return 8; - case 'f': return 4 /* C-side floats, not JS-side */; - case 'd': return 8; - } - toss("Unhandled signature sizeof:",s); - }; + const affirmBigIntArray = BigInt64Array ? ()=>true : ()=>toss('BigInt64Array is not available.'); - /** Returns the (signed) TypedArray associated with the type - described by the given SIG. Throws for an unknown SIG. */ - /********** - const sigTypedArray = function(s){ - switch(sigIR(s)) { - case 'i32': return Int32Array; - case 'i64': return affirmBigIntArray() && BigInt64Array; - case 'float': return Float32Array; - case 'double': return Float64Array; - } - toss("Unhandled signature TypedArray:",s); - }; - **************/ /** Returns the name of a DataView getter method corresponding to the given SIG. */ const sigDVGetter = function(s){ @@ -217,6 +192,8 @@ self.Jaccwabyt = function StructBinderFactory(config){ toss("Unhandled DataView set wrapper for signature:",s); }; + /** Returns the given struct and member name in a form suitable for + debugging and error output. */ const sPropName = (s,k)=>s+'::'+k; const __propThrowOnSet = function(structName,propName){ @@ -673,13 +650,20 @@ self.Jaccwabyt = function StructBinderFactory(config){ // 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){ // offsets of size-1 members may be odd values. + 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 description =",m,"from",structInfo.members); + 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 description =",m,"from",structInfo.members); + console.warn("Invalid struct member description =",m,"from",structInfo); toss(structName,"member",k,"offset is not aligned. offset="+m.offset); } } diff --git a/manifest b/manifest index 7d4a4ffa9e..ceb804eae8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Initial\sinfrastructure\sfor\sadding\svirtual\stable/table-valued\sfunction\ssupport\sto\sWASM. -D 2022-12-05T05:30:03.152 +C Remove\ssome\sdead\scode.\sImprove\ssome\serror\schecks\sand\scomments. +D 2022-12-05T05:45:00.486 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -503,7 +503,7 @@ F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08 F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62 F ext/wasm/api/pre-js.c-pp.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f9e91c1d5f F ext/wasm/api/sqlite3-api-cleanup.js 680d5ccfff54459db136a49b2199d9f879c8405d9c99af1dda0cc5e7c29056f4 -F ext/wasm/api/sqlite3-api-glue.js 6028d0c3e6f475a513040a45612238b749ec6c155181d5bd029d66577ab4d0d6 +F ext/wasm/api/sqlite3-api-glue.js 40504fa3d382b9181e20e299ac5318ef55345090b8f5098601d7f759d57d6418 F ext/wasm/api/sqlite3-api-oo1.js 91a7d7b9203fb0f031e6ba380a644a7f871e1798b388de399c01ed4087bac9e0 F ext/wasm/api/sqlite3-api-prologue.js 697a5989ad52a9ba7bc60b5436589bd05885ee2201d84c38c5e9af3876af3ba4 F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f @@ -539,7 +539,7 @@ F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5 F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2 F ext/wasm/index-dist.html c806b6005145b71d64240606e9c6e0bf56878ee8829c66fe7486cebf34b0e6b1 F ext/wasm/index.html f151b7c7b5cfdc066567d556acd168e769efd4e982286dc5f849a5ee69ecd0ff -F ext/wasm/jaccwabyt/jaccwabyt.js 7c41784c442aa67f0e86e7c14aa51b3a28e3b21eb579c71c16af3c988fbf966f +F ext/wasm/jaccwabyt/jaccwabyt.js 292d37ad3b5fcef420db7b449813c38f1656f490f43e214ea4895793158e7fce F ext/wasm/jaccwabyt/jaccwabyt.md 50df3ccb7a773634000496a2ccb805dd25cf8cd963696a7deec3209a68c6093b F ext/wasm/module-symbols.html 980680c8acfa3c8ae6a5aa223512d1b8e78040ced20f8ba2c382129bc73ec028 F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06 @@ -2065,11 +2065,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 1b779afa3ed2f35a110e460fc6ed13cba744db85b9924149ab028b100d1e1e12 -R b429259a443dd7b0ac8ceede26128588 -T *branch * wasm-vtab -T *sym-wasm-vtab * -T -sym-trunk * Cancelled\sby\sbranch. +P c202d7a0398b9aabc2babba5c4c91a313f32bbf37549d419775642bb4aa3936a +R acfab192817c95e0e585836998ec2507 U stephan -Z bd980b10d448d088ee0cbb8238fc2a43 +Z 572c98dbcc011253d2f467baefba9d4d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f70604b10c..cddf20fae5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c202d7a0398b9aabc2babba5c4c91a313f32bbf37549d419775642bb4aa3936a \ No newline at end of file +6712fbe46a97867cea309f78a274edbb6bd166a505b41e18a580306da0e063db \ No newline at end of file From 08fc64ea04d7b8ce458ba13608502159a2727738 Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 5 Dec 2022 07:51:25 +0000 Subject: [PATCH 03/22] More work on the JS side of the virtual table APIs. FossilOrigin-Name: cb9881ec001b0e2faf047e57acfd1722d2b546255a54e0f850f568edfe2df1cd --- ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api | 14 +++++ ext/wasm/api/sqlite3-api-glue.js | 64 ++++++++------------- ext/wasm/api/sqlite3-api-prologue.js | 22 +++++++ ext/wasm/api/sqlite3-wasm.c | 44 ++++++++++---- manifest | 18 +++--- manifest.uuid | 2 +- 6 files changed, 102 insertions(+), 62 deletions(-) diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api index 096bf44018..12ab94b2dc 100644 --- a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api +++ b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api @@ -7,6 +7,7 @@ _sqlite3_bind_null _sqlite3_bind_parameter_count _sqlite3_bind_parameter_index _sqlite3_bind_text +_sqlite3_busy_handler _sqlite3_busy_timeout _sqlite3_changes _sqlite3_changes64 @@ -24,14 +25,19 @@ _sqlite3_column_text _sqlite3_column_type _sqlite3_compileoption_get _sqlite3_compileoption_used +_sqlite3_complete _sqlite3_create_function _sqlite3_create_function_v2 +_sqlite3_create_module +_sqlite3_create_module_v2 _sqlite3_create_window_function _sqlite3_data_count _sqlite3_db_filename _sqlite3_db_handle _sqlite3_db_name +_sqlite3_declare_vtab _sqlite3_deserialize +_sqlite3_drop_modules _sqlite3_errmsg _sqlite3_error_offset _sqlite3_errstr @@ -50,6 +56,7 @@ _sqlite3_malloc64 _sqlite3_msize _sqlite3_open _sqlite3_open_v2 +_sqlite3_overload_function _sqlite3_prepare_v2 _sqlite3_prepare_v3 _sqlite3_randomness @@ -93,6 +100,13 @@ _sqlite3_value_type _sqlite3_vfs_find _sqlite3_vfs_register _sqlite3_vfs_unregister +_sqlite3_vtab_distinct +_sqlite3_vtab_in +_sqlite3_vtab_in_first +_sqlite3_vtab_in_next +_sqlite3_vtab_nochange +_sqlite3_vtab_on_conflict +_sqlite3_vtab_rhs_value _malloc _free _realloc diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js index 582b0c0a30..c1c91136ac 100644 --- a/ext/wasm/api/sqlite3-api-glue.js +++ b/ext/wasm/api/sqlite3-api-glue.js @@ -37,20 +37,6 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ }); delete self.Jaccwabyt; - if(0){ - /* "The problem" is that the following isn't even remotely - type-safe. OTOH, nothing about WASM pointers is. */ - const argPointer = wasm.xWrap.argAdapter('*'); - wasm.xWrap.argAdapter('StructType', (v)=>{ - if(v && v.constructor && v instanceof StructBinder.StructType){ - v = v.pointer; - } - return wasm.isPtr(v) - ? argPointer(v) - : toss("Invalid (object) type for StructType-type argument."); - }); - } - {/* Convert Arrays and certain TypedArrays to strings for 'flexible-string'-type arguments */ const xString = wasm.xWrap.argAdapter('string'); @@ -68,15 +54,21 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ `sqlite3_vfs*` via capi.sqlite3_vfs.pointer. */ const aPtr = wasm.xWrap.argAdapter('*'); + const nilType = function(){}; wasm.xWrap.argAdapter('sqlite3_filename', aPtr) ('sqlite3_stmt*', aPtr) ('sqlite3_context*', aPtr) ('sqlite3_value*', aPtr) ('void*', aPtr) - ('sqlite3*', (v)=>{ - if(sqlite3.oo1 && v instanceof sqlite3.oo1.DB) v = v.pointer; - return aPtr(v); - }) + ('sqlite3*', (v)=> + aPtr((v instanceof (sqlite3?.oo1?.DB || nilType)) + ? v.pointer : v)) + ('sqlite3_index_info*', (v)=> + aPtr((v instanceof (capi.sqlite3_index_info || nilType)) + ? v.pointer : v)) + ('sqlite3_module*', (v)=> + aPtr((v instanceof (capi.sqlite3_module || nilType)) + ? v.pointer : v)) /** `sqlite3_vfs*`: @@ -87,14 +79,13 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ */ ('sqlite3_vfs*', (v)=>{ if('string'===typeof v){ - const x = capi.sqlite3_vfs_find(v); /* A NULL sqlite3_vfs pointer will be treated as the default VFS in many contexts. We specifically do not want that behavior here. */ - if(!x) sqlite3.SQLite3Error.toss("Unknown sqlite3_vfs name:",v); - return x; - }else if(v instanceof sqlite3.capi.sqlite3_vfs) v = v.pointer; - return aPtr(v); + return capi.sqlite3_vfs_find(v) + || sqlite3.SQLite3Error.toss("Unknown sqlite3_vfs name:",v); + } + return aPtr((v instanceof capi.sqlite3_vfs) ? v.pointer : v); }); wasm.xWrap.resultAdapter('sqlite3*', aPtr) @@ -127,7 +118,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ : fI64Disabled(e[0]); } - /* There's no(?) need to expose bindingSignatures to clients, + /* There's no need to expose bindingSignatures to clients, implicitly making it part of the public interface. */ delete wasm.bindingSignatures; @@ -141,21 +132,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ return errCode; }; } - }/*xWrap() bindings*/; - /** - When registering a VFS and its related components it may be - necessary to ensure that JS keeps a reference to them to keep - them from getting garbage collected. Simply pass each such value - to this function and a reference will be held to it for the life - of the app. - */ - capi.sqlite3_vfs_register.addReference = function f(...args){ - if(!f._) f._ = []; - f._.push(...args); - }; - /** Internal helper to assist in validating call argument counts in the hand-written sqlite3_xyz() wrappers. We do this only for @@ -603,10 +581,11 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ } wasm.ctype = JSON.parse(wasm.cstringToJs(cJson)); //console.debug('wasm.ctype length =',wasm.cstrlen(cJson)); - const defineGroups = ['access', 'blobFinalizers', 'dataTypes', + const defineGroups = ['access', 'authorizer', + 'blobFinalizers', 'dataTypes', 'encodings', 'fcntl', 'flock', 'ioCap', - 'limits', - 'openFlags', 'prepareFlags', 'resultCodes', + 'limits', 'openFlags', + 'prepareFlags', 'resultCodes', 'serialize', 'syncFlags', 'trace', 'udfFlags', 'version' ]; if(wasm.bigIntEnabled){ @@ -658,7 +637,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ capi.sqlite3_index_info[k] = capi[k]; delete capi[k]; } - } + capi.sqlite3_vtab_config = + (pDb, op, arg=0)=>wasm.exports.sqlite3_wasm_vtab_config( + wasm.xWrap.argAdapter('sqlite3*')(pDb), op, arg); + }/* end vtab-related setup */ }/*end C constant and struct imports*/ const pKvvfs = capi.sqlite3_vfs_find("kvvfs"); diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index 5ebe7af058..b66497e6ba 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -890,6 +890,10 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( the lines of sqlite3_prepare_v3(). The slightly problematic part is the final argument (text destructor). */ ], + //["sqlite3_busy_handler","int", "sqlite3*", "*", "*"], + // ^^^^ TODO: custom binding which auto-converts JS function arg + // to a WASM function, noting that calling it multiple times + // would introduce a leak. ["sqlite3_busy_timeout","int", "sqlite3*", "int"], ["sqlite3_close_v2", "int", "sqlite3*"], ["sqlite3_changes", "int", "sqlite3*"], @@ -904,6 +908,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ["sqlite3_column_type","int", "sqlite3_stmt*", "int"], ["sqlite3_compileoption_get", "string", "int"], ["sqlite3_compileoption_used", "int", "string"], + ["sqlite3_complete", "int", "flexible-string"], /* sqlite3_create_function(), sqlite3_create_function_v2(), and sqlite3_create_window_function() use hand-written bindings to simplify handling of their function-type arguments. */ @@ -998,14 +1003,31 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ["sqlite3_bind_int64","int", ["sqlite3_stmt*", "int", "i64"]], ["sqlite3_changes64","i64", ["sqlite3*"]], ["sqlite3_column_int64","i64", ["sqlite3_stmt*", "int"]], + ["sqlite3_create_module", "int", + ["sqlite3*","string","sqlite3_module*","*"]], + ["sqlite3_create_module_v2", "int", + ["sqlite3*","string","sqlite3_module*","*","*"]], + ["sqlite3_declare_vtab", "int", ["sqlite3*", "flexible-string"]], + ["sqlite3_drop_modules", "int", ["sqlite3*", "**"]], ["sqlite3_malloc64", "*","i64"], ["sqlite3_msize", "i64", "*"], + ["sqlite3_overload_function", "int", ["sqlite3*","string","int"]], ["sqlite3_realloc64", "*","*", "i64"], ["sqlite3_result_int64",undefined, "*", "i64"], ["sqlite3_result_zeroblob64", "int", "*", "i64"], ["sqlite3_total_changes64", "i64", ["sqlite3*"]], ["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]], ["sqlite3_value_int64","i64", "sqlite3_value*"], + //EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int) + ["sqlite3_vtab_distinct","int", "sqlite3_index_info*"], + ["sqlite3_vtab_in","int", "sqlite3_index_info*", "int", "int"], + ["sqlite3_vtab_in_first", "int", "sqlite3_value*", "**"], + ["sqlite3_vtab_in_next", "int", "sqlite3_value*", "**"], + /*["sqlite3_vtab_config" is variadic and requires a hand-written + proxy.] */ + ["sqlite3_vtab_nochange","int", "sqlite3_context*"], + ["sqlite3_vtab_on_conflict","int", "sqlite3*"], + ["sqlite3_vtab_rhs_value","int", "sqlite3_index_info*", "int", "**"] ]; /** diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c index dc5dff62a7..96234bca3a 100644 --- a/ext/wasm/api/sqlite3-wasm.c +++ b/ext/wasm/api/sqlite3-wasm.c @@ -410,13 +410,11 @@ const char * sqlite3_wasm_enum_json(void){ DefInt(SQLITE_ACCESS_READ)/*docs say this is unused*/; } _DefGroup; -#if 0 /* TODO? Authorizer... */ DefGroup(authorizer){ DefInt(SQLITE_DENY); DefInt(SQLITE_IGNORE); } _DefGroup; -#endif DefGroup(blobFinalizers) { /* SQLITE_STATIC/TRANSIENT need to be handled explicitly as @@ -709,6 +707,14 @@ const char * sqlite3_wasm_enum_json(void){ DefInt(SQLITE_INDEX_CONSTRAINT_LIMIT); DefInt(SQLITE_INDEX_CONSTRAINT_OFFSET); DefInt(SQLITE_INDEX_CONSTRAINT_FUNCTION); + DefInt(SQLITE_VTAB_CONSTRAINT_SUPPORT); + DefInt(SQLITE_VTAB_INNOCUOUS); + DefInt(SQLITE_VTAB_DIRECTONLY); + DefInt(SQLITE_ROLLBACK); + //DefInt(SQLITE_IGNORE); // Also used by sqlite3_authorizer() callback + DefInt(SQLITE_FAIL); + //DefInt(SQLITE_ABORT); // Also an error code + DefInt(SQLITE_REPLACE); } _DefGroup; #undef DefGroup @@ -867,15 +873,6 @@ const char * sqlite3_wasm_enum_json(void){ M(xShadowName, "i(s)"); } _StructBinder; #undef CurrentStruct - /* - module/vtab todos: - - - sqlite3_create_module() - - sqlite3_create_module_v2() - - sqlite3_drop_modules() - - sqlite3_declare_vtab() - - sqlite3_overload_function() - */ /** ** Workaround: in order to map the various inner structs from @@ -1269,6 +1266,31 @@ sqlite3_kvvfs_methods * sqlite3_wasm_kvvfs_methods(void){ return &sqlite3KvvfsMethods; } +/* +** This function is NOT part of the sqlite3 public API. It is strictly +** for use by the sqlite project's own JS/WASM bindings. +** +** This is a proxy for the variadic sqlite3_vtab_config() which passes +** its argument on, or not, to sqlite3_vtab_config(), depending on the +** value of its 2nd argument. Returns the result of +** sqlite3_vtab_config(), or SQLITE_MISUSE if the 2nd arg is not a +** valid value. +*/ +SQLITE_WASM_KEEP +int sqlite3_wasm_vtab_config(sqlite3 *pDb, int op, int arg){ + switch(op){ + case SQLITE_VTAB_DIRECTONLY: + case SQLITE_VTAB_INNOCUOUS: + return sqlite3_vtab_config(pDb, op); + case SQLITE_VTAB_CONSTRAINT_SUPPORT: + return sqlite3_vtab_config(pDb, op, arg); + default: + return SQLITE_MISUSE; + } + +} + + #if defined(__EMSCRIPTEN__) && defined(SQLITE_ENABLE_WASMFS) #include diff --git a/manifest b/manifest index ceb804eae8..08e9801bce 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\ssome\sdead\scode.\sImprove\ssome\serror\schecks\sand\scomments. -D 2022-12-05T05:45:00.486 +C More\swork\son\sthe\sJS\sside\sof\sthe\svirtual\stable\sAPIs. +D 2022-12-05T07:51:25.186 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -494,7 +494,7 @@ F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34ce F ext/wasm/GNUmakefile bfa47f169468ca9db031105b0e336db29a88e93c3abd217d0bbb2b8731fa5413 F ext/wasm/README-dist.txt 2d670b426fc7c613b90a7d2f2b05b433088fe65181abead970980f0a4a75ea20 F ext/wasm/README.md ef39861aa21632fdbca0bdd469f78f0096f6449a720f3f39642594af503030e9 -F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 89af0612bad5c651f69e629c7e9689be6d3c8a92a9010da5dd90a87c1d86817a +F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 5b042c543c83134c20d222b7b8cd9e3401a5d552d709364d82461c064cd26089 F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287 F ext/wasm/api/README.md 20a256f4aaae80035d2bb1c9e3e0a125570313a8d137d427471d7be10edde87a F ext/wasm/api/extern-post-js.c-pp.js 8923f76c3d2213159e12d641dc750523ead5c848185dc4996fae5cc12397f88d @@ -503,16 +503,16 @@ F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08 F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62 F ext/wasm/api/pre-js.c-pp.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f9e91c1d5f F ext/wasm/api/sqlite3-api-cleanup.js 680d5ccfff54459db136a49b2199d9f879c8405d9c99af1dda0cc5e7c29056f4 -F ext/wasm/api/sqlite3-api-glue.js 40504fa3d382b9181e20e299ac5318ef55345090b8f5098601d7f759d57d6418 +F ext/wasm/api/sqlite3-api-glue.js dd7f3cc427154f280d9718dbc755ae4ed21c81d193f16b32184731c299c1d3be F ext/wasm/api/sqlite3-api-oo1.js 91a7d7b9203fb0f031e6ba380a644a7f871e1798b388de399c01ed4087bac9e0 -F ext/wasm/api/sqlite3-api-prologue.js 697a5989ad52a9ba7bc60b5436589bd05885ee2201d84c38c5e9af3876af3ba4 +F ext/wasm/api/sqlite3-api-prologue.js d2cb6dd5ca109b36c5038301a6881f6ca137b946350e79e701114e461ab56298 F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 F ext/wasm/api/sqlite3-opfs-async-proxy.js f79dd8d98ef3e0b55c10bb2bee7a3840fa967318e1f577c156aafc34664271d1 F ext/wasm/api/sqlite3-vfs-helper.js 4ad4faf02e1524bf0296be8452c00b5708dce6faf649468d0377e26a0b299263 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 29d6487a26b2fb6a471cde52c37ffee7c27ed6a91914b308c247e0706f454ffb F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 -F ext/wasm/api/sqlite3-wasm.c 5120fb3419aba02d20cbe1e645b58dae5faeaaae8ccd46b8931ae04d311df9e5 +F ext/wasm/api/sqlite3-wasm.c 723522a6c2a2463884a83fa1cc7ae5770deaaf0856a1058cc1023b2bfa1c898b F ext/wasm/api/sqlite3-worker1-promiser.js 0c7a9826dbf82a5ed4e4f7bf7816e825a52aff253afbf3350431f5773faf0e4b F ext/wasm/api/sqlite3-worker1.js 1e54ea3d540161bcfb2100368a2fc0cad871a207b8336afee1c445715851ec54 F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8 @@ -2065,8 +2065,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c202d7a0398b9aabc2babba5c4c91a313f32bbf37549d419775642bb4aa3936a -R acfab192817c95e0e585836998ec2507 +P 6712fbe46a97867cea309f78a274edbb6bd166a505b41e18a580306da0e063db +R 556ab7e7db905d4fcefcfcbe9067fc69 U stephan -Z 572c98dbcc011253d2f467baefba9d4d +Z c9a0ef228c6ee4583769e98c5e79436a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index cddf20fae5..d7b2b1b5f4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6712fbe46a97867cea309f78a274edbb6bd166a505b41e18a580306da0e063db \ No newline at end of file +cb9881ec001b0e2faf047e57acfd1722d2b546255a54e0f850f568edfe2df1cd \ No newline at end of file From 0adef0937451b9c93688c00e26a792915361af5d Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 5 Dec 2022 11:30:39 +0000 Subject: [PATCH 04/22] Export sqlite3_bind/value/result_pointer() to wasm. Add 'static-string' argument converter to support the lifetime requirements of bind/result_pointer()'s string argument. Correct an endless loop in wasm.cstrlen() when passed a non-C-string argument. FossilOrigin-Name: a94552434a657376d5ce1831de05c1b15fb153020848cd825fb0df413c3baa70 --- ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api | 3 ++ ext/wasm/api/sqlite3-api-glue.js | 33 ++++++++++++++++++++- ext/wasm/api/sqlite3-api-prologue.js | 5 ++++ ext/wasm/common/whwasmutil.js | 9 +++--- manifest | 18 +++++------ manifest.uuid | 2 +- 6 files changed, 55 insertions(+), 15 deletions(-) diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api index 12ab94b2dc..5c0419e9da 100644 --- a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api +++ b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api @@ -6,6 +6,7 @@ _sqlite3_bind_int64 _sqlite3_bind_null _sqlite3_bind_parameter_count _sqlite3_bind_parameter_index +_sqlite3_bind_pointer _sqlite3_bind_text _sqlite3_busy_handler _sqlite3_busy_timeout @@ -72,6 +73,7 @@ _sqlite3_result_error_toobig _sqlite3_result_int _sqlite3_result_int64 _sqlite3_result_null +_sqlite3_result_pointer _sqlite3_result_text _sqlite3_result_zeroblob _sqlite3_result_zeroblob64 @@ -95,6 +97,7 @@ _sqlite3_value_bytes _sqlite3_value_double _sqlite3_value_int _sqlite3_value_int64 +_sqlite3_value_pointer _sqlite3_value_text _sqlite3_value_type _sqlite3_vfs_find diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js index c1c91136ac..dc9db9435f 100644 --- a/ext/wasm/api/sqlite3-api-glue.js +++ b/ext/wasm/api/sqlite3-api-glue.js @@ -43,7 +43,38 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ wasm.xWrap.argAdapter( 'flexible-string', (v)=>xString(util.flexibleString(v)) ); - } + + /** + The 'static-string' argument adapter treats its argument as + either... + + - WASM pointer: assumed to be a long-lived C-string which gets + returned as-is. + + - Anything else: gets coerced to a JS string for use as a map + key. If a matching entry is found (as described next), it is + returned, else wasm.allocCString() is used to create a a new + string, map its pointer to (''+v) for the remainder of the + application's life, and returns that pointer value for this + call and all future calls which are passed a + string-equivalent argument. + + Use case: sqlite3_bind_pointer() and sqlite3_result_pointer() + call for "a static string and preferably a string + literal". This converter is used to ensure that the string + value seen by those functions is long-lived and behaves as they + need it to. + */ + wasm.xWrap.argAdapter( + 'static-string', + function(v){ + if(wasm.isPtr(v)) return v; + v = ''+v; + let rc = this[v]; + return rc || (rc = this[v] = wasm.allocCString(v)); + }.bind(Object.create(null)) + ); + }/* special-case string-type argument conversions */ if(1){// WhWasmUtil.xWrap() bindings... /** diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index b66497e6ba..cf57329569 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -884,6 +884,8 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"], ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"], ["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"], + ["sqlite3_bind_pointer", "int", + "sqlite3_stmt*", "int", "*", "static-string", "*"], ["sqlite3_bind_text","int", "sqlite3_stmt*", "int", "string", "int", "int" /* We should arguably create a hand-written binding of bind_text() which does more flexible text conversion, along @@ -958,6 +960,8 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ["sqlite3_result_error_toobig", undefined, "sqlite3_context*"], ["sqlite3_result_int",undefined, "sqlite3_context*", "int"], ["sqlite3_result_null",undefined, "sqlite3_context*"], + ["sqlite3_result_pointer",undefined, + "sqlite3_context*", "*", "static-string", "*"], ["sqlite3_result_text",undefined, "sqlite3_context*", "string", "int", "*"], ["sqlite3_result_zeroblob", undefined, "sqlite3_context*", "int"], ["sqlite3_serialize","*", "sqlite3*", "string", "*", "int"], @@ -980,6 +984,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ["sqlite3_value_bytes","int", "sqlite3_value*"], ["sqlite3_value_double","f64", "sqlite3_value*"], ["sqlite3_value_int","int", "sqlite3_value*"], + ["sqlite3_value_pointer", "*", "sqlite3_value*", "static-string"], ["sqlite3_value_text", "string", "sqlite3_value*"], ["sqlite3_value_type", "int", "sqlite3_value*"], ["sqlite3_vfs_find", "*", "string"], diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js index 84d829daba..9bce82f1a9 100644 --- a/ext/wasm/common/whwasmutil.js +++ b/ext/wasm/common/whwasmutil.js @@ -725,11 +725,12 @@ self.WhWasmUtilInstaller = function(target){ Expects ptr to be a pointer into the WASM heap memory which refers to a NUL-terminated C-style string encoded as UTF-8. Returns the length, in bytes, of the string, as for `strlen(3)`. - As a special case, if !ptr then it it returns `null`. Throws if - ptr is out of range for target.heap8u(). + As a special case, if !ptr or if it's not a pointer then it + returns `null`. Throws if ptr is out of range for + target.heap8u(). */ target.cstrlen = function(ptr){ - if(!ptr) return null; + if(!ptr || !target.isPtr(ptr)) return null; const h = heapWrappers().HEAP8U; let pos = ptr; for( ; h[pos] !== 0; ++pos ){} @@ -753,7 +754,7 @@ self.WhWasmUtilInstaller = function(target){ refers to a NUL-terminated C-style string encoded as UTF-8. This function counts its byte length using cstrlen() then returns a JS-format string representing its contents. As a special case, if - ptr is falsy, `null` is returned. + ptr is falsy or not a pointer, `null` is returned. */ target.cstringToJs = function(ptr){ const n = target.cstrlen(ptr); diff --git a/manifest b/manifest index 08e9801bce..cd9e8c1ae2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C More\swork\son\sthe\sJS\sside\sof\sthe\svirtual\stable\sAPIs. -D 2022-12-05T07:51:25.186 +C Export\ssqlite3_bind/value/result_pointer()\sto\swasm.\sAdd\s'static-string'\sargument\sconverter\sto\ssupport\sthe\slifetime\srequirements\sof\sbind/result_pointer()'s\sstring\sargument.\sCorrect\san\sendless\sloop\sin\swasm.cstrlen()\swhen\spassed\sa\snon-C-string\sargument. +D 2022-12-05T11:30:39.470 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -494,7 +494,7 @@ F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34ce F ext/wasm/GNUmakefile bfa47f169468ca9db031105b0e336db29a88e93c3abd217d0bbb2b8731fa5413 F ext/wasm/README-dist.txt 2d670b426fc7c613b90a7d2f2b05b433088fe65181abead970980f0a4a75ea20 F ext/wasm/README.md ef39861aa21632fdbca0bdd469f78f0096f6449a720f3f39642594af503030e9 -F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 5b042c543c83134c20d222b7b8cd9e3401a5d552d709364d82461c064cd26089 +F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 21a7c443f496f891e5362db75884a5c3c72058559bbfbcae707ec5bbefd80de9 F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287 F ext/wasm/api/README.md 20a256f4aaae80035d2bb1c9e3e0a125570313a8d137d427471d7be10edde87a F ext/wasm/api/extern-post-js.c-pp.js 8923f76c3d2213159e12d641dc750523ead5c848185dc4996fae5cc12397f88d @@ -503,9 +503,9 @@ F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08 F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62 F ext/wasm/api/pre-js.c-pp.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f9e91c1d5f F ext/wasm/api/sqlite3-api-cleanup.js 680d5ccfff54459db136a49b2199d9f879c8405d9c99af1dda0cc5e7c29056f4 -F ext/wasm/api/sqlite3-api-glue.js dd7f3cc427154f280d9718dbc755ae4ed21c81d193f16b32184731c299c1d3be +F ext/wasm/api/sqlite3-api-glue.js 170fd05a8064d2f23c253a45debe533b0c23872f9495c6d4d20463b700252770 F ext/wasm/api/sqlite3-api-oo1.js 91a7d7b9203fb0f031e6ba380a644a7f871e1798b388de399c01ed4087bac9e0 -F ext/wasm/api/sqlite3-api-prologue.js d2cb6dd5ca109b36c5038301a6881f6ca137b946350e79e701114e461ab56298 +F ext/wasm/api/sqlite3-api-prologue.js d930ddf9c325405c97f9d0367020eac7cfa3da660c098585a11fd2466b1f5e16 F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 F ext/wasm/api/sqlite3-opfs-async-proxy.js f79dd8d98ef3e0b55c10bb2bee7a3840fa967318e1f577c156aafc34664271d1 @@ -521,7 +521,7 @@ F ext/wasm/c-pp.c 92285f7bce67ed7b7020b40fde8ed0982c442b63dc33df9dfd4b658d4a6c07 F ext/wasm/common/SqliteTestUtil.js d8bf97ecb0705a2299765c8fc9e11b1a5ac7f10988bbf375a6558b7ca287067b F ext/wasm/common/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f F ext/wasm/common/testing.css 35889709547d89a6109ff83b25c11bbc91d8dd43aab8722e428655ca98880a06 -F ext/wasm/common/whwasmutil.js 1bc1c973662db7d52763512e67c2369fdbfe9e8bae33069ac89f4fbe40d678b2 +F ext/wasm/common/whwasmutil.js 0de1e72494d52185d518892a3ac95d38b8e295d3699b64ddb36a3d46c11c8346 F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508 F ext/wasm/demo-123.js ebae30756585bca655b4ab2553ec9236a87c23ad24fc8652115dcedb06d28df6 @@ -2065,8 +2065,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 6712fbe46a97867cea309f78a274edbb6bd166a505b41e18a580306da0e063db -R 556ab7e7db905d4fcefcfcbe9067fc69 +P cb9881ec001b0e2faf047e57acfd1722d2b546255a54e0f850f568edfe2df1cd +R 43c6939a23c10432b26f996c39515ebf U stephan -Z c9a0ef228c6ee4583769e98c5e79436a +Z e6790963ab3f2e980219be88a41c0b38 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d7b2b1b5f4..0e7dc35e19 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cb9881ec001b0e2faf047e57acfd1722d2b546255a54e0f850f568edfe2df1cd \ No newline at end of file +a94552434a657376d5ce1831de05c1b15fb153020848cd825fb0df413c3baa70 \ No newline at end of file From cf8f0d20463adf368cedb434d6d70cd255ab185a Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 5 Dec 2022 11:54:13 +0000 Subject: [PATCH 05/22] Rename 'static-string' argument adapter to 'string:static'. Replace JS unit tests which were lost via editing a generated copy of tester1.js instead of the original tester1.c-pp.js input file. FossilOrigin-Name: 9d81d51d5a255b42f8416da850c992a9e4c8eebc940e0702a9262cfcaa6d7b2f --- ext/wasm/api/sqlite3-api-glue.js | 4 ++-- ext/wasm/api/sqlite3-api-prologue.js | 6 +++--- ext/wasm/tester1.c-pp.js | 20 ++++++++++++++++++++ manifest | 16 ++++++++-------- manifest.uuid | 2 +- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js index dc9db9435f..b460093f8d 100644 --- a/ext/wasm/api/sqlite3-api-glue.js +++ b/ext/wasm/api/sqlite3-api-glue.js @@ -45,7 +45,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ ); /** - The 'static-string' argument adapter treats its argument as + The 'string:static' argument adapter treats its argument as either... - WASM pointer: assumed to be a long-lived C-string which gets @@ -66,7 +66,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ need it to. */ wasm.xWrap.argAdapter( - 'static-string', + 'string:static', function(v){ if(wasm.isPtr(v)) return v; v = ''+v; diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index cf57329569..4087adb504 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -885,7 +885,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"], ["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"], ["sqlite3_bind_pointer", "int", - "sqlite3_stmt*", "int", "*", "static-string", "*"], + "sqlite3_stmt*", "int", "*", "string:static", "*"], ["sqlite3_bind_text","int", "sqlite3_stmt*", "int", "string", "int", "int" /* We should arguably create a hand-written binding of bind_text() which does more flexible text conversion, along @@ -961,7 +961,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ["sqlite3_result_int",undefined, "sqlite3_context*", "int"], ["sqlite3_result_null",undefined, "sqlite3_context*"], ["sqlite3_result_pointer",undefined, - "sqlite3_context*", "*", "static-string", "*"], + "sqlite3_context*", "*", "string:static", "*"], ["sqlite3_result_text",undefined, "sqlite3_context*", "string", "int", "*"], ["sqlite3_result_zeroblob", undefined, "sqlite3_context*", "int"], ["sqlite3_serialize","*", "sqlite3*", "string", "*", "int"], @@ -984,7 +984,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ["sqlite3_value_bytes","int", "sqlite3_value*"], ["sqlite3_value_double","f64", "sqlite3_value*"], ["sqlite3_value_int","int", "sqlite3_value*"], - ["sqlite3_value_pointer", "*", "sqlite3_value*", "static-string"], + ["sqlite3_value_pointer", "*", "sqlite3_value*", "string:static"], ["sqlite3_value_text", "string", "sqlite3_value*"], ["sqlite3_value_type", "int", "sqlite3_value*"], ["sqlite3_vfs_find", "*", "string"], diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index 0aaee97693..aa5fa41d2d 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -660,6 +660,26 @@ self.sqlite3InitModule = sqlite3InitModule; T.assert(rc>0 && Number.isFinite(rc)); rc = w.xCallWrapped('sqlite3_wasm_enum_json','utf8'); T.assert('string'===typeof rc).assert(rc.length>300); + + + { // 'string:static' argAdapter() sanity checks... + let argAd = w.xWrap.argAdapter('string:static'); + let p0 = argAd('foo'), p1 = argAd('bar'); + T.assert(w.isPtr(p0) && w.isPtr(p1)) + .assert(p0 !== p1) + .assert(p0 === argAd('foo')) + .assert(p1 === argAd('bar')); + } + + // 'flexible-string' argAdapter() sanity checks... + w.scopedAllocCall(()=>{ + const argAd = w.xWrap.argAdapter('flexible-string'); + const cj = (v)=>w.cstringToJs(argAd(v)); + T.assert('Hi' === cj('Hi')) + .assert('hi' === cj(['h','i'])) + .assert('HI' === cj(new Uint8Array([72, 73]))); + }); + if(haveWasmCTests()){ if(!sqlite3.config.useStdAlloc){ fw = w.xWrap('sqlite3_wasm_test_str_hello', 'utf8:dealloc',['i32']); diff --git a/manifest b/manifest index cd9e8c1ae2..63d8142b60 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Export\ssqlite3_bind/value/result_pointer()\sto\swasm.\sAdd\s'static-string'\sargument\sconverter\sto\ssupport\sthe\slifetime\srequirements\sof\sbind/result_pointer()'s\sstring\sargument.\sCorrect\san\sendless\sloop\sin\swasm.cstrlen()\swhen\spassed\sa\snon-C-string\sargument. -D 2022-12-05T11:30:39.470 +C Rename\s'static-string'\sargument\sadapter\sto\s'string:static'.\sReplace\sJS\sunit\stests\swhich\swere\slost\svia\sediting\sa\sgenerated\scopy\sof\stester1.js\sinstead\sof\sthe\soriginal\stester1.c-pp.js\sinput\sfile. +D 2022-12-05T11:54:13.530 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -503,9 +503,9 @@ F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08 F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62 F ext/wasm/api/pre-js.c-pp.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f9e91c1d5f F ext/wasm/api/sqlite3-api-cleanup.js 680d5ccfff54459db136a49b2199d9f879c8405d9c99af1dda0cc5e7c29056f4 -F ext/wasm/api/sqlite3-api-glue.js 170fd05a8064d2f23c253a45debe533b0c23872f9495c6d4d20463b700252770 +F ext/wasm/api/sqlite3-api-glue.js 2c45a3c05badb11c37152d9d819156420a5c026ef9cf6fee97512b279b33bf44 F ext/wasm/api/sqlite3-api-oo1.js 91a7d7b9203fb0f031e6ba380a644a7f871e1798b388de399c01ed4087bac9e0 -F ext/wasm/api/sqlite3-api-prologue.js d930ddf9c325405c97f9d0367020eac7cfa3da660c098585a11fd2466b1f5e16 +F ext/wasm/api/sqlite3-api-prologue.js 0dba5a99f795ce6bb88b621960cc3f5f3e6370ee6f16230a0b165136529fcf40 F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 F ext/wasm/api/sqlite3-opfs-async-proxy.js f79dd8d98ef3e0b55c10bb2bee7a3840fa967318e1f577c156aafc34664271d1 @@ -555,7 +555,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac F ext/wasm/tester1-worker.html 29b1d87f7d51f70d61645719fee657f3787fe939bb695f27034c75404e8f1e6f F ext/wasm/tester1.c-pp.html 74aa9b31c75f12490653f814b53c3dd39f40cd3f70d6a53a716f4e8587107399 -F ext/wasm/tester1.c-pp.js d096a8fadfd27caa680a4311b1d529551f8fe885a63dd27457c87b6008c64632 +F ext/wasm/tester1.c-pp.js d03c8c50063ec82d38694db077fc75af390c8baa0f72eb52d3c4e4fde68ee95e F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70 F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 @@ -2065,8 +2065,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P cb9881ec001b0e2faf047e57acfd1722d2b546255a54e0f850f568edfe2df1cd -R 43c6939a23c10432b26f996c39515ebf +P a94552434a657376d5ce1831de05c1b15fb153020848cd825fb0df413c3baa70 +R 3e5f8074bc013b334ba01f938431dc3c U stephan -Z e6790963ab3f2e980219be88a41c0b38 +Z 6b18e44631fce1838526a30c03df5312 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 0e7dc35e19..5b3f6a2a2a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a94552434a657376d5ce1831de05c1b15fb153020848cd825fb0df413c3baa70 \ No newline at end of file +9d81d51d5a255b42f8416da850c992a9e4c8eebc940e0702a9262cfcaa6d7b2f \ No newline at end of file From 9a49a97487c93708a0b720aae39b4123e9a02715 Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 5 Dec 2022 13:12:48 +0000 Subject: [PATCH 06/22] Export sqlite3_vtab_collation() to wasm. Rename 'flexible-string' JS argument adapter to 'string:flexible' for consistency. FossilOrigin-Name: 15f8042fddaeabab43dd187c463d3ccc56758cbf19bf2ca4837d9087a4850c1a --- ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api | 1 + ext/wasm/api/sqlite3-api-glue.js | 46 ++++++++++----------- ext/wasm/api/sqlite3-api-oo1.js | 14 +++---- ext/wasm/api/sqlite3-api-prologue.js | 8 ++-- ext/wasm/tester1.c-pp.js | 4 +- manifest | 20 ++++----- manifest.uuid | 2 +- 7 files changed, 48 insertions(+), 47 deletions(-) diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api index 5c0419e9da..f5aabfe079 100644 --- a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api +++ b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api @@ -103,6 +103,7 @@ _sqlite3_value_type _sqlite3_vfs_find _sqlite3_vfs_register _sqlite3_vfs_unregister +_sqlite3_vtab_collation _sqlite3_vtab_distinct _sqlite3_vtab_in _sqlite3_vtab_in_first diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js index b460093f8d..ddfc1daf43 100644 --- a/ext/wasm/api/sqlite3-api-glue.js +++ b/ext/wasm/api/sqlite3-api-glue.js @@ -38,10 +38,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ delete self.Jaccwabyt; {/* Convert Arrays and certain TypedArrays to strings for - 'flexible-string'-type arguments */ + 'string:flexible'-type arguments */ const xString = wasm.xWrap.argAdapter('string'); wasm.xWrap.argAdapter( - 'flexible-string', (v)=>xString(util.flexibleString(v)) + 'string:flexible', (v)=>xString(util.flexibleString(v)) ); /** @@ -176,29 +176,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ (1===n?"":'s')+"."); }; - /** - Helper for flexible-string conversions which require a - byte-length counterpart argument. Passed a value and its - ostensible length, this function returns [V,N], where V - is either v or a transformed copy of v and N is either n, - -1, or the byte length of v (if it's a byte array). - */ - const __flexiString = function(v,n){ - if('string'===typeof v){ - n = -1; - }else if(util.isSQLableTypedArray(v)){ - n = v.byteLength; - v = util.typedArrayToString(v); - }else if(Array.isArray(v)){ - v = v.join(""); - n = -1; - } - return [v, n]; - }; - if(1){/* Special-case handling of sqlite3_exec() */ const __exec = wasm.xWrap("sqlite3_exec", "int", - ["sqlite3*", "flexible-string", "*", "*", "**"]); + ["sqlite3*", "string:flexible", "*", "*", "**"]); /* Documented in the api object's initializer. */ capi.sqlite3_exec = function f(pDb, sql, callback, pVoid, pErrMsg){ if(f.length!==arguments.length){ @@ -549,6 +529,26 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ if(1){/* Special-case handling of sqlite3_prepare_v2() and sqlite3_prepare_v3() */ + /** + Helper for string:flexible conversions which require a + byte-length counterpart argument. Passed a value and its + ostensible length, this function returns [V,N], where V + is either v or a transformed copy of v and N is either n, + -1, or the byte length of v (if it's a byte array). + */ + const __flexiString = (v,n)=>{ + if('string'===typeof v){ + n = -1; + }else if(util.isSQLableTypedArray(v)){ + n = v.byteLength; + v = util.typedArrayToString(v); + }else if(Array.isArray(v)){ + v = v.join(""); + n = -1; + } + return [v, n]; + }; + /** Scope-local holder of the two impls of sqlite3_prepare_v2/v3(). */ diff --git a/ext/wasm/api/sqlite3-api-oo1.js b/ext/wasm/api/sqlite3-api-oo1.js index e077b0c506..b377efc242 100644 --- a/ext/wasm/api/sqlite3-api-oo1.js +++ b/ext/wasm/api/sqlite3-api-oo1.js @@ -192,13 +192,13 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ /** Sets SQL which should be exec()'d on a DB instance after it is opened with the given VFS pointer. The SQL may be any type - supported by the "flexible-string" function argument - conversion. Alternately, the 2nd argument may be a function, in - which case it is called with (theOo1DbObject,sqlite3Namespace) at - the end of the DB() constructor. The function must throw on - error, in which case the db is closed and the exception is - propagated. This function is intended only for use by DB - subclasses or sqlite3_vfs implementations. + supported by the "string:flexible" function argument conversion. + Alternately, the 2nd argument may be a function, in which case it + is called with (theOo1DbObject,sqlite3Namespace) at the end of + the DB() constructor. The function must throw on error, in which + case the db is closed and the exception is propagated. This + function is intended only for use by DB subclasses or sqlite3_vfs + implementations. */ dbCtorHelper.setVfsPostOpenSql = function(pVfs, sql){ __vfsPostOpenSql[pVfs] = sql; diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index 4087adb504..5f456edf27 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -602,7 +602,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( If the callback is not a JS function then this binding performs no translation of the callback, but the sql argument is still converted to a WASM string for the call using the - "flexible-string" argument converter. + "string:flexible" argument converter. */ sqlite3_exec: (pDb, sql, callback, pVoid, pErrMsg)=>{}/*installed later*/, @@ -910,7 +910,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ["sqlite3_column_type","int", "sqlite3_stmt*", "int"], ["sqlite3_compileoption_get", "string", "int"], ["sqlite3_compileoption_used", "int", "string"], - ["sqlite3_complete", "int", "flexible-string"], + ["sqlite3_complete", "int", "string:flexible"], /* sqlite3_create_function(), sqlite3_create_function_v2(), and sqlite3_create_window_function() use hand-written bindings to simplify handling of their function-type arguments. */ @@ -1012,7 +1012,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ["sqlite3*","string","sqlite3_module*","*"]], ["sqlite3_create_module_v2", "int", ["sqlite3*","string","sqlite3_module*","*","*"]], - ["sqlite3_declare_vtab", "int", ["sqlite3*", "flexible-string"]], + ["sqlite3_declare_vtab", "int", ["sqlite3*", "string:flexible"]], ["sqlite3_drop_modules", "int", ["sqlite3*", "**"]], ["sqlite3_malloc64", "*","i64"], ["sqlite3_msize", "i64", "*"], @@ -1023,7 +1023,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ["sqlite3_total_changes64", "i64", ["sqlite3*"]], ["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]], ["sqlite3_value_int64","i64", "sqlite3_value*"], - //EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int) + ["sqlite3_vtab_collation","string","sqlite3_index_info*","int"], ["sqlite3_vtab_distinct","int", "sqlite3_index_info*"], ["sqlite3_vtab_in","int", "sqlite3_index_info*", "int", "int"], ["sqlite3_vtab_in_first", "int", "sqlite3_value*", "**"], diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index aa5fa41d2d..2d1b634e55 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -671,9 +671,9 @@ self.sqlite3InitModule = sqlite3InitModule; .assert(p1 === argAd('bar')); } - // 'flexible-string' argAdapter() sanity checks... + // 'string:flexible' argAdapter() sanity checks... w.scopedAllocCall(()=>{ - const argAd = w.xWrap.argAdapter('flexible-string'); + const argAd = w.xWrap.argAdapter('string:flexible'); const cj = (v)=>w.cstringToJs(argAd(v)); T.assert('Hi' === cj('Hi')) .assert('hi' === cj(['h','i'])) diff --git a/manifest b/manifest index 63d8142b60..3084b5ab0b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Rename\s'static-string'\sargument\sadapter\sto\s'string:static'.\sReplace\sJS\sunit\stests\swhich\swere\slost\svia\sediting\sa\sgenerated\scopy\sof\stester1.js\sinstead\sof\sthe\soriginal\stester1.c-pp.js\sinput\sfile. -D 2022-12-05T11:54:13.530 +C Export\ssqlite3_vtab_collation()\sto\swasm.\sRename\s'flexible-string'\sJS\sargument\sadapter\sto\s'string:flexible'\sfor\sconsistency. +D 2022-12-05T13:12:48.698 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -494,7 +494,7 @@ F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34ce F ext/wasm/GNUmakefile bfa47f169468ca9db031105b0e336db29a88e93c3abd217d0bbb2b8731fa5413 F ext/wasm/README-dist.txt 2d670b426fc7c613b90a7d2f2b05b433088fe65181abead970980f0a4a75ea20 F ext/wasm/README.md ef39861aa21632fdbca0bdd469f78f0096f6449a720f3f39642594af503030e9 -F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 21a7c443f496f891e5362db75884a5c3c72058559bbfbcae707ec5bbefd80de9 +F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api e17dc504c135e0d9585282faa82bf8ef3c45465b086fb02fb5605e821efb5bbc F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287 F ext/wasm/api/README.md 20a256f4aaae80035d2bb1c9e3e0a125570313a8d137d427471d7be10edde87a F ext/wasm/api/extern-post-js.c-pp.js 8923f76c3d2213159e12d641dc750523ead5c848185dc4996fae5cc12397f88d @@ -503,9 +503,9 @@ F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08 F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62 F ext/wasm/api/pre-js.c-pp.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f9e91c1d5f F ext/wasm/api/sqlite3-api-cleanup.js 680d5ccfff54459db136a49b2199d9f879c8405d9c99af1dda0cc5e7c29056f4 -F ext/wasm/api/sqlite3-api-glue.js 2c45a3c05badb11c37152d9d819156420a5c026ef9cf6fee97512b279b33bf44 -F ext/wasm/api/sqlite3-api-oo1.js 91a7d7b9203fb0f031e6ba380a644a7f871e1798b388de399c01ed4087bac9e0 -F ext/wasm/api/sqlite3-api-prologue.js 0dba5a99f795ce6bb88b621960cc3f5f3e6370ee6f16230a0b165136529fcf40 +F ext/wasm/api/sqlite3-api-glue.js e3422737c64bb6d871ddff7f7c85e637cc1597edd3bc49ef537578c57d6cfaa9 +F ext/wasm/api/sqlite3-api-oo1.js 793883953d4024e7b8c5ee1c7a6cb49c18ca53a1d235a203f93746f8907d32ba +F ext/wasm/api/sqlite3-api-prologue.js 6f5aee50867dae4e0885dd1bd1913f1f42f433def15ca9309dc5b3e83ab5c667 F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 F ext/wasm/api/sqlite3-opfs-async-proxy.js f79dd8d98ef3e0b55c10bb2bee7a3840fa967318e1f577c156aafc34664271d1 @@ -555,7 +555,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac F ext/wasm/tester1-worker.html 29b1d87f7d51f70d61645719fee657f3787fe939bb695f27034c75404e8f1e6f F ext/wasm/tester1.c-pp.html 74aa9b31c75f12490653f814b53c3dd39f40cd3f70d6a53a716f4e8587107399 -F ext/wasm/tester1.c-pp.js d03c8c50063ec82d38694db077fc75af390c8baa0f72eb52d3c4e4fde68ee95e +F ext/wasm/tester1.c-pp.js 419a2fd31b0230e0495ed38a56dbe1e2bbc93c5953b796de43e2a70901970b83 F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70 F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 @@ -2065,8 +2065,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P a94552434a657376d5ce1831de05c1b15fb153020848cd825fb0df413c3baa70 -R 3e5f8074bc013b334ba01f938431dc3c +P 9d81d51d5a255b42f8416da850c992a9e4c8eebc940e0702a9262cfcaa6d7b2f +R 277425a2c74bda828b2402faf303a6b1 U stephan -Z 6b18e44631fce1838526a30c03df5312 +Z c0b7c94a232e1e96230a439e5bd96242 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5b3f6a2a2a..43725293de 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9d81d51d5a255b42f8416da850c992a9e4c8eebc940e0702a9262cfcaa6d7b2f \ No newline at end of file +15f8042fddaeabab43dd187c463d3ccc56758cbf19bf2ca4837d9087a4850c1a \ No newline at end of file From e0818715b7fdadfba5bb23472048987b339b9f15 Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 5 Dec 2022 13:33:42 +0000 Subject: [PATCH 07/22] Export collation-related APIs and strncmp()/strnicmp() to wasm. FossilOrigin-Name: c3c56d9b944fd0d806d8dad9f0c7be3d7a5441765310908872cc525d82ab6a33 --- ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api | 5 +++++ ext/wasm/api/sqlite3-api-glue.js | 4 ++-- ext/wasm/api/sqlite3-api-prologue.js | 11 ++++++++++- manifest | 16 ++++++++-------- manifest.uuid | 2 +- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api index f5aabfe079..59cca49c8d 100644 --- a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api +++ b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api @@ -14,6 +14,7 @@ _sqlite3_changes _sqlite3_changes64 _sqlite3_clear_bindings _sqlite3_close_v2 +_sqlite3_collation_needed _sqlite3_column_blob _sqlite3_column_bytes _sqlite3_column_count @@ -27,6 +28,8 @@ _sqlite3_column_type _sqlite3_compileoption_get _sqlite3_compileoption_used _sqlite3_complete +_sqlite3_create_collation +_sqlite3_create_collation_v2 _sqlite3_create_function _sqlite3_create_function_v2 _sqlite3_create_module @@ -83,7 +86,9 @@ _sqlite3_sourceid _sqlite3_sql _sqlite3_step _sqlite3_strglob +_sqlite3_stricmp _sqlite3_strlike +_sqlite3_strnicmp _sqlite3_total_changes _sqlite3_total_changes64 _sqlite3_trace_v2 diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js index ddfc1daf43..0516953f10 100644 --- a/ext/wasm/api/sqlite3-api-glue.js +++ b/ext/wasm/api/sqlite3-api-glue.js @@ -579,7 +579,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ "int", ["sqlite3*", "*", "int", "int", "**", "**"]); - /* Documented in the api object's initializer. */ + /* Documented in the capi object's initializer. */ capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail){ if(f.length!==arguments.length){ return __dbArgcMismatch(pDb,"sqlite3_prepare_v3",f.length); @@ -596,7 +596,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ } }; - /* Documented in the api object's initializer. */ + /* Documented in the capi object's initializer. */ capi.sqlite3_prepare_v2 = function f(pDb, sql, sqlLen, ppStmt, pzTail){ return (f.length===arguments.length) ? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail) diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index 5f456edf27..5632569d72 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -900,6 +900,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ["sqlite3_close_v2", "int", "sqlite3*"], ["sqlite3_changes", "int", "sqlite3*"], ["sqlite3_clear_bindings","int", "sqlite3_stmt*"], + ["sqlite3_collation_needed", "int", "sqlite3*", "*", "*"/*=>v(ppis)*/], ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"], ["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"], ["sqlite3_column_count", "int", "sqlite3_stmt*"], @@ -914,6 +915,12 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( /* sqlite3_create_function(), sqlite3_create_function_v2(), and sqlite3_create_window_function() use hand-written bindings to simplify handling of their function-type arguments. */ + ["sqlite3_create_collation", "int", + "sqlite3*", "string", "int"/*SQLITE_UTF8 is the only legal value*/, + "*", "*"], + ["sqlite3_create_collation_v2", "int", + "sqlite3*", "string", "int"/*SQLITE_UTF8 is the only legal value*/, + "*", "*", "*"], ["sqlite3_data_count", "int", "sqlite3_stmt*"], ["sqlite3_db_filename", "string", "sqlite3*", "string"], ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"], @@ -970,7 +977,9 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ["sqlite3_sql", "string", "sqlite3_stmt*"], ["sqlite3_step", "int", "sqlite3_stmt*"], ["sqlite3_strglob", "int", "string","string"], - ["sqlite3_strlike", "int", "string","string","int"], + ["sqlite3_stricmp", "int", "string", "string"], + ["sqlite3_strlike", "int", "string", "string","int"], + ["sqlite3_strnicmp", "int", "string", "string", "int"], ["sqlite3_trace_v2", "int", "sqlite3*", "int", "*", "*"], ["sqlite3_total_changes", "int", "sqlite3*"], /* Note sqlite3_uri_...() has very specific requirements diff --git a/manifest b/manifest index 3084b5ab0b..2b59fffc13 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Export\ssqlite3_vtab_collation()\sto\swasm.\sRename\s'flexible-string'\sJS\sargument\sadapter\sto\s'string:flexible'\sfor\sconsistency. -D 2022-12-05T13:12:48.698 +C Export\scollation-related\sAPIs\sand\sstrncmp()/strnicmp()\sto\swasm. +D 2022-12-05T13:33:42.870 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -494,7 +494,7 @@ F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34ce F ext/wasm/GNUmakefile bfa47f169468ca9db031105b0e336db29a88e93c3abd217d0bbb2b8731fa5413 F ext/wasm/README-dist.txt 2d670b426fc7c613b90a7d2f2b05b433088fe65181abead970980f0a4a75ea20 F ext/wasm/README.md ef39861aa21632fdbca0bdd469f78f0096f6449a720f3f39642594af503030e9 -F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api e17dc504c135e0d9585282faa82bf8ef3c45465b086fb02fb5605e821efb5bbc +F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 65456c98b3433b6b34b1253885ccf9a59146a8fb1b5d41a8638e86b5d1f87d55 F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287 F ext/wasm/api/README.md 20a256f4aaae80035d2bb1c9e3e0a125570313a8d137d427471d7be10edde87a F ext/wasm/api/extern-post-js.c-pp.js 8923f76c3d2213159e12d641dc750523ead5c848185dc4996fae5cc12397f88d @@ -503,9 +503,9 @@ F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08 F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62 F ext/wasm/api/pre-js.c-pp.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f9e91c1d5f F ext/wasm/api/sqlite3-api-cleanup.js 680d5ccfff54459db136a49b2199d9f879c8405d9c99af1dda0cc5e7c29056f4 -F ext/wasm/api/sqlite3-api-glue.js e3422737c64bb6d871ddff7f7c85e637cc1597edd3bc49ef537578c57d6cfaa9 +F ext/wasm/api/sqlite3-api-glue.js c3a11e1d0e6fd381f68f9e76ad01f3616a6b809fbf9f5aa8e323955c128a6811 F ext/wasm/api/sqlite3-api-oo1.js 793883953d4024e7b8c5ee1c7a6cb49c18ca53a1d235a203f93746f8907d32ba -F ext/wasm/api/sqlite3-api-prologue.js 6f5aee50867dae4e0885dd1bd1913f1f42f433def15ca9309dc5b3e83ab5c667 +F ext/wasm/api/sqlite3-api-prologue.js 92dd2dd3efedfbe9f75d2663ed6af1164ace93bf64b20204cb12db13c08affec F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 F ext/wasm/api/sqlite3-opfs-async-proxy.js f79dd8d98ef3e0b55c10bb2bee7a3840fa967318e1f577c156aafc34664271d1 @@ -2065,8 +2065,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 9d81d51d5a255b42f8416da850c992a9e4c8eebc940e0702a9262cfcaa6d7b2f -R 277425a2c74bda828b2402faf303a6b1 +P 15f8042fddaeabab43dd187c463d3ccc56758cbf19bf2ca4837d9087a4850c1a +R 017b8d9d1b435c1f731acc879040c83a U stephan -Z c0b7c94a232e1e96230a439e5bd96242 +Z 3190520e942052577f9152539aa749d6 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 43725293de..27930bfe58 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -15f8042fddaeabab43dd187c463d3ccc56758cbf19bf2ca4837d9087a4850c1a \ No newline at end of file +c3c56d9b944fd0d806d8dad9f0c7be3d7a5441765310908872cc525d82ab6a33 \ No newline at end of file From e1d25177c2acf7c3584c29ba9979427c4ac4060e Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 5 Dec 2022 14:13:55 +0000 Subject: [PATCH 08/22] Expose sqlite3_get/set_auxdata() to wasm. Minor test app CSS tweaks. FossilOrigin-Name: 44659ad32a9fe6363badfc5dbb0bd51d6fb2ee1c8aa47b71e9cf3dbd631fde9e --- ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api | 2 ++ ext/wasm/api/sqlite3-api-prologue.js | 22 +++++++++++++-------- ext/wasm/common/emscripten.css | 2 +- ext/wasm/common/testing.css | 6 ++++++ ext/wasm/tester1-worker.html | 6 +----- ext/wasm/tester1.c-pp.html | 9 ++------- manifest | 22 ++++++++++----------- manifest.uuid | 2 +- 8 files changed, 38 insertions(+), 33 deletions(-) diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api index 59cca49c8d..523488cf08 100644 --- a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api +++ b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api @@ -52,6 +52,7 @@ _sqlite3_extended_result_codes _sqlite3_file_control _sqlite3_finalize _sqlite3_free +_sqlite3_get_auxdata _sqlite3_initialize _sqlite3_libversion _sqlite3_libversion_number @@ -81,6 +82,7 @@ _sqlite3_result_text _sqlite3_result_zeroblob _sqlite3_result_zeroblob64 _sqlite3_serialize +_sqlite3_set_auxdata _sqlite3_shutdown _sqlite3_sourceid _sqlite3_sql diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index 5632569d72..a51e957f8f 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -942,6 +942,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"], ["sqlite3_finalize", "int", "sqlite3_stmt*"], ["sqlite3_free", undefined,"*"], + ["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"], ["sqlite3_initialize", undefined], /*["sqlite3_interrupt", undefined, "sqlite3*" ^^^ we cannot actually currently support this because JS is @@ -959,19 +960,20 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( the range of supported argument types. */ ["sqlite3_realloc", "*","*","int"], ["sqlite3_reset", "int", "sqlite3_stmt*"], - ["sqlite3_result_blob",undefined, "sqlite3_context*", "*", "int", "*"], - ["sqlite3_result_double",undefined, "sqlite3_context*", "f64"], - ["sqlite3_result_error",undefined, "sqlite3_context*", "string", "int"], + ["sqlite3_result_blob", undefined, "sqlite3_context*", "*", "int", "*"], + ["sqlite3_result_double", undefined, "sqlite3_context*", "f64"], + ["sqlite3_result_error", undefined, "sqlite3_context*", "string", "int"], ["sqlite3_result_error_code", undefined, "sqlite3_context*", "int"], ["sqlite3_result_error_nomem", undefined, "sqlite3_context*"], ["sqlite3_result_error_toobig", undefined, "sqlite3_context*"], - ["sqlite3_result_int",undefined, "sqlite3_context*", "int"], - ["sqlite3_result_null",undefined, "sqlite3_context*"], - ["sqlite3_result_pointer",undefined, + ["sqlite3_result_int", undefined, "sqlite3_context*", "int"], + ["sqlite3_result_null", undefined, "sqlite3_context*"], + ["sqlite3_result_pointer", undefined, "sqlite3_context*", "*", "string:static", "*"], - ["sqlite3_result_text",undefined, "sqlite3_context*", "string", "int", "*"], + ["sqlite3_result_text", undefined, "sqlite3_context*", "string", "int", "*"], ["sqlite3_result_zeroblob", undefined, "sqlite3_context*", "int"], ["sqlite3_serialize","*", "sqlite3*", "string", "*", "int"], + ["sqlite3_set_auxdata", undefined, "sqlite3_context*", "int", "*", "*"/* => v(*) */], ["sqlite3_shutdown", undefined], ["sqlite3_sourceid", "string"], ["sqlite3_sql", "string", "sqlite3_stmt*"], @@ -1012,6 +1014,10 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( Functions which require BigInt (int64) support are separated from the others because we need to conditionally bind them or apply dummy impls, depending on the capabilities of the environment. + + Note that not all of these functions directly require int64 + but are only for use with APIs which require int64. For example, + the vtab-related functions. */ wasm.bindingSignatures.int64 = [ ["sqlite3_bind_int64","int", ["sqlite3_stmt*", "int", "i64"]], @@ -1027,7 +1033,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ["sqlite3_msize", "i64", "*"], ["sqlite3_overload_function", "int", ["sqlite3*","string","int"]], ["sqlite3_realloc64", "*","*", "i64"], - ["sqlite3_result_int64",undefined, "*", "i64"], + ["sqlite3_result_int64", undefined, "*", "i64"], ["sqlite3_result_zeroblob64", "int", "*", "i64"], ["sqlite3_total_changes64", "i64", ["sqlite3*"]], ["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]], diff --git a/ext/wasm/common/emscripten.css b/ext/wasm/common/emscripten.css index 7e3dc811d0..d8f82c73b2 100644 --- a/ext/wasm/common/emscripten.css +++ b/ext/wasm/common/emscripten.css @@ -1,4 +1,4 @@ -/* emcscript-related styling, used during the module load/intialization processes... */ +/* emscripten-related styling, used during the module load/intialization processes... */ .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; } div.emscripten { text-align: center; } div.emscripten_border { border: 1px solid black; } diff --git a/ext/wasm/common/testing.css b/ext/wasm/common/testing.css index 9438b330c9..fb44f1d612 100644 --- a/ext/wasm/common/testing.css +++ b/ext/wasm/common/testing.css @@ -61,3 +61,9 @@ span.labeled-input { flex-direction: column-reverse; } label[for] { cursor: pointer } + +h1 { + border-radius: 0.25em; + padding: 0.15em 0.25em; +} +h1:first-of-type {margin: 0 0 0.5em 0;} diff --git a/ext/wasm/tester1-worker.html b/ext/wasm/tester1-worker.html index eba3fdeb4e..a9c12d72c5 100644 --- a/ext/wasm/tester1-worker.html +++ b/ext/wasm/tester1-worker.html @@ -7,11 +7,7 @@ sqlite3 tester #1: Worker thread - +

sqlite3 tester #1: Worker thread

diff --git a/ext/wasm/tester1.c-pp.html b/ext/wasm/tester1.c-pp.html index b1b68e486e..535e58962d 100644 --- a/ext/wasm/tester1.c-pp.html +++ b/ext/wasm/tester1.c-pp.html @@ -13,14 +13,9 @@ ES6 Module in UI thread UI thread //#endif - + - -

+

See tester1-worker.html for the Worker-thread variant.
diff --git a/manifest b/manifest index 2b59fffc13..8345aa2237 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Export\scollation-related\sAPIs\sand\sstrncmp()/strnicmp()\sto\swasm. -D 2022-12-05T13:33:42.870 +C Expose\ssqlite3_get/set_auxdata()\sto\swasm.\sMinor\stest\sapp\sCSS\stweaks. +D 2022-12-05T14:13:55.858 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -494,7 +494,7 @@ F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34ce F ext/wasm/GNUmakefile bfa47f169468ca9db031105b0e336db29a88e93c3abd217d0bbb2b8731fa5413 F ext/wasm/README-dist.txt 2d670b426fc7c613b90a7d2f2b05b433088fe65181abead970980f0a4a75ea20 F ext/wasm/README.md ef39861aa21632fdbca0bdd469f78f0096f6449a720f3f39642594af503030e9 -F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 65456c98b3433b6b34b1253885ccf9a59146a8fb1b5d41a8638e86b5d1f87d55 +F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api ffa70413409e922ce0f761779787a1d9100b34b43c8e3106bb7ccf2786a41326 F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287 F ext/wasm/api/README.md 20a256f4aaae80035d2bb1c9e3e0a125570313a8d137d427471d7be10edde87a F ext/wasm/api/extern-post-js.c-pp.js 8923f76c3d2213159e12d641dc750523ead5c848185dc4996fae5cc12397f88d @@ -505,7 +505,7 @@ F ext/wasm/api/pre-js.c-pp.js b88499dc303c21fc3f55f2c364a0f814f587b60a9578430388 F ext/wasm/api/sqlite3-api-cleanup.js 680d5ccfff54459db136a49b2199d9f879c8405d9c99af1dda0cc5e7c29056f4 F ext/wasm/api/sqlite3-api-glue.js c3a11e1d0e6fd381f68f9e76ad01f3616a6b809fbf9f5aa8e323955c128a6811 F ext/wasm/api/sqlite3-api-oo1.js 793883953d4024e7b8c5ee1c7a6cb49c18ca53a1d235a203f93746f8907d32ba -F ext/wasm/api/sqlite3-api-prologue.js 92dd2dd3efedfbe9f75d2663ed6af1164ace93bf64b20204cb12db13c08affec +F ext/wasm/api/sqlite3-api-prologue.js 815fef5ee93e1bb11ebec5a1d6a1b8ae2e47cfeb66dc5f6e93380ccce045f194 F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 F ext/wasm/api/sqlite3-opfs-async-proxy.js f79dd8d98ef3e0b55c10bb2bee7a3840fa967318e1f577c156aafc34664271d1 @@ -519,8 +519,8 @@ F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d F ext/wasm/batch-runner.js 49609e89aaac9989d6c1ad3fae268e4878e1ad7bc5fd3e5c2f44959660780b2e F ext/wasm/c-pp.c 92285f7bce67ed7b7020b40fde8ed0982c442b63dc33df9dfd4b658d4a6c0779 F ext/wasm/common/SqliteTestUtil.js d8bf97ecb0705a2299765c8fc9e11b1a5ac7f10988bbf375a6558b7ca287067b -F ext/wasm/common/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f -F ext/wasm/common/testing.css 35889709547d89a6109ff83b25c11bbc91d8dd43aab8722e428655ca98880a06 +F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15 +F ext/wasm/common/testing.css 0ff15602a3ab2bad8aef2c3bd120c7ee3fd1c2054ad2ace7e214187ae68d926f F ext/wasm/common/whwasmutil.js 0de1e72494d52185d518892a3ac95d38b8e295d3699b64ddb36a3d46c11c8346 F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508 @@ -553,8 +553,8 @@ F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d826 F ext/wasm/sql/001-sudoku.sql 35b7cb7239ba5d5f193bc05ec379bcf66891bce6f2a5b3879f2f78d0917299b5 F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555e685bce3da8c3f F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac -F ext/wasm/tester1-worker.html 29b1d87f7d51f70d61645719fee657f3787fe939bb695f27034c75404e8f1e6f -F ext/wasm/tester1.c-pp.html 74aa9b31c75f12490653f814b53c3dd39f40cd3f70d6a53a716f4e8587107399 +F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9 +F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406 F ext/wasm/tester1.c-pp.js 419a2fd31b0230e0495ed38a56dbe1e2bbc93c5953b796de43e2a70901970b83 F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70 F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d @@ -2065,8 +2065,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 15f8042fddaeabab43dd187c463d3ccc56758cbf19bf2ca4837d9087a4850c1a -R 017b8d9d1b435c1f731acc879040c83a +P c3c56d9b944fd0d806d8dad9f0c7be3d7a5441765310908872cc525d82ab6a33 +R 585ea2dfb36f1f8d84b5d643e3dc1f7a U stephan -Z 3190520e942052577f9152539aa749d6 +Z 583c0236badf6d39ab9de3ab68428681 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 27930bfe58..3aea11316b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c3c56d9b944fd0d806d8dad9f0c7be3d7a5441765310908872cc525d82ab6a33 \ No newline at end of file +44659ad32a9fe6363badfc5dbb0bd51d6fb2ee1c8aa47b71e9cf3dbd631fde9e \ No newline at end of file From cfb66014bc067ea38f03728972153753a258c348 Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 5 Dec 2022 14:32:35 +0000 Subject: [PATCH 09/22] Jaccwabyt (JS) doc updates. FossilOrigin-Name: a329a809b5da135a9c251e4d5f637d45d01d0248110ac05f2ad8f01d9df38c64 --- ext/wasm/jaccwabyt/jaccwabyt.js | 7 +++-- ext/wasm/jaccwabyt/jaccwabyt.md | 51 +++++++++++++++++++-------------- manifest | 14 ++++----- manifest.uuid | 2 +- 4 files changed, 43 insertions(+), 31 deletions(-) diff --git a/ext/wasm/jaccwabyt/jaccwabyt.js b/ext/wasm/jaccwabyt/jaccwabyt.js index 7c8d42b331..960aae7936 100644 --- a/ext/wasm/jaccwabyt/jaccwabyt.js +++ b/ext/wasm/jaccwabyt/jaccwabyt.js @@ -598,10 +598,13 @@ self.Jaccwabyt = function StructBinderFactory(config){ new DataView(heap().buffer, this.pointer + descr.offset, descr.sizeof) )[f._.getters[sigGlyph]](0, isLittleEndian); if(dbg.getter) log("debug.getter:",xPropName,"result =",rc); - if(rc && isAutoPtrSig(descr.signature)){ + /* // Removed: it is legal for multiple StructType instances to + // proxy the same pointer, and instanceForPointer() cannot account + // for that. + if(rc && isAutoPtrSig(descr.signature)){ rc = StructType.instanceForPointer(rc) || rc; if(dbg.getter) log("debug.getter:",xPropName,"resolved =",rc); - } + }*/ return rc; }; if(descr.readOnly){ diff --git a/ext/wasm/jaccwabyt/jaccwabyt.md b/ext/wasm/jaccwabyt/jaccwabyt.md index 73f6bfa947..855a1d16a0 100644 --- a/ext/wasm/jaccwabyt/jaccwabyt.md +++ b/ext/wasm/jaccwabyt/jaccwabyt.md @@ -281,8 +281,8 @@ supported letters are: signature entry. - **`f`** = `float` (4 bytes) - **`d`** = `double` (8 bytes) -- **`c`** = `int8` (char - see notes below!) -- **`C`** = `int8` (unsigned char - see notes below!) +- **`c`** = `int8` (1 byte) char - see notes below! +- **`C`** = `uint8` (1 byte) unsigned char - see notes below! - **`p`** = `int32` (see notes below!) - **`P`** = Like `p` but with extra handling. Described below. - **`s`** = like `int32` but is a _hint_ that it's a pointer to a @@ -295,10 +295,10 @@ supported letters are: Noting that: -- All of these types are numeric. Attempting to set any struct-bound - property to a non-numeric value will trigger an exception except in - cases explicitly noted otherwise. -- "Char" types: WASM does not define an `int8` type, nor does it +- **All of these types are numeric**. Attempting to set any + struct-bound property to a non-numeric value will trigger an + exception except in cases explicitly noted otherwise. +- **"Char" types**: WASM does not define an `int8` type, nor does it distinguish between signed and unsigned. This API treats `c` as `int8` and `C` as `uint8` for purposes of getting and setting values when using the `DataView` class. It is _not_ recommended that client @@ -345,12 +345,15 @@ special use of unsigned numbers). A capital `P` changes the semantics of plain member pointers (but not, as of this writing, function pointer members) as follows: -- When a `P`-type member is **fetched** via `myStruct.x` and its value is - a non-0 integer, [`StructBinder.instanceForPointer()`][StructBinder] - is used to try to map that pointer to a struct instance. If a match - is found, the "get" operation returns that instance instead of the - integer. If no match is found, it behaves exactly as for `p`, returning - the integer value. +- When a `P`-type member is **fetched** via `myStruct.x` and its + value is a non-0 integer, + [`StructBinder.instanceForPointer()`][StructBinder] is used to try + to map that pointer to a struct instance. If a match is found, the + "get" operation returns that instance instead of the integer. If no + match is found, it behaves exactly as for `p`, returning the integer + value. Removed because it's legal and possible to for multiple + instances to proxy the same pointer and this infrastructure cannot + account for that. - When a `P`-type member is **set** via `myStruct.x=y`, if [`(y instanceof StructType)`][StructType] then the value of `y.pointer` is stored in `myStruct.x`. If `y` is neither a number nor @@ -403,7 +406,6 @@ instances which have not been manually disposed. The following usage pattern offers one way to easily ensure proper cleanup of struct instances: - > ```javascript const my = new MyStruct(); @@ -417,11 +419,6 @@ try { from the byte array. */ // Pass the struct to C code which takes a MyStruct pointer: aCFunction( my.pointer ); - // Type-safely check if a pointer returned from C is a MyStruct: - const x = MyStruct.instanceForPointer( anotherCFunction() ); - // If it is a MyStruct, x now refers to that object. Note, however, - // that this only works for instances created in JS, as the - // pointer mapping only exists in JS space. } finally { my.dispose(); } @@ -434,6 +431,15 @@ to use `try`/`finally` without a `catch`, and doing so is an ideal match for the memory management requirements of Jaccwaby-bound struct instances. +It is often useful to wrap an existing instance of a C-side struct +without taking over ownership of its memory. That can be achieved by +simply passing a pointer to the constructor. For example: + +```js +const m = new MyStruct( functionReturningASharedPtr() ); +// calling m.dispose() will _not_ free the wrapped C-side instance. +``` + Now that we have struct instances, there are a number of things we can do with them, as covered in the rest of this document. @@ -557,7 +563,10 @@ The Struct Binder has the following members: any of its "significant" configuration values may have undefined results. -- `instanceForPointer(pointer)` +- `instanceForPointer(pointer)` (DEPRECATED) + *Do not use this - it will be removed* because it is legal for + multiple StructType instances to proxy the same pointer, and + instanceForPointer() cannot account for that.\ Given a pointer value relative to `config.memory`, if that pointer resolves to a struct of _any type_ generated via the same Struct Binder, this returns the struct instance associated with it, or @@ -599,7 +608,7 @@ individual instances via `theInstance.constructor`.): [struct's constructor][StructCtors]. If true, the memory is owned by someone other than the object and must outlive the object. -- `instanceForPointer(pointer)` +- `instanceForPointer(pointer)` (DEPRECATED) Works identically to the [StructBinder][] method of the same name. - `isA(value)` @@ -752,7 +761,7 @@ These constructors have the following "static" members: with _all_ instances and clears the `instanceForPointer()` mappings. Returns `this`. -- `instanceForPointer(pointer)` +- `instanceForPointer(pointer)` (DEPRECATED) Given a pointer value (accessible via the `pointer` property of all struct instances) which ostensibly refers to an instance of this class, this returns the instance associated with it, or `undefined` diff --git a/manifest b/manifest index 8345aa2237..0a6cf576d7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Expose\ssqlite3_get/set_auxdata()\sto\swasm.\sMinor\stest\sapp\sCSS\stweaks. -D 2022-12-05T14:13:55.858 +C Jaccwabyt\s(JS)\sdoc\supdates. +D 2022-12-05T14:32:35.107 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -539,8 +539,8 @@ F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5 F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2 F ext/wasm/index-dist.html c806b6005145b71d64240606e9c6e0bf56878ee8829c66fe7486cebf34b0e6b1 F ext/wasm/index.html f151b7c7b5cfdc066567d556acd168e769efd4e982286dc5f849a5ee69ecd0ff -F ext/wasm/jaccwabyt/jaccwabyt.js 292d37ad3b5fcef420db7b449813c38f1656f490f43e214ea4895793158e7fce -F ext/wasm/jaccwabyt/jaccwabyt.md 50df3ccb7a773634000496a2ccb805dd25cf8cd963696a7deec3209a68c6093b +F ext/wasm/jaccwabyt/jaccwabyt.js 199f3a0a7513692dac8e843fed210d4e7da12b1e3f168aff6b796e941424e8da +F ext/wasm/jaccwabyt/jaccwabyt.md c0172c0795522a137a5591ccc63703e5fc0410d7d7677884edfa8d6a9ab093f4 F ext/wasm/module-symbols.html 980680c8acfa3c8ae6a5aa223512d1b8e78040ced20f8ba2c382129bc73ec028 F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06 F ext/wasm/scratchpad-wasmfs-main.js 4c140457f4d6da9d646a49addd91edb6e9ad1643c6c48e3258b5bce24725dc18 @@ -2065,8 +2065,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c3c56d9b944fd0d806d8dad9f0c7be3d7a5441765310908872cc525d82ab6a33 -R 585ea2dfb36f1f8d84b5d643e3dc1f7a +P 44659ad32a9fe6363badfc5dbb0bd51d6fb2ee1c8aa47b71e9cf3dbd631fde9e +R b435a2d94f66e49b4a6802642705f112 U stephan -Z 583c0236badf6d39ab9de3ab68428681 +Z 58b6d11303c3251b731643b22a0a2877 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3aea11316b..a3e46a1ef5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -44659ad32a9fe6363badfc5dbb0bd51d6fb2ee1c8aa47b71e9cf3dbd631fde9e \ No newline at end of file +a329a809b5da135a9c251e4d5f637d45d01d0248110ac05f2ad8f01d9df38c64 \ No newline at end of file From 2582d418d3acf2932c438ad26726d8f1976463ae Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 5 Dec 2022 15:05:46 +0000 Subject: [PATCH 10/22] Remove two features of jaccwabyt which were fundamentally flawed, along with approx. 250 lines of unit tests which heavily relied on them. Thankfully, none of the sqlite3.js-level code used those bits. FossilOrigin-Name: a190abc307847174f36421eaa3f47ef349c6f84a2bb35857fa64f64bbe722708 --- ext/wasm/jaccwabyt/jaccwabyt.js | 65 ------- ext/wasm/jaccwabyt/jaccwabyt.md | 57 +------ ext/wasm/tester1.c-pp.js | 289 ++------------------------------ manifest | 16 +- manifest.uuid | 2 +- 5 files changed, 22 insertions(+), 407 deletions(-) diff --git a/ext/wasm/jaccwabyt/jaccwabyt.js b/ext/wasm/jaccwabyt/jaccwabyt.js index 960aae7936..0bd7869bc6 100644 --- a/ext/wasm/jaccwabyt/jaccwabyt.js +++ b/ext/wasm/jaccwabyt/jaccwabyt.js @@ -200,30 +200,6 @@ self.Jaccwabyt = function StructBinderFactory(config){ return ()=>toss(sPropName(structName,propName),"is read-only."); }; - /** - When C code passes a pointer of a bound struct to back into - a JS function via a function pointer struct member, it - arrives in JS as a number (pointer). - StructType.instanceForPointer(ptr) can be used to get the - instance associated with that pointer, and __ptrBacklinks - holds that mapping. WeakMap keys must be objects, so we - cannot use a weak map to map pointers to instances. We use - the StructType constructor as the WeakMap key, mapped to a - plain, prototype-less Object which maps the pointers to - struct instances. That arrangement gives us a - per-StructType type-safe way to resolve pointers. - */ - const __ptrBacklinks = new WeakMap(); - /** - Similar to __ptrBacklinks but is scoped at the StructBinder - level and holds pointer-to-object mappings for all struct - instances created by any struct from any StructFactory - which this specific StructBinder has created. The intention - of this is to help implement more transparent handling of - pointer-type property resolution. - */ - const __ptrBacklinksGlobal = Object.create(null); - /** In order to completely hide StructBinder-bound struct pointers from JS code, we store them in a scope-local @@ -265,8 +241,6 @@ self.Jaccwabyt = function StructBinderFactory(config){ }); } delete obj.ondispose; - delete __ptrBacklinks.get(ctor)[m]; - delete __ptrBacklinksGlobal[m]; __instancePointerMap.delete(obj); if(ctor.debugFlags.__flags.dealloc){ log("debug.dealloc:",(obj[xPtrPropName]?"EXTERNAL":""), @@ -299,8 +273,6 @@ self.Jaccwabyt = function StructBinderFactory(config){ } if(fill) heap().fill(0, m, m + ctor.structInfo.sizeof); __instancePointerMap.set(obj, m); - __ptrBacklinks.get(ctor)[m] = obj; - __ptrBacklinksGlobal[m] = obj; }catch(e){ __freeStruct(ctor, obj, m); throw e; @@ -349,16 +321,6 @@ self.Jaccwabyt = function StructBinderFactory(config){ return emscriptenFormat ? f._(m.signature) : m.signature; }; - /** - Returns the instanceForPointer() impl for the given - StructType constructor. - */ - const __instanceBacklinkFactory = function(ctor){ - const b = Object.create(null); - __ptrBacklinks.set(ctor, b); - return (ptr)=>b[ptr]; - }; - const __ptrPropDescriptor = { configurable: false, enumerable: false, get: function(){return __instancePointerMap.get(this)}, @@ -533,7 +495,6 @@ self.Jaccwabyt = function StructBinderFactory(config){ */ Object.defineProperties(StructType, { allocCString: rop(__allocCString), - instanceForPointer: rop((ptr)=>__ptrBacklinksGlobal[ptr]), isA: rop((v)=>v instanceof StructType), hasExternalPointer: rop((v)=>(v instanceof StructType) && !!v[xPtrPropName]), memberKey: __memberKeyProp @@ -598,13 +559,6 @@ self.Jaccwabyt = function StructBinderFactory(config){ new DataView(heap().buffer, this.pointer + descr.offset, descr.sizeof) )[f._.getters[sigGlyph]](0, isLittleEndian); if(dbg.getter) log("debug.getter:",xPropName,"result =",rc); - /* // Removed: it is legal for multiple StructType instances to - // proxy the same pointer, and instanceForPointer() cannot account - // for that. - if(rc && isAutoPtrSig(descr.signature)){ - rc = StructType.instanceForPointer(rc) || rc; - if(dbg.getter) log("debug.getter:",xPropName,"resolved =",rc); - }*/ return rc; }; if(descr.readOnly){ @@ -694,27 +648,9 @@ self.Jaccwabyt = function StructBinderFactory(config){ }; Object.defineProperties(StructCtor,{ debugFlags: debugFlags, - disposeAll: rop(function(){ - const map = __ptrBacklinks.get(StructCtor); - Object.keys(map).forEach(function(ptr){ - const b = map[ptr]; - if(b) __freeStruct(StructCtor, b, ptr); - }); - __ptrBacklinks.set(StructCtor, Object.create(null)); - return StructCtor; - }), - instanceForPointer: rop(__instanceBacklinkFactory(StructCtor)), isA: rop((v)=>v instanceof StructCtor), memberKey: __memberKeyProp, memberKeys: __structMemberKeys, - resolveToInstance: rop(function(v, throwIfNot=false){ - if(!(v instanceof StructCtor)){ - v = Number.isSafeInteger(v) - ? StructCtor.instanceForPointer(v) : undefined; - } - if(!v && throwIfNot) toss("Value is-not-a",StructCtor.structName); - return v; - }), methodInfoForKey: rop(function(mKey){ }), structInfo: rop(structInfo), @@ -732,7 +668,6 @@ self.Jaccwabyt = function StructBinderFactory(config){ ); return StructCtor; }; - StructBinder.instanceForPointer = StructType.instanceForPointer; StructBinder.StructType = StructType; StructBinder.config = config; StructBinder.allocCString = __allocCString; diff --git a/ext/wasm/jaccwabyt/jaccwabyt.md b/ext/wasm/jaccwabyt/jaccwabyt.md index 855a1d16a0..c6cf5c8a25 100644 --- a/ext/wasm/jaccwabyt/jaccwabyt.md +++ b/ext/wasm/jaccwabyt/jaccwabyt.md @@ -345,15 +345,6 @@ special use of unsigned numbers). A capital `P` changes the semantics of plain member pointers (but not, as of this writing, function pointer members) as follows: -- When a `P`-type member is **fetched** via `myStruct.x` and its - value is a non-0 integer, - [`StructBinder.instanceForPointer()`][StructBinder] is used to try - to map that pointer to a struct instance. If a match is found, the - "get" operation returns that instance instead of the integer. If no - match is found, it behaves exactly as for `p`, returning the integer - value. Removed because it's legal and possible to for multiple - instances to proxy the same pointer and this infrastructure cannot - account for that. - When a `P`-type member is **set** via `myStruct.x=y`, if [`(y instanceof StructType)`][StructType] then the value of `y.pointer` is stored in `myStruct.x`. If `y` is neither a number nor @@ -399,9 +390,7 @@ It is important to understand that creating a new instance allocates memory on the WASM heap. We must not simply rely on garbage collection to clean up the instances because doing so will not free up the WASM heap memory. The correct way to free up that memory is to use the -object's `dispose()` method. Alternately, there is a "nuclear option": -`MyBinder.disposeAll()` will free the memory allocated for _all_ -instances which have not been manually disposed. +object's `dispose()` method. The following usage pattern offers one way to easily ensure proper cleanup of struct instances: @@ -563,23 +552,6 @@ The Struct Binder has the following members: any of its "significant" configuration values may have undefined results. -- `instanceForPointer(pointer)` (DEPRECATED) - *Do not use this - it will be removed* because it is legal for - multiple StructType instances to proxy the same pointer, and - instanceForPointer() cannot account for that.\ - Given a pointer value relative to `config.memory`, if that pointer - resolves to a struct of _any type_ generated via the same Struct - Binder, this returns the struct instance associated with it, or - `undefined` if no struct object is mapped to that pointer. This - differs from the struct-type-specific member of the same name in - that this one is not "type-safe": it does not know the type of the - returned object (if any) and may return a struct of any - [StructType][] for which this Struct Binder has created a - constructor. It cannot return instances created via a different - [StructBinderFactory][] because each factory can hypothetically have - a different memory heap. - - API: Struct Type ------------------------------------------------------------ @@ -608,9 +580,6 @@ individual instances via `theInstance.constructor`.): [struct's constructor][StructCtors]. If true, the memory is owned by someone other than the object and must outlive the object. -- `instanceForPointer(pointer)` (DEPRECATED) - Works identically to the [StructBinder][] method of the same name. - - `isA(value)` Returns true if its argument is a StructType instance _from the same [StructBinder][]_ as this StructType. @@ -755,21 +724,6 @@ pointer can be taken over using something like These constructors have the following "static" members: -- `disposeAll()` - For each instance of this struct, the equivalent of its `dispose()` - method is called. This frees all WASM-allocated memory associated - with _all_ instances and clears the `instanceForPointer()` - mappings. Returns `this`. - -- `instanceForPointer(pointer)` (DEPRECATED) - Given a pointer value (accessible via the `pointer` property of all - struct instances) which ostensibly refers to an instance of this - class, this returns the instance associated with it, or `undefined` - if no object _of this specific struct type_ is mapped to that - pointer. When C-side code calls back into JS code and passes a - pointer to an object, this function can be used to type-safely - "cast" that pointer back to its original object. - - `isA(value)` Returns true if its argument was created by this constructor. @@ -779,15 +733,6 @@ These constructors have the following "static" members: - `memberKeys(string)` Works exactly as documented for [StructType][]. -- `resolveToInstance(value [,throwIfNot=false])` - Works like `instanceForPointer()` but accepts either an instance - of this struct type or a pointer which resolves to one. - It returns an instance of this struct type on success. - By default it returns a falsy value if its argument is not, - or does not resolve to, an instance of this struct type, - but if passed a truthy second argument then it will throw - instead. - - `structInfo` The structure description passed to [StructBinder][] when this constructor was generated. diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index 2d1b634e55..5db00cee64 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -740,9 +740,6 @@ self.sqlite3InitModule = sqlite3InitModule; assert(undefined === K.prototype.lookupMember('nope',false)). assert(k1 instanceof StructType). assert(StructType.isA(k1)). - assert(K.resolveToInstance(k1.pointer)===k1). - mustThrowMatching(()=>K.resolveToInstance(null,true), /is-not-a my_struct/). - assert(k1 === StructType.instanceForPointer(k1.pointer)). mustThrowMatching(()=>k1.$ro = 1, /read-only/); Object.keys(MyStructDef.members).forEach(function(key){ key = K.memberKey(key); @@ -752,8 +749,7 @@ self.sqlite3InitModule = sqlite3InitModule; " from "+k1.memoryDump()); }); T.assert('number' === typeof k1.pointer). - mustThrowMatching(()=>k1.pointer = 1, /pointer/). - assert(K.instanceForPointer(k1.pointer) === k1); + mustThrowMatching(()=>k1.pointer = 1, /pointer/); k1.$p4 = 1; k1.$pP = 2; T.assert(1 === k1.$p4).assert(2 === k1.$pP); if(MyStructDef.members.$p8){ @@ -768,22 +764,13 @@ self.sqlite3InitModule = sqlite3InitModule; assert('number' === typeof k1.$cstr). assert('A C-string.' === k1.memberToJsString('cstr')); k1.$pP = k2; - T.assert(k1.$pP === k2); + T.assert(k1.$pP === k2.pointer); k1.$pP = null/*null is special-cased to 0.*/; T.assert(0===k1.$pP); let ptr = k1.pointer; k1.dispose(); T.assert(undefined === k1.pointer). - assert(undefined === K.instanceForPointer(ptr)). mustThrowMatching(()=>{k1.$pP=1}, /disposed instance/); - const k3 = new K(); - ptr = k3.pointer; - T.assert(k3 === K.instanceForPointer(ptr)); - K.disposeAll(); - T.assert(ptr). - assert(undefined === k2.pointer). - assert(undefined === k3.pointer). - assert(undefined === K.instanceForPointer(ptr)); }finally{ k1.dispose(); k2.dispose(); @@ -813,10 +800,8 @@ self.sqlite3InitModule = sqlite3InitModule; assert(wts instanceof WTStruct). assert(wts instanceof StructType). assert(StructType.isA(wts)). - assert(wts === StructType.instanceForPointer(wts.pointer)); - T.assert(wts.pointer>0).assert(0===wts.$v4).assert(0n===wts.$v8). - assert(0===wts.$ppV).assert(0===wts.$xFunc). - assert(WTStruct.instanceForPointer(wts.pointer) === wts); + assert(wts.pointer>0).assert(0===wts.$v4).assert(0n===wts.$v8). + assert(0===wts.$ppV).assert(0===wts.$xFunc); const testFunc = W.xGet('sqlite3_wasm_test_struct'/*name gets mangled in -O3 builds!*/); let counter = 0; @@ -825,7 +810,6 @@ self.sqlite3InitModule = sqlite3InitModule; /*log("This from a JS function called from C, "+ "which itself was called from JS. arg =",arg);*/ ++counter; - T.assert(WTStruct.instanceForPointer(arg) === wts); if(3===counter){ tossQuietly("Testing exception propagation."); } @@ -849,7 +833,7 @@ self.sqlite3InitModule = sqlite3InitModule; testFunc(wts.pointer); //log("wts.pointer, wts.$ppV",wts.pointer, wts.$ppV); T.assert(1===counter).assert(20 === wts.$v4).assert(40n === wts.$v8) - .assert(autoResolvePtr ? (wts.$ppV === wts) : (wts.$ppV === wts.pointer)) + .assert(wts.$ppV === wts.pointer) .assert('string' === typeof wts.memberToJsString('cstr')) .assert(wts.memberToJsString('cstr') === wts.memberToJsString('$cstr')) .mustThrowMatching(()=>wts.memberToJsString('xFunc'), @@ -857,279 +841,30 @@ self.sqlite3InitModule = sqlite3InitModule; ; testFunc(wts.pointer); T.assert(2===counter).assert(40 === wts.$v4).assert(80n === wts.$v8) - .assert(autoResolvePtr ? (wts.$ppV === wts) : (wts.$ppV === wts.pointer)); + .assert(wts.$ppV === wts.pointer); /** The 3rd call to wtsFunc throw from JS, which is called from C, which is called from JS. Let's ensure that that exception propagates back here... */ T.mustThrowMatching(()=>testFunc(wts.pointer),/^Testing/); W.uninstallFunction(wts.$xFunc); wts.$xFunc = 0; - if(autoResolvePtr){ - wts.$ppV = 0; - T.assert(!wts.$ppV); - //WTStruct.debugFlags(0x03); - wts.$ppV = wts; - T.assert(wts === wts.$ppV) - //WTStruct.debugFlags(0); - } + wts.$ppV = 0; + T.assert(!wts.$ppV); + //WTStruct.debugFlags(0x03); + wts.$ppV = wts; + T.assert(wts.pointer === wts.$ppV) wts.setMemberCString('cstr', "A C-string."); T.assert(Array.isArray(wts.ondispose)). assert(wts.ondispose[0] === wts.$cstr). assert('A C-string.' === wts.memberToJsString('cstr')); const ptr = wts.pointer; wts.dispose(); - T.assert(ptr).assert(undefined === wts.pointer). - assert(undefined === WTStruct.instanceForPointer(ptr)) + T.assert(ptr).assert(undefined === wts.pointer); }finally{ wts.dispose(); } }/*StructBinder*/) - //////////////////////////////////////////////////////////////////// - .t('sqlite3.StructBinder part 2', function(sqlite3){ - // https://www.sqlite.org/c3ref/vfs.html - // https://www.sqlite.org/c3ref/io_methods.html - const sqlite3_io_methods = capi.sqlite3_io_methods, - sqlite3_vfs = capi.sqlite3_vfs, - sqlite3_file = capi.sqlite3_file; - //log("struct sqlite3_file", sqlite3_file.memberKeys()); - //log("struct sqlite3_vfs", sqlite3_vfs.memberKeys()); - //log("struct sqlite3_io_methods", sqlite3_io_methods.memberKeys()); - const installMethod = function callee(tgt, name, func){ - if(1===arguments.length){ - return (n,f)=>callee(tgt,n,f); - } - if(!callee.argcProxy){ - callee.argcProxy = function(func,sig){ - return function(...args){ - if(func.length!==arguments.length){ - toss("Argument mismatch. Native signature is:",sig); - } - return func.apply(this, args); - } - }; - callee.ondisposeRemoveFunc = function(){ - if(this.__ondispose){ - const who = this; - this.__ondispose.forEach( - (v)=>{ - if('number'===typeof v){ - try{wasm.uninstallFunction(v)} - catch(e){/*ignore*/} - }else{/*wasm function wrapper property*/ - delete who[v]; - } - } - ); - delete this.__ondispose; - } - }; - }/*static init*/ - const sigN = tgt.memberSignature(name), - memKey = tgt.memberKey(name); - //log("installMethod",tgt, name, sigN); - if(!tgt.__ondispose){ - T.assert(undefined === tgt.ondispose); - tgt.ondispose = [callee.ondisposeRemoveFunc]; - tgt.__ondispose = []; - } - const fProxy = callee.argcProxy(func, sigN); - const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true)); - tgt[memKey] = pFunc; - /** - ACHTUNG: function pointer IDs are from a different pool than - allocation IDs, starting at 1 and incrementing in steps of 1, - so if we set tgt[memKey] to those values, we'd very likely - later misinterpret them as plain old pointer addresses unless - unless we use some silly heuristic like "all values <5k are - presumably function pointers," or actually perform a function - lookup on every pointer to first see if it's a function. That - would likely work just fine, but would be kludgy. - - It turns out that "all values less than X are functions" is - essentially how it works in wasm: a function pointer is - reported to the client as its index into the - __indirect_function_table. - - So... once jaccwabyt can be told how to access the - function table, it could consider all pointer values less - than that table's size to be functions. As "real" pointer - values start much, much higher than the function table size, - that would likely work reasonably well. e.g. the object - pointer address for sqlite3's default VFS is (in this local - setup) 65104, whereas the function table has fewer than 600 - entries. - */ - const wrapperKey = '$'+memKey; - tgt[wrapperKey] = fProxy; - tgt.__ondispose.push(pFunc, wrapperKey); - //log("tgt.__ondispose =",tgt.__ondispose); - return (n,f)=>callee(tgt, n, f); - }/*installMethod*/; - - const installIOMethods = function instm(iom){ - (iom instanceof capi.sqlite3_io_methods) || toss("Invalid argument type."); - if(!instm._requireFileArg){ - instm._requireFileArg = function(arg,methodName){ - arg = capi.sqlite3_file.resolveToInstance(arg); - if(!arg){ - err("sqlite3_io_methods::xClose() was passed a non-sqlite3_file."); - } - return arg; - }; - instm._methods = { - // https://sqlite.org/c3ref/io_methods.html - xClose: /*i(P)*/function(f){ - /* int (*xClose)(sqlite3_file*) */ - log("xClose(",f,")"); - if(!(f = instm._requireFileArg(f,'xClose'))) return capi.SQLITE_MISUSE; - f.dispose(/*noting that f has externally-owned memory*/); - return 0; - }, - xRead: /*i(Ppij)*/function(f,dest,n,offset){ - /* int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst) */ - log("xRead(",arguments,")"); - if(!(f = instm._requireFileArg(f))) return capi.SQLITE_MISUSE; - wasm.heap8().fill(0, dest + offset, n); - return 0; - }, - xWrite: /*i(Ppij)*/function(f,dest,n,offset){ - /* int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst) */ - log("xWrite(",arguments,")"); - if(!(f=instm._requireFileArg(f,'xWrite'))) return capi.SQLITE_MISUSE; - return 0; - }, - xTruncate: /*i(Pj)*/function(f){ - /* int (*xTruncate)(sqlite3_file*, sqlite3_int64 size) */ - log("xTruncate(",arguments,")"); - if(!(f=instm._requireFileArg(f,'xTruncate'))) return capi.SQLITE_MISUSE; - return 0; - }, - xSync: /*i(Pi)*/function(f){ - /* int (*xSync)(sqlite3_file*, int flags) */ - log("xSync(",arguments,")"); - if(!(f=instm._requireFileArg(f,'xSync'))) return capi.SQLITE_MISUSE; - return 0; - }, - xFileSize: /*i(Pp)*/function(f,pSz){ - /* int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize) */ - log("xFileSize(",arguments,")"); - if(!(f=instm._requireFileArg(f,'xFileSize'))) return capi.SQLITE_MISUSE; - wasm.setMemValue(pSz, 0/*file size*/); - return 0; - }, - xLock: /*i(Pi)*/function(f){ - /* int (*xLock)(sqlite3_file*, int) */ - log("xLock(",arguments,")"); - if(!(f=instm._requireFileArg(f,'xLock'))) return capi.SQLITE_MISUSE; - return 0; - }, - xUnlock: /*i(Pi)*/function(f){ - /* int (*xUnlock)(sqlite3_file*, int) */ - log("xUnlock(",arguments,")"); - if(!(f=instm._requireFileArg(f,'xUnlock'))) return capi.SQLITE_MISUSE; - return 0; - }, - xCheckReservedLock: /*i(Pp)*/function(){ - /* int (*xCheckReservedLock)(sqlite3_file*, int *pResOut) */ - log("xCheckReservedLock(",arguments,")"); - return 0; - }, - xFileControl: /*i(Pip)*/function(){ - /* int (*xFileControl)(sqlite3_file*, int op, void *pArg) */ - log("xFileControl(",arguments,")"); - return capi.SQLITE_NOTFOUND; - }, - xSectorSize: /*i(P)*/function(){ - /* int (*xSectorSize)(sqlite3_file*) */ - log("xSectorSize(",arguments,")"); - return 0/*???*/; - }, - xDeviceCharacteristics:/*i(P)*/function(){ - /* int (*xDeviceCharacteristics)(sqlite3_file*) */ - log("xDeviceCharacteristics(",arguments,")"); - return 0; - } - }; - }/*static init*/ - iom.$iVersion = 1; - Object.keys(instm._methods).forEach( - (k)=>installMethod(iom, k, instm._methods[k]) - ); - }/*installIOMethods()*/; - - const iom = new sqlite3_io_methods, sfile = new sqlite3_file; - const err = console.error.bind(console); - try { - const IOM = sqlite3_io_methods, S3F = sqlite3_file; - //log("iom proto",iom,iom.constructor.prototype); - //log("sfile",sfile,sfile.constructor.prototype); - T.assert(0===sfile.$pMethods).assert(iom.pointer > 0); - //log("iom",iom); - sfile.$pMethods = iom.pointer; - T.assert(iom.pointer === sfile.$pMethods) - .assert(IOM.resolveToInstance(iom)) - .assert(undefined ===IOM.resolveToInstance(sfile)) - .mustThrow(()=>IOM.resolveToInstance(0,true)) - .assert(S3F.resolveToInstance(sfile.pointer)) - .assert(undefined===S3F.resolveToInstance(iom)) - .assert(iom===IOM.resolveToInstance(sfile.$pMethods)); - T.assert(0===iom.$iVersion); - installIOMethods(iom); - T.assert(1===iom.$iVersion); - //log("iom.__ondispose",iom.__ondispose); - T.assert(Array.isArray(iom.__ondispose)).assert(iom.__ondispose.length>10); - }finally{ - iom.dispose(); - T.assert(undefined === iom.__ondispose); - } - - const dVfs = new sqlite3_vfs(capi.sqlite3_vfs_find(null)); - try { - const SB = sqlite3.StructBinder; - T.assert(dVfs instanceof SB.StructType) - .assert(dVfs.pointer) - .assert('sqlite3_vfs' === dVfs.structName) - .assert(!!dVfs.structInfo) - .assert(SB.StructType.hasExternalPointer(dVfs)) - .assert(dVfs.$iVersion>0) - .assert('number'===typeof dVfs.$zName) - .assert('number'===typeof dVfs.$xSleep) - .assert(wasm.functionEntry(dVfs.$xOpen)) - .assert(dVfs.memberIsString('zName')) - .assert(dVfs.memberIsString('$zName')) - .assert(!dVfs.memberIsString('pAppData')) - .mustThrowMatching(()=>dVfs.memberToJsString('xSleep'), - /Invalid member type signature for C-string/) - .mustThrowMatching(()=>dVfs.memberSignature('nope'), /nope is not a mapped/) - .assert('string' === typeof dVfs.memberToJsString('zName')) - .assert(dVfs.memberToJsString('zName')===dVfs.memberToJsString('$zName')) - ; - //log("Default VFS: @",dVfs.pointer); - Object.keys(sqlite3_vfs.structInfo.members).forEach(function(mname){ - const mk = sqlite3_vfs.memberKey(mname), mbr = sqlite3_vfs.structInfo.members[mname], - addr = dVfs[mk], prefix = 'defaultVfs.'+mname; - if(1===mbr.signature.length){ - let sep = '?', val = undefined; - switch(mbr.signature[0]){ - // TODO: move this into an accessor, e.g. getPreferredValue(member) - case 'i': case 'j': case 'f': case 'd': sep = '='; val = dVfs[mk]; break - case 'p': case 'P': sep = '@'; val = dVfs[mk]; break; - case 's': sep = '='; - val = dVfs.memberToJsString(mname); - break; - } - //log(prefix, sep, val); - }else{ - //log(prefix," = funcptr @",addr, wasm.functionEntry(addr)); - } - }); - }finally{ - dVfs.dispose(); - T.assert(undefined===dVfs.pointer); - } - }/*StructBinder part 2*/) - //////////////////////////////////////////////////////////////////// .t('sqlite3.wasm.pstack', function(sqlite3){ const P = wasm.pstack; diff --git a/manifest b/manifest index 0a6cf576d7..a3f0d928c3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Jaccwabyt\s(JS)\sdoc\supdates. -D 2022-12-05T14:32:35.107 +C Remove\stwo\sfeatures\sof\sjaccwabyt\swhich\swere\sfundamentally\sflawed,\salong\swith\sapprox.\s250\slines\sof\sunit\stests\swhich\sheavily\srelied\son\sthem.\sThankfully,\snone\sof\sthe\ssqlite3.js-level\scode\sused\sthose\sbits. +D 2022-12-05T15:05:46.306 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -539,8 +539,8 @@ F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5 F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2 F ext/wasm/index-dist.html c806b6005145b71d64240606e9c6e0bf56878ee8829c66fe7486cebf34b0e6b1 F ext/wasm/index.html f151b7c7b5cfdc066567d556acd168e769efd4e982286dc5f849a5ee69ecd0ff -F ext/wasm/jaccwabyt/jaccwabyt.js 199f3a0a7513692dac8e843fed210d4e7da12b1e3f168aff6b796e941424e8da -F ext/wasm/jaccwabyt/jaccwabyt.md c0172c0795522a137a5591ccc63703e5fc0410d7d7677884edfa8d6a9ab093f4 +F ext/wasm/jaccwabyt/jaccwabyt.js b7261221133cda8d363f16ddbac8e5b671fd51ce962fc34dc10e738a293b696d +F ext/wasm/jaccwabyt/jaccwabyt.md 72742a3205f1477de68086e7e4a854ed5f7d08dfcd6db54cdbea4dba4866f159 F ext/wasm/module-symbols.html 980680c8acfa3c8ae6a5aa223512d1b8e78040ced20f8ba2c382129bc73ec028 F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06 F ext/wasm/scratchpad-wasmfs-main.js 4c140457f4d6da9d646a49addd91edb6e9ad1643c6c48e3258b5bce24725dc18 @@ -555,7 +555,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9 F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406 -F ext/wasm/tester1.c-pp.js 419a2fd31b0230e0495ed38a56dbe1e2bbc93c5953b796de43e2a70901970b83 +F ext/wasm/tester1.c-pp.js 8ed17c0e1f271e536cb7ccd86d3992785fc8bf2f94f9c2e0088ca670601ee087 F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70 F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 @@ -2065,8 +2065,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 44659ad32a9fe6363badfc5dbb0bd51d6fb2ee1c8aa47b71e9cf3dbd631fde9e -R b435a2d94f66e49b4a6802642705f112 +P a329a809b5da135a9c251e4d5f637d45d01d0248110ac05f2ad8f01d9df38c64 +R 3d4ed37777b015bac598ce3a6734f5aa U stephan -Z 58b6d11303c3251b731643b22a0a2877 +Z 002b2dd6406bdc41efd7e7f9f5d7918f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a3e46a1ef5..14e600f31e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a329a809b5da135a9c251e4d5f637d45d01d0248110ac05f2ad8f01d9df38c64 \ No newline at end of file +a190abc307847174f36421eaa3f47ef349c6f84a2bb35857fa64f64bbe722708 \ No newline at end of file From 6b271abc9853e77a19bb208893c6e2a3924e9f50 Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 6 Dec 2022 06:09:03 +0000 Subject: [PATCH 11/22] Add a demonstration sqlite3_vtab/module implemented in JS, based on ext/misc/templatevtab.c. Add oo1.selectArrays() and selectObjects(). FossilOrigin-Name: 60482c97e02bc4cafefef281be0cf0bc8c5c53232162829c137f3f7a80cdc534 --- ext/wasm/GNUmakefile | 2 +- ext/wasm/api/README.md | 9 +- ext/wasm/api/sqlite3-api-oo1.js | 29 ++ ext/wasm/api/sqlite3-api-prologue.js | 1 - ext/wasm/api/sqlite3-v-helper.js | 392 +++++++++++++++++++++++++++ ext/wasm/api/sqlite3-vfs-helper.js | 221 --------------- ext/wasm/jaccwabyt/jaccwabyt.js | 1 + ext/wasm/jaccwabyt/jaccwabyt.md | 3 +- ext/wasm/tester1.c-pp.js | 197 +++++++++++++- manifest | 26 +- manifest.uuid | 2 +- 11 files changed, 637 insertions(+), 246 deletions(-) create mode 100644 ext/wasm/api/sqlite3-v-helper.js delete mode 100644 ext/wasm/api/sqlite3-vfs-helper.js diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile index 968d4f440c..1b18437682 100644 --- a/ext/wasm/GNUmakefile +++ b/ext/wasm/GNUmakefile @@ -289,7 +289,7 @@ sqlite3-api.jses += $(dir.api)/sqlite3-api-glue.js sqlite3-api.jses += $(sqlite3-api-build-version.js) sqlite3-api.jses += $(dir.api)/sqlite3-api-oo1.js sqlite3-api.jses += $(dir.api)/sqlite3-api-worker1.js -sqlite3-api.jses += $(dir.api)/sqlite3-vfs-helper.js +sqlite3-api.jses += $(dir.api)/sqlite3-v-helper.js sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs.c-pp.js sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js diff --git a/ext/wasm/api/README.md b/ext/wasm/api/README.md index f9955a8957..ce34b26b8a 100644 --- a/ext/wasm/api/README.md +++ b/ext/wasm/api/README.md @@ -78,11 +78,10 @@ browser client: a Promise-based interface into the Worker #1 API. This is a far user-friendlier way to interface with databases running in a Worker thread. -- **`sqlite3-vfs-helper.js`**\ - This internal-use-only file installs `sqlite3.VfsHelper` for use by - `sqlite3-*.js` files which create `sqlite3_vfs` implementations. - `sqlite3.VfsHelper` gets removed from the the `sqlite3` object after - the library is finished initializing. +- **`sqlite3-v-helper.js`**\ + Installs `sqlite3.VfsHelper` and `sqlite3.VtabHelper` for use by + downstream code which creates `sqlite3_vfs` and `sqlite3_module` + implementations. - **`sqlite3-vfs-opfs.c-pp.js`**\ is an sqlite3 VFS implementation which supports Google Chrome's Origin-Private FileSystem (OPFS) as a storage layer to provide diff --git a/ext/wasm/api/sqlite3-api-oo1.js b/ext/wasm/api/sqlite3-api-oo1.js index b377efc242..6253c659fc 100644 --- a/ext/wasm/api/sqlite3-api-oo1.js +++ b/ext/wasm/api/sqlite3-api-oo1.js @@ -473,6 +473,15 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ return rc; }; + /** + Internal impl of the DB.selectArrays() and + selectObjects() methods. + */ + const __selectAll = + (db, sql, bind, rowMode)=>db.exec({ + sql, bind, rowMode, returnValue: 'resultRows' + }); + /** Expects to be given a DB instance or an `sqlite3*` pointer (may be null) and an sqlite3 API result code. If the result code is @@ -1098,6 +1107,26 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ return __selectFirstRow(this, sql, bind, {}); }, + /** + Runs the given SQL and returns an array of all results, with + each row represented as an array, as per the 'array' `rowMode` + option to `exec()`. An empty result set resolves + to an empty array. The second argument, if any, is treated as + the 'bind' option to a call to exec(). + */ + selectArrays: function(sql,bind){ + return __selectAll(this, sql, bind, 'array'); + }, + + /** + Works identically to selectArrays() except that each value + in the returned array is an object, as per the 'object' `rowMode` + option to `exec()`. + */ + selectObjects: function(sql,bind){ + return __selectAll(this, sql, bind, 'object'); + }, + /** Returns the number of currently-opened Stmt handles for this db handle, or 0 if this DB instance is closed. diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index a51e957f8f..558fcda1e0 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -1642,7 +1642,6 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( some initializers. Retain them when running in test mode so that we can add tests for them. */ delete sqlite3.util; - delete sqlite3.VfsHelper; delete sqlite3.StructBinder; } return sqlite3; diff --git a/ext/wasm/api/sqlite3-v-helper.js b/ext/wasm/api/sqlite3-v-helper.js new file mode 100644 index 0000000000..84272266e8 --- /dev/null +++ b/ext/wasm/api/sqlite3-v-helper.js @@ -0,0 +1,392 @@ +/* +** 2022-11-30 +** +** The author disclaims copyright to this source code. In place of a +** legal notice, here is a blessing: +** +** * May you do good and not evil. +** * May you find forgiveness for yourself and forgive others. +** * May you share freely, never taking more than you give. +*/ + +/** + This file installs sqlite3.VfsHelper, and object which exists to + assist in the creation of JavaScript implementations of sqlite3_vfs, + along with its virtual table counterpart, sqlite3.VtabHelper. +*/ +'use strict'; +self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ + const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss; + const vh = Object.create(null), vt = Object.create(null); + + sqlite3.VfsHelper = vh; + sqlite3.VtabHelper = vt; + + /** + Installs a StructBinder-bound function pointer member of the + given name and function in the given StructType target object. + It creates a WASM proxy for the given function and arranges for + that proxy to be cleaned up when tgt.dispose() is called. Throws + on the slightest hint of error, e.g. tgt is-not-a StructType, + name does not map to a struct-bound member, etc. + + Returns a proxy for this function which is bound to tgt and takes + 2 args (name,func). That function returns the same thing, + permitting calls to be chained. + + If called with only 1 arg, it has no side effects but returns a + func with the same signature as described above. + + If tgt.ondispose is set before this is called then it _must_ + be an array, to which this function will append entries. + + ACHTUNG: because we cannot generically know how to transform JS + exceptions into result codes, the installed functions do no + automatic catching of exceptions. It is critical, to avoid + undefined behavior in the C layer, that methods mapped via + this function do not throw. The exception, as it were, to that + rule is... + + If applyArgcCheck is true then each method gets wrapped in a + proxy which asserts that it is passed the expected number of + arguments, throwing if the argument count does not match + expectations. That is only intended for dev-time usage for sanity + checking, and will leave the C environment in an undefined + state. For non-dev-time use, it is a given that the C API will + never call one of the generated function wrappers with the wrong + argument count. + */ + vh.installMethod = vt.installMethod = function callee( + tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck + ){ + if(!(tgt instanceof sqlite3.StructBinder.StructType)){ + toss("Usage error: target object is-not-a StructType."); + } + if(1===arguments.length){ + return (n,f)=>callee(tgt, n, f, applyArgcCheck); + } + if(!callee.argcProxy){ + callee.argcProxy = function(tgt, funcName, func,sig){ + return function(...args){ + if(func.length!==arguments.length){ + toss("Argument mismatch for", + tgt.structInfo.name+"::"+funcName + +": Native signature is:",sig); + } + return func.apply(this, args); + } + }; + /* An ondispose() callback for use with + sqlite3.StructBinder-created types. */ + callee.removeFuncList = function(){ + if(this.ondispose.__removeFuncList){ + this.ondispose.__removeFuncList.forEach( + (v,ndx)=>{ + if('number'===typeof v){ + try{wasm.uninstallFunction(v)} + catch(e){/*ignore*/} + } + /* else it's a descriptive label for the next number in + the list. */ + } + ); + delete this.ondispose.__removeFuncList; + } + }; + }/*static init*/ + const sigN = tgt.memberSignature(name); + if(sigN.length<2){ + toss("Member",name," is not a function pointer. Signature =",sigN); + } + const memKey = tgt.memberKey(name); + const fProxy = applyArgcCheck + /** This middle-man proxy is only for use during development, to + confirm that we always pass the proper number of + arguments. We know that the C-level code will always use the + correct argument count. */ + ? callee.argcProxy(tgt, memKey, func, sigN) + : func; + const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true)); + tgt[memKey] = pFunc; + if(!tgt.ondispose) tgt.ondispose = []; + if(!tgt.ondispose.__removeFuncList){ + tgt.ondispose.push('ondispose.__removeFuncList handler', + callee.removeFuncList); + tgt.ondispose.__removeFuncList = []; + } + tgt.ondispose.__removeFuncList.push(memKey, pFunc); + return (n,f)=>callee(tgt, n, f, applyArgcCheck); + }/*installMethod*/; + vh.installMethod.installMethodArgcCheck = false; + + /** + Installs methods into the given StructType-type instance. Each + entry in the given methods object must map to a known member of + the given StructType, else an exception will be triggered. See + installMethod() for more details, including the semantics of the + 3rd argument. + + As an exception to the above, if any two or more methods in the + 2nd argument are the exact same function, installMethod() is + _not_ called for the 2nd and subsequent instances, and instead + those instances get assigned the same method pointer which is + created for the first instance. This optimization is primarily to + accommodate special handling of sqlite3_module::xConnect and + xCreate methods. + + On success, returns this object. Throws on error. + */ + vh.installMethods = vt.installMethods = function( + structType, methods, applyArgcCheck = vh.installMethod.installMethodArgcCheck + ){ + const seen = new Map /* map of */; + for(const k of Object.keys(methods)){ + const m = methods[k]; + const prior = seen.get(m); + if(prior){ + const mkey = structType.memberKey(k); + structType[mkey] = structType[structType.memberKey(prior)]; + }else{ + vh.installMethod(structType, k, m, applyArgcCheck); + seen.set(m, k); + } + } + return this; + }; + + /** + Uses sqlite3_vfs_register() to register the + sqlite3.capi.sqlite3_vfs-type vfs, which must have already been + filled out properly. If the 2nd argument is truthy, the VFS is + registered as the default VFS, else it is not. + + On success, returns this object. Throws on error. + */ + vh.registerVfs = function(vfs, asDefault=false){ + if(!(vfs instanceof sqlite3.capi.sqlite3_vfs)){ + toss("Expecting a sqlite3_vfs-type argument."); + } + const rc = capi.sqlite3_vfs_register(vfs.pointer, asDefault ? 1 : 0); + if(rc){ + toss("sqlite3_vfs_register(",vfs,") failed with rc",rc); + } + if(vfs.pointer !== capi.sqlite3_vfs_find(vfs.$zName)){ + toss("BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS", + vfs); + } + return this; + }; + + /** + A wrapper for installMethods() or registerVfs() to reduce + installation of a VFS and/or its I/O methods to a single + call. + + Accepts an object which contains the properties "io" and/or + "vfs", each of which is itself an object with following properties: + + - `struct`: an sqlite3.StructType-type struct. This must be a + populated (except for the methods) object of type + sqlite3_io_methods (for the "io" entry) or sqlite3_vfs (for the + "vfs" entry). + + - `methods`: an object mapping sqlite3_io_methods method names + (e.g. 'xClose') to JS implementations of those methods. The JS + implementations must be call-compatible with their native + counterparts. + + For each of those object, this function passes its (`struct`, + `methods`, (optional) `applyArgcCheck`) properties to + this.installMethods(). + + If the `vfs` entry is set then: + + - Its `struct` property is passed to this.registerVfs(). The + `vfs` entry may optionally have an `asDefault` property, which + gets passed as the 2nd argument to registerVfs(). + + - If `struct.$zName` is falsy and the entry has a string-type + `name` property, `struct.$zName` is set to the C-string form of + that `name` value before registerVfs() is called. + + On success returns this object. Throws on error. + */ + vh.installVfs = function(opt){ + let count = 0; + const propList = ['io','vfs']; + for(const key of propList){ + const o = opt[key]; + if(o){ + ++count; + this.installMethods(o.struct, o.methods, !!o.applyArgcCheck); + if('vfs'===key){ + if(!o.struct.$zName && 'string'===typeof o.name){ + o.struct.$zName = wasm.allocCString(o.name); + /* Note that we leak that C-string. */ + } + this.registerVfs(o.struct, !!o.asDefault); + } + } + } + if(!count) toss("Misuse: installVfs() options object requires at least", + "one of:", propList); + return this; + }; + + /** + Expects to be passed the (argc,argv) arguments of + sqlite3_module::xFilter(), or an equivalent API. This function + transforms the arguments (an array of (sqlite3_value*)) into a JS + array of equivalent JS values. It uses the same type conversions + as sqlite3_create_function_v2() and friends. Throws on error, + e.g. if it cannot figure out a sensible data conversion. + */ + vt.sqlite3ValuesToJs = capi.sqlite3_create_function_v2.udfConvertArgs; + + /** + Factory function for xyz2js() impls. + */ + const __v2jsFactory = function(structType){ + return function(ptr,remove=false){ + if(0===arguments.length) ptr = new structType; + if(ptr instanceof structType){ + //T.assert(!this.has(ptr.pointer)); + this.set(ptr.pointer, ptr); + return ptr; + }else if(!wasm.isPtr(ptr)){ + sqlite3.SQLite3Error.toss("Invalid argument to v2jsFactory"); + } + let rc = this.get(ptr); + if(remove) this.delete(ptr); + /*arguable else if(!rc){ + rc = new structType(ptr); + this.set(ptr, rc); + }*/ + return rc; + }.bind(new Map); + }; + /** + EXPERIMENTAL. DO NOT USE IN CLIENT CODE. + + Has 3 distinct uses: + + - vtab2js() instantiates a new capi.sqlite3_vtab instance, maps + its pointer for later by-pointer lookup, and returns that + object. This is intended to be called from + sqlite3_module::xConnect() or xCreate() implementations. + + - vtab2js(pVtab) accepts a WASM pointer to a C-level + (sqlite3_vtab*) instance and returns the capi.sqlite3_vtab + object created by the first form of this function, or undefined + if that form has not been used. This is intended to be called + from sqlite3_module methods which take a (sqlite3_vtab*) pointer + _except_ for xDisconnect(), in which case use... + + - vtab2js(pVtab,true) as for the previous form, but removes the + pointer-to-object mapping before returning. The caller must + call dispose() on the returned object. This is intended to be + called from sqlite3_module::xDisconnect() implementations or + in error handling of a failed xCreate() or xConnect(). + */ + vt.vtab2js = __v2jsFactory(capi.sqlite3_vtab); + + /** + EXPERIMENTAL. DO NOT USE IN CLIENT CODE. + + Works identically to vtab2js() except that it deals with + sqlite3_cursor objects and pointers instead of sqlite3_vtab. + + - vcur2js() is intended to be called from sqlite3_module::xOpen() + + - vcur2js(pCursor) is intended to be called from all sqlite3_module + methods which take a (sqlite3_vtab_cursor*) _except_ for + xClose(), in which case use... + + - vcur2js(pCursor, true) will remove the m apping of pCursor to a + capi.sqlite3_vtab_cursor object and return that object. The + caller must call dispose() on the returned object. This is + intended to be called form xClose() or in error handling of a + failed xOpen(). + */ + vt.vcur2js = __v2jsFactory(capi.sqlite3_vtab_cursor); + + /** + Given an error object, this function returns + sqlite3.capi.SQLITE_NOMEM if (e instanceof + sqlite3.WasmAllocError), else it returns its + second argument. Its intended usage is in the methods + of a sqlite3_vfs or sqlite3_module: + + ``` + try{ + let rc = ... + return rc; + }catch(e){ + return sqlite3.VtabHelper.exceptionToRc(e, sqlite3.capi.SQLITE_XYZ); + // where SQLITE_XYZ is some call-appropriate result code. + } + ``` + */ + /**vh.exceptionToRc = vt.exceptionToRc = + (e, defaultRc=capi.SQLITE_ERROR)=>( + (e instanceof sqlite3.WasmAllocError) + ? capi.SQLITE_NOMEM + : defaultRc + );*/ + + /** + Given an sqlite3_module method name and error object, this + function returns sqlite3.capi.SQLITE_NOMEM if (e instanceof + sqlite3.WasmAllocError), else it returns its second argument. Its + intended usage is in the methods of a sqlite3_vfs or + sqlite3_module: + + ``` + try{ + let rc = ... + return rc; + }catch(e){ + return sqlite3.VtabHelper.xMethodError( + 'xColumn', e, sqlite3.capi.SQLITE_XYZ); + // where SQLITE_XYZ is some call-appropriate result code + // defaulting to SQLITE_ERROR. + } + ``` + + If xMethodError.errorReporter is a function, it is called in + order to report the error, else the error is not reported. + If that function throws, that exception is ignored. + */ + vt.xMethodError = function f(methodName, err, defaultRc=capi.SQLITE_ERROR){ + if(f.errorReporter instanceof Function){ + try{f.errorReporter("sqlite3_module::"+methodName+"(): "+err.message);} + catch(e){/*ignored*/} + } + return (err instanceof sqlite3.WasmAllocError) + ? capi.SQLITE_NOMEM + : defaultRc; + }; + vt.xMethodError.errorReporter = 1 ? console.error.bind(console) : false; + + /** + "The problem" with this is that it introduces an outer function with + a different arity than the passed-in method callback. That means we + cannot do argc validation on these. Additionally, some methods (namely + xConnect) may have call-specific error handling. It would be a shame to + hard-coded that per-method support in this function. + */ + /** vt.methodCatcher = function(methodName, method, defaultErrRc=capi.SQLITE_ERROR){ + return function(...args){ + try { method(...args); } + }catch(e){ return vt.xMethodError(methodName, e, defaultRc) } + }; + */ + + /** + A helper for sqlite3_vtab::xRow() implementations. It must be + passed that function's 2nd argument and the value for that + pointer. Returns the same as wasm.setMemValue() and will throw + if the 1st or 2nd arguments are invalid for that function. + */ + vt.setRowId = (ppRowid64, value)=>wasm.setMemValue(ppRowid64, value, 'i64'); +}/*sqlite3ApiBootstrap.initializers.push()*/); diff --git a/ext/wasm/api/sqlite3-vfs-helper.js b/ext/wasm/api/sqlite3-vfs-helper.js deleted file mode 100644 index f9d3c18c7b..0000000000 --- a/ext/wasm/api/sqlite3-vfs-helper.js +++ /dev/null @@ -1,221 +0,0 @@ -/* -** 2022-11-30 -** -** The author disclaims copyright to this source code. In place of a -** legal notice, here is a blessing: -** -** * May you do good and not evil. -** * May you find forgiveness for yourself and forgive others. -** * May you share freely, never taking more than you give. -*/ - -/** - This file installs sqlite.VfsHelper, an object which exists - to assist in the creation of JavaScript implementations of - sqlite3_vfs. It is NOT part of the public API, and is an - internal implemenation detail for use in this project's - own development of VFSes. It may be exposed to clients - at some point, provided there is value in doing so. -*/ -'use strict'; -self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ - const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss; - const vh = Object.create(null); - - /** - Does nothing more than holds a permanent reference to each - argument. This is useful in some cases to ensure that, e.g., a - custom sqlite3_io_methods instance does not get - garbage-collected. - - Returns this object. - */ - vh.holdReference = function(...args){ - for(const v of args) this.refs.add(v); - return vh; - }.bind({refs: new Set}); - - /** - Installs a StructBinder-bound function pointer member of the - given name and function in the given StructType target object. - It creates a WASM proxy for the given function and arranges for - that proxy to be cleaned up when tgt.dispose() is called. Throws - on the slightest hint of error, e.g. tgt is-not-a StructType, - name does not map to a struct-bound member, etc. - - If applyArgcCheck is true then each method gets wrapped in a - proxy which asserts that it is passed the expected number of - arguments, throwing if the argument count does not match - expectations. That is only recommended for dev-time usage for - sanity checking. Once a VFS implementation is known to be - working, it is a given that the C API will never call it with the - wrong argument count. - - Returns a proxy for this function which is bound to tgt and takes - 2 args (name,func). That function returns the same thing, - permitting calls to be chained. - - If called with only 1 arg, it has no side effects but returns a - func with the same signature as described above. - - If tgt.ondispose is set before this is called then it _must_ - be an array, to which this function will append entries. - */ - vh.installMethod = function callee(tgt, name, func, - applyArgcCheck=callee.installMethodArgcCheck){ - if(!(tgt instanceof sqlite3.StructBinder.StructType)){ - toss("Usage error: target object is-not-a StructType."); - } - if(1===arguments.length){ - return (n,f)=>callee(tgt, n, f, applyArgcCheck); - } - if(!callee.argcProxy){ - callee.argcProxy = function(func,sig){ - return function(...args){ - if(func.length!==arguments.length){ - toss("Argument mismatch. Native signature is:",sig); - } - return func.apply(this, args); - } - }; - /* An ondispose() callback for use with - sqlite3.StructBinder-created types. */ - callee.removeFuncList = function(){ - if(this.ondispose.__removeFuncList){ - this.ondispose.__removeFuncList.forEach( - (v,ndx)=>{ - if('number'===typeof v){ - try{wasm.uninstallFunction(v)} - catch(e){/*ignore*/} - } - /* else it's a descriptive label for the next number in - the list. */ - } - ); - delete this.ondispose.__removeFuncList; - } - }; - }/*static init*/ - const sigN = tgt.memberSignature(name); - if(sigN.length<2){ - toss("Member",name," is not a function pointer. Signature =",sigN); - } - const memKey = tgt.memberKey(name); - const fProxy = applyArgcCheck - /** This middle-man proxy is only for use during development, to - confirm that we always pass the proper number of - arguments. We know that the C-level code will always use the - correct argument count. */ - ? callee.argcProxy(func, sigN) - : func; - const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true)); - tgt[memKey] = pFunc; - if(!tgt.ondispose) tgt.ondispose = []; - if(!tgt.ondispose.__removeFuncList){ - tgt.ondispose.push('ondispose.__removeFuncList handler', - callee.removeFuncList); - tgt.ondispose.__removeFuncList = []; - } - tgt.ondispose.__removeFuncList.push(memKey, pFunc); - return (n,f)=>callee(tgt, n, f, applyArgcCheck); - }/*installMethod*/; - vh.installMethod.installMethodArgcCheck = false; - - /** - Installs methods into the given StructType-type object. Each - entry in the given methods object must map to a known member of - the given StructType, else an exception will be triggered. - See installMethod() for more details, including the semantics - of the 3rd argument. - - On success, passes its first argument to holdRefence() and - returns this object. Throws on error. - */ - vh.installMethods = function(structType, methods, - applyArgcCheck=vh.installMethod.installMethodArgcCheck){ - for(const k of Object.keys(methods)){ - vh.installMethod(structType, k, methods[k], applyArgcCheck); - } - return vh.holdReference(structType); - }; - - /** - Uses sqlite3_vfs_register() to register the - sqlite3.capi.sqlite3_vfs-type vfs, which must have already been - filled out properly. If the 2nd argument is truthy, the VFS is - registered as the default VFS, else it is not. - - On success, passes its first argument to this.holdReference() and - returns this object. Throws on error. - */ - vh.registerVfs = function(vfs, asDefault=false){ - if(!(vfs instanceof sqlite3.capi.sqlite3_vfs)){ - toss("Expecting a sqlite3_vfs-type argument."); - } - const rc = capi.sqlite3_vfs_register(vfs.pointer, asDefault ? 1 : 0); - if(rc){ - toss("sqlite3_vfs_register(",vfs,") failed with rc",rc); - } - if(vfs.pointer !== capi.sqlite3_vfs_find(vfs.$zName)){ - toss("BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS", - vfs); - } - return vh.holdReference(vfs); - }; - - /** - A wrapper for installMethods() or registerVfs() to reduce - installation of a VFS and/or its I/O methods to a single - call. - - Accepts an object which contains the properties "io" and/or - "vfs", each of which is itself an object with following properties: - - - `struct`: an sqlite3.StructType-type struct. This must be a - populated (except for the methods) object of type - sqlite3_io_methods (for the "io" entry) or sqlite3_vfs (for the - "vfs" entry). - - - `methods`: an object mapping sqlite3_io_methods method names - (e.g. 'xClose') to JS implementations of those methods. - - For each of those object, this function passes its (`struct`, - `methods`, (optional) `applyArgcCheck`) properties to - this.installMethods(). - - If the `vfs` entry is set then: - - - Its `struct` property is passed to this.registerVfs(). The - `vfs` entry may optionally have an `asDefault` property, which - gets passed as the 2nd argument to registerVfs(). - - - If `struct.$zName` is falsy and the entry has a string-type - `name` property, `struct.$zName` is set to the C-string form of - that `name` value before registerVfs() is called. - - On success returns this object. Throws on error. - */ - vh.installVfs = function(opt){ - let count = 0; - const propList = ['io','vfs']; - for(const key of propList){ - const o = opt[key]; - if(o){ - ++count; - this.installMethods(o.struct, o.methods, !!o.applyArgcCheck); - if('vfs'===key){ - if(!o.struct.$zName && 'string'===typeof o.name){ - o.struct.$zName = wasm.allocCString(o.name); - /* Note that we leak that C-string. */ - } - this.registerVfs(o.struct, !!o.asDefault); - } - } - } - if(!count) toss("Misuse: installVfs() options object requires at least", - "one of:", propList); - return this; - }; - - sqlite3.VfsHelper = vh; -}/*sqlite3ApiBootstrap.initializers.push()*/); diff --git a/ext/wasm/jaccwabyt/jaccwabyt.js b/ext/wasm/jaccwabyt/jaccwabyt.js index 0bd7869bc6..1fa6baf154 100644 --- a/ext/wasm/jaccwabyt/jaccwabyt.js +++ b/ext/wasm/jaccwabyt/jaccwabyt.js @@ -231,6 +231,7 @@ self.Jaccwabyt = function StructBinderFactory(config){ obj.ondispose.forEach(function(x){ try{ if(x instanceof Function) x.call(obj); + else if(x instanceof StructType) x.dispose(); else if('number' === typeof x) dealloc(x); // else ignore. Strings are permitted to annotate entries // to assist in debugging. diff --git a/ext/wasm/jaccwabyt/jaccwabyt.md b/ext/wasm/jaccwabyt/jaccwabyt.md index c6cf5c8a25..17ada1edf0 100644 --- a/ext/wasm/jaccwabyt/jaccwabyt.md +++ b/ext/wasm/jaccwabyt/jaccwabyt.md @@ -426,7 +426,8 @@ simply passing a pointer to the constructor. For example: ```js const m = new MyStruct( functionReturningASharedPtr() ); -// calling m.dispose() will _not_ free the wrapped C-side instance. +// calling m.dispose() will _not_ free the wrapped C-side instance +// but will trigger any ondispose handler. ``` Now that we have struct instances, there are a number of things we diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index 5db00cee64..6fcc895329 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -419,6 +419,7 @@ self.sqlite3InitModule = sqlite3InitModule; //////////////////////////////////////////////////////////////////// T.g('C/WASM Utilities') .t('sqlite3.wasm namespace', function(sqlite3){ + // TODO: break this into smaller individual test functions. const w = wasm; const chr = (x)=>x.charCodeAt(0); //log("heap getters..."); @@ -974,7 +975,7 @@ self.sqlite3InitModule = sqlite3InitModule; .t('Create db', function(sqlite3){ const dbFile = '/tester1.db'; wasm.sqlite3_wasm_vfs_unlink(0, dbFile); - const db = this.db = new sqlite3.oo1.DB(dbFile); + const db = this.db = new sqlite3.oo1.DB(dbFile, 0 ? 'ct' : 'c'); T.assert(Number.isInteger(db.pointer)) .mustThrowMatching(()=>db.pointer=1, /read-only/) .assert(0===sqlite3.capi.sqlite3_extended_result_codes(db.pointer,1)) @@ -1197,6 +1198,29 @@ self.sqlite3InitModule = sqlite3InitModule; rc = db.selectArray('select a, b from t where b=-1'); T.assert(undefined === rc); }) + //////////////////////////////////////////////////////////////////////// + .t('selectArrays/Objects()', function(sqlite3){ + const db = this.db; + const sql = 'select a, b from t where a=? or b=? order by a'; + let rc = db.selectArrays(sql, [1, 4]); + T.assert(Array.isArray(rc)) + .assert(2===rc.length) + .assert(2===rc[0].length) + .assert(1===rc[0][0]) + .assert(2===rc[0][1]) + .assert(3===rc[1][0]) + .assert(4===rc[1][1]) + rc = db.selectArrays(sql, [99,99]); + T.assert(Array.isArray(rc)).assert(0===rc.length); + rc = db.selectObjects(sql, [1,4]); + T.assert(Array.isArray(rc)) + .assert(2===rc.length) + .assert('object' === typeof rc[1]) + .assert(1===rc[0].a) + .assert(2===rc[0].b) + .assert(3===rc[1].a) + .assert(4===rc[1].b); + }) //////////////////////////////////////////////////////////////////////// .t({ @@ -1503,6 +1527,173 @@ self.sqlite3InitModule = sqlite3InitModule; T.mustThrow(()=>db.exec("select * from foo.bar")); }) + //////////////////////////////////////////////////////////////////////// + .t({ + name: 'Custom virtual tables', + predicate: ()=>wasm.bigIntEnabled, + test: function(sqlite3){ + warn("The vtab/module JS bindings are experimental and subject to change."); + const vth = sqlite3.VtabHelper; + const tmplCols = Object.assign(Object.create(null),{ + A: 0, B: 1 + }); + /** + The vtab demonstrated here is a JS-ification of + ext/misc/templatevtab.c. + */ + const tmplMethods = { + xConnect: function(pDb, pAux, argc, argv, ppVtab, pzErr){ + try{ + const rc = capi.sqlite3_declare_vtab( + pDb, "CREATE TABLE ignored(a,b)" + ); + if(0===rc){ + const t = vth.vtab2js(); + wasm.setPtrValue(ppVtab, t.pointer); + T.assert(t === vth.vtab2js(wasm.getPtrValue(ppVtab))); + } + return rc; + }catch(e){ + if(!(e instanceof sqlite3.WasmAllocError)){ + wasm.setPtrValue(pzErr, wasm.allocCString(e.message)); + } + return vth.xMethodError('xConnect',e); + } + }, + xDisconnect: function(pVtab){ + try { + const t = vth.vtab2js(pVtab, true); + t.dispose(); + return 0; + }catch(e){ + return vth.xMethodError('xDisconnect',e); + } + }, + xOpen: function(pVtab, ppCursor){ + try{ + const t = vth.vtab2js(pVtab), c = vth.vcur2js(); + T.assert(t instanceof capi.sqlite3_vtab); + T.assert(c instanceof capi.sqlite3_vtab_cursor); + wasm.setPtrValue(ppCursor, c.pointer); + c._rowId = 0; + return 0; + }catch(e){ + return vth.xMethodError('xOpen',e); + } + }, + xClose: function(pCursor){ + try{ + const c = vth.vcur2js(pCursor,true); + T.assert(c instanceof capi.sqlite3_vtab_cursor) + .assert(!vth.vcur2js(pCursor)); + c.dispose(); + return 0; + }catch(e){ + return vth.xMethodError('xClose',e); + } + }, + xNext: function(pCursor){ + try{ + const c = vth.vcur2js(pCursor); + ++c._rowId; + return 0; + }catch(e){ + return vth.xMethodError('xNext',e); + } + + }, + xColumn: function(pCursor, pCtx, iCol){ + try{ + const c = vth.vcur2js(pCursor); + switch(iCol){ + case tmplCols.A: + capi.sqlite3_result_int(pCtx, 1000 + c._rowId); + break; + case tmplCols.B: + capi.sqlite3_result_int(pCtx, 2000 + c._rowId); + break; + default: sqlite3.SQLite3Error.toss("Invalid column id",iCol); + } + return 0; + }catch(e){ + return vth.xMethodError('xColumn',e); + } + }, + xRowid: function(pCursor, ppRowid64){ + try{ + const c = vth.vcur2js(pCursor); + vth.setRowId(ppRowid64, c._rowId); + return 0; + }catch(e){ + return vth.xMethodError('xRowid',e); + } + }, + xEof: function(pCursor){ + const c = vth.vcur2js(pCursor); + return c._rowId>=10; + }, + xFilter: function(pCursor, idxNum, idxCStr, + argc, argv/* [sqlite3_value* ...] */){ + try{ + const c = vth.vcur2js(pCursor); + c._rowId = 0; + return 0; + }catch(e){ + return vth.xMethodError('xFilter',e); + } + }, + xBestIndex: function(pVtab, pIdxInfo){ + try{ + const t = vth.vtab2js(pVtab); + const pii = new capi.sqlite3_index_info(pIdxInfo); + pii.$estimatedRows = 10; + pii.$estimatedCost = 10.0; + pii.dispose(); + return 0; + }catch(e){ + return vth.xMethodError('xBestIndex',e); + } + } + }; + /** + Problem to resolve: the vtab API places relevance on + whether xCreate and xConnect are exactly the same function + (same pointer address). Two JS-side references to the same + method will end up, without acrobatics to counter it, being + compiled as two different WASM-side bindings, i.e. two + different pointers. + + In order to account for this, VtabHelper.installMethods() + checks for duplicate function entries and maps them to the + same WASM-compiled instance + */ + if(1){ + tmplMethods.xCreate = tmplMethods.xConnect; + } + + const tmplMod = new sqlite3.capi.sqlite3_module(); + tmplMod.ondispose = []; + tmplMod.$iVersion = 0; + vth.installMethods(tmplMod, tmplMethods, true); + if(tmplMethods.xCreate){ + T.assert(tmplMod.$xCreate === tmplMod.$xConnect, + "installMethods() must avoid re-compiling identical functions"); + tmplMod.$xCreate = 0; + } + let rc = capi.sqlite3_create_module( + this.db, "testvtab", tmplMod, 0 + ); + this.db.checkRc(rc); + + const list = this.db.selectArrays( + "SELECT a,b FROM testvtab order by a" + ); + T.assert(10===list.length) + .assert(1000===list[0][0]) + .assert(2009===list[list.length-1][1]) + } + })/*vtab sanity checks*/ + //////////////////////////////////////////////////////////////////// .t({ name: 'C-side WASM tests (if compiled in)', @@ -1590,8 +1781,8 @@ self.sqlite3InitModule = sqlite3InitModule; }/* jaccwabyt-specific tests */) .t('Close db', function(){ - T.assert(this.db).assert(Number.isInteger(this.db.pointer)); - wasm.exports.sqlite3_wasm_db_reset(this.db.pointer); + T.assert(this.db).assert(wasm.isPtr(this.db.pointer)); + wasm.sqlite3_wasm_db_reset(this.db); this.db.close(); T.assert(!this.db.pointer); }) diff --git a/manifest b/manifest index a3f0d928c3..3a917c3196 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\stwo\sfeatures\sof\sjaccwabyt\swhich\swere\sfundamentally\sflawed,\salong\swith\sapprox.\s250\slines\sof\sunit\stests\swhich\sheavily\srelied\son\sthem.\sThankfully,\snone\sof\sthe\ssqlite3.js-level\scode\sused\sthose\sbits. -D 2022-12-05T15:05:46.306 +C Add\sa\sdemonstration\ssqlite3_vtab/module\simplemented\sin\sJS,\sbased\son\sext/misc/templatevtab.c.\sAdd\soo1.selectArrays()\sand\sselectObjects(). +D 2022-12-06T06:09:03.466 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -491,12 +491,12 @@ F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3 F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04 F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c -F ext/wasm/GNUmakefile bfa47f169468ca9db031105b0e336db29a88e93c3abd217d0bbb2b8731fa5413 +F ext/wasm/GNUmakefile 54c0db93a5493f625c0a993c12aee5d83951440eee03b2aecfc8aeb998182998 F ext/wasm/README-dist.txt 2d670b426fc7c613b90a7d2f2b05b433088fe65181abead970980f0a4a75ea20 F ext/wasm/README.md ef39861aa21632fdbca0bdd469f78f0096f6449a720f3f39642594af503030e9 F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api ffa70413409e922ce0f761779787a1d9100b34b43c8e3106bb7ccf2786a41326 F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287 -F ext/wasm/api/README.md 20a256f4aaae80035d2bb1c9e3e0a125570313a8d137d427471d7be10edde87a +F ext/wasm/api/README.md 17fb1e10335cc87e366dec496c5b17b061f3f75cdf216e825258de34d97a3e53 F ext/wasm/api/extern-post-js.c-pp.js 8923f76c3d2213159e12d641dc750523ead5c848185dc4996fae5cc12397f88d F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08902f15c34720ee4a1 @@ -504,12 +504,12 @@ F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b F ext/wasm/api/pre-js.c-pp.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f9e91c1d5f F ext/wasm/api/sqlite3-api-cleanup.js 680d5ccfff54459db136a49b2199d9f879c8405d9c99af1dda0cc5e7c29056f4 F ext/wasm/api/sqlite3-api-glue.js c3a11e1d0e6fd381f68f9e76ad01f3616a6b809fbf9f5aa8e323955c128a6811 -F ext/wasm/api/sqlite3-api-oo1.js 793883953d4024e7b8c5ee1c7a6cb49c18ca53a1d235a203f93746f8907d32ba -F ext/wasm/api/sqlite3-api-prologue.js 815fef5ee93e1bb11ebec5a1d6a1b8ae2e47cfeb66dc5f6e93380ccce045f194 +F ext/wasm/api/sqlite3-api-oo1.js b970787aaf0bdd3a3df59cf66aeb84d0decaaa0529aed7eaf45121087181245f +F ext/wasm/api/sqlite3-api-prologue.js 31cffd8ce212fad8d316a08decd864b0f614c5fce3686153707dffe40f8279e8 F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 F ext/wasm/api/sqlite3-opfs-async-proxy.js f79dd8d98ef3e0b55c10bb2bee7a3840fa967318e1f577c156aafc34664271d1 -F ext/wasm/api/sqlite3-vfs-helper.js 4ad4faf02e1524bf0296be8452c00b5708dce6faf649468d0377e26a0b299263 +F ext/wasm/api/sqlite3-v-helper.js 4451763a0cd85734f0afe18b48918cb3c88ca99cef399b7c5f12119281e7b6a8 w ext/wasm/api/sqlite3-vfs-helper.js F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 29d6487a26b2fb6a471cde52c37ffee7c27ed6a91914b308c247e0706f454ffb F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasm.c 723522a6c2a2463884a83fa1cc7ae5770deaaf0856a1058cc1023b2bfa1c898b @@ -539,8 +539,8 @@ F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5 F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2 F ext/wasm/index-dist.html c806b6005145b71d64240606e9c6e0bf56878ee8829c66fe7486cebf34b0e6b1 F ext/wasm/index.html f151b7c7b5cfdc066567d556acd168e769efd4e982286dc5f849a5ee69ecd0ff -F ext/wasm/jaccwabyt/jaccwabyt.js b7261221133cda8d363f16ddbac8e5b671fd51ce962fc34dc10e738a293b696d -F ext/wasm/jaccwabyt/jaccwabyt.md 72742a3205f1477de68086e7e4a854ed5f7d08dfcd6db54cdbea4dba4866f159 +F ext/wasm/jaccwabyt/jaccwabyt.js f4fc93375e9c40ef60f56cbecca1b4dc8bf4f53fab2c3abc860ed34890c5d32d +F ext/wasm/jaccwabyt/jaccwabyt.md 4bf62f7519857cdd674594aba7436cc4fae177eefbfaabc00740e16d9a828bee F ext/wasm/module-symbols.html 980680c8acfa3c8ae6a5aa223512d1b8e78040ced20f8ba2c382129bc73ec028 F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06 F ext/wasm/scratchpad-wasmfs-main.js 4c140457f4d6da9d646a49addd91edb6e9ad1643c6c48e3258b5bce24725dc18 @@ -555,7 +555,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9 F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406 -F ext/wasm/tester1.c-pp.js 8ed17c0e1f271e536cb7ccd86d3992785fc8bf2f94f9c2e0088ca670601ee087 +F ext/wasm/tester1.c-pp.js d96a77dbf0d8af11e3f3adb013bee2bfb5bf9410e3f5eade528d70104451dd10 F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70 F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 @@ -2065,8 +2065,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P a329a809b5da135a9c251e4d5f637d45d01d0248110ac05f2ad8f01d9df38c64 -R 3d4ed37777b015bac598ce3a6734f5aa +P a190abc307847174f36421eaa3f47ef349c6f84a2bb35857fa64f64bbe722708 +R 5c37541d673cc882e16d46aec14f6ca8 U stephan -Z 002b2dd6406bdc41efd7e7f9f5d7918f +Z d89d1c25adf51ede4f60b7c8a7ea4184 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 14e600f31e..17c068d5db 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a190abc307847174f36421eaa3f47ef349c6f84a2bb35857fa64f64bbe722708 \ No newline at end of file +60482c97e02bc4cafefef281be0cf0bc8c5c53232162829c137f3f7a80cdc534 \ No newline at end of file From 2a665edbd4816e0684389ecfdc63a5d5db9479a5 Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 6 Dec 2022 06:16:11 +0000 Subject: [PATCH 12/22] Minor test tweaks. FossilOrigin-Name: f902f3b2c79d6c699ead1efeb1426e1e0f4ac709afdff88be1de62f34f3d5ccc --- ext/wasm/tester1.c-pp.js | 23 ++++++++++++----------- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index 6fcc895329..2866d34f59 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -1656,16 +1656,16 @@ self.sqlite3InitModule = sqlite3InitModule; } }; /** - Problem to resolve: the vtab API places relevance on - whether xCreate and xConnect are exactly the same function - (same pointer address). Two JS-side references to the same - method will end up, without acrobatics to counter it, being - compiled as two different WASM-side bindings, i.e. two - different pointers. + The vtab API places relevance on whether xCreate and + xConnect are exactly the same function (same pointer + address). Two JS-side references to the same method will + end up, without acrobatics to counter it, being compiled as + two different WASM-side bindings, i.e. two different + pointers. In order to account for this, VtabHelper.installMethods() checks for duplicate function entries and maps them to the - same WASM-compiled instance + same WASM-compiled instance. */ if(1){ tmplMethods.xCreate = tmplMethods.xConnect; @@ -1676,8 +1676,9 @@ self.sqlite3InitModule = sqlite3InitModule; tmplMod.$iVersion = 0; vth.installMethods(tmplMod, tmplMethods, true); if(tmplMethods.xCreate){ - T.assert(tmplMod.$xCreate === tmplMod.$xConnect, - "installMethods() must avoid re-compiling identical functions"); + T.assert(tmplMod.$xCreate) + .assert(tmplMod.$xCreate === tmplMod.$xConnect, + "installMethods() must avoid re-compiling identical functions"); tmplMod.$xCreate = 0; } let rc = capi.sqlite3_create_module( @@ -1696,8 +1697,8 @@ self.sqlite3InitModule = sqlite3InitModule; //////////////////////////////////////////////////////////////////// .t({ - name: 'C-side WASM tests (if compiled in)', - predicate: haveWasmCTests, + name: 'C-side WASM tests', + predicate: ()=>(haveWasmCTests() || "Not compiled in."), test: function(){ const w = wasm, db = this.db; const stack = w.scopedAllocPush(); diff --git a/manifest b/manifest index 3a917c3196..b4b8f16bb1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\sdemonstration\ssqlite3_vtab/module\simplemented\sin\sJS,\sbased\son\sext/misc/templatevtab.c.\sAdd\soo1.selectArrays()\sand\sselectObjects(). -D 2022-12-06T06:09:03.466 +C Minor\stest\stweaks. +D 2022-12-06T06:16:11.079 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -509,7 +509,7 @@ F ext/wasm/api/sqlite3-api-prologue.js 31cffd8ce212fad8d316a08decd864b0f614c5fce F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 F ext/wasm/api/sqlite3-opfs-async-proxy.js f79dd8d98ef3e0b55c10bb2bee7a3840fa967318e1f577c156aafc34664271d1 -F ext/wasm/api/sqlite3-v-helper.js 4451763a0cd85734f0afe18b48918cb3c88ca99cef399b7c5f12119281e7b6a8 w ext/wasm/api/sqlite3-vfs-helper.js +F ext/wasm/api/sqlite3-v-helper.js 4451763a0cd85734f0afe18b48918cb3c88ca99cef399b7c5f12119281e7b6a8 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 29d6487a26b2fb6a471cde52c37ffee7c27ed6a91914b308c247e0706f454ffb F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasm.c 723522a6c2a2463884a83fa1cc7ae5770deaaf0856a1058cc1023b2bfa1c898b @@ -555,7 +555,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9 F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406 -F ext/wasm/tester1.c-pp.js d96a77dbf0d8af11e3f3adb013bee2bfb5bf9410e3f5eade528d70104451dd10 +F ext/wasm/tester1.c-pp.js 411a120a4e57b5f43c3f7448d72c48b4fedb7b4b62efe0c617dd412c192c2810 F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70 F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 @@ -2065,8 +2065,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P a190abc307847174f36421eaa3f47ef349c6f84a2bb35857fa64f64bbe722708 -R 5c37541d673cc882e16d46aec14f6ca8 +P 60482c97e02bc4cafefef281be0cf0bc8c5c53232162829c137f3f7a80cdc534 +R 72355a527ceb0556cf62fff969df2dd7 U stephan -Z d89d1c25adf51ede4f60b7c8a7ea4184 +Z 77f81bcdf15e49ab52ab2cf2ea76255f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 17c068d5db..7d693291c1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -60482c97e02bc4cafefef281be0cf0bc8c5c53232162829c137f3f7a80cdc534 \ No newline at end of file +f902f3b2c79d6c699ead1efeb1426e1e0f4ac709afdff88be1de62f34f3d5ccc \ No newline at end of file From b849832a79271c8743ddcd455d6bfcaca88433d0 Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 6 Dec 2022 08:21:23 +0000 Subject: [PATCH 13/22] Minor internal JS code/docs cleanups. FossilOrigin-Name: 21331bdd36a91b07a687ffadce392dcf2ccd0fd824b35d9dd027d4289a40fc96 --- ext/wasm/api/sqlite3-api-glue.js | 4 ++-- ext/wasm/common/whwasmutil.js | 17 +++++++++++++---- ext/wasm/jaccwabyt/jaccwabyt.js | 14 +++++++++----- ext/wasm/jaccwabyt/jaccwabyt.md | 18 +++++++++--------- manifest | 18 +++++++++--------- manifest.uuid | 2 +- 6 files changed, 43 insertions(+), 30 deletions(-) diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js index 0516953f10..89c8044be1 100644 --- a/ext/wasm/api/sqlite3-api-glue.js +++ b/ext/wasm/api/sqlite3-api-glue.js @@ -31,9 +31,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ heap: 0 ? wasm.memory : wasm.heap8u, alloc: wasm.alloc, dealloc: wasm.dealloc, - functionTable: wasm.functionTable, bigIntEnabled: wasm.bigIntEnabled, - memberPrefix: '$' + memberPrefix: /* Never change this: this prefix is baked into any + amount of code and client-facing docs. */ '$' }); delete self.Jaccwabyt; diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js index 9bce82f1a9..ea344c6ea3 100644 --- a/ext/wasm/common/whwasmutil.js +++ b/ext/wasm/common/whwasmutil.js @@ -943,10 +943,19 @@ self.WhWasmUtilInstaller = function(target){ const __allocCStr = function(jstr, returnWithLength, allocator, funcName){ __affirmAlloc(target, funcName); if('string'!==typeof jstr) return null; - const n = target.jstrlen(jstr), - ptr = allocator(n+1); - target.jstrcpy(jstr, target.heap8u(), ptr, n+1, true); - return returnWithLength ? [ptr, n] : ptr; + if(0){/* older impl, possibly more widely compatible? */ + const n = target.jstrlen(jstr), + ptr = allocator(n+1); + target.jstrcpy(jstr, target.heap8u(), ptr, n+1, true); + return returnWithLength ? [ptr, n] : ptr; + }else{/* newer, (probably) faster and (certainly) simpler impl */ + const u = cache.utf8Encoder.encode(jstr), + ptr = allocator(u.length+1), + heap = heapWrappers().HEAP8U; + heap.set(u, ptr); + heap[ptr + u.length] = 0; + return returnWithLength ? [ptr, u.length] : ptr; + } }; /** diff --git a/ext/wasm/jaccwabyt/jaccwabyt.js b/ext/wasm/jaccwabyt/jaccwabyt.js index 1fa6baf154..d5225f6e4d 100644 --- a/ext/wasm/jaccwabyt/jaccwabyt.js +++ b/ext/wasm/jaccwabyt/jaccwabyt.js @@ -61,7 +61,6 @@ self.Jaccwabyt = function StructBinderFactory(config){ BigInt = self['BigInt'], BigInt64Array = self['BigInt64Array'], /* Undocumented (on purpose) config options: */ - functionTable = config.functionTable/*EXPERIMENTAL, undocumented*/, ptrSizeof = config.ptrSizeof || 4, ptrIR = config.ptrIR || 'i32' ; @@ -258,7 +257,7 @@ self.Jaccwabyt = function StructBinderFactory(config){ iterable: false, value: v}}; /** Allocates obj's memory buffer based on the size defined in - DEF.sizeof. */ + ctor.structInfo.sizeof. */ const __allocStruct = function(ctor, obj, m){ let fill = !m; if(m) Object.defineProperty(obj, xPtrPropName, rop(m)); @@ -295,7 +294,7 @@ self.Jaccwabyt = function StructBinderFactory(config){ if tossIfNotFound is true, else returns undefined if not found. The given name may be either the name of the structInfo.members key (faster) or the key as modified by the - memberPrefix/memberSuffix settings. + memberPrefix and memberSuffix settings. */ const __lookupMember = function(structInfo, memberName, tossIfNotFound=true){ let m = structInfo.members[memberName]; @@ -423,8 +422,9 @@ self.Jaccwabyt = function StructBinderFactory(config){ const mem = alloc(u.length+1); if(!mem) toss("Allocation error while duplicating string:",str); const h = heap(); - let i = 0; - for( ; i < u.length; ++i ) h[mem + i] = u[i]; + //let i = 0; + //for( ; i < u.length; ++i ) h[mem + i] = u[i]; + h.set(u, mem); h[mem + u.length] = 0; //log("allocCString @",mem," =",u); return mem; @@ -436,6 +436,10 @@ self.Jaccwabyt = function StructBinderFactory(config){ to free any prior memory, if appropriate. The newly-allocated string is added to obj.ondispose so will be freed when the object is disposed. + + The given name may be either the name of the structInfo.members + key (faster) or the key as modified by the memberPrefix and + memberSuffix settings. */ const __setMemberCString = function(obj, memberName, str){ const m = __lookupMember(obj.structInfo, memberName, true); diff --git a/ext/wasm/jaccwabyt/jaccwabyt.md b/ext/wasm/jaccwabyt/jaccwabyt.md index 17ada1edf0..49e2d3b8ff 100644 --- a/ext/wasm/jaccwabyt/jaccwabyt.md +++ b/ext/wasm/jaccwabyt/jaccwabyt.md @@ -205,7 +205,6 @@ simply look like: The StructBinder factory function returns a function which can then be used to create bindings for our structs. - Step 2: Create a Struct Description ------------------------------------------------------------ @@ -606,14 +605,15 @@ legally be called on concrete struct instances unless noted otherwise: - If it is a function, it is called with the struct object as its `this`. That method must not throw - if it does, the exception will be ignored. - - If it is an array, it may contain functions, pointers, and/or JS - strings. If an entry is a function, it is called as described - above. If it's a number, it's assumed to be a pointer and is - passed to the `dealloc()` function configured for the parent - [StructBinder][]. If it's a JS string, it's assumed to be a - helpful description of the next entry in the list and is simply - ignored. Strings are supported primarily for use as debugging - information. + - If it is an array, it may contain functions, pointers, other + [StructType] instances, and/or JS strings. If an entry is a + function, it is called as described above. If it's a number, it's + assumed to be a pointer and is passed to the `dealloc()` function + configured for the parent [StructBinder][]. If it's a + [StructType][] instance then its `dispose()` method is called. If + it's a JS string, it's assumed to be a helpful description of the + next entry in the list and is simply ignored. Strings are + supported primarily for use as debugging information. - Some struct APIs will manipulate the `ondispose` member, creating it as an array or converting it from a function to array as needed. diff --git a/manifest b/manifest index 14bb688eee..92dde177a1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\strunk\sinto\swasm-vtab\sbranch. -D 2022-12-06T06:21:02.190 +C Minor\sinternal\sJS\scode/docs\scleanups. +D 2022-12-06T08:21:23.652 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -503,7 +503,7 @@ F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08 F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62 F ext/wasm/api/pre-js.c-pp.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f9e91c1d5f F ext/wasm/api/sqlite3-api-cleanup.js 680d5ccfff54459db136a49b2199d9f879c8405d9c99af1dda0cc5e7c29056f4 -F ext/wasm/api/sqlite3-api-glue.js c3a11e1d0e6fd381f68f9e76ad01f3616a6b809fbf9f5aa8e323955c128a6811 +F ext/wasm/api/sqlite3-api-glue.js 057c9ed555ee68ee795dc61e8d923862a0ddeb3d4cbad89866515cf5a1b77343 F ext/wasm/api/sqlite3-api-oo1.js b970787aaf0bdd3a3df59cf66aeb84d0decaaa0529aed7eaf45121087181245f F ext/wasm/api/sqlite3-api-prologue.js 31cffd8ce212fad8d316a08decd864b0f614c5fce3686153707dffe40f8279e8 F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f @@ -521,7 +521,7 @@ F ext/wasm/c-pp.c 92285f7bce67ed7b7020b40fde8ed0982c442b63dc33df9dfd4b658d4a6c07 F ext/wasm/common/SqliteTestUtil.js d8bf97ecb0705a2299765c8fc9e11b1a5ac7f10988bbf375a6558b7ca287067b F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15 F ext/wasm/common/testing.css 0ff15602a3ab2bad8aef2c3bd120c7ee3fd1c2054ad2ace7e214187ae68d926f -F ext/wasm/common/whwasmutil.js 0de1e72494d52185d518892a3ac95d38b8e295d3699b64ddb36a3d46c11c8346 +F ext/wasm/common/whwasmutil.js cedbdb2162db129fd95951025572e087066d5457adc27ffd8083610a26306fc9 F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508 F ext/wasm/demo-123.js ebae30756585bca655b4ab2553ec9236a87c23ad24fc8652115dcedb06d28df6 @@ -539,8 +539,8 @@ F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5 F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2 F ext/wasm/index-dist.html c806b6005145b71d64240606e9c6e0bf56878ee8829c66fe7486cebf34b0e6b1 F ext/wasm/index.html f151b7c7b5cfdc066567d556acd168e769efd4e982286dc5f849a5ee69ecd0ff -F ext/wasm/jaccwabyt/jaccwabyt.js f4fc93375e9c40ef60f56cbecca1b4dc8bf4f53fab2c3abc860ed34890c5d32d -F ext/wasm/jaccwabyt/jaccwabyt.md 4bf62f7519857cdd674594aba7436cc4fae177eefbfaabc00740e16d9a828bee +F ext/wasm/jaccwabyt/jaccwabyt.js 35c7eaa61ba4b875cd49da5a06a35d9935fd19121de65dd5f467cbe376359782 +F ext/wasm/jaccwabyt/jaccwabyt.md 888aff20e486abb6c955d432f9a3af271e2cdd2cd99a92c6f87077116ca57091 F ext/wasm/module-symbols.html 980680c8acfa3c8ae6a5aa223512d1b8e78040ced20f8ba2c382129bc73ec028 F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06 F ext/wasm/scratchpad-wasmfs-main.js 4c140457f4d6da9d646a49addd91edb6e9ad1643c6c48e3258b5bce24725dc18 @@ -2067,8 +2067,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P f902f3b2c79d6c699ead1efeb1426e1e0f4ac709afdff88be1de62f34f3d5ccc f41f18b1c3c950565ee3c237aebb51cfc3241813c6425813a8217e07aa0153a6 -R 8bcaf9d3b9f238bc8e19a8bbe1bb65e6 +P d106edb956bbe22bddc2c6e5bcdf4fb8f797794c725c2e359e3fa4b31d881843 +R 9cc98a74b7c97dbae209498a8d29cfcb U stephan -Z 78f5f82441cc43a02424eee016e46cb3 +Z 5e0b6a6419517a5a90c958328ab9c938 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 1b960ebdc5..7afb1aff37 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d106edb956bbe22bddc2c6e5bcdf4fb8f797794c725c2e359e3fa4b31d881843 \ No newline at end of file +21331bdd36a91b07a687ffadce392dcf2ccd0fd824b35d9dd027d4289a40fc96 \ No newline at end of file From 671386c6376b00363ef24fe8732d9e8de1078a7d Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 6 Dec 2022 08:39:17 +0000 Subject: [PATCH 14/22] Add wasm.cArgvToJs() to support sqlite3_module::xConnect(). FossilOrigin-Name: c3ebdccf94d5e63c229bf91056c08052d78732e663334070ef3b0ef6fb4bfb8f --- ext/wasm/common/whwasmutil.js | 21 +++++++++++++++++++++ ext/wasm/tester1.c-pp.js | 5 +++++ manifest | 14 +++++++------- manifest.uuid | 2 +- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js index ea344c6ea3..571486912f 100644 --- a/ext/wasm/common/whwasmutil.js +++ b/ext/wasm/common/whwasmutil.js @@ -1131,6 +1131,27 @@ self.WhWasmUtilInstaller = function(target){ */ target.allocMainArgv = (list)=>__allocMainArgv(false, list); + /** + Expects to be given a C-style string array and its length. It + returns a JS array of strings and/or nulls: any entry in the + pArgv array which is NULL results in a null entry in the result + array. If argc is 0 then an empty array is returned. + + Results are undefined if any entry in the first argc entries of + pArgv are neither 0 (NULL) nor legal UTF-format C strings. + + To be clear, the expected C-style arguments to be passed to this + function are `(int, char **)` (optionally const-qualified). + */ + target.cArgvToJs = (argc, pArgv)=>{ + const list = []; + for(let i = 0; i < argc; ++i){ + const arg = target.getPtrValue(pArgv + (target.ptrSizeof * i)); + list.push( arg ? target.cstringToJs(arg) : null ); + } + return list; + }; + /** Wraps function call func() in a scopedAllocPush() and scopedAllocPop() block, such that all calls to scopedAlloc() and diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index 2866d34f59..8ba88db18f 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -1544,6 +1544,11 @@ self.sqlite3InitModule = sqlite3InitModule; const tmplMethods = { xConnect: function(pDb, pAux, argc, argv, ppVtab, pzErr){ try{ + const args = wasm.cArgvToJs(argc, argv); + T.assert(args.length>=3) + .assert(args[0] === 'testvtab') + .assert(args[1] === 'main') + .assert(args[2] === 'testvtab'); const rc = capi.sqlite3_declare_vtab( pDb, "CREATE TABLE ignored(a,b)" ); diff --git a/manifest b/manifest index 92dde177a1..d416956d91 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\sinternal\sJS\scode/docs\scleanups. -D 2022-12-06T08:21:23.652 +C Add\swasm.cArgvToJs()\sto\ssupport\ssqlite3_module::xConnect(). +D 2022-12-06T08:39:17.647 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -521,7 +521,7 @@ F ext/wasm/c-pp.c 92285f7bce67ed7b7020b40fde8ed0982c442b63dc33df9dfd4b658d4a6c07 F ext/wasm/common/SqliteTestUtil.js d8bf97ecb0705a2299765c8fc9e11b1a5ac7f10988bbf375a6558b7ca287067b F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15 F ext/wasm/common/testing.css 0ff15602a3ab2bad8aef2c3bd120c7ee3fd1c2054ad2ace7e214187ae68d926f -F ext/wasm/common/whwasmutil.js cedbdb2162db129fd95951025572e087066d5457adc27ffd8083610a26306fc9 +F ext/wasm/common/whwasmutil.js 8be1a3a3ebca51ab5d02fc89f6d45f974b99f0d99262227094e8af4b7ade3234 F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508 F ext/wasm/demo-123.js ebae30756585bca655b4ab2553ec9236a87c23ad24fc8652115dcedb06d28df6 @@ -555,7 +555,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9 F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406 -F ext/wasm/tester1.c-pp.js 411a120a4e57b5f43c3f7448d72c48b4fedb7b4b62efe0c617dd412c192c2810 +F ext/wasm/tester1.c-pp.js 51d396bc0a4e6abc700def5529ce290ea84ba2018741fc7e701c5162b0f1e5fb F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70 F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 @@ -2067,8 +2067,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d106edb956bbe22bddc2c6e5bcdf4fb8f797794c725c2e359e3fa4b31d881843 -R 9cc98a74b7c97dbae209498a8d29cfcb +P 21331bdd36a91b07a687ffadce392dcf2ccd0fd824b35d9dd027d4289a40fc96 +R f99279163c9ea24b92a1c120dee81c3c U stephan -Z 5e0b6a6419517a5a90c958328ab9c938 +Z 5af57eae4e4ffe17648ac57b69cb7a17 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 7afb1aff37..9e31dbe0cc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -21331bdd36a91b07a687ffadce392dcf2ccd0fd824b35d9dd027d4289a40fc96 \ No newline at end of file +c3ebdccf94d5e63c229bf91056c08052d78732e663334070ef3b0ef6fb4bfb8f \ No newline at end of file From 75435f8b2ddff951d48cbe5271f3549b0b9f3b5a Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 6 Dec 2022 08:46:39 +0000 Subject: [PATCH 15/22] Rename wasm.cstringToJs() to wasm.cstrToJs() for consistency with other wasm.cstr... APIs. FossilOrigin-Name: cbf483ea0ba3e6dc08ad7ed654380f818544b4c3cedfdb8aa848a83298268ceb --- ext/wasm/api/sqlite3-api-glue.js | 14 +++++++------- ext/wasm/api/sqlite3-api-oo1.js | 6 +++--- ext/wasm/api/sqlite3-api-prologue.js | 6 +++--- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 8 ++++---- ext/wasm/common/whwasmutil.js | 14 +++++++------- ext/wasm/tester1.c-pp.js | 6 +++--- manifest | 22 +++++++++++----------- manifest.uuid | 2 +- 8 files changed, 39 insertions(+), 39 deletions(-) diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js index 89c8044be1..14c0d58a42 100644 --- a/ext/wasm/api/sqlite3-api-glue.js +++ b/ext/wasm/api/sqlite3-api-glue.js @@ -193,8 +193,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ try { let aVals = [], aNames = [], i = 0, offset = 0; for( ; i < nCols; offset += (wasm.ptrSizeof * ++i) ){ - aVals.push( wasm.cstringToJs(wasm.getPtrValue(pColVals + offset)) ); - aNames.push( wasm.cstringToJs(wasm.getPtrValue(pColNames + offset)) ); + aVals.push( wasm.cstrToJs(wasm.getPtrValue(pColVals + offset)) ); + aNames.push( wasm.cstrToJs(wasm.getPtrValue(pColNames + offset)) ); } rc = callback(pVoid, nCols, aVals, aNames) | 0; /* The first 2 args of the callback are useless for JS but @@ -610,7 +610,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ toss("Maintenance required: increase sqlite3_wasm_enum_json()'s", "static buffer size!"); } - wasm.ctype = JSON.parse(wasm.cstringToJs(cJson)); + wasm.ctype = JSON.parse(wasm.cstrToJs(cJson)); //console.debug('wasm.ctype length =',wasm.cstrlen(cJson)); const defineGroups = ['access', 'authorizer', 'blobFinalizers', 'dataTypes', @@ -702,7 +702,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ try { const zXKey = kvvfsMakeKey(zClass,zKey); if(!zXKey) return -3/*OOM*/; - const jKey = wasm.cstringToJs(zXKey); + const jKey = wasm.cstrToJs(zXKey); const jV = kvvfsStorage(zClass).getItem(jKey); if(!jV) return -1; const nV = jV.length /* Note that we are relying 100% on v being @@ -731,8 +731,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ try { const zXKey = kvvfsMakeKey(zClass,zKey); if(!zXKey) return 1/*OOM*/; - const jKey = wasm.cstringToJs(zXKey); - kvvfsStorage(zClass).setItem(jKey, wasm.cstringToJs(zData)); + const jKey = wasm.cstrToJs(zXKey); + kvvfsStorage(zClass).setItem(jKey, wasm.cstrToJs(zData)); return 0; }catch(e){ console.error("kvstorageWrite()",e); @@ -746,7 +746,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ try { const zXKey = kvvfsMakeKey(zClass,zKey); if(!zXKey) return 1/*OOM*/; - kvvfsStorage(zClass).removeItem(wasm.cstringToJs(zXKey)); + kvvfsStorage(zClass).removeItem(wasm.cstrToJs(zXKey)); return 0; }catch(e){ console.error("kvstorageDelete()",e); diff --git a/ext/wasm/api/sqlite3-api-oo1.js b/ext/wasm/api/sqlite3-api-oo1.js index 6253c659fc..4ec61af07c 100644 --- a/ext/wasm/api/sqlite3-api-oo1.js +++ b/ext/wasm/api/sqlite3-api-oo1.js @@ -73,7 +73,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ if(capi.SQLITE_TRACE_STMT===t){ // x == SQL, p == sqlite3_stmt* console.log("SQL TRACE #"+(++this.counter), - wasm.cstringToJs(x)); + wasm.cstrToJs(x)); } }.bind({counter: 0})); @@ -139,7 +139,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ console.error("Invalid DB ctor args",opt,arguments); toss3("Invalid arguments for DB constructor."); } - let fnJs = ('number'===typeof fn) ? wasm.cstringToJs(fn) : fn; + let fnJs = ('number'===typeof fn) ? wasm.cstrToJs(fn) : fn; const vfsCheck = ctor._name2vfs[fnJs]; if(vfsCheck){ vfsName = vfsCheck.vfs; @@ -600,7 +600,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ ); if(pVfs){ const v = new capi.sqlite3_vfs(pVfs); - try{ rc = wasm.cstringToJs(v.$zName) } + try{ rc = wasm.cstrToJs(v.$zName) } finally { v.dispose() } } return rc; diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index 558fcda1e0..bccae8b199 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -348,13 +348,13 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( /** If v is-a Array, its join("") result is returned. If isSQLableTypedArray(v) is true then typedArrayToString(v) is - returned. If it looks like a WASM pointer, wasm.cstringToJs(v) is + returned. If it looks like a WASM pointer, wasm.cstrToJs(v) is returned. Else v is returned as-is. */ const flexibleString = function(v){ if(isSQLableTypedArray(v)) return typedArrayToString(v); else if(Array.isArray(v)) return v.join(""); - else if(wasm.isPtr(v)) v = wasm.cstringToJs(v); + else if(wasm.isPtr(v)) v = wasm.cstrToJs(v); return v; }; @@ -1339,7 +1339,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( let pVfs = capi.sqlite3_vfs_find(0); while(pVfs){ const oVfs = new capi.sqlite3_vfs(pVfs); - rc.push(wasm.cstringToJs(oVfs.$zName)); + rc.push(wasm.cstrToJs(oVfs.$zName)); pVfs = oVfs.$pNext; oVfs.dispose(); } diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index f5a1eb6cc2..99d79641f4 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -803,7 +803,7 @@ const installOpfsVfs = function callee(options){ const vfsSyncWrappers = { xAccess: function(pVfs,zName,flags,pOut){ mTimeStart('xAccess'); - const rc = opRun('xAccess', wasm.cstringToJs(zName)); + const rc = opRun('xAccess', wasm.cstrToJs(zName)); wasm.setMemValue( pOut, (rc ? 0 : 1), 'i32' ); mTimeEnd(); return 0; @@ -823,7 +823,7 @@ const installOpfsVfs = function callee(options){ }, xDelete: function(pVfs, zName, doSyncDir){ mTimeStart('xDelete'); - opRun('xDelete', wasm.cstringToJs(zName), doSyncDir, false); + opRun('xDelete', wasm.cstrToJs(zName), doSyncDir, false); /* We're ignoring errors because we cannot yet differentiate between harmless and non-harmless failures. */ mTimeEnd(); @@ -855,7 +855,7 @@ const installOpfsVfs = function callee(options){ C-string here. */ opfsFlags |= state.opfsFlags.OPFS_UNLOCK_ASAP; } - zName = wasm.cstringToJs(zName); + zName = wasm.cstrToJs(zName); } const fh = Object.create(null); fh.fid = pFile; @@ -1231,7 +1231,7 @@ const installOpfsVfs = function callee(options){ const readBuf = wasm.scopedAlloc(16); rc = ioSyncWrappers.xRead(sq3File.pointer, readBuf, 6, 2); wasm.setMemValue(readBuf+6,0); - let jRead = wasm.cstringToJs(readBuf); + let jRead = wasm.cstrToJs(readBuf); log("xRead() got:",jRead); if("sanity"!==jRead) toss("Unexpected xRead() value."); if(vfsSyncWrappers.xSleep){ diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js index 571486912f..0da1841b6e 100644 --- a/ext/wasm/common/whwasmutil.js +++ b/ext/wasm/common/whwasmutil.js @@ -756,7 +756,7 @@ self.WhWasmUtilInstaller = function(target){ JS-format string representing its contents. As a special case, if ptr is falsy or not a pointer, `null` is returned. */ - target.cstringToJs = function(ptr){ + target.cstrToJs = function(ptr){ const n = target.cstrlen(ptr); return n ? __utf8Decode(heapWrappers().HEAP8U, ptr, ptr+n) : (null===n ? n : ""); }; @@ -1147,7 +1147,7 @@ self.WhWasmUtilInstaller = function(target){ const list = []; for(let i = 0; i < argc; ++i){ const arg = target.getPtrValue(pArgv + (target.ptrSizeof * i)); - list.push( arg ? target.cstringToJs(arg) : null ); + list.push( arg ? target.cstrToJs(arg) : null ); } return list; }; @@ -1315,14 +1315,14 @@ self.WhWasmUtilInstaller = function(target){ if('string'===typeof v) return target.scopedAllocCString(v); return v ? xcv.arg[ptrIR](v) : null; }; - xcv.result.string = xcv.result.utf8 = (i)=>target.cstringToJs(i); + xcv.result.string = xcv.result.utf8 = (i)=>target.cstrToJs(i); xcv.result['string:dealloc'] = xcv.result['utf8:dealloc'] = (i)=>{ - try { return i ? target.cstringToJs(i) : null } + try { return i ? target.cstrToJs(i) : null } finally{ target.dealloc(i) } }; - xcv.result.json = (i)=>JSON.parse(target.cstringToJs(i)); + xcv.result.json = (i)=>JSON.parse(target.cstrToJs(i)); xcv.result['json:dealloc'] = (i)=>{ - try{ return i ? JSON.parse(target.cstringToJs(i)) : null } + try{ return i ? JSON.parse(target.cstrToJs(i)) : null } finally{ target.dealloc(i) } } xcv.result['void'] = (v)=>undefined; @@ -1460,7 +1460,7 @@ self.WhWasmUtilInstaller = function(target){ ```js target.xWrap.resultAdapter('string:my_free',(i)=>{ - try { return i ? target.cstringToJs(i) : null } + try { return i ? target.cstrToJs(i) : null } finally{ target.exports.my_free(i) } }; ``` diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index 8ba88db18f..c32c4e5e84 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -547,13 +547,13 @@ self.sqlite3InitModule = sqlite3InitModule; let cpy = w.scopedAlloc(n+10); let rc = w.cstrncpy(cpy, cStr, n+10); T.assert(n+1 === rc). - assert("hello" === w.cstringToJs(cpy)). + assert("hello" === w.cstrToJs(cpy)). assert(chr('o') === w.getMemValue(cpy+n-1)). assert(0 === w.getMemValue(cpy+n)); let cStr2 = w.scopedAllocCString("HI!!!"); rc = w.cstrncpy(cpy, cStr2, 3); T.assert(3===rc). - assert("HI!lo" === w.cstringToJs(cpy)). + assert("HI!lo" === w.cstrToJs(cpy)). assert(chr('!') === w.getMemValue(cpy+2)). assert(chr('l') === w.getMemValue(cpy+3)); }finally{ @@ -675,7 +675,7 @@ self.sqlite3InitModule = sqlite3InitModule; // 'string:flexible' argAdapter() sanity checks... w.scopedAllocCall(()=>{ const argAd = w.xWrap.argAdapter('string:flexible'); - const cj = (v)=>w.cstringToJs(argAd(v)); + const cj = (v)=>w.cstrToJs(argAd(v)); T.assert('Hi' === cj('Hi')) .assert('hi' === cj(['h','i'])) .assert('HI' === cj(new Uint8Array([72, 73]))); diff --git a/manifest b/manifest index d416956d91..cd9692c393 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\swasm.cArgvToJs()\sto\ssupport\ssqlite3_module::xConnect(). -D 2022-12-06T08:39:17.647 +C Rename\swasm.cstringToJs()\sto\swasm.cstrToJs()\sfor\sconsistency\swith\sother\swasm.cstr...\sAPIs. +D 2022-12-06T08:46:39.353 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -503,14 +503,14 @@ F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08 F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62 F ext/wasm/api/pre-js.c-pp.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f9e91c1d5f F ext/wasm/api/sqlite3-api-cleanup.js 680d5ccfff54459db136a49b2199d9f879c8405d9c99af1dda0cc5e7c29056f4 -F ext/wasm/api/sqlite3-api-glue.js 057c9ed555ee68ee795dc61e8d923862a0ddeb3d4cbad89866515cf5a1b77343 -F ext/wasm/api/sqlite3-api-oo1.js b970787aaf0bdd3a3df59cf66aeb84d0decaaa0529aed7eaf45121087181245f -F ext/wasm/api/sqlite3-api-prologue.js 31cffd8ce212fad8d316a08decd864b0f614c5fce3686153707dffe40f8279e8 +F ext/wasm/api/sqlite3-api-glue.js 8fa55af37c9880f94a803f32591dc0304750cc2f750048daf41fe942757bee64 +F ext/wasm/api/sqlite3-api-oo1.js 416e6398721a4cbb80ddfa3d7b303216790f1d344efdbbc36239d39abc66aa27 +F ext/wasm/api/sqlite3-api-prologue.js a7596c30392d9ca8f5b7c14feb4e6788107d1159fd5f90eb26708d653d36c9bc F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 F ext/wasm/api/sqlite3-opfs-async-proxy.js f79dd8d98ef3e0b55c10bb2bee7a3840fa967318e1f577c156aafc34664271d1 F ext/wasm/api/sqlite3-v-helper.js 4451763a0cd85734f0afe18b48918cb3c88ca99cef399b7c5f12119281e7b6a8 -F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 29d6487a26b2fb6a471cde52c37ffee7c27ed6a91914b308c247e0706f454ffb +F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js e9656232ae4f5ef2d2fdd1711e89d40ba81c8f0faed0aadb22004341da5c8184 F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasm.c 723522a6c2a2463884a83fa1cc7ae5770deaaf0856a1058cc1023b2bfa1c898b F ext/wasm/api/sqlite3-worker1-promiser.js 0c7a9826dbf82a5ed4e4f7bf7816e825a52aff253afbf3350431f5773faf0e4b @@ -521,7 +521,7 @@ F ext/wasm/c-pp.c 92285f7bce67ed7b7020b40fde8ed0982c442b63dc33df9dfd4b658d4a6c07 F ext/wasm/common/SqliteTestUtil.js d8bf97ecb0705a2299765c8fc9e11b1a5ac7f10988bbf375a6558b7ca287067b F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15 F ext/wasm/common/testing.css 0ff15602a3ab2bad8aef2c3bd120c7ee3fd1c2054ad2ace7e214187ae68d926f -F ext/wasm/common/whwasmutil.js 8be1a3a3ebca51ab5d02fc89f6d45f974b99f0d99262227094e8af4b7ade3234 +F ext/wasm/common/whwasmutil.js f0a742270b490748b9fdb0974287429b036698609b40eee81f13fe13e64358a7 F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508 F ext/wasm/demo-123.js ebae30756585bca655b4ab2553ec9236a87c23ad24fc8652115dcedb06d28df6 @@ -555,7 +555,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9 F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406 -F ext/wasm/tester1.c-pp.js 51d396bc0a4e6abc700def5529ce290ea84ba2018741fc7e701c5162b0f1e5fb +F ext/wasm/tester1.c-pp.js 81c40395be4a7e97a3ca0ff62a4e02204239b1db6f24fe15b3c96a17fb41f29b F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70 F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 @@ -2067,8 +2067,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 21331bdd36a91b07a687ffadce392dcf2ccd0fd824b35d9dd027d4289a40fc96 -R f99279163c9ea24b92a1c120dee81c3c +P c3ebdccf94d5e63c229bf91056c08052d78732e663334070ef3b0ef6fb4bfb8f +R 89bdf08b4a75fdd12936e8e156f340f6 U stephan -Z 5af57eae4e4ffe17648ac57b69cb7a17 +Z 095ae4e504a3bccb462600500450b6bf # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 9e31dbe0cc..143d7cba7b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c3ebdccf94d5e63c229bf91056c08052d78732e663334070ef3b0ef6fb4bfb8f \ No newline at end of file +cbf483ea0ba3e6dc08ad7ed654380f818544b4c3cedfdb8aa848a83298268ceb \ No newline at end of file From d254db53e57cbe18858f38f64b74c9c054f2aa5c Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 6 Dec 2022 09:49:04 +0000 Subject: [PATCH 16/22] Remove deprecated symbol sqlite3.opfs.OpfsDb, which was renamed to sqlite3.oo1.OpfsDb on 2022-11-29. FossilOrigin-Name: 0ce51bed65d5e430364f74bf959fb76c42ac5eec0769490231d8c8110a1f388c --- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js | 7 ++----- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js index 99d79641f4..49ebfbd80b 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -1156,11 +1156,8 @@ const installOpfsVfs = function callee(options){ opt.vfs = opfsVfs.$zName; sqlite3.oo1.DB.dbCtorHelper.call(this, opt); }; - sqlite3.oo1.OpfsDb = - opfsUtil.OpfsDb /* sqlite3.opfs.OpfsDb => deprecated name - - will be phased out Real Soon */ = - OpfsDb; OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype); + sqlite3.oo1.OpfsDb = OpfsDb; sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenSql( opfsVfs.pointer, function(oo1Db, sqlite3){ @@ -1185,7 +1182,7 @@ const installOpfsVfs = function callee(options){ ], 0, 0, 0); } ); - } + }/*extend sqlite3.oo1*/ const sanityCheck = function(){ const scope = wasm.scopedAllocPush(); diff --git a/manifest b/manifest index cd9692c393..7c57dc1324 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Rename\swasm.cstringToJs()\sto\swasm.cstrToJs()\sfor\sconsistency\swith\sother\swasm.cstr...\sAPIs. -D 2022-12-06T08:46:39.353 +C Remove\sdeprecated\ssymbol\ssqlite3.opfs.OpfsDb,\swhich\swas\srenamed\sto\ssqlite3.oo1.OpfsDb\son\s2022-11-29. +D 2022-12-06T09:49:04.292 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -510,7 +510,7 @@ F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1 F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 F ext/wasm/api/sqlite3-opfs-async-proxy.js f79dd8d98ef3e0b55c10bb2bee7a3840fa967318e1f577c156aafc34664271d1 F ext/wasm/api/sqlite3-v-helper.js 4451763a0cd85734f0afe18b48918cb3c88ca99cef399b7c5f12119281e7b6a8 -F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js e9656232ae4f5ef2d2fdd1711e89d40ba81c8f0faed0aadb22004341da5c8184 +F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 8ec510fee735c646fb18a3b99f0ca5ca461f9e066c43cdc404d7144f12ae6ed6 F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasm.c 723522a6c2a2463884a83fa1cc7ae5770deaaf0856a1058cc1023b2bfa1c898b F ext/wasm/api/sqlite3-worker1-promiser.js 0c7a9826dbf82a5ed4e4f7bf7816e825a52aff253afbf3350431f5773faf0e4b @@ -2067,8 +2067,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c3ebdccf94d5e63c229bf91056c08052d78732e663334070ef3b0ef6fb4bfb8f -R 89bdf08b4a75fdd12936e8e156f340f6 +P cbf483ea0ba3e6dc08ad7ed654380f818544b4c3cedfdb8aa848a83298268ceb +R 16a04cd1971a4487c1631d3a37d3ce6e U stephan -Z 095ae4e504a3bccb462600500450b6bf +Z 455bc03c9fd6d42a81f698c07992ea6a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 143d7cba7b..2a7e690681 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cbf483ea0ba3e6dc08ad7ed654380f818544b4c3cedfdb8aa848a83298268ceb \ No newline at end of file +0ce51bed65d5e430364f74bf959fb76c42ac5eec0769490231d8c8110a1f388c \ No newline at end of file From 241cde98b89255f41ec13b35a33b3dfdaa9cf580 Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 6 Dec 2022 11:21:46 +0000 Subject: [PATCH 17/22] JS vtables: add infrastructure related to accessing and modifying sqlite3_index_info. FossilOrigin-Name: 0d77c348039926c24e0fb50a7dc7e4b62895cd201c021f8e29832917e4b8b09f --- ext/wasm/api/sqlite3-v-helper.js | 72 ++++++++++++++++++++++++++------ ext/wasm/tester1.c-pp.js | 67 ++++++++++++++++++++++------- manifest | 14 +++---- manifest.uuid | 2 +- 4 files changed, 121 insertions(+), 34 deletions(-) diff --git a/ext/wasm/api/sqlite3-v-helper.js b/ext/wasm/api/sqlite3-v-helper.js index 84272266e8..a23070b24c 100644 --- a/ext/wasm/api/sqlite3-v-helper.js +++ b/ext/wasm/api/sqlite3-v-helper.js @@ -22,6 +22,53 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ sqlite3.VfsHelper = vh; sqlite3.VtabHelper = vt; + const sii = capi.sqlite3_index_info; + /** + If n is >=0 and less than this.$nConstraint, this function + returns either a WASM pointer to the 0-based nth entry of + this.$aConstraint (if passed a truthy 2nd argument) or an + sqlite3_index_info.sqlite3_index_constraint object wrapping that + address (if passed a falsy value or no 2nd argument). Returns a + falsy value if n is out of range. + */ + sii.prototype.nthConstraint = function(n, asPtr=false){ + if(n<0 || n>=this.$nConstraint) return false; + const ptr = this.$aConstraint + ( + sii.sqlite3_index_constraint.structInfo.sizeof * n + ); + return asPtr ? ptr : new sii.sqlite3_index_constraint(ptr); + }; + + /** + Works identically to nthConstraint() but returns state from + this.$aConstraintUsage, so returns an + sqlite3_index_info.sqlite3_index_constraint_usage instance + if passed no 2nd argument or a falsy 2nd argument. + */ + sii.prototype.nthConstraintUsage = function(n, asPtr=false){ + if(n<0 || n>=this.$nConstraint) return false; + const ptr = this.$aConstraintUsage + ( + sii.sqlite3_index_constraint_usage.structInfo.sizeof * n + ); + return asPtr ? ptr : new sii.sqlite3_index_constraint_usage(ptr); + }; + + /** + If n is >=0 and less than this.$nOrderBy, this function + returns either a WASM pointer to the 0-based nth entry of + this.$aOrderBy (if passed a truthy 2nd argument) or an + sqlite3_index_info.sqlite3_index_orderby object wrapping that + address (if passed a falsy value or no 2nd argument). Returns a + falsy value if n is out of range. + */ + sii.prototype.nthOrderBy = function(n, asPtr=false){ + if(n<0 || n>=this.$nOrderBy) return false; + const ptr = this.$aOrderBy + ( + sii.sqlite3_index_orderby.structInfo.sizeof * n + ); + return asPtr ? ptr : new sii.sqlite3_index_orderby(ptr); + }; + /** Installs a StructBinder-bound function pointer member of the given name and function in the given StructType target object. @@ -109,6 +156,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true)); tgt[memKey] = pFunc; if(!tgt.ondispose) tgt.ondispose = []; + else if(!Array.isArray(tgt.ondispose)) tgt.ondispose = [tgt.ondispose]; if(!tgt.ondispose.__removeFuncList){ tgt.ondispose.push('ondispose.__removeFuncList handler', callee.removeFuncList); @@ -244,9 +292,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ vt.sqlite3ValuesToJs = capi.sqlite3_create_function_v2.udfConvertArgs; /** - Factory function for xyz2js() impls. + Factory function for wrapXyz() impls. */ - const __v2jsFactory = function(structType){ + const __xWrapFactory = function(structType){ return function(ptr,remove=false){ if(0===arguments.length) ptr = new structType; if(ptr instanceof structType){ @@ -254,7 +302,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ this.set(ptr.pointer, ptr); return ptr; }else if(!wasm.isPtr(ptr)){ - sqlite3.SQLite3Error.toss("Invalid argument to v2jsFactory"); + sqlite3.SQLite3Error.toss("Invalid argument to xWrapFactory"); } let rc = this.get(ptr); if(remove) this.delete(ptr); @@ -270,45 +318,45 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ Has 3 distinct uses: - - vtab2js() instantiates a new capi.sqlite3_vtab instance, maps + - wrapVtab() instantiates a new capi.sqlite3_vtab instance, maps its pointer for later by-pointer lookup, and returns that object. This is intended to be called from sqlite3_module::xConnect() or xCreate() implementations. - - vtab2js(pVtab) accepts a WASM pointer to a C-level + - wrapVtab(pVtab) accepts a WASM pointer to a C-level (sqlite3_vtab*) instance and returns the capi.sqlite3_vtab object created by the first form of this function, or undefined if that form has not been used. This is intended to be called from sqlite3_module methods which take a (sqlite3_vtab*) pointer _except_ for xDisconnect(), in which case use... - - vtab2js(pVtab,true) as for the previous form, but removes the + - wrapVtab(pVtab,true) as for the previous form, but removes the pointer-to-object mapping before returning. The caller must call dispose() on the returned object. This is intended to be called from sqlite3_module::xDisconnect() implementations or in error handling of a failed xCreate() or xConnect(). */ - vt.vtab2js = __v2jsFactory(capi.sqlite3_vtab); + vt.xWrapVtab = __xWrapFactory(capi.sqlite3_vtab); /** EXPERIMENTAL. DO NOT USE IN CLIENT CODE. - Works identically to vtab2js() except that it deals with + Works identically to wrapVtab() except that it deals with sqlite3_cursor objects and pointers instead of sqlite3_vtab. - - vcur2js() is intended to be called from sqlite3_module::xOpen() + - wrapCursor() is intended to be called from sqlite3_module::xOpen() - - vcur2js(pCursor) is intended to be called from all sqlite3_module + - wrapCursor(pCursor) is intended to be called from all sqlite3_module methods which take a (sqlite3_vtab_cursor*) _except_ for xClose(), in which case use... - - vcur2js(pCursor, true) will remove the m apping of pCursor to a + - wrapCursor(pCursor, true) will remove the m apping of pCursor to a capi.sqlite3_vtab_cursor object and return that object. The caller must call dispose() on the returned object. This is intended to be called form xClose() or in error handling of a failed xOpen(). */ - vt.vcur2js = __v2jsFactory(capi.sqlite3_vtab_cursor); + vt.xWrapCursor = __xWrapFactory(capi.sqlite3_vtab_cursor); /** Given an error object, this function returns diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index c32c4e5e84..7013f3cea8 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -1553,9 +1553,9 @@ self.sqlite3InitModule = sqlite3InitModule; pDb, "CREATE TABLE ignored(a,b)" ); if(0===rc){ - const t = vth.vtab2js(); + const t = vth.xWrapVtab(); wasm.setPtrValue(ppVtab, t.pointer); - T.assert(t === vth.vtab2js(wasm.getPtrValue(ppVtab))); + T.assert(t === vth.xWrapVtab(wasm.getPtrValue(ppVtab))); } return rc; }catch(e){ @@ -1567,7 +1567,7 @@ self.sqlite3InitModule = sqlite3InitModule; }, xDisconnect: function(pVtab){ try { - const t = vth.vtab2js(pVtab, true); + const t = vth.xWrapVtab(pVtab, true); t.dispose(); return 0; }catch(e){ @@ -1576,7 +1576,7 @@ self.sqlite3InitModule = sqlite3InitModule; }, xOpen: function(pVtab, ppCursor){ try{ - const t = vth.vtab2js(pVtab), c = vth.vcur2js(); + const t = vth.xWrapVtab(pVtab), c = vth.xWrapCursor(); T.assert(t instanceof capi.sqlite3_vtab); T.assert(c instanceof capi.sqlite3_vtab_cursor); wasm.setPtrValue(ppCursor, c.pointer); @@ -1588,9 +1588,9 @@ self.sqlite3InitModule = sqlite3InitModule; }, xClose: function(pCursor){ try{ - const c = vth.vcur2js(pCursor,true); + const c = vth.xWrapCursor(pCursor,true); T.assert(c instanceof capi.sqlite3_vtab_cursor) - .assert(!vth.vcur2js(pCursor)); + .assert(!vth.xWrapCursor(pCursor)); c.dispose(); return 0; }catch(e){ @@ -1599,7 +1599,7 @@ self.sqlite3InitModule = sqlite3InitModule; }, xNext: function(pCursor){ try{ - const c = vth.vcur2js(pCursor); + const c = vth.xWrapCursor(pCursor); ++c._rowId; return 0; }catch(e){ @@ -1609,7 +1609,7 @@ self.sqlite3InitModule = sqlite3InitModule; }, xColumn: function(pCursor, pCtx, iCol){ try{ - const c = vth.vcur2js(pCursor); + const c = vth.xWrapCursor(pCursor); switch(iCol){ case tmplCols.A: capi.sqlite3_result_int(pCtx, 1000 + c._rowId); @@ -1626,7 +1626,7 @@ self.sqlite3InitModule = sqlite3InitModule; }, xRowid: function(pCursor, ppRowid64){ try{ - const c = vth.vcur2js(pCursor); + const c = vth.xWrapCursor(pCursor); vth.setRowId(ppRowid64, c._rowId); return 0; }catch(e){ @@ -1634,14 +1634,17 @@ self.sqlite3InitModule = sqlite3InitModule; } }, xEof: function(pCursor){ - const c = vth.vcur2js(pCursor); + const c = vth.xWrapCursor(pCursor); return c._rowId>=10; }, xFilter: function(pCursor, idxNum, idxCStr, argc, argv/* [sqlite3_value* ...] */){ try{ - const c = vth.vcur2js(pCursor); + const c = vth.xWrapCursor(pCursor); c._rowId = 0; + const list = vth.sqlite3ValuesToJs(argc, argv); + T.assert(argc === list.length); + //log(argc,"xFilter value(s):",list); return 0; }catch(e){ return vth.xMethodError('xFilter',e); @@ -1649,10 +1652,44 @@ self.sqlite3InitModule = sqlite3InitModule; }, xBestIndex: function(pVtab, pIdxInfo){ try{ - const t = vth.vtab2js(pVtab); - const pii = new capi.sqlite3_index_info(pIdxInfo); + //const t = vth.xWrapVtab(pVtab); + const sii = capi.sqlite3_index_info; + const pii = new sii(pIdxInfo); pii.$estimatedRows = 10; pii.$estimatedCost = 10.0; + //log("xBestIndex $nConstraint =",pii.$nConstraint); + if(pii.$nConstraint>0){ + // Validate nthConstraint() and nthConstraintUsage() + const max = pii.$nConstraint; + for(let i=0; i < max; ++i ){ + let v = pii.nthConstraint(i,true); + T.assert(wasm.isPtr(v)); + v = pii.nthConstraint(i); + T.assert(v instanceof sii.sqlite3_index_constraint) + .assert(v.pointer >= pii.$aConstraint); + v.dispose(); + v = pii.nthConstraintUsage(i,true); + T.assert(wasm.isPtr(v)); + v = pii.nthConstraintUsage(i); + T.assert(v instanceof sii.sqlite3_index_constraint_usage) + .assert(v.pointer >= pii.$aConstraintUsage); + v.$argvIndex = i;//just to get some values into xFilter + v.dispose(); + } + } + //log("xBestIndex $nOrderBy =",pii.$nOrderBy); + if(pii.$nOrderBy>0){ + // Validate nthOrderBy() + const max = pii.$nOrderBy; + for(let i=0; i < max; ++i ){ + let v = pii.nthOrderBy(i,true); + T.assert(wasm.isPtr(v)); + v = pii.nthOrderBy(i); + T.assert(v instanceof sii.sqlite3_index_orderby) + .assert(v.pointer >= pii.$aOrderBy); + v.dispose(); + } + } pii.dispose(); return 0; }catch(e){ @@ -1692,7 +1729,9 @@ self.sqlite3InitModule = sqlite3InitModule; this.db.checkRc(rc); const list = this.db.selectArrays( - "SELECT a,b FROM testvtab order by a" + "SELECT a,b FROM testvtab where a<9999 and b>1 order by a, b" + /* Query is shaped so that it will ensure that some constraints + end up in xBestIndex(). */ ); T.assert(10===list.length) .assert(1000===list[0][0]) diff --git a/manifest b/manifest index 7c57dc1324..3bfa27aa70 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sdeprecated\ssymbol\ssqlite3.opfs.OpfsDb,\swhich\swas\srenamed\sto\ssqlite3.oo1.OpfsDb\son\s2022-11-29. -D 2022-12-06T09:49:04.292 +C JS\svtables:\sadd\sinfrastructure\srelated\sto\saccessing\sand\smodifying\ssqlite3_index_info. +D 2022-12-06T11:21:46.303 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -509,7 +509,7 @@ F ext/wasm/api/sqlite3-api-prologue.js a7596c30392d9ca8f5b7c14feb4e6788107d1159f F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 F ext/wasm/api/sqlite3-opfs-async-proxy.js f79dd8d98ef3e0b55c10bb2bee7a3840fa967318e1f577c156aafc34664271d1 -F ext/wasm/api/sqlite3-v-helper.js 4451763a0cd85734f0afe18b48918cb3c88ca99cef399b7c5f12119281e7b6a8 +F ext/wasm/api/sqlite3-v-helper.js 6b408ee4e926cb0f7fe41a63a1205049283af301fe3f5de3c038845ccf9106df F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 8ec510fee735c646fb18a3b99f0ca5ca461f9e066c43cdc404d7144f12ae6ed6 F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasm.c 723522a6c2a2463884a83fa1cc7ae5770deaaf0856a1058cc1023b2bfa1c898b @@ -555,7 +555,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9 F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406 -F ext/wasm/tester1.c-pp.js 81c40395be4a7e97a3ca0ff62a4e02204239b1db6f24fe15b3c96a17fb41f29b +F ext/wasm/tester1.c-pp.js c5679da7895377df03e6075fc0e9dff8b5f570bd4edb63f714154d3030279fce F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70 F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 @@ -2067,8 +2067,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P cbf483ea0ba3e6dc08ad7ed654380f818544b4c3cedfdb8aa848a83298268ceb -R 16a04cd1971a4487c1631d3a37d3ce6e +P 0ce51bed65d5e430364f74bf959fb76c42ac5eec0769490231d8c8110a1f388c +R a1b37a98bcb406acaf386e5a65bbf6e3 U stephan -Z 455bc03c9fd6d42a81f698c07992ea6a +Z 3e0a3245949f854c4eed760afd40e3ce # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 2a7e690681..a5ae05d6f7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0ce51bed65d5e430364f74bf959fb76c42ac5eec0769490231d8c8110a1f388c \ No newline at end of file +0d77c348039926c24e0fb50a7dc7e4b62895cd201c021f8e29832917e4b8b09f \ No newline at end of file From 30da58c5d66c386129a872ccd3a13b452c67717a Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 7 Dec 2022 03:42:39 +0000 Subject: [PATCH 18/22] Add addOnDispose() method to Jaccwabyt and code-adjacent minor internal cleanups. FossilOrigin-Name: 6a2723fe3f28dd94328d901e64e1e9ee9a1b2e9eeaed6c54038a5b83c914db78 --- ext/wasm/api/sqlite3-v-helper.js | 4 +-- ext/wasm/jaccwabyt/jaccwabyt.js | 47 ++++++++++++++++++++------------ ext/wasm/jaccwabyt/jaccwabyt.md | 33 ++++++++++++++++++++-- ext/wasm/tester1.c-pp.js | 19 +++++++++++-- manifest | 18 ++++++------ manifest.uuid | 2 +- 6 files changed, 88 insertions(+), 35 deletions(-) diff --git a/ext/wasm/api/sqlite3-v-helper.js b/ext/wasm/api/sqlite3-v-helper.js index a23070b24c..1f2950f749 100644 --- a/ext/wasm/api/sqlite3-v-helper.js +++ b/ext/wasm/api/sqlite3-v-helper.js @@ -350,10 +350,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ methods which take a (sqlite3_vtab_cursor*) _except_ for xClose(), in which case use... - - wrapCursor(pCursor, true) will remove the m apping of pCursor to a + - wrapCursor(pCursor, true) will remove the mapping of pCursor to a capi.sqlite3_vtab_cursor object and return that object. The caller must call dispose() on the returned object. This is - intended to be called form xClose() or in error handling of a + intended to be called from xClose() or in error handling of a failed xOpen(). */ vt.xWrapCursor = __xWrapFactory(capi.sqlite3_vtab_cursor); diff --git a/ext/wasm/jaccwabyt/jaccwabyt.js b/ext/wasm/jaccwabyt/jaccwabyt.js index d5225f6e4d..f02c8bbdef 100644 --- a/ext/wasm/jaccwabyt/jaccwabyt.js +++ b/ext/wasm/jaccwabyt/jaccwabyt.js @@ -10,9 +10,12 @@ *********************************************************************** - The Jaccwabyt API is documented in detail in an external file. + The Jaccwabyt API is documented in detail in an external file, + _possibly_ called jaccwabyt.md in the same directory as this file. - Project home: https://fossil.wanderinghorse.net/r/jaccwabyt + Project homes: + - https://fossil.wanderinghorse.net/r/jaccwabyt + - https://sqlite.org/src/dir/ext/wasm/jaccwabyt */ 'use strict'; @@ -219,15 +222,9 @@ self.Jaccwabyt = function StructBinderFactory(config){ const __freeStruct = function(ctor, obj, m){ if(!m) m = __instancePointerMap.get(obj); if(m) { - if(obj.ondispose instanceof Function){ - try{obj.ondispose()} - catch(e){ - /*do not rethrow: destructors must not throw*/ - console.warn("ondispose() for",ctor.structName,'@', - m,'threw. NOT propagating it.',e); - } - }else if(Array.isArray(obj.ondispose)){ - obj.ondispose.forEach(function(x){ + if(Array.isArray(obj.ondispose)){ + let x; + while((x = obj.ondispose.shift())){ try{ if(x instanceof Function) x.call(obj); else if(x instanceof StructType) x.dispose(); @@ -238,7 +235,14 @@ self.Jaccwabyt = function StructBinderFactory(config){ console.warn("ondispose() for",ctor.structName,'@', m,'threw. NOT propagating it.',e); } - }); + } + }else if(obj.ondispose instanceof Function){ + try{obj.ondispose()} + catch(e){ + /*do not rethrow: destructors must not throw*/ + console.warn("ondispose() for",ctor.structName,'@', + m,'threw. NOT propagating it.',e); + } } delete obj.ondispose; __instancePointerMap.delete(obj); @@ -333,7 +337,9 @@ self.Jaccwabyt = function StructBinderFactory(config){ /** Impl of X.memberKeys() for StructType and struct ctors. */ const __structMemberKeys = rop(function(){ const a = []; - Object.keys(this.structInfo.members).forEach((k)=>a.push(this.memberKey(k))); + for(const k of Object.keys(this.structInfo.members)){ + a.push(this.memberKey(k)); + } return a; }); @@ -399,15 +405,15 @@ self.Jaccwabyt = function StructBinderFactory(config){ Adds value v to obj.ondispose, creating ondispose, or converting it to an array, if needed. */ - const __addOnDispose = function(obj, v){ + const __addOnDispose = function(obj, ...v){ if(obj.ondispose){ - if(obj.ondispose instanceof Function){ + if(!Array.isArray(obj.ondispose)){ obj.ondispose = [obj.ondispose]; - }/*else assume it's an array*/ + } }else{ obj.ondispose = []; } - obj.ondispose.push(v); + obj.ondispose.push(...v); }; /** @@ -494,6 +500,13 @@ self.Jaccwabyt = function StructBinderFactory(config){ return __setMemberCString(this, memberName, str); }) }); + // Function-type non-Property inherited members + Object.assign(StructType.prototype,{ + addOnDispose: function(...v){ + __addOnDispose(this,...v); + return this; + } + }); /** "Static" properties for StructType. diff --git a/ext/wasm/jaccwabyt/jaccwabyt.md b/ext/wasm/jaccwabyt/jaccwabyt.md index 49e2d3b8ff..dd80ed1c68 100644 --- a/ext/wasm/jaccwabyt/jaccwabyt.md +++ b/ext/wasm/jaccwabyt/jaccwabyt.md @@ -4,7 +4,6 @@ Jaccwabyt 🐇 **Jaccwabyt**: _JavaScript ⇄ C Struct Communication via WASM Byte Arrays_ - Welcome to Jaccwabyt, a JavaScript API which creates bindings for WASM-compiled C structs, defining them in such a way that changes to their state in JS are visible in C/WASM, and vice versa, permitting @@ -27,8 +26,28 @@ are based solely on feature compatibility tables provided at **Formalities:** - Author: [Stephan Beal][sgb] -- License: Public Domain -- Project Home: +- Project Homes: + - \ + Is the primary home but... + - \ + ... most development happens here. + +The license for both this documentation and the software it documents +is the same as [sqlite3][], the project from which this spinoff +project was spawned: + +----- + +> 2022-06-30: +> +> The author disclaims copyright to this source code. In place of a +> legal notice, here is a blessing: +> +> May you do good and not evil. +> May you find forgiveness for yourself and forgive others. +> May you share freely, never taking more than you give. + +----- Table of Contents @@ -571,6 +590,14 @@ only called by the [StructBinder][]-generated has the following "static" properties (^Which are accessible from individual instances via `theInstance.constructor`.): +- `addOnDispose(...value)`\ + If this object has no `ondispose` property, this function creates it + as an array and pushes the given value(s) onto it. If the object has + a function-typed `ondispose` property, this call replaces it with an + array and moves that function into the array. In all other cases, + `ondispose` is assumed to be an array and the argument(s) is/are + appended to it. Returns `this`. + - `allocCString(str)` Identical to the [StructBinder][] method of the same name. diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index 7013f3cea8..910bbc94e6 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -710,7 +710,7 @@ self.sqlite3InitModule = sqlite3InitModule; }/*WhWasmUtil*/) //////////////////////////////////////////////////////////////////// - .t('sqlite3.StructBinder (jaccwabyt)', function(sqlite3){ + .t('sqlite3.StructBinder (jaccwabyt🐇)', function(sqlite3){ const S = sqlite3, W = S.wasm; const MyStructDef = { sizeof: 16, @@ -864,6 +864,18 @@ self.sqlite3InitModule = sqlite3InitModule; }finally{ wts.dispose(); } + + if(1){ // ondispose of other struct instances + const s1 = new WTStruct, s2 = new WTStruct, s3 = new WTStruct; + T.assert(s1.lookupMember instanceof Function) + .assert(s1.addOnDispose instanceof Function); + s1.addOnDispose(s2,"testing variadic args"); + T.assert(2===s1.ondispose.length); + s2.addOnDispose(s3); + s1.dispose(); + T.assert(!s2.pointer,"Expecting s2 to be ondispose'd by s1."); + T.assert(!s3.pointer,"Expecting s3 to be ondispose'd by s2."); + } }/*StructBinder*/) //////////////////////////////////////////////////////////////////// @@ -1549,6 +1561,7 @@ self.sqlite3InitModule = sqlite3InitModule; .assert(args[0] === 'testvtab') .assert(args[1] === 'main') .assert(args[2] === 'testvtab'); + console.debug("xConnect() args =",args); const rc = capi.sqlite3_declare_vtab( pDb, "CREATE TABLE ignored(a,b)" ); @@ -1577,8 +1590,8 @@ self.sqlite3InitModule = sqlite3InitModule; xOpen: function(pVtab, ppCursor){ try{ const t = vth.xWrapVtab(pVtab), c = vth.xWrapCursor(); - T.assert(t instanceof capi.sqlite3_vtab); - T.assert(c instanceof capi.sqlite3_vtab_cursor); + T.assert(t instanceof capi.sqlite3_vtab) + .assert(c instanceof capi.sqlite3_vtab_cursor); wasm.setPtrValue(ppCursor, c.pointer); c._rowId = 0; return 0; diff --git a/manifest b/manifest index 3bfa27aa70..e691430191 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C JS\svtables:\sadd\sinfrastructure\srelated\sto\saccessing\sand\smodifying\ssqlite3_index_info. -D 2022-12-06T11:21:46.303 +C Add\saddOnDispose()\smethod\sto\sJaccwabyt\sand\scode-adjacent\sminor\sinternal\scleanups. +D 2022-12-07T03:42:39.134 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -509,7 +509,7 @@ F ext/wasm/api/sqlite3-api-prologue.js a7596c30392d9ca8f5b7c14feb4e6788107d1159f F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 F ext/wasm/api/sqlite3-opfs-async-proxy.js f79dd8d98ef3e0b55c10bb2bee7a3840fa967318e1f577c156aafc34664271d1 -F ext/wasm/api/sqlite3-v-helper.js 6b408ee4e926cb0f7fe41a63a1205049283af301fe3f5de3c038845ccf9106df +F ext/wasm/api/sqlite3-v-helper.js 2125255f102ab07a2653d74d4931d716b0d27c5a89bebc188ad828de0dd1dcef F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 8ec510fee735c646fb18a3b99f0ca5ca461f9e066c43cdc404d7144f12ae6ed6 F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasm.c 723522a6c2a2463884a83fa1cc7ae5770deaaf0856a1058cc1023b2bfa1c898b @@ -539,8 +539,8 @@ F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5 F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2 F ext/wasm/index-dist.html c806b6005145b71d64240606e9c6e0bf56878ee8829c66fe7486cebf34b0e6b1 F ext/wasm/index.html f151b7c7b5cfdc066567d556acd168e769efd4e982286dc5f849a5ee69ecd0ff -F ext/wasm/jaccwabyt/jaccwabyt.js 35c7eaa61ba4b875cd49da5a06a35d9935fd19121de65dd5f467cbe376359782 -F ext/wasm/jaccwabyt/jaccwabyt.md 888aff20e486abb6c955d432f9a3af271e2cdd2cd99a92c6f87077116ca57091 +F ext/wasm/jaccwabyt/jaccwabyt.js b7efd07ea3927e9d0bc75b3819c6d40bdfb0a03cbc8d93331be16799f35261c3 +F ext/wasm/jaccwabyt/jaccwabyt.md 37911f00db12cbcca73aa1ed72594430365f30aafae2fa9c886961de74e5e0eb F ext/wasm/module-symbols.html 980680c8acfa3c8ae6a5aa223512d1b8e78040ced20f8ba2c382129bc73ec028 F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06 F ext/wasm/scratchpad-wasmfs-main.js 4c140457f4d6da9d646a49addd91edb6e9ad1643c6c48e3258b5bce24725dc18 @@ -555,7 +555,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9 F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406 -F ext/wasm/tester1.c-pp.js c5679da7895377df03e6075fc0e9dff8b5f570bd4edb63f714154d3030279fce +F ext/wasm/tester1.c-pp.js 8144e0e0f76b14fcd5223fad190bd94a50caf19b2419848b782448cda3ccbc78 F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70 F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 @@ -2067,8 +2067,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 0ce51bed65d5e430364f74bf959fb76c42ac5eec0769490231d8c8110a1f388c -R a1b37a98bcb406acaf386e5a65bbf6e3 +P 0d77c348039926c24e0fb50a7dc7e4b62895cd201c021f8e29832917e4b8b09f +R c60d510be7a6225cada64eb18dd4b778 U stephan -Z 3e0a3245949f854c4eed760afd40e3ce +Z 9a43ff51fca7fb341935fe3d300c9a6e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a5ae05d6f7..ae8e40499b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0d77c348039926c24e0fb50a7dc7e4b62895cd201c021f8e29832917e4b8b09f \ No newline at end of file +6a2723fe3f28dd94328d901e64e1e9ee9a1b2e9eeaed6c54038a5b83c914db78 \ No newline at end of file From 1eb1b59b893efb2fd4244d0116beb3c7db250d48 Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 7 Dec 2022 07:22:34 +0000 Subject: [PATCH 19/22] Work on an alternate (slightly simpler) approach to binding JS vtabs. Non-eponymous vtabs are not working, for reasons as yet unknown. FossilOrigin-Name: 6a0fefb93bcccd950df211cf5c2f49660c7b92115dd01b2b508a4ab9e3ab3d23 --- ext/wasm/api/sqlite3-api-prologue.js | 55 ++- ext/wasm/api/sqlite3-v-helper.js | 258 ++++++++--- ext/wasm/jaccwabyt/jaccwabyt.js | 2 +- ext/wasm/tester1.c-pp.js | 625 +++++++++++++++++---------- manifest | 18 +- manifest.uuid | 2 +- 6 files changed, 659 insertions(+), 301 deletions(-) diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index bccae8b199..e6a8c0fc3c 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -185,28 +185,49 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( /** Constructs this object with a message depending on its arguments: - - If it's passed only a single integer argument, it is assumed - to be an sqlite3 C API result code. The message becomes the - result of sqlite3.capi.sqlite3_js_rc_str() or (if that returns - falsy) a synthesized string which contains that integer. + If its first argument is an integer, it is assumed to be + an SQLITE_... result code and it is passed to + sqlite3.capi.sqlite3_js_rc_str() to stringify it. - - If passed 2 arguments and the 2nd is a object, it behaves - like the Error(string,object) constructor except that the first - argument is subject to the is-integer semantics from the - previous point. + If called with exactly 2 arguments and the 2nd is an object, + that object is treated as the 2nd argument to the parent + constructor. - - Else all arguments are concatenated with a space between each - one, using args.join(' '), to create the error message. + The exception's message is created by concatenating its + arguments with a space between each, except for the + two-args-with-an-objec form and that the first argument will + get coerced to a string, as described above, if it's an + integer. + + If passed an integer first argument, the error object's + `resultCode` member will be set to the given integer value, + else it will be set to capi.SQLITE_ERROR. */ constructor(...args){ - if(1===args.length && __isInt(args[0])){ - super(__rcStr(args[0])); - }else if(2===args.length && 'object'===typeof args[1]){ - if(__isInt(args[0])) super(__rcStr(args[0]), args[1]); - else super(...args); - }else{ - super(args.join(' ')); + let rc; + if(args.length){ + if(__isInt(args[0])){ + rc = args[0]; + if(1===args.length){ + super(__rcStr(args[0])); + }else{ + const rcStr = __rcStr(rc); + if('object'===typeof args[1]){ + super(rcStr,args[1]); + }else{ + args[0] = rcStr+':'; + super(args.join(' ')); + } + } + }else{ + if(2===args.length && 'object'===typeof args[1]){ + super(...args); + }else{ + super(args.join(' ')); + } + } } + this.resultCode = rc || capi.SQLITE_ERROR; this.name = 'SQLite3Error'; } }; diff --git a/ext/wasm/api/sqlite3-v-helper.js b/ext/wasm/api/sqlite3-v-helper.js index 1f2950f749..73ba8cc49e 100644 --- a/ext/wasm/api/sqlite3-v-helper.js +++ b/ext/wasm/api/sqlite3-v-helper.js @@ -16,7 +16,7 @@ */ 'use strict'; self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ - const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss; + const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3; const vh = Object.create(null), vt = Object.create(null); sqlite3.VfsHelper = vh; @@ -72,21 +72,29 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ /** Installs a StructBinder-bound function pointer member of the given name and function in the given StructType target object. + It creates a WASM proxy for the given function and arranges for - that proxy to be cleaned up when tgt.dispose() is called. Throws + that proxy to be cleaned up when tgt.dispose() is called. Throws on the slightest hint of error, e.g. tgt is-not-a StructType, name does not map to a struct-bound member, etc. - Returns a proxy for this function which is bound to tgt and takes - 2 args (name,func). That function returns the same thing, - permitting calls to be chained. + As a special case, if the given function is a pointer, it is + assumed to be an existing WASM-bound function pointer and is used + as-is with no extra level of proxying or cleanup. Results are + undefined if it's a pointer and it's _not_ a function pointer. + It is legal to pass a value of 0, indicating a NULL pointer, with + the caveat that 0 _is_ a legal function pointer in WASM but it + will not be accepted as such _here_. (Justification: the function + at address zero must be one which initially came from the WASM + module, not a method we want to bind to a virtual table or VFS.) + + This function returns a proxy for itself which is bound to tgt + and takes 2 args (name,func). That function returns the same + thing as this one, permitting calls to be chained. If called with only 1 arg, it has no side effects but returns a func with the same signature as described above. - If tgt.ondispose is set before this is called then it _must_ - be an array, to which this function will append entries. - ACHTUNG: because we cannot generically know how to transform JS exceptions into result codes, the installed functions do no automatic catching of exceptions. It is critical, to avoid @@ -94,20 +102,20 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ this function do not throw. The exception, as it were, to that rule is... - If applyArgcCheck is true then each method gets wrapped in a - proxy which asserts that it is passed the expected number of - arguments, throwing if the argument count does not match - expectations. That is only intended for dev-time usage for sanity - checking, and will leave the C environment in an undefined - state. For non-dev-time use, it is a given that the C API will - never call one of the generated function wrappers with the wrong - argument count. + If applyArgcCheck is true then each JS function (as opposed to + function pointers) gets wrapped in a proxy which asserts that it + is passed the expected number of arguments, throwing if the + argument count does not match expectations. That is only intended + for dev-time usage for sanity checking, and will leave the C + environment in an undefined state. */ vh.installMethod = vt.installMethod = function callee( tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck ){ if(!(tgt instanceof sqlite3.StructBinder.StructType)){ toss("Usage error: target object is-not-a StructType."); + }else if(!(func instanceof Function) && !wasm.isPtr(func)){ + toss("Usage errror: expecting a Function or WASM pointer to one."); } if(1===arguments.length){ return (n,f)=>callee(tgt, n, f, applyArgcCheck); @@ -143,26 +151,33 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ }/*static init*/ const sigN = tgt.memberSignature(name); if(sigN.length<2){ - toss("Member",name," is not a function pointer. Signature =",sigN); + toss("Member",name,"does not have a function pointer signature:",sigN); } const memKey = tgt.memberKey(name); - const fProxy = applyArgcCheck + const fProxy = (applyArgcCheck && !wasm.isPtr(func)) /** This middle-man proxy is only for use during development, to confirm that we always pass the proper number of arguments. We know that the C-level code will always use the correct argument count. */ ? callee.argcProxy(tgt, memKey, func, sigN) : func; - const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true)); - tgt[memKey] = pFunc; - if(!tgt.ondispose) tgt.ondispose = []; - else if(!Array.isArray(tgt.ondispose)) tgt.ondispose = [tgt.ondispose]; - if(!tgt.ondispose.__removeFuncList){ - tgt.ondispose.push('ondispose.__removeFuncList handler', + if(wasm.isPtr(fProxy)){ + if(fProxy && !wasm.functionEntry(fProxy)){ + toss("Pointer",fProxy,"is not a WASM function table entry."); + } + tgt[memKey] = fProxy; + }else{ + const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true)); + tgt[memKey] = pFunc; + if(!tgt.ondispose) tgt.ondispose = []; + else if(!Array.isArray(tgt.ondispose)) tgt.ondispose = [tgt.ondispose]; + if(!tgt.ondispose || !tgt.ondispose.__removeFuncList){ + tgt.addOnDispose('ondispose.__removeFuncList handler', callee.removeFuncList); - tgt.ondispose.__removeFuncList = []; + tgt.ondispose.__removeFuncList = []; + } + tgt.ondispose.__removeFuncList.push(memKey, pFunc); } - tgt.ondispose.__removeFuncList.push(memKey, pFunc); return (n,f)=>callee(tgt, n, f, applyArgcCheck); }/*installMethod*/; vh.installMethod.installMethodArgcCheck = false; @@ -269,8 +284,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ this.installMethods(o.struct, o.methods, !!o.applyArgcCheck); if('vfs'===key){ if(!o.struct.$zName && 'string'===typeof o.name){ - o.struct.$zName = wasm.allocCString(o.name); - /* Note that we leak that C-string. */ + o.struct.addOnDispose( + o.struct.$zName = wasm.allocCString(o.name) + ); } this.registerVfs(o.struct, !!o.asDefault); } @@ -292,24 +308,20 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ vt.sqlite3ValuesToJs = capi.sqlite3_create_function_v2.udfConvertArgs; /** - Factory function for wrapXyz() impls. + Factory function for xAbc() impls. */ - const __xWrapFactory = function(structType){ - return function(ptr,remove=false){ + const __xWrapFactory = function(methodName,structType){ + return function(ptr,removeMapping=false){ if(0===arguments.length) ptr = new structType; if(ptr instanceof structType){ //T.assert(!this.has(ptr.pointer)); this.set(ptr.pointer, ptr); return ptr; }else if(!wasm.isPtr(ptr)){ - sqlite3.SQLite3Error.toss("Invalid argument to xWrapFactory"); + sqlite3.SQLite3Error.toss("Invalid argument to",methodName+"()"); } let rc = this.get(ptr); - if(remove) this.delete(ptr); - /*arguable else if(!rc){ - rc = new structType(ptr); - this.set(ptr, rc); - }*/ + if(removeMapping) this.delete(ptr); return rc; }.bind(new Map); }; @@ -336,7 +348,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ called from sqlite3_module::xDisconnect() implementations or in error handling of a failed xCreate() or xConnect(). */ - vt.xWrapVtab = __xWrapFactory(capi.sqlite3_vtab); + vt.xVtab = __xWrapFactory('xVtab',capi.sqlite3_vtab); /** EXPERIMENTAL. DO NOT USE IN CLIENT CODE. @@ -356,7 +368,16 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ intended to be called from xClose() or in error handling of a failed xOpen(). */ - vt.xWrapCursor = __xWrapFactory(capi.sqlite3_vtab_cursor); + vt.xCursor = __xWrapFactory('xCursor',capi.sqlite3_vtab_cursor); + + /** + Convenience form of creating an sqlite3_index_info wrapper, + intended for use in xBestIndex implementations. Note that the + caller is expected to call dispose() on the returned object + before returning. Though not _strictly_ required, as that object + does not own the pIdxInfo memory, it is nonetheless good form. + */ + vt.xIndexInfo = (pIdxInfo)=>new capi.sqlite3_index_info(pIdxInfo); /** Given an error object, this function returns @@ -394,27 +415,38 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ let rc = ... return rc; }catch(e){ - return sqlite3.VtabHelper.xMethodError( + return sqlite3.VtabHelper.xError( 'xColumn', e, sqlite3.capi.SQLITE_XYZ); - // where SQLITE_XYZ is some call-appropriate result code - // defaulting to SQLITE_ERROR. + // where SQLITE_XYZ is some call-appropriate result code. } ``` - If xMethodError.errorReporter is a function, it is called in + If no 3rd argument is provided, its default depends on + the error type: + + - An sqlite3.WasmAllocError always resolves to capi.SQLITE_NOMEM. + + - If err is an SQLite3Error then its `resultCode` property + is used. + + - If all else fails, capi.SQLITE_ERROR is used. + + If xError.errorReporter is a function, it is called in order to report the error, else the error is not reported. If that function throws, that exception is ignored. */ - vt.xMethodError = function f(methodName, err, defaultRc=capi.SQLITE_ERROR){ + vt.xError = function f(methodName, err, defaultRc){ if(f.errorReporter instanceof Function){ try{f.errorReporter("sqlite3_module::"+methodName+"(): "+err.message);} catch(e){/*ignored*/} } - return (err instanceof sqlite3.WasmAllocError) - ? capi.SQLITE_NOMEM - : defaultRc; + let rc; + if(err instanceof sqlite3.WasmAllocError) rc = capi.SQLITE_NOMEM; + else if(arguments.length>2) rc = defaultRc; + else if(err instanceof sqlite3.SQLite3Error) rc = err.resultCode; + return rc || capi.SQLITE_ERROR; }; - vt.xMethodError.errorReporter = 1 ? console.error.bind(console) : false; + vt.xError.errorReporter = 1 ? console.error.bind(console) : false; /** "The problem" with this is that it introduces an outer function with @@ -426,15 +458,139 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ /** vt.methodCatcher = function(methodName, method, defaultErrRc=capi.SQLITE_ERROR){ return function(...args){ try { method(...args); } - }catch(e){ return vt.xMethodError(methodName, e, defaultRc) } + }catch(e){ return vt.xError(methodName, e, defaultRc) } }; */ /** - A helper for sqlite3_vtab::xRow() implementations. It must be + A helper for sqlite3_vtab::xRowid() implementations. It must be passed that function's 2nd argument and the value for that pointer. Returns the same as wasm.setMemValue() and will throw if the 1st or 2nd arguments are invalid for that function. */ - vt.setRowId = (ppRowid64, value)=>wasm.setMemValue(ppRowid64, value, 'i64'); + vt.xRowid = (ppRowid64, value)=>wasm.setMemValue(ppRowid64, value, 'i64'); + + /** + Sets up an sqlite3_module() object for later installation into + individual databases using sqlite3_create_module(). Requires an + object with the following properties: + + - `methods`: an object containing a mapping of properties with + the C-side names of the sqlite3_module methods, e.g. xCreate, + xBestIndex, etc., to JS implementations for those functions. + Certain special-case handling is performed, as described below. + + - `catchExceptions` (default=false): if truthy, the given methods + are not mapped as-is, but are instead wrapped inside wrappers + which translate exceptions into result codes of SQLITE_ERROR or + SQLITE_NOMEM, depending on whether the exception is an + sqlite3.WasmAllocError. In the case of the xConnect and xCreate + methods, the exception handler also sets the output error + string to the exception's error string. + + - OPTIONAL `struct`: a sqlite3.capi.sqlite3_module() instance. If + not set, one will be created automatically and (on success) + added to the object. + + - OPTIONAL `iVersion`: if set, it must be an integer value and it + gets assigned to the `$iVersion` member of the struct object. + If it's _not_ set, and the passed-in `struct` object's `$iVersion` + is 0 (the default) then this function attempts to define a value + for that property based on the list of methods it has. + + If `catchExceptions` is false, it is up to the client to ensure + that no exceptions escape the methods, as doing so would move + them through the C API, leading to undefined + behavior. (VtabHelper.xError() is intended to assist in reporting + such exceptions.) + + If `methods.xConnect` is `true` then the value of + `methods.xCreate` is used in its place, and vice versa. This is + to facilitate creation of those methods inline in the passed-in + object without requiring the client to explicitly get a reference + to one of them in order to assign it to the other one. Note that + sqlite treats those two functions specially if they are exactly + the same function (same pointer value). The + `catchExceptions`-installed handlers will account for identical + references to those two functions and will install the same + wrapper function for both. + + The given methods are expected to return integer values, as + expected by the C API. If `catchExceptions` is truthy, the return + value of the wrapped function will be used as-is and will be + translated to 0 if the function returns a falsy value (e.g. if it + does not have an explicit return). If `catchExceptions` is _not_ + active, the method implementations must explicitly return integer + values. + + Throws on error. Returns the sqlite3_module object on success. + */ + vt.setupModule = function(opt){ + const mod = opt.struct || new capi.sqlite3_module(); + try{ + const methods = opt.methods || toss("Missing 'methods' object."); + if(true===methods.xConnect) methods.xConnect = methods.xCreate; + else if(true===methods.xCreate) methods.xCreate = methods.xConnect; + if(opt.catchExceptions){ + const fwrap = function(methodName, func){ + if(['xConnect','xCreate'].indexOf(methodName) >= 0){ + return function(pDb, pAux, argc, argv, ppVtab, pzErr){ + try{return func(...arguments) || 0;} + catch(e){ + if(!(e instanceof sqlite3.WasmAllocError)){ + wasm.setPtrValue(pzErr, wasm.allocCString(e.message)); + } + return vt.xError(methodName, e); + } + }; + }else{ + return function(...args){ + try{return func(...args) || 0;} + catch(e){ + return vt.xError(methodName, e); + } + }; + } + }; + const mnames = [ + 'xCreate', 'xConnect', 'xBestIndex', 'xDisconnect', + 'xDestroy', 'xOpen', 'xClose', 'xFilter', 'xNext', + 'xEof', 'xColumn', 'xRowid', 'xUpdate', + 'xBegin', 'xSync', 'xCommit', 'xRollback', + 'xFindFunction', 'xRename', 'xSavepoint', 'xRelease', + 'xRollbackTo', 'xShadowName' + ]; + const remethods = Object.create(null); + for(const k of mnames){ + const m = methods[k]; + if(!(m instanceof Function)) continue; + else if('xConnect'===k && methods.xCreate===m){ + remethods[k] = methods.xCreate; + }else if('xCreate'===k && methods.xConnect===m){ + remethods[k] = methods.xConnect; + }else{ + remethods[k] = fwrap(k, m); + } + } + this.installMethods(mod, remethods, false); + }else{ + this.installMethods( + mod, methods, !!opt.applyArgcCheck/*undocumented option*/ + ); + } + if(0===mod.$iVersion){ + let v; + if('number'===typeof opt.iVersion) v = opt.iVersion; + else if(mod.$xShadowName) v = 3; + else if(mod.$xSavePoint || mod.$xRelease || mod.$xRollbackTo) v = 2; + else v = 1; + mod.$iVersion = v; + } + }catch(e){ + if(!opt.struct) mod.dispose(); + throw e; + } + if(!opt.struct) opt.struct = mod; + return mod; + }/*setupModule()*/; }/*sqlite3ApiBootstrap.initializers.push()*/); diff --git a/ext/wasm/jaccwabyt/jaccwabyt.js b/ext/wasm/jaccwabyt/jaccwabyt.js index f02c8bbdef..d4ec719fb5 100644 --- a/ext/wasm/jaccwabyt/jaccwabyt.js +++ b/ext/wasm/jaccwabyt/jaccwabyt.js @@ -222,6 +222,7 @@ self.Jaccwabyt = function StructBinderFactory(config){ const __freeStruct = function(ctor, obj, m){ if(!m) m = __instancePointerMap.get(obj); if(m) { + __instancePointerMap.delete(obj); if(Array.isArray(obj.ondispose)){ let x; while((x = obj.ondispose.shift())){ @@ -245,7 +246,6 @@ self.Jaccwabyt = function StructBinderFactory(config){ } } delete obj.ondispose; - __instancePointerMap.delete(obj); if(ctor.debugFlags.__flags.dealloc){ log("debug.dealloc:",(obj[xPtrPropName]?"EXTERNAL":""), ctor.structName,"instance:", diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index 910bbc94e6..83b02522e4 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -301,14 +301,12 @@ self.sqlite3InitModule = sqlite3InitModule; addTest: function(name, callback){ let predicate; if(1===arguments.length){ - const opt = arguments[0]; - predicate = opt.predicate; - name = opt.name; - callback = opt.test; + this.currentTestGroup.addTest(arguments[0]); + }else{ + this.currentTestGroup.addTest({ + name, predicate, test: callback + }); } - this.currentTestGroup.addTest({ - name, predicate, test: callback - }); return this; }, runTests: async function(sqlite3){ @@ -399,12 +397,21 @@ self.sqlite3InitModule = sqlite3InitModule; catch(e){T.assert("test ing ." === e.message)} try{ throw new sqlite3.SQLite3Error(capi.SQLITE_SCHEMA) } - catch(e){ T.assert('SQLITE_SCHEMA' === e.message) } + catch(e){ + T.assert('SQLITE_SCHEMA' === e.message) + .assert(capi.SQLITE_SCHEMA === e.resultCode); + } try{ sqlite3.SQLite3Error.toss(capi.SQLITE_CORRUPT,{cause: true}) } catch(e){ - T.assert('SQLITE_CORRUPT'===e.message) + T.assert('SQLITE_CORRUPT' === e.message) + .assert(capi.SQLITE_CORRUPT === e.resultCode) .assert(true===e.cause); } + try{ sqlite3.SQLite3Error.toss("resultCode check") } + catch(e){ + T.assert(capi.SQLITE_ERROR === e.resultCode) + .assert('resultCode check' === e.message); + } }) //////////////////////////////////////////////////////////////////// .t('strglob/strlike', function(sqlite3){ @@ -988,6 +995,20 @@ self.sqlite3InitModule = sqlite3InitModule; const dbFile = '/tester1.db'; wasm.sqlite3_wasm_vfs_unlink(0, dbFile); const db = this.db = new sqlite3.oo1.DB(dbFile, 0 ? 'ct' : 'c'); + db.onclose = { + disposeThese: [], + after: function(){ + while(this.disposeThese.length){ + const v = this.disposeThese.shift(); + console.debug("db.onclose cleaning up:",v); + if(wasm.isPtr(v)) wasm.dealloc(v); + else if(v instanceof sqlite3.StructBinder.StructType){ + v.dispose(); + } + } + } + }; + T.assert(Number.isInteger(db.pointer)) .mustThrowMatching(()=>db.pointer=1, /read-only/) .assert(0===sqlite3.capi.sqlite3_extended_result_codes(db.pointer,1)) @@ -1539,219 +1560,6 @@ self.sqlite3InitModule = sqlite3InitModule; T.mustThrow(()=>db.exec("select * from foo.bar")); }) - //////////////////////////////////////////////////////////////////////// - .t({ - name: 'Custom virtual tables', - predicate: ()=>wasm.bigIntEnabled, - test: function(sqlite3){ - warn("The vtab/module JS bindings are experimental and subject to change."); - const vth = sqlite3.VtabHelper; - const tmplCols = Object.assign(Object.create(null),{ - A: 0, B: 1 - }); - /** - The vtab demonstrated here is a JS-ification of - ext/misc/templatevtab.c. - */ - const tmplMethods = { - xConnect: function(pDb, pAux, argc, argv, ppVtab, pzErr){ - try{ - const args = wasm.cArgvToJs(argc, argv); - T.assert(args.length>=3) - .assert(args[0] === 'testvtab') - .assert(args[1] === 'main') - .assert(args[2] === 'testvtab'); - console.debug("xConnect() args =",args); - const rc = capi.sqlite3_declare_vtab( - pDb, "CREATE TABLE ignored(a,b)" - ); - if(0===rc){ - const t = vth.xWrapVtab(); - wasm.setPtrValue(ppVtab, t.pointer); - T.assert(t === vth.xWrapVtab(wasm.getPtrValue(ppVtab))); - } - return rc; - }catch(e){ - if(!(e instanceof sqlite3.WasmAllocError)){ - wasm.setPtrValue(pzErr, wasm.allocCString(e.message)); - } - return vth.xMethodError('xConnect',e); - } - }, - xDisconnect: function(pVtab){ - try { - const t = vth.xWrapVtab(pVtab, true); - t.dispose(); - return 0; - }catch(e){ - return vth.xMethodError('xDisconnect',e); - } - }, - xOpen: function(pVtab, ppCursor){ - try{ - const t = vth.xWrapVtab(pVtab), c = vth.xWrapCursor(); - T.assert(t instanceof capi.sqlite3_vtab) - .assert(c instanceof capi.sqlite3_vtab_cursor); - wasm.setPtrValue(ppCursor, c.pointer); - c._rowId = 0; - return 0; - }catch(e){ - return vth.xMethodError('xOpen',e); - } - }, - xClose: function(pCursor){ - try{ - const c = vth.xWrapCursor(pCursor,true); - T.assert(c instanceof capi.sqlite3_vtab_cursor) - .assert(!vth.xWrapCursor(pCursor)); - c.dispose(); - return 0; - }catch(e){ - return vth.xMethodError('xClose',e); - } - }, - xNext: function(pCursor){ - try{ - const c = vth.xWrapCursor(pCursor); - ++c._rowId; - return 0; - }catch(e){ - return vth.xMethodError('xNext',e); - } - - }, - xColumn: function(pCursor, pCtx, iCol){ - try{ - const c = vth.xWrapCursor(pCursor); - switch(iCol){ - case tmplCols.A: - capi.sqlite3_result_int(pCtx, 1000 + c._rowId); - break; - case tmplCols.B: - capi.sqlite3_result_int(pCtx, 2000 + c._rowId); - break; - default: sqlite3.SQLite3Error.toss("Invalid column id",iCol); - } - return 0; - }catch(e){ - return vth.xMethodError('xColumn',e); - } - }, - xRowid: function(pCursor, ppRowid64){ - try{ - const c = vth.xWrapCursor(pCursor); - vth.setRowId(ppRowid64, c._rowId); - return 0; - }catch(e){ - return vth.xMethodError('xRowid',e); - } - }, - xEof: function(pCursor){ - const c = vth.xWrapCursor(pCursor); - return c._rowId>=10; - }, - xFilter: function(pCursor, idxNum, idxCStr, - argc, argv/* [sqlite3_value* ...] */){ - try{ - const c = vth.xWrapCursor(pCursor); - c._rowId = 0; - const list = vth.sqlite3ValuesToJs(argc, argv); - T.assert(argc === list.length); - //log(argc,"xFilter value(s):",list); - return 0; - }catch(e){ - return vth.xMethodError('xFilter',e); - } - }, - xBestIndex: function(pVtab, pIdxInfo){ - try{ - //const t = vth.xWrapVtab(pVtab); - const sii = capi.sqlite3_index_info; - const pii = new sii(pIdxInfo); - pii.$estimatedRows = 10; - pii.$estimatedCost = 10.0; - //log("xBestIndex $nConstraint =",pii.$nConstraint); - if(pii.$nConstraint>0){ - // Validate nthConstraint() and nthConstraintUsage() - const max = pii.$nConstraint; - for(let i=0; i < max; ++i ){ - let v = pii.nthConstraint(i,true); - T.assert(wasm.isPtr(v)); - v = pii.nthConstraint(i); - T.assert(v instanceof sii.sqlite3_index_constraint) - .assert(v.pointer >= pii.$aConstraint); - v.dispose(); - v = pii.nthConstraintUsage(i,true); - T.assert(wasm.isPtr(v)); - v = pii.nthConstraintUsage(i); - T.assert(v instanceof sii.sqlite3_index_constraint_usage) - .assert(v.pointer >= pii.$aConstraintUsage); - v.$argvIndex = i;//just to get some values into xFilter - v.dispose(); - } - } - //log("xBestIndex $nOrderBy =",pii.$nOrderBy); - if(pii.$nOrderBy>0){ - // Validate nthOrderBy() - const max = pii.$nOrderBy; - for(let i=0; i < max; ++i ){ - let v = pii.nthOrderBy(i,true); - T.assert(wasm.isPtr(v)); - v = pii.nthOrderBy(i); - T.assert(v instanceof sii.sqlite3_index_orderby) - .assert(v.pointer >= pii.$aOrderBy); - v.dispose(); - } - } - pii.dispose(); - return 0; - }catch(e){ - return vth.xMethodError('xBestIndex',e); - } - } - }; - /** - The vtab API places relevance on whether xCreate and - xConnect are exactly the same function (same pointer - address). Two JS-side references to the same method will - end up, without acrobatics to counter it, being compiled as - two different WASM-side bindings, i.e. two different - pointers. - - In order to account for this, VtabHelper.installMethods() - checks for duplicate function entries and maps them to the - same WASM-compiled instance. - */ - if(1){ - tmplMethods.xCreate = tmplMethods.xConnect; - } - - const tmplMod = new sqlite3.capi.sqlite3_module(); - tmplMod.ondispose = []; - tmplMod.$iVersion = 0; - vth.installMethods(tmplMod, tmplMethods, true); - if(tmplMethods.xCreate){ - T.assert(tmplMod.$xCreate) - .assert(tmplMod.$xCreate === tmplMod.$xConnect, - "installMethods() must avoid re-compiling identical functions"); - tmplMod.$xCreate = 0; - } - let rc = capi.sqlite3_create_module( - this.db, "testvtab", tmplMod, 0 - ); - this.db.checkRc(rc); - - const list = this.db.selectArrays( - "SELECT a,b FROM testvtab where a<9999 and b>1 order by a, b" - /* Query is shaped so that it will ensure that some constraints - end up in xBestIndex(). */ - ); - T.assert(10===list.length) - .assert(1000===list[0][0]) - .assert(2009===list[list.length-1][1]) - } - })/*vtab sanity checks*/ - //////////////////////////////////////////////////////////////////// .t({ name: 'C-side WASM tests', @@ -1838,6 +1646,379 @@ self.sqlite3InitModule = sqlite3InitModule; } }/* jaccwabyt-specific tests */) + //////////////////////////////////////////////////////////////////////// + .t({ + name: 'virtual table #1', + predicate: ()=>!!capi.sqlite3_index_info, + test: function(sqlite3){ + warn("The vtab/module JS bindings are experimental and subject to change."); + const vth = sqlite3.VtabHelper; + const tmplCols = Object.assign(Object.create(null),{ + A: 0, B: 1 + }); + /** + The vtab demonstrated here is a JS-ification of + ext/misc/templatevtab.c. + */ + const tmplMethods = { + xConnect: function(pDb, pAux, argc, argv, ppVtab, pzErr){ + try{ + const args = wasm.cArgvToJs(argc, argv); + T.assert(args.length>=3) + .assert(args[0] === 'testvtab') + .assert(args[1] === 'main') + .assert(args[2] === 'testvtab'); + console.debug("xConnect() args =",args); + const rc = capi.sqlite3_declare_vtab( + pDb, "CREATE TABLE ignored(a,b)" + ); + if(0===rc){ + const t = vth.xVtab(); + wasm.setPtrValue(ppVtab, t.pointer); + T.assert(t === vth.xVtab(wasm.getPtrValue(ppVtab))); + } + return rc; + }catch(e){ + if(!(e instanceof sqlite3.WasmAllocError)){ + wasm.setPtrValue(pzErr, wasm.allocCString(e.message)); + } + return vth.xError('xConnect',e); + } + }, + xDisconnect: function(pVtab){ + try { + const t = vth.xVtab(pVtab, true); + t.dispose(); + return 0; + }catch(e){ + return vth.xError('xDisconnect',e); + } + }, + xOpen: function(pVtab, ppCursor){ + try{ + const t = vth.xVtab(pVtab), c = vth.xCursor(); + T.assert(t instanceof capi.sqlite3_vtab) + .assert(c instanceof capi.sqlite3_vtab_cursor); + wasm.setPtrValue(ppCursor, c.pointer); + c._rowId = 0; + return 0; + }catch(e){ + return vth.xError('xOpen',e); + } + }, + xClose: function(pCursor){ + try{ + const c = vth.xCursor(pCursor,true); + T.assert(c instanceof capi.sqlite3_vtab_cursor) + .assert(!vth.xCursor(pCursor)); + c.dispose(); + return 0; + }catch(e){ + return vth.xError('xClose',e); + } + }, + xNext: function(pCursor){ + try{ + const c = vth.xCursor(pCursor); + ++c._rowId; + return 0; + }catch(e){ + return vth.xError('xNext',e); + } + + }, + xColumn: function(pCursor, pCtx, iCol){ + try{ + const c = vth.xCursor(pCursor); + switch(iCol){ + case tmplCols.A: + capi.sqlite3_result_int(pCtx, 1000 + c._rowId); + break; + case tmplCols.B: + capi.sqlite3_result_int(pCtx, 2000 + c._rowId); + break; + default: sqlite3.SQLite3Error.toss("Invalid column id",iCol); + } + return 0; + }catch(e){ + return vth.xError('xColumn',e); + } + }, + xRowid: function(pCursor, ppRowid64){ + try{ + const c = vth.xCursor(pCursor); + vth.xRowid(ppRowid64, c._rowId); + return 0; + }catch(e){ + return vth.xError('xRowid',e); + } + }, + xEof: function(pCursor){ + const c = vth.xCursor(pCursor), + rc = c._rowId>=10; + c.dispose(); + return rc; + }, + xFilter: function(pCursor, idxNum, idxCStr, + argc, argv/* [sqlite3_value* ...] */){ + try{ + const c = vth.xCursor(pCursor); + c._rowId = 0; + const list = vth.sqlite3ValuesToJs(argc, argv); + T.assert(argc === list.length); + //log(argc,"xFilter value(s):",list); + c.dispose(); + return 0; + }catch(e){ + return vth.xError('xFilter',e); + } + }, + xBestIndex: function(pVtab, pIdxInfo){ + try{ + //const t = vth.xVtab(pVtab); + const sii = capi.sqlite3_index_info; + const pii = new sii(pIdxInfo); + pii.$estimatedRows = 10; + pii.$estimatedCost = 10.0; + //log("xBestIndex $nConstraint =",pii.$nConstraint); + if(pii.$nConstraint>0){ + // Validate nthConstraint() and nthConstraintUsage() + const max = pii.$nConstraint; + for(let i=0; i < max; ++i ){ + let v = pii.nthConstraint(i,true); + T.assert(wasm.isPtr(v)); + v = pii.nthConstraint(i); + T.assert(v instanceof sii.sqlite3_index_constraint) + .assert(v.pointer >= pii.$aConstraint); + v.dispose(); + v = pii.nthConstraintUsage(i,true); + T.assert(wasm.isPtr(v)); + v = pii.nthConstraintUsage(i); + T.assert(v instanceof sii.sqlite3_index_constraint_usage) + .assert(v.pointer >= pii.$aConstraintUsage); + v.$argvIndex = i;//just to get some values into xFilter + v.dispose(); + } + } + //log("xBestIndex $nOrderBy =",pii.$nOrderBy); + if(pii.$nOrderBy>0){ + // Validate nthOrderBy() + const max = pii.$nOrderBy; + for(let i=0; i < max; ++i ){ + let v = pii.nthOrderBy(i,true); + T.assert(wasm.isPtr(v)); + v = pii.nthOrderBy(i); + T.assert(v instanceof sii.sqlite3_index_orderby) + .assert(v.pointer >= pii.$aOrderBy); + v.dispose(); + } + } + pii.dispose(); + return 0; + }catch(e){ + return vth.xError('xBestIndex',e); + } + } + }; + /** + The vtab API places relevance on whether xCreate and + xConnect are exactly the same function (same pointer + address). Two JS-side references to the same method will + end up, without acrobatics to counter it, being compiled as + two different WASM-side bindings, i.e. two different + pointers. + + In order to account for this, VtabHelper.installMethods() + checks for duplicate function entries and maps them to the + same WASM-compiled instance. + */ + if(1){ + tmplMethods.xCreate = tmplMethods.xConnect; + } + + const tmplMod = new sqlite3.capi.sqlite3_module(); + tmplMod.$iVersion = 0; + this.db.onclose.disposeThese.push(tmplMod); + vth.installMethods(tmplMod, tmplMethods, true); + if(tmplMethods.xCreate){ + T.assert(tmplMod.$xCreate) + .assert(tmplMod.$xCreate === tmplMod.$xConnect, + "installMethods() must avoid re-compiling identical functions"); + tmplMod.$xCreate = 0; + } + let rc = capi.sqlite3_create_module( + this.db, "testvtab", tmplMod, 0 + ); + this.db.checkRc(rc); + + const list = this.db.selectArrays( + "SELECT a,b FROM testvtab where a<9999 and b>1 order by a, b" + /* Query is shaped so that it will ensure that some constraints + end up in xBestIndex(). */ + ); + T.assert(10===list.length) + .assert(1000===list[0][0]) + .assert(2009===list[list.length-1][1]) + } + })/*custom vtab #1*/ + + //////////////////////////////////////////////////////////////////////// + .t({ + name: 'virtual table #2 (w/ automated exception wrapping)', + predicate: ()=>!!capi.sqlite3_index_info, + test: function(sqlite3){ + warn("The vtab/module JS bindings are experimental and subject to change."); + const vth = sqlite3.VtabHelper; + const tmplCols = Object.assign(Object.create(null),{ + A: 0, B: 1 + }); + /** + The vtab demonstrated here is a JS-ification of + ext/misc/templatevtab.c. + */ + let throwOnConnect = 1 ? 0 : capi.SQLITE_CANTOPEN + /* ^^^ just for testing exception wrapping. Note that sqlite + always translates errors from a vtable to a generic + SQLITE_ERROR unless it's from xConnect()/xCreate() and that + callback sets an error string. */; + const modConfig = { + /* catchExceptions changes how the methods are wrapped */ + catchExceptions: false, + name: "vtab2test", + methods:{ + xConnect: function(pDb, pAux, argc, argv, ppVtab, pzErr){ + if(throwOnConnect){ + sqlite3.SQLite3Error.toss( + throwOnConnect, + "Throwing a test exception." + ); + } + const args = wasm.cArgvToJs(argc, argv); + console.debug("xCreate/xConnect args:",args); + T.assert(args.length>=3); + const rc = capi.sqlite3_declare_vtab( + pDb, "CREATE TABLE ignored(a,b)" + ); + if(0===rc){ + const t = vth.xVtab(); + wasm.setPtrValue(ppVtab, t.pointer); + T.assert(t === vth.xVtab(wasm.getPtrValue(ppVtab))); + } + return rc; + }, + xDisconnect: function(pVtab){ + const t = vth.xVtab(pVtab, true); + t.dispose(); + }, + xOpen: function(pVtab, ppCursor){ + const t = vth.xVtab(pVtab), c = vth.xCursor(); + T.assert(t instanceof capi.sqlite3_vtab) + .assert(c instanceof capi.sqlite3_vtab_cursor); + wasm.setPtrValue(ppCursor, c.pointer); + c._rowId = 0; + }, + xClose: function(pCursor){ + const c = vth.xCursor(pCursor,true); + T.assert(c instanceof capi.sqlite3_vtab_cursor) + .assert(!vth.xCursor(pCursor)); + c.dispose(); + }, + xNext: function(pCursor){ + const c = vth.xCursor(pCursor); + ++c._rowId; + }, + xColumn: function(pCursor, pCtx, iCol){ + const c = vth.xCursor(pCursor); + switch(iCol){ + case tmplCols.A: + capi.sqlite3_result_int(pCtx, 1000 + c._rowId); + break; + case tmplCols.B: + capi.sqlite3_result_int(pCtx, 2000 + c._rowId); + break; + default: sqlite3.SQLite3Error.toss("Invalid column id",iCol); + } + }, + xRowid: function(pCursor, ppRowid64){ + const c = vth.xCursor(pCursor); + vth.xRowid(ppRowid64, c._rowId); + c.dispose(); + }, + xEof: function(pCursor){ + const c = vth.xCursor(pCursor), + rc = c._rowId>=10; + c.dispose(); + return rc; + }, + xFilter: function(pCursor, idxNum, idxCStr, + argc, argv/* [sqlite3_value* ...] */){ + const c = vth.xCursor(pCursor); + c._rowId = 0; + const list = vth.sqlite3ValuesToJs(argc, argv); + T.assert(argc === list.length); + c.dispose(); + }, + xBestIndex: function(pVtab, pIdxInfo){ + //const t = vth.xVtab(pVtab); + const pii = vth.xIndexInfo(pIdxInfo); + pii.$estimatedRows = 10; + pii.$estimatedCost = 10.0; + pii.dispose(); + } + }/*methods*/ + }; + const doEponymous = + /* Bug (somewhere): non-eponymous is behaving as is + the call to sqlite3_create_module() is missing + or failed: + + SQL TRACE #63 create virtual table testvtab2 using vtab2test(arg1, arg2) + + => sqlite3 result code 1: no such module: vtab2test + */ true; + if(doEponymous){ + warn("Reminder: non-eponymous mode is still not working here.", + "Details are in the code comments."); + modConfig.methods.xCreate = 0; + }else{ + modConfig.methods.xCreate = (...args)=>0; + } + const tmplMod = vth.setupModule(modConfig); + T.assert(tmplMod instanceof capi.sqlite3_module) + .assert(1===tmplMod.$iVersion); + if(doEponymous){ + if(modConfig.methods.xCreate !== 0){ + T.assert(modConfig.methods.xCreate === modConfig.methods.xConnect) + .assert(tmplMod.$xCreate === tmplMod.$xConnect); + }else{ + T.assert(0 === tmplMod.$xCreate); + } + } + this.db.onclose.disposeThese.push(tmplMod); + this.db.checkRc(capi.sqlite3_create_module( + this.db, modConfig.name, tmplMod, 0 + )); + if(!doEponymous){ + this.db.exec([ + "create virtual table testvtab2 using ", + modConfig.name, + "(arg1, arg2)" + ]); + } + const list = this.db.selectArrays( + ["SELECT a,b FROM ", + (doEponymous ? modConfig.name : "testvtab2"), + " where a<9999 and b>1 order by a, b" + ]/* Query is shaped so that it will ensure that some + constraints end up in xBestIndex(). */ + ); + T.assert(10===list.length) + .assert(1000===list[0][0]) + .assert(2009===list[list.length-1][1]) + } + })/*custom vtab #2*/ + + //////////////////////////////////////////////////////////////////////// .t('Close db', function(){ T.assert(this.db).assert(wasm.isPtr(this.db.pointer)); wasm.sqlite3_wasm_db_reset(this.db); diff --git a/manifest b/manifest index e691430191..8786729db6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\saddOnDispose()\smethod\sto\sJaccwabyt\sand\scode-adjacent\sminor\sinternal\scleanups. -D 2022-12-07T03:42:39.134 +C Work\son\san\salternate\s(slightly\ssimpler)\sapproach\sto\sbinding\sJS\svtabs.\sNon-eponymous\svtabs\sare\snot\sworking,\sfor\sreasons\sas\syet\sunknown. +D 2022-12-07T07:22:34.835 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -505,11 +505,11 @@ F ext/wasm/api/pre-js.c-pp.js b88499dc303c21fc3f55f2c364a0f814f587b60a9578430388 F ext/wasm/api/sqlite3-api-cleanup.js 680d5ccfff54459db136a49b2199d9f879c8405d9c99af1dda0cc5e7c29056f4 F ext/wasm/api/sqlite3-api-glue.js 8fa55af37c9880f94a803f32591dc0304750cc2f750048daf41fe942757bee64 F ext/wasm/api/sqlite3-api-oo1.js 416e6398721a4cbb80ddfa3d7b303216790f1d344efdbbc36239d39abc66aa27 -F ext/wasm/api/sqlite3-api-prologue.js a7596c30392d9ca8f5b7c14feb4e6788107d1159fd5f90eb26708d653d36c9bc +F ext/wasm/api/sqlite3-api-prologue.js 1380e933325c11786b2afc93fc8ff88c2fd1ffeac3e0081da35e5a7317f20e09 F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 F ext/wasm/api/sqlite3-opfs-async-proxy.js f79dd8d98ef3e0b55c10bb2bee7a3840fa967318e1f577c156aafc34664271d1 -F ext/wasm/api/sqlite3-v-helper.js 2125255f102ab07a2653d74d4931d716b0d27c5a89bebc188ad828de0dd1dcef +F ext/wasm/api/sqlite3-v-helper.js c0c56d4fb1272140629ac858297a825e0a8e04005df92c70ef4a4aa75d4d4645 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 8ec510fee735c646fb18a3b99f0ca5ca461f9e066c43cdc404d7144f12ae6ed6 F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasm.c 723522a6c2a2463884a83fa1cc7ae5770deaaf0856a1058cc1023b2bfa1c898b @@ -539,7 +539,7 @@ F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5 F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2 F ext/wasm/index-dist.html c806b6005145b71d64240606e9c6e0bf56878ee8829c66fe7486cebf34b0e6b1 F ext/wasm/index.html f151b7c7b5cfdc066567d556acd168e769efd4e982286dc5f849a5ee69ecd0ff -F ext/wasm/jaccwabyt/jaccwabyt.js b7efd07ea3927e9d0bc75b3819c6d40bdfb0a03cbc8d93331be16799f35261c3 +F ext/wasm/jaccwabyt/jaccwabyt.js 06f2ef1ad640c26c593def3d960336e9bb789819b920516480895c38ed5f58fa F ext/wasm/jaccwabyt/jaccwabyt.md 37911f00db12cbcca73aa1ed72594430365f30aafae2fa9c886961de74e5e0eb F ext/wasm/module-symbols.html 980680c8acfa3c8ae6a5aa223512d1b8e78040ced20f8ba2c382129bc73ec028 F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06 @@ -555,7 +555,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9 F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406 -F ext/wasm/tester1.c-pp.js 8144e0e0f76b14fcd5223fad190bd94a50caf19b2419848b782448cda3ccbc78 +F ext/wasm/tester1.c-pp.js 661c9461fa104f231ff9e767c89ba1fc4a4af6a61db076772ca634d562afd35d F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70 F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 @@ -2067,8 +2067,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 0d77c348039926c24e0fb50a7dc7e4b62895cd201c021f8e29832917e4b8b09f -R c60d510be7a6225cada64eb18dd4b778 +P 6a2723fe3f28dd94328d901e64e1e9ee9a1b2e9eeaed6c54038a5b83c914db78 +R 8623f61e63ac3c807b096f8d7028ccc0 U stephan -Z 9a43ff51fca7fb341935fe3d300c9a6e +Z 80cda1da5b829b2851b20f834a26edf8 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index ae8e40499b..c832b9405d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6a2723fe3f28dd94328d901e64e1e9ee9a1b2e9eeaed6c54038a5b83c914db78 \ No newline at end of file +6a0fefb93bcccd950df211cf5c2f49660c7b92115dd01b2b508a4ab9e3ab3d23 \ No newline at end of file From ab8b22a03d033adaa61f82e5c080de64c8200549 Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 8 Dec 2022 04:19:38 +0000 Subject: [PATCH 20/22] Remove some dead JS code and tweak some docs. FossilOrigin-Name: 0ee495452c014680697aa9035c245024df127a52d1820ab0e02580a015d96ecb --- ext/wasm/api/sqlite3-opfs-async-proxy.js | 27 ++++---------- ext/wasm/api/sqlite3-v-helper.js | 1 + ext/wasm/speedtest1-worker.html | 2 +- ext/wasm/speedtest1.html | 6 ++-- ext/wasm/tester1.c-pp.js | 45 +++++++++++++++--------- manifest | 20 +++++------ manifest.uuid | 2 +- 7 files changed, 50 insertions(+), 53 deletions(-) diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.js b/ext/wasm/api/sqlite3-opfs-async-proxy.js index 339ec126d0..1456ae08d2 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.js @@ -13,7 +13,7 @@ A Worker which manages asynchronous OPFS handles on behalf of a synchronous API which controls it via a combination of Worker messages, SharedArrayBuffer, and Atomics. It is the asynchronous - counterpart of the API defined in sqlite3-api-opfs.js. + counterpart of the API defined in sqlite3-vfs-opfs.js. Highly indebted to: @@ -343,16 +343,6 @@ const installAsyncProxy = function(self){ const affirmNotRO = function(opName,fh){ if(fh.readOnly) toss(opName+"(): File is read-only: "+fh.filenameAbs); }; - const affirmLocked = function(opName,fh){ - //if(!fh.syncHandle) toss(opName+"(): File does not have a lock: "+fh.filenameAbs); - /** - Currently a no-op, as speedtest1 triggers xRead() without a - lock (that seems like a bug but it's currently uninvestigated). - This means, however, that some OPFS VFS routines may trigger - acquisition of a lock but never let it go until xUnlock() is - called (which it likely won't be if xLock() was not called). - */ - }; /** We track 2 different timers: the "metrics" timer records how much @@ -393,7 +383,6 @@ const installAsyncProxy = function(self){ */ let flagAsyncShutdown = false; - /** Asynchronous wrappers for sqlite3_vfs and sqlite3_io_methods methods, as well as helpers like mkdir(). Maintenance reminder: @@ -427,11 +416,11 @@ const installAsyncProxy = function(self){ }, xAccess: async (filename)=>{ mTimeStart('xAccess'); - /* OPFS cannot support the full range of xAccess() queries sqlite3 - calls for. We can essentially just tell if the file is - accessible, but if it is it's automatically writable (unless - it's locked, which we cannot(?) know without trying to open - it). OPFS does not have the notion of read-only. + /* OPFS cannot support the full range of xAccess() queries + sqlite3 calls for. We can essentially just tell if the file + is accessible, but if it is then it's automatically writable + (unless it's locked, which we cannot(?) know without trying + to open it). OPFS does not have the notion of read-only. The return semantics of this function differ from sqlite3's xAccess semantics because we are limited in what we can @@ -519,7 +508,6 @@ const installAsyncProxy = function(self){ let rc = 0; wTimeStart('xFileSize'); try{ - affirmLocked('xFileSize',fh); const sz = await (await getSyncHandle(fh,'xFileSize')).getSize(); state.s11n.serialize(Number(sz)); }catch(e){ @@ -615,7 +603,6 @@ const installAsyncProxy = function(self){ let rc = 0, nRead; const fh = __openFiles[fid]; try{ - affirmLocked('xRead',fh); wTimeStart('xRead'); nRead = (await getSyncHandle(fh,'xRead')).read( fh.sabView.subarray(0, n), @@ -659,7 +646,6 @@ const installAsyncProxy = function(self){ const fh = __openFiles[fid]; wTimeStart('xTruncate'); try{ - affirmLocked('xTruncate',fh); affirmNotRO('xTruncate', fh); await (await getSyncHandle(fh,'xTruncate')).truncate(size); }catch(e){ @@ -696,7 +682,6 @@ const installAsyncProxy = function(self){ const fh = __openFiles[fid]; wTimeStart('xWrite'); try{ - affirmLocked('xWrite',fh); affirmNotRO('xWrite', fh); rc = ( n === (await getSyncHandle(fh,'xWrite')) diff --git a/ext/wasm/api/sqlite3-v-helper.js b/ext/wasm/api/sqlite3-v-helper.js index 73ba8cc49e..88c86a6a0a 100644 --- a/ext/wasm/api/sqlite3-v-helper.js +++ b/ext/wasm/api/sqlite3-v-helper.js @@ -538,6 +538,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ try{return func(...arguments) || 0;} catch(e){ if(!(e instanceof sqlite3.WasmAllocError)){ + wasm.dealloc(wasm.getPtrValue(pzErr)); wasm.setPtrValue(pzErr, wasm.allocCString(e.message)); } return vt.xError(methodName, e); diff --git a/ext/wasm/speedtest1-worker.html b/ext/wasm/speedtest1-worker.html index 9fcd29ea72..cd0fdb027c 100644 --- a/ext/wasm/speedtest1-worker.html +++ b/ext/wasm/speedtest1-worker.html @@ -75,7 +75,7 @@
  • The easiest way to try different optimization levels is, from this directory: -
    $ rm -f speedtest1.js; make -e emcc_opt='-O2' speedtest1.js
    +
    $ rm -f jswasm/speedtest1.js; make -e emcc_opt='-O2' speedtest1
    Then reload this page. -O2 seems to consistently produce the fastest results.
  • diff --git a/ext/wasm/speedtest1.html b/ext/wasm/speedtest1.html index 5286b9e482..9cc20924e9 100644 --- a/ext/wasm/speedtest1.html +++ b/ext/wasm/speedtest1.html @@ -40,9 +40,9 @@