diff --git a/src/workerd/io/limit-enforcer.h b/src/workerd/io/limit-enforcer.h index a396420e166..3287be9b5ee 100644 --- a/src/workerd/io/limit-enforcer.h +++ b/src/workerd/io/limit-enforcer.h @@ -17,7 +17,7 @@ static constexpr size_t DEFAULT_MAX_PBKDF2_ITERATIONS = 100'000; // Interface for an object that enforces resource limits on an Isolate level. // // See also LimitEnforcer, which enforces on a per-request level. -class IsolateLimitEnforcer { +class IsolateLimitEnforcer: public kj::Refcounted { public: // Get CreateParams to pass when constructing a new isolate. virtual v8::Isolate::CreateParams getCreateParams() = 0; diff --git a/src/workerd/io/worker.c++ b/src/workerd/io/worker.c++ index e33d25fa3e2..4cfd7bdb0cd 100644 --- a/src/workerd/io/worker.c++ +++ b/src/workerd/io/worker.c++ @@ -663,7 +663,7 @@ struct Worker::Isolate::Impl { // because our GlobalScope object needs to have a function called on it, and any attached // inspector needs to be notified. JSG doesn't know about these things. - Impl(const Api& api, + Impl(Api& api, IsolateObserver& metrics, IsolateLimitEnforcer& limitEnforcer, InspectorPolicy inspectorPolicy) @@ -672,6 +672,8 @@ struct Worker::Isolate::Impl { actorCacheLru(limitEnforcer.getActorCacheLruOptions()) { jsg::runInV8Stack([&](jsg::V8StackScope& stackScope) { auto lock = api.lock(stackScope); + + limitEnforcer.customizeIsolate(lock->v8Isolate); if (inspectorPolicy != InspectorPolicy::DISALLOW) { // We just created our isolate, so we don't need to use Isolate::Impl::Lock. KJ_ASSERT(!isMultiTenantProcess(), "inspector is not safe in multi-tenant processes"); @@ -970,17 +972,19 @@ const HeapSnapshotDeleter HeapSnapshotDeleter::INSTANCE; Worker::Isolate::Isolate(kj::Own apiParam, kj::StringPtr id, + kj::Own limitEnforcerParam, InspectorPolicy inspectorPolicy, ConsoleMode consoleMode) : metrics(kj::atomicAddRef(apiParam->getMetrics())), id(kj::str(id)), api(kj::mv(apiParam)), - limitEnforcer(api->getLimitEnforcer()), + limitEnforcer(kj::mv(limitEnforcerParam)), consoleMode(consoleMode), featureFlagsForFl(makeCompatJson(decompileCompatibilityFlagsForFl(api->getFeatureFlags()))), - impl(kj::heap(*api, *metrics, limitEnforcer, inspectorPolicy)), + impl(kj::heap(*api, *metrics, *limitEnforcer, inspectorPolicy)), weakIsolateRef(WeakIsolateRef::wrap(this)), traceAsyncContextKey(kj::refcounted()) { + api->setEnforcer(*limitEnforcer); metrics->created(); // We just created our isolate, so we don't need to use Isolate::Impl::Lock (nor an async lock). jsg::runInV8Stack([&](jsg::V8StackScope& stackScope) { @@ -1387,7 +1391,7 @@ Worker::Isolate::~Isolate() noexcept(false) { // Update the isolate stats one last time to make sure we're accurate for cleanup in // `evicted()`. - limitEnforcer.reportMetrics(*metrics); + limitEnforcer->reportMetrics(*metrics); metrics->evicted(); weakIsolateRef->invalidate(); @@ -1402,6 +1406,7 @@ Worker::Isolate::~Isolate() noexcept(false) { auto inspector = kj::mv(impl->inspector); auto dropTraceAsyncContextKey = kj::mv(traceAsyncContextKey); }); + api->invalidateEnforcer(); } Worker::Script::~Script() noexcept(false) { @@ -3808,7 +3813,7 @@ kj::Own Worker::Isolate::newScript(kj::StringPtr scriptId, } void Worker::Isolate::completedRequest() const { - limitEnforcer.completedRequest(id); + limitEnforcer->completedRequest(id); } bool Worker::Isolate::isInspectorEnabled() const { diff --git a/src/workerd/io/worker.h b/src/workerd/io/worker.h index 68e01dd5c27..4552d0c1d9e 100644 --- a/src/workerd/io/worker.h +++ b/src/workerd/io/worker.h @@ -276,6 +276,7 @@ class Worker::Isolate: public kj::AtomicRefcounted { // inspector session to stay open across them). explicit Isolate(kj::Own api, kj::StringPtr id, + kj::Own limitEnforcer, InspectorPolicy inspectorPolicy, ConsoleMode consoleMode = ConsoleMode::INSPECTOR_ONLY); @@ -305,11 +306,11 @@ class Worker::Isolate: public kj::AtomicRefcounted { kj::Maybe errorReporter = kj::none) const; inline IsolateLimitEnforcer& getLimitEnforcer() { - return limitEnforcer; + return *limitEnforcer; } inline const IsolateLimitEnforcer& getLimitEnforcer() const { - return limitEnforcer; + return *limitEnforcer; } inline Api& getApi() { @@ -409,7 +410,8 @@ class Worker::Isolate: public kj::AtomicRefcounted { kj::String id; kj::Own api; - IsolateLimitEnforcer& limitEnforcer; + // TODO: should this be before or after api? + kj::Own limitEnforcer; ConsoleMode consoleMode; // If non-null, a serialized JSON object with a single "flags" property, which is a list of @@ -532,10 +534,10 @@ class Worker::Api { virtual jsg::JsObject wrapExecutionContext( jsg::Lock& lock, jsg::Ref ref) const = 0; - virtual IsolateLimitEnforcer& getLimitEnforcer() = 0; - virtual const IsolateLimitEnforcer& getLimitEnforcer() const = 0; virtual IsolateObserver& getMetrics() = 0; virtual const IsolateObserver& getMetrics() const = 0; + virtual void setEnforcer(IsolateLimitEnforcer&) = 0; + virtual void invalidateEnforcer() = 0; // Set the module fallback service callback, if any. using ModuleFallbackCallback = kj::Maybe>( diff --git a/src/workerd/server/server.c++ b/src/workerd/server/server.c++ index e7ff45d15f8..8718cd85308 100644 --- a/src/workerd/server/server.c++ +++ b/src/workerd/server/server.c++ @@ -2922,7 +2922,7 @@ kj::Own Server::makeWorker(kj::StringPtr name, }; auto observer = kj::atomicRefcounted(); - auto limitEnforcer = kj::heap(); + auto limitEnforcer = kj::refcounted(); kj::Maybe> newModuleRegistry; if (featureFlags.getNewModuleRegistry()) { @@ -2933,15 +2933,16 @@ kj::Own Server::makeWorker(kj::StringPtr name, *observer, conf, featureFlags.asReader(), pythonConfig); } - auto api = - kj::heap(globalContext->v8System, featureFlags.asReader(), kj::mv(limitEnforcer), - kj::mv(observer), *memoryCacheProvider, pythonConfig, kj::mv(newModuleRegistry)); + auto api = kj::heap(globalContext->v8System, featureFlags.asReader(), + limitEnforcer->getCreateParams(), kj::mv(observer), *memoryCacheProvider, pythonConfig, + kj::mv(newModuleRegistry)); auto inspectorPolicy = Worker::Isolate::InspectorPolicy::DISALLOW; if (inspectorOverride != kj::none) { // For workerd, if the inspector is enabled, it is always fully trusted. inspectorPolicy = Worker::Isolate::InspectorPolicy::ALLOW_FULLY_TRUSTED; } - auto isolate = kj::atomicRefcounted(kj::mv(api), name, inspectorPolicy, + auto isolate = kj::atomicRefcounted(kj::mv(api), name, kj::mv(limitEnforcer), + inspectorPolicy, conf.isServiceWorkerScript() ? Worker::ConsoleMode::INSPECTOR_ONLY : consoleMode); // If we are using the inspector, we need to register the Worker::Isolate diff --git a/src/workerd/server/workerd-api.c++ b/src/workerd/server/workerd-api.c++ index ceb1ca79cce..b459fe71a2c 100644 --- a/src/workerd/server/workerd-api.c++ +++ b/src/workerd/server/workerd-api.c++ @@ -132,7 +132,6 @@ static const PythonConfig defaultConfig{ struct WorkerdApi::Impl final { kj::Own features; kj::Maybe> maybeOwnedModuleRegistry; - kj::Own limitEnforcer; kj::Own observer; JsgWorkerdIsolate jsgIsolate; api::MemoryCacheProvider& memoryCacheProvider; @@ -160,19 +159,15 @@ struct WorkerdApi::Impl final { Impl(jsg::V8System& v8System, CompatibilityFlags::Reader featuresParam, - kj::Own limitEnforcerParam, + v8::Isolate::CreateParams createParams, kj::Own observerParam, api::MemoryCacheProvider& memoryCacheProvider, const PythonConfig& pythonConfig = defaultConfig, kj::Maybe> newModuleRegistry = kj::none) : features(capnp::clone(featuresParam)), maybeOwnedModuleRegistry(kj::mv(newModuleRegistry)), - limitEnforcer(kj::mv(limitEnforcerParam)), observer(kj::atomicAddRef(*observerParam)), - jsgIsolate(v8System, - Configuration(*this), - kj::mv(observerParam), - limitEnforcer->getCreateParams()), + jsgIsolate(v8System, Configuration(*this), kj::mv(observerParam), kj::mv(createParams)), memoryCacheProvider(memoryCacheProvider), pythonConfig(pythonConfig) { jsgIsolate.runInLockScope( @@ -219,14 +214,14 @@ struct WorkerdApi::Impl final { WorkerdApi::WorkerdApi(jsg::V8System& v8System, CompatibilityFlags::Reader features, - kj::Own limitEnforcer, + v8::Isolate::CreateParams createParams, kj::Own observer, api::MemoryCacheProvider& memoryCacheProvider, const PythonConfig& pythonConfig, kj::Maybe> newModuleRegistry) : impl(kj::heap(v8System, features, - kj::mv(limitEnforcer), + kj::mv(createParams), kj::mv(observer), memoryCacheProvider, pythonConfig, @@ -276,14 +271,6 @@ jsg::JsObject WorkerdApi::wrapExecutionContext( kj::downcast(lock).wrap(lock.v8Context(), kj::mv(ref))); } -IsolateLimitEnforcer& WorkerdApi::getLimitEnforcer() { - return *impl->limitEnforcer; -} - -const IsolateLimitEnforcer& WorkerdApi::getLimitEnforcer() const { - return *impl->limitEnforcer; -} - IsolateObserver& WorkerdApi::getMetrics() { return *impl->observer; } @@ -292,6 +279,9 @@ const IsolateObserver& WorkerdApi::getMetrics() const { return *impl->observer; } +void WorkerdApi::setEnforcer(IsolateLimitEnforcer&) {} +void WorkerdApi::invalidateEnforcer() {} + Worker::Script::Source WorkerdApi::extractSource(kj::StringPtr name, config::Worker::Reader conf, Worker::ValidationErrorReporter& errorReporter, diff --git a/src/workerd/server/workerd-api.h b/src/workerd/server/workerd-api.h index bec54bbd8a5..d1d3f1f8de2 100644 --- a/src/workerd/server/workerd-api.h +++ b/src/workerd/server/workerd-api.h @@ -34,7 +34,7 @@ class WorkerdApi final: public Worker::Api { public: WorkerdApi(jsg::V8System& v8System, CompatibilityFlags::Reader features, - kj::Own limitEnforcer, + v8::Isolate::CreateParams createParams, kj::Own observer, api::MemoryCacheProvider& memoryCacheProvider, const PythonConfig& pythonConfig, @@ -55,10 +55,10 @@ class WorkerdApi final: public Worker::Api { jsg::Lock& lock) const override; jsg::JsObject wrapExecutionContext( jsg::Lock& lock, jsg::Ref ref) const override; - IsolateLimitEnforcer& getLimitEnforcer() override; - const IsolateLimitEnforcer& getLimitEnforcer() const override; IsolateObserver& getMetrics() override; const IsolateObserver& getMetrics() const override; + void setEnforcer(IsolateLimitEnforcer&) override; + void invalidateEnforcer() override; static Worker::Script::Source extractSource(kj::StringPtr name, config::Worker::Reader conf, diff --git a/src/workerd/tests/test-fixture.c++ b/src/workerd/tests/test-fixture.c++ index 4be9020526b..755a242487b 100644 --- a/src/workerd/tests/test-fixture.c++ +++ b/src/workerd/tests/test-fixture.c++ @@ -323,13 +323,15 @@ TestFixture::TestFixture(SetupParams&& params) memoryCacheProvider(kj::heap(*timer)), api(kj::heap(testV8System, params.featureFlags.orDefault(CompatibilityFlags::Reader()), - kj::heap(), + kj::heap()->getCreateParams(), kj::atomicRefcounted(), *memoryCacheProvider, defaultPythonConfig, kj::none)), - workerIsolate(kj::atomicRefcounted( - kj::mv(api), scriptId, Worker::Isolate::InspectorPolicy::DISALLOW)), + workerIsolate(kj::atomicRefcounted(kj::mv(api), + scriptId, + kj::heap(), + Worker::Isolate::InspectorPolicy::DISALLOW)), workerScript(kj::atomicRefcounted(kj::atomicAddRef(*workerIsolate), scriptId, server::WorkerdApi::extractSource(mainModuleName,