GetterSetter.h (4226B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef vm_GetterSetter_h 8 #define vm_GetterSetter_h 9 10 #include "gc/Barrier.h" // js::GCPtr<JSObject*> 11 #include "gc/Cell.h" // js::gc::CellWithGCPointer 12 13 #include "js/TypeDecls.h" // JS::HandleObject 14 #include "js/UbiNode.h" // JS::ubi::TracerConcrete 15 16 namespace js { 17 18 // [SMDOC] Getter/Setter Properties 19 // 20 // Getter/setter properties are implemented similar to plain data properties: 21 // the shape contains the property's key, attributes, and slot number, but the 22 // getter/setter objects are stored separately as part of the object. 23 // 24 // To simplify the NativeObject and Shape code, a single slot is allocated for 25 // each getter/setter property (again similar to data properties). This slot 26 // contains a PrivateGCThingValue pointing to a js::GetterSetter instance. 27 // 28 // js::GetterSetter 29 // ================ 30 // js::GetterSetter is an immutable type that stores the getter/setter objects. 31 // Because accessor properties can be defined with only a getter or only a 32 // setter, a GetterSetter's objects can be nullptr. 33 // 34 // JIT/IC Guards 35 // ============= 36 // An object's shape implies a certain property is an accessor, but it does not 37 // imply the identity of the getter/setter objects. This means IC code needs to 38 // guard on the slot value (the GetterSetter*) when optimizing a call to a 39 // particular getter/setter function. 40 // 41 // See EmitGuardGetterSetterSlot in jit/CacheIR.cpp. 42 // 43 // HadGetterSetterChange Optimization 44 // ================================== 45 // Some getters and setters defined on the prototype chain are very hot, for 46 // example the 'length' getter for typed arrays. To avoid the GetterSetter guard 47 // in the common case, when attaching a stub for a known 'holder' object, we 48 // use the HadGetterSetterChange object flag. 49 // 50 // When this flag is not set, the object is guaranteed to get a different shape 51 // when an accessor property is either deleted or mutated, because when that 52 // happens the HadGetterSetterChange will be set which triggers a shape change. 53 // 54 // This means CacheIR does not have to guard on the GetterSetter slot for 55 // accessors on the prototype chain until the first time an accessor property is 56 // mutated or deleted. 57 class GetterSetter : public gc::CellWithGCPointer<JSObject> { 58 friend class gc::CellAllocator; 59 60 public: 61 // Getter object, stored in the cell header. 62 JSObject* getter() const { return headerPtr(); } 63 64 GCPtr<JSObject*> setter_; 65 66 #ifndef JS_64BIT 67 // Ensure size >= MinCellSize on 32-bit platforms. 68 uint64_t padding_ = 0; 69 #endif 70 71 private: 72 GetterSetter(HandleObject getter, HandleObject setter); 73 74 public: 75 static GetterSetter* create(JSContext* cx, Handle<NativeObject*> owner, 76 HandleObject getter, HandleObject setter); 77 78 JSObject* setter() const { return setter_; } 79 80 static const JS::TraceKind TraceKind = JS::TraceKind::GetterSetter; 81 82 js::gc::AllocKind getAllocKind() const { 83 return js::gc::AllocKind::GETTER_SETTER; 84 } 85 void fixupAfterMovingGC() {} 86 87 static constexpr size_t offsetOfGetter() { return offsetOfHeaderPtr(); } 88 static constexpr size_t offsetOfSetter() { 89 return offsetof(GetterSetter, setter_); 90 } 91 92 void traceChildren(JSTracer* trc); 93 }; 94 95 } // namespace js 96 97 // JS::ubi::Nodes can point to GetterSetters; they're js::gc::Cell instances 98 // with no associated compartment. 99 namespace JS { 100 namespace ubi { 101 102 template <> 103 class Concrete<js::GetterSetter> : TracerConcrete<js::GetterSetter> { 104 protected: 105 explicit Concrete(js::GetterSetter* ptr) 106 : TracerConcrete<js::GetterSetter>(ptr) {} 107 108 public: 109 static void construct(void* storage, js::GetterSetter* ptr) { 110 new (storage) Concrete(ptr); 111 } 112 113 Size size(mozilla::MallocSizeOf mallocSizeOf) const override; 114 115 const char16_t* typeName() const override { return concreteTypeName; } 116 static const char16_t concreteTypeName[]; 117 }; 118 119 } // namespace ubi 120 } // namespace JS 121 122 #endif // vm_GetterSetter_h