]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Internal cleanups and minor speed optimizations in the sqlite3.wasm.xWrap() infrastru...
authorstephan <stephan@noemail.net>
Fri, 23 Dec 2022 18:14:36 +0000 (18:14 +0000)
committerstephan <stephan@noemail.net>
Fri, 23 Dec 2022 18:14:36 +0000 (18:14 +0000)
FossilOrigin-Name: c4dab53b8ea3401abd57671b8f3cb39fa4431b864d4c4e14ae24592f8d4cba0a

ext/wasm/common/whwasmutil.js
ext/wasm/tester1.c-pp.js
manifest
manifest.uuid

index c99e36041b007fbc14f5297b650cb17f8b26fc38..4b1026e4cd36ffda9117e611e2874415e2301713 100644 (file)
@@ -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||[]);
   };
 
   /**
index bef34a0ba54a7ec93fd41cdb226c89ae08010e73..eb014d7b51a0755c6eb20873ddb67c38ed47daad 100644 (file)
@@ -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*/
 
index eacaf992fbfa63ab1ab2aec95c384c21e8651c66..a0be8ba9e60def18cd5a2c479865cbcd887ba550 100644 (file)
--- 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.
index aa150a668bc6dd36a2b54044b89e2f539813a902..8d218fa6eda1bd6fde81b1a54782685c3455feaa 100644 (file)
@@ -1 +1 @@
-0a39172ee134816f5ce17a403b960e9c22bb56efd5bcf77ecde465efe0d88b1d
\ No newline at end of file
+c4dab53b8ea3401abd57671b8f3cb39fa4431b864d4c4e14ae24592f8d4cba0a
\ No newline at end of file