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/. */
7 /* Fundamental operations on objects. */
9 #ifndef vm_ObjectOperations_h
10 #define vm_ObjectOperations_h
12 #include "mozilla/Attributes.h" // MOZ_ALWAYS_INLINE
13 #include "mozilla/Maybe.h"
15 #include <stdint.h> // uint32_t
17 #include "js/Id.h" // INT_TO_JSID, jsid, JSID_INT_MAX, SYMBOL_TO_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
31 // The functions below are the fundamental operations on objects. See the
32 // comment about "Standard internal methods" in jsapi.h.
35 * ES6 [[GetPrototypeOf]]. Get obj's prototype, storing it in protop.
37 * If obj is definitely not a proxy, the infallible obj->getProto() can be used
38 * instead. See the comment on JSObject::getTaggedProto().
40 inline bool GetPrototype(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
41 JS::MutableHandle
<JSObject
*> protop
);
44 * ES6 [[SetPrototypeOf]]. Change obj's prototype to proto.
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.
50 extern bool SetPrototype(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
51 JS::Handle
<JSObject
*> proto
,
52 JS::ObjectOpResult
& result
);
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
);
59 * ES6 [[IsExtensible]]. Extensible objects can have new properties defined on
60 * them. Inextensible objects can't, and their [[Prototype]] slot is fixed as
63 inline bool IsExtensible(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
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.
71 extern bool PreventExtensions(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
72 JS::ObjectOpResult
& result
);
74 /* Convenience function. As above, but throw on failure. */
75 extern bool PreventExtensions(JSContext
* cx
, JS::Handle
<JSObject
*> obj
);
78 * ES6 [[GetOwnProperty]]. Get a description of one of obj's own properties.
80 * If no such property exists on obj, desc will be Nothing().
82 extern bool GetOwnPropertyDescriptor(
83 JSContext
* cx
, JS::Handle
<JSObject
*> obj
, JS::Handle
<jsid
> id
,
84 JS::MutableHandle
<mozilla::Maybe
<JS::PropertyDescriptor
>> desc
);
86 /* ES6 [[DefineOwnProperty]]. Define a property on obj. */
87 extern bool DefineProperty(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
89 Handle
<JS::PropertyDescriptor
> desc
,
90 JS::ObjectOpResult
& result
);
93 * When the 'result' out-param is omitted, the behavior is the same as above,
94 * except that any failure results in a TypeError.
96 extern bool DefineProperty(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
98 JS::Handle
<JS::PropertyDescriptor
> desc
);
100 extern bool DefineAccessorProperty(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
102 JS::Handle
<JSObject
*> getter
,
103 JS::Handle
<JSObject
*> setter
, unsigned attrs
,
104 JS::ObjectOpResult
& result
);
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
);
110 extern bool DefineAccessorProperty(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
112 JS::Handle
<JSObject
*> getter
,
113 JS::Handle
<JSObject
*> setter
,
114 unsigned attrs
= JSPROP_ENUMERATE
);
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
);
120 extern bool DefineDataProperty(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
121 PropertyName
* name
, JS::Handle
<JS::Value
> value
,
122 unsigned attrs
= JSPROP_ENUMERATE
);
124 extern bool DefineDataElement(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
125 uint32_t index
, JS::Handle
<JS::Value
> value
,
126 unsigned attrs
= JSPROP_ENUMERATE
);
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.
132 inline bool HasProperty(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
133 JS::Handle
<jsid
> id
, bool* foundp
);
135 inline bool HasProperty(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
136 PropertyName
* name
, bool* foundp
);
139 * ES6 [[Get]]. Get the value of the property `obj[id]`, or undefined if no
140 * such property exists.
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`.
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
);
150 inline bool GetProperty(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
151 JS::Handle
<JS::Value
> receiver
, PropertyName
* name
,
152 JS::MutableHandle
<JS::Value
> vp
);
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
);
158 inline bool GetProperty(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
159 JS::Handle
<JSObject
*> receiver
, PropertyName
* name
,
160 JS::MutableHandle
<JS::Value
> vp
);
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
);
166 inline bool GetElement(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
167 JS::Handle
<JSObject
*> receiver
, uint32_t index
,
168 JS::MutableHandle
<JS::Value
> vp
);
170 inline bool GetPropertyNoGC(JSContext
* cx
, JSObject
* obj
,
171 const JS::Value
& receiver
, jsid id
, JS::Value
* vp
);
173 inline bool GetPropertyNoGC(JSContext
* cx
, JSObject
* obj
,
174 const JS::Value
& receiver
, PropertyName
* name
,
177 inline bool GetElementNoGC(JSContext
* cx
, JSObject
* obj
,
178 const JS::Value
& receiver
, uint32_t index
,
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);
188 // Like GetProperty but optimized for interesting symbol properties like
190 MOZ_ALWAYS_INLINE
bool GetInterestingSymbolProperty(
191 JSContext
* cx
, JS::Handle
<JSObject
*> obj
, JS::Symbol
* sym
,
192 JS::MutableHandle
<JS::Value
> vp
);
195 * ES6 [[Set]]. Carry out the assignment `obj[id] = v`.
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.
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.
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
);
212 inline bool SetProperty(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
213 JS::Handle
<jsid
> id
, JS::Handle
<JS::Value
> v
);
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
);
220 inline bool SetProperty(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
221 PropertyName
* name
, JS::Handle
<JS::Value
> v
);
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
);
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.
232 inline bool PutProperty(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
233 JS::Handle
<jsid
> id
, JS::Handle
<JS::Value
> v
,
237 * ES6 [[Delete]]. Equivalent to the JS code `delete obj[id]`.
239 inline bool DeleteProperty(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
240 JS::Handle
<jsid
> id
, JS::ObjectOpResult
& result
);
242 inline bool DeleteElement(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
243 uint32_t index
, JS::ObjectOpResult
& result
);
245 /*** SpiderMonkey nonstandard internal methods ******************************/
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.
254 extern bool GetPrototypeIfOrdinary(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
256 JS::MutableHandle
<JSObject
*> protop
);
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.
264 extern bool SetImmutablePrototype(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
268 * Deprecated. Finds a PropertyDescriptor somewhere along the prototype chain,
269 * similar to GetOwnPropertyDescriptor. |holder| indicates on which object the
270 * property was found.
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
);
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.
282 extern bool LookupProperty(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
284 JS::MutableHandle
<JSObject
*> objp
,
285 PropertyResult
* propp
);
287 inline bool LookupProperty(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
289 JS::MutableHandle
<JSObject
*> objp
,
290 PropertyResult
* propp
) {
291 JS::Rooted
<jsid
> id(cx
, NameToId(name
));
292 return LookupProperty(cx
, obj
, id
, objp
, propp
);
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
);
301 #endif /* vm_ObjectOperations_h */