From 26b625b386645941ee7277481d22fb84550aa6ea Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Mon, 7 Aug 2023 17:07:10 +0000 Subject: [PATCH] JSPI - Fix idbstore with jspi. Return the promise from handleSleep so wasm is suspended until each idb operation is done. Fixes #19989 --- src/library_idbstore.js | 12 ++++++------ test/browser/test_idbstore_sync.c | 2 ++ test/common.py | 9 +++++++++ test/test_browser.py | 21 ++++++++++++++++++--- 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/library_idbstore.js b/src/library_idbstore.js index 0b3bc1798bfbe..832e2670cb839 100644 --- a/src/library_idbstore.js +++ b/src/library_idbstore.js @@ -81,7 +81,7 @@ var LibraryIDBStore = { emscripten_idb_load__async: true, emscripten_idb_load__deps: ['malloc'], emscripten_idb_load: (db, id, pbuffer, pnum, perror) => { - Asyncify.handleSleep(function(wakeUp) { + return Asyncify.handleSleep(function(wakeUp) { IDBStore.getFile(UTF8ToString(db), UTF8ToString(id), function(error, byteArray) { if (error) { {{{ makeSetValue('perror', 0, '1', 'i32') }}}; @@ -99,7 +99,7 @@ var LibraryIDBStore = { }, emscripten_idb_store__async: true, emscripten_idb_store: (db, id, ptr, num, perror) => { - Asyncify.handleSleep(function(wakeUp) { + return Asyncify.handleSleep(function(wakeUp) { IDBStore.setFile(UTF8ToString(db), UTF8ToString(id), new Uint8Array(HEAPU8.subarray(ptr, ptr+num)), function(error) { {{{ makeSetValue('perror', 0, '!!error', 'i32') }}}; wakeUp(); @@ -108,7 +108,7 @@ var LibraryIDBStore = { }, emscripten_idb_delete__async: true, emscripten_idb_delete: (db, id, perror) => { - Asyncify.handleSleep(function(wakeUp) { + return Asyncify.handleSleep(function(wakeUp) { IDBStore.deleteFile(UTF8ToString(db), UTF8ToString(id), function(error) { {{{ makeSetValue('perror', 0, '!!error', 'i32') }}}; wakeUp(); @@ -117,7 +117,7 @@ var LibraryIDBStore = { }, emscripten_idb_exists__async: true, emscripten_idb_exists: (db, id, pexists, perror) => { - Asyncify.handleSleep(function(wakeUp) { + return Asyncify.handleSleep(function(wakeUp) { IDBStore.existsFile(UTF8ToString(db), UTF8ToString(id), function(error, exists) { {{{ makeSetValue('pexists', 0, '!!exists', 'i32') }}}; {{{ makeSetValue('perror', 0, '!!error', 'i32') }}}; @@ -128,7 +128,7 @@ var LibraryIDBStore = { // extra worker methods - proxied emscripten_idb_load_blob__async: true, emscripten_idb_load_blob: (db, id, pblob, perror) => { - Asyncify.handleSleep(function(wakeUp) { + return Asyncify.handleSleep(function(wakeUp) { assert(!IDBStore.pending); IDBStore.pending = function(msg) { IDBStore.pending = null; @@ -154,7 +154,7 @@ var LibraryIDBStore = { }, emscripten_idb_store_blob__async: true, emscripten_idb_store_blob: (db, id, ptr, num, perror) => { - Asyncify.handleSleep(function(wakeUp) { + return Asyncify.handleSleep(function(wakeUp) { assert(!IDBStore.pending); IDBStore.pending = function(msg) { IDBStore.pending = null; diff --git a/test/browser/test_idbstore_sync.c b/test/browser/test_idbstore_sync.c index e44c4dea71870..e2a21a65ad491 100644 --- a/test/browser/test_idbstore_sync.c +++ b/test/browser/test_idbstore_sync.c @@ -25,7 +25,9 @@ void test() { sum++; printf("checking\n"); + exists = 5555; emscripten_idb_exists(DB, "the_secret", &exists, &error); + assert(exists != 5555); assert(!error); assert(exists); sum++; diff --git a/test/common.py b/test/common.py index c37daad31d7a5..60d376b3ce5ca 100644 --- a/test/common.py +++ b/test/common.py @@ -557,6 +557,9 @@ class RunnerCore(unittest.TestCase, metaclass=RunnerMeta): def is_wasm(self): return self.get_setting('WASM') != 0 + def is_browser_test(self): + return False + def check_dylink(self): if self.get_setting('ALLOW_MEMORY_GROWTH') == 1 and not self.is_wasm(): self.skipTest('no dynamic linking with memory growth (without wasm)') @@ -663,6 +666,9 @@ def require_jspi(self): if not self.is_wasm(): self.skipTest('JSPI is not currently supported for WASM2JS') + if self.is_browser_test(): + return + exp_args = ['--experimental-wasm-stack-switching', '--experimental-wasm-type-reflection'] if config.NODE_JS and config.NODE_JS in self.js_engines: version = shared.check_node_version() @@ -1809,6 +1815,9 @@ def tearDownClass(cls): # WindowsError: [Error 32] The process cannot access the file because it is being used by another process. time.sleep(0.1) + def is_browser_test(self): + return True + def assert_out_queue_empty(self, who): if not self.harness_out_queue.empty(): while not self.harness_out_queue.empty(): diff --git a/test/test_browser.py b/test/test_browser.py index 76f84b08a72c8..8372798c0e024 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -242,6 +242,11 @@ def require_wasm64(self): # All the browsers we run on support wasm64 (Chrome and Firefox). return True + def require_jspi(self): + if not is_chrome(): + self.skipTest(f'Current browser ({EMTEST_BROWSER}) does not support JSPI. Only chromium-based browsers ({CHROMIUM_BASED_BROWSERS}) support JSPI today.') + super(browser, self).require_jspi() + def test_sdl1_in_emscripten_nonstrict_mode(self): if 'EMCC_STRICT' in os.environ and int(os.environ['EMCC_STRICT']): self.skipTest('This test requires being run in non-strict mode (EMCC_STRICT env. variable unset)') @@ -1507,10 +1512,20 @@ def test_idbstore(self): args=['-lidbstore.js', f'-DSTAGE={stage}', f'-DSECRET="{secret}"'], output_basename=f'idbstore_{stage}') - @also_with_wasm64 - def test_idbstore_sync(self): + @parameterized({ + 'asyncify': (1, False), + 'asyncify_wasm64': (1, True), + 'jspi': (2, False), + }) + def test_idbstore_sync(self, asyncify, wasm64): + if wasm64: + self.require_wasm64() + self.set_setting('MEMORY64') + self.emcc_args.append('-Wno-experimental') + if asyncify == 2: + self.require_jspi() secret = str(time.time()) - self.btest(test_file('browser/test_idbstore_sync.c'), '6', args=['-lidbstore.js', f'-DSECRET="{secret}"', '-O3', '-g2', '-sASYNCIFY']) + self.btest(test_file('browser/test_idbstore_sync.c'), '6', args=['-lidbstore.js', f'-DSECRET="{secret}"', '-O3', '-g2', '-sASYNCIFY=' + str(asyncify)]) def test_idbstore_sync_worker(self): secret = str(time.time())