--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1128,16 +1128,98 @@ VariantToJsval(JSContext* aCx, nsIVarian
Throw(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
}
return false;
}
return true;
}
+static int
+CompareIdsAtIndices(const void* aElement1, const void* aElement2, void* aClosure)
+{
+ const uint16_t index1 = *static_cast<const uint16_t*>(aElement1);
+ const uint16_t index2 = *static_cast<const uint16_t*>(aElement2);
+ const PropertyInfo* infos = static_cast<PropertyInfo*>(aClosure);
+
+ MOZ_ASSERT(JSID_BITS(infos[index1].id) != JSID_BITS(infos[index2].id));
+
+ return JSID_BITS(infos[index1].id) < JSID_BITS(infos[index2].id) ? -1 : 1;
+}
+
+template <typename SpecT>
+static bool
+InitIdsInternal(JSContext* cx, const Prefable<SpecT>* pref, PropertyInfo* infos,
+ PropertyType type)
+{
+ MOZ_ASSERT(pref);
+ MOZ_ASSERT(pref->specs);
+
+ // Index of the Prefable that contains the id for the current PropertyInfo.
+ uint32_t prefIndex = 0;
+
+ do {
+ // We ignore whether the set of ids is enabled and just intern all the IDs,
+ // because this is only done once per application runtime.
+ const SpecT* spec = pref->specs;
+ // Index of the property/function/constant spec for our current PropertyInfo
+ // in the "specs" array of the relevant Prefable.
+ uint32_t specIndex = 0;
+ do {
+ if (!JS::PropertySpecNameToPermanentId(cx, spec->name, &infos->id)) {
+ return false;
+ }
+ infos->type = type;
+ infos->prefIndex = prefIndex;
+ infos->specIndex = specIndex++;
+ ++infos;
+ } while ((++spec)->name);
+ ++prefIndex;
+ } while ((++pref)->specs);
+
+ return true;
+}
+
+#define INIT_IDS_IF_DEFINED(TypeName) { \
+ if (nativeProperties->Has##TypeName##s() && \
+ !InitIdsInternal(cx, \
+ nativeProperties->TypeName##s(), \
+ nativeProperties->TypeName##PropertyInfos(), \
+ e##TypeName)) { \
+ return false; \
+ } \
+}
+
+bool
+InitIds(JSContext* cx, const NativeProperties* nativeProperties)
+{
+ INIT_IDS_IF_DEFINED(StaticMethod);
+ INIT_IDS_IF_DEFINED(StaticAttribute);
+ INIT_IDS_IF_DEFINED(Method);
+ INIT_IDS_IF_DEFINED(Attribute);
+ INIT_IDS_IF_DEFINED(UnforgeableMethod);
+ INIT_IDS_IF_DEFINED(UnforgeableAttribute);
+ INIT_IDS_IF_DEFINED(Constant);
+
+ // Initialize and sort the index array.
+ uint16_t* indices = nativeProperties->sortedPropertyIndices;
+ for (unsigned int i = 0; i < nativeProperties->propertyInfoCount; ++i) {
+ indices[i] = i;
+ }
+ // CompareIdsAtIndices() doesn't actually modify the PropertyInfo array, so
+ // the const_cast here is OK in spite of the signature of NS_QuickSort().
+ NS_QuickSort(indices, nativeProperties->propertyInfoCount, sizeof(uint16_t),
+ CompareIdsAtIndices,
+ const_cast<PropertyInfo*>(nativeProperties->PropertyInfos()));
+
+ return true;
+}
+
+#undef INIT_IDS_IF_DEFINED
+
bool
QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp)
{
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
JS::Rooted<JS::Value> thisv(cx, JS_THIS(cx, vp));
if (thisv.isNull())
return false;
@@ -1284,259 +1366,221 @@ XrayCreateFunction(JSContext* cx, JS::Ha
JS::ObjectValue(*wrapper));
#ifdef DEBUG
js::SetFunctionNativeReserved(obj, XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_SELF,
JS::ObjectValue(*obj));
#endif
return obj;
}
+struct IdToIndexComparator
+{
+ // The id we're searching for.
+ const jsid& mId;
+ // The list of ids we're searching in.
+ const PropertyInfo* mInfos;
+
+ explicit IdToIndexComparator(const jsid& aId, const PropertyInfo* aInfos) :
+ mId(aId), mInfos(aInfos) {}
+ int operator()(const uint16_t aIndex) const {
+ if (JSID_BITS(mId) == JSID_BITS(mInfos[aIndex].id)) {
+ return 0;
+ }
+ return JSID_BITS(mId) < JSID_BITS(mInfos[aIndex].id) ? -1 : 1;
+ }
+};
+
+static const PropertyInfo*
+XrayFindOwnPropertyInfo(JSContext* cx, JS::Handle<jsid> id,
+ const NativeProperties* nativeProperties)
+{
+ if (MOZ_UNLIKELY(nativeProperties->iteratorAliasMethodIndex >= 0) &&
+ id == SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::iterator))) {
+ return nativeProperties->MethodPropertyInfos() +
+ nativeProperties->iteratorAliasMethodIndex;
+ }
+
+ size_t idx;
+ const uint16_t* sortedPropertyIndices = nativeProperties->sortedPropertyIndices;
+ const PropertyInfo* propertyInfos = nativeProperties->PropertyInfos();
+
+ if (BinarySearchIf(sortedPropertyIndices, 0,
+ nativeProperties->propertyInfoCount,
+ IdToIndexComparator(id, propertyInfos), &idx)) {
+ return propertyInfos + sortedPropertyIndices[idx];
+ }
+
+ return nullptr;
+}
+
static bool
XrayResolveAttribute(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
- const Prefable<const JSPropertySpec>* attributes,
- const jsid* attributeIds,
- const JSPropertySpec* attributeSpecs,
+ const Prefable<const JSPropertySpec>& pref,
+ const JSPropertySpec& attrSpec,
JS::MutableHandle<JS::PropertyDescriptor> desc,
bool& cacheOnHolder)
{
- for (; attributes->specs; ++attributes) {
- if (attributes->isEnabled(cx, obj)) {
- // Set i to be the index into our full list of ids/specs that we're
- // looking at now.
- size_t i = attributes->specs - attributeSpecs;
- for ( ; attributeIds[i] != JSID_VOID; ++i) {
- if (id == attributeIds[i]) {
- cacheOnHolder = true;
-
- const JSPropertySpec& attrSpec = attributeSpecs[i];
- // Because of centralization, we need to make sure we fault in the
- // JitInfos as well. At present, until the JSAPI changes, the easiest
- // way to do this is wrap them up as functions ourselves.
- desc.setAttributes(attrSpec.flags);
- // They all have getters, so we can just make it.
- JS::Rooted<JSObject*> funobj(cx,
- XrayCreateFunction(cx, wrapper, attrSpec.accessors.getter.native, 0, id));
- if (!funobj)
- return false;
- desc.setGetterObject(funobj);
- desc.attributesRef() |= JSPROP_GETTER;
- if (attrSpec.accessors.setter.native.op) {
- // We have a setter! Make it.
- funobj =
- XrayCreateFunction(cx, wrapper, attrSpec.accessors.setter.native, 1, id);
- if (!funobj)
- return false;
- desc.setSetterObject(funobj);
- desc.attributesRef() |= JSPROP_SETTER;
- } else {
- desc.setSetter(nullptr);
- }
- desc.object().set(wrapper);
- desc.value().setUndefined();
- return true;
- }
- }
- }
+ if (!pref.isEnabled(cx, obj)) {
+ return true;
}
+
+ cacheOnHolder = true;
+
+ // Because of centralization, we need to make sure we fault in the JitInfos as
+ // well. At present, until the JSAPI changes, the easiest way to do this is
+ // wrap them up as functions ourselves.
+ desc.setAttributes(attrSpec.flags);
+ // They all have getters, so we can just make it.
+ JS::Rooted<JSObject*> funobj(cx,
+ XrayCreateFunction(cx, wrapper, attrSpec.accessors.getter.native, 0, id));
+ if (!funobj)
+ return false;
+ desc.setGetterObject(funobj);
+ desc.attributesRef() |= JSPROP_GETTER;
+ if (attrSpec.accessors.setter.native.op) {
+ // We have a setter! Make it.
+ funobj =
+ XrayCreateFunction(cx, wrapper, attrSpec.accessors.setter.native, 1, id);
+ if (!funobj)
+ return false;
+ desc.setSetterObject(funobj);
+ desc.attributesRef() |= JSPROP_SETTER;
+ } else {
+ desc.setSetter(nullptr);
+ }
+ desc.object().set(wrapper);
+ desc.value().setUndefined();
+
return true;
}
static bool
XrayResolveMethod(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
- const Prefable<const JSFunctionSpec>* methods,
- const jsid* methodIds,
- const JSFunctionSpec* methodSpecs,
+ const Prefable<const JSFunctionSpec>& pref,
+ const JSFunctionSpec& methodSpec,
JS::MutableHandle<JS::PropertyDescriptor> desc,
bool& cacheOnHolder)
{
- const Prefable<const JSFunctionSpec>* method;
- for (method = methods; method->specs; ++method) {
- if (method->isEnabled(cx, obj)) {
- // Set i to be the index into our full list of ids/specs that we're
- // looking at now.
- size_t i = method->specs - methodSpecs;
- for ( ; methodIds[i] != JSID_VOID; ++i) {
- if (id == methodIds[i]) {
- cacheOnHolder = true;
-
- const JSFunctionSpec& methodSpec = methodSpecs[i];
- JSObject *funobj;
- if (methodSpec.selfHostedName) {
- JSFunction* fun =
- JS::GetSelfHostedFunction(cx, methodSpec.selfHostedName, id,
- methodSpec.nargs);
- if (!fun) {
- return false;
- }
- MOZ_ASSERT(!methodSpec.call.op, "Bad FunctionSpec declaration: non-null native");
- MOZ_ASSERT(!methodSpec.call.info, "Bad FunctionSpec declaration: non-null jitinfo");
- funobj = JS_GetFunctionObject(fun);
- } else {
- funobj = XrayCreateFunction(cx, wrapper, methodSpec.call,
- methodSpec.nargs, id);
- if (!funobj) {
- return false;
- }
- }
- desc.value().setObject(*funobj);
- desc.setAttributes(methodSpec.flags);
- desc.object().set(wrapper);
- desc.setSetter(nullptr);
- desc.setGetter(nullptr);
- return true;
- }
- }
+ if (!pref.isEnabled(cx, obj)) {
+ return true;
+ }
+
+ cacheOnHolder = true;
+
+ JSObject *funobj;
+ if (methodSpec.selfHostedName) {
+ JSFunction* fun =
+ JS::GetSelfHostedFunction(cx, methodSpec.selfHostedName, id,
+ methodSpec.nargs);
+ if (!fun) {
+ return false;
+ }
+ MOZ_ASSERT(!methodSpec.call.op, "Bad FunctionSpec declaration: non-null native");
+ MOZ_ASSERT(!methodSpec.call.info, "Bad FunctionSpec declaration: non-null jitinfo");
+ funobj = JS_GetFunctionObject(fun);
+ } else {
+ funobj = XrayCreateFunction(cx, wrapper, methodSpec.call,
+ methodSpec.nargs, id);
+ if (!funobj) {
+ return false;
}
}
- return true;
-}
-
-// Try to resolve a property as an unforgeable property from the given
-// NativeProperties, if it's there. nativeProperties is allowed to be null (in
-// which case we of course won't resolve anything).
-static bool
-XrayResolveUnforgeableProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
- JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
- JS::MutableHandle<JS::PropertyDescriptor> desc,
- bool& cacheOnHolder,
- const NativeProperties* nativeProperties)
-{
- if (!nativeProperties) {
- return true;
- }
-
- if (nativeProperties->HasUnforgeableAttributes()) {
- if (!XrayResolveAttribute(cx, wrapper, obj, id,
- nativeProperties->UnforgeableAttributes(),
- nativeProperties->UnforgeableAttributeIds(),
- nativeProperties->UnforgeableAttributeSpecs(),
- desc, cacheOnHolder)) {
- return false;
- }
-
- if (desc.object()) {
- return true;
- }
- }
-
- if (nativeProperties->HasUnforgeableMethods()) {
- if (!XrayResolveMethod(cx, wrapper, obj, id,
- nativeProperties->UnforgeableMethods(),
- nativeProperties->UnforgeableMethodIds(),
- nativeProperties->UnforgeableMethodSpecs(),
- desc, cacheOnHolder)) {
- return false;
- }
-
- if (desc.object()) {
- return true;
- }
- }
+ desc.value().setObject(*funobj);
+ desc.setAttributes(methodSpec.flags);
+ desc.object().set(wrapper);
+ desc.setSetter(nullptr);
+ desc.setGetter(nullptr);
return true;
}
static bool
+XrayResolveConstant(JSContext* cx, JS::Handle<JSObject*> wrapper,
+ JS::Handle<JSObject*> obj, JS::Handle<jsid>,
+ const Prefable<const ConstantSpec>& pref,
+ const ConstantSpec& constantSpec,
+ JS::MutableHandle<JS::PropertyDescriptor> desc,
+ bool& cacheOnHolder)
+{
+ if (!pref.isEnabled(cx, obj)) {
+ return true;
+ }
+
+ cacheOnHolder = true;
+
+ desc.setAttributes(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
+ desc.object().set(wrapper);
+ desc.value().set(constantSpec.value);
+
+ return true;
+}
+
+#define RESOLVE_CASE(PropType, SpecType, Resolver) \
+ case e##PropType: { \
+ MOZ_ASSERT(nativeProperties->Has##PropType##s()); \
+ const Prefable<const SpecType>& pref = \
+ nativeProperties->PropType##s()[propertyInfo.prefIndex]; \
+ return Resolver(cx, wrapper, obj, id, pref, \
+ pref.specs[propertyInfo.specIndex], desc, cacheOnHolder); \
+ }
+
+static bool
XrayResolveProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
JS::MutableHandle<JS::PropertyDescriptor> desc,
bool& cacheOnHolder, DOMObjectType type,
- const NativeProperties* nativeProperties)
+ const NativeProperties* nativeProperties,
+ const PropertyInfo& propertyInfo)
{
- bool hasMethods = false;
- if (type == eInterface) {
- hasMethods = nativeProperties->HasStaticMethods();
- } else {
- hasMethods = nativeProperties->HasMethods();
- }
- if (hasMethods) {
- const Prefable<const JSFunctionSpec>* methods;
- const jsid* methodIds;
- const JSFunctionSpec* methodSpecs;
- if (type == eInterface) {
- methods = nativeProperties->StaticMethods();
- methodIds = nativeProperties->StaticMethodIds();
- methodSpecs = nativeProperties->StaticMethodSpecs();
- } else {
- methods = nativeProperties->Methods();
- methodIds = nativeProperties->MethodIds();
- methodSpecs = nativeProperties->MethodSpecs();
+ MOZ_ASSERT(type != eGlobalInterfacePrototype);
+
+ // Make sure we resolve for matched object type.
+ switch (propertyInfo.type) {
+ case eStaticMethod:
+ case eStaticAttribute:
+ if (type != eInterface) {
+ return true;
}
- JS::Rooted<jsid> methodId(cx);
- if (nativeProperties->iteratorAliasMethodIndex != -1 &&
- id == SYMBOL_TO_JSID(
- JS::GetWellKnownSymbol(cx, JS::SymbolCode::iterator))) {
- methodId =
- nativeProperties->MethodIds()[nativeProperties->iteratorAliasMethodIndex];
- } else {
- methodId = id;
- }
- if (!XrayResolveMethod(cx, wrapper, obj, methodId, methods, methodIds,
- methodSpecs, desc, cacheOnHolder)) {
- return false;
- }
- if (desc.object()) {
+ break;
+ case eMethod:
+ case eAttribute:
+ if (type != eGlobalInstance && type != eInterfacePrototype) {
return true;
}
- }
-
- if (type == eInterface) {
- if (nativeProperties->HasStaticAttributes()) {
- if (!XrayResolveAttribute(cx, wrapper, obj, id,
- nativeProperties->StaticAttributes(),
- nativeProperties->StaticAttributeIds(),
- nativeProperties->StaticAttributeSpecs(),
- desc, cacheOnHolder)) {
- return false;
- }
- if (desc.object()) {
- return true;
- }
+ break;
+ case eUnforgeableMethod:
+ case eUnforgeableAttribute:
+ if (!IsInstance(type)) {
+ return true;
+ }
+ break;
+ case eConstant:
+ if (IsInstance(type)) {
+ return true;
}
- } else {
- if (nativeProperties->HasAttributes()) {
- if (!XrayResolveAttribute(cx, wrapper, obj, id,
- nativeProperties->Attributes(),
- nativeProperties->AttributeIds(),
- nativeProperties->AttributeSpecs(),
- desc, cacheOnHolder)) {
- return false;
- }
- if (desc.object()) {
- return true;
- }
- }
+ break;
}
- if (nativeProperties->HasConstants()) {
- const Prefable<const ConstantSpec>* constant;
- for (constant = nativeProperties->Constants(); constant->specs; ++constant) {
- if (constant->isEnabled(cx, obj)) {
- // Set i to be the index into our full list of ids/specs that we're
- // looking at now.
- size_t i = constant->specs - nativeProperties->ConstantSpecs();
- for ( ; nativeProperties->ConstantIds()[i] != JSID_VOID; ++i) {
- if (id == nativeProperties->ConstantIds()[i]) {
- cacheOnHolder = true;
-
- desc.setAttributes(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
- desc.object().set(wrapper);
- desc.value().set(nativeProperties->ConstantSpecs()[i].value);
- return true;
- }
- }
- }
- }
+ switch (propertyInfo.type) {
+ RESOLVE_CASE(StaticMethod, JSFunctionSpec, XrayResolveMethod)
+ RESOLVE_CASE(StaticAttribute, JSPropertySpec, XrayResolveAttribute)
+ RESOLVE_CASE(Method, JSFunctionSpec, XrayResolveMethod)
+ RESOLVE_CASE(Attribute, JSPropertySpec, XrayResolveAttribute)
+ RESOLVE_CASE(UnforgeableMethod, JSFunctionSpec, XrayResolveMethod)
+ RESOLVE_CASE(UnforgeableAttribute, JSPropertySpec, XrayResolveAttribute)
+ RESOLVE_CASE(Constant, ConstantSpec, XrayResolveConstant)
}
return true;
}
+#undef RESOLVE_CASE
+
static bool
ResolvePrototypeOrConstructor(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj,
size_t protoAndIfaceCacheIndex, unsigned attrs,
JS::MutableHandle<JS::PropertyDescriptor> desc,
bool& cacheOnHolder)
{
JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj));
@@ -1607,47 +1651,53 @@ XrayResolveOwnProperty(JSContext* cx, JS
JS::MutableHandle<JS::PropertyDescriptor> desc,
bool& cacheOnHolder)
{
cacheOnHolder = false;
DOMObjectType type;
const NativePropertyHooks *nativePropertyHooks =
GetNativePropertyHooks(cx, obj, type);
- const NativePropertiesHolder& nativeProperties =
- nativePropertyHooks->mNativeProperties;
ResolveOwnProperty resolveOwnProperty =
nativePropertyHooks->mResolveOwnProperty;
if (type == eNamedPropertiesObject) {
// None of these should be cached on the holder, since they're dynamic.
return resolveOwnProperty(cx, wrapper, obj, id, desc);
}
- // Check for unforgeable properties first.
- if (IsInstance(type)) {
- const NativePropertiesHolder& nativeProperties =
- nativePropertyHooks->mNativeProperties;
- if (!XrayResolveUnforgeableProperty(cx, wrapper, obj, id, desc, cacheOnHolder,
- nativeProperties.regular)) {
- return false;
- }
-
- if (!desc.object() && xpc::AccessCheck::isChrome(wrapper) &&
- !XrayResolveUnforgeableProperty(cx, wrapper, obj, id, desc, cacheOnHolder,
- nativeProperties.chromeOnly)) {
- return false;
- }
-
- if (desc.object()) {
- return true;
- }
+ const NativePropertiesHolder& nativePropertiesHolder =
+ nativePropertyHooks->mNativeProperties;
+ const NativeProperties* nativeProperties = nullptr;
+ const PropertyInfo* found = nullptr;
+
+ if ((nativeProperties = nativePropertiesHolder.regular)) {
+ found = XrayFindOwnPropertyInfo(cx, id, nativeProperties);
+ }
+ if (!found &&
+ (nativeProperties = nativePropertiesHolder.chromeOnly) &&
+ xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper))) {
+ found = XrayFindOwnPropertyInfo(cx, id, nativeProperties);
}
if (IsInstance(type)) {
+ // Check for unforgeable properties first to prevent names provided by
+ // resolveOwnProperty callback from shadowing them.
+ if (found && (found->type == eUnforgeableMethod ||
+ found->type == eUnforgeableAttribute)) {
+ if (!XrayResolveProperty(cx, wrapper, obj, id, desc, cacheOnHolder, type,
+ nativeProperties, *found)) {
+ return false;
+ }
+
+ if (desc.object()) {
+ return true;
+ }
+ }
+
if (resolveOwnProperty) {
if (!resolveOwnProperty(cx, wrapper, obj, id, desc)) {
return false;
}
if (desc.object()) {
// None of these should be cached on the holder, since they're dynamic.
return true;
@@ -1729,27 +1779,19 @@ XrayResolveOwnProperty(JSContext* cx, JS
// The properties for globals live on the instance, so return here as there
// are no properties on their interface prototype object.
if (type == eGlobalInterfacePrototype) {
return true;
}
}
- if (nativeProperties.regular &&
+ if (found &&
!XrayResolveProperty(cx, wrapper, obj, id, desc, cacheOnHolder, type,
- nativeProperties.regular)) {
- return false;
- }
-
- if (!desc.object() &&
- nativeProperties.chromeOnly &&
- xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
- !XrayResolveProperty(cx, wrapper, obj, id, desc, cacheOnHolder, type,
- nativeProperties.chromeOnly)) {
+ nativeProperties, *found)) {
return false;
}
return true;
}
bool
XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
@@ -1761,53 +1803,91 @@ XrayDefineProperty(JSContext* cx, JS::Ha
return true;
const DOMProxyHandler* handler = GetDOMProxyHandler(obj);
return handler->defineProperty(cx, wrapper, id, desc, result, defined);
}
template<typename SpecType>
bool
-XrayAttributeOrMethodKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
- JS::Handle<JSObject*> obj,
- const Prefable<const SpecType>* list,
- const jsid* ids, const SpecType* specList,
- unsigned flags, JS::AutoIdVector& props)
+XrayAppendPropertyKeys(JSContext* cx, JS::Handle<JSObject*> obj,
+ const Prefable<const SpecType>* pref,
+ const PropertyInfo* infos, unsigned flags,
+ JS::AutoIdVector& props)
{
- for (; list->specs; ++list) {
- if (list->isEnabled(cx, obj)) {
- // Set i to be the index into our full list of ids/specs that we're
- // looking at now.
- size_t i = list->specs - specList;
- for ( ; ids[i] != JSID_VOID; ++i) {
- // Skip non-enumerable properties and symbol-keyed properties unless
- // they are specially requested via flags.
+ do {
+ bool prefIsEnabled = pref->isEnabled(cx, obj);
+ if (prefIsEnabled) {
+ const SpecType* spec = pref->specs;
+ do {
+ const jsid& id = infos++->id;
if (((flags & JSITER_HIDDEN) ||
- (specList[i].flags & JSPROP_ENUMERATE)) &&
- ((flags & JSITER_SYMBOLS) || !JSID_IS_SYMBOL(ids[i])) &&
- !props.append(ids[i])) {
+ (spec->flags & JSPROP_ENUMERATE)) &&
+ ((flags & JSITER_SYMBOLS) || !JSID_IS_SYMBOL(id)) &&
+ !props.append(id)) {
return false;
}
- }
+ } while ((++spec)->name);
+ }
+ // Break if we have reached the end of pref.
+ if (!(++pref)->specs) {
+ break;
}
- }
+ // Advance infos if the previous pref is disabled. The -1 is required
+ // because there is an end-of-list terminator between pref->specs and
+ // (pref - 1)->specs.
+ if (!prefIsEnabled) {
+ infos += pref->specs - (pref - 1)->specs - 1;
+ }
+ } while (1);
+
return true;
}
-#define ADD_KEYS_IF_DEFINED(FieldName) { \
- if (nativeProperties->Has##FieldName##s() && \
- !XrayAttributeOrMethodKeys(cx, wrapper, obj, \
- nativeProperties->FieldName##s(), \
- nativeProperties->FieldName##Ids(), \
- nativeProperties->FieldName##Specs(), \
- flags, props)) { \
- return false; \
- } \
+template<>
+bool
+XrayAppendPropertyKeys<ConstantSpec>(JSContext* cx, JS::Handle<JSObject*> obj,
+ const Prefable<const ConstantSpec>* pref,
+ const PropertyInfo* infos, unsigned flags,
+ JS::AutoIdVector& props)
+{
+ do {
+ bool prefIsEnabled = pref->isEnabled(cx, obj);
+ if (prefIsEnabled) {
+ const ConstantSpec* spec = pref->specs;
+ do {
+ if (!props.append(infos++->id)) {
+ return false;
+ }
+ } while ((++spec)->name);
+ }
+ // Break if we have reached the end of pref.
+ if (!(++pref)->specs) {
+ break;
+ }
+ // Advance infos if the previous pref is disabled. The -1 is required
+ // because there is an end-of-list terminator between pref->specs and
+ // (pref - 1)->specs.
+ if (!prefIsEnabled) {
+ infos += pref->specs - (pref - 1)->specs - 1;
+ }
+ } while (1);
+
+ return true;
}
+#define ADD_KEYS_IF_DEFINED(FieldName) { \
+ if (nativeProperties->Has##FieldName##s() && \
+ !XrayAppendPropertyKeys(cx, obj, \
+ nativeProperties->FieldName##s(), \
+ nativeProperties->FieldName##PropertyInfos(), \
+ flags, props)) { \
+ return false; \
+ } \
+}
bool
XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj,
unsigned flags, JS::AutoIdVector& props,
DOMObjectType type,
const NativeProperties* nativeProperties)
{
@@ -1815,39 +1895,27 @@ XrayOwnPropertyKeys(JSContext* cx, JS::H
if (IsInstance(type)) {
ADD_KEYS_IF_DEFINED(UnforgeableMethod);
ADD_KEYS_IF_DEFINED(UnforgeableAttribute);
if (type == eGlobalInstance) {
ADD_KEYS_IF_DEFINED(Method);
ADD_KEYS_IF_DEFINED(Attribute);
}
- } else if (type == eInterface) {
- ADD_KEYS_IF_DEFINED(StaticMethod);
- ADD_KEYS_IF_DEFINED(StaticAttribute);
- } else if (type != eGlobalInterfacePrototype) {
- MOZ_ASSERT(IsInterfacePrototype(type));
- ADD_KEYS_IF_DEFINED(Method);
- ADD_KEYS_IF_DEFINED(Attribute);
- }
-
- if (nativeProperties->HasConstants()) {
- const Prefable<const ConstantSpec>* constant;
- for (constant = nativeProperties->Constants(); constant->specs; ++constant) {
- if (constant->isEnabled(cx, obj)) {
- // Set i to be the index into our full list of ids/specs that we're
- // looking at now.
- size_t i = constant->specs - nativeProperties->ConstantSpecs();
- for ( ; nativeProperties->ConstantIds()[i] != JSID_VOID; ++i) {
- if (!props.append(nativeProperties->ConstantIds()[i])) {
- return false;
- }
- }
- }
+ } else {
+ MOZ_ASSERT(type != eGlobalInterfacePrototype);
+ if (type == eInterface) {
+ ADD_KEYS_IF_DEFINED(StaticMethod);
+ ADD_KEYS_IF_DEFINED(StaticAttribute);
+ } else {
+ MOZ_ASSERT(type == eInterfacePrototype);
+ ADD_KEYS_IF_DEFINED(Method);
+ ADD_KEYS_IF_DEFINED(Attribute);
}
+ ADD_KEYS_IF_DEFINED(Constant);
}
return true;
}
#undef ADD_KEYS_IF_DEFINED
bool
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1773,41 +1773,18 @@ AtomizeAndPinJSString(JSContext* cx, jsi
{
if (JSString *str = ::JS_AtomizeAndPinString(cx, chars)) {
id = INTERNED_STRING_TO_JSID(cx, str);
return true;
}
return false;
}
-// Spec needs a name property
-template <typename Spec>
-static bool
-InitIds(JSContext* cx, const Prefable<Spec>* prefableSpecs, jsid* ids)
-{
- MOZ_ASSERT(prefableSpecs);
- MOZ_ASSERT(prefableSpecs->specs);
- do {
- // We ignore whether the set of ids is enabled and just intern all the IDs,
- // because this is only done once per application runtime.
- Spec* spec = prefableSpecs->specs;
- do {
- if (!JS::PropertySpecNameToPermanentId(cx, spec->name, ids)) {
- return false;
- }
- } while (++ids, (++spec)->name);
-
- // We ran out of ids for that pref. Put a JSID_VOID in on the id
- // corresponding to the list terminator for the pref.
- *ids = JSID_VOID;
- ++ids;
- } while ((++prefableSpecs)->specs);
-
- return true;
-}
+bool
+InitIds(JSContext* cx, const NativeProperties* properties);
bool
QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
template <class T>
struct
WantsQueryInterface
{
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2131,24 +2131,25 @@ class PropertyDefiner:
else:
if self.hasNonChromeOnly():
return "s" + self.name
return "nullptr"
def usedForXrays(self):
return self.descriptor.wantsXrays
+ def length(self, chrome):
+ return len(self.chrome) if chrome else len(self.regular)
+
def __str__(self):
# We only need to generate id arrays for things that will end
# up used via ResolveProperty or EnumerateProperties.
- str = self.generateArray(self.regular, self.variableName(False),
- self.usedForXrays())
+ str = self.generateArray(self.regular, self.variableName(False))
if self.hasChromeOnly():
- str += self.generateArray(self.chrome, self.variableName(True),
- self.usedForXrays())
+ str += self.generateArray(self.chrome, self.variableName(True))
return str
@staticmethod
def getStringAttr(member, name):
attr = member.getExtendedAttribute(name)
if attr is None:
return None
# It's a list of strings
@@ -2165,17 +2166,17 @@ class PropertyDefiner:
PropertyDefiner.getStringAttr(interfaceMember,
"Pref"),
PropertyDefiner.getStringAttr(interfaceMember,
"Func"),
interfaceMember.getExtendedAttribute("SecureContext") is not None,
nonExposureSet)
def generatePrefableArray(self, array, name, specFormatter, specTerminator,
- specType, getCondition, getDataTuple, doIdArrays):
+ specType, getCondition, getDataTuple):
"""
This method generates our various arrays.
array is an array of interface members as passed to generateArray
name is the name as passed to generateArray
specFormatter is a function that takes a single argument, a tuple,
@@ -2234,27 +2235,36 @@ class PropertyDefiner:
condition.nonExposedGlobals,
condition.func))
else:
prefableSpecs.append(prefableWithoutDisablersTemplate %
(name, len(specs)))
switchToCondition(self, lastCondition)
+ numSpecsInCurPrefable = 0
+ maxNumSpecsInPrefable = 0
+
for member in array:
curCondition = getCondition(member, self.descriptor)
if lastCondition != curCondition:
# Terminate previous list
specs.append(specTerminator)
+ if numSpecsInCurPrefable > maxNumSpecsInPrefable:
+ maxNumSpecsInPrefable = numSpecsInCurPrefable
+ numSpecsInCurPrefable = 0
# And switch to our new condition
switchToCondition(self, curCondition)
lastCondition = curCondition
# And the actual spec
specs.append(specFormatter(getDataTuple(member)))
+ numSpecsInCurPrefable += 1
specs.append(specTerminator)
+ if numSpecsInCurPrefable > maxNumSpecsInPrefable:
+ maxNumSpecsInPrefable = numSpecsInCurPrefable
prefableSpecs.append(" { nullptr, nullptr }")
specType = "const " + specType
arrays = fill(
"""
// We deliberately use brace-elision to make Visual Studio produce better initalization code.
#if defined(__clang__)
#pragma clang diagnostic push
@@ -2274,18 +2284,32 @@ class PropertyDefiner:
};
""",
specType=specType,
name=name,
disablers='\n'.join(disablers),
specs=',\n'.join(specs),
prefableSpecs=',\n'.join(prefableSpecs))
- if doIdArrays:
- arrays += "static jsid %s_ids[%i];\n\n" % (name, len(specs))
+
+ if self.usedForXrays():
+ arrays = fill(
+ """
+ $*{arrays}
+ static_assert(${numPrefableSpecs} <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
+ "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
+ static_assert(${maxNumSpecsInPrefable} <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
+ "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");
+
+ """,
+ arrays=arrays,
+ # Minus 1 because there's a list terminator in prefableSpecs.
+ numPrefableSpecs=len(prefableSpecs)-1,
+ maxNumSpecsInPrefable=maxNumSpecsInPrefable)
+
return arrays
# The length of a method is the minimum of the lengths of the
# argument lists of all its overloads.
def overloadLength(arguments):
i = len(arguments)
while i > 0 and arguments[i - 1].optional:
@@ -2563,17 +2587,17 @@ class MethodDefiner(PropertyDefiner):
if not descriptor.interface.hasInterfaceObject():
# static methods go on the interface object
assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
else:
if not descriptor.interface.hasInterfacePrototypeObject():
# non-static methods go on the interface prototype object
assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
- def generateArray(self, array, name, doIdArrays):
+ def generateArray(self, array, name):
if len(array) == 0:
return ""
def condition(m, d):
return m["condition"]
def flags(m):
unforgeable = " | JSPROP_PERMANENT | JSPROP_READONLY" if self.unforgeable else ""
@@ -2624,17 +2648,17 @@ class MethodDefiner(PropertyDefiner):
return ' JS_SYM_FNSPEC(%s, %s, %s, %s, %s, %s)' % fields
return ' JS_FNSPEC("%s", %s, %s, %s, %s, %s)' % fields
return self.generatePrefableArray(
array, name,
formatSpec,
' JS_FS_END',
'JSFunctionSpec',
- condition, specData, doIdArrays)
+ condition, specData)
def IsCrossOriginWritable(attr, descriptor):
"""
Return whether the IDLAttribute in question is cross-origin writable on the
interface represented by descriptor. This is needed to handle the fact that
some, but not all, interfaces implementing URLUtils want a cross-origin
writable .href.
@@ -2674,17 +2698,17 @@ class AttrDefiner(PropertyDefiner):
if not descriptor.interface.hasInterfaceObject():
# static attributes go on the interface object
assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
else:
if not descriptor.interface.hasInterfacePrototypeObject():
# non-static attributes go on the interface prototype object
assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
- def generateArray(self, array, name, doIdArrays):
+ def generateArray(self, array, name):
if len(array) == 0:
return ""
def flags(attr):
unforgeable = " | JSPROP_PERMANENT" if self.unforgeable else ""
# Attributes generated as part of a maplike/setlike declaration are
# not enumerable.
enumerable = " | JSPROP_ENUMERATE" if not attr.isMaplikeOrSetlikeAttr() else ""
@@ -2757,44 +2781,44 @@ class AttrDefiner(PropertyDefiner):
return (attr.identifier.name, flags(attr), getter(attr),
setter(attr))
return self.generatePrefableArray(
array, name,
lambda fields: ' { "%s", %s, %s, %s }' % fields,
' { nullptr, 0, nullptr, nullptr, nullptr, nullptr }',
'JSPropertySpec',
- PropertyDefiner.getControllingCondition, specData, doIdArrays)
+ PropertyDefiner.getControllingCondition, specData)
class ConstDefiner(PropertyDefiner):
"""
A class for definining constants on the interface object
"""
def __init__(self, descriptor, name):
PropertyDefiner.__init__(self, descriptor, name)
self.name = name
constants = [m for m in descriptor.interface.members if m.isConst()]
self.chrome = [m for m in constants if isChromeOnly(m)]
self.regular = [m for m in constants if not isChromeOnly(m)]
- def generateArray(self, array, name, doIdArrays):
+ def generateArray(self, array, name):
if len(array) == 0:
return ""
def specData(const):
return (const.identifier.name,
convertConstIDLValueToJSVal(const.value))
return self.generatePrefableArray(
array, name,
lambda fields: ' { "%s", %s }' % fields,
' { 0, JS::UndefinedValue() }',
'ConstantSpec',
- PropertyDefiner.getControllingCondition, specData, doIdArrays)
+ PropertyDefiner.getControllingCondition, specData)
class PropertyArrays():
def __init__(self, descriptor):
self.staticMethods = MethodDefiner(descriptor, "StaticMethods",
static=True)
self.staticAttrs = AttrDefiner(descriptor, "StaticAttributes",
static=True)
@@ -2826,53 +2850,94 @@ class PropertyArrays():
class CGNativeProperties(CGList):
def __init__(self, descriptor, properties):
def generateNativeProperties(name, chrome):
def check(p):
return p.hasChromeOnly() if chrome else p.hasNonChromeOnly()
nativePropsInts = []
- nativePropsTrios = []
+ nativePropsPtrs = []
+ nativePropsDuos = []
+
+ duosOffset = 0
+ idsOffset = 0
+ for array in properties.arrayNames():
+ propertyArray = getattr(properties, array)
+ if check(propertyArray):
+ varName = propertyArray.variableName(chrome)
+ bitfields = "true, %d /* %s */" % (duosOffset, varName)
+ duosOffset += 1
+ nativePropsInts.append(CGGeneric(bitfields))
+
+ if propertyArray.usedForXrays():
+ ids = "&%s_propertyInfos[%d]" % (name, idsOffset)
+ idsOffset += propertyArray.length(chrome)
+ else:
+ ids = "nullptr"
+ duo = "{ %s, %s }" % (varName, ids)
+ nativePropsDuos.append(CGGeneric(duo))
+ else:
+ bitfields = "false, 0"
+ nativePropsInts.append(CGGeneric(bitfields))
iteratorAliasIndex = -1
for index, item in enumerate(properties.methods.regular):
if item.get("hasIteratorAlias"):
iteratorAliasIndex = index
break
nativePropsInts.append(CGGeneric(str(iteratorAliasIndex)))
- offset = 0
- for array in properties.arrayNames():
- propertyArray = getattr(properties, array)
- if check(propertyArray):
- varName = propertyArray.variableName(chrome)
- bitfields = "true, %d /* %s */" % (offset, varName)
- offset += 1
- nativePropsInts.append(CGGeneric(bitfields))
-
- if propertyArray.usedForXrays():
- ids = "%(name)s_ids"
- else:
- ids = "nullptr"
- trio = "{ %(name)s, " + ids + ", %(name)s_specs }"
- trio = trio % {'name': varName}
- nativePropsTrios.append(CGGeneric(trio))
- else:
- bitfields = "false, 0"
- nativePropsInts.append(CGGeneric(bitfields))
-
- nativePropsTrios = \
- [CGWrapper(CGIndenter(CGList(nativePropsTrios, ",\n")),
+ nativePropsDuos = \
+ [CGWrapper(CGIndenter(CGList(nativePropsDuos, ",\n")),
pre='{\n', post='\n}')]
- nativeProps = nativePropsInts + nativePropsTrios
+
pre = ("static const NativePropertiesN<%d> %s = {\n" %
- (offset, name))
+ (duosOffset, name))
+ post = "\n};\n"
+ if descriptor.wantsXrays:
+ pre = fill(
+ """
+ static uint16_t ${name}_sortedPropertyIndices[${size}];
+ static PropertyInfo ${name}_propertyInfos[${size}];
+
+ $*{pre}
+ """,
+ name=name,
+ size=idsOffset,
+ pre=pre)
+ if iteratorAliasIndex > 0:
+ # The iteratorAliasMethodIndex is a signed integer, so the
+ # max value it can store is 2^(nbits-1)-1.
+ post = fill(
+ """
+ $*{post}
+ static_assert(${iteratorAliasIndex} < 1ull << (CHAR_BIT * sizeof(${name}.iteratorAliasMethodIndex) - 1),
+ "We have an iterator alias index that is oversized");
+ """,
+ post=post,
+ iteratorAliasIndex=iteratorAliasIndex,
+ name=name)
+ post = fill(
+ """
+ $*{post}
+ static_assert(${propertyInfoCount} < 1ull << CHAR_BIT * sizeof(${name}.propertyInfoCount),
+ "We have a property info count that is oversized");
+ """,
+ post=post,
+ propertyInfoCount=idsOffset,
+ name=name)
+ nativePropsInts.append(CGGeneric("%d" % idsOffset))
+ nativePropsPtrs.append(CGGeneric("%s_sortedPropertyIndices" % name))
+ else:
+ nativePropsInts.append(CGGeneric("0"))
+ nativePropsPtrs.append(CGGeneric("nullptr"))
+ nativeProps = nativePropsInts + nativePropsPtrs + nativePropsDuos
return CGWrapper(CGIndenter(CGList(nativeProps, ",\n")),
- pre=pre, post="\n};\n")
+ pre=pre, post=post)
nativeProperties = []
if properties.hasNonChromeOnly():
nativeProperties.append(
generateNativeProperties("sNativeProperties", False))
if properties.hasChromeOnly():
nativeProperties.append(
generateNativeProperties("sChromeOnlyNativeProperties", True))
@@ -2977,26 +3042,23 @@ class CGCreateInterfaceObjectsMethod(CGA
}
""",
type=constructorProtoType,
getConstructorProto=getConstructorProto)
idsToInit = []
# There is no need to init any IDs in bindings that don't want Xrays.
if self.descriptor.wantsXrays:
- for var in self.properties.arrayNames():
- props = getattr(self.properties, var)
- # We only have non-chrome ids to init if we have no chrome ids.
- if props.hasChromeOnly():
- idsToInit.append(props.variableName(True))
- if props.hasNonChromeOnly():
- idsToInit.append(props.variableName(False))
+ if self.properties.hasNonChromeOnly():
+ idsToInit.append("sNativeProperties")
+ if self.properties.hasChromeOnly():
+ idsToInit.append("sChromeOnlyNativeProperties")
if len(idsToInit) > 0:
- initIdCalls = ["!InitIds(aCx, %s, %s_ids)" % (varname, varname)
- for varname in idsToInit]
+ initIdCalls = ["!InitIds(aCx, %s.Upcast())" % (properties)
+ for properties in idsToInit]
idsInitedFlag = CGGeneric("static bool sIdsInited = false;\n")
setFlag = CGGeneric("sIdsInited = true;\n")
initIdConditionals = [CGIfWrapper(CGGeneric("return;\n"), call)
for call in initIdCalls]
initIds = CGList([idsInitedFlag,
CGIfWrapper(CGList(initIdConditionals + [setFlag]),
"!sIdsInited && NS_IsMainThread()")])
else:
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -165,107 +165,152 @@ struct Prefable {
PrefableDisablers* const disablers;
// Array of specs, terminated in whatever way is customary for T.
// Null to indicate a end-of-array for Prefable, when such an
// indicator is needed.
const T* const specs;
};
-// Conceptually, NativeProperties has seven (Prefable<T>*, jsid*, T*) trios
+enum PropertyType {
+ eStaticMethod,
+ eStaticAttribute,
+ eMethod,
+ eAttribute,
+ eUnforgeableMethod,
+ eUnforgeableAttribute,
+ eConstant,
+ ePropertyTypeCount
+};
+
+#define NUM_BITS_PROPERTY_INFO_TYPE 3
+#define NUM_BITS_PROPERTY_INFO_PREF_INDEX 13
+#define NUM_BITS_PROPERTY_INFO_SPEC_INDEX 16
+
+struct PropertyInfo {
+ jsid id;
+ // One of PropertyType, will be used for accessing the corresponding Duo in
+ // NativePropertiesN.duos[].
+ uint32_t type: NUM_BITS_PROPERTY_INFO_TYPE;
+ // The index to the corresponding Preable in Duo.mPrefables[].
+ uint32_t prefIndex: NUM_BITS_PROPERTY_INFO_PREF_INDEX;
+ // The index to the corresponding spec in Duo.mPrefables[prefIndex].specs[].
+ uint32_t specIndex: NUM_BITS_PROPERTY_INFO_SPEC_INDEX;
+};
+
+static_assert(ePropertyTypeCount <= 1ull << NUM_BITS_PROPERTY_INFO_TYPE,
+ "We have property type count that is > (1 << NUM_BITS_PROPERTY_INFO_TYPE)");
+
+// Conceptually, NativeProperties has seven (Prefable<T>*, PropertyInfo*) duos
// (where T is one of JSFunctionSpec, JSPropertySpec, or ConstantSpec), one for
// each of: static methods and attributes, methods and attributes, unforgeable
// methods and attributes, and constants.
//
-// That's 21 pointers, but in most instances most of the trios are all null,
-// and there are many instances. To save space we use a variable-length type,
+// That's 14 pointers, but in most instances most of the duos are all null, and
+// there are many instances. To save space we use a variable-length type,
// NativePropertiesN<N>, to hold the data and getters to access it. It has N
-// actual trios (stored in trios[]), plus four bits for each of the 7 possible
-// trios: 1 bit that states if that trio is present, and 3 that state that
-// trio's offset (if present) in trios[].
+// actual duos (stored in duos[]), plus four bits for each of the 7 possible
+// duos: 1 bit that states if that duo is present, and 3 that state that duo's
+// offset (if present) in duos[].
//
-// All trio accesses should be done via the getters, which contain assertions
-// that check we don't overrun the end of the struct. (The trio data members are
+// All duo accesses should be done via the getters, which contain assertions
+// that check we don't overrun the end of the struct. (The duo data members are
// public only so they can be statically initialized.) These assertions should
// never fail so long as (a) accesses to the variable-length part are guarded by
// appropriate Has*() calls, and (b) all instances are well-formed, i.e. the
// value of N matches the number of mHas* members that are true.
//
+// We store all the property ids a NativePropertiesN owns in a single array of
+// PropertyInfo structs. Each struct contains an id and the information needed
+// to find the corresponding Prefable for the enabled check, as well as the
+// information needed to find the correct property descriptor in the
+// Prefable. We also store an array of indices into the PropertyInfo array,
+// sorted by bits of the corresponding jsid. Given a jsid, this allows us to
+// binary search for the index of the corresponding PropertyInfo, if any.
+//
// Finally, we define a typedef of NativePropertiesN<7>, NativeProperties, which
// we use as a "base" type used to refer to all instances of NativePropertiesN.
// (7 is used because that's the maximum valid parameter, though any other
// value 1..6 could also be used.) This is reasonable because of the
// aforementioned assertions in the getters. Upcast() is used to convert
// specific instances to this "base" type.
//
template <int N>
struct NativePropertiesN {
- // Trio structs are stored in the trios[] array, and each element in the
- // array could require a different T. Therefore, we can't use the correct
- // type for mPrefables and mSpecs. Instead we use void* and cast to the
- // correct type in the getters.
- struct Trio {
+ // Duo structs are stored in the duos[] array, and each element in the array
+ // could require a different T. Therefore, we can't use the correct type for
+ // mPrefables. Instead we use void* and cast to the correct type in the
+ // getters.
+ struct Duo {
const /*Prefable<const T>*/ void* const mPrefables;
- const jsid* const mIds;
- const /*T*/ void* const mSpecs;
+ PropertyInfo* const mPropertyInfos;
};
- const int32_t iteratorAliasMethodIndex;
-
constexpr const NativePropertiesN<7>* Upcast() const {
return reinterpret_cast<const NativePropertiesN<7>*>(this);
}
+ const PropertyInfo* PropertyInfos() const {
+ return duos[0].mPropertyInfos;
+ }
+
#define DO(SpecT, FieldName) \
public: \
- /* The bitfields indicating the trio's presence and (if present) offset. */ \
+ /* The bitfields indicating the duo's presence and (if present) offset. */ \
const uint32_t mHas##FieldName##s:1; \
const uint32_t m##FieldName##sOffset:3; \
private: \
- const Trio* FieldName##sTrio() const { \
+ const Duo* FieldName##sDuo() const { \
MOZ_ASSERT(Has##FieldName##s()); \
- return &trios[m##FieldName##sOffset]; \
+ return &duos[m##FieldName##sOffset]; \
} \
public: \
bool Has##FieldName##s() const { \
return mHas##FieldName##s; \
} \
const Prefable<const SpecT>* FieldName##s() const { \
return static_cast<const Prefable<const SpecT>*> \
- (FieldName##sTrio()->mPrefables); \
+ (FieldName##sDuo()->mPrefables); \
} \
- const jsid* FieldName##Ids() const { \
- return FieldName##sTrio()->mIds; \
- } \
- const SpecT* FieldName##Specs() const { \
- return static_cast<const SpecT*>(FieldName##sTrio()->mSpecs); \
+ PropertyInfo* FieldName##PropertyInfos() const { \
+ return FieldName##sDuo()->mPropertyInfos; \
}
DO(JSFunctionSpec, StaticMethod)
DO(JSPropertySpec, StaticAttribute)
DO(JSFunctionSpec, Method)
DO(JSPropertySpec, Attribute)
DO(JSFunctionSpec, UnforgeableMethod)
DO(JSPropertySpec, UnforgeableAttribute)
DO(ConstantSpec, Constant)
#undef DO
- const Trio trios[N];
+ // The index to the iterator method in MethodPropertyInfos() array.
+ const int16_t iteratorAliasMethodIndex;
+ // The number of PropertyInfo structs that the duos manage. This is the total
+ // count across all duos.
+ const uint16_t propertyInfoCount;
+ // The sorted indices array from sorting property ids, which will be used when
+ // we binary search for a property.
+ uint16_t* sortedPropertyIndices;
+
+ const Duo duos[N];
};
-// Ensure the struct has the expected size. The 8 is for the
-// iteratorAliasMethodIndex plus the bitfields; the rest is for trios[].
+// Ensure the struct has the expected size. The 8 is for the bitfields plus
+// iteratorAliasMethodIndex and idsLength; the rest is for the idsSortedIndex,
+// and duos[].
static_assert(sizeof(NativePropertiesN<1>) == 8 + 3*sizeof(void*), "1 size");
-static_assert(sizeof(NativePropertiesN<2>) == 8 + 6*sizeof(void*), "2 size");
-static_assert(sizeof(NativePropertiesN<3>) == 8 + 9*sizeof(void*), "3 size");
-static_assert(sizeof(NativePropertiesN<4>) == 8 + 12*sizeof(void*), "4 size");
-static_assert(sizeof(NativePropertiesN<5>) == 8 + 15*sizeof(void*), "5 size");
-static_assert(sizeof(NativePropertiesN<6>) == 8 + 18*sizeof(void*), "6 size");
-static_assert(sizeof(NativePropertiesN<7>) == 8 + 21*sizeof(void*), "7 size");
+static_assert(sizeof(NativePropertiesN<2>) == 8 + 5*sizeof(void*), "2 size");
+static_assert(sizeof(NativePropertiesN<3>) == 8 + 7*sizeof(void*), "3 size");
+static_assert(sizeof(NativePropertiesN<4>) == 8 + 9*sizeof(void*), "4 size");
+static_assert(sizeof(NativePropertiesN<5>) == 8 + 11*sizeof(void*), "5 size");
+static_assert(sizeof(NativePropertiesN<6>) == 8 + 13*sizeof(void*), "6 size");
+static_assert(sizeof(NativePropertiesN<7>) == 8 + 15*sizeof(void*), "7 size");
// The "base" type.
typedef NativePropertiesN<7> NativeProperties;
struct NativePropertiesHolder
{
const NativeProperties* regular;
const NativeProperties* chromeOnly;