mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 20:15:17 +00:00
LibJS: Add a basic mark&sweep garbage collector :^)
Objects can now be allocated via the interpreter's heap. Objects that are allocated in this way will need to be provably reachable from at least one of the known object graph roots. The roots are currently determined by Heap::collect_roots(). Anything that wants be collectable garbage should inherit from Cell, the fundamental atom of the GC heap. This is pretty neat! :^)
This commit is contained in:
parent
6da131d5db
commit
63e4b744ed
Notes:
sideshowbarker
2024-07-19 08:49:34 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/63e4b744ed1
13 changed files with 498 additions and 6 deletions
|
@ -39,7 +39,7 @@ Value ScopeNode::execute(Interpreter& interpreter) const
|
|||
|
||||
Value FunctionDeclaration::execute(Interpreter& interpreter) const
|
||||
{
|
||||
auto* function = new Function(name(), body());
|
||||
auto* function = interpreter.heap().allocate<Function>(name(), body());
|
||||
interpreter.global_object().put(m_name, Value(function));
|
||||
return Value(function);
|
||||
}
|
||||
|
|
39
Libraries/LibJS/Cell.cpp
Normal file
39
Libraries/LibJS/Cell.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <AK/LogStream.h>
|
||||
#include <LibJS/Cell.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
const LogStream& operator<<(const LogStream& stream, const Cell* cell)
|
||||
{
|
||||
if (!cell)
|
||||
return stream << "Cell{nullptr}";
|
||||
return stream << cell->class_name() << '{' << static_cast<const void*>(cell) << '}';
|
||||
}
|
||||
|
||||
}
|
62
Libraries/LibJS/Cell.h
Normal file
62
Libraries/LibJS/Cell.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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 <AK/Forward.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class Cell {
|
||||
public:
|
||||
virtual ~Cell() {}
|
||||
|
||||
bool is_marked() const { return m_mark; }
|
||||
void set_marked(bool b) { m_mark = b; }
|
||||
|
||||
bool is_live() const { return m_live; }
|
||||
void set_live(bool b) { m_live = b; }
|
||||
|
||||
virtual const char* class_name() const = 0;
|
||||
|
||||
class Visitor {
|
||||
public:
|
||||
virtual void did_visit(Cell*) = 0;
|
||||
};
|
||||
|
||||
virtual void visit_graph(Visitor& visitor)
|
||||
{
|
||||
visitor.did_visit(this);
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_mark { false };
|
||||
bool m_live { true };
|
||||
};
|
||||
|
||||
const LogStream& operator<<(const LogStream&, const Cell*);
|
||||
|
||||
}
|
|
@ -29,6 +29,9 @@
|
|||
namespace JS {
|
||||
|
||||
class ASTNode;
|
||||
class Cell;
|
||||
class Heap;
|
||||
class HeapBlock;
|
||||
class Interpreter;
|
||||
class Object;
|
||||
class ScopeNode;
|
||||
|
|
160
Libraries/LibJS/Heap.cpp
Normal file
160
Libraries/LibJS/Heap.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <AK/HashTable.h>
|
||||
#include <LibJS/Heap.h>
|
||||
#include <LibJS/HeapBlock.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Object.h>
|
||||
|
||||
#define HEAP_DEBUG
|
||||
|
||||
namespace JS {
|
||||
|
||||
Heap::Heap(Interpreter& interpreter)
|
||||
: m_interpreter(interpreter)
|
||||
{
|
||||
}
|
||||
|
||||
Heap::~Heap()
|
||||
{
|
||||
}
|
||||
|
||||
Cell* Heap::allocate_cell(size_t size)
|
||||
{
|
||||
for (auto& block : m_blocks) {
|
||||
if (size > block->cell_size())
|
||||
continue;
|
||||
if (auto* cell = block->allocate())
|
||||
return cell;
|
||||
}
|
||||
|
||||
auto* block = (HeapBlock*)malloc(HeapBlock::block_size);
|
||||
new (block) HeapBlock(size);
|
||||
m_blocks.append(NonnullOwnPtr<HeapBlock>(NonnullOwnPtr<HeapBlock>::Adopt, *block));
|
||||
return block->allocate();
|
||||
}
|
||||
|
||||
void Heap::collect_garbage()
|
||||
{
|
||||
HashTable<Cell*> roots;
|
||||
collect_roots(roots);
|
||||
|
||||
HashTable<Cell*> live_cells;
|
||||
visit_live_cells(roots, live_cells);
|
||||
|
||||
clear_all_mark_bits();
|
||||
mark_live_cells(live_cells);
|
||||
sweep_dead_cells();
|
||||
}
|
||||
|
||||
void Heap::collect_roots(HashTable<Cell*>& roots)
|
||||
{
|
||||
roots.set(&m_interpreter.global_object());
|
||||
|
||||
#ifdef HEAP_DEBUG
|
||||
dbg() << "collect_roots:";
|
||||
for (auto* root : roots) {
|
||||
dbg() << " + " << root;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
class LivenessVisitor final : public Cell::Visitor {
|
||||
public:
|
||||
LivenessVisitor(HashTable<Cell*>& live_cells)
|
||||
: m_live_cells(live_cells)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void did_visit(Cell* cell) override
|
||||
{
|
||||
m_live_cells.set(cell);
|
||||
}
|
||||
|
||||
private:
|
||||
HashTable<Cell*>& m_live_cells;
|
||||
};
|
||||
|
||||
void Heap::visit_live_cells(const HashTable<Cell*>& roots, HashTable<Cell*>& live_cells)
|
||||
{
|
||||
LivenessVisitor visitor(live_cells);
|
||||
for (auto* root : roots) {
|
||||
root->visit_graph(visitor);
|
||||
}
|
||||
|
||||
#ifdef HEAP_DEBUG
|
||||
dbg() << "visit_live_cells:";
|
||||
for (auto* cell : live_cells) {
|
||||
dbg() << " @ " << cell;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Heap::clear_all_mark_bits()
|
||||
{
|
||||
for (auto& block : m_blocks) {
|
||||
block->for_each_cell([&](Cell* cell) {
|
||||
cell->set_marked(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Heap::mark_live_cells(const HashTable<Cell*>& live_cells)
|
||||
{
|
||||
#ifdef HEAP_DEBUG
|
||||
dbg() << "mark_live_cells:";
|
||||
#endif
|
||||
for (auto& block : m_blocks) {
|
||||
block->for_each_cell([&](Cell* cell) {
|
||||
if (live_cells.contains(cell)) {
|
||||
#ifdef HEAP_DEBUG
|
||||
dbg() << " ! " << cell;
|
||||
#endif
|
||||
cell->set_marked(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Heap::sweep_dead_cells()
|
||||
{
|
||||
#ifdef HEAP_DEBUG
|
||||
dbg() << "sweep_dead_cells:";
|
||||
#endif
|
||||
for (auto& block : m_blocks) {
|
||||
block->for_each_cell([&](Cell* cell) {
|
||||
if (cell->is_live() && !cell->is_marked()) {
|
||||
#ifdef HEAP_DEBUG
|
||||
dbg() << " ~ " << cell;
|
||||
#endif
|
||||
block->deallocate(cell);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
69
Libraries/LibJS/Heap.h
Normal file
69
Libraries/LibJS/Heap.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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 <AK/Noncopyable.h>
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <AK/Types.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibJS/Cell.h>
|
||||
#include <LibJS/Forward.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class Heap {
|
||||
AK_MAKE_NONCOPYABLE(Heap);
|
||||
AK_MAKE_NONMOVABLE(Heap);
|
||||
|
||||
public:
|
||||
explicit Heap(Interpreter&);
|
||||
~Heap();
|
||||
|
||||
template<typename T, typename... Args>
|
||||
T* allocate(Args&&... args)
|
||||
{
|
||||
auto* memory = allocate_cell(sizeof(T));
|
||||
new (memory) T(forward<Args>(args)...);
|
||||
return static_cast<T*>(memory);
|
||||
}
|
||||
|
||||
void collect_garbage();
|
||||
|
||||
private:
|
||||
Cell* allocate_cell(size_t);
|
||||
|
||||
void collect_roots(HashTable<Cell*>&);
|
||||
void visit_live_cells(const HashTable<Cell*>& roots, HashTable<Cell*>& live_cells);
|
||||
void clear_all_mark_bits();
|
||||
void mark_live_cells(const HashTable<Cell*>& live_cells);
|
||||
void sweep_dead_cells();
|
||||
|
||||
Interpreter& m_interpreter;
|
||||
Vector<NonnullOwnPtr<HeapBlock>> m_blocks;
|
||||
};
|
||||
|
||||
}
|
64
Libraries/LibJS/HeapBlock.cpp
Normal file
64
Libraries/LibJS/HeapBlock.cpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <LibJS/HeapBlock.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
HeapBlock::HeapBlock(size_t cell_size)
|
||||
: m_cell_size(cell_size)
|
||||
{
|
||||
for (size_t i = 0; i < cell_count(); ++i) {
|
||||
auto* freelist_entry = static_cast<FreelistEntry*>(cell(i));
|
||||
freelist_entry->set_live(false);
|
||||
if (i == cell_count() - 1)
|
||||
freelist_entry->next = nullptr;
|
||||
else
|
||||
freelist_entry->next = static_cast<FreelistEntry*>(cell(i + 1));
|
||||
}
|
||||
m_freelist = static_cast<FreelistEntry*>(cell(0));
|
||||
}
|
||||
|
||||
Cell* HeapBlock::allocate()
|
||||
{
|
||||
if (!m_freelist)
|
||||
return nullptr;
|
||||
return exchange(m_freelist, m_freelist->next);
|
||||
}
|
||||
|
||||
void HeapBlock::deallocate(Cell* cell)
|
||||
{
|
||||
ASSERT(cell->is_live());
|
||||
ASSERT(!cell->is_marked());
|
||||
cell->~Cell();
|
||||
auto* freelist_entry = static_cast<FreelistEntry*>(cell);
|
||||
freelist_entry->set_live(false);
|
||||
freelist_entry->next = m_freelist;
|
||||
m_freelist = freelist_entry;
|
||||
}
|
||||
|
||||
}
|
66
Libraries/LibJS/HeapBlock.h
Normal file
66
Libraries/LibJS/HeapBlock.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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 <AK/Types.h>
|
||||
#include <LibJS/Cell.h>
|
||||
#include <LibJS/Forward.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class HeapBlock {
|
||||
public:
|
||||
static constexpr size_t block_size = 16 * KB;
|
||||
|
||||
explicit HeapBlock(size_t cell_size);
|
||||
|
||||
size_t cell_size() const { return m_cell_size; }
|
||||
size_t cell_count() const { return (block_size - sizeof(HeapBlock)) / m_cell_size; }
|
||||
|
||||
Cell* cell(size_t index) { return reinterpret_cast<Cell*>(&m_storage[index * cell_size()]); }
|
||||
|
||||
Cell* allocate();
|
||||
void deallocate(Cell*);
|
||||
|
||||
template<typename Callback>
|
||||
void for_each_cell(Callback callback)
|
||||
{
|
||||
for (size_t i = 0; i < cell_count(); ++i)
|
||||
callback(cell(i));
|
||||
}
|
||||
|
||||
private:
|
||||
struct FreelistEntry : public Cell {
|
||||
FreelistEntry* next;
|
||||
};
|
||||
|
||||
size_t m_cell_size { 0 };
|
||||
FreelistEntry* m_freelist { nullptr };
|
||||
u8 m_storage[];
|
||||
};
|
||||
|
||||
}
|
|
@ -32,8 +32,9 @@
|
|||
namespace JS {
|
||||
|
||||
Interpreter::Interpreter()
|
||||
: m_heap(*this)
|
||||
{
|
||||
m_global_object = new Object;
|
||||
m_global_object = heap().allocate<Object>();
|
||||
}
|
||||
|
||||
Interpreter::~Interpreter()
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include <AK/Vector.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
|
@ -45,12 +46,16 @@ public:
|
|||
Object& global_object() { return *m_global_object; }
|
||||
const Object& global_object() const { return *m_global_object; }
|
||||
|
||||
Heap& heap() { return m_heap; }
|
||||
|
||||
void do_return();
|
||||
|
||||
private:
|
||||
void enter_scope(const ScopeNode&);
|
||||
void exit_scope(const ScopeNode&);
|
||||
|
||||
Heap m_heap;
|
||||
|
||||
Vector<ScopeFrame> m_scope_stack;
|
||||
|
||||
Object* m_global_object { nullptr };
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
OBJS = \
|
||||
AST.o \
|
||||
Cell.o \
|
||||
Function.o \
|
||||
Heap.o \
|
||||
HeapBlock.o \
|
||||
Interpreter.o \
|
||||
Object.o \
|
||||
Value.o
|
||||
|
|
|
@ -30,6 +30,14 @@
|
|||
|
||||
namespace JS {
|
||||
|
||||
Object::Object()
|
||||
{
|
||||
}
|
||||
|
||||
Object::~Object()
|
||||
{
|
||||
}
|
||||
|
||||
Value Object::get(String property_name) const
|
||||
{
|
||||
return m_properties.get(property_name).value_or(js_undefined());
|
||||
|
@ -40,4 +48,13 @@ void Object::put(String property_name, Value value)
|
|||
m_properties.set(property_name, move(value));
|
||||
}
|
||||
|
||||
void Object::visit_graph(Cell::Visitor& visitor)
|
||||
{
|
||||
Cell::visit_graph(visitor);
|
||||
for (auto& it : m_properties) {
|
||||
if (it.value.is_object())
|
||||
it.value.as_object()->visit_graph(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,21 +27,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <LibJS/Cell.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Cell.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class Object {
|
||||
class Object : public Cell {
|
||||
public:
|
||||
Object() {}
|
||||
virtual ~Object() {}
|
||||
Object();
|
||||
virtual ~Object();
|
||||
|
||||
Value get(String property_name) const;
|
||||
void put(String property_name, Value);
|
||||
|
||||
virtual bool is_function() const { return false; }
|
||||
|
||||
virtual const char* class_name() const { return "Object"; }
|
||||
virtual const char* class_name() const override { return "Object"; }
|
||||
virtual void visit_graph(Cell::Visitor&) override;
|
||||
|
||||
private:
|
||||
HashMap<String, Value> m_properties;
|
||||
|
|
Loading…
Add table
Reference in a new issue