Pārlūkot izejas kodu

LibJS: Stop having AsyncFunctionDriverWrapper leak itself

Async functions whose promise is never resolved were leaking, since they
had a strong root JS::Handle on themselves.

This doesn't appear to actually be necessary, since the wrapper will be
kept alive as long as it's reachable (and if it's not reachable, nobody
is going to resolve/reject the promise either).

This fixes the vast majority of leaks on Speedometer, bringing memory
usage at the end of a full run from ~12 GiB to ~3 GiB.
Andreas Kling 8 mēneši atpakaļ
vecāks
revīzija
b6a5b7e186

+ 1 - 10
Libraries/LibJS/Runtime/AsyncFunctionDriverWrapper.cpp

@@ -20,8 +20,7 @@ JS_DEFINE_ALLOCATOR(AsyncFunctionDriverWrapper);
 NonnullGCPtr<Promise> AsyncFunctionDriverWrapper::create(Realm& realm, GeneratorObject* generator_object)
 NonnullGCPtr<Promise> AsyncFunctionDriverWrapper::create(Realm& realm, GeneratorObject* generator_object)
 {
 {
     auto top_level_promise = Promise::create(realm);
     auto top_level_promise = Promise::create(realm);
-    // Note: This generates a handle to itself, which it clears upon completing its execution
-    //       The top_level_promise is also kept alive by this Wrapper
+    // Note: The top_level_promise is also kept alive by this Wrapper
     auto wrapper = realm.heap().allocate<AsyncFunctionDriverWrapper>(realm, realm, *generator_object, *top_level_promise);
     auto wrapper = realm.heap().allocate<AsyncFunctionDriverWrapper>(realm, realm, *generator_object, *top_level_promise);
     // Prime the generator:
     // Prime the generator:
     // This runs until the first `await value;`
     // This runs until the first `await value;`
@@ -34,7 +33,6 @@ AsyncFunctionDriverWrapper::AsyncFunctionDriverWrapper(Realm& realm, NonnullGCPt
     : Promise(realm.intrinsics().promise_prototype())
     : Promise(realm.intrinsics().promise_prototype())
     , m_generator_object(generator_object)
     , m_generator_object(generator_object)
     , m_top_level_promise(top_level_promise)
     , m_top_level_promise(top_level_promise)
-    , m_self_handle(make_handle(*this))
 {
 {
 }
 }
 
 
@@ -140,10 +138,6 @@ void AsyncFunctionDriverWrapper::continue_async_execution(VM& vm, Value value, b
             auto promise_value = TRY(result.get(vm, vm.names.value));
             auto promise_value = TRY(result.get(vm, vm.names.value));
 
 
             if (TRY(result.get(vm, vm.names.done)).to_boolean()) {
             if (TRY(result.get(vm, vm.names.done)).to_boolean()) {
-
-                // We should not execute anymore, so we are safe to allow ourselves to be GC'd.
-                m_self_handle = {};
-
                 // When returning a promise, we need to unwrap it.
                 // When returning a promise, we need to unwrap it.
                 if (promise_value.is_object() && is<Promise>(promise_value.as_object())) {
                 if (promise_value.is_object() && is<Promise>(promise_value.as_object())) {
                     auto& returned_promise = static_cast<Promise&>(promise_value.as_object());
                     auto& returned_promise = static_cast<Promise&>(promise_value.as_object());
@@ -175,9 +169,6 @@ void AsyncFunctionDriverWrapper::continue_async_execution(VM& vm, Value value, b
 
 
     if (result.is_throw_completion()) {
     if (result.is_throw_completion()) {
         m_top_level_promise->reject(result.throw_completion().value().value_or(js_undefined()));
         m_top_level_promise->reject(result.throw_completion().value().value_or(js_undefined()));
-
-        // We should not execute anymore, so we are safe to allow our selfs to be GC'd
-        m_self_handle = {};
     }
     }
 
 
     // For the initial execution, the execution context will be popped for us later on by ECMAScriptFunctionObject.
     // For the initial execution, the execution context will be popped for us later on by ECMAScriptFunctionObject.

+ 0 - 1
Libraries/LibJS/Runtime/AsyncFunctionDriverWrapper.h

@@ -38,7 +38,6 @@ private:
     NonnullGCPtr<GeneratorObject> m_generator_object;
     NonnullGCPtr<GeneratorObject> m_generator_object;
     NonnullGCPtr<Promise> m_top_level_promise;
     NonnullGCPtr<Promise> m_top_level_promise;
     GCPtr<Promise> m_current_promise { nullptr };
     GCPtr<Promise> m_current_promise { nullptr };
-    Handle<AsyncFunctionDriverWrapper> m_self_handle;
     OwnPtr<ExecutionContext> m_suspended_execution_context;
     OwnPtr<ExecutionContext> m_suspended_execution_context;
 };
 };