Bug 1690340 - Part 4: Insert the "Page Source" before the "Extensions for Developers...
[gecko.git] / js / public / PropertyDescriptor.h
blobde70838f61aa5e96e2682882a31948692074c2b4
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/. */
6 /* Property descriptors and flags. */
8 #ifndef js_PropertyDescriptor_h
9 #define js_PropertyDescriptor_h
11 #include "mozilla/Assertions.h" // MOZ_ASSERT, MOZ_ASSERT_IF
13 #include <stdint.h> // uint8_t
15 #include "jstypes.h" // JS_PUBLIC_API
17 #include "js/Class.h" // JS{Getter,Setter}Op
18 #include "js/RootingAPI.h" // JS::Handle, js::{,Mutable}WrappedPtrOperations
19 #include "js/Value.h" // JS::Value
21 struct JS_PUBLIC_API JSContext;
22 class JS_PUBLIC_API JSObject;
23 class JS_PUBLIC_API JSTracer;
25 /* Property attributes, set in JSPropertySpec and passed to API functions.
27 * The data structure in which some of these values are stored only uses a
28 * uint8_t to store the relevant information. Proceed with caution if trying to
29 * reorder or change the the first byte worth of flags.
32 /** The property is visible in for/in loops. */
33 static constexpr uint8_t JSPROP_ENUMERATE = 0x01;
35 /**
36 * The property is non-writable. This flag is only valid when neither
37 * JSPROP_GETTER nor JSPROP_SETTER is set.
39 static constexpr uint8_t JSPROP_READONLY = 0x02;
41 /**
42 * The property is non-configurable: it can't be deleted, and if it's an
43 * accessor descriptor, its getter and setter can't be changed.
45 static constexpr uint8_t JSPROP_PERMANENT = 0x04;
47 /* (0x08 is unused; add to JSPROP_FLAGS_MASK if ever defined) */
49 /** The property has a getter function. */
50 static constexpr uint8_t JSPROP_GETTER = 0x10;
52 /** The property has a setter function. */
53 static constexpr uint8_t JSPROP_SETTER = 0x20;
55 /* (0x40 is unused; add to JSPROP_FLAGS_MASK if ever defined) */
57 /** A bit for internal JS engine use only. */
58 static constexpr uint8_t JSPROP_INTERNAL_USE_BIT = 0x80;
60 /* (0x1000 is unused; add to JSPROP_FLAGS_MASK if ever defined) */
62 /**
63 * Resolve hooks and enumerate hooks must pass this flag when calling
64 * JS_Define* APIs to reify lazily-defined properties.
66 * JSPROP_RESOLVING is used only with property-defining APIs. It tells the
67 * engine to skip the resolve hook when performing the lookup at the beginning
68 * of property definition. This keeps the resolve hook from accidentally
69 * triggering itself: unchecked recursion.
71 * For enumerate hooks, triggering the resolve hook would be merely silly, not
72 * fatal, except in some cases involving non-configurable properties.
74 static constexpr unsigned JSPROP_RESOLVING = 0x2000;
76 /**
77 * When redefining an existing property, ignore the value of the
78 * JSPROP_ENUMERATE flag. This flag is ignored in other situations.
80 static constexpr unsigned JSPROP_IGNORE_ENUMERATE = 0x4000;
82 /**
83 * When redefining an existing property, ignore the value of the JSPROP_READONLY
84 * flag. This flag is ignored in other situations.
86 static constexpr unsigned JSPROP_IGNORE_READONLY = 0x8000;
88 /**
89 * When redefining an existing property, ignore the value of the
90 * JSPROP_PERMANENT flag. This flag is ignored in other situations.
92 static constexpr unsigned JSPROP_IGNORE_PERMANENT = 0x10000;
94 /**
95 * When redefining an existing property, ignore the Value in the descriptor.
96 * This flag is ignored in other situations.
98 static constexpr unsigned JSPROP_IGNORE_VALUE = 0x20000;
100 /* (higher flags are unused; add to JSPROP_FLAGS_MASK if ever defined) */
102 static constexpr unsigned JSPROP_FLAGS_MASK =
103 JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_GETTER |
104 JSPROP_SETTER | JSPROP_INTERNAL_USE_BIT | JSPROP_RESOLVING |
105 JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_READONLY | JSPROP_IGNORE_PERMANENT |
106 JSPROP_IGNORE_VALUE;
108 namespace JS {
111 * A structure that represents a property on an object, or the absence of a
112 * property. Use {,Mutable}Handle<PropertyDescriptor> to interact with
113 * instances of this structure rather than interacting directly with member
114 * fields.
116 struct JS_PUBLIC_API PropertyDescriptor {
117 JSObject* obj = nullptr;
118 unsigned attrs = 0;
119 JSGetterOp getter = nullptr;
120 JSSetterOp setter = nullptr;
121 Value value;
123 PropertyDescriptor() = default;
125 void trace(JSTracer* trc);
128 } // namespace JS
130 namespace js {
132 template <typename Wrapper>
133 class WrappedPtrOperations<JS::PropertyDescriptor, Wrapper> {
134 const JS::PropertyDescriptor& desc() const {
135 return static_cast<const Wrapper*>(this)->get();
138 bool has(unsigned bit) const {
139 MOZ_ASSERT(bit != 0);
140 MOZ_ASSERT((bit & (bit - 1)) == 0); // only a single bit
141 return (desc().attrs & bit) != 0;
144 bool hasAny(unsigned bits) const { return (desc().attrs & bits) != 0; }
146 bool hasAll(unsigned bits) const { return (desc().attrs & bits) == bits; }
148 public:
149 // Descriptors with JSGetterOp/JSSetterOp are considered data
150 // descriptors. It's complicated.
151 bool isAccessorDescriptor() const {
152 return hasAny(JSPROP_GETTER | JSPROP_SETTER);
154 bool isGenericDescriptor() const {
155 return (desc().attrs & (JSPROP_GETTER | JSPROP_SETTER |
156 JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE)) ==
157 (JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE);
159 bool isDataDescriptor() const {
160 return !isAccessorDescriptor() && !isGenericDescriptor();
163 bool hasConfigurable() const { return !has(JSPROP_IGNORE_PERMANENT); }
164 bool configurable() const {
165 MOZ_ASSERT(hasConfigurable());
166 return !has(JSPROP_PERMANENT);
169 bool hasEnumerable() const { return !has(JSPROP_IGNORE_ENUMERATE); }
170 bool enumerable() const {
171 MOZ_ASSERT(hasEnumerable());
172 return has(JSPROP_ENUMERATE);
175 bool hasValue() const {
176 return !isAccessorDescriptor() && !has(JSPROP_IGNORE_VALUE);
178 JS::HandleValue value() const {
179 return JS::Handle<JS::Value>::fromMarkedLocation(&desc().value);
182 bool hasWritable() const {
183 return !isAccessorDescriptor() && !has(JSPROP_IGNORE_READONLY);
185 bool writable() const {
186 MOZ_ASSERT(hasWritable());
187 return !has(JSPROP_READONLY);
190 bool hasGetterObject() const { return has(JSPROP_GETTER); }
191 JS::Handle<JSObject*> getterObject() const {
192 MOZ_ASSERT(hasGetterObject());
193 return JS::Handle<JSObject*>::fromMarkedLocation(
194 reinterpret_cast<JSObject* const*>(&desc().getter));
196 bool hasSetterObject() const { return has(JSPROP_SETTER); }
197 JS::Handle<JSObject*> setterObject() const {
198 MOZ_ASSERT(hasSetterObject());
199 return JS::Handle<JSObject*>::fromMarkedLocation(
200 reinterpret_cast<JSObject* const*>(&desc().setter));
203 bool hasGetterOrSetter() const { return desc().getter || desc().setter; }
205 JS::Handle<JSObject*> object() const {
206 return JS::Handle<JSObject*>::fromMarkedLocation(&desc().obj);
208 unsigned attributes() const { return desc().attrs; }
209 JSGetterOp getter() const { return desc().getter; }
210 JSSetterOp setter() const { return desc().setter; }
212 void assertValid() const {
213 #ifdef DEBUG
214 MOZ_ASSERT(
215 (attributes() &
216 ~(JSPROP_ENUMERATE | JSPROP_IGNORE_ENUMERATE | JSPROP_PERMANENT |
217 JSPROP_IGNORE_PERMANENT | JSPROP_READONLY | JSPROP_IGNORE_READONLY |
218 JSPROP_IGNORE_VALUE | JSPROP_GETTER | JSPROP_SETTER |
219 JSPROP_RESOLVING | JSPROP_INTERNAL_USE_BIT)) == 0);
220 MOZ_ASSERT(!hasAll(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE));
221 MOZ_ASSERT(!hasAll(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT));
222 if (isAccessorDescriptor()) {
223 MOZ_ASSERT(!has(JSPROP_READONLY));
224 MOZ_ASSERT(!has(JSPROP_IGNORE_READONLY));
225 MOZ_ASSERT(!has(JSPROP_IGNORE_VALUE));
226 MOZ_ASSERT(!has(JSPROP_INTERNAL_USE_BIT));
227 MOZ_ASSERT(value().isUndefined());
228 MOZ_ASSERT_IF(!has(JSPROP_GETTER), !getter());
229 MOZ_ASSERT_IF(!has(JSPROP_SETTER), !setter());
230 } else {
231 MOZ_ASSERT(!hasAll(JSPROP_IGNORE_READONLY | JSPROP_READONLY));
232 MOZ_ASSERT_IF(has(JSPROP_IGNORE_VALUE), value().isUndefined());
235 MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_ENUMERATE));
236 MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_PERMANENT));
237 MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_READONLY));
238 MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_VALUE));
239 #endif
242 void assertComplete() const {
243 #ifdef DEBUG
244 assertValid();
245 MOZ_ASSERT(
246 (attributes() & ~(JSPROP_ENUMERATE | JSPROP_PERMANENT |
247 JSPROP_READONLY | JSPROP_GETTER | JSPROP_SETTER |
248 JSPROP_RESOLVING | JSPROP_INTERNAL_USE_BIT)) == 0);
249 MOZ_ASSERT_IF(isAccessorDescriptor(),
250 has(JSPROP_GETTER) && has(JSPROP_SETTER));
251 #endif
254 void assertCompleteIfFound() const {
255 #ifdef DEBUG
256 if (object()) {
257 assertComplete();
259 #endif
263 template <typename Wrapper>
264 class MutableWrappedPtrOperations<JS::PropertyDescriptor, Wrapper>
265 : public js::WrappedPtrOperations<JS::PropertyDescriptor, Wrapper> {
266 JS::PropertyDescriptor& desc() { return static_cast<Wrapper*>(this)->get(); }
268 public:
269 void clear() {
270 object().set(nullptr);
271 setAttributes(0);
272 setGetter(nullptr);
273 setSetter(nullptr);
274 value().setUndefined();
277 void initFields(JS::Handle<JSObject*> obj, JS::Handle<JS::Value> v,
278 unsigned attrs, JSGetterOp getterOp, JSSetterOp setterOp) {
279 object().set(obj);
280 value().set(v);
281 setAttributes(attrs);
282 setGetter(getterOp);
283 setSetter(setterOp);
286 void assign(JS::PropertyDescriptor& other) {
287 object().set(other.obj);
288 setAttributes(other.attrs);
289 setGetter(other.getter);
290 setSetter(other.setter);
291 value().set(other.value);
294 void setDataDescriptor(JS::Handle<JS::Value> v, unsigned attrs) {
295 MOZ_ASSERT((attrs & ~(JSPROP_ENUMERATE | JSPROP_PERMANENT |
296 JSPROP_READONLY | JSPROP_IGNORE_ENUMERATE |
297 JSPROP_IGNORE_PERMANENT | JSPROP_IGNORE_READONLY)) ==
299 object().set(nullptr);
300 setAttributes(attrs);
301 setGetter(nullptr);
302 setSetter(nullptr);
303 value().set(v);
306 JS::MutableHandle<JSObject*> object() {
307 return JS::MutableHandle<JSObject*>::fromMarkedLocation(&desc().obj);
309 unsigned& attributesRef() { return desc().attrs; }
310 JSGetterOp& getter() { return desc().getter; }
311 JSSetterOp& setter() { return desc().setter; }
312 JS::MutableHandle<JS::Value> value() {
313 return JS::MutableHandle<JS::Value>::fromMarkedLocation(&desc().value);
315 void setValue(JS::Handle<JS::Value> v) {
316 MOZ_ASSERT(!(desc().attrs & (JSPROP_GETTER | JSPROP_SETTER)));
317 attributesRef() &= ~JSPROP_IGNORE_VALUE;
318 value().set(v);
321 void setConfigurable(bool configurable) {
322 setAttributes(
323 (desc().attrs & ~(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT)) |
324 (configurable ? 0 : JSPROP_PERMANENT));
326 void setEnumerable(bool enumerable) {
327 setAttributes(
328 (desc().attrs & ~(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE)) |
329 (enumerable ? JSPROP_ENUMERATE : 0));
331 void setWritable(bool writable) {
332 MOZ_ASSERT(!(desc().attrs & (JSPROP_GETTER | JSPROP_SETTER)));
333 setAttributes((desc().attrs & ~(JSPROP_IGNORE_READONLY | JSPROP_READONLY)) |
334 (writable ? 0 : JSPROP_READONLY));
336 void setAttributes(unsigned attrs) { desc().attrs = attrs; }
338 void setGetter(JSGetterOp op) { desc().getter = op; }
339 void setSetter(JSSetterOp op) { desc().setter = op; }
340 void setGetterObject(JSObject* obj) {
341 desc().getter = reinterpret_cast<JSGetterOp>(obj);
342 desc().attrs &=
343 ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY);
344 desc().attrs |= JSPROP_GETTER;
346 void setSetterObject(JSObject* obj) {
347 desc().setter = reinterpret_cast<JSSetterOp>(obj);
348 desc().attrs &=
349 ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY);
350 desc().attrs |= JSPROP_SETTER;
353 JS::MutableHandle<JSObject*> getterObject() {
354 MOZ_ASSERT(this->hasGetterObject());
355 return JS::MutableHandle<JSObject*>::fromMarkedLocation(
356 reinterpret_cast<JSObject**>(&desc().getter));
358 JS::MutableHandle<JSObject*> setterObject() {
359 MOZ_ASSERT(this->hasSetterObject());
360 return JS::MutableHandle<JSObject*>::fromMarkedLocation(
361 reinterpret_cast<JSObject**>(&desc().setter));
365 } // namespace js
367 namespace JS {
369 extern JS_PUBLIC_API bool ObjectToCompletePropertyDescriptor(
370 JSContext* cx, Handle<JSObject*> obj, Handle<Value> descriptor,
371 MutableHandle<PropertyDescriptor> desc);
374 * ES6 draft rev 32 (2015 Feb 2) 6.2.4.4 FromPropertyDescriptor(Desc).
376 * If desc.object() is null, then vp is set to undefined.
378 extern JS_PUBLIC_API bool FromPropertyDescriptor(
379 JSContext* cx, Handle<PropertyDescriptor> desc, MutableHandle<Value> vp);
381 } // namespace JS
383 #endif /* js_PropertyDescriptor_h */