mirror of
https://github.com/RGBCube/serenity
synced 2025-05-16 23:15:07 +00:00
LibJS: Move well-known symbols to the VM
No need to instantiate unique symbols for each Interpreter; they can be VM-global. This reduces the memory cost and startup time anyway.
This commit is contained in:
parent
676cb87a8f
commit
d1b58ee9ad
20 changed files with 60 additions and 52 deletions
|
@ -48,10 +48,6 @@ Interpreter::Interpreter(VM& vm)
|
||||||
: m_vm(vm)
|
: m_vm(vm)
|
||||||
, m_console(*this)
|
, m_console(*this)
|
||||||
{
|
{
|
||||||
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
|
||||||
m_well_known_symbol_##snake_name = js_symbol(*this, "Symbol." #SymbolName, false);
|
|
||||||
JS_ENUMERATE_WELL_KNOWN_SYMBOLS
|
|
||||||
#undef __JS_ENUMERATE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Interpreter::~Interpreter()
|
Interpreter::~Interpreter()
|
||||||
|
@ -212,17 +208,6 @@ Reference Interpreter::get_reference(const FlyString& name)
|
||||||
return { Reference::GlobalVariable, name };
|
return { Reference::GlobalVariable, name };
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol* Interpreter::get_global_symbol(const String& description)
|
|
||||||
{
|
|
||||||
auto result = m_global_symbol_map.get(description);
|
|
||||||
if (result.has_value())
|
|
||||||
return result.value();
|
|
||||||
|
|
||||||
auto new_global_symbol = js_symbol(*this, description, true);
|
|
||||||
m_global_symbol_map.set(description, new_global_symbol);
|
|
||||||
return new_global_symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Interpreter::gather_roots(HashTable<Cell*>& roots)
|
void Interpreter::gather_roots(HashTable<Cell*>& roots)
|
||||||
{
|
{
|
||||||
if (m_last_value.is_cell())
|
if (m_last_value.is_cell())
|
||||||
|
@ -237,14 +222,6 @@ void Interpreter::gather_roots(HashTable<Cell*>& roots)
|
||||||
}
|
}
|
||||||
roots.set(call_frame.environment);
|
roots.set(call_frame.environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
|
||||||
roots.set(well_known_symbol_##snake_name());
|
|
||||||
JS_ENUMERATE_WELL_KNOWN_SYMBOLS
|
|
||||||
#undef __JS_ENUMERATE
|
|
||||||
|
|
||||||
for (auto& symbol : m_global_symbol_map)
|
|
||||||
roots.set(symbol.value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value Interpreter::call_internal(Function& function, Value this_value, Optional<MarkedValueList> arguments)
|
Value Interpreter::call_internal(Function& function, Value this_value, Optional<MarkedValueList> arguments)
|
||||||
|
|
|
@ -134,8 +134,6 @@ public:
|
||||||
|
|
||||||
Reference get_reference(const FlyString& name);
|
Reference get_reference(const FlyString& name);
|
||||||
|
|
||||||
Symbol* get_global_symbol(const String& description);
|
|
||||||
|
|
||||||
void gather_roots(HashTable<Cell*>&);
|
void gather_roots(HashTable<Cell*>&);
|
||||||
|
|
||||||
void enter_scope(const ScopeNode&, ArgumentVector, ScopeType, GlobalObject&);
|
void enter_scope(const ScopeNode&, ArgumentVector, ScopeType, GlobalObject&);
|
||||||
|
@ -228,11 +226,6 @@ public:
|
||||||
const LexicalEnvironment* get_this_environment() const;
|
const LexicalEnvironment* get_this_environment() const;
|
||||||
Value get_new_target() const;
|
Value get_new_target() const;
|
||||||
|
|
||||||
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
|
||||||
Symbol* well_known_symbol_##snake_name() const { return m_well_known_symbol_##snake_name; }
|
|
||||||
JS_ENUMERATE_WELL_KNOWN_SYMBOLS
|
|
||||||
#undef __JS_ENUMERATE
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Interpreter(VM&);
|
explicit Interpreter(VM&);
|
||||||
|
|
||||||
|
@ -253,13 +246,6 @@ private:
|
||||||
bool m_underscore_is_last_value { false };
|
bool m_underscore_is_last_value { false };
|
||||||
|
|
||||||
Console m_console;
|
Console m_console;
|
||||||
|
|
||||||
HashMap<String, Symbol*> m_global_symbol_map;
|
|
||||||
|
|
||||||
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
|
||||||
Symbol* m_well_known_symbol_##snake_name { nullptr };
|
|
||||||
JS_ENUMERATE_WELL_KNOWN_SYMBOLS
|
|
||||||
#undef __JS_ENUMERATE
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
|
@ -43,7 +43,7 @@ void ArrayIteratorPrototype::initialize(GlobalObject& global_object)
|
||||||
Object::initialize(global_object);
|
Object::initialize(global_object);
|
||||||
|
|
||||||
define_native_function("next", next, 0, Attribute::Configurable | Attribute::Writable);
|
define_native_function("next", next, 0, Attribute::Configurable | Attribute::Writable);
|
||||||
define_property(global_object.interpreter().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "Array Iterator"), Attribute::Configurable);
|
define_property(global_object.vm().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "Array Iterator"), Attribute::Configurable);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayIteratorPrototype::~ArrayIteratorPrototype()
|
ArrayIteratorPrototype::~ArrayIteratorPrototype()
|
||||||
|
|
|
@ -80,7 +80,7 @@ void ArrayPrototype::initialize(GlobalObject& global_object)
|
||||||
// Use define_property here instead of define_native_function so that
|
// Use define_property here instead of define_native_function so that
|
||||||
// Object.is(Array.prototype[Symbol.iterator], Array.prototype.values)
|
// Object.is(Array.prototype[Symbol.iterator], Array.prototype.values)
|
||||||
// evaluates to true
|
// evaluates to true
|
||||||
define_property(global_object.interpreter().well_known_symbol_iterator(), get("values"), attr);
|
define_property(global_object.vm().well_known_symbol_iterator(), get("values"), attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayPrototype::~ArrayPrototype()
|
ArrayPrototype::~ArrayPrototype()
|
||||||
|
|
|
@ -45,7 +45,7 @@ void BigIntPrototype::initialize(GlobalObject& global_object)
|
||||||
define_native_function("toLocaleString", to_locale_string, 0, attr);
|
define_native_function("toLocaleString", to_locale_string, 0, attr);
|
||||||
define_native_function("valueOf", value_of, 0, attr);
|
define_native_function("valueOf", value_of, 0, attr);
|
||||||
|
|
||||||
define_property(global_object.interpreter().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "BigInt"), Attribute::Configurable);
|
define_property(global_object.vm().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "BigInt"), Attribute::Configurable);
|
||||||
}
|
}
|
||||||
|
|
||||||
BigIntPrototype::~BigIntPrototype()
|
BigIntPrototype::~BigIntPrototype()
|
||||||
|
|
|
@ -51,7 +51,7 @@ void FunctionPrototype::initialize(GlobalObject& global_object)
|
||||||
define_native_function("bind", bind, 1, attr);
|
define_native_function("bind", bind, 1, attr);
|
||||||
define_native_function("call", call, 1, attr);
|
define_native_function("call", call, 1, attr);
|
||||||
define_native_function("toString", to_string, 0, attr);
|
define_native_function("toString", to_string, 0, attr);
|
||||||
define_native_function(global_object.interpreter().well_known_symbol_has_instance(), symbol_has_instance, 1, 0);
|
define_native_function(global_object.vm().well_known_symbol_has_instance(), symbol_has_instance, 1, 0);
|
||||||
define_property("length", Value(0), Attribute::Configurable);
|
define_property("length", Value(0), Attribute::Configurable);
|
||||||
define_property("name", js_string(heap(), ""), Attribute::Configurable);
|
define_property("name", js_string(heap(), ""), Attribute::Configurable);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ Object* get_iterator(GlobalObject& global_object, Value value, String hint, Valu
|
||||||
auto object = value.to_object(interpreter, global_object);
|
auto object = value.to_object(interpreter, global_object);
|
||||||
if (!object)
|
if (!object)
|
||||||
return {};
|
return {};
|
||||||
method = object->get(interpreter.well_known_symbol_iterator());
|
method = object->get(global_object.vm().well_known_symbol_iterator());
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ IteratorPrototype::IteratorPrototype(GlobalObject& global_object)
|
||||||
void IteratorPrototype::initialize(GlobalObject& global_object)
|
void IteratorPrototype::initialize(GlobalObject& global_object)
|
||||||
{
|
{
|
||||||
Object::initialize(global_object);
|
Object::initialize(global_object);
|
||||||
define_native_function(global_object.interpreter().well_known_symbol_iterator(), symbol_iterator, 0, Attribute::Writable | Attribute::Enumerable);
|
define_native_function(global_object.vm().well_known_symbol_iterator(), symbol_iterator, 0, Attribute::Writable | Attribute::Enumerable);
|
||||||
}
|
}
|
||||||
|
|
||||||
IteratorPrototype::~IteratorPrototype()
|
IteratorPrototype::~IteratorPrototype()
|
||||||
|
|
|
@ -49,7 +49,7 @@ void JSONObject::initialize(GlobalObject& global_object)
|
||||||
define_native_function("stringify", stringify, 3, attr);
|
define_native_function("stringify", stringify, 3, attr);
|
||||||
define_native_function("parse", parse, 2, attr);
|
define_native_function("parse", parse, 2, attr);
|
||||||
|
|
||||||
define_property(global_object.interpreter().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "JSON"), Attribute::Configurable);
|
define_property(global_object.vm().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "JSON"), Attribute::Configurable);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject::~JSONObject()
|
JSONObject::~JSONObject()
|
||||||
|
|
|
@ -75,7 +75,7 @@ void MathObject::initialize(GlobalObject& global_object)
|
||||||
define_property("SQRT1_2", Value(M_SQRT1_2), 0);
|
define_property("SQRT1_2", Value(M_SQRT1_2), 0);
|
||||||
define_property("SQRT2", Value(M_SQRT2), 0);
|
define_property("SQRT2", Value(M_SQRT2), 0);
|
||||||
|
|
||||||
define_property(global_object.interpreter().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "Math"), Attribute::Configurable);
|
define_property(global_object.vm().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "Math"), Attribute::Configurable);
|
||||||
}
|
}
|
||||||
|
|
||||||
MathObject::~MathObject()
|
MathObject::~MathObject()
|
||||||
|
|
|
@ -80,7 +80,7 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_string)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
String tag;
|
String tag;
|
||||||
auto to_string_tag = this_object->get(global_object.interpreter().well_known_symbol_to_string_tag());
|
auto to_string_tag = this_object->get(global_object.vm().well_known_symbol_to_string_tag());
|
||||||
|
|
||||||
if (to_string_tag.is_string()) {
|
if (to_string_tag.is_string()) {
|
||||||
tag = to_string_tag.as_string().string();
|
tag = to_string_tag.as_string().string();
|
||||||
|
|
|
@ -43,7 +43,7 @@ void StringIteratorPrototype::initialize(GlobalObject& global_object)
|
||||||
Object::initialize(global_object);
|
Object::initialize(global_object);
|
||||||
|
|
||||||
define_native_function("next", next, 0, Attribute::Configurable | Attribute::Writable);
|
define_native_function("next", next, 0, Attribute::Configurable | Attribute::Writable);
|
||||||
define_property(global_object.interpreter().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "String Iterator"), Attribute::Configurable);
|
define_property(global_object.vm().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "String Iterator"), Attribute::Configurable);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringIteratorPrototype::~StringIteratorPrototype()
|
StringIteratorPrototype::~StringIteratorPrototype()
|
||||||
|
|
|
@ -89,7 +89,7 @@ void StringPrototype::initialize(GlobalObject& global_object)
|
||||||
define_native_function("includes", includes, 1, attr);
|
define_native_function("includes", includes, 1, attr);
|
||||||
define_native_function("slice", slice, 2, attr);
|
define_native_function("slice", slice, 2, attr);
|
||||||
define_native_function("lastIndexOf", last_index_of, 1, attr);
|
define_native_function("lastIndexOf", last_index_of, 1, attr);
|
||||||
define_native_function(global_object.interpreter().well_known_symbol_iterator(), symbol_iterator, 0, attr);
|
define_native_function(global_object.vm().well_known_symbol_iterator(), symbol_iterator, 0, attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringPrototype::~StringPrototype()
|
StringPrototype::~StringPrototype()
|
||||||
|
|
|
@ -45,6 +45,11 @@ Symbol* js_symbol(Heap& heap, String description, bool is_global)
|
||||||
return heap.allocate_without_global_object<Symbol>(move(description), is_global);
|
return heap.allocate_without_global_object<Symbol>(move(description), is_global);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Symbol* js_symbol(VM& vm, String description, bool is_global)
|
||||||
|
{
|
||||||
|
return js_symbol(vm.heap(), move(description), is_global);
|
||||||
|
}
|
||||||
|
|
||||||
Symbol* js_symbol(Interpreter& interpreter, String description, bool is_global)
|
Symbol* js_symbol(Interpreter& interpreter, String description, bool is_global)
|
||||||
{
|
{
|
||||||
return js_symbol(interpreter.heap(), description, is_global);
|
return js_symbol(interpreter.heap(), description, is_global);
|
||||||
|
|
|
@ -52,5 +52,6 @@ private:
|
||||||
|
|
||||||
Symbol* js_symbol(Heap&, String description, bool is_global);
|
Symbol* js_symbol(Heap&, String description, bool is_global);
|
||||||
Symbol* js_symbol(Interpreter&, String description, bool is_global);
|
Symbol* js_symbol(Interpreter&, String description, bool is_global);
|
||||||
|
Symbol* js_symbol(VM&, String description, bool is_global);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ void SymbolConstructor::initialize(GlobalObject& global_object)
|
||||||
define_native_function("keyFor", key_for, 1, Attribute::Writable | Attribute::Configurable);
|
define_native_function("keyFor", key_for, 1, Attribute::Writable | Attribute::Configurable);
|
||||||
|
|
||||||
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
||||||
define_property(#SymbolName, global_object.interpreter().well_known_symbol_##snake_name(), 0);
|
define_property(#SymbolName, global_object.vm().well_known_symbol_##snake_name(), 0);
|
||||||
JS_ENUMERATE_WELL_KNOWN_SYMBOLS
|
JS_ENUMERATE_WELL_KNOWN_SYMBOLS
|
||||||
#undef __JS_ENUMERATE
|
#undef __JS_ENUMERATE
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ JS_DEFINE_NATIVE_FUNCTION(SymbolConstructor::for_)
|
||||||
description = interpreter.argument(0).to_string(interpreter);
|
description = interpreter.argument(0).to_string(interpreter);
|
||||||
}
|
}
|
||||||
|
|
||||||
return interpreter.get_global_symbol(description);
|
return global_object.vm().get_global_symbol(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(SymbolConstructor::key_for)
|
JS_DEFINE_NATIVE_FUNCTION(SymbolConstructor::key_for)
|
||||||
|
|
|
@ -51,7 +51,7 @@ void SymbolPrototype::initialize(GlobalObject& global_object)
|
||||||
define_native_function("toString", to_string, 0, Attribute::Writable | Attribute::Configurable);
|
define_native_function("toString", to_string, 0, Attribute::Writable | Attribute::Configurable);
|
||||||
define_native_function("valueOf", value_of, 0, Attribute::Writable | Attribute::Configurable);
|
define_native_function("valueOf", value_of, 0, Attribute::Writable | Attribute::Configurable);
|
||||||
|
|
||||||
define_property(global_object.interpreter().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "Symbol"), Attribute::Configurable);
|
define_property(global_object.vm().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "Symbol"), Attribute::Configurable);
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolPrototype::~SymbolPrototype()
|
SymbolPrototype::~SymbolPrototype()
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <LibJS/Interpreter.h>
|
#include <LibJS/Interpreter.h>
|
||||||
|
#include <LibJS/Runtime/Symbol.h>
|
||||||
#include <LibJS/Runtime/VM.h>
|
#include <LibJS/Runtime/VM.h>
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
@ -37,6 +38,10 @@ NonnullRefPtr<VM> VM::create()
|
||||||
VM::VM()
|
VM::VM()
|
||||||
: m_heap(*this)
|
: m_heap(*this)
|
||||||
{
|
{
|
||||||
|
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
||||||
|
m_well_known_symbol_##snake_name = js_symbol(*this, "Symbol." #SymbolName, false);
|
||||||
|
JS_ENUMERATE_WELL_KNOWN_SYMBOLS
|
||||||
|
#undef __JS_ENUMERATE
|
||||||
}
|
}
|
||||||
|
|
||||||
VM::~VM()
|
VM::~VM()
|
||||||
|
@ -85,6 +90,25 @@ void VM::gather_roots(HashTable<Cell*>& roots)
|
||||||
roots.set(m_exception);
|
roots.set(m_exception);
|
||||||
for (auto* interpreter : m_interpreters)
|
for (auto* interpreter : m_interpreters)
|
||||||
interpreter->gather_roots(roots);
|
interpreter->gather_roots(roots);
|
||||||
|
|
||||||
|
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
||||||
|
roots.set(well_known_symbol_##snake_name());
|
||||||
|
JS_ENUMERATE_WELL_KNOWN_SYMBOLS
|
||||||
|
#undef __JS_ENUMERATE
|
||||||
|
|
||||||
|
for (auto& symbol : m_global_symbol_map)
|
||||||
|
roots.set(symbol.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol* VM::get_global_symbol(const String& description)
|
||||||
|
{
|
||||||
|
auto result = m_global_symbol_map.get(description);
|
||||||
|
if (result.has_value())
|
||||||
|
return result.value();
|
||||||
|
|
||||||
|
auto new_global_symbol = js_symbol(*this, description, true);
|
||||||
|
m_global_symbol_map.set(description, new_global_symbol);
|
||||||
|
return new_global_symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/HashMap.h>
|
||||||
#include <AK/RefCounted.h>
|
#include <AK/RefCounted.h>
|
||||||
#include <LibJS/Heap/Heap.h>
|
#include <LibJS/Heap/Heap.h>
|
||||||
|
|
||||||
|
@ -63,6 +64,13 @@ public:
|
||||||
|
|
||||||
void gather_roots(HashTable<Cell*>&);
|
void gather_roots(HashTable<Cell*>&);
|
||||||
|
|
||||||
|
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
||||||
|
Symbol* well_known_symbol_##snake_name() const { return m_well_known_symbol_##snake_name; }
|
||||||
|
JS_ENUMERATE_WELL_KNOWN_SYMBOLS
|
||||||
|
#undef __JS_ENUMERATE
|
||||||
|
|
||||||
|
Symbol* get_global_symbol(const String& description);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VM();
|
VM();
|
||||||
|
|
||||||
|
@ -70,6 +78,13 @@ private:
|
||||||
|
|
||||||
Heap m_heap;
|
Heap m_heap;
|
||||||
Vector<Interpreter*> m_interpreters;
|
Vector<Interpreter*> m_interpreters;
|
||||||
|
|
||||||
|
HashMap<String, Symbol*> m_global_symbol_map;
|
||||||
|
|
||||||
|
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
||||||
|
Symbol* m_well_known_symbol_##snake_name { nullptr };
|
||||||
|
JS_ENUMERATE_WELL_KNOWN_SYMBOLS
|
||||||
|
#undef __JS_ENUMERATE
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -702,7 +702,7 @@ Value instance_of(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, rhs.to_string_without_side_effects().characters());
|
interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, rhs.to_string_without_side_effects().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto has_instance_method = rhs.as_object().get(interpreter.well_known_symbol_has_instance());
|
auto has_instance_method = rhs.as_object().get(interpreter.vm().well_known_symbol_has_instance());
|
||||||
if (!has_instance_method.is_empty()) {
|
if (!has_instance_method.is_empty()) {
|
||||||
if (!has_instance_method.is_function()) {
|
if (!has_instance_method.is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, has_instance_method.to_string_without_side_effects().characters());
|
interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, has_instance_method.to_string_without_side_effects().characters());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue