DOMJSProxyHandler.h (6807B)
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 file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_DOMJSProxyHandler_h 8 #define mozilla_dom_DOMJSProxyHandler_h 9 10 #include "js/Proxy.h" 11 #include "jsapi.h" 12 #include "mozilla/Assertions.h" 13 #include "mozilla/Maybe.h" 14 15 namespace mozilla::dom { 16 17 /** 18 * DOM proxies store the expando object in the private slot. 19 * 20 * The expando object is a plain JSObject whose properties correspond to 21 * "expandos" (custom properties set by the script author). 22 * 23 * The exact value stored in the proxy's private slot depends on whether the 24 * interface is annotated with the [OverrideBuiltins] extended attribute. 25 * 26 * If it is, the proxy is initialized with a PrivateValue, which contains a 27 * pointer to a JS::ExpandoAndGeneration object; this contains a pointer to 28 * the actual expando object as well as the "generation" of the object. The 29 * proxy handler will trace the expando object stored in the 30 * JS::ExpandoAndGeneration while the proxy itself is alive. 31 * 32 * If it is not, the proxy is initialized with an UndefinedValue. In 33 * EnsureExpandoObject, it is set to an ObjectValue that points to the 34 * expando object directly. (It is set back to an UndefinedValue only when 35 * the object is about to die.) 36 */ 37 38 class BaseDOMProxyHandler : public js::BaseProxyHandler { 39 public: 40 explicit constexpr BaseDOMProxyHandler(const void* aProxyFamily, 41 bool aHasPrototype = false) 42 : js::BaseProxyHandler(aProxyFamily, aHasPrototype) {} 43 44 // Implementations of methods that can be implemented in terms of 45 // other lower-level methods. 46 bool getOwnPropertyDescriptor( 47 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, 48 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const override; 49 virtual bool ownPropertyKeys( 50 JSContext* cx, JS::Handle<JSObject*> proxy, 51 JS::MutableHandleVector<jsid> props) const override; 52 53 virtual bool getPrototypeIfOrdinary( 54 JSContext* cx, JS::Handle<JSObject*> proxy, bool* isOrdinary, 55 JS::MutableHandle<JSObject*> proto) const override; 56 57 // We override getOwnEnumerablePropertyKeys() and implement it directly 58 // instead of using the default implementation, which would call 59 // ownPropertyKeys and then filter out the non-enumerable ones. This avoids 60 // unnecessary work during enumeration. 61 virtual bool getOwnEnumerablePropertyKeys( 62 JSContext* cx, JS::Handle<JSObject*> proxy, 63 JS::MutableHandleVector<jsid> props) const override; 64 65 protected: 66 // Hook for subclasses to implement shared ownPropertyKeys()/keys() 67 // functionality. The "flags" argument is either JSITER_OWNONLY (for keys()) 68 // or JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS (for 69 // ownPropertyKeys()). 70 virtual bool ownPropNames(JSContext* cx, JS::Handle<JSObject*> proxy, 71 unsigned flags, 72 JS::MutableHandleVector<jsid> props) const = 0; 73 74 // Hook for subclasses to allow set() to ignore named props while other things 75 // that look at property descriptors see them. This is intentionally not 76 // named getOwnPropertyDescriptor to avoid subclasses that override it hiding 77 // our public getOwnPropertyDescriptor. 78 virtual bool getOwnPropDescriptor( 79 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, 80 bool ignoreNamedProps, 81 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const = 0; 82 }; 83 84 class DOMProxyHandler : public BaseDOMProxyHandler { 85 public: 86 constexpr DOMProxyHandler() : BaseDOMProxyHandler(&family) {} 87 88 bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, 89 JS::Handle<jsid> id, 90 JS::Handle<JS::PropertyDescriptor> desc, 91 JS::ObjectOpResult& result) const override { 92 bool unused; 93 return defineProperty(cx, proxy, id, desc, result, &unused); 94 } 95 virtual bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, 96 JS::Handle<jsid> id, 97 JS::Handle<JS::PropertyDescriptor> desc, 98 JS::ObjectOpResult& result, bool* done) const; 99 bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, 100 JS::ObjectOpResult& result) const override; 101 bool preventExtensions(JSContext* cx, JS::Handle<JSObject*> proxy, 102 JS::ObjectOpResult& result) const override; 103 bool isExtensible(JSContext* cx, JS::Handle<JSObject*> proxy, 104 bool* extensible) const override; 105 bool set(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, 106 JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver, 107 JS::ObjectOpResult& result) const override; 108 109 /* 110 * If assigning to proxy[id] hits a named setter with OverrideBuiltins or 111 * an indexed setter, call it and set *done to true on success. Otherwise, set 112 * *done to false. 113 */ 114 virtual bool setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, 115 JS::Handle<jsid> id, JS::Handle<JS::Value> v, 116 bool* done) const; 117 118 /* 119 * Get the expando object for the given DOM proxy. 120 */ 121 static JSObject* GetExpandoObject(JSObject* obj); 122 123 /* 124 * Clear the expando object for the given DOM proxy and return it. This 125 * function will ensure that the returned object is exposed to active JS if 126 * the given object is exposed. 127 * 128 * GetAndClearExpandoObject does not DROP or clear the preserving wrapper 129 * flag. 130 */ 131 static JSObject* GetAndClearExpandoObject(JSObject* obj); 132 133 /* 134 * Ensure that the given proxy (obj) has an expando object, and return it. 135 * Returns null on failure. 136 */ 137 static JSObject* EnsureExpandoObject(JSContext* cx, 138 JS::Handle<JSObject*> obj); 139 140 static const char family; 141 }; 142 143 // Class used by shadowing handlers (the ones that have [OverrideBuiltins]. 144 // This handles tracing the expando in JS::ExpandoAndGeneration. 145 class ShadowingDOMProxyHandler : public DOMProxyHandler { 146 public: 147 virtual void trace(JSTracer* trc, JSObject* proxy) const override; 148 }; 149 150 inline bool IsDOMProxy(JSObject* obj) { 151 return js::IsProxy(obj) && 152 js::GetProxyHandler(obj)->family() == &DOMProxyHandler::family; 153 } 154 155 inline const DOMProxyHandler* GetDOMProxyHandler(JSObject* obj) { 156 MOZ_ASSERT(IsDOMProxy(obj)); 157 return static_cast<const DOMProxyHandler*>(js::GetProxyHandler(obj)); 158 } 159 160 } // namespace mozilla::dom 161 162 #endif /* mozilla_dom_DOMProxyHandler_h */