ObjectOperations.h (13185B)
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 /* Fundamental operations on objects. */ 8 9 #ifndef vm_ObjectOperations_h 10 #define vm_ObjectOperations_h 11 12 #include "mozilla/Attributes.h" // MOZ_ALWAYS_INLINE 13 #include "mozilla/Maybe.h" 14 15 #include <stdint.h> // uint32_t 16 17 #include "js/Id.h" // jsid 18 #include "js/PropertyDescriptor.h" // JSPROP_ENUMERATE, JS::PropertyDescriptor 19 #include "js/RootingAPI.h" // JS::Handle, JS::MutableHandle, JS::Rooted 20 #include "js/TypeDecls.h" // fwd-decl: JSContext, Symbol, Value 21 #include "vm/StringType.h" // js::NameToId 22 23 namespace JS { 24 class ObjectOpResult; 25 } 26 27 namespace js { 28 29 class PropertyResult; 30 31 // The functions below are the fundamental operations on objects. See the 32 // comment about "Standard internal methods" in jsapi.h. 33 34 /* 35 * ES6 [[GetPrototypeOf]]. Get obj's prototype, storing it in protop. 36 * 37 * If obj is definitely not a proxy, the infallible obj->getProto() can be used 38 * instead. See the comment on JSObject::getTaggedProto(). 39 */ 40 inline bool GetPrototype(JSContext* cx, JS::Handle<JSObject*> obj, 41 JS::MutableHandle<JSObject*> protop); 42 43 /* 44 * ES6 [[SetPrototypeOf]]. Change obj's prototype to proto. 45 * 46 * Returns false on error, success of operation in *result. For example, if 47 * obj is not extensible, its prototype is fixed. js::SetPrototype will return 48 * true, because no exception is thrown for this; but *result will be false. 49 */ 50 extern bool SetPrototype(JSContext* cx, JS::Handle<JSObject*> obj, 51 JS::Handle<JSObject*> proto, 52 JS::ObjectOpResult& result); 53 54 /* Convenience function: like the above, but throw on failure. */ 55 extern bool SetPrototype(JSContext* cx, JS::Handle<JSObject*> obj, 56 JS::Handle<JSObject*> proto); 57 58 /* 59 * ES6 [[IsExtensible]]. Extensible objects can have new properties defined on 60 * them. Inextensible objects can't, and their [[Prototype]] slot is fixed as 61 * well. 62 */ 63 inline bool IsExtensible(JSContext* cx, JS::Handle<JSObject*> obj, 64 bool* extensible); 65 66 /* 67 * ES6 [[PreventExtensions]]. Attempt to change the [[Extensible]] bit on |obj| 68 * to false. Indicate success or failure through the |result| outparam, or 69 * actual error through the return value. 70 */ 71 extern bool PreventExtensions(JSContext* cx, JS::Handle<JSObject*> obj, 72 JS::ObjectOpResult& result); 73 74 /* Convenience function. As above, but throw on failure. */ 75 extern bool PreventExtensions(JSContext* cx, JS::Handle<JSObject*> obj); 76 77 /* 78 * ES6 [[GetOwnProperty]]. Get a description of one of obj's own properties. 79 * 80 * If no such property exists on obj, desc will be Nothing(). 81 */ 82 extern bool GetOwnPropertyDescriptor( 83 JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, 84 JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> desc); 85 86 /* ES6 [[DefineOwnProperty]]. Define a property on obj. */ 87 extern bool DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj, 88 JS::Handle<jsid> id, 89 Handle<JS::PropertyDescriptor> desc, 90 JS::ObjectOpResult& result); 91 92 /* 93 * When the 'result' out-param is omitted, the behavior is the same as above, 94 * except that any failure results in a TypeError. 95 */ 96 extern bool DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj, 97 JS::Handle<jsid> id, 98 JS::Handle<JS::PropertyDescriptor> desc); 99 100 extern bool DefineAccessorProperty(JSContext* cx, JS::Handle<JSObject*> obj, 101 JS::Handle<jsid> id, 102 JS::Handle<JSObject*> getter, 103 JS::Handle<JSObject*> setter, unsigned attrs, 104 JS::ObjectOpResult& result); 105 106 extern bool DefineDataProperty(JSContext* cx, JS::Handle<JSObject*> obj, 107 JS::Handle<jsid> id, JS::Handle<JS::Value> value, 108 unsigned attrs, JS::ObjectOpResult& result); 109 110 extern bool DefineAccessorProperty(JSContext* cx, JS::Handle<JSObject*> obj, 111 JS::Handle<jsid> id, 112 JS::Handle<JSObject*> getter, 113 JS::Handle<JSObject*> setter, 114 unsigned attrs = JSPROP_ENUMERATE); 115 116 extern bool DefineDataProperty(JSContext* cx, JS::Handle<JSObject*> obj, 117 JS::Handle<jsid> id, JS::Handle<JS::Value> value, 118 unsigned attrs = JSPROP_ENUMERATE); 119 120 extern bool DefineDataProperty(JSContext* cx, JS::Handle<JSObject*> obj, 121 PropertyName* name, JS::Handle<JS::Value> value, 122 unsigned attrs = JSPROP_ENUMERATE); 123 124 extern bool DefineDataElement(JSContext* cx, JS::Handle<JSObject*> obj, 125 uint32_t index, JS::Handle<JS::Value> value, 126 unsigned attrs = JSPROP_ENUMERATE); 127 128 /* 129 * ES6 [[Has]]. Set *foundp to true if `id in obj` (that is, if obj has an own 130 * or inherited property obj[id]), false otherwise. 131 */ 132 inline bool HasProperty(JSContext* cx, JS::Handle<JSObject*> obj, 133 JS::Handle<jsid> id, bool* foundp); 134 135 inline bool HasProperty(JSContext* cx, JS::Handle<JSObject*> obj, 136 PropertyName* name, bool* foundp); 137 138 /* 139 * ES6 [[Get]]. Get the value of the property `obj[id]`, or undefined if no 140 * such property exists. 141 * 142 * Typically obj == receiver; if obj != receiver then the caller is most likely 143 * a proxy using GetProperty to finish a property get that started out as 144 * `receiver[id]`, and we've already searched the prototype chain up to `obj`. 145 */ 146 inline bool GetProperty(JSContext* cx, JS::Handle<JSObject*> obj, 147 JS::Handle<JS::Value> receiver, JS::Handle<jsid> id, 148 JS::MutableHandle<JS::Value> vp); 149 150 inline bool GetProperty(JSContext* cx, JS::Handle<JSObject*> obj, 151 JS::Handle<JS::Value> receiver, PropertyName* name, 152 JS::MutableHandle<JS::Value> vp); 153 154 inline bool GetProperty(JSContext* cx, JS::Handle<JSObject*> obj, 155 JS::Handle<JSObject*> receiver, JS::Handle<jsid> id, 156 JS::MutableHandle<JS::Value> vp); 157 158 inline bool GetProperty(JSContext* cx, JS::Handle<JSObject*> obj, 159 JS::Handle<JSObject*> receiver, PropertyName* name, 160 JS::MutableHandle<JS::Value> vp); 161 162 inline bool GetElement(JSContext* cx, JS::Handle<JSObject*> obj, 163 JS::Handle<JS::Value> receiver, uint32_t index, 164 JS::MutableHandle<JS::Value> vp); 165 166 inline bool GetElement(JSContext* cx, JS::Handle<JSObject*> obj, 167 JS::Handle<JSObject*> receiver, uint32_t index, 168 JS::MutableHandle<JS::Value> vp); 169 170 inline bool GetPropertyNoGC(JSContext* cx, JSObject* obj, 171 const JS::Value& receiver, jsid id, JS::Value* vp); 172 173 inline bool GetPropertyNoGC(JSContext* cx, JSObject* obj, 174 const JS::Value& receiver, PropertyName* name, 175 JS::Value* vp); 176 177 inline bool GetElementNoGC(JSContext* cx, JSObject* obj, 178 const JS::Value& receiver, uint32_t index, 179 JS::Value* vp); 180 181 // Returns whether |obj| or an object on its proto chain may have an interesting 182 // symbol property (see JSObject::hasInterestingSymbolProperty). If it returns 183 // true, *holder is set to the object that may have this property. 184 MOZ_ALWAYS_INLINE bool MaybeHasInterestingSymbolProperty( 185 JSContext* cx, JSObject* obj, JS::Symbol* symbol, 186 JSObject** holder = nullptr); 187 188 // Like GetProperty but optimized for interesting symbol properties like 189 // @@toStringTag. 190 MOZ_ALWAYS_INLINE bool GetInterestingSymbolProperty( 191 JSContext* cx, JS::Handle<JSObject*> obj, JS::Symbol* sym, 192 JS::MutableHandle<JS::Value> vp); 193 194 /* 195 * ES6 [[Set]]. Carry out the assignment `obj[id] = v`. 196 * 197 * The `receiver` argument has to do with how [[Set]] interacts with the 198 * prototype chain and proxies. It's hard to explain and ES6 doesn't really 199 * try. Long story short, if you just want bog-standard assignment, pass 200 * `ObjectValue(*obj)` as receiver. Or better, use one of the signatures that 201 * doesn't have a receiver parameter. 202 * 203 * Callers pass obj != receiver e.g. when a proxy is involved, obj is the 204 * proxy's target, and the proxy is using SetProperty to finish an assignment 205 * that started out as `receiver[id] = v`, by delegating it to obj. 206 */ 207 inline bool SetProperty(JSContext* cx, JS::Handle<JSObject*> obj, 208 JS::Handle<jsid> id, JS::Handle<JS::Value> v, 209 JS::Handle<JS::Value> receiver, 210 JS::ObjectOpResult& result); 211 212 inline bool SetProperty(JSContext* cx, JS::Handle<JSObject*> obj, 213 JS::Handle<jsid> id, JS::Handle<JS::Value> v); 214 215 inline bool SetProperty(JSContext* cx, JS::Handle<JSObject*> obj, 216 PropertyName* name, JS::Handle<JS::Value> v, 217 JS::Handle<JS::Value> receiver, 218 JS::ObjectOpResult& result); 219 220 inline bool SetProperty(JSContext* cx, JS::Handle<JSObject*> obj, 221 PropertyName* name, JS::Handle<JS::Value> v); 222 223 inline bool SetElement(JSContext* cx, JS::Handle<JSObject*> obj, uint32_t index, 224 JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver, 225 JS::ObjectOpResult& result); 226 227 /* 228 * ES6 draft rev 31 (15 Jan 2015) 7.3.3 Put (O, P, V, Throw), except that on 229 * success, the spec says this is supposed to return a boolean value, which we 230 * don't bother doing. 231 */ 232 inline bool PutProperty(JSContext* cx, JS::Handle<JSObject*> obj, 233 JS::Handle<jsid> id, JS::Handle<JS::Value> v, 234 bool strict); 235 236 /* 237 * ES6 [[Delete]]. Equivalent to the JS code `delete obj[id]`. 238 */ 239 inline bool DeleteProperty(JSContext* cx, JS::Handle<JSObject*> obj, 240 JS::Handle<jsid> id, JS::ObjectOpResult& result); 241 242 inline bool DeleteElement(JSContext* cx, JS::Handle<JSObject*> obj, 243 uint32_t index, JS::ObjectOpResult& result); 244 245 /*** SpiderMonkey nonstandard internal methods ******************************/ 246 247 /** 248 * If |obj| (underneath any functionally-transparent wrapper proxies) has as 249 * its [[GetPrototypeOf]] trap the ordinary [[GetPrototypeOf]] behavior defined 250 * for ordinary objects, set |*isOrdinary = true| and store |obj|'s prototype 251 * in |result|. Otherwise set |*isOrdinary = false|. In case of error, both 252 * outparams have unspecified value. 253 */ 254 extern bool GetPrototypeIfOrdinary(JSContext* cx, JS::Handle<JSObject*> obj, 255 bool* isOrdinary, 256 JS::MutableHandle<JSObject*> protop); 257 258 /* 259 * Attempt to make |obj|'s [[Prototype]] immutable, such that subsequently 260 * trying to change it will not work. If an internal error occurred, 261 * returns false. Otherwise, |*succeeded| is set to true iff |obj|'s 262 * [[Prototype]] is now immutable. 263 */ 264 extern bool SetImmutablePrototype(JSContext* cx, JS::Handle<JSObject*> obj, 265 bool* succeeded); 266 267 /* 268 * Deprecated. Finds a PropertyDescriptor somewhere along the prototype chain, 269 * similar to GetOwnPropertyDescriptor. |holder| indicates on which object the 270 * property was found. 271 */ 272 extern bool GetPropertyDescriptor( 273 JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, 274 MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> desc, 275 JS::MutableHandle<JSObject*> holder); 276 277 /* 278 * Deprecated. A version of HasProperty that also returns the object on which 279 * the property was found (but that information is unreliable for proxies), and 280 * the Shape of the property, if native. 281 */ 282 extern bool LookupProperty(JSContext* cx, JS::Handle<JSObject*> obj, 283 JS::Handle<jsid> id, 284 JS::MutableHandle<JSObject*> objp, 285 PropertyResult* propp); 286 287 inline bool LookupProperty(JSContext* cx, JS::Handle<JSObject*> obj, 288 PropertyName* name, 289 JS::MutableHandle<JSObject*> objp, 290 PropertyResult* propp) { 291 JS::Rooted<jsid> id(cx, NameToId(name)); 292 return LookupProperty(cx, obj, id, objp, propp); 293 } 294 295 /* Set *result to tell whether obj has an own property with the given id. */ 296 extern bool HasOwnProperty(JSContext* cx, JS::Handle<JSObject*> obj, 297 JS::Handle<jsid> id, bool* result); 298 299 } /* namespace js */ 300 301 #endif /* vm_ObjectOperations_h */