/* * Copyright (c) 2020, Andreas Kling * Copyright (c) 2020-2022, Linus Groh * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace JS { #define JS_OBJECT(class_, base_class) \ public: \ using Base = base_class; \ virtual StringView class_name() const override \ { \ return #class_##sv; \ } struct PrivateElement { enum class Kind { Field, Method, Accessor }; PrivateName key; Kind kind { Kind::Field }; Value value; }; class Object : public Cell { public: static Object* create(Realm&, Object* prototype); Object(Realm&, Object* prototype); explicit Object(Object& prototype); explicit Object(Shape&); virtual void initialize(Realm&) override; virtual ~Object() = default; enum class PropertyKind { Key, Value, KeyAndValue, }; enum class IntegrityLevel { Sealed, Frozen, }; enum class ShouldThrowExceptions { No, Yes, }; // Please DO NOT make up your own non-standard methods unless you // have a very good reason to do so. If any object abstract // operation from the spec is missing, add it instead. // Functionality for implementation details like shapes and // property storage are obviously exempt from this rule :^) // // Methods named [[Foo]]() in the spec are named internal_foo() // here, as they are "The [[Foo]] internal method of a ... object". // They must be virtual and may be overridden. All other methods // follow the regular PascalCase name converted to camel_case // naming convention and must not be virtual. // 7.1 Type Conversion, https://tc39.es/ecma262/#sec-type-conversion ThrowCompletionOr ordinary_to_primitive(Value::PreferredType preferred_type) const; // 7.2 Testing and Comparison Operations, https://tc39.es/ecma262/#sec-testing-and-comparison-operations ThrowCompletionOr is_extensible() const; // 7.3 Operations on Objects, https://tc39.es/ecma262/#sec-operations-on-objects ThrowCompletionOr get(PropertyKey const&) const; ThrowCompletionOr set(PropertyKey const&, Value, ShouldThrowExceptions); ThrowCompletionOr create_data_property(PropertyKey const&, Value); ThrowCompletionOr create_method_property(PropertyKey const&, Value); ThrowCompletionOr create_data_property_or_throw(PropertyKey const&, Value); void create_non_enumerable_data_property_or_throw(PropertyKey const&, Value); ThrowCompletionOr define_property_or_throw(PropertyKey const&, PropertyDescriptor const&); ThrowCompletionOr delete_property_or_throw(PropertyKey const&); ThrowCompletionOr has_property(PropertyKey const&) const; ThrowCompletionOr has_own_property(PropertyKey const&) const; ThrowCompletionOr set_integrity_level(IntegrityLevel); ThrowCompletionOr test_integrity_level(IntegrityLevel) const; ThrowCompletionOr> enumerable_own_property_names(PropertyKind kind) const; ThrowCompletionOr copy_data_properties(Value source, HashTable const& seen_names, GlobalObject& global_object); PrivateElement* private_element_find(PrivateName const& name); ThrowCompletionOr private_field_add(PrivateName const& name, Value value); ThrowCompletionOr private_method_or_accessor_add(PrivateElement element); ThrowCompletionOr private_get(PrivateName const& name); ThrowCompletionOr private_set(PrivateName const& name, Value value); ThrowCompletionOr define_field(ClassFieldDefinition const&); // 10.1 Ordinary Object Internal Methods and Internal Slots, https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots virtual ThrowCompletionOr internal_get_prototype_of() const; virtual ThrowCompletionOr internal_set_prototype_of(Object* prototype); virtual ThrowCompletionOr internal_is_extensible() const; virtual ThrowCompletionOr internal_prevent_extensions(); virtual ThrowCompletionOr> internal_get_own_property(PropertyKey const&) const; virtual ThrowCompletionOr internal_define_own_property(PropertyKey const&, PropertyDescriptor const&); virtual ThrowCompletionOr internal_has_property(PropertyKey const&) const; virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver) const; virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver); virtual ThrowCompletionOr internal_delete(PropertyKey const&); virtual ThrowCompletionOr> internal_own_property_keys() const; ThrowCompletionOr ordinary_set_with_own_descriptor(PropertyKey const&, Value, Value, Optional); // 10.4.7 Immutable Prototype Exotic Objects, https://tc39.es/ecma262/#sec-immutable-prototype-exotic-objects ThrowCompletionOr set_immutable_prototype(Object* prototype); // 20.1 Object Objects, https://tc39.es/ecma262/#sec-object-objects ThrowCompletionOr define_properties(Value properties); // 14.7.5 The for-in, for-of, and for-await-of Statements Optional enumerate_object_properties(Function(Value)>) const; // Implementation-specific storage abstractions Optional storage_get(PropertyKey const&) const; bool storage_has(PropertyKey const&) const; void storage_set(PropertyKey const&, ValueAndAttributes const&); void storage_delete(PropertyKey const&); // Non-standard methods Value get_without_side_effects(PropertyKey const&) const; void define_direct_property(PropertyKey const& property_key, Value value, PropertyAttributes attributes) { storage_set(property_key, { value, attributes }); }; void define_direct_accessor(PropertyKey const&, FunctionObject* getter, FunctionObject* setter, PropertyAttributes attributes); void define_native_function(PropertyKey const&, Function(VM&, GlobalObject&)>, i32 length, PropertyAttributes attributes); void define_native_accessor(PropertyKey const&, Function(VM&, GlobalObject&)> getter, Function(VM&, GlobalObject&)> setter, PropertyAttributes attributes); virtual bool is_function() const { return false; } virtual bool is_typed_array() const { return false; } virtual bool is_string_object() const { return false; } virtual bool is_global_object() const { return false; } virtual bool is_proxy_object() const { return false; } virtual bool is_native_function() const { return false; } virtual bool is_ecmascript_function_object() const { return false; } // B.3.7 The [[IsHTMLDDA]] Internal Slot, https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot virtual bool is_htmldda() const { return false; } bool has_parameter_map() const { return m_has_parameter_map; } void set_has_parameter_map() { m_has_parameter_map = true; } virtual StringView class_name() const override { return "Object"sv; } virtual void visit_edges(Cell::Visitor&) override; Value get_direct(size_t index) const { return m_storage[index]; } IndexedProperties const& indexed_properties() const { return m_indexed_properties; } IndexedProperties& indexed_properties() { return m_indexed_properties; } void set_indexed_property_elements(Vector&& values) { m_indexed_properties = IndexedProperties(move(values)); } Shape& shape() { return *m_shape; } Shape const& shape() const { return *m_shape; } GlobalObject& global_object() const; void ensure_shape_is_unique(); template bool fast_is() const = delete; protected: enum class GlobalObjectTag { Tag }; enum class ConstructWithoutPrototypeTag { Tag }; Object(GlobalObjectTag, Realm&); Object(ConstructWithoutPrototypeTag, Realm&); void set_prototype(Object*); // [[Extensible]] bool m_is_extensible { true }; // [[ParameterMap]] bool m_has_parameter_map { false }; private: void set_shape(Shape& shape) { m_shape = &shape; } Object* prototype() { return shape().prototype(); } Object const* prototype() const { return shape().prototype(); } Shape* m_shape { nullptr }; Vector m_storage; IndexedProperties m_indexed_properties; OwnPtr> m_private_elements; // [[PrivateElements]] }; }