Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
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 // A jsid is an identifier for a property or method of an object which is
11 // either a 31-bit signed integer, interned string or object.
12 //
13 // Also, there is an additional jsid value, JSID_VOID, which does not occur in
14 // JS scripts but may be used to indicate the absence of a valid jsid. A void
15 // jsid is not a valid id and only arises as an exceptional API return value,
16 // such as in JS_NextProperty. Embeddings must not pass JSID_VOID into JSAPI
17 // entry points expecting a jsid and do not need to handle JSID_VOID in hooks
18 // receiving a jsid except when explicitly noted in the API contract.
19 //
20 // A jsid is not implicitly convertible to or from a jsval; JS_ValueToId or
21 // JS_IdToValue must be used instead.
23 #include "mozilla/NullPtr.h"
25 #include "jstypes.h"
27 #include "js/HeapAPI.h"
28 #include "js/RootingAPI.h"
29 #include "js/TypeDecls.h"
30 #include "js/Utility.h"
32 struct jsid
33 {
34 size_t asBits;
35 bool operator==(jsid rhs) const { return asBits == rhs.asBits; }
36 bool operator!=(jsid rhs) const { return asBits != rhs.asBits; }
37 };
38 #define JSID_BITS(id) (id.asBits)
40 #define JSID_TYPE_STRING 0x0
41 #define JSID_TYPE_INT 0x1
42 #define JSID_TYPE_VOID 0x2
43 #define JSID_TYPE_OBJECT 0x4
44 #define JSID_TYPE_MASK 0x7
46 // Avoid using canonical 'id' for jsid parameters since this is a magic word in
47 // Objective-C++ which, apparently, wants to be able to #include jsapi.h.
48 #define id iden
50 static MOZ_ALWAYS_INLINE bool
51 JSID_IS_STRING(jsid id)
52 {
53 return (JSID_BITS(id) & JSID_TYPE_MASK) == 0;
54 }
56 static MOZ_ALWAYS_INLINE JSString *
57 JSID_TO_STRING(jsid id)
58 {
59 MOZ_ASSERT(JSID_IS_STRING(id));
60 return (JSString *)JSID_BITS(id);
61 }
63 static MOZ_ALWAYS_INLINE bool
64 JSID_IS_ZERO(jsid id)
65 {
66 return JSID_BITS(id) == 0;
67 }
69 static MOZ_ALWAYS_INLINE bool
70 JSID_IS_INT(jsid id)
71 {
72 return !!(JSID_BITS(id) & JSID_TYPE_INT);
73 }
75 static MOZ_ALWAYS_INLINE int32_t
76 JSID_TO_INT(jsid id)
77 {
78 MOZ_ASSERT(JSID_IS_INT(id));
79 return ((uint32_t)JSID_BITS(id)) >> 1;
80 }
82 #define JSID_INT_MIN 0
83 #define JSID_INT_MAX INT32_MAX
85 static MOZ_ALWAYS_INLINE bool
86 INT_FITS_IN_JSID(int32_t i)
87 {
88 return i >= 0;
89 }
91 static MOZ_ALWAYS_INLINE jsid
92 INT_TO_JSID(int32_t i)
93 {
94 jsid id;
95 MOZ_ASSERT(INT_FITS_IN_JSID(i));
96 JSID_BITS(id) = ((i << 1) | JSID_TYPE_INT);
97 return id;
98 }
100 static MOZ_ALWAYS_INLINE bool
101 JSID_IS_OBJECT(jsid id)
102 {
103 return (JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_OBJECT &&
104 (size_t)JSID_BITS(id) != JSID_TYPE_OBJECT;
105 }
107 static MOZ_ALWAYS_INLINE JSObject *
108 JSID_TO_OBJECT(jsid id)
109 {
110 MOZ_ASSERT(JSID_IS_OBJECT(id));
111 return (JSObject *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
112 }
114 static MOZ_ALWAYS_INLINE jsid
115 OBJECT_TO_JSID(JSObject *obj)
116 {
117 jsid id;
118 MOZ_ASSERT(obj != nullptr);
119 MOZ_ASSERT(((size_t)obj & JSID_TYPE_MASK) == 0);
120 JS_ASSERT(!js::gc::IsInsideNursery(js::gc::GetGCThingRuntime(obj), obj));
121 JSID_BITS(id) = ((size_t)obj | JSID_TYPE_OBJECT);
122 return id;
123 }
125 static MOZ_ALWAYS_INLINE bool
126 JSID_IS_GCTHING(jsid id)
127 {
128 return JSID_IS_STRING(id) || JSID_IS_OBJECT(id);
129 }
131 static MOZ_ALWAYS_INLINE void *
132 JSID_TO_GCTHING(jsid id)
133 {
134 return (void *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
135 }
137 static MOZ_ALWAYS_INLINE bool
138 JSID_IS_VOID(const jsid id)
139 {
140 MOZ_ASSERT_IF(((size_t)JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_VOID,
141 JSID_BITS(id) == JSID_TYPE_VOID);
142 return ((size_t)JSID_BITS(id) == JSID_TYPE_VOID);
143 }
145 static MOZ_ALWAYS_INLINE bool
146 JSID_IS_EMPTY(const jsid id)
147 {
148 return ((size_t)JSID_BITS(id) == JSID_TYPE_OBJECT);
149 }
151 #undef id
153 extern JS_PUBLIC_DATA(const jsid) JSID_VOID;
154 extern JS_PUBLIC_DATA(const jsid) JSID_EMPTY;
156 extern JS_PUBLIC_DATA(const JS::HandleId) JSID_VOIDHANDLE;
157 extern JS_PUBLIC_DATA(const JS::HandleId) JSID_EMPTYHANDLE;
159 namespace js {
161 inline bool
162 IsPoisonedId(jsid iden)
163 {
164 if (JSID_IS_STRING(iden))
165 return JS::IsPoisonedPtr(JSID_TO_STRING(iden));
166 if (JSID_IS_OBJECT(iden))
167 return JS::IsPoisonedPtr(JSID_TO_OBJECT(iden));
168 return false;
169 }
171 template <> struct GCMethods<jsid>
172 {
173 static jsid initial() { return JSID_VOID; }
174 static ThingRootKind kind() { return THING_ROOT_ID; }
175 static bool poisoned(jsid id) { return IsPoisonedId(id); }
176 static bool needsPostBarrier(jsid id) { return false; }
177 #ifdef JSGC_GENERATIONAL
178 static void postBarrier(jsid *idp) {}
179 static void relocate(jsid *idp) {}
180 #endif
181 };
183 }
185 #endif /* js_Id_h */