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
;
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
) {}
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;
58 SelfHostedWrapper() = delete;
60 explicit constexpr SelfHostedWrapper(const char* funname
)
65 enum class Type
: uint8_t { String
, Int32
, Double
};
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
) {}
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
);
101 JSNativeWrapper native
;
102 SelfHostedWrapper selfHosted
;
107 constexpr Accessor(JSNative op
, const JSJitInfo
* info
) : native(op
, info
) {}
109 explicit constexpr Accessor(const char* funname
) : selfHosted(funname
) {}
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
{
133 constexpr Accessors(Accessor getter
, Accessor setter
)
134 : getter(getter
), setter(setter
) {}
139 AccessorsOrValue() = delete;
141 constexpr AccessorsOrValue(Accessor getter
, Accessor setter
)
142 : accessors(getter
, setter
) {}
144 explicit constexpr AccessorsOrValue(ValueWrapper value
) : value(value
) {}
147 AccessorsOrValue(const AccessorsOrValue
& other
) = default;
149 static constexpr AccessorsOrValue
fromAccessors(Accessor getter
,
151 return AccessorsOrValue(getter
, setter
);
154 static constexpr AccessorsOrValue
fromValue(ValueWrapper value
) {
155 return AccessorsOrValue(value
);
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());
189 // JSPROP_* property attributes as defined in PropertyDescriptor.h.
192 // Whether AccessorsOrValue below stores a value, JSNative accessors, or
193 // self-hosted accessors.
194 enum class Kind
: uint8_t { Value
, SelfHostedAccessor
, NativeAccessor
};
201 JSPropertySpec() = delete;
203 constexpr JSPropertySpec(const char* name
, uint8_t attributes
, Kind kind
,
205 : name(name
), attributes_(attributes
), kind_(kind
), u(u
) {}
206 constexpr JSPropertySpec(JS::SymbolCode name
, uint8_t attributes
, Kind kind
,
208 : name(name
), attributes_(attributes
), kind_(kind
), u(u
) {}
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
),
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
),
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
,
276 return JSPropertySpec(name
, attributes
, Kind::Value
,
277 AccessorsOrValue::fromValue(
278 JSPropertySpec::ValueWrapper::stringValue(s
)));
281 static constexpr JSPropertySpec
stringValue(JS::SymbolCode name
,
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());
315 // Verify that our accessors match our Kind.
316 if (kind_
== Kind::SelfHostedAccessor
) {
317 checkAccessorsAreSelfHosted();
319 checkAccessorsAreNative();
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");
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
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>(), \
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, \
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>(), \
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
;
408 JSNativeWrapper call
;
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
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