aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstephan <stephan@noemail.net>2022-12-23 18:14:36 +0000
committerstephan <stephan@noemail.net>2022-12-23 18:14:36 +0000
commitb5915699d0404bcd3b502e18af3d889d0bf581dc (patch)
treef63587528651df8df3f430207766331bddfee608
parent0f29f17bf6ea1044d4daa7bbc00283a026a1c514 (diff)
downloadsqlite-b5915699d0404bcd3b502e18af3d889d0bf581dc.tar.gz
sqlite-b5915699d0404bcd3b502e18af3d889d0bf581dc.zip
Internal cleanups and minor speed optimizations in the sqlite3.wasm.xWrap() infrastructure.
FossilOrigin-Name: c4dab53b8ea3401abd57671b8f3cb39fa4431b864d4c4e14ae24592f8d4cba0a
-rw-r--r--ext/wasm/common/whwasmutil.js203
-rw-r--r--ext/wasm/tester1.c-pp.js64
-rw-r--r--manifest14
-rw-r--r--manifest.uuid2
4 files changed, 181 insertions, 102 deletions
diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js
index c99e36041..4b1026e4c 100644
--- a/ext/wasm/common/whwasmutil.js
+++ b/ext/wasm/common/whwasmutil.js
@@ -359,7 +359,8 @@ self.WhWasmUtilInstaller = function(target){
/**
Given a function pointer, returns the WASM function table entry
- if found, else returns a falsy value.
+ if found, else returns a falsy value: undefined if fptr is out of
+ range or null if it's in range but the table entry is empty.
*/
target.functionEntry = function(fptr){
const ft = target.functionTable();
@@ -552,13 +553,12 @@ self.WhWasmUtilInstaller = function(target){
cache.scopedAlloc[cache.scopedAlloc.length-1].push(ptr);
}
}catch(e){
- if(ptr===oldLen) cache.freeFuncIndexes.push(oldLen);
- throw e;
+ if(ptr===oldLen) cache.freeFuncIndexes.push(oldLen);
+ throw e;
}
- return ptr;
+ return ptr;
};
-
/**
Expects a JS function and signature, exactly as for
this.jsFuncToWasm(). It uses that function to create a
@@ -612,8 +612,13 @@ self.WhWasmUtilInstaller = function(target){
installFunction() has been called and results are undefined if
ptr was not returned by that function. The returned function
may be passed back to installFunction() to reinstall it.
+
+ To simplify certain use cases, if passed a falsy non-0 value
+ (noting that 0 is a valid function table index), this function
+ has no side effects and returns undefined.
*/
target.uninstallFunction = function(ptr){
+ if(!ptr && 0!==ptr) return undefined;
const fi = cache.freeFuncIndexes;
const ft = target.functionTable();
fi.push(ptr);
@@ -730,7 +735,7 @@ self.WhWasmUtilInstaller = function(target){
? cache : heapWrappers();
for(const p of (Array.isArray(ptr) ? ptr : [ptr])){
switch (type) {
- case 'i1':
+ case 'i1':
case 'i8': c.HEAP8[p>>0] = value; continue;
case 'i16': c.HEAP16[p>>1] = value; continue;
case 'i32': c.HEAP32[p>>2] = value; continue;
@@ -803,7 +808,6 @@ self.WhWasmUtilInstaller = function(target){
/** f64 variant of poke8(). */
target.poke64f = (ptr, value)=>target.poke(ptr, value, 'f64');
-
/** Deprecated alias for getMemValue() */
target.getMemValue = target.peek;
/** Deprecated alias for peekPtr() */
@@ -1351,7 +1355,7 @@ self.WhWasmUtilInstaller = function(target){
const __argcMismatch =
(f,n)=>toss(f+"() requires",n,"argument(s).");
-
+
/**
Looks up a WASM-exported function named fname from
target.exports. If found, it is called, passed all remaining
@@ -1390,18 +1394,25 @@ self.WhWasmUtilInstaller = function(target){
if(target.bigIntEnabled){
xArg.set('i64', (i)=>BigInt(i));
}
- xArg.set('i32', (i)=>(i | 0));
- xArg.set('i16', (i)=>((i | 0) & 0xFFFF));
- xArg.set('i8', (i)=>((i | 0) & 0xFF));
- xArg.set('f32', (i)=>Number(i).valueOf());
- xArg.set('float', xArg.get('f32'));
- xArg.set('f64', xArg.get('f32'));
- xArg.set('double', xArg.get('f64'));
- xArg.set('int', xArg.get('i32'));
- xResult.set('*', xArg.get(ptrIR));
- xResult.set('pointer', xArg.get(ptrIR));
- xArg.set('**', xArg.get(ptrIR));
- xResult.set('number', (v)=>Number(v));
+ const __xArgPtr = 'i32' === ptrIR
+ ? ((i)=>(i | 0)) : ((i)=>(BigInt(i) | BigInt(0)));
+ xArg.set('i32', __xArgPtr )
+ .set('i16', (i)=>((i | 0) & 0xFFFF))
+ .set('i8', (i)=>((i | 0) & 0xFF))
+ .set('f32', (i)=>Number(i).valueOf())
+ .set('float', xArg.get('f32'))
+ .set('f64', xArg.get('f32'))
+ .set('double', xArg.get('f64'))
+ .set('int', xArg.get('i32'))
+ .set('null', (i)=>i)
+ .set(null, xArg.get('null'))
+ .set('**', __xArgPtr);
+ xResult.set('*', __xArgPtr)
+ .set('pointer', __xArgPtr)
+ .set('number', (v)=>Number(v))
+ .set('void', (v)=>undefined)
+ .set('null', (v)=>v)
+ .set(null, xResult.get('null'));
{ /* Copy certain xArg[...] handlers to xResult[...] and
add pointer-style variants of them. */
@@ -1430,15 +1441,17 @@ self.WhWasmUtilInstaller = function(target){
TODO? Permit an Int8Array/Uint8Array and convert it to a string?
Would that be too much magic concentrated in one place, ready to
- backfire?
+ backfire? We handle that at the client level in sqlite3 with a
+ custom argument converter.
*/
- xArg.set('string', function(v){
+ const __xArgString = function(v){
if('string'===typeof v) return target.scopedAllocCString(v);
- return v ? xArg.get(ptrIR)(v) : null;
- });
- xArg.set('utf8', xArg.get('string'));
- xArg.set('pointer', xArg.get('string'));
- xArg.set('*', xArg.get('string'));
+ return v ? __xArgPtr(v) : null;
+ };
+ xArg.set('string', __xArgString);
+ xArg.set('utf8', __xArgString);
+ xArg.set('pointer', __xArgString);
+ xArg.set('*', __xArgString);
xResult.set('string', (i)=>target.cstrToJs(i));
xResult.set('utf8', xResult.get('string'));
@@ -1452,25 +1465,6 @@ self.WhWasmUtilInstaller = function(target){
try{ return i ? JSON.parse(target.cstrToJs(i)) : null }
finally{ target.dealloc(i) }
});
- xResult.set('void', (v)=>undefined);
- xResult.set('null', (v)=>v);
-
- if(0){
- /***
- This idea can't currently work because we don't know the
- signature for the func and don't have a way for the user to
- convey it. To do this we likely need to be able to match
- arg/result handlers by a regex, but that would incur an O(N)
- cost as we check the regex one at a time. Another use case for
- such a thing would be pseudotypes like "int:-1" to say that
- the value will always be treated like -1 (which has a useful
- case in the sqlite3 bindings).
- */
- xArg.set('func-ptr', function(v){
- if(!(v instanceof Function)) return xArg.get(ptrIR);
- const f = target.jsFuncToWasm(v, WHAT_SIGNATURE);
- });
- }
/**
Internal-use-only base class for FuncPtrAdapter and potentially
@@ -1537,8 +1531,8 @@ self.WhWasmUtilInstaller = function(target){
value. This is only useful for use with "global" functions
which do not rely on any state other than this function
pointer. If the being-converted function pointer is intended
- to be mapped to some sort of state object (e.g. an sqlite3*)
- then "context" (see below) is the proper mode.
+ to be mapped to some sort of state object (e.g. an
+ `sqlite3*`) then "context" (see below) is the proper mode.
- 'context': similar to singleton mode but for a given
"context", where the context is a key provided by the user
@@ -1698,35 +1692,41 @@ self.WhWasmUtilInstaller = function(target){
(t)=>xResult.get(t) || toss("Result adapter not found:",t);
cache.xWrap.convertArg = (t,...args)=>__xArgAdapterCheck(t)(...args);
+ cache.xWrap.convertArgNoCheck = (t,...args)=>xArg.get(t)(...args);
+
cache.xWrap.convertResult =
(t,v)=>(null===t ? v : (t ? __xResultAdapterCheck(t)(v) : undefined));
+ cache.xWrap.convertResultNoCheck =
+ (t,v)=>(null===t ? v : (t ? xResult.get(t)(v) : undefined));
/**
- Creates a wrapper for the WASM-exported function fname. Uses
- xGet() to fetch the exported function (which throws on
- error) and returns either that function or a wrapper for that
- function which converts the JS-side argument types into WASM-side
- types and converts the result type. If the function takes no
- arguments and resultType is `null` then the function is returned
- as-is, else a wrapper is created for it to adapt its arguments
- and result value, as described below.
+ Creates a wrapper for another function which converts the arguments
+ of the wrapper to argument types accepted by the wrapped function,
+ then converts the wrapped function's result to another form
+ for the wrapper.
- (If you're familiar with Emscripten's ccall() and cwrap(), this
- function is essentially cwrap() on steroids.)
+ The first argument must be one of:
- This function's arguments are:
+ - A JavaScript function.
+ - The name of a WASM-exported function. In the latter case xGet()
+ is used to fetch the exported function, which throws if it's not
+ found.
+ - A pointer into the indirect function table. e.g. a pointer
+ returned from target.installFunction().
- - fname: the exported function's name. xGet() is used to fetch
- this, so will throw if no exported function is found with that
- name.
-
- - resultType: the name of the result type. A literal `null` means
- to return the original function's value as-is (mnemonic: there
- is "null" conversion going on). Literal `undefined` or the
- string `"void"` mean to ignore the function's result and return
- `undefined`. Aside from those two special cases, it may be one
- of the values described below or any mapping installed by the
- client using xWrap.resultAdapter().
+ It returns either the passed-in function or a wrapper for that
+ function which converts the JS-side argument types into WASM-side
+ types and converts the result type.
+
+ The second argument, `resultType`, describes the conversion for
+ the wrapped functions result. A literal `null` or the string
+ `'null'` both mean to return the original function's value as-is
+ (mnemonic: there is "null" conversion going on). Literal
+ `undefined` or the string `"void"` both mean to ignore the
+ function's result and return `undefined`. Aside from those two
+ special cases, the `resultType` value may be one of the values
+ described below or any mapping installed by the client using
+ xWrap.resultAdapter().
If passed 3 arguments and the final one is an array, that array
must contain a list of type names (see below) for adapting the
@@ -1740,6 +1740,12 @@ self.WhWasmUtilInstaller = function(target){
xWrap('funcname', 'i32', ['string', 'f64']);
```
+ This function enforces that the given list of arguments has the
+ same arity as the being-wrapped function (as defined by its
+ `length` property) and it will throw if that is not the case.
+ Similarly, the created wrapper will throw if passed a differing
+ argument count.
+
Type names are symbolic names which map the arguments to an
adapter function to convert, if needed, the value before passing
it on to WASM or to convert a return result from WASM. The list
@@ -1776,6 +1782,10 @@ self.WhWasmUtilInstaller = function(target){
Non-numeric conversions include:
+ - `null` literal or `"null"` string (args and results): perform
+ no translation and pass the arg on as-is. This is primarily
+ useful for results but may have a use or two for arguments.
+
- `string` or `utf8` (args): has two different semantics in order
to accommodate various uses of certain C APIs
(e.g. output-style strings)...
@@ -1790,9 +1800,9 @@ self.WhWasmUtilInstaller = function(target){
client has already allocated and it's passed on as
a WASM pointer.
- - `string` or `utf8` (results): treats the result value as a
- const C-string, encoded as UTF-8, copies it to a JS string,
- and returns that JS string.
+ - `string` or `utf8` (results): treats the result value as a
+ const C-string, encoded as UTF-8, copies it to a JS string,
+ and returns that JS string.
- `string:dealloc` or `utf8:dealloc) (results): treats the result value
as a non-const UTF-8 C-string, ownership of which has just been
@@ -1829,6 +1839,11 @@ self.WhWasmUtilInstaller = function(target){
type conversions are valid for both arguments _and_ result types
as they often have different memory ownership requirements.
+ Design note: the ability to pass in a JS function as the first
+ argument is of relatively limited use, primarily for testing
+ argument and result converters. JS functions, by and large, will
+ not want to deal with C-type arguments.
+
TODOs:
- Figure out how/whether we can (semi-)transparently handle
@@ -1849,14 +1864,21 @@ self.WhWasmUtilInstaller = function(target){
abstracting it into this API (and taking on the associated
costs) may well not make good sense.
*/
- target.xWrap = function(fname, resultType, ...argTypes){
+ target.xWrap = function(fArg, resultType, ...argTypes){
if(3===arguments.length && Array.isArray(arguments[2])){
argTypes = arguments[2];
}
- const xf = target.xGet(fname);
- if(argTypes.length!==xf.length) __argcMismatch(fname, xf.length);
+ if(target.isPtr(fArg)){
+ fArg = target.functionEntry(fArg)
+ || toss("Function pointer not found in WASM function table.");
+ }
+ const fIsFunc = (fArg instanceof Function);
+ const xf = fIsFunc ? fArg : target.xGet(fArg);
+ if(fIsFunc) fArg = xf.name || 'unnamed function';
+ if(argTypes.length!==xf.length) __argcMismatch(fArg, xf.length);
if((null===resultType) && 0===xf.length){
- /* Func taking no args with an as-is return. We don't need a wrapper. */
+ /* Func taking no args with an as-is return. We don't need a wrapper.
+ We forego the argc check here, though. */
return xf;
}
/*Verify the arg type conversions are valid...*/;
@@ -1869,11 +1891,11 @@ self.WhWasmUtilInstaller = function(target){
if(0===xf.length){
// No args to convert, so we can create a simpler wrapper...
return (...args)=>(args.length
- ? __argcMismatch(fname, xf.length)
+ ? __argcMismatch(fArg, xf.length)
: cxw.convertResult(resultType, xf.call(null)));
}
return function(...args){
- if(args.length!==xf.length) __argcMismatch(fname, xf.length);
+ if(args.length!==xf.length) __argcMismatch(fArg, xf.length);
const scope = target.scopedAllocPush();
try{
/*
@@ -1891,8 +1913,8 @@ self.WhWasmUtilInstaller = function(target){
and what those arguments are, is _not_ part of the public
interface and is _not_ stable.
*/
- for(const i in args) args[i] = cxw.convertArg(argTypes[i], args[i], i, args);
- return cxw.convertResult(resultType, xf.apply(null,args));
+ for(const i in args) args[i] = cxw.convertArgNoCheck(argTypes[i], args[i], i, args);
+ return cxw.convertResultNoCheck(resultType, xf.apply(null,args));
}finally{
target.scopedAllocPop(scope);
}
@@ -1984,14 +2006,13 @@ self.WhWasmUtilInstaller = function(target){
/**
Functions like xCall() but performs argument and result type
- conversions as for xWrap(). The first argument is the name of the
- exported function to call. The 2nd its the name of its result
- type, as documented for xWrap(). The 3rd is an array of argument
- type name, as documented for xWrap() (use a falsy value or an
- empty array for nullary functions). The 4th+ arguments are
- arguments for the call, with the special case that if the 4th
- argument is an array, it is used as the arguments for the
- call. Returns the converted result of the call.
+ conversions as for xWrap(). The first, second, and third
+ arguments are as documented for xWrap(), except that the 3rd
+ argument may be either a falsy value or empty array to represent
+ nullary functions. The 4th+ arguments are arguments for the call,
+ with the special case that if the 4th argument is an array, it is
+ used as the arguments for the call. Returns the converted result
+ of the call.
This is just a thin wrapper around xWrap(). If the given function
is to be called more than once, it's more efficient to use
@@ -2000,9 +2021,9 @@ self.WhWasmUtilInstaller = function(target){
arguably more efficient because it will hypothetically free the
wrapper function quickly.
*/
- target.xCallWrapped = function(fname, resultType, argTypes, ...args){
+ target.xCallWrapped = function(fArg, resultType, argTypes, ...args){
if(Array.isArray(arguments[3])) args = arguments[3];
- return target.xWrap(fname, resultType, argTypes||[]).apply(null, args||[]);
+ return target.xWrap(fArg, resultType, argTypes||[]).apply(null, args||[]);
};
/**
diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js
index bef34a0ba..eb014d7b5 100644
--- a/ext/wasm/tester1.c-pp.js
+++ b/ext/wasm/tester1.c-pp.js
@@ -539,7 +539,7 @@ self.sqlite3InitModule = sqlite3InitModule;
}
w.dealloc(m);
}
-
+
// isPtr32()
{
const ip = w.isPtr32;
@@ -743,6 +743,65 @@ self.sqlite3InitModule = sqlite3InitModule;
.assert('HI' === cj(new Uint8Array([72, 73])));
});
+ // jsFuncToWasm()
+ {
+ const fsum3 = (x,y,z)=>x+y+z;
+ fw = w.jsFuncToWasm('i(iii)', fsum3);
+ T.assert(fw instanceof Function)
+ .assert( fsum3 !== fw )
+ .assert( 3 === fw.length )
+ .assert( 6 === fw(1,2,3) );
+ T.mustThrowMatching( ()=>w.jsFuncToWasm('x()', function(){}),
+ 'Invalid signature letter: x');
+ }
+
+ // xWrap(Function,...)
+ {
+ let fp;
+ try {
+ const fmy = function fmy(i,s,d){
+ if(fmy.debug) log("fmy(",...arguments,")");
+ T.assert( 3 === i )
+ .assert( w.isPtr(s) )
+ .assert( w.cstrToJs(s) === 'a string' )
+ .assert( T.eqApprox(1.2, d) );
+ return w.allocCString("hi");
+ };
+ fmy.debug = false;
+ const xwArgs = ['string:dealloc', ['i32', 'string', 'f64']];
+ fw = w.xWrap(fmy, ...xwArgs);
+ const fmyArgs = [3, 'a string', 1.2];
+ let rc = fw(...fmyArgs);
+ T.assert( 'hi' === rc );
+ if(0){
+ /* Retain this as a "reminder to self"...
+
+ This extra level of indirection does not work: the
+ string argument is ending up as a null in fmy() but
+ the numeric arguments are making their ways through
+
+ What's happening is: installFunction() is creating a
+ WASM-compatible function instance. When we pass a JS string
+ into there it's getting coerced into `null` before being passed
+ on to the lower-level wrapper.
+ */
+ fmy.debug = true;
+ fp = wasm.installFunction('i(isd)', fw);
+ fw = w.functionEntry(fp);
+ rc = fw(...fmyArgs);
+ log("rc =",rc);
+ T.assert( 'hi' === rc );
+ // Similarly, this does not work:
+ //let fpw = w.xWrap(fp, null, [null,null,null]);
+ //rc = fpw(...fmyArgs);
+ //log("rc =",rc);
+ //T.assert( 'hi' === rc );
+ }
+ }finally{
+ wasm.uninstallFunction(fp);
+ }
+ }
+
if(haveWasmCTests()){
if(!sqlite3.config.useStdAlloc){
fw = w.xWrap('sqlite3_wasm_test_str_hello', 'utf8:dealloc',['i32']);
@@ -768,7 +827,7 @@ self.sqlite3InitModule = sqlite3InitModule;
});
}
}
- }
+ }/*xWrap()*/
}/*WhWasmUtil*/)
////////////////////////////////////////////////////////////////////
@@ -997,7 +1056,6 @@ self.sqlite3InitModule = sqlite3InitModule;
P.restore(stack);
}
}/*pstack tests*/)
-
////////////////////////////////////////////////////////////////////
;/*end of C/WASM utils checks*/
diff --git a/manifest b/manifest
index eacaf992f..a0be8ba9e 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\ssqlite3.capi\sJS\sbindings\sfor\sthe\ssqlite3session_...(),\ssqlite3changeset_...()\sand\ssqlite3changegroup_...()\sAPIs,\snoting\sthat\sthey\sare\scompletely\suntested.\sAside\sfrom\smissing\stests,\sthese\sbindings\sreveal\sa\sslight\sstring-argument-type\sshortcoming\sin\sthe\scallback\sfunction\spointer\s"reverse\sbinding"\swhich\sshould\sideally\sbe\sresolved\sbefore\spublishing\sthem.
-D 2022-12-23T14:11:54.508
+C Internal\scleanups\sand\sminor\sspeed\soptimizations\sin\sthe\ssqlite3.wasm.xWrap()\sinfrastructure.
+D 2022-12-23T18:14:36.766
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 af85d9a09fa79847d08279be0f61978ecc3bed893c88003f4a85d8bd204e6b5a
+F ext/wasm/common/whwasmutil.js ccfd4addd60f0c3f02ee1669c4e5c8935ca770ed7b737ea3e9e82cc6505576c8
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 f09266873e1a34d9bdb6d3981ec8c9e382f31f215c9fd2f9016d2394b8ae9b7b
F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9
F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406
-F ext/wasm/tester1.c-pp.js c45c46cdae1949d426ee12a736087ab180beacc2a20cd829f9052b957adf9ac9
+F ext/wasm/tester1.c-pp.js 4202e7ec525445386f29612ddf1365348edd1f6002b8b21721c954b9569b756a
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 cd8c100808da1043fcf63555f48f30c90272c48c6627321ceb0a0995b34733d1
-R 042a575edf17a004d3f3655705629da7
+P 0a39172ee134816f5ce17a403b960e9c22bb56efd5bcf77ecde465efe0d88b1d
+R 01a5a3416aa00dbf975dac1dad0558b8
U stephan
-Z 81bf3460fe50c1e6a01aac07ed8bed30
+Z fd750e2a8255c013dd9faba040bbeb23
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index aa150a668..8d218fa6e 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-0a39172ee134816f5ce17a403b960e9c22bb56efd5bcf77ecde465efe0d88b1d \ No newline at end of file
+c4dab53b8ea3401abd57671b8f3cb39fa4431b864d4c4e14ae24592f8d4cba0a \ No newline at end of file