diff --git a/src/workerd/api/pyodide/pyodide.c++ b/src/workerd/api/pyodide/pyodide.c++ index 3d9493464f2..02f443d4c66 100644 --- a/src/workerd/api/pyodide/pyodide.c++ +++ b/src/workerd/api/pyodide/pyodide.c++ @@ -485,6 +485,7 @@ void DiskCache::put(jsg::Lock& js, kj::String key, kj::Array data) { } jsg::JsValue SetupEmscripten::getModule(jsg::Lock& js) { + js.installJspi(); js.v8Context()->SetSecurityToken(emscriptenRuntime.contextToken.getHandle(js)); return emscriptenRuntime.emscriptenRuntime.getHandle(js); } diff --git a/src/workerd/api/pyodide/setup-emscripten.c++ b/src/workerd/api/pyodide/setup-emscripten.c++ index b0ae7aed039..336514e5ad4 100644 --- a/src/workerd/api/pyodide/setup-emscripten.c++ +++ b/src/workerd/api/pyodide/setup-emscripten.c++ @@ -72,6 +72,7 @@ EmscriptenRuntime EmscriptenRuntime::initialize( kj::Maybe emsciptenSetupJsReader; kj::Maybe pythonStdlibZipReader; kj::Maybe pyodideAsmWasmReader; + js.installJspi(); for (auto module: bundle.getModules()) { if (module.getName().endsWith("emscriptenSetup.js")) { emsciptenSetupJsReader = module.getData(); diff --git a/src/workerd/jsg/jsg.c++ b/src/workerd/jsg/jsg.c++ index 6d2cc7e1779..3b598bb7f78 100644 --- a/src/workerd/jsg/jsg.c++ +++ b/src/workerd/jsg/jsg.c++ @@ -187,6 +187,12 @@ void Lock::setAllowEval(bool allow) { IsolateBase::from(v8Isolate).setAllowEval({}, allow); } +void Lock::installJspi() { + IsolateBase::from(v8Isolate).setJspiEnabled({}, true); + v8Isolate->InstallConditionalFeatures(v8Context()); + IsolateBase::from(v8Isolate).setJspiEnabled({}, false); +} + void Lock::setCaptureThrowsAsRejections(bool capture) { IsolateBase::from(v8Isolate).setCaptureThrowsAsRejections({}, capture); } diff --git a/src/workerd/jsg/jsg.h b/src/workerd/jsg/jsg.h index 8e5be0ba874..fdd5c402368 100644 --- a/src/workerd/jsg/jsg.h +++ b/src/workerd/jsg/jsg.h @@ -2528,6 +2528,9 @@ class Lock { // Use to enable/disable dynamic code evaluation (via eval(), new Function(), or WebAssembly). void setAllowEval(bool allow); + // Install JSPI on the current context. Currently used only for Python workers. + void installJspi(); + void setCaptureThrowsAsRejections(bool capture); void setCommonJsExportDefault(bool exportDefault); diff --git a/src/workerd/jsg/setup.c++ b/src/workerd/jsg/setup.c++ index 36bf2852019..864b3f3b270 100644 --- a/src/workerd/jsg/setup.c++ +++ b/src/workerd/jsg/setup.c++ @@ -343,6 +343,7 @@ IsolateBase::IsolateBase(const V8System& system, ptr->SetModifyCodeGenerationFromStringsCallback(&modifyCodeGenCallback); ptr->SetAllowWasmCodeGenerationCallback(&allowWasmCallback); + ptr->SetWasmJSPIEnabledCallback(&jspiEnabledCallback); // We don't support SharedArrayBuffer so Atomics.wait() doesn't make sense, and might allow DoS // attacks. @@ -461,6 +462,12 @@ bool IsolateBase::allowWasmCallback(v8::Local context, v8::LocalevalAllowed; } +bool IsolateBase::jspiEnabledCallback(v8::Local context) { + IsolateBase* self = + static_cast(context->GetIsolate()->GetData(SET_DATA_ISOLATE_BASE)); + return self->jspiEnabled; +} + void IsolateBase::jitCodeEvent(const v8::JitCodeEvent* event) noexcept { // We register this callback with V8 in order to build a mapping of code addresses to source // code locations, which we use when reporting stack traces during crashes. diff --git a/src/workerd/jsg/setup.h b/src/workerd/jsg/setup.h index 35956d364e8..e0f535a436e 100644 --- a/src/workerd/jsg/setup.h +++ b/src/workerd/jsg/setup.h @@ -122,6 +122,9 @@ class IsolateBase { inline void setAllowEval(kj::Badge, bool allow) { evalAllowed = allow; } + inline void setJspiEnabled(kj::Badge, bool enabled) { + jspiEnabled = enabled; + } inline void setCaptureThrowsAsRejections(kj::Badge, bool capture) { captureThrowsAsRejections = capture; } @@ -236,6 +239,7 @@ class IsolateBase { v8::Isolate* ptr; kj::Maybe uuid; bool evalAllowed = false; + bool jspiEnabled = false; // The Web Platform API specifications require that any API that returns a JavaScript Promise // should never throw errors synchronously. Rather, they are supposed to capture any synchronous @@ -320,6 +324,7 @@ class IsolateBase { static v8::ModifyCodeGenerationFromStringsResult modifyCodeGenCallback( v8::Local context, v8::Local source, bool isCodeLike); static bool allowWasmCallback(v8::Local context, v8::Local source); + static bool jspiEnabledCallback(v8::Local context); static void jitCodeEvent(const v8::JitCodeEvent* event) noexcept; diff --git a/src/workerd/server/tests/python/hello/worker.py b/src/workerd/server/tests/python/hello/worker.py index badd15b0c4a..4fb06e7b34f 100644 --- a/src/workerd/server/tests/python/hello/worker.py +++ b/src/workerd/server/tests/python/hello/worker.py @@ -1,4 +1,8 @@ def test(): + from js.WebAssembly import Suspending + + Suspending # noqa: B018 + # This just tests that nothing raises when we run this. It isn't great though # because we don't test whether we printed anything. # TODO: update this to test that something happened