mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 22:02:44 +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
	
	 Andreas Kling
						Andreas Kling