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