aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstephan <stephan@noemail.net>2022-10-02 03:11:13 +0000
committerstephan <stephan@noemail.net>2022-10-02 03:11:13 +0000
commit63e9ec2f9c7042fc8fb3f858144ee9ebe5408f69 (patch)
tree1e85e4eef656f867b1a220388cf0563f715223ac
parent6479c5a359e932a76225a903f1a6655cda8c277d (diff)
downloadsqlite-63e9ec2f9c7042fc8fb3f858144ee9ebe5408f69.tar.gz
sqlite-63e9ec2f9c7042fc8fb3f858144ee9ebe5408f69.zip
More fleshing out of sqlite3.capi.wasm.pstack.
FossilOrigin-Name: eb5726677a727a958df11f1fba078d30c7c0ba2a9bdb158e8641b35b5f971af3
-rw-r--r--ext/wasm/api/sqlite3-api-glue.js59
-rw-r--r--ext/wasm/api/sqlite3-api-oo1.js88
-rw-r--r--ext/wasm/api/sqlite3-api-prologue.js22
-rw-r--r--ext/wasm/api/sqlite3-wasm.c12
-rw-r--r--ext/wasm/common/whwasmutil.js45
-rw-r--r--ext/wasm/testing1.js41
-rw-r--r--manifest22
-rw-r--r--manifest.uuid2
8 files changed, 205 insertions, 86 deletions
diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js
index ab9424aca..b6ec1695e 100644
--- a/ext/wasm/api/sqlite3-api-glue.js
+++ b/ext/wasm/api/sqlite3-api-glue.js
@@ -55,10 +55,11 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
if(1){// WhWasmUtil.xWrap() bindings...
/**
- Add some descriptive xWrap() aliases for '*' intended to
- (A) initially improve readability/correctness of capi.signatures
- and (B) eventually perhaps provide some sort of type-safety
- in their conversions.
+ Add some descriptive xWrap() aliases for '*' intended to (A)
+ initially improve readability/correctness of capi.signatures
+ and (B) eventually perhaps provide automatic conversion from
+ higher-level representations, e.g. capi.sqlite3_vfs to
+ `sqlite3_vfs*` via capi.sqlite3_vfs.pointer.
*/
const aPtr = wasm.xWrap.argAdapter('*');
wasm.xWrap.argAdapter('sqlite3*', aPtr)('sqlite3_stmt*', aPtr);
@@ -248,6 +249,56 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
};
}/*sqlite3_prepare_v2/v3()*/;
+ if(1){// Extend wasm.pstack, now that the wasm utils are installed
+ /**
+ Allocates n chunks, each sz bytes, as a single memory block and
+ returns the addresses as an array of n element, each holding
+ the address of one chunk.
+
+ Throws a WasmAllocError if allocation fails.
+
+ Example:
+
+ ```
+ const [p1, p2, p3] = wasm.pstack.allocChunks(3,4);
+ ```
+ */
+ wasm.pstack.allocChunks = (n,sz)=>{
+ const mem = wasm.pstack.alloc(n * sz);
+ const rc = [];
+ let i = 0, offset = 0;
+ for(; i < n; offset = (sz * ++i)){
+ rc.push(mem + offset);
+ }
+ return rc;
+ };
+
+ /**
+ A convenience wrapper for allocChunks() which sizes each chunks
+ as either 8 bytes (safePtrSize is truthy) or wasm.ptrSizeof (if
+ safePtrSize is truthy).
+
+ How it returns its result differs depending on its first
+ argument: if it's 1, it returns a single pointer value. If it's
+ more than 1, it returns the same as allocChunks().
+
+ When one of the pointers refers to a 64-bit value, e.g. a
+ double or int64, and that value must be written or fetch,
+ e.g. using wasm.setMemValue() or wasm.getMemValue(), it is
+ important that the pointer in question be aligned to an 8-byte
+ boundary or else it will not be fetched or written properly and
+ will corrupt or read neighboring memory.
+
+ However, when all pointers involved are "small", it is safe to
+ pass a falsy value to save to memory.
+ */
+ wasm.pstack.allocPtr = (n=1,safePtrSize=true) =>{
+ return 1===n
+ ? wasm.pstack.alloc(safePtrSize ? 8 : wasm.ptrSizeof)
+ : wasm.pstack.allocChunks(n, safePtrSize ? 8 : wasm.ptrSizeof);
+ };
+ }/*wasm.pstack filler*/
+
/**
Install JS<->C struct bindings for the non-opaque struct types we
need... */
diff --git a/ext/wasm/api/sqlite3-api-oo1.js b/ext/wasm/api/sqlite3-api-oo1.js
index 627af2e8a..07f0657fa 100644
--- a/ext/wasm/api/sqlite3-api-oo1.js
+++ b/ext/wasm/api/sqlite3-api-oo1.js
@@ -18,7 +18,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const toss = (...args)=>{throw new Error(args.join(' '))};
const toss3 = (...args)=>{throw new sqlite3.SQLite3Error(...args)};
- const capi = sqlite3.capi, util = capi.util;
+ const capi = sqlite3.capi, wasm = capi.wasm, util = capi.util;
/* What follows is colloquially known as "OO API #1". It is a
binding of the sqlite3 API which is designed to be run within
the same thread (main or worker) as the one in which the
@@ -33,7 +33,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
accessor and store their real values in this map. Keys = DB/Stmt
objects, values = pointer values. This also unifies how those are
accessed, for potential use downstream via custom
- capi.wasm.xWrap() function signatures which know how to extract
+ wasm.xWrap() function signatures which know how to extract
it.
*/
const __ptrMap = new WeakMap();
@@ -72,7 +72,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
being-construct DB object as its "this". See the DB constructor
for the argument docs. This is split into a separate function
in order to enable simple creation of special-case DB constructors,
- e.g. a hypothetical LocalStorageDB or OpfsDB.
+ e.g. JsStorageDB and OpfsDB.
Expects to be passed a configuration object with the following
properties:
@@ -123,7 +123,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) ? capi.wasm.cstringToJs(fn) : fn;
+ let fnJs = ('number'===typeof fn) ? wasm.cstringToJs(fn) : fn;
const vfsCheck = ctor._name2vfs[fnJs];
if(vfsCheck){
vfsName = vfsCheck.vfs;
@@ -136,20 +136,20 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
if( flagsStr.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
oflags |= capi.SQLITE_OPEN_EXRESCODE;
- const stack = capi.wasm.scopedAllocPush();
+ const scope = wasm.scopedAllocPush();
try {
- const ppDb = capi.wasm.scopedAllocPtr() /* output (sqlite3**) arg */;
+ const ppDb = wasm.allocPtr() /* output (sqlite3**) arg */;
const pVfsName = vfsName ? (
- ('number'===typeof vfsName ? vfsName : capi.wasm.scopedAllocCString(vfsName))
+ ('number'===typeof vfsName ? vfsName : wasm.scopedAllocCString(vfsName))
): 0;
const rc = capi.sqlite3_open_v2(fn, ppDb, oflags, pVfsName);
- ptr = capi.wasm.getPtrValue(ppDb);
+ ptr = wasm.getPtrValue(ppDb);
checkSqlite3Rc(ptr, rc);
}catch( e ){
if( ptr ) capi.sqlite3_close_v2(ptr);
throw e;
}finally{
- capi.wasm.scopedAllocPop(stack);
+ wasm.scopedAllocPop(scope);
}
this.filename = fnJs;
__ptrMap.set(this, ptr);
@@ -265,7 +265,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
blob: 5
};
BindTypes['undefined'] == BindTypes.null;
- if(capi.wasm.bigIntEnabled){
+ if(wasm.bigIntEnabled){
BindTypes.bigint = BindTypes.number;
}
@@ -454,7 +454,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
if(s && s.pointer) s.finalize();
});
Object.values(__udfMap.get(this)).forEach(
- capi.wasm.uninstallFunction.bind(capi.wasm)
+ wasm.uninstallFunction.bind(capi.wasm)
);
__ptrMap.delete(this);
__stmtMap.delete(this);
@@ -539,15 +539,15 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
*/
prepare: function(sql){
affirmDbOpen(this);
- const stack = capi.wasm.pstack.pointer;
+ const stack = wasm.pstack.pointer;
let ppStmt, pStmt;
try{
- ppStmt = capi.wasm.pstack.alloc(8)/* output (sqlite3_stmt**) arg */;
+ ppStmt = wasm.pstack.alloc(8)/* output (sqlite3_stmt**) arg */;
DB.checkRc(this, capi.sqlite3_prepare_v2(this.pointer, sql, -1, ppStmt, null));
- pStmt = capi.wasm.getPtrValue(ppStmt);
+ pStmt = wasm.getPtrValue(ppStmt);
}
finally {
- capi.wasm.pstack.restore(stack);
+ wasm.pstack.restore(stack);
}
if(!pStmt) toss3("Cannot prepare empty SQL.");
const stmt = new Stmt(this, pStmt, BindTypes);
@@ -846,7 +846,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
let i, pVal, valType, arg;
const tgt = [];
for(i = 0; i < argc; ++i){
- pVal = capi.wasm.getPtrValue(pArgv + (capi.wasm.ptrSizeof * i));
+ pVal = wasm.getPtrValue(pArgv + (wasm.ptrSizeof * i));
/**
Curiously: despite ostensibly requiring 8-byte
alignment, the pArgv array is parcelled into chunks of
@@ -868,7 +868,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const pBlob = capi.sqlite3_value_blob(pVal);
arg = new Uint8Array(n);
let i;
- const heap = n ? capi.wasm.heap8() : false;
+ const heap = n ? wasm.heap8() : false;
for(i = 0; i < n; ++i) arg[i] = heap[pBlob+i];
break;
}
@@ -902,10 +902,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
capi.sqlite3_result_null(pCx);
break;
}else if(util.isBindableTypedArray(val)){
- const pBlob = capi.wasm.allocFromTypedArray(val);
+ const pBlob = wasm.allocFromTypedArray(val);
capi.sqlite3_result_blob(pCx, pBlob, val.byteLength,
capi.SQLITE_TRANSIENT);
- capi.wasm.dealloc(pBlob);
+ wasm.dealloc(pBlob);
break;
}
// else fall through
@@ -925,7 +925,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
}
};
- const pUdf = capi.wasm.installFunction(wrapper, "v(iii)");
+ const pUdf = wasm.installFunction(wrapper, "v(iii)");
let fFlags = 0 /*flags for sqlite3_create_function_v2()*/;
if(getOwnOption(opt, 'deterministic')) fFlags |= capi.SQLITE_DETERMINISTIC;
if(getOwnOption(opt, 'directOnly')) fFlags |= capi.SQLITE_DIRECTONLY;
@@ -938,12 +938,12 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
capi.SQLITE_UTF8 | fFlags, null/*pApp*/, pUdf,
null/*xStep*/, null/*xFinal*/, null/*xDestroy*/));
}catch(e){
- capi.wasm.uninstallFunction(pUdf);
+ wasm.uninstallFunction(pUdf);
throw e;
}
const udfMap = __udfMap.get(this);
if(udfMap[name]){
- try{capi.wasm.uninstallFunction(udfMap[name])}
+ try{wasm.uninstallFunction(udfMap[name])}
catch(e){/*ignore*/}
}
udfMap[name] = pUdf;
@@ -1049,7 +1049,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
case BindTypes.string:
return t;
case BindTypes.bigint:
- if(capi.wasm.bigIntEnabled) return t;
+ if(wasm.bigIntEnabled) return t;
/* else fall through */
default:
//console.log("isSupportedBindType",t,v);
@@ -1109,7 +1109,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const bindOne = function f(stmt,ndx,bindType,val){
affirmUnlocked(stmt, 'bind()');
if(!f._){
- if(capi.wasm.bigIntEnabled){
+ if(wasm.bigIntEnabled){
f._maxInt = BigInt("0x7fffffffffffffff");
f._minInt = ~f._maxInt;
}
@@ -1120,25 +1120,25 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
string: function(stmt, ndx, val, asBlob){
if(1){
/* _Hypothetically_ more efficient than the impl in the 'else' block. */
- const stack = capi.wasm.scopedAllocPush();
+ const stack = wasm.scopedAllocPush();
try{
- const n = capi.wasm.jstrlen(val);
- const pStr = capi.wasm.scopedAlloc(n);
- capi.wasm.jstrcpy(val, capi.wasm.heap8u(), pStr, n, false);
+ const n = wasm.jstrlen(val);
+ const pStr = wasm.scopedAlloc(n);
+ wasm.jstrcpy(val, wasm.heap8u(), pStr, n, false);
const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
return f(stmt.pointer, ndx, pStr, n, capi.SQLITE_TRANSIENT);
}finally{
- capi.wasm.scopedAllocPop(stack);
+ wasm.scopedAllocPop(stack);
}
}else{
- const bytes = capi.wasm.jstrToUintArray(val,false);
- const pStr = capi.wasm.alloc(bytes.length || 1);
- capi.wasm.heap8u().set(bytes.length ? bytes : [0], pStr);
+ const bytes = wasm.jstrToUintArray(val,false);
+ const pStr = wasm.alloc(bytes.length || 1);
+ wasm.heap8u().set(bytes.length ? bytes : [0], pStr);
try{
const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
return f(stmt.pointer, ndx, pStr, bytes.length, capi.SQLITE_TRANSIENT);
}finally{
- capi.wasm.dealloc(pStr);
+ wasm.dealloc(pStr);
}
}
}
@@ -1160,7 +1160,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
else if('bigint'===typeof val){
if(val<f._minInt || val>f._maxInt){
toss3("BigInt value is out of range for storing as int64: "+val);
- }else if(capi.wasm.bigIntEnabled){
+ }else if(wasm.bigIntEnabled){
m = capi.sqlite3_bind_int64;
}else if(val >= Number.MIN_SAFE_INTEGER && val <= Number.MAX_SAFE_INTEGER){
val = Number(val);
@@ -1170,7 +1170,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
}else{ // !int32, !bigint
val = Number(val);
- if(capi.wasm.bigIntEnabled && Number.isInteger(val)){
+ if(wasm.bigIntEnabled && Number.isInteger(val)){
m = capi.sqlite3_bind_int64;
}else{
m = capi.sqlite3_bind_double;
@@ -1190,22 +1190,22 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
"that it be a string, Uint8Array, or Int8Array.");
}else if(1){
/* _Hypothetically_ more efficient than the impl in the 'else' block. */
- const stack = capi.wasm.scopedAllocPush();
+ const stack = wasm.scopedAllocPush();
try{
- const pBlob = capi.wasm.scopedAlloc(val.byteLength || 1);
- capi.wasm.heap8().set(val.byteLength ? val : [0], pBlob)
+ const pBlob = wasm.scopedAlloc(val.byteLength || 1);
+ wasm.heap8().set(val.byteLength ? val : [0], pBlob)
rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
capi.SQLITE_TRANSIENT);
}finally{
- capi.wasm.scopedAllocPop(stack);
+ wasm.scopedAllocPop(stack);
}
}else{
- const pBlob = capi.wasm.allocFromTypedArray(val);
+ const pBlob = wasm.allocFromTypedArray(val);
try{
rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
capi.SQLITE_TRANSIENT);
}finally{
- capi.wasm.dealloc(pBlob);
+ wasm.dealloc(pBlob);
}
}
break;
@@ -1518,7 +1518,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
: asType){
case capi.SQLITE_NULL: return null;
case capi.SQLITE_INTEGER:{
- if(capi.wasm.bigIntEnabled){
+ if(wasm.bigIntEnabled){
const rc = capi.sqlite3_column_int64(this.pointer, ndx);
if(rc>=Number.MIN_SAFE_INTEGER && rc<=Number.MAX_SAFE_INTEGER){
/* Coerce "normal" number ranges to normal number values,
@@ -1549,8 +1549,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const n = capi.sqlite3_column_bytes(this.pointer, ndx),
ptr = capi.sqlite3_column_blob(this.pointer, ndx),
rc = new Uint8Array(n);
- //heap = n ? capi.wasm.heap8() : false;
- if(n) rc.set(capi.wasm.heap8u().slice(ptr, ptr+n), 0);
+ //heap = n ? wasm.heap8() : false;
+ if(n) rc.set(wasm.heap8u().slice(ptr, ptr+n), 0);
//for(let i = 0; i < n; ++i) rc[i] = heap[ptr + i];
if(n && this.db._blobXfer instanceof Array){
/* This is an optimization soley for the
diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js
index 97376be6c..59533815f 100644
--- a/ext/wasm/api/sqlite3-api-prologue.js
+++ b/ext/wasm/api/sqlite3-api-prologue.js
@@ -265,6 +265,9 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
this.name = 'WasmAllocError';
}
};
+ WasmAllocError.toss = (...args)=>{
+ throw new WasmAllocError(args.join(' '));
+ };
/**
The main sqlite3 binding API gets installed into this object,
@@ -733,6 +736,9 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
Functions which are intended solely for API-internal use by the
WASM components, not client code. These get installed into
capi.wasm.
+
+ TODO: get rid of sqlite3_wasm_vfs_unlink(). It is ill-conceived
+ and only rarely actually useful.
*/
capi.wasm.bindingSignatures.wasm = [
["sqlite3_wasm_vfs_unlink", "int", "string"]
@@ -781,15 +787,21 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
Attempts to allocate the given number of bytes from the
pstack. On success, it zeroes out a block of memory of the
given size, adjusts the pstack pointer, and returns a pointer
- to the memory. On error, returns 0. The memory must eventually
- be released using restore().
+ to the memory. On error, returns throws a WasmAllocError. The
+ memory must eventually be released using restore().
This method always adjusts the given value to be a multiple
of 8 bytes because failing to do so can lead to incorrect
results when reading and writing 64-bit values from/to the WASM
heap.
*/
- alloc: capi.wasm.exports.sqlite3_wasm_pstack_alloc
+ alloc: (n)=>{
+ return capi.wasm.exports.sqlite3_wasm_pstack_alloc(n)
+ || WasmAllocError.toss("Could not allocate",n,
+ "bytes from the pstack.");
+ }
+ // More methods get added after the capi.wasm object is populated
+ // by WhWasmUtilInstaller.
});
/**
sqlite3.capi.wasm.pstack.pointer resolves to the current pstack
@@ -828,7 +840,9 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
this.name = 'SQLite3Error';
}
};
-
+ SQLite3Error.toss = (...args)=>{
+ throw new SQLite3Error(args.join(' '));
+ };
/** State for sqlite3_wasmfs_opfs_dir(). */
let __persistentDir = undefined;
diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c
index a2de8ca71..b9454155d 100644
--- a/ext/wasm/api/sqlite3-wasm.c
+++ b/ext/wasm/api/sqlite3-wasm.c
@@ -59,6 +59,10 @@
#include <assert.h>
#include "sqlite3.c" /* yes, .c instead of .h. */
+#if defined(__EMSCRIPTEN__)
+# include <emscripten/console.h>
+#endif
+
/*
** WASM_KEEP is identical to EMSCRIPTEN_KEEPALIVE but is not
** Emscripten-specific. It explicitly marks functions for export into
@@ -667,6 +671,9 @@ WASM_KEEP
int sqlite3_wasm_vfs_unlink(const char * zName){
int rc = SQLITE_MISUSE /* ??? */;
sqlite3_vfs * const pVfs = sqlite3_vfs_find(0);
+#if defined(__EMSCRIPTEN__)
+ emscripten_console_warn("sqlite3_wasm_vfs_unlink() will be removed.");
+#endif
if( zName && pVfs && pVfs->xDelete ){
rc = pVfs->xDelete(pVfs, zName, 1);
}
@@ -750,9 +757,7 @@ int sqlite3_wasm_db_serialize( sqlite3* pDb, unsigned char **pOut, sqlite3_int64
}
-#if defined(__EMSCRIPTEN__)
-#include <emscripten/console.h>
-#if defined(SQLITE_WASM_WASMFS)
+#if defined(__EMSCRIPTEN__) && defined(SQLITE_WASM_WASMFS)
#include <emscripten/wasmfs.h>
/*
@@ -809,6 +814,5 @@ int sqlite3_wasm_init_wasmfs(const char *zUnused){
return SQLITE_NOTFOUND;
}
#endif /* __EMSCRIPTEN__ && SQLITE_WASM_WASMFS */
-#endif
#undef WASM_KEEP
diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js
index 39a214be0..6b08d4f78 100644
--- a/ext/wasm/common/whwasmutil.js
+++ b/ext/wasm/common/whwasmutil.js
@@ -1091,28 +1091,36 @@ self.WhWasmUtilInstaller = function(target){
};
/** Internal impl for allocPtr() and scopedAllocPtr(). */
- const __allocPtr = function(howMany, method){
+ const __allocPtr = function(howMany, safePtrSize, method){
__affirmAlloc(target, method);
- let m = target[method](howMany * ptrSizeof);
- target.setMemValue(m, 0, ptrIR)
+ const pIr = safePtrSize ? 'i64' : ptrIR;
+ let m = target[method](howMany * (safePtrSize ? 8 : ptrSizeof));
+ target.setMemValue(m, 0, pIr)
if(1===howMany){
return m;
}
const a = [m];
for(let i = 1; i < howMany; ++i){
- m += ptrSizeof;
+ m += (safePtrSize ? 8 : ptrSizeof);
a[i] = m;
- target.setMemValue(m, 0, ptrIR);
+ target.setMemValue(m, 0, pIr);
}
return a;
};
/**
- Allocates a single chunk of memory capable of holding `howMany`
- pointers and zeroes them out. If `howMany` is 1 then the memory
- chunk is returned directly, else an array of pointer addresses is
- returned, which can optionally be used with "destructuring
- assignment" like this:
+ Allocates one or more pointers as a single chunk of memory and
+ zeroes them out.
+
+ The first argument is the number of pointers to allocate. The
+ second specifies whether they should use a "safe" pointer size (8
+ bytes) or whether they may use the default pointer size
+ (typically 4 but also possibly 8).
+
+ How the result is returned depends on its first argument: if
+ passed 1, it returns the allocated memory address. If passed more
+ than one then an array of pointer addresses is returned, which
+ can optionally be used with "destructuring assignment" like this:
```
const [p1, p2, p3] = allocPtr(3);
@@ -1121,14 +1129,27 @@ self.WhWasmUtilInstaller = function(target){
ACHTUNG: when freeing the memory, pass only the _first_ result
value to dealloc(). The others are part of the same memory chunk
and must not be freed separately.
+
+ The reason for the 2nd argument is..
+
+ When one of the pointers will refer to a 64-bit value, e.g. a
+ double or int64, an that value must be written or fetch,
+ e.g. using setMemValue() or getMemValue(), it is important that
+ the pointer in question be aligned to an 8-byte boundary or else
+ it will not be fetched or written properly and will corrupt or
+ read neighboring memory. It i only safe to pass false when the
+ client code is certain that it will only get/fetch 4-byte values
+ (or smaller).
*/
- target.allocPtr = (howMany=1)=>__allocPtr(howMany, 'alloc');
+ target.allocPtr =
+ (howMany=1, safePtrSize=true)=>__allocPtr(howMany, safePtrSize, 'alloc');
/**
Identical to allocPtr() except that it allocates using scopedAlloc()
instead of alloc().
*/
- target.scopedAllocPtr = (howMany=1)=>__allocPtr(howMany, 'scopedAlloc');
+ target.scopedAllocPtr =
+ (howMany=1, safePtrSize=true)=>__allocPtr(howMany, safePtrSize, 'scopedAlloc');
/**
If target.exports[name] exists, it is returned, else an
diff --git a/ext/wasm/testing1.js b/ext/wasm/testing1.js
index dd61ab281..053fb6f27 100644
--- a/ext/wasm/testing1.js
+++ b/ext/wasm/testing1.js
@@ -1030,31 +1030,60 @@
*/
const testPstack = function(db,sqlite3){
const w = sqlite3.capi.wasm, P = w.pstack;
+ const isAllocErr = (e)=>e instanceof sqlite3.WasmAllocError;
const stack = P.pointer;
T.assert(0===stack % 8 /* must be 8-byte aligned */);
try{
const quota = P.remaining;
log("pstack quota",quota);
T.assert(quota >= 4096)
- .assert(0 === P.alloc(0))
- .assert(0 === P.alloc(-1));
+ .mustThrowMatching(()=>P.alloc(0), isAllocErr)
+ .mustThrowMatching(()=>P.alloc(-1), isAllocErr);
let p1 = P.alloc(12);
T.assert(p1 === stack - 16/*8-byte aligned*/)
.assert(P.pointer === p1);
let p2 = P.alloc(7);
T.assert(p2 === p1-8/*8-byte aligned, stack grows downwards*/)
- .assert(0 === P.alloc(quota))
+ .mustThrowMatching(()=>P.alloc(quota), isAllocErr)
.assert(24 === stack - p2)
.assert(P.pointer === p2);
let n = quota - (stack - p2);
let p3 = P.alloc(n);
T.assert(p3 === stack-quota)
- .assert(0 === P.alloc(1));
+ .mustThrowMatching(()=>P.alloc(1), isAllocErr);
}finally{
P.restore(stack);
- T.assert(P.pointer === stack);
}
- }/*testPstack()*/;
+
+ T.assert(P.pointer === stack);
+ try {
+ const [p1, p2, p3] = P.allocChunks(3,4);
+ T.assert(P.pointer === stack-16/*always rounded to multiple of 8*/)
+ .assert(p2 === p1 + 4)
+ .assert(p3 === p2 + 4);
+ T.mustThrowMatching(()=>P.allocChunks(1024, 1024 * 16),
+ (e)=>e instanceof sqlite3.WasmAllocError)
+ }finally{
+ P.restore(stack);
+ }
+
+ T.assert(P.pointer === stack);
+ try {
+ let [p1, p2, p3] = P.allocPtr(3,false);
+ let sPos = stack-16/*always rounded to multiple of 8*/;
+ T.assert(P.pointer === sPos)
+ .assert(p2 === p1 + 4)
+ .assert(p3 === p2 + 4);
+ [p1, p2, p3] = P.allocPtr(3);
+ T.assert(P.pointer === sPos-24/*3 x 8 bytes*/)
+ .assert(p2 === p1 + 8)
+ .assert(p3 === p2 + 8);
+ p1 = P.allocPtr();
+ T.assert('number'===typeof p1);
+ }finally{
+ P.restore(stack);
+ }
+}/*testPstack()*/;
const clearKvvfs = function(){
const sz = sqlite3.capi.sqlite3_web_kvvfs_size();
diff --git a/manifest b/manifest
index d3947b8c2..c9a71476e 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Document\sthe\sroles\sof\sthe\snew\s(this\spast\sweek)\sJS\sfiles\sadded\sto\sthe\sbuild\sprocess.
-D 2022-10-02T01:48:14.286
+C More\sfleshing\sout\sof\ssqlite3.capi.wasm.pstack.
+D 2022-10-02T03:11:13.806
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -485,19 +485,19 @@ F ext/wasm/api/post-js-footer.js b64319261d920211b8700004d08b956a6c285f3b0bba814
F ext/wasm/api/post-js-header.js 2e5c886398013ba2af88028ecbced1e4b22dc96a86467f1ecc5ba9e64ef90a8b
F ext/wasm/api/pre-js.js 2db711eb637991b383fc6b5c0f3df65ec48a7201e5730e304beba8de2d3f9b0b
F ext/wasm/api/sqlite3-api-cleanup.js 5d22d1d3818ecacb23bfa223d5970cd0617d8cdbb48c8bc4bbd463f05b021a99
-F ext/wasm/api/sqlite3-api-glue.js b15a51b88aaa472d36bf82d5123dbfdafe8ddf6ca75fba934510e4a20bbe4adb
-F ext/wasm/api/sqlite3-api-oo1.js 7667d320f6b9fb5252050a2f9c0b1769e11b84dbc0763b999baf65b451b14369
+F ext/wasm/api/sqlite3-api-glue.js 474a5e0bf8016e22aefee44ca45408f08f4159c0b782295ac1d86c4556e91d9a
+F ext/wasm/api/sqlite3-api-oo1.js 066e67f3033e1b300140d431557c468f5cd0a4c17253f156e05b8a2e2c802da7
F ext/wasm/api/sqlite3-api-opfs.js 1b097808b7b081b0f0700cf97d49ef19760e401706168edff9cd45cf9169f541
-F ext/wasm/api/sqlite3-api-prologue.js a93bd69969eb8b8f9c4cb34e5d86dcbbe5adbeeea39c1cce57194256c5f28434
+F ext/wasm/api/sqlite3-api-prologue.js 9b0c5150f0129b3dc558fec0bfc9c8bf7ebda402b58965bcf98b2ed117b55239
F ext/wasm/api/sqlite3-api-worker1.js 7f4f46cb6b512a48572d7567233896e6a9c46570c44bdc3d13419730c7c221c8
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
-F ext/wasm/api/sqlite3-wasm.c d72aecf0e50a4403402095ef4e8d6a814fdc2256589944c1dc974c70d2f65b7e
+F ext/wasm/api/sqlite3-wasm.c 2a0f9e4bf1b141a787918951360601128d6a0a190a31a8e5cfe237c99fa640c6
F ext/wasm/batch-runner.html c363032aba7a525920f61f8be112a29459f73f07e46f0ba3b7730081a617826e
F ext/wasm/batch-runner.js ce92650a6681586c89bef26ceae96674a55ca5a9727815202ca62e1a00ff5015
F ext/wasm/common/SqliteTestUtil.js 647bf014bd30bdd870a7e9001e251d12fc1c9ec9ce176a1004b838a4b33c5c05
F ext/wasm/common/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
F ext/wasm/common/testing.css 3a5143699c2b73a85b962271e1a9b3241b30d90e30d895e4f55665e648572962
-F ext/wasm/common/whwasmutil.js d2557d6ef1ebaaf3c9a0cea2231fd398b0d8ca8129b51580af1c92f8d04335e0
+F ext/wasm/common/whwasmutil.js cdb33775fdc55c9b1cbb617d22d24b4a29dc9c1389b827a5b14886a291480d70
F ext/wasm/demo-123-worker.html e419b66495d209b5211ec64903b4cfb3ca7df20d652b41fcd28bf018a773234f
F ext/wasm/demo-123.html aa281d33b7eefa755f3122b7b5a18f39a42dc5fb69c8879171bf14b4c37c4ec4
F ext/wasm/demo-123.js 536579fd587974c2511c5bf82034b253d4fdeceabb726927ad7599ef6b7578e8
@@ -530,7 +530,7 @@ F ext/wasm/test-opfs-vfs.js a59ff9210b17d46b0c6fbf6a0ba60143c033327865f2e556e14f
F ext/wasm/testing-worker1-promiser.html 6eaec6e04a56cf24cf4fa8ef49d78ce8905dde1354235c9125dca6885f7ce893
F ext/wasm/testing-worker1-promiser.js bd788e33c1807e0a6dda9c9a9d784bd3350ca49c9dd8ae2cc8719b506b6e013e
F ext/wasm/testing1.html 50575755e43232dbe4c2f97c9086b3118eb91ec2ee1fae931e6d7669fb17fcae
-F ext/wasm/testing1.js 51ef1ced0669f804787ce96f19dcf64367550a7923a998514be56076326988d7
+F ext/wasm/testing1.js bdea170b16189028c1f63023c620df52ddf31ed416bad56d729c60031b1e27ae
F ext/wasm/testing2.html a66951c38137ff1d687df79466351f3c734fa9c6d9cce71d3cf97c291b2167e3
F ext/wasm/testing2.js 88f40ef3cd8201bdadd120a711c36bbf0ce56cc0eab1d5e7debb71fed7822494
F ext/wasm/wasmfs.make 3cce1820006196de140f90f2da4b4ea657083fb5bfee7d125be43f7a85748c8f
@@ -2029,8 +2029,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 f9db664f756f3707afcb5dce87f6d946625848f27ea84337af68de72d4ad6c6b
-R 8201c0f212d8f73dc23b363b8bdcd606
+P 8b3bc7313aff551e5ee0b7aeb927095cf19b9b96abbdd922066c130656b8aa7d
+R a0d2cb1d1b18288fcfda68347c547fdd
U stephan
-Z 7616e552f06f17aa339add7ed573ed79
+Z 5fc153c99e29258d724616b67e70d32b
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 29067e24b..fa1c36d77 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-8b3bc7313aff551e5ee0b7aeb927095cf19b9b96abbdd922066c130656b8aa7d \ No newline at end of file
+eb5726677a727a958df11f1fba078d30c7c0ba2a9bdb158e8641b35b5f971af3 \ No newline at end of file