Skip to content

Commit

Permalink
Enable JSPI (#3259)
Browse files Browse the repository at this point in the history
This enables JSPI in Python workers. It will not be usable until we
also update to the newer Pyodide runtime.
  • Loading branch information
hoodmane authored Dec 19, 2024
1 parent 7d0e7cd commit 7f143db
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/workerd/api/pyodide/pyodide.c++
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ void DiskCache::put(jsg::Lock& js, kj::String key, kj::Array<kj::byte> data) {
}

jsg::JsValue SetupEmscripten::getModule(jsg::Lock& js) {
js.installJspi();
js.v8Context()->SetSecurityToken(emscriptenRuntime.contextToken.getHandle(js));
return emscriptenRuntime.emscriptenRuntime.getHandle(js);
}
Expand Down
1 change: 1 addition & 0 deletions src/workerd/api/pyodide/setup-emscripten.c++
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ EmscriptenRuntime EmscriptenRuntime::initialize(
kj::Maybe<capnp::Data::Reader> emsciptenSetupJsReader;
kj::Maybe<capnp::Data::Reader> pythonStdlibZipReader;
kj::Maybe<capnp::Data::Reader> pyodideAsmWasmReader;
js.installJspi();
for (auto module: bundle.getModules()) {
if (module.getName().endsWith("emscriptenSetup.js")) {
emsciptenSetupJsReader = module.getData();
Expand Down
6 changes: 6 additions & 0 deletions src/workerd/jsg/jsg.c++
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
3 changes: 3 additions & 0 deletions src/workerd/jsg/jsg.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
7 changes: 7 additions & 0 deletions src/workerd/jsg/setup.c++
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -461,6 +462,12 @@ bool IsolateBase::allowWasmCallback(v8::Local<v8::Context> context, v8::Local<v8
return self->evalAllowed;
}

bool IsolateBase::jspiEnabledCallback(v8::Local<v8::Context> context) {
IsolateBase* self =
static_cast<IsolateBase*>(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.
Expand Down
5 changes: 5 additions & 0 deletions src/workerd/jsg/setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ class IsolateBase {
inline void setAllowEval(kj::Badge<Lock>, bool allow) {
evalAllowed = allow;
}
inline void setJspiEnabled(kj::Badge<Lock>, bool enabled) {
jspiEnabled = enabled;
}
inline void setCaptureThrowsAsRejections(kj::Badge<Lock>, bool capture) {
captureThrowsAsRejections = capture;
}
Expand Down Expand Up @@ -236,6 +239,7 @@ class IsolateBase {
v8::Isolate* ptr;
kj::Maybe<kj::String> 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
Expand Down Expand Up @@ -320,6 +324,7 @@ class IsolateBase {
static v8::ModifyCodeGenerationFromStringsResult modifyCodeGenCallback(
v8::Local<v8::Context> context, v8::Local<v8::Value> source, bool isCodeLike);
static bool allowWasmCallback(v8::Local<v8::Context> context, v8::Local<v8::String> source);
static bool jspiEnabledCallback(v8::Local<v8::Context> context);

static void jitCodeEvent(const v8::JitCodeEvent* event) noexcept;

Expand Down
4 changes: 4 additions & 0 deletions src/workerd/server/tests/python/hello/worker.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down

0 comments on commit 7f143db

Please sign in to comment.