Bug 1874684 - Part 25: Editorial updates. r=dminor
[gecko.git] / js / public / PropertySpec.h
blob0c37e598fbca68249700c0ea70e4a821ec49550f
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_PropertySpec_h
9 #define js_PropertySpec_h
11 #include "mozilla/Assertions.h" // MOZ_ASSERT{,_IF}
13 #include <stddef.h> // size_t
14 #include <stdint.h> // uint8_t, uint16_t, int32_t, uint32_t, uintptr_t
15 #include <type_traits> // std::enable_if
17 #include "jstypes.h" // JS_PUBLIC_API
19 #include "js/CallArgs.h" // JSNative
20 #include "js/PropertyDescriptor.h" // JSPROP_*
21 #include "js/RootingAPI.h" // JS::MutableHandle
22 #include "js/Symbol.h" // JS::SymbolCode, PropertySpecNameIsSymbol
23 #include "js/Value.h" // JS::Value
25 struct JS_PUBLIC_API JSContext;
26 class JSJitInfo;
28 /**
29 * Wrapper to relace JSNative for JSPropertySpecs and JSFunctionSpecs. This will
30 * allow us to pass one JSJitInfo per function with the property/function spec,
31 * without additional field overhead.
33 struct JSNativeWrapper {
34 JSNative op = nullptr;
35 const JSJitInfo* info = nullptr;
37 JSNativeWrapper() = default;
39 JSNativeWrapper(const JSNativeWrapper& other) = default;
41 constexpr JSNativeWrapper(JSNative op, const JSJitInfo* info)
42 : op(op), info(info) {}
45 /**
46 * Description of a property. JS_DefineProperties and JS_InitClass take arrays
47 * of these and define many properties at once. JS_PSG, JS_PSGS and JS_PS_END
48 * are helper macros for defining such arrays.
50 struct JSPropertySpec {
51 struct SelfHostedWrapper {
52 // The same type as JSNativeWrapper's first field, so that the access in
53 // JSPropertySpec::checkAccessorsAreSelfHosted become valid.
54 JSNative unused = nullptr;
56 const char* funname;
58 SelfHostedWrapper() = delete;
60 explicit constexpr SelfHostedWrapper(const char* funname)
61 : funname(funname) {}
64 struct ValueWrapper {
65 enum class Type : uint8_t { String, Int32, Double };
66 Type type;
67 union {
68 const char* string;
69 int32_t int32;
70 double double_;
73 private:
74 ValueWrapper() = delete;
76 explicit constexpr ValueWrapper(int32_t n) : type(Type::Int32), int32(n) {}
78 explicit constexpr ValueWrapper(const char* s)
79 : type(Type::String), string(s) {}
81 explicit constexpr ValueWrapper(double d)
82 : type(Type::Double), double_(d) {}
84 public:
85 ValueWrapper(const ValueWrapper& other) = default;
87 static constexpr ValueWrapper int32Value(int32_t n) {
88 return ValueWrapper(n);
91 static constexpr ValueWrapper stringValue(const char* s) {
92 return ValueWrapper(s);
95 static constexpr ValueWrapper doubleValue(double d) {
96 return ValueWrapper(d);
100 union Accessor {
101 JSNativeWrapper native;
102 SelfHostedWrapper selfHosted;
104 private:
105 Accessor() = delete;
107 constexpr Accessor(JSNative op, const JSJitInfo* info) : native(op, info) {}
109 explicit constexpr Accessor(const char* funname) : selfHosted(funname) {}
111 public:
112 Accessor(const Accessor& other) = default;
114 static constexpr Accessor nativeAccessor(JSNative op,
115 const JSJitInfo* info = nullptr) {
116 return Accessor(op, info);
119 static constexpr Accessor selfHostedAccessor(const char* funname) {
120 return Accessor(funname);
123 static constexpr Accessor noAccessor() {
124 return Accessor(nullptr, nullptr);
128 union AccessorsOrValue {
129 struct Accessors {
130 Accessor getter;
131 Accessor setter;
133 constexpr Accessors(Accessor getter, Accessor setter)
134 : getter(getter), setter(setter) {}
135 } accessors;
136 ValueWrapper value;
138 private:
139 AccessorsOrValue() = delete;
141 constexpr AccessorsOrValue(Accessor getter, Accessor setter)
142 : accessors(getter, setter) {}
144 explicit constexpr AccessorsOrValue(ValueWrapper value) : value(value) {}
146 public:
147 AccessorsOrValue(const AccessorsOrValue& other) = default;
149 static constexpr AccessorsOrValue fromAccessors(Accessor getter,
150 Accessor setter) {
151 return AccessorsOrValue(getter, setter);
154 static constexpr AccessorsOrValue fromValue(ValueWrapper value) {
155 return AccessorsOrValue(value);
159 union Name {
160 private:
161 const char* string_;
162 uintptr_t symbol_;
164 public:
165 Name() = delete;
167 explicit constexpr Name(const char* str) : string_(str) {}
168 explicit constexpr Name(JS::SymbolCode symbol)
169 : symbol_(uint32_t(symbol) + 1) {}
171 explicit operator bool() const { return !!symbol_; }
173 bool isSymbol() const { return JS::PropertySpecNameIsSymbol(symbol_); }
174 JS::SymbolCode symbol() const {
175 MOZ_ASSERT(isSymbol());
176 return JS::SymbolCode(symbol_ - 1);
179 bool isString() const { return !isSymbol(); }
180 const char* string() const {
181 MOZ_ASSERT(isString());
182 return string_;
186 Name name;
188 private:
189 // JSPROP_* property attributes as defined in PropertyDescriptor.h.
190 uint8_t attributes_;
192 // Whether AccessorsOrValue below stores a value, JSNative accessors, or
193 // self-hosted accessors.
194 enum class Kind : uint8_t { Value, SelfHostedAccessor, NativeAccessor };
195 Kind kind_;
197 public:
198 AccessorsOrValue u;
200 private:
201 JSPropertySpec() = delete;
203 constexpr JSPropertySpec(const char* name, uint8_t attributes, Kind kind,
204 AccessorsOrValue u)
205 : name(name), attributes_(attributes), kind_(kind), u(u) {}
206 constexpr JSPropertySpec(JS::SymbolCode name, uint8_t attributes, Kind kind,
207 AccessorsOrValue u)
208 : name(name), attributes_(attributes), kind_(kind), u(u) {}
210 public:
211 JSPropertySpec(const JSPropertySpec& other) = default;
213 static constexpr JSPropertySpec nativeAccessors(
214 const char* name, uint8_t attributes, JSNative getter,
215 const JSJitInfo* getterInfo, JSNative setter = nullptr,
216 const JSJitInfo* setterInfo = nullptr) {
217 return JSPropertySpec(
218 name, attributes, Kind::NativeAccessor,
219 AccessorsOrValue::fromAccessors(
220 JSPropertySpec::Accessor::nativeAccessor(getter, getterInfo),
221 JSPropertySpec::Accessor::nativeAccessor(setter, setterInfo)));
224 static constexpr JSPropertySpec nativeAccessors(
225 JS::SymbolCode name, uint8_t attributes, JSNative getter,
226 const JSJitInfo* getterInfo, JSNative setter = nullptr,
227 const JSJitInfo* setterInfo = nullptr) {
228 return JSPropertySpec(
229 name, attributes, Kind::NativeAccessor,
230 AccessorsOrValue::fromAccessors(
231 JSPropertySpec::Accessor::nativeAccessor(getter, getterInfo),
232 JSPropertySpec::Accessor::nativeAccessor(setter, setterInfo)));
235 static constexpr JSPropertySpec selfHostedAccessors(
236 const char* name, uint8_t attributes, const char* getterName,
237 const char* setterName = nullptr) {
238 return JSPropertySpec(
239 name, attributes, Kind::SelfHostedAccessor,
240 AccessorsOrValue::fromAccessors(
241 JSPropertySpec::Accessor::selfHostedAccessor(getterName),
242 setterName
243 ? JSPropertySpec::Accessor::selfHostedAccessor(setterName)
244 : JSPropertySpec::Accessor::noAccessor()));
247 static constexpr JSPropertySpec selfHostedAccessors(
248 JS::SymbolCode name, uint8_t attributes, const char* getterName,
249 const char* setterName = nullptr) {
250 return JSPropertySpec(
251 name, attributes, Kind::SelfHostedAccessor,
252 AccessorsOrValue::fromAccessors(
253 JSPropertySpec::Accessor::selfHostedAccessor(getterName),
254 setterName
255 ? JSPropertySpec::Accessor::selfHostedAccessor(setterName)
256 : JSPropertySpec::Accessor::noAccessor()));
259 static constexpr JSPropertySpec int32Value(const char* name,
260 uint8_t attributes, int32_t n) {
261 return JSPropertySpec(name, attributes, Kind::Value,
262 AccessorsOrValue::fromValue(
263 JSPropertySpec::ValueWrapper::int32Value(n)));
266 static constexpr JSPropertySpec int32Value(JS::SymbolCode name,
267 uint8_t attributes, int32_t n) {
268 return JSPropertySpec(name, attributes, Kind::Value,
269 AccessorsOrValue::fromValue(
270 JSPropertySpec::ValueWrapper::int32Value(n)));
273 static constexpr JSPropertySpec stringValue(const char* name,
274 uint8_t attributes,
275 const char* s) {
276 return JSPropertySpec(name, attributes, Kind::Value,
277 AccessorsOrValue::fromValue(
278 JSPropertySpec::ValueWrapper::stringValue(s)));
281 static constexpr JSPropertySpec stringValue(JS::SymbolCode name,
282 uint8_t attributes,
283 const char* s) {
284 return JSPropertySpec(name, attributes, Kind::Value,
285 AccessorsOrValue::fromValue(
286 JSPropertySpec::ValueWrapper::stringValue(s)));
289 static constexpr JSPropertySpec doubleValue(const char* name,
290 uint8_t attributes, double d) {
291 return JSPropertySpec(name, attributes, Kind::Value,
292 AccessorsOrValue::fromValue(
293 JSPropertySpec::ValueWrapper::doubleValue(d)));
296 static constexpr JSPropertySpec sentinel() {
297 return JSPropertySpec(nullptr, 0, Kind::NativeAccessor,
298 AccessorsOrValue::fromAccessors(
299 JSPropertySpec::Accessor::noAccessor(),
300 JSPropertySpec::Accessor::noAccessor()));
303 unsigned attributes() const { return attributes_; }
305 bool isAccessor() const {
306 return (kind_ == Kind::NativeAccessor || kind_ == Kind::SelfHostedAccessor);
309 JS_PUBLIC_API bool getValue(JSContext* cx,
310 JS::MutableHandle<JS::Value> value) const;
312 bool isSelfHosted() const {
313 MOZ_ASSERT(isAccessor());
314 #ifdef DEBUG
315 // Verify that our accessors match our Kind.
316 if (kind_ == Kind::SelfHostedAccessor) {
317 checkAccessorsAreSelfHosted();
318 } else {
319 checkAccessorsAreNative();
321 #endif
322 return kind_ == Kind::SelfHostedAccessor;
325 static_assert(sizeof(SelfHostedWrapper) == sizeof(JSNativeWrapper),
326 "JSPropertySpec::getter/setter must be compact");
327 static_assert(offsetof(SelfHostedWrapper, unused) ==
328 offsetof(JSNativeWrapper, op) &&
329 offsetof(SelfHostedWrapper, funname) ==
330 offsetof(JSNativeWrapper, info),
331 "checkAccessorsAreNative below require that "
332 "SelfHostedWrapper::funname overlay "
333 "JSNativeWrapper::info and "
334 "SelfHostedWrapper::unused overlay "
335 "JSNativeWrapper::op");
337 private:
338 void checkAccessorsAreNative() const {
339 // We may have a getter or a setter or both. And whichever ones we have
340 // should not have a SelfHostedWrapper for the accessor.
341 MOZ_ASSERT_IF(u.accessors.getter.native.info, u.accessors.getter.native.op);
342 MOZ_ASSERT_IF(u.accessors.setter.native.info, u.accessors.setter.native.op);
345 void checkAccessorsAreSelfHosted() const {
346 MOZ_ASSERT(!u.accessors.getter.selfHosted.unused);
347 MOZ_ASSERT(!u.accessors.setter.selfHosted.unused);
351 // There can be many JSPropertySpec instances so verify the size is what we
352 // expect:
354 // - Name (1 word)
355 // - attributes_ + isAccessor_ (1 word)
356 // - AccessorsOrValue (4 words, native + JSJitInfo for both getter and setter)
357 static_assert(sizeof(JSPropertySpec) == 6 * sizeof(uintptr_t));
359 template <unsigned Attributes>
360 constexpr uint8_t CheckAccessorAttrs() {
361 static_assert((Attributes & ~(JSPROP_ENUMERATE | JSPROP_PERMANENT)) == 0,
362 "Unexpected flag (not JSPROP_ENUMERATE or JSPROP_PERMANENT)");
363 return uint8_t(Attributes);
366 #define JS_PSG(name, getter, attributes) \
367 JSPropertySpec::nativeAccessors(name, CheckAccessorAttrs<attributes>(), \
368 getter, nullptr)
369 #define JS_PSGS(name, getter, setter, attributes) \
370 JSPropertySpec::nativeAccessors(name, CheckAccessorAttrs<attributes>(), \
371 getter, nullptr, setter, nullptr)
372 #define JS_SYM_GET(symbol, getter, attributes) \
373 JSPropertySpec::nativeAccessors(::JS::SymbolCode::symbol, \
374 CheckAccessorAttrs<attributes>(), getter, \
375 nullptr)
376 #define JS_SYM_GETSET(symbol, getter, setter, attributes) \
377 JSPropertySpec::nativeAccessors(::JS::SymbolCode::symbol, \
378 CheckAccessorAttrs<attributes>(), getter, \
379 nullptr, setter, nullptr)
380 #define JS_SELF_HOSTED_GET(name, getterName, attributes) \
381 JSPropertySpec::selfHostedAccessors(name, CheckAccessorAttrs<attributes>(), \
382 getterName)
383 #define JS_SELF_HOSTED_GETSET(name, getterName, setterName, attributes) \
384 JSPropertySpec::selfHostedAccessors(name, CheckAccessorAttrs<attributes>(), \
385 getterName, setterName)
386 #define JS_SELF_HOSTED_SYM_GET(symbol, getterName, attributes) \
387 JSPropertySpec::selfHostedAccessors( \
388 ::JS::SymbolCode::symbol, CheckAccessorAttrs<attributes>(), getterName)
389 #define JS_STRING_PS(name, string, attributes) \
390 JSPropertySpec::stringValue(name, attributes, string)
391 #define JS_STRING_SYM_PS(symbol, string, attributes) \
392 JSPropertySpec::stringValue(::JS::SymbolCode::symbol, attributes, string)
393 #define JS_INT32_PS(name, value, attributes) \
394 JSPropertySpec::int32Value(name, attributes, value)
395 #define JS_DOUBLE_PS(name, value, attributes) \
396 JSPropertySpec::doubleValue(name, attributes, value)
397 #define JS_PS_END JSPropertySpec::sentinel()
400 * To define a native function, set call to a JSNativeWrapper. To define a
401 * self-hosted function, set selfHostedName to the name of a function
402 * compiled during JSRuntime::initSelfHosting.
404 struct JSFunctionSpec {
405 using Name = JSPropertySpec::Name;
407 Name name;
408 JSNativeWrapper call;
409 uint16_t nargs;
410 uint16_t flags;
411 const char* selfHostedName;
413 // JSPROP_* property attributes as defined in PropertyDescriptor.h
414 unsigned attributes() const { return flags; }
418 * Terminating sentinel initializer to put at the end of a JSFunctionSpec array
419 * that's passed to JS_DefineFunctions or JS_InitClass.
421 #define JS_FS_END JS_FN(nullptr, nullptr, 0, 0)
424 * Initializer macros for a JSFunctionSpec array element.
426 * - JS_FNINFO allows the simple adding of JSJitInfos.
427 * - JS_SELF_HOSTED_FN declares a self-hosted function.
428 * - JS_INLINABLE_FN allows specifying an InlinableNative enum value for natives
429 * inlined or specialized by the JIT.
430 * - JS_TRAMPOLINE_FN allows specifying a TrampolineNative enum value for
431 * natives that have a JitEntry trampoline.
432 * - JS_FNSPEC has slots for all the fields.
434 * The _SYM variants allow defining a function with a symbol key rather than a
435 * string key. For example, use JS_SYM_FN(iterator, ...) to define an
436 * @@iterator method.
438 #define JS_FN(name, call, nargs, flags) \
439 JS_FNSPEC(name, call, nullptr, nargs, flags, nullptr)
440 #define JS_INLINABLE_FN(name, call, nargs, flags, native) \
441 JS_FNSPEC(name, call, &js::jit::JitInfo_##native, nargs, flags, nullptr)
442 #define JS_TRAMPOLINE_FN(name, call, nargs, flags, native) \
443 JS_FNSPEC(name, call, &js::jit::JitInfo_##native, nargs, flags, nullptr)
444 #define JS_SYM_FN(symbol, call, nargs, flags) \
445 JS_SYM_FNSPEC(symbol, call, nullptr, nargs, flags, nullptr)
446 #define JS_FNINFO(name, call, info, nargs, flags) \
447 JS_FNSPEC(name, call, info, nargs, flags, nullptr)
448 #define JS_SELF_HOSTED_FN(name, selfHostedName, nargs, flags) \
449 JS_FNSPEC(name, nullptr, nullptr, nargs, flags, selfHostedName)
450 #define JS_SELF_HOSTED_SYM_FN(symbol, selfHostedName, nargs, flags) \
451 JS_SYM_FNSPEC(symbol, nullptr, nullptr, nargs, flags, selfHostedName)
452 #define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \
453 JS_FNSPEC(::JS::SymbolCode::symbol, call, info, nargs, flags, selfHostedName)
454 #define JS_FNSPEC(name, call, info, nargs, flags, selfHostedName) \
455 { JSFunctionSpec::Name(name), {call, info}, nargs, flags, selfHostedName }
457 #endif // js_PropertySpec_h