diff options
-rw-r--r-- | Libraries/LibJS/AST.cpp | 6 | ||||
-rw-r--r-- | Libraries/LibJS/Forward.h | 1 | ||||
-rw-r--r-- | Libraries/LibJS/Heap/Heap.cpp | 20 | ||||
-rw-r--r-- | Libraries/LibJS/Heap/Heap.h | 5 | ||||
-rw-r--r-- | Libraries/LibJS/Interpreter.cpp | 6 | ||||
-rw-r--r-- | Libraries/LibJS/Interpreter.h | 3 | ||||
-rw-r--r-- | Libraries/LibJS/Makefile | 1 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/ArrayPrototype.cpp | 20 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/FunctionPrototype.cpp | 9 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/MarkedValueList.cpp | 55 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/MarkedValueList.h | 58 | ||||
-rw-r--r-- | Libraries/LibWeb/DOM/Node.cpp | 5 | ||||
-rw-r--r-- | Libraries/LibWeb/DOM/XMLHttpRequest.cpp | 5 |
13 files changed, 178 insertions, 16 deletions
diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 6a254a78df..87989e47bf 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -33,6 +33,7 @@ #include <LibJS/Runtime/Array.h> #include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/GlobalObject.h> +#include <LibJS/Runtime/MarkedValueList.h> #include <LibJS/Runtime/NativeFunction.h> #include <LibJS/Runtime/PrimitiveString.h> #include <LibJS/Runtime/ScriptFunction.h> @@ -112,8 +113,7 @@ Value CallExpression::execute(Interpreter& interpreter) const auto& function = static_cast<Function&>(callee.as_object()); - Vector<Value> arguments; - arguments.ensure_capacity(m_arguments.size()); + MarkedValueList arguments(interpreter.heap()); for (size_t i = 0; i < m_arguments.size(); ++i) { auto value = m_arguments[i].execute(interpreter); if (interpreter.exception()) @@ -125,7 +125,7 @@ Value CallExpression::execute(Interpreter& interpreter) const auto& call_frame = interpreter.push_call_frame(); call_frame.function_name = function.name(); - call_frame.arguments = move(arguments); + call_frame.arguments = arguments.values(); call_frame.environment = function.create_environment(); Object* new_object = nullptr; diff --git a/Libraries/LibJS/Forward.h b/Libraries/LibJS/Forward.h index dccf3347ca..abf94639f9 100644 --- a/Libraries/LibJS/Forward.h +++ b/Libraries/LibJS/Forward.h @@ -63,6 +63,7 @@ class Heap; class HeapBlock; class Interpreter; class LexicalEnvironment; +class MarkedValueList; class PrimitiveString; class ScopeNode; class Shape; diff --git a/Libraries/LibJS/Heap/Heap.cpp b/Libraries/LibJS/Heap/Heap.cpp index 0bb47f0d6b..c36a43e7cf 100644 --- a/Libraries/LibJS/Heap/Heap.cpp +++ b/Libraries/LibJS/Heap/Heap.cpp @@ -30,6 +30,7 @@ #include <LibJS/Heap/Heap.h> #include <LibJS/Heap/HeapBlock.h> #include <LibJS/Interpreter.h> +#include <LibJS/Runtime/MarkedValueList.h> #include <LibJS/Runtime/Object.h> #include <setjmp.h> #include <stdio.h> @@ -104,6 +105,13 @@ void Heap::gather_roots(HashTable<Cell*>& roots) for (auto* handle : m_handles) roots.set(handle->cell()); + for (auto* list : m_marked_value_lists) { + for (auto& value : list->values()) { + if (value.is_cell()) + roots.set(value.as_cell()); + } + } + #ifdef HEAP_DEBUG dbg() << "gather_roots:"; for (auto* root : roots) { @@ -266,6 +274,18 @@ void Heap::did_destroy_handle(Badge<HandleImpl>, HandleImpl& impl) m_handles.remove(&impl); } +void Heap::did_create_marked_value_list(Badge<MarkedValueList>, MarkedValueList& list) +{ + ASSERT(!m_marked_value_lists.contains(&list)); + m_marked_value_lists.set(&list); +} + +void Heap::did_destroy_marked_value_list(Badge<MarkedValueList>, MarkedValueList& list) +{ + ASSERT(m_marked_value_lists.contains(&list)); + m_marked_value_lists.remove(&list); +} + void Heap::defer_gc(Badge<DeferGC>) { ++m_gc_deferrals; diff --git a/Libraries/LibJS/Heap/Heap.h b/Libraries/LibJS/Heap/Heap.h index 5504472107..6544021b5a 100644 --- a/Libraries/LibJS/Heap/Heap.h +++ b/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 did_create_marked_value_list(Badge<MarkedValueList>, MarkedValueList&); + void did_destroy_marked_value_list(Badge<MarkedValueList>, MarkedValueList&); + void defer_gc(Badge<DeferGC>); void undefer_gc(Badge<DeferGC>); @@ -90,6 +93,8 @@ private: Vector<NonnullOwnPtr<HeapBlock>> m_blocks; HashTable<HandleImpl*> m_handles; + HashTable<MarkedValueList*> m_marked_value_lists; + size_t m_gc_deferrals { 0 }; bool m_should_gc_when_deferral_ends { false }; }; diff --git a/Libraries/LibJS/Interpreter.cpp b/Libraries/LibJS/Interpreter.cpp index 24fdb5f49d..3dcc3ec250 100644 --- a/Libraries/LibJS/Interpreter.cpp +++ b/Libraries/LibJS/Interpreter.cpp @@ -30,6 +30,7 @@ #include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/LexicalEnvironment.h> +#include <LibJS/Runtime/MarkedValueList.h> #include <LibJS/Runtime/NativeFunction.h> #include <LibJS/Runtime/Object.h> #include <LibJS/Runtime/Shape.h> @@ -177,12 +178,13 @@ void Interpreter::gather_roots(Badge<Heap>, HashTable<Cell*>& roots) } } -Value Interpreter::call(Function* function, Value this_value, const Vector<Value>& arguments) +Value Interpreter::call(Function* function, Value this_value, Optional<MarkedValueList> arguments) { auto& call_frame = push_call_frame(); call_frame.function_name = function->name(); call_frame.this_value = this_value; - call_frame.arguments = arguments; + if (arguments.has_value()) + call_frame.arguments = arguments.value().values(); call_frame.environment = function->create_environment(); auto result = function->call(*this); pop_call_frame(); diff --git a/Libraries/LibJS/Interpreter.h b/Libraries/LibJS/Interpreter.h index a6f54d97aa..9b32334df8 100644 --- a/Libraries/LibJS/Interpreter.h +++ b/Libraries/LibJS/Interpreter.h @@ -34,6 +34,7 @@ #include <LibJS/Heap/Heap.h> #include <LibJS/Runtime/Exception.h> #include <LibJS/Runtime/LexicalEnvironment.h> +#include <LibJS/Runtime/MarkedValueList.h> #include <LibJS/Runtime/Value.h> namespace JS { @@ -100,7 +101,7 @@ public: void enter_scope(const ScopeNode&, ArgumentVector, ScopeType); void exit_scope(const ScopeNode&); - Value call(Function*, Value this_value = {}, const Vector<Value>& arguments = {}); + Value call(Function*, Value this_value = {}, Optional<MarkedValueList> arguments = {}); CallFrame& push_call_frame() { diff --git a/Libraries/LibJS/Makefile b/Libraries/LibJS/Makefile index 3e924b8dac..686110098c 100644 --- a/Libraries/LibJS/Makefile +++ b/Libraries/LibJS/Makefile @@ -27,6 +27,7 @@ OBJS = \ Runtime/GlobalObject.o \ Runtime/LexicalEnvironment.o \ Runtime/MathObject.o \ + Runtime/MarkedValueList.o \ Runtime/NativeFunction.o \ Runtime/NativeProperty.o \ Runtime/NumberConstructor.o \ diff --git a/Libraries/LibJS/Runtime/ArrayPrototype.cpp b/Libraries/LibJS/Runtime/ArrayPrototype.cpp index d59c939128..fc38b71acb 100644 --- a/Libraries/LibJS/Runtime/ArrayPrototype.cpp +++ b/Libraries/LibJS/Runtime/ArrayPrototype.cpp @@ -34,6 +34,7 @@ #include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Function.h> #include <LibJS/Runtime/GlobalObject.h> +#include <LibJS/Runtime/MarkedValueList.h> #include <LibJS/Runtime/Value.h> namespace JS { @@ -96,13 +97,18 @@ Value ArrayPrototype::filter(Interpreter& interpreter) auto this_value = interpreter.argument(1); auto initial_array_size = array->elements().size(); auto* new_array = Array::create(interpreter.global_object()); + for (size_t i = 0; i < initial_array_size; ++i) { if (i >= array->elements().size()) break; auto value = array->elements()[i]; if (value.is_empty()) continue; - auto result = interpreter.call(callback, this_value, { value, Value((i32)i), array }); + MarkedValueList arguments(interpreter.heap()); + arguments.append(value); + arguments.append(Value((i32)i)); + arguments.append(array); + auto result = interpreter.call(callback, this_value, move(arguments)); if (interpreter.exception()) return {}; if (result.to_boolean()) @@ -127,7 +133,11 @@ Value ArrayPrototype::for_each(Interpreter& interpreter) auto value = array->elements()[i]; if (value.is_empty()) continue; - interpreter.call(callback, this_value, { value, Value((i32)i), array }); + MarkedValueList arguments(interpreter.heap()); + arguments.append(value); + arguments.append(Value((i32)i)); + arguments.append(array); + interpreter.call(callback, this_value, move(arguments)); if (interpreter.exception()) return {}; } @@ -151,7 +161,11 @@ Value ArrayPrototype::map(Interpreter& interpreter) auto value = array->elements()[i]; if (value.is_empty()) continue; - auto result = interpreter.call(callback, this_value, { value, Value((i32)i), array }); + MarkedValueList arguments(interpreter.heap()); + arguments.append(value); + arguments.append(Value((i32)i)); + arguments.append(array); + auto result = interpreter.call(callback, this_value, move(arguments)); if (interpreter.exception()) return {}; new_array->elements().append(result); diff --git a/Libraries/LibJS/Runtime/FunctionPrototype.cpp b/Libraries/LibJS/Runtime/FunctionPrototype.cpp index 69a6c24934..7b44c4e2e1 100644 --- a/Libraries/LibJS/Runtime/FunctionPrototype.cpp +++ b/Libraries/LibJS/Runtime/FunctionPrototype.cpp @@ -32,6 +32,7 @@ #include <LibJS/Runtime/Function.h> #include <LibJS/Runtime/FunctionPrototype.h> #include <LibJS/Runtime/GlobalObject.h> +#include <LibJS/Runtime/MarkedValueList.h> #include <LibJS/Runtime/ScriptFunction.h> namespace JS { @@ -72,10 +73,10 @@ Value FunctionPrototype::apply(Interpreter& interpreter) auto length_property = arg_array.as_object().get("length"); if (length_property.has_value()) length = length_property.value().to_number().to_i32(); - Vector<Value> arguments; + MarkedValueList arguments(interpreter.heap()); for (size_t i = 0; i < length; ++i) arguments.append(arg_array.as_object().get(String::number(i)).value_or(js_undefined())); - return interpreter.call(function, this_arg, arguments); + return interpreter.call(function, this_arg, move(arguments)); } Value FunctionPrototype::bind(Interpreter& interpreter) @@ -96,12 +97,12 @@ Value FunctionPrototype::call(Interpreter& interpreter) return interpreter.throw_exception<TypeError>("Not a Function object"); auto function = static_cast<Function*>(this_object); auto this_arg = interpreter.argument(0); - Vector<Value> arguments; + MarkedValueList arguments(interpreter.heap()); if (interpreter.argument_count() > 1) { for (size_t i = 1; i < interpreter.argument_count(); ++i) arguments.append(interpreter.argument(i)); } - return interpreter.call(function, this_arg, arguments); + return interpreter.call(function, this_arg, move(arguments)); } Value FunctionPrototype::to_string(Interpreter& interpreter) diff --git a/Libraries/LibJS/Runtime/MarkedValueList.cpp b/Libraries/LibJS/Runtime/MarkedValueList.cpp new file mode 100644 index 0000000000..5980ed84bc --- /dev/null +++ b/Libraries/LibJS/Runtime/MarkedValueList.cpp @@ -0,0 +1,55 @@ +/* + * 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 <LibJS/Heap/Heap.h> +#include <LibJS/Runtime/MarkedValueList.h> + +namespace JS { + +MarkedValueList::MarkedValueList(Heap& heap) + : m_heap(heap) +{ + m_heap.did_create_marked_value_list({}, *this); +} + +MarkedValueList:: MarkedValueList(MarkedValueList&& other) + : m_heap(other.m_heap) + , m_values(move(other.m_values)) +{ + m_heap.did_create_marked_value_list({}, *this); +} + +MarkedValueList::~MarkedValueList() +{ + m_heap.did_destroy_marked_value_list({}, *this); +} + +void MarkedValueList::append(Value value) +{ + m_values.append(value); +} + +} diff --git a/Libraries/LibJS/Runtime/MarkedValueList.h b/Libraries/LibJS/Runtime/MarkedValueList.h new file mode 100644 index 0000000000..d9c262ed65 --- /dev/null +++ b/Libraries/LibJS/Runtime/MarkedValueList.h @@ -0,0 +1,58 @@ +/* + * 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/Vector.h> +#include <LibJS/Forward.h> +#include <LibJS/Runtime/Value.h> + +namespace JS { + +class MarkedValueList { + AK_MAKE_NONCOPYABLE(MarkedValueList); + +public: + explicit MarkedValueList(Heap&); + MarkedValueList(MarkedValueList&&); + ~MarkedValueList(); + + MarkedValueList& operator=(MarkedValueList&&) = delete; + + bool is_empty() const { return m_values.is_empty(); } + size_t size() const { return m_values.size(); } + void clear() { m_values.clear(); } + Vector<Value, 32>& values() { return m_values; } + + void append(Value); + +private: + Heap& m_heap; + Vector<Value, 32> m_values; +}; + +} diff --git a/Libraries/LibWeb/DOM/Node.cpp b/Libraries/LibWeb/DOM/Node.cpp index 97120bb380..b8c1636380 100644 --- a/Libraries/LibWeb/DOM/Node.cpp +++ b/Libraries/LibWeb/DOM/Node.cpp @@ -28,6 +28,7 @@ #include <LibJS/AST.h> #include <LibJS/Interpreter.h> #include <LibJS/Runtime/Function.h> +#include <LibJS/Runtime/MarkedValueList.h> #include <LibJS/Runtime/ScriptFunction.h> #include <LibWeb/Bindings/EventWrapper.h> #include <LibWeb/Bindings/NodeWrapper.h> @@ -142,7 +143,9 @@ void Node::dispatch_event(NonnullRefPtr<Event> event) dbg() << "calling event listener with this=" << this_value; #endif auto* event_wrapper = wrap(function->heap(), *event); - document().interpreter().call(function, this_value, { event_wrapper }); + JS::MarkedValueList arguments(function->heap()); + arguments.append(event_wrapper); + document().interpreter().call(function, this_value, move(arguments)); } } diff --git a/Libraries/LibWeb/DOM/XMLHttpRequest.cpp b/Libraries/LibWeb/DOM/XMLHttpRequest.cpp index 82caf5b71b..757ce79bb3 100644 --- a/Libraries/LibWeb/DOM/XMLHttpRequest.cpp +++ b/Libraries/LibWeb/DOM/XMLHttpRequest.cpp @@ -83,8 +83,9 @@ void XMLHttpRequest::dispatch_event(NonnullRefPtr<Event> event) if (listener.event_name == event->name()) { auto* function = const_cast<EventListener&>(*listener.listener).function(); auto* this_value = wrap(function->heap(), *this); - auto* event_wrapper = wrap(function->heap(), *event); - function->interpreter().call(function, this_value, { event_wrapper }); + JS::MarkedValueList arguments(function->heap()); + arguments.append(wrap(function->heap(), *event)); + function->interpreter().call(function, this_value, move(arguments)); } } } |