Shape.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /*
  2. * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/HashMap.h>
  8. #include <AK/OwnPtr.h>
  9. #include <AK/WeakPtr.h>
  10. #include <AK/Weakable.h>
  11. #include <LibJS/Forward.h>
  12. #include <LibJS/Heap/Cell.h>
  13. #include <LibJS/Runtime/PropertyAttributes.h>
  14. #include <LibJS/Runtime/StringOrSymbol.h>
  15. #include <LibJS/Runtime/Value.h>
  16. namespace JS {
  17. struct PropertyMetadata {
  18. size_t offset { 0 };
  19. PropertyAttributes attributes { 0 };
  20. };
  21. struct TransitionKey {
  22. StringOrSymbol property_name;
  23. PropertyAttributes attributes { 0 };
  24. bool operator==(const TransitionKey& other) const
  25. {
  26. return property_name == other.property_name && attributes == other.attributes;
  27. }
  28. };
  29. class Shape final
  30. : public Cell
  31. , public Weakable<Shape> {
  32. public:
  33. virtual ~Shape() override;
  34. enum class TransitionType {
  35. Invalid,
  36. Put,
  37. Configure,
  38. Prototype,
  39. };
  40. enum class ShapeWithoutGlobalObjectTag { Tag };
  41. explicit Shape(ShapeWithoutGlobalObjectTag);
  42. explicit Shape(Object& global_object);
  43. Shape(Shape& previous_shape, const StringOrSymbol& property_name, PropertyAttributes attributes, TransitionType);
  44. Shape(Shape& previous_shape, Object* new_prototype);
  45. Shape* create_put_transition(const StringOrSymbol&, PropertyAttributes attributes);
  46. Shape* create_configure_transition(const StringOrSymbol&, PropertyAttributes attributes);
  47. Shape* create_prototype_transition(Object* new_prototype);
  48. void add_property_without_transition(const StringOrSymbol&, PropertyAttributes);
  49. void add_property_without_transition(PropertyName const&, PropertyAttributes);
  50. bool is_unique() const { return m_unique; }
  51. Shape* create_unique_clone() const;
  52. GlobalObject* global_object() const;
  53. Object* prototype() { return m_prototype; }
  54. const Object* prototype() const { return m_prototype; }
  55. Optional<PropertyMetadata> lookup(const StringOrSymbol&) const;
  56. const HashMap<StringOrSymbol, PropertyMetadata>& property_table() const;
  57. size_t property_count() const;
  58. struct Property {
  59. StringOrSymbol key;
  60. PropertyMetadata value;
  61. };
  62. Vector<Property> property_table_ordered() const;
  63. void set_prototype_without_transition(Object* new_prototype) { m_prototype = new_prototype; }
  64. void remove_property_from_unique_shape(const StringOrSymbol&, size_t offset);
  65. void add_property_to_unique_shape(const StringOrSymbol&, PropertyAttributes attributes);
  66. void reconfigure_property_in_unique_shape(const StringOrSymbol& property_name, PropertyAttributes attributes);
  67. private:
  68. virtual const char* class_name() const override { return "Shape"; }
  69. virtual void visit_edges(Visitor&) override;
  70. #ifdef JS_TRACK_ZOMBIE_CELLS
  71. virtual void did_become_zombie() override;
  72. #endif
  73. Shape* get_or_prune_cached_forward_transition(TransitionKey const&);
  74. Shape* get_or_prune_cached_prototype_transition(Object* prototype);
  75. void ensure_property_table() const;
  76. PropertyAttributes m_attributes { 0 };
  77. TransitionType m_transition_type : 6 { TransitionType::Invalid };
  78. bool m_unique : 1 { false };
  79. Object* m_global_object { nullptr };
  80. mutable OwnPtr<HashMap<StringOrSymbol, PropertyMetadata>> m_property_table;
  81. HashMap<TransitionKey, WeakPtr<Shape>> m_forward_transitions;
  82. HashMap<Object*, WeakPtr<Shape>> m_prototype_transitions;
  83. Shape* m_previous { nullptr };
  84. StringOrSymbol m_property_name;
  85. Object* m_prototype { nullptr };
  86. size_t m_property_count { 0 };
  87. };
  88. }
  89. template<>
  90. struct AK::Traits<JS::TransitionKey> : public GenericTraits<JS::TransitionKey> {
  91. static unsigned hash(const JS::TransitionKey& key)
  92. {
  93. return pair_int_hash(key.attributes.bits(), Traits<JS::StringOrSymbol>::hash(key.property_name));
  94. }
  95. };