1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 /* Property and element API. */
7 
8 #ifndef js_PropertyAndElement_h
9 #define js_PropertyAndElement_h
10 
11 #include <stddef.h>  // size_t
12 #include <stdint.h>  // uint32_t
13 
14 #include "jstypes.h"  // JS_PUBLIC_API
15 
16 #include "js/CallArgs.h"            // JSNative
17 #include "js/Class.h"               // JS::ObjectOpResult
18 #include "js/GCVector.h"            // JS::GCVector
19 #include "js/Id.h"                  // jsid
20 #include "js/PropertyDescriptor.h"  // JS::PropertyDescriptor
21 #include "js/RootingAPI.h"          // JS::Handle, JS::MutableHandle
22 
23 struct JSContext;
24 class JSFunction;
25 class JSObject;
26 class JSString;
27 
28 namespace JS {
29 
30 using IdVector = JS::GCVector<jsid>;
31 
32 } /* namespace JS */
33 
34 /**
35  * Define a property on obj.
36  *
37  * This function uses JS::ObjectOpResult to indicate conditions that ES6
38  * specifies as non-error failures. This is inconvenient at best, so use this
39  * function only if you are implementing a proxy handler's defineProperty()
40  * method. For all other purposes, use one of the many DefineProperty functions
41  * below that throw an exception in all failure cases.
42  *
43  * Implements: ES6 [[DefineOwnProperty]] internal method.
44  */
45 extern JS_PUBLIC_API bool JS_DefinePropertyById(
46     JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
47     JS::Handle<JS::PropertyDescriptor> desc, JS::ObjectOpResult& result);
48 
49 /**
50  * Define a property on obj, throwing a TypeError if the attempt fails.
51  * This is the C++ equivalent of `Object.defineProperty(obj, id, desc)`.
52  */
53 extern JS_PUBLIC_API bool JS_DefinePropertyById(
54     JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
55     JS::Handle<JS::PropertyDescriptor> desc);
56 
57 extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
58                                                 JS::Handle<JSObject*> obj,
59                                                 JS::Handle<jsid> id,
60                                                 JS::Handle<JS::Value> value,
61                                                 unsigned attrs);
62 
63 extern JS_PUBLIC_API bool JS_DefinePropertyById(
64     JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
65     JSNative getter, JSNative setter, unsigned attrs);
66 
67 extern JS_PUBLIC_API bool JS_DefinePropertyById(
68     JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
69     JS::Handle<JSObject*> getter, JS::Handle<JSObject*> setter, unsigned attrs);
70 
71 extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
72                                                 JS::Handle<JSObject*> obj,
73                                                 JS::Handle<jsid> id,
74                                                 JS::Handle<JSObject*> value,
75                                                 unsigned attrs);
76 
77 extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
78                                                 JS::Handle<JSObject*> obj,
79                                                 JS::Handle<jsid> id,
80                                                 JS::Handle<JSString*> value,
81                                                 unsigned attrs);
82 
83 extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
84                                                 JS::Handle<JSObject*> obj,
85                                                 JS::Handle<jsid> id,
86                                                 int32_t value, unsigned attrs);
87 
88 extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
89                                                 JS::Handle<JSObject*> obj,
90                                                 JS::Handle<jsid> id,
91                                                 uint32_t value, unsigned attrs);
92 
93 extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
94                                                 JS::Handle<JSObject*> obj,
95                                                 JS::Handle<jsid> id,
96                                                 double value, unsigned attrs);
97 
98 extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx,
99                                             JS::Handle<JSObject*> obj,
100                                             const char* name,
101                                             JS::Handle<JS::Value> value,
102                                             unsigned attrs);
103 
104 extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx,
105                                             JS::Handle<JSObject*> obj,
106                                             const char* name, JSNative getter,
107                                             JSNative setter, unsigned attrs);
108 
109 extern JS_PUBLIC_API bool JS_DefineProperty(
110     JSContext* cx, JS::Handle<JSObject*> obj, const char* name,
111     JS::Handle<JSObject*> getter, JS::Handle<JSObject*> setter, unsigned attrs);
112 
113 extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx,
114                                             JS::Handle<JSObject*> obj,
115                                             const char* name,
116                                             JS::Handle<JSObject*> value,
117                                             unsigned attrs);
118 
119 extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx,
120                                             JS::Handle<JSObject*> obj,
121                                             const char* name,
122                                             JS::Handle<JSString*> value,
123                                             unsigned attrs);
124 
125 extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx,
126                                             JS::Handle<JSObject*> obj,
127                                             const char* name, int32_t value,
128                                             unsigned attrs);
129 
130 extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx,
131                                             JS::Handle<JSObject*> obj,
132                                             const char* name, uint32_t value,
133                                             unsigned attrs);
134 
135 extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx,
136                                             JS::Handle<JSObject*> obj,
137                                             const char* name, double value,
138                                             unsigned attrs);
139 
140 extern JS_PUBLIC_API bool JS_DefineUCProperty(
141     JSContext* cx, JS::Handle<JSObject*> obj, const char16_t* name,
142     size_t namelen, JS::Handle<JS::PropertyDescriptor> desc,
143     JS::ObjectOpResult& result);
144 
145 extern JS_PUBLIC_API bool JS_DefineUCProperty(
146     JSContext* cx, JS::Handle<JSObject*> obj, const char16_t* name,
147     size_t namelen, JS::Handle<JS::PropertyDescriptor> desc);
148 
149 extern JS_PUBLIC_API bool JS_DefineUCProperty(
150     JSContext* cx, JS::Handle<JSObject*> obj, const char16_t* name,
151     size_t namelen, JS::Handle<JS::Value> value, unsigned attrs);
152 
153 extern JS_PUBLIC_API bool JS_DefineUCProperty(
154     JSContext* cx, JS::Handle<JSObject*> obj, const char16_t* name,
155     size_t namelen, JS::Handle<JSObject*> getter, JS::Handle<JSObject*> setter,
156     unsigned attrs);
157 
158 extern JS_PUBLIC_API bool JS_DefineUCProperty(
159     JSContext* cx, JS::Handle<JSObject*> obj, const char16_t* name,
160     size_t namelen, JS::Handle<JSObject*> value, unsigned attrs);
161 
162 extern JS_PUBLIC_API bool JS_DefineUCProperty(
163     JSContext* cx, JS::Handle<JSObject*> obj, const char16_t* name,
164     size_t namelen, JS::Handle<JSString*> value, unsigned attrs);
165 
166 extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx,
167                                               JS::Handle<JSObject*> obj,
168                                               const char16_t* name,
169                                               size_t namelen, int32_t value,
170                                               unsigned attrs);
171 
172 extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx,
173                                               JS::Handle<JSObject*> obj,
174                                               const char16_t* name,
175                                               size_t namelen, uint32_t value,
176                                               unsigned attrs);
177 
178 extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx,
179                                               JS::Handle<JSObject*> obj,
180                                               const char16_t* name,
181                                               size_t namelen, double value,
182                                               unsigned attrs);
183 
184 extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx,
185                                            JS::Handle<JSObject*> obj,
186                                            uint32_t index,
187                                            JS::Handle<JS::Value> value,
188                                            unsigned attrs);
189 
190 extern JS_PUBLIC_API bool JS_DefineElement(
191     JSContext* cx, JS::Handle<JSObject*> obj, uint32_t index,
192     JS::Handle<JSObject*> getter, JS::Handle<JSObject*> setter, unsigned attrs);
193 
194 extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx,
195                                            JS::Handle<JSObject*> obj,
196                                            uint32_t index,
197                                            JS::Handle<JSObject*> value,
198                                            unsigned attrs);
199 
200 extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx,
201                                            JS::Handle<JSObject*> obj,
202                                            uint32_t index,
203                                            JS::Handle<JSString*> value,
204                                            unsigned attrs);
205 
206 extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx,
207                                            JS::Handle<JSObject*> obj,
208                                            uint32_t index, int32_t value,
209                                            unsigned attrs);
210 
211 extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx,
212                                            JS::Handle<JSObject*> obj,
213                                            uint32_t index, uint32_t value,
214                                            unsigned attrs);
215 
216 extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx,
217                                            JS::Handle<JSObject*> obj,
218                                            uint32_t index, double value,
219                                            unsigned attrs);
220 
221 /**
222  * Compute the expression `id in obj`.
223  *
224  * If obj has an own or inherited property obj[id], set *foundp = true and
225  * return true. If not, set *foundp = false and return true. On error, return
226  * false with an exception pending.
227  *
228  * Implements: ES6 [[Has]] internal method.
229  */
230 extern JS_PUBLIC_API bool JS_HasPropertyById(JSContext* cx,
231                                              JS::Handle<JSObject*> obj,
232                                              JS::Handle<jsid> id, bool* foundp);
233 
234 extern JS_PUBLIC_API bool JS_HasProperty(JSContext* cx,
235                                          JS::Handle<JSObject*> obj,
236                                          const char* name, bool* foundp);
237 
238 extern JS_PUBLIC_API bool JS_HasUCProperty(JSContext* cx,
239                                            JS::Handle<JSObject*> obj,
240                                            const char16_t* name, size_t namelen,
241                                            bool* vp);
242 
243 extern JS_PUBLIC_API bool JS_HasElement(JSContext* cx,
244                                         JS::Handle<JSObject*> obj,
245                                         uint32_t index, bool* foundp);
246 
247 /**
248  * Determine whether obj has an own property with the key `id`.
249  *
250  * Implements: ES6 7.3.11 HasOwnProperty(O, P).
251  */
252 extern JS_PUBLIC_API bool JS_HasOwnPropertyById(JSContext* cx,
253                                                 JS::Handle<JSObject*> obj,
254                                                 JS::Handle<jsid> id,
255                                                 bool* foundp);
256 
257 extern JS_PUBLIC_API bool JS_HasOwnProperty(JSContext* cx,
258                                             JS::Handle<JSObject*> obj,
259                                             const char* name, bool* foundp);
260 
261 /**
262  * Get the value of the property `obj[id]`, or undefined if no such property
263  * exists. This is the C++ equivalent of `vp = Reflect.get(obj, id, receiver)`.
264  *
265  * Most callers don't need the `receiver` argument. Consider using
266  * JS_GetProperty instead. (But if you're implementing a proxy handler's set()
267  * method, it's often correct to call this function and pass the receiver
268  * through.)
269  *
270  * Implements: ES6 [[Get]] internal method.
271  */
272 extern JS_PUBLIC_API bool JS_ForwardGetPropertyTo(
273     JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
274     JS::Handle<JS::Value> receiver, JS::MutableHandleValue vp);
275 
276 extern JS_PUBLIC_API bool JS_ForwardGetElementTo(JSContext* cx,
277                                                  JS::Handle<JSObject*> obj,
278                                                  uint32_t index,
279                                                  JS::Handle<JSObject*> receiver,
280                                                  JS::MutableHandleValue vp);
281 
282 /**
283  * Get the value of the property `obj[id]`, or undefined if no such property
284  * exists. The result is stored in vp.
285  *
286  * Implements: ES6 7.3.1 Get(O, P).
287  */
288 extern JS_PUBLIC_API bool JS_GetPropertyById(JSContext* cx,
289                                              JS::Handle<JSObject*> obj,
290                                              JS::Handle<jsid> id,
291                                              JS::MutableHandleValue vp);
292 
293 extern JS_PUBLIC_API bool JS_GetProperty(JSContext* cx,
294                                          JS::Handle<JSObject*> obj,
295                                          const char* name,
296                                          JS::MutableHandleValue vp);
297 
298 extern JS_PUBLIC_API bool JS_GetUCProperty(JSContext* cx,
299                                            JS::Handle<JSObject*> obj,
300                                            const char16_t* name, size_t namelen,
301                                            JS::MutableHandleValue vp);
302 
303 extern JS_PUBLIC_API bool JS_GetElement(JSContext* cx,
304                                         JS::Handle<JSObject*> obj,
305                                         uint32_t index,
306                                         JS::MutableHandleValue vp);
307 
308 /**
309  * Perform the same property assignment as `Reflect.set(obj, id, v, receiver)`.
310  *
311  * This function has a `receiver` argument that most callers don't need.
312  * Consider using JS_SetProperty instead.
313  *
314  * Implements: ES6 [[Set]] internal method.
315  */
316 extern JS_PUBLIC_API bool JS_ForwardSetPropertyTo(
317     JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
318     JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver,
319     JS::ObjectOpResult& result);
320 
321 /**
322  * Perform the assignment `obj[id] = v`.
323  *
324  * This function performs non-strict assignment, so if the property is
325  * read-only, nothing happens and no error is thrown.
326  */
327 extern JS_PUBLIC_API bool JS_SetPropertyById(JSContext* cx,
328                                              JS::Handle<JSObject*> obj,
329                                              JS::Handle<jsid> id,
330                                              JS::Handle<JS::Value> v);
331 
332 extern JS_PUBLIC_API bool JS_SetProperty(JSContext* cx,
333                                          JS::Handle<JSObject*> obj,
334                                          const char* name,
335                                          JS::Handle<JS::Value> v);
336 
337 extern JS_PUBLIC_API bool JS_SetUCProperty(JSContext* cx,
338                                            JS::Handle<JSObject*> obj,
339                                            const char16_t* name, size_t namelen,
340                                            JS::Handle<JS::Value> v);
341 
342 extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx,
343                                         JS::Handle<JSObject*> obj,
344                                         uint32_t index,
345                                         JS::Handle<JS::Value> v);
346 
347 extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx,
348                                         JS::Handle<JSObject*> obj,
349                                         uint32_t index,
350                                         JS::Handle<JSObject*> v);
351 
352 extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx,
353                                         JS::Handle<JSObject*> obj,
354                                         uint32_t index,
355                                         JS::Handle<JSString*> v);
356 
357 extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx,
358                                         JS::Handle<JSObject*> obj,
359                                         uint32_t index, int32_t v);
360 
361 extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx,
362                                         JS::Handle<JSObject*> obj,
363                                         uint32_t index, uint32_t v);
364 
365 extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx,
366                                         JS::Handle<JSObject*> obj,
367                                         uint32_t index, double v);
368 
369 /**
370  * Delete a property. This is the C++ equivalent of
371  * `result = Reflect.deleteProperty(obj, id)`.
372  *
373  * This function has a `result` out parameter that most callers don't need.
374  * Unless you can pass through an ObjectOpResult provided by your caller, it's
375  * probably best to use the JS_DeletePropertyById signature with just 3
376  * arguments.
377  *
378  * Implements: ES6 [[Delete]] internal method.
379  */
380 extern JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx,
381                                                 JS::Handle<JSObject*> obj,
382                                                 JS::Handle<jsid> id,
383                                                 JS::ObjectOpResult& result);
384 
385 extern JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx,
386                                             JS::Handle<JSObject*> obj,
387                                             const char* name,
388                                             JS::ObjectOpResult& result);
389 
390 extern JS_PUBLIC_API bool JS_DeleteUCProperty(JSContext* cx,
391                                               JS::Handle<JSObject*> obj,
392                                               const char16_t* name,
393                                               size_t namelen,
394                                               JS::ObjectOpResult& result);
395 
396 extern JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx,
397                                            JS::Handle<JSObject*> obj,
398                                            uint32_t index,
399                                            JS::ObjectOpResult& result);
400 
401 /**
402  * Delete a property, ignoring strict failures. This is the C++ equivalent of
403  * the JS `delete obj[id]` in non-strict mode code.
404  */
405 extern JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx,
406                                                 JS::Handle<JSObject*> obj,
407                                                 jsid id);
408 
409 extern JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx,
410                                             JS::Handle<JSObject*> obj,
411                                             const char* name);
412 
413 extern JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx,
414                                            JS::Handle<JSObject*> obj,
415                                            uint32_t index);
416 
417 /**
418  * Get an array of the non-symbol enumerable properties of obj.
419  * This function is roughly equivalent to:
420  *
421  *     var result = [];
422  *     for (key in obj) {
423  *         result.push(key);
424  *     }
425  *     return result;
426  *
427  * This is the closest thing we currently have to the ES6 [[Enumerate]]
428  * internal method.
429  *
430  * The array of ids returned by JS_Enumerate must be rooted to protect its
431  * contents from garbage collection. Use JS::Rooted<JS::IdVector>.
432  */
433 extern JS_PUBLIC_API bool JS_Enumerate(JSContext* cx, JS::Handle<JSObject*> obj,
434                                        JS::MutableHandle<JS::IdVector> props);
435 
436 /*** Other property-defining functions **************************************/
437 
438 extern JS_PUBLIC_API JSObject* JS_DefineObject(JSContext* cx,
439                                                JS::Handle<JSObject*> obj,
440                                                const char* name,
441                                                const JSClass* clasp = nullptr,
442                                                unsigned attrs = 0);
443 
444 extern JS_PUBLIC_API bool JS_DefineProperties(JSContext* cx,
445                                               JS::Handle<JSObject*> obj,
446                                               const JSPropertySpec* ps);
447 
448 /* * */
449 
450 extern JS_PUBLIC_API bool JS_AlreadyHasOwnPropertyById(
451     JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
452     bool* foundp);
453 
454 extern JS_PUBLIC_API bool JS_AlreadyHasOwnProperty(JSContext* cx,
455                                                    JS::Handle<JSObject*> obj,
456                                                    const char* name,
457                                                    bool* foundp);
458 
459 extern JS_PUBLIC_API bool JS_AlreadyHasOwnUCProperty(JSContext* cx,
460                                                      JS::Handle<JSObject*> obj,
461                                                      const char16_t* name,
462                                                      size_t namelen,
463                                                      bool* foundp);
464 
465 extern JS_PUBLIC_API bool JS_AlreadyHasOwnElement(JSContext* cx,
466                                                   JS::Handle<JSObject*> obj,
467                                                   uint32_t index, bool* foundp);
468 
469 extern JS_PUBLIC_API bool JS_DefineFunctions(JSContext* cx,
470                                              JS::Handle<JSObject*> obj,
471                                              const JSFunctionSpec* fs);
472 
473 extern JS_PUBLIC_API JSFunction* JS_DefineFunction(
474     JSContext* cx, JS::Handle<JSObject*> obj, const char* name, JSNative call,
475     unsigned nargs, unsigned attrs);
476 
477 extern JS_PUBLIC_API JSFunction* JS_DefineUCFunction(
478     JSContext* cx, JS::Handle<JSObject*> obj, const char16_t* name,
479     size_t namelen, JSNative call, unsigned nargs, unsigned attrs);
480 
481 extern JS_PUBLIC_API JSFunction* JS_DefineFunctionById(
482     JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
483     JSNative call, unsigned nargs, unsigned attrs);
484 
485 #endif /* js_PropertyAndElement_h */
486