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::GCPtrObject 11 #include "gc/Cell.h" // js::gc::TenuredCellWithGCPointer 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::TenuredCellWithGCPointer<JSObject> { 58 public: 59 // Getter object, stored in the cell header. getter()60 JSObject* getter() const { return headerPtr(); } 61 62 GCPtrObject setter_; 63 64 #ifndef JS_64BIT 65 // Ensure size >= MinCellSize on 32-bit platforms. 66 uint64_t padding_ = 0; 67 #endif 68 69 private: 70 GetterSetter(JSObject* getter, JSObject* setter); 71 72 public: 73 static GetterSetter* create(JSContext* cx, HandleObject getter, 74 HandleObject setter); 75 setter()76 JSObject* setter() const { return setter_; } 77 78 static const JS::TraceKind TraceKind = JS::TraceKind::GetterSetter; 79 80 void traceChildren(JSTracer* trc); 81 finalize(JSFreeOp * fop)82 void finalize(JSFreeOp* fop) { 83 // Nothing to do. 84 } 85 }; 86 87 } // namespace js 88 89 // JS::ubi::Nodes can point to GetterSetters; they're js::gc::Cell instances 90 // with no associated compartment. 91 namespace JS { 92 namespace ubi { 93 94 template <> 95 class Concrete<js::GetterSetter> : TracerConcrete<js::GetterSetter> { 96 protected: Concrete(js::GetterSetter * ptr)97 explicit Concrete(js::GetterSetter* ptr) 98 : TracerConcrete<js::GetterSetter>(ptr) {} 99 100 public: construct(void * storage,js::GetterSetter * ptr)101 static void construct(void* storage, js::GetterSetter* ptr) { 102 new (storage) Concrete(ptr); 103 } 104 105 Size size(mozilla::MallocSizeOf mallocSizeOf) const override; 106 typeName()107 const char16_t* typeName() const override { return concreteTypeName; } 108 static const char16_t concreteTypeName[]; 109 }; 110 111 } // namespace ubi 112 } // namespace JS 113 114 #endif // vm_GetterSetter_h 115