зеркало из https://github.com/mozilla/gecko-dev.git
268 строки
10 KiB
C++
268 строки
10 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/* Property descriptors and flags. */
|
|
|
|
#ifndef js_PropertySpec_h
|
|
#define js_PropertySpec_h
|
|
|
|
#include "mozilla/Assertions.h" // MOZ_ASSERT{,_IF}
|
|
|
|
#include <stddef.h> // size_t
|
|
#include <stdint.h> // uint8_t, uint16_t, int32_t, uint32_t, uintptr_t
|
|
#include <type_traits> // std::enable_if
|
|
|
|
#include "jstypes.h" // JS_PUBLIC_API
|
|
|
|
#include "js/CallArgs.h" // JSNative
|
|
#include "js/PropertyDescriptor.h" // JSPROP_*
|
|
#include "js/RootingAPI.h" // JS::MutableHandle
|
|
#include "js/Value.h" // JS::Value
|
|
|
|
struct JSContext;
|
|
struct JSJitInfo;
|
|
|
|
/**
|
|
* Wrapper to relace JSNative for JSPropertySpecs and JSFunctionSpecs. This will
|
|
* allow us to pass one JSJitInfo per function with the property/function spec,
|
|
* without additional field overhead.
|
|
*/
|
|
struct JSNativeWrapper {
|
|
JSNative op;
|
|
const JSJitInfo* info;
|
|
};
|
|
|
|
/**
|
|
* Macro static initializers which make it easy to pass no JSJitInfo as part of
|
|
* a JSPropertySpec or JSFunctionSpec.
|
|
*/
|
|
#define JSNATIVE_WRAPPER(native) \
|
|
{ \
|
|
{ native, nullptr } \
|
|
}
|
|
|
|
/**
|
|
* Description of a property. JS_DefineProperties and JS_InitClass take arrays
|
|
* of these and define many properties at once. JS_PSG, JS_PSGS and JS_PS_END
|
|
* are helper macros for defining such arrays.
|
|
*/
|
|
struct JSPropertySpec {
|
|
struct SelfHostedWrapper {
|
|
void* unused;
|
|
const char* funname;
|
|
};
|
|
|
|
struct ValueWrapper {
|
|
uintptr_t type;
|
|
union {
|
|
const char* string;
|
|
int32_t int32;
|
|
};
|
|
};
|
|
|
|
const char* name;
|
|
uint8_t flags;
|
|
union {
|
|
struct {
|
|
union {
|
|
JSNativeWrapper native;
|
|
SelfHostedWrapper selfHosted;
|
|
} getter;
|
|
union {
|
|
JSNativeWrapper native;
|
|
SelfHostedWrapper selfHosted;
|
|
} setter;
|
|
} accessors;
|
|
ValueWrapper value;
|
|
};
|
|
|
|
bool isAccessor() const { return !(flags & JSPROP_INTERNAL_USE_BIT); }
|
|
JS_PUBLIC_API bool getValue(JSContext* cx,
|
|
JS::MutableHandle<JS::Value> value) const;
|
|
|
|
bool isSelfHosted() const {
|
|
MOZ_ASSERT(isAccessor());
|
|
|
|
#ifdef DEBUG
|
|
// Verify that our accessors match our JSPROP_GETTER flag.
|
|
if (flags & JSPROP_GETTER) {
|
|
checkAccessorsAreSelfHosted();
|
|
} else {
|
|
checkAccessorsAreNative();
|
|
}
|
|
#endif
|
|
return (flags & JSPROP_GETTER);
|
|
}
|
|
|
|
static_assert(sizeof(SelfHostedWrapper) == sizeof(JSNativeWrapper),
|
|
"JSPropertySpec::getter/setter must be compact");
|
|
static_assert(offsetof(SelfHostedWrapper, funname) ==
|
|
offsetof(JSNativeWrapper, info),
|
|
"JS_SELF_HOSTED* macros below require that "
|
|
"SelfHostedWrapper::funname overlay "
|
|
"JSNativeWrapper::info");
|
|
|
|
private:
|
|
void checkAccessorsAreNative() const {
|
|
// We may have a getter or a setter or both. And whichever ones we have
|
|
// should not have a SelfHostedWrapper for the accessor.
|
|
MOZ_ASSERT_IF(accessors.getter.native.info, accessors.getter.native.op);
|
|
MOZ_ASSERT_IF(accessors.setter.native.info, accessors.setter.native.op);
|
|
}
|
|
|
|
void checkAccessorsAreSelfHosted() const {
|
|
MOZ_ASSERT(!accessors.getter.selfHosted.unused);
|
|
MOZ_ASSERT(!accessors.setter.selfHosted.unused);
|
|
}
|
|
};
|
|
|
|
namespace JS {
|
|
namespace detail {
|
|
|
|
/* NEVER DEFINED, DON'T USE. For use by JS_CAST_STRING_TO only. */
|
|
template <size_t N>
|
|
inline int CheckIsCharacterLiteral(const char (&arr)[N]);
|
|
|
|
/* NEVER DEFINED, DON'T USE. For use by JS_CAST_INT32_TO only. */
|
|
inline int CheckIsInt32(int32_t value);
|
|
|
|
} // namespace detail
|
|
} // namespace JS
|
|
|
|
#define JS_CAST_STRING_TO(s, To) \
|
|
(static_cast<void>(sizeof(JS::detail::CheckIsCharacterLiteral(s))), \
|
|
reinterpret_cast<To>(s))
|
|
|
|
#define JS_CAST_INT32_TO(s, To) \
|
|
(static_cast<void>(sizeof(JS::detail::CheckIsInt32(s))), \
|
|
reinterpret_cast<To>(s))
|
|
|
|
#define JS_CHECK_ACCESSOR_FLAGS(flags) \
|
|
(static_cast<std::enable_if<((flags) & ~(JSPROP_ENUMERATE | \
|
|
JSPROP_PERMANENT)) == 0>::type>(0), \
|
|
(flags))
|
|
|
|
#define JS_PS_ACCESSOR_SPEC(name, getter, setter, flags, extraFlags) \
|
|
{ \
|
|
name, uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | extraFlags), { \
|
|
{ getter, setter } \
|
|
} \
|
|
}
|
|
#define JS_PS_VALUE_SPEC(name, value, flags) \
|
|
{ \
|
|
name, uint8_t(flags | JSPROP_INTERNAL_USE_BIT), { \
|
|
{ value, JSNATIVE_WRAPPER(nullptr) } \
|
|
} \
|
|
}
|
|
|
|
#define SELFHOSTED_WRAPPER(name) \
|
|
{ \
|
|
{ nullptr, JS_CAST_STRING_TO(name, const JSJitInfo*) } \
|
|
}
|
|
#define STRINGVALUE_WRAPPER(value) \
|
|
{ \
|
|
{ \
|
|
reinterpret_cast<JSNative>(JSVAL_TYPE_STRING), \
|
|
JS_CAST_STRING_TO(value, const JSJitInfo*) \
|
|
} \
|
|
}
|
|
#define INT32VALUE_WRAPPER(value) \
|
|
{ \
|
|
{ \
|
|
reinterpret_cast<JSNative>(JSVAL_TYPE_INT32), \
|
|
JS_CAST_INT32_TO(value, const JSJitInfo*) \
|
|
} \
|
|
}
|
|
|
|
/*
|
|
* JSPropertySpec uses JSNativeWrapper. These macros encapsulate the definition
|
|
* of JSNative-backed JSPropertySpecs, by defining the JSNativeWrappers for
|
|
* them.
|
|
*/
|
|
#define JS_PSG(name, getter, flags) \
|
|
JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), \
|
|
JSNATIVE_WRAPPER(nullptr), flags, 0)
|
|
#define JS_PSGS(name, getter, setter, flags) \
|
|
JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), \
|
|
JSNATIVE_WRAPPER(setter), flags, 0)
|
|
#define JS_SYM_GET(symbol, getter, flags) \
|
|
JS_PS_ACCESSOR_SPEC( \
|
|
reinterpret_cast<const char*>(uint32_t(::JS::SymbolCode::symbol) + 1), \
|
|
JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(nullptr), flags, 0)
|
|
#define JS_SELF_HOSTED_GET(name, getterName, flags) \
|
|
JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), \
|
|
JSNATIVE_WRAPPER(nullptr), flags, JSPROP_GETTER)
|
|
#define JS_SELF_HOSTED_GETSET(name, getterName, setterName, flags) \
|
|
JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), \
|
|
SELFHOSTED_WRAPPER(setterName), flags, \
|
|
JSPROP_GETTER | JSPROP_SETTER)
|
|
#define JS_SELF_HOSTED_SYM_GET(symbol, getterName, flags) \
|
|
JS_PS_ACCESSOR_SPEC( \
|
|
reinterpret_cast<const char*>(uint32_t(::JS::SymbolCode::symbol) + 1), \
|
|
SELFHOSTED_WRAPPER(getterName), JSNATIVE_WRAPPER(nullptr), flags, \
|
|
JSPROP_GETTER)
|
|
#define JS_STRING_PS(name, string, flags) \
|
|
JS_PS_VALUE_SPEC(name, STRINGVALUE_WRAPPER(string), flags)
|
|
#define JS_STRING_SYM_PS(symbol, string, flags) \
|
|
JS_PS_VALUE_SPEC( \
|
|
reinterpret_cast<const char*>(uint32_t(::JS::SymbolCode::symbol) + 1), \
|
|
STRINGVALUE_WRAPPER(string), flags)
|
|
#define JS_INT32_PS(name, value, flags) \
|
|
JS_PS_VALUE_SPEC(name, INT32VALUE_WRAPPER(value), flags)
|
|
#define JS_PS_END \
|
|
JS_PS_ACCESSOR_SPEC(nullptr, JSNATIVE_WRAPPER(nullptr), \
|
|
JSNATIVE_WRAPPER(nullptr), 0, 0)
|
|
|
|
/**
|
|
* To define a native function, set call to a JSNativeWrapper. To define a
|
|
* self-hosted function, set selfHostedName to the name of a function
|
|
* compiled during JSRuntime::initSelfHosting.
|
|
*/
|
|
struct JSFunctionSpec {
|
|
const char* name;
|
|
JSNativeWrapper call;
|
|
uint16_t nargs;
|
|
uint16_t flags;
|
|
const char* selfHostedName;
|
|
};
|
|
|
|
/*
|
|
* Terminating sentinel initializer to put at the end of a JSFunctionSpec array
|
|
* that's passed to JS_DefineFunctions or JS_InitClass.
|
|
*/
|
|
#define JS_FS_END JS_FN(nullptr, nullptr, 0, 0)
|
|
|
|
/*
|
|
* Initializer macros for a JSFunctionSpec array element. JS_FNINFO allows the
|
|
* simple adding of JSJitInfos. JS_SELF_HOSTED_FN declares a self-hosted
|
|
* function. JS_INLINABLE_FN allows specifying an InlinableNative enum value for
|
|
* natives inlined or specialized by the JIT. Finally JS_FNSPEC has slots for
|
|
* all the fields.
|
|
*
|
|
* The _SYM variants allow defining a function with a symbol key rather than a
|
|
* string key. For example, use JS_SYM_FN(iterator, ...) to define an
|
|
* @@iterator method.
|
|
*/
|
|
#define JS_FN(name, call, nargs, flags) \
|
|
JS_FNSPEC(name, call, nullptr, nargs, flags, nullptr)
|
|
#define JS_INLINABLE_FN(name, call, nargs, flags, native) \
|
|
JS_FNSPEC(name, call, &js::jit::JitInfo_##native, nargs, flags, nullptr)
|
|
#define JS_SYM_FN(symbol, call, nargs, flags) \
|
|
JS_SYM_FNSPEC(symbol, call, nullptr, nargs, flags, nullptr)
|
|
#define JS_FNINFO(name, call, info, nargs, flags) \
|
|
JS_FNSPEC(name, call, info, nargs, flags, nullptr)
|
|
#define JS_SELF_HOSTED_FN(name, selfHostedName, nargs, flags) \
|
|
JS_FNSPEC(name, nullptr, nullptr, nargs, flags, selfHostedName)
|
|
#define JS_SELF_HOSTED_SYM_FN(symbol, selfHostedName, nargs, flags) \
|
|
JS_SYM_FNSPEC(symbol, nullptr, nullptr, nargs, flags, selfHostedName)
|
|
#define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \
|
|
JS_FNSPEC( \
|
|
reinterpret_cast<const char*>(uint32_t(::JS::SymbolCode::symbol) + 1), \
|
|
call, info, nargs, flags, selfHostedName)
|
|
#define JS_FNSPEC(name, call, info, nargs, flags, selfHostedName) \
|
|
{ name, {call, info}, nargs, flags, selfHostedName }
|
|
|
|
#endif // js_PropertySpec_h
|