[SM91] Update to Spidermonkey 91.1.3 APIs
[0ad.git] / libraries / source / spidermonkey / include-win32-debug / js / Id.h
blob9ecd071c4ec8be0077ed17d4d9b5897b07c8efee
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 #ifndef js_Id_h
8 #define js_Id_h
10 // [SMDOC] Property Key / JSID
12 // A jsid is an identifier for a property or method of an object which is
13 // either a 31-bit unsigned integer, interned string or symbol.
15 // Also, there is an additional jsid value, JSID_VOID, which does not occur in
16 // JS scripts but may be used to indicate the absence of a valid jsid. A void
17 // jsid is not a valid id and only arises as an exceptional API return value,
18 // such as in JS_NextProperty. Embeddings must not pass JSID_VOID into JSAPI
19 // entry points expecting a jsid and do not need to handle JSID_VOID in hooks
20 // receiving a jsid except when explicitly noted in the API contract.
22 // A jsid is not implicitly convertible to or from a Value; JS_ValueToId or
23 // JS_IdToValue must be used instead.
25 #include "mozilla/Maybe.h"
27 #include "jstypes.h"
29 #include "js/GCAnnotations.h"
30 #include "js/HeapAPI.h"
31 #include "js/RootingAPI.h"
32 #include "js/TraceKind.h"
33 #include "js/TracingAPI.h"
34 #include "js/TypeDecls.h"
36 // All jsids with the low bit set are integer ids. This means the other type
37 // tags must all be even.
38 #define JSID_TYPE_INT_BIT 0x1
40 // Use 0 for JSID_TYPE_STRING to avoid a bitwise op for atom <-> id conversions.
41 #define JSID_TYPE_STRING 0x0
42 #define JSID_TYPE_VOID 0x2
43 #define JSID_TYPE_SYMBOL 0x4
44 // (0x6 is unused)
45 #define JSID_TYPE_MASK 0x7
47 namespace JS {
49 enum class SymbolCode : uint32_t;
51 struct PropertyKey {
52 size_t asBits;
54 constexpr PropertyKey() : asBits(JSID_TYPE_VOID) {}
56 static constexpr MOZ_ALWAYS_INLINE PropertyKey fromRawBits(size_t bits) {
57 PropertyKey id;
58 id.asBits = bits;
59 return id;
62 bool operator==(const PropertyKey& rhs) const { return asBits == rhs.asBits; }
63 bool operator!=(const PropertyKey& rhs) const { return asBits != rhs.asBits; }
65 MOZ_ALWAYS_INLINE bool isVoid() const {
66 MOZ_ASSERT_IF((asBits & JSID_TYPE_MASK) == JSID_TYPE_VOID,
67 asBits == JSID_TYPE_VOID);
68 return asBits == JSID_TYPE_VOID;
71 MOZ_ALWAYS_INLINE bool isInt() const {
72 return !!(asBits & JSID_TYPE_INT_BIT);
75 MOZ_ALWAYS_INLINE bool isString() const {
76 return (asBits & JSID_TYPE_MASK) == JSID_TYPE_STRING;
79 MOZ_ALWAYS_INLINE bool isSymbol() const {
80 return (asBits & JSID_TYPE_MASK) == JSID_TYPE_SYMBOL;
83 MOZ_ALWAYS_INLINE bool isGCThing() const { return isString() || isSymbol(); }
85 MOZ_ALWAYS_INLINE int32_t toInt() const {
86 MOZ_ASSERT(isInt());
87 uint32_t bits = static_cast<uint32_t>(asBits) >> 1;
88 return static_cast<int32_t>(bits);
91 MOZ_ALWAYS_INLINE JSString* toString() const {
92 MOZ_ASSERT(isString());
93 // Use XOR instead of `& ~JSID_TYPE_MASK` because small immediates can be
94 // encoded more efficiently on some platorms.
95 return reinterpret_cast<JSString*>(asBits ^ JSID_TYPE_STRING);
98 MOZ_ALWAYS_INLINE JS::Symbol* toSymbol() const {
99 MOZ_ASSERT(isSymbol());
100 return reinterpret_cast<JS::Symbol*>(asBits ^ JSID_TYPE_SYMBOL);
103 js::gc::Cell* toGCThing() const {
104 MOZ_ASSERT(isGCThing());
105 return reinterpret_cast<js::gc::Cell*>(asBits & ~(size_t)JSID_TYPE_MASK);
108 GCCellPtr toGCCellPtr() const {
109 js::gc::Cell* thing = toGCThing();
110 if (isString()) {
111 return JS::GCCellPtr(thing, JS::TraceKind::String);
113 MOZ_ASSERT(isSymbol());
114 return JS::GCCellPtr(thing, JS::TraceKind::Symbol);
117 bool isPrivateName() const;
119 bool isWellKnownSymbol(JS::SymbolCode code) const;
121 // This API can be used by embedders to convert pinned (aka interned) strings,
122 // as created by JS_AtomizeAndPinJSString, into PropertyKeys.
123 // This means the string does not have to be explicitly rooted.
125 // Only use this API when absolutely necessary, otherwise use JS_StringToId.
126 static PropertyKey fromPinnedString(JSString* str);
128 // Must not be used on atoms that are representable as integer PropertyKey.
129 // Prefer NameToId or AtomToId over this function:
131 // A PropertyName is an atom that does not contain an integer in the range
132 // [0, UINT32_MAX]. However, PropertyKey can only hold an integer in the range
133 // [0, JSID_INT_MAX] (where JSID_INT_MAX == 2^31-1). Thus, for the range of
134 // integers (JSID_INT_MAX, UINT32_MAX], to represent as a 'id', it must be
135 // the case id.isString() and id.toString()->isIndex(). In most
136 // cases when creating a PropertyKey, code does not have to care about
137 // this corner case because:
139 // - When given an arbitrary JSAtom*, AtomToId must be used, which checks for
140 // integer atoms representable as integer PropertyKey, and does this
141 // conversion.
143 // - When given a PropertyName*, NameToId can be used which does not need
144 // to do any dynamic checks.
146 // Thus, it is only the rare third case which needs this function, which
147 // handles any JSAtom* that is known not to be representable with an int
148 // PropertyKey.
149 static PropertyKey fromNonIntAtom(JSAtom* atom) {
150 MOZ_ASSERT((size_t(atom) & JSID_TYPE_MASK) == 0);
151 MOZ_ASSERT(PropertyKey::isNonIntAtom(atom));
152 return PropertyKey::fromRawBits(size_t(atom) | JSID_TYPE_STRING);
155 // The JSAtom/JSString type exposed to embedders is opaque.
156 static PropertyKey fromNonIntAtom(JSString* str) {
157 MOZ_ASSERT((size_t(str) & JSID_TYPE_MASK) == 0);
158 MOZ_ASSERT(PropertyKey::isNonIntAtom(str));
159 return PropertyKey::fromRawBits(size_t(str) | JSID_TYPE_STRING);
162 // Internal API!
163 // All string PropertyKeys are actually atomized.
164 MOZ_ALWAYS_INLINE bool isAtom() const { return isString(); }
166 MOZ_ALWAYS_INLINE bool isAtom(JSAtom* atom) const {
167 MOZ_ASSERT(PropertyKey::isNonIntAtom(atom));
168 return isAtom() && toAtom() == atom;
171 MOZ_ALWAYS_INLINE JSAtom* toAtom() const { return (JSAtom*)toString(); }
173 private:
174 static bool isNonIntAtom(JSAtom* atom);
175 static bool isNonIntAtom(JSString* atom);
176 } JS_HAZ_GC_POINTER;
178 } // namespace JS
180 using jsid = JS::PropertyKey;
182 #define JSID_BITS(id) (id.asBits)
184 static MOZ_ALWAYS_INLINE bool JSID_IS_STRING(jsid id) { return id.isString(); }
186 static MOZ_ALWAYS_INLINE JSString* JSID_TO_STRING(jsid id) {
187 return id.toString();
190 static MOZ_ALWAYS_INLINE bool JSID_IS_INT(jsid id) { return id.isInt(); }
192 static MOZ_ALWAYS_INLINE int32_t JSID_TO_INT(jsid id) { return id.toInt(); }
194 #define JSID_INT_MIN 0
195 #define JSID_INT_MAX INT32_MAX
197 static MOZ_ALWAYS_INLINE bool INT_FITS_IN_JSID(int32_t i) { return i >= 0; }
199 static MOZ_ALWAYS_INLINE jsid INT_TO_JSID(int32_t i) {
200 jsid id;
201 MOZ_ASSERT(INT_FITS_IN_JSID(i));
202 uint32_t bits = (static_cast<uint32_t>(i) << 1) | JSID_TYPE_INT_BIT;
203 JSID_BITS(id) = static_cast<size_t>(bits);
204 return id;
207 static MOZ_ALWAYS_INLINE jsid SYMBOL_TO_JSID(JS::Symbol* sym) {
208 jsid id;
209 MOZ_ASSERT(sym != nullptr);
210 MOZ_ASSERT((size_t(sym) & JSID_TYPE_MASK) == 0);
211 MOZ_ASSERT(!js::gc::IsInsideNursery(reinterpret_cast<js::gc::Cell*>(sym)));
212 JSID_BITS(id) = (size_t(sym) | JSID_TYPE_SYMBOL);
213 return id;
216 static MOZ_ALWAYS_INLINE bool JSID_IS_VOID(const jsid id) {
217 return id.isVoid();
220 constexpr const jsid JSID_VOID;
222 extern JS_PUBLIC_DATA const JS::HandleId JSID_VOIDHANDLE;
224 namespace JS {
226 template <>
227 struct GCPolicy<jsid> {
228 static void trace(JSTracer* trc, jsid* idp, const char* name) {
229 // It's not safe to trace unbarriered pointers except as part of root
230 // marking.
231 UnsafeTraceRoot(trc, idp, name);
233 static bool isValid(jsid id) {
234 return !id.isGCThing() ||
235 js::gc::IsCellPointerValid(id.toGCCellPtr().asCell());
238 static bool isTenured(jsid id) {
239 MOZ_ASSERT_IF(id.isGCThing(),
240 !js::gc::IsInsideNursery(id.toGCCellPtr().asCell()));
241 return true;
245 #ifdef DEBUG
246 MOZ_ALWAYS_INLINE void AssertIdIsNotGray(jsid id) {
247 if (id.isGCThing()) {
248 AssertCellIsNotGray(id.toGCCellPtr().asCell());
251 #endif
253 } // namespace JS
255 namespace js {
257 template <>
258 struct BarrierMethods<jsid> {
259 static gc::Cell* asGCThingOrNull(jsid id) {
260 if (id.isGCThing()) {
261 return id.toGCThing();
263 return nullptr;
265 static void postWriteBarrier(jsid* idp, jsid prev, jsid next) {
266 MOZ_ASSERT_IF(JSID_IS_STRING(next),
267 !gc::IsInsideNursery(JSID_TO_STRING(next)));
269 static void exposeToJS(jsid id) {
270 if (id.isGCThing()) {
271 js::gc::ExposeGCThingToActiveJS(id.toGCCellPtr());
276 // If the jsid is a GC pointer type, convert to that type and call |f| with the
277 // pointer and return the result wrapped in a Maybe, otherwise return None().
278 template <typename F>
279 auto MapGCThingTyped(const jsid& id, F&& f) {
280 if (id.isString()) {
281 return mozilla::Some(f(id.toString()));
283 if (id.isSymbol()) {
284 return mozilla::Some(f(id.toSymbol()));
286 MOZ_ASSERT(!id.isGCThing());
287 using ReturnType = decltype(f(static_cast<JSString*>(nullptr)));
288 return mozilla::Maybe<ReturnType>();
291 // If the jsid is a GC pointer type, convert to that type and call |f| with the
292 // pointer. Return whether this happened.
293 template <typename F>
294 bool ApplyGCThingTyped(const jsid& id, F&& f) {
295 return MapGCThingTyped(id,
296 [&f](auto t) {
297 f(t);
298 return true;
300 .isSome();
303 template <typename Wrapper>
304 class WrappedPtrOperations<JS::PropertyKey, Wrapper> {
305 const JS::PropertyKey& id() const {
306 return static_cast<const Wrapper*>(this)->get();
309 public:
310 bool isVoid() const { return id().isVoid(); }
311 bool isInt() const { return id().isInt(); }
312 bool isString() const { return id().isString(); }
313 bool isSymbol() const { return id().isSymbol(); }
314 bool isGCThing() const { return id().isGCThing(); }
316 int32_t toInt() const { return id().toInt(); }
317 JSString* toString() const { return id().toString(); }
318 JS::Symbol* toSymbol() const { return id().toSymbol(); }
320 bool isPrivateName() const { return id().isPrivateName(); }
322 bool isWellKnownSymbol(JS::SymbolCode code) const {
323 return id().isWellKnownSymbol(code);
326 // Internal API
327 bool isAtom() const { return id().isAtom(); }
328 bool isAtom(JSAtom* atom) const { return id().isAtom(atom); }
329 JSAtom* toAtom() const { return id().toAtom(); }
332 } // namespace js
334 #endif /* js_Id_h */