diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js index e302c0191a..da17fcb98e 100644 --- a/ext/wasm/api/sqlite3-api-glue.js +++ b/ext/wasm/api/sqlite3-api-glue.js @@ -24,6 +24,251 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ self.WhWasmUtilInstaller(wasm); delete self.WhWasmUtilInstaller; + /** + Signatures for the WASM-exported C-side functions. Each entry + is an array with 2+ elements: + + [ "c-side name", + "result type" (wasm.xWrap() syntax), + [arg types in xWrap() syntax] + // ^^^ this needn't strictly be an array: it can be subsequent + // elements instead: [x,y,z] is equivalent to x,y,z + ] + + Note that support for the API-specific data types in the + result/argument type strings gets plugged in at a later phase in + the API initialization process. + */ + wasm.bindingSignatures = [ + // Please keep these sorted by function name! + ["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"], + ["sqlite3_bind_blob","int", "sqlite3_stmt*", "int", "*", "int", "*" + /* TODO: we should arguably write a custom wrapper which knows + how to handle Blob, TypedArrays, and JS strings. */ + ], + ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"], + ["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"], + ["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", "*", "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 + 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*"], + ["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*"], + ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"], + ["sqlite3_column_int","int", "sqlite3_stmt*", "int"], + ["sqlite3_column_name","string", "sqlite3_stmt*", "int"], + ["sqlite3_column_text","string", "sqlite3_stmt*", "int"], + ["sqlite3_column_type","int", "sqlite3_stmt*", "int"], + ["sqlite3_column_value","sqlite3_value*", "sqlite3_stmt*", "int"], + ["sqlite3_compileoption_get", "string", "int"], + ["sqlite3_compileoption_used", "int", "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. */ + /* sqlite3_create_collation() and sqlite3_create_collation_v2() + use hand-written bindings to simplify passing of the callback + function. + ["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*"], + ["sqlite3_db_name", "string", "sqlite3*", "int"], + ["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"], + ["sqlite3_deserialize", "int", "sqlite3*", "string", "*", "i64", "i64", "int"] + /* Careful! Short version: de/serialize() are problematic because they + might use a different allocator than the user for managing the + deserialized block. de/serialize() are ONLY safe to use with + sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. */, + ["sqlite3_errcode", "int", "sqlite3*"], + ["sqlite3_errmsg", "string", "sqlite3*"], + ["sqlite3_error_offset", "int", "sqlite3*"], + ["sqlite3_errstr", "string", "int"], + /*["sqlite3_exec", "int", "sqlite3*", "string", "*", "*", "**" + Handled seperately to perform translation of the callback + into a WASM-usable one. ],*/ + ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"], + ["sqlite3_extended_errcode", "int", "sqlite3*"], + ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"], + ["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 + single-threaded and we don't have a portable way to access a DB + from 2 SharedWorkers concurrently. ],*/ + ["sqlite3_keyword_count", "int"], + ["sqlite3_keyword_name", "int", ["int", "**", "*"]], + ["sqlite3_keyword_check", "int", ["string", "int"]], + ["sqlite3_libversion", "string"], + ["sqlite3_libversion_number", "int"], + ["sqlite3_limit", "int", ["sqlite3*", "int", "int"]], + ["sqlite3_malloc", "*","int"], + ["sqlite3_open", "int", "string", "*"], + ["sqlite3_open_v2", "int", "string", "*", "int", "string"], + /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled + separately due to us requiring two different sets of semantics + for those, depending on how their SQL argument is provided. */ + /* sqlite3_randomness() uses a hand-written wrapper to extend + the range of supported argument types. */ + [ + "sqlite3_progress_handler", undefined, [ + "sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({ + name: 'xProgressHandler', + signature: 'i(p)', + bindMode: 'singleton' + }), "*" + ] + ], + ["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_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_context*", "*", "string:static", "*"], + ["sqlite3_result_subtype", undefined, "sqlite3_value*", "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*"], + ["sqlite3_status", "int", "int", "*", "*", "int"], + ["sqlite3_step", "int", "sqlite3_stmt*"], + ["sqlite3_stmt_isexplain", "int", ["sqlite3_stmt*"]], + ["sqlite3_stmt_readonly", "int", ["sqlite3_stmt*"]], + ["sqlite3_stmt_status", "int", "sqlite3_stmt*", "int", "int"], + ["sqlite3_strglob", "int", "string","string"], + ["sqlite3_stricmp", "int", "string", "string"], + ["sqlite3_strlike", "int", "string", "string","int"], + ["sqlite3_strnicmp", "int", "string", "string", "int"], + ["sqlite3_table_column_metadata", "int", + "sqlite3*", "string", "string", "string", + "**", "**", "*", "*", "*"], + ["sqlite3_total_changes", "int", "sqlite3*"], + ["sqlite3_trace_v2", "int", "sqlite3*", "int", "*", "*"], + ["sqlite3_txn_state", "int", ["sqlite3*","string"]], + /* Note that sqlite3_uri_...() have very specific requirements for + their first C-string arguments, so we cannot perform any value + conversion on those. */ + ["sqlite3_uri_boolean", "int", "sqlite3_filename", "string", "int"], + ["sqlite3_uri_key", "string", "sqlite3_filename", "int"], + ["sqlite3_uri_parameter", "string", "sqlite3_filename", "string"], + ["sqlite3_user_data","void*", "sqlite3_context*"], + ["sqlite3_value_blob", "*", "sqlite3_value*"], + ["sqlite3_value_bytes","int", "sqlite3_value*"], + ["sqlite3_value_double","f64", "sqlite3_value*"], + ["sqlite3_value_dup", "sqlite3_value*", "sqlite3_value*"], + ["sqlite3_value_free", undefined, "sqlite3_value*"], + ["sqlite3_value_frombind", "int", "sqlite3_value*"], + ["sqlite3_value_int","int", "sqlite3_value*"], + ["sqlite3_value_nochange", "int", "sqlite3_value*"], + ["sqlite3_value_numeric_type", "int", "sqlite3_value*"], + ["sqlite3_value_pointer", "*", "sqlite3_value*", "string:static"], + ["sqlite3_value_subtype", "int", "sqlite3_value*"], + ["sqlite3_value_text", "string", "sqlite3_value*"], + ["sqlite3_value_type", "int", "sqlite3_value*"], + ["sqlite3_vfs_find", "*", "string"], + ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"], + ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"] + ]/*wasm.bindingSignatures*/; + + if(false && wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){ + /* ^^^ "the problem" is that this is an option feature and the + build-time function-export list does not currently take + optional features into account. */ + wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]); + } + + /** + 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"]], + ["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*", "string:flexible"]], + ["sqlite3_drop_modules", "int", ["sqlite3*", "**"]], + ["sqlite3_last_insert_rowid", "i64", ["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_set_last_insert_rowid", undefined, ["sqlite3*", "i64"]], + ["sqlite3_status64", "int", "int", "*", "*", "int"], + ["sqlite3_total_changes64", "i64", ["sqlite3*"]], + ["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]], + ["sqlite3_value_int64","i64", "sqlite3_value*"], + ["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*", "**"], + ["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", "**"] + ]; + + /** + Functions which are intended solely for API-internal use by the + WASM components, not client code. These get installed into + sqlite3.wasm. Some of them get exposed to clients via variants + named sqlite3_js_...(). + */ + wasm.bindingSignatures.wasm = [ + ["sqlite3_wasm_db_reset", "int", "sqlite3*"], + ["sqlite3_wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"], + ["sqlite3_wasm_vfs_create_file", "int", + "sqlite3_vfs*","string","*", "int"], + ["sqlite3_wasm_vfs_unlink", "int", "sqlite3_vfs*","string"] + ]; + /** Install JS<->C struct bindings for the non-opaque struct types we need... */ @@ -166,7 +411,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ Sets the given db's error state. Accepts: - (sqlite3*, int code, string msg) - - (sqlite3*, Error [,string msg]) + - (sqlite3*, Error e [,string msg = ''+e]) If passed a WasmAllocError, the message is ingored and the result code is SQLITE_NOMEM. If passed any other Error type, @@ -183,7 +428,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ resultCode = capi.SQLITE_NOMEM; message = 0 /*avoid allocating message string*/; }else if(resultCode instanceof Error){ - message = message || resultCode.message; + message = message || ''+resultCode; resultCode = (resultCode.resultCode || capi.SQLITE_ERROR); } return __db_err(pDb, resultCode, message); @@ -211,15 +456,29 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ const __ccv2 = wasm.xWrap( 'sqlite3_create_collation_v2', 'int', - 'sqlite3*','string','int','*','*','*' - /* int(*xCompare)(void*,int,const void*,int,const void*) */ - /* void(*xDestroy(void*) */); + 'sqlite3*','string','int','*', + new wasm.xWrap.FuncPtrAdapter({ + /* int(*xCompare)(void*,int,const void*,int,const void*) */ + name: 'xCompare', + signature: 'i(pipip)', + bindMode: 'static' + }), + new wasm.xWrap.FuncPtrAdapter({ + /* void(*xDestroy(void*) */ + name: 'xDestroy', + signature: 'v(p)', + bindMode: 'static' + }) + ); /** Works exactly like C's sqlite3_create_collation_v2() except that: 1) It permits its two function arguments to be JS functions, - for which it will install WASM-bound proxies. + for which it will install WASM-bound proxies. The bindings + are "permanent," in that they will stay in the WASM environment + until it shuts down unless the client somehow finds and removes + them. 2) It returns capi.SQLITE_FORMAT if the 3rd argument is not capi.SQLITE_UTF8. No other encodings are supported. @@ -235,19 +494,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ pDb, capi.SQLITE_FORMAT, "SQLITE_UTF8 is the only supported encoding." ); } - let rc, pfCompare, pfDestroy; + let rc; try{ - if(xCompare instanceof Function){ - pfCompare = wasm.installFunction(xCompare, 'i(pipip)'); - } - if(xDestroy instanceof Function){ - pfDestroy = wasm.installFunction(xDestroy, 'v(p)'); - } - rc = __ccv2(pDb, zName, eTextRep, pArg, - pfCompare || xCompare, pfDestroy || xDestroy); + rc = __ccv2(pDb, zName, eTextRep, pArg, xCompare, xDestroy); }catch(e){ - if(pfCompare) wasm.uninstallFunction(pfCompare); - if(pfDestroy) wasm.uninstallFunction(pfDestroy); rc = util.sqlite3_wasm_db_error(pDb, e); } return rc; @@ -259,17 +509,20 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ : __dbArgcMismatch(pDb, 'sqlite3_create_collation', 5); } - }/*sqlite3_create_collation() and friends*/ if(1){/* Special-case handling of sqlite3_exec() */ const __exec = wasm.xWrap("sqlite3_exec", "int", - ["sqlite3*", "string:flexible", "*", "*", "**"]); + ["sqlite3*", "string:flexible", + new wasm.xWrap.FuncPtrAdapter({ + signature: 'i(pipp)', + bindMode: 'transient' + }), "*", "**"]); /* Documented in the api object's initializer. */ capi.sqlite3_exec = function f(pDb, sql, callback, pVoid, pErrMsg){ if(f.length!==arguments.length){ return __dbArgcMismatch(pDb,"sqlite3_exec",f.length); - }else if('function' !== typeof callback){ + }else if(!(callback instanceof Function)){ return __exec(pDb, sql, callback, pVoid, pErrMsg); } /* Wrap the callback in a WASM-bound function and convert the callback's @@ -294,15 +547,12 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ } return rc; }; - let pFunc, rc; + let rc; try{ - pFunc = wasm.installFunction("ipipp", cbwrap); - rc = __exec(pDb, sql, pFunc, pVoid, pErrMsg); + rc = __exec(pDb, sql, cbwrap, pVoid, pErrMsg); }catch(e){ rc = util.sqlite3_wasm_db_error(pDb, capi.SQLITE_ERROR, - "Error running exec(): "+e.message); - }finally{ - if(pFunc) wasm.uninstallFunction(pFunc); + "Error running exec(): "+e); } return rc; }; diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index 4aecf23846..e472bbdab0 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -878,250 +878,6 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( ) ? !!capi.sqlite3_compileoption_used(optName) : false; }/*compileOptionUsed()*/; - /** - Signatures for the WASM-exported C-side functions. Each entry - is an array with 2+ elements: - - [ "c-side name", - "result type" (wasm.xWrap() syntax), - [arg types in xWrap() syntax] - // ^^^ this needn't strictly be an array: it can be subsequent - // elements instead: [x,y,z] is equivalent to x,y,z - ] - - Note that support for the API-specific data types in the - result/argument type strings gets plugged in at a later phase in - the API initialization process. - */ - wasm.bindingSignatures = [ - // Please keep these sorted by function name! - ["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"], - ["sqlite3_bind_blob","int", "sqlite3_stmt*", "int", "*", "int", "*" - /* TODO: we should arguably write a custom wrapper which knows - how to handle Blob, TypedArrays, and JS strings. */ - ], - ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"], - ["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"], - ["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", "*", "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 - 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*"], - ["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*"], - ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"], - ["sqlite3_column_int","int", "sqlite3_stmt*", "int"], - ["sqlite3_column_name","string", "sqlite3_stmt*", "int"], - ["sqlite3_column_text","string", "sqlite3_stmt*", "int"], - ["sqlite3_column_type","int", "sqlite3_stmt*", "int"], - ["sqlite3_column_value","sqlite3_value*", "sqlite3_stmt*", "int"], - ["sqlite3_compileoption_get", "string", "int"], - ["sqlite3_compileoption_used", "int", "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. */ - /* sqlite3_create_collation() and sqlite3_create_collation_v2() - use hand-written bindings to simplify passing of the callback - function. - ["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*"], - ["sqlite3_db_name", "string", "sqlite3*", "int"], - ["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"], - ["sqlite3_deserialize", "int", "sqlite3*", "string", "*", "i64", "i64", "int"] - /* Careful! Short version: de/serialize() are problematic because they - might use a different allocator than the user for managing the - deserialized block. de/serialize() are ONLY safe to use with - sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. */, - ["sqlite3_errcode", "int", "sqlite3*"], - ["sqlite3_errmsg", "string", "sqlite3*"], - ["sqlite3_error_offset", "int", "sqlite3*"], - ["sqlite3_errstr", "string", "int"], - /*["sqlite3_exec", "int", "sqlite3*", "string", "*", "*", "**" - Handled seperately to perform translation of the callback - into a WASM-usable one. ],*/ - ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"], - ["sqlite3_extended_errcode", "int", "sqlite3*"], - ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"], - ["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 - single-threaded and we don't have a portable way to access a DB - from 2 SharedWorkers concurrently. ],*/ - ["sqlite3_keyword_count", "int"], - ["sqlite3_keyword_name", "int", ["int", "**", "*"]], - ["sqlite3_keyword_check", "int", ["string", "int"]], - ["sqlite3_libversion", "string"], - ["sqlite3_libversion_number", "int"], - ["sqlite3_limit", "int", ["sqlite3*", "int", "int"]], - ["sqlite3_malloc", "*","int"], - ["sqlite3_open", "int", "string", "*"], - ["sqlite3_open_v2", "int", "string", "*", "int", "string"], - /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled - separately due to us requiring two different sets of semantics - for those, depending on how their SQL argument is provided. */ - /* sqlite3_randomness() uses a hand-written wrapper to extend - the range of supported argument types. */ - //TODO: hand-written wrapper to convert function-type arg: - //void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); - // - //!TODO!: accept arg/result conversion descriptions which are objects - //following an interface and a FuncPtr impl which does that conversion. - //That would require moving these bindings int sqlite3-api-glue.js, after - //whwasmutil.js is loaded. - ["sqlite3_progress_handler", undefined, ["sqlite3*","int", "*", "*"]], - ["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_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_context*", "*", "string:static", "*"], - ["sqlite3_result_subtype", undefined, "sqlite3_value*", "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*"], - ["sqlite3_status", "int", "int", "*", "*", "int"], - ["sqlite3_step", "int", "sqlite3_stmt*"], - ["sqlite3_stmt_isexplain", "int", ["sqlite3_stmt*"]], - ["sqlite3_stmt_readonly", "int", ["sqlite3_stmt*"]], - ["sqlite3_stmt_status", "int", "sqlite3_stmt*", "int", "int"], - ["sqlite3_strglob", "int", "string","string"], - ["sqlite3_stricmp", "int", "string", "string"], - ["sqlite3_strlike", "int", "string", "string","int"], - ["sqlite3_strnicmp", "int", "string", "string", "int"], - ["sqlite3_table_column_metadata", "int", - "sqlite3*", "string", "string", "string", - "**", "**", "*", "*", "*"], - ["sqlite3_total_changes", "int", "sqlite3*"], - ["sqlite3_trace_v2", "int", "sqlite3*", "int", "*", "*"], - ["sqlite3_txn_state", "int", ["sqlite3*","string"]], - /* Note that sqlite3_uri_...() have very specific requirements for - their first C-string arguments, so we cannot perform any value - conversion on those. */ - ["sqlite3_uri_boolean", "int", "sqlite3_filename", "string", "int"], - ["sqlite3_uri_key", "string", "sqlite3_filename", "int"], - ["sqlite3_uri_parameter", "string", "sqlite3_filename", "string"], - ["sqlite3_user_data","void*", "sqlite3_context*"], - ["sqlite3_value_blob", "*", "sqlite3_value*"], - ["sqlite3_value_bytes","int", "sqlite3_value*"], - ["sqlite3_value_double","f64", "sqlite3_value*"], - ["sqlite3_value_dup", "sqlite3_value*", "sqlite3_value*"], - ["sqlite3_value_free", undefined, "sqlite3_value*"], - ["sqlite3_value_frombind", "int", "sqlite3_value*"], - ["sqlite3_value_int","int", "sqlite3_value*"], - ["sqlite3_value_nochange", "int", "sqlite3_value*"], - ["sqlite3_value_numeric_type", "int", "sqlite3_value*"], - ["sqlite3_value_pointer", "*", "sqlite3_value*", "string:static"], - ["sqlite3_value_subtype", "int", "sqlite3_value*"], - ["sqlite3_value_text", "string", "sqlite3_value*"], - ["sqlite3_value_type", "int", "sqlite3_value*"], - ["sqlite3_vfs_find", "*", "string"], - ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"], - ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"] - ]/*wasm.bindingSignatures*/; - - if(false && wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){ - /* ^^^ "the problem" is that this is an option feature and the - build-time function-export list does not currently take - optional features into account. */ - wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]); - } - - /** - 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"]], - ["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*", "string:flexible"]], - ["sqlite3_drop_modules", "int", ["sqlite3*", "**"]], - ["sqlite3_last_insert_rowid", "i64", ["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_set_last_insert_rowid", undefined, ["sqlite3*", "i64"]], - ["sqlite3_status64", "int", "int", "*", "*", "int"], - ["sqlite3_total_changes64", "i64", ["sqlite3*"]], - ["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]], - ["sqlite3_value_int64","i64", "sqlite3_value*"], - ["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*", "**"], - ["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", "**"] - ]; - - /** - Functions which are intended solely for API-internal use by the - WASM components, not client code. These get installed into - sqlite3.wasm. Some of them get exposed to clients via variants - named sqlite3_js_...(). - */ - wasm.bindingSignatures.wasm = [ - ["sqlite3_wasm_db_reset", "int", "sqlite3*"], - ["sqlite3_wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"], - ["sqlite3_wasm_vfs_create_file", "int", - "sqlite3_vfs*","string","*", "int"], - ["sqlite3_wasm_vfs_unlink", "int", "sqlite3_vfs*","string"] - ]; - /** sqlite3.wasm.pstack (pseudo-stack) holds a special-case stack-style allocator intended only for use with _small_ data of diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js index d8ac70c0b5..0885db112a 100644 --- a/ext/wasm/common/whwasmutil.js +++ b/ext/wasm/common/whwasmutil.js @@ -494,6 +494,70 @@ self.WhWasmUtilInstaller = function(target){ e: { f: func } })).exports['f']; }/*jsFuncToWasm()*/; + + /** + Documented as target.installFunction() except for the 3rd + argument: if truthy, the newly-created function pointer + is stashed in the current scoped-alloc scope and will be + cleaned up at the matching scopedAllocPop(), else it + is not stashed there. + */ + const __installFunction = function f(func, sig, scoped){ + if(scoped && !cache.scopedAlloc.length){ + toss("No scopedAllocPush() scope is active."); + } + if('string'===typeof func){ + const x = sig; + sig = func; + func = x; + } + if('string'!==typeof sig || !(func instanceof Function)){ + toss("Invalid arguments: expecting (function,signature) "+ + "or (signature,function)."); + } + const ft = target.functionTable(); + const oldLen = ft.length; + let ptr; + while(cache.freeFuncIndexes.length){ + ptr = cache.freeFuncIndexes.pop(); + if(ft.get(ptr)){ /* Table was modified via a different API */ + ptr = null; + continue; + }else{ + break; + } + } + if(!ptr){ + ptr = oldLen; + ft.grow(1); + } + try{ + /*this will only work if func is a WASM-exported function*/ + ft.set(ptr, func); + if(scoped){ + cache.scopedAlloc[cache.scopedAlloc.length-1].push(ptr); + } + return ptr; + }catch(e){ + if(!(e instanceof TypeError)){ + if(ptr===oldLen) cache.freeFuncIndexes.push(oldLen); + throw e; + } + } + // It's not a WASM-exported function, so compile one... + try { + const fptr = target.jsFuncToWasm(func, sig); + ft.set(ptr, fptr); + if(scoped){ + cache.scopedAlloc[cache.scopedAlloc.length-1].push(ptr); + } + }catch(e){ + if(ptr===oldLen) cache.freeFuncIndexes.push(oldLen); + throw e; + } + return ptr; + }; + /** Expects a JS function and signature, exactly as for @@ -526,50 +590,19 @@ self.WhWasmUtilInstaller = function(target){ https://github.com/emscripten-core/emscripten/issues/17323 */ - target.installFunction = function f(func, sig){ - if(2!==arguments.length){ - toss("installFunction() requires exactly 2 arguments"); - } - if('string'===typeof func){ - const x = sig; - sig = func; - func = x; - } - const ft = target.functionTable(); - const oldLen = ft.length; - let ptr; - while(cache.freeFuncIndexes.length){ - ptr = cache.freeFuncIndexes.pop(); - if(ft.get(ptr)){ /* Table was modified via a different API */ - ptr = null; - continue; - }else{ - break; - } - } - if(!ptr){ - ptr = oldLen; - ft.grow(1); - } - try{ - /*this will only work if func is a WASM-exported function*/ - ft.set(ptr, func); - return ptr; - }catch(e){ - if(!(e instanceof TypeError)){ - if(ptr===oldLen) cache.freeFuncIndexes.push(oldLen); - throw e; - } - } - // It's not a WASM-exported function, so compile one... - try { - ft.set(ptr, target.jsFuncToWasm(func, sig)); - }catch(e){ - if(ptr===oldLen) cache.freeFuncIndexes.push(oldLen); - throw e; - } - return ptr; - }; + target.installFunction = (func, sig)=>__installFunction(func, sig, false); + + /** + EXPERIMENTAL! DO NOT USE IN CLIENT CODE! + + Works exactly like installFunction() but requires that a + scopedAllocPush() is active and uninstalls the given function + when that alloc scope is popped via scopedAllocPop(). + This is used for implementing JS/WASM function bindings which + should only persist for the life of a call into a single + C-side function. + */ + target.scopedInstallFunction = (func, sig)=>__installFunction(func, sig, true); /** Requires a pointer value previously returned from @@ -1083,7 +1116,13 @@ self.WhWasmUtilInstaller = function(target){ if(n<0) toss("Invalid state object for scopedAllocPop()."); if(0===arguments.length) state = cache.scopedAlloc[n]; cache.scopedAlloc.splice(n,1); - for(let p; (p = state.pop()); ) target.dealloc(p); + for(let p; (p = state.pop()); ){ + if(target.functionEntry(p)){ + //console.warn("scopedAllocPop() uninstalling transient function",p); + target.uninstallFunction(p); + } + else target.dealloc(p); + } }; /** @@ -1303,12 +1342,12 @@ self.WhWasmUtilInstaller = function(target){ State for use with xWrap() */ cache.xWrap = Object.create(null); - const xcv = cache.xWrap.convert = Object.create(null); + cache.xWrap.convert = Object.create(null); /** Map of type names to argument conversion functions. */ cache.xWrap.convert.arg = new Map; /** Map of type names to return result conversion functions. */ cache.xWrap.convert.result = new Map; - const xArg = xcv.arg, xResult = xcv.result; + const xArg = cache.xWrap.convert.arg, xResult = cache.xWrap.convert.result; if(target.bigIntEnabled){ xArg.set('i64', (i)=>BigInt(i)); @@ -1395,6 +1434,87 @@ self.WhWasmUtilInstaller = function(target){ }); } + const __FuncPtrBindModes = ['transient','static','singleton']; + /** + EXPERIMENTAL. + + An attempt at adding function pointer conversion support to + xWrap(). This type is recognized by xWrap() as a proxy for + converting a JS function to a C-side function, either permanently + or only for the duration of a a single call into the C layer. + */ + xArg.FuncPtrAdapter = class { + /** + Requires an options object with these properties: + + - signature: an function signature compatible with + jsFuncToWasm(). + + - bindMode (string): one of ('transient', 'static', + 'singleton'). If 'transient', it uses + scopedInstallFunction() for its function bindings, meaning + they're limited to the lifetime of a single xWrap()-induced + function call. If it's 'static', the binding is permanent, + lasting the life of the WASM environment. If it's 'singleton' + then this function remembers the last function it installed + and uninstalls it before installing any replacements on + subsequent calls. If it's passed the exact same JS function + to install later, it will re-use the existing binding. + + - name (optional): string describing the function binding. This + is solely for debugging and error-reporting purposes. If not + provided, an empty string is assumed. + + The constructor only saves the above state for later, and does + not actually bind any functions. Its convertArg() methor is + called via xWrap() to perform any bindings. + */ + constructor(opt){ + this.signature = opt.signature; + if(__FuncPtrBindModes.indexOf(opt.bindMode)<0){ + toss("Invalid options.bindMode ("+opt.bindMod+") for FuncPtrAdapter. "+ + "Expecting one of: ("+__FuncPtrBindModes.join(', ')+')'); + } + this.bindMode = opt.bindMode; + this.name = opt.name || ''; + this.singleton = ('singleton'===this.bindMode) ? [] : undefined; + //console.warn("FuncPtrAdapter()",this.signature,this.transient); + } + /** + Gets called via xWrap() to "convert" v to a WASM-bound function + pointer. If v is one of (a pointer, null, undefined) then + (v||0) is returned, otherwise v must be a Function, for which + xit creates (if needed) a WASM function binding and returns the + WASM pointer to that binding. It throws if passed an invalid + type. + */ + convertArg(v){ + //console.warn("FuncPtrAdapter.convertArg()",this.signature,this.transient,v); + if(v instanceof Function){ + if(this.singleton && this.singleton[0]===v){ + return this.singleton[1]; + } + const fp = __installFunction(v, this.signature, 'transient'===this.bindMode); + if(this.singleton){ + if(this.singleton[1]){ + try{target.uninstallFunction(this.singleton[1])} + catch(e){/*ignored*/} + } + this.singleton[0] = v; + this.singleton[1] = fp; + } + return fp; + }else if(target.isPtr(v) || null===v || undefined===v){ + return v || 0; + }else{ + throw new TypeError("Invalid FuncPtrAdapter argument type. "+ + "Expecting "+(this.name ? this.name+' ' : '')+ + "function matching signature "+ + this.signature+"."); + } + } + }; + const __xArgAdapterCheck = (t)=>xArg.get(t) || toss("Argument adapter not found:",t); @@ -1565,7 +1685,10 @@ self.WhWasmUtilInstaller = function(target){ } /*Verify the arg type conversions are valid...*/; if(undefined!==resultType && null!==resultType) __xResultAdapterCheck(resultType); - argTypes.forEach(__xArgAdapterCheck); + for(const t of argTypes){ + if(t instanceof xArg.FuncPtrAdapter) xArg.set(t, (v)=>t.convertArg(v)); + else __xArgAdapterCheck(t); + } const cxw = cache.xWrap; if(0===xf.length){ // No args to convert, so we can create a simpler wrapper... @@ -1666,6 +1789,8 @@ self.WhWasmUtilInstaller = function(target){ 'argAdapter()', xArg); }; + target.xWrap.FuncPtrAdapter = xArg.FuncPtrAdapter; + /** Functions like xCall() but performs argument and result type conversions as for xWrap(). The first argument is the name of the diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index 7daf9e2b7b..92e8ec0521 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -1054,7 +1054,13 @@ self.sqlite3InitModule = sqlite3InitModule; .assert(ex.message.indexOf("Invalid SQL")>0); T.assert(db === db.checkRc(0)) .assert(db === sqlite3.oo1.DB.checkRc(db,0)) - .assert(null === sqlite3.oo1.DB.checkRc(null,0)) + .assert(null === sqlite3.oo1.DB.checkRc(null,0)); + + this.progressHandlerCount = 0; + capi.sqlite3_progress_handler(db, 5, (p)=>{ + ++this.progressHandlerCount; + return 0; + }, 0); }) //////////////////////////////////////////////////////////////////// .t('sqlite3_db_config() and sqlite3_db_status()', function(sqlite3){ @@ -1107,6 +1113,7 @@ self.sqlite3InitModule = sqlite3InitModule; new TextEncoder('utf-8').encode("select 3 as a") ); //debug("statement =",st); + this.progressHandlerCount = 0; try { T.assert(wasm.isPtr(st.pointer)) .mustThrowMatching(()=>st.pointer=1, /read-only/) @@ -1145,7 +1152,9 @@ self.sqlite3InitModule = sqlite3InitModule; st, capi.SQLITE_STMTSTATUS_RUN, 0 ) > 0); - T.assert(0===capi.sqlite3_strglob("*.txt", "foo.txt")). + T.assert(this.progressHandlerCount > 0, + "Expecting progress callback."). + assert(0===capi.sqlite3_strglob("*.txt", "foo.txt")). assert(0!==capi.sqlite3_strglob("*.txt", "foo.xtx")). assert(0===capi.sqlite3_strlike("%.txt", "foo.txt", 0)). assert(0!==capi.sqlite3_strlike("%.txt", "foo.xtx", 0)); @@ -1207,6 +1216,7 @@ self.sqlite3InitModule = sqlite3InitModule; .t('Table t', function(sqlite3){ const db = this.db; let list = []; + this.progressHandlerCount = 0; let rc = db.exec({ sql:['CREATE TABLE t(a,b);', // ^^^ using TEMP TABLE breaks the db export test @@ -1220,7 +1230,9 @@ self.sqlite3InitModule = sqlite3InitModule; T.assert(rc === db) .assert(2 === list.length) .assert('string'===typeof list[1]) - .assert(4===db.changes()); + .assert(4===db.changes()) + .assert(this.progressHandlerCount > 0, + "Expecting progress callback.") if(wasm.bigIntEnabled){ T.assert(4n===db.changes(false,true)); } @@ -1643,6 +1655,7 @@ self.sqlite3InitModule = sqlite3InitModule; T.assert(2===db.selectValue('select a from foo.bar where a>1 order by a')); let colCount = 0, rowCount = 0; const execCallback = function(pVoid, nCols, aVals, aNames){ + //console.warn("execCallback(",arguments,")"); colCount = nCols; ++rowCount; T.assert(2===aVals.length) diff --git a/manifest b/manifest index 640e47605d..fb68b35513 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C ext/wasm/module-symbols.html:\sfor\sC\sAPIs\swhich\shave\sextended\sJS-side\ssemantics,\slink\sto\sthe\sJS-side\sAPI\sdocs\sinstead\sof\sthe\sC\sdocs. -D 2022-12-12T11:38:22.370 +C Move\sJS-to-C\sbinding\ssignatures\sfrom\ssqlite3-api-prologue.js\sto\ssqlite3-api-glue.js\sto\sallow\sfor\suse\sof\sthe\snew/experimental\ssqlite3.wasm.xWrap()\sfeature\swhich\sautomatically\sbinds\sJS\sfunctions\sto\sWASM/C\sas\sneeded,\swhich\ssimplifies\screation\sof\sbindings\swhich\stake\sC\sfunction\spointers.\sReimplement\ssqlite3_exec(),\ssqlite3_create_collation(),\ssqlite3_progress_handler()\sto\suse\sthis\snew\sfeature. +D 2022-12-12T14:31:38.581 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 1d1c0542392a17e1ab9dc652c00091afefe8489108bb8da899b68eab50c3f813 +F ext/wasm/api/sqlite3-api-glue.js 5c3854480b600195edd7a9c98a9ea4f07f59cc6abe7ab2f19d30cdaa62f24b78 F ext/wasm/api/sqlite3-api-oo1.js 6d10849609231ccd46fa11b1d3fbbe0f45d9fe84c66a0b054601036540844300 -F ext/wasm/api/sqlite3-api-prologue.js 979a469f329636e7345a1a720b0be6e93c7585231387ebdef2b4493ff9a2bf74 +F ext/wasm/api/sqlite3-api-prologue.js 39fbca8f25219c218d631433828ede53be8d518aa9f0da480758a3ea8abc1be8 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 7795b84b66a7a8dedc791340709b310bb497c3c72a80bef364fa2a58e2ddae3f @@ -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 399918a67a22cab80f3a3f4f1c39eb2f83226953ed19579f2761157532a5c036 +F ext/wasm/common/whwasmutil.js 60531749126c3d505521b9e9a0adb468951e3a201ca65fdc8a37d20a6c1194e0 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 49bee1aafa597ab1ac518a0d7cbe93b734867d6f48371b87a3346709de0069c2 +F ext/wasm/tester1.c-pp.js 6f7fcaeedff2c94fd9ebfd37a665cc7797524868b70fce2854ecab60b3d74274 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 01d3a9bba3120cfec3f752048281f18ce7ab48fa7584750c097233a9ce095a20 -R 919e96e26165900597588955a230bf5e +P d557015208f504c6d5d20ebf1e451b3f07b19590d76371b16a9f4b54e9645282 +R 5a61f05e144f2d7b8121b7e697a724d0 U stephan -Z db12a0f20be16fdb93fc89d67734b367 +Z 82382106256d8062d011dc4fe2d4d001 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 2e83ad06e2..de9a05d4f3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d557015208f504c6d5d20ebf1e451b3f07b19590d76371b16a9f4b54e9645282 \ No newline at end of file +9386d6f634680b4e0fa5487c34c63acb29f0b7a6ae738b8f6164ad084a229b62 \ No newline at end of file