瀏覽代碼

LibJS: Add DeferGC, a RAII way to prevent GC temporarily

Andreas Kling 5 年之前
父節點
當前提交
2a9e29fbb8
共有 4 個文件被更改,包括 78 次插入0 次删除
  1. 1 0
      Libraries/LibJS/Forward.h
  2. 50 0
      Libraries/LibJS/Heap/DeferGC.h
  3. 21 0
      Libraries/LibJS/Heap/Heap.cpp
  4. 6 0
      Libraries/LibJS/Heap/Heap.h

+ 1 - 0
Libraries/LibJS/Forward.h

@@ -53,6 +53,7 @@ namespace JS {
 
 class ASTNode;
 class Cell;
+class DeferGC;
 class Error;
 class Exception;
 class Expression;

+ 50 - 0
Libraries/LibJS/Heap/DeferGC.h

@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <LibJS/Heap/Heap.h>
+
+namespace JS {
+
+class DeferGC {
+public:
+    explicit DeferGC(Heap& heap)
+        : m_heap(heap)
+    {
+        m_heap.defer_gc({});
+    }
+
+    ~DeferGC()
+    {
+        m_heap.undefer_gc({});
+    }
+
+private:
+    Heap& m_heap;
+};
+
+}

+ 21 - 0
Libraries/LibJS/Heap/Heap.cpp

@@ -84,6 +84,10 @@ Cell* Heap::allocate_cell(size_t size)
 void Heap::collect_garbage(CollectionType collection_type)
 {
     if (collection_type == CollectionType::CollectGarbage) {
+        if (m_gc_deferrals) {
+            m_should_gc_when_deferral_ends = true;
+            return;
+        }
         HashTable<Cell*> roots;
         gather_roots(roots);
         mark_live_cells(roots);
@@ -262,4 +266,21 @@ void Heap::did_destroy_handle(Badge<HandleImpl>, HandleImpl& impl)
     m_handles.remove(&impl);
 }
 
+void Heap::defer_gc(Badge<DeferGC>)
+{
+    ++m_gc_deferrals;
+}
+
+void Heap::undefer_gc(Badge<DeferGC>)
+{
+    ASSERT(m_gc_deferrals > 0);
+    --m_gc_deferrals;
+
+    if (!m_gc_deferrals) {
+        if (m_should_gc_when_deferral_ends)
+            collect_garbage();
+        m_should_gc_when_deferral_ends = false;
+    }
+}
+
 }

+ 6 - 0
Libraries/LibJS/Heap/Heap.h

@@ -68,6 +68,9 @@ public:
     void did_create_handle(Badge<HandleImpl>, HandleImpl&);
     void did_destroy_handle(Badge<HandleImpl>, HandleImpl&);
 
+    void defer_gc(Badge<DeferGC>);
+    void undefer_gc(Badge<DeferGC>);
+
 private:
     Cell* allocate_cell(size_t);
 
@@ -86,6 +89,9 @@ private:
     Interpreter& m_interpreter;
     Vector<NonnullOwnPtr<HeapBlock>> m_blocks;
     HashTable<HandleImpl*> m_handles;
+
+    size_t m_gc_deferrals { 0 };
+    bool m_should_gc_when_deferral_ends { false };
 };
 
 }