mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Backed out changeset d385df62c0e7 (bug 1267186) for hazard failures
This commit is contained in:
parent
889cd30471
commit
98f0a3271a
@ -1766,6 +1766,98 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (name_struct->mType == nsGlobalNameStruct::eTypeNewDOMBinding ||
|
||||
name_struct->mType == nsGlobalNameStruct::eTypeClassProto ||
|
||||
name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
|
||||
// Lookup new DOM bindings.
|
||||
DefineInterface getOrCreateInterfaceObject =
|
||||
name_struct->mDefineDOMInterface;
|
||||
if (getOrCreateInterfaceObject) {
|
||||
if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor &&
|
||||
!OldBindingConstructorEnabled(name_struct, aWin, cx)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ConstructorEnabled* checkEnabledForScope = name_struct->mConstructorEnabled;
|
||||
// We do the enabled check on the current compartment of cx, but for the
|
||||
// actual object we pass in the underlying object in the Xray case. That
|
||||
// way the callee can decide whether to allow access based on the caller
|
||||
// or the window being touched.
|
||||
JS::Rooted<JSObject*> global(cx,
|
||||
js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false));
|
||||
if (!global) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
if (checkEnabledForScope && !checkEnabledForScope(cx, global)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// The DOM constructor resolve machinery interacts with Xrays in tricky
|
||||
// ways, and there are some asymmetries that are important to understand.
|
||||
//
|
||||
// In the regular (non-Xray) case, we only want to resolve constructors
|
||||
// once (so that if they're deleted, they don't reappear). We do this by
|
||||
// stashing the constructor in a slot on the global, such that we can see
|
||||
// during resolve whether we've created it already. This is rather
|
||||
// memory-intensive, so we don't try to maintain these semantics when
|
||||
// manipulating a global over Xray (so the properties just re-resolve if
|
||||
// they've been deleted).
|
||||
//
|
||||
// Unfortunately, there's a bit of an impedance-mismatch between the Xray
|
||||
// and non-Xray machinery. The Xray machinery wants an API that returns a
|
||||
// JS::PropertyDescriptor, so that the resolve hook doesn't have to get
|
||||
// snared up with trying to define a property on the Xray holder. At the
|
||||
// same time, the DefineInterface callbacks are set up to define things
|
||||
// directly on the global. And re-jiggering them to return property
|
||||
// descriptors is tricky, because some DefineInterface callbacks define
|
||||
// multiple things (like the Image() alias for HTMLImageElement).
|
||||
//
|
||||
// So the setup is as-follows:
|
||||
//
|
||||
// * The resolve function takes a JS::PropertyDescriptor, but in the
|
||||
// non-Xray case, callees may define things directly on the global, and
|
||||
// set the value on the property descriptor to |undefined| to indicate
|
||||
// that there's nothing more for the caller to do. We assert against
|
||||
// this behavior in the Xray case.
|
||||
//
|
||||
// * We make sure that we do a non-Xray resolve first, so that all the
|
||||
// slots are set up. In the Xray case, this means unwrapping and doing
|
||||
// a non-Xray resolve before doing the Xray resolve.
|
||||
//
|
||||
// This all could use some grand refactoring, but for now we just limp
|
||||
// along.
|
||||
if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
|
||||
JS::Rooted<JSObject*> interfaceObject(cx);
|
||||
{
|
||||
JSAutoCompartment ac(cx, global);
|
||||
interfaceObject = getOrCreateInterfaceObject(cx, global, id, false);
|
||||
}
|
||||
if (NS_WARN_IF(!interfaceObject)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (!JS_WrapObject(cx, &interfaceObject)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
FillPropertyDescriptor(desc, obj, 0, JS::ObjectValue(*interfaceObject));
|
||||
} else {
|
||||
JS::Rooted<JSObject*> interfaceObject(cx,
|
||||
getOrCreateInterfaceObject(cx, obj, id, true));
|
||||
if (NS_WARN_IF(!interfaceObject)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// We've already defined the property. We indicate this to the caller
|
||||
// by filling a property descriptor with JS::UndefinedValue() as the
|
||||
// value. We still have to fill in a property descriptor, though, so
|
||||
// that the caller knows the property is in fact on this object. It
|
||||
// doesn't matter what we pass for the "readonly" argument here.
|
||||
FillPropertyDescriptor(desc, obj, JS::UndefinedValue(), false);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
|
||||
if (!OldBindingConstructorEnabled(name_struct, aWin, cx)) {
|
||||
return NS_OK;
|
||||
|
@ -229,7 +229,6 @@
|
||||
#include "mozilla/dom/ImageBitmap.h"
|
||||
#include "mozilla/dom/ServiceWorkerRegistration.h"
|
||||
#include "mozilla/dom/U2F.h"
|
||||
#include "mozilla/dom/WebIDLGlobalNameHash.h"
|
||||
#ifdef HAVE_SIDEBAR
|
||||
#include "mozilla/dom/ExternalBinding.h"
|
||||
#endif
|
||||
@ -4500,15 +4499,6 @@ nsGlobalWindow::DoResolve(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool found;
|
||||
if (!WebIDLGlobalNameHash::DefineIfEnabled(aCx, aObj, aId, aDesc, &found)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult rv = nsWindowSH::GlobalResolve(this, aCx, aObj, aId, aDesc);
|
||||
if (NS_FAILED(rv)) {
|
||||
return Throw(aCx, rv);
|
||||
@ -4537,10 +4527,6 @@ nsGlobalWindow::MayResolve(jsid aId)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (WebIDLGlobalNameHash::MayResolve(aId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsScriptNameSpaceManager *nameSpaceManager = PeekNameSpaceManager();
|
||||
if (!nameSpaceManager) {
|
||||
// Really shouldn't happen. Fail safe.
|
||||
@ -4564,13 +4550,12 @@ nsGlobalWindow::GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
|
||||
nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager();
|
||||
if (nameSpaceManager) {
|
||||
JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
|
||||
|
||||
WebIDLGlobalNameHash::GetNames(aCx, wrapper, aNames);
|
||||
|
||||
for (auto i = nameSpaceManager->GlobalNameIter(); !i.Done(); i.Next()) {
|
||||
const GlobalNameMapEntry* entry = i.Get();
|
||||
if (nsWindowSH::NameStructEnabled(aCx, this, entry->mKey,
|
||||
entry->mGlobalName)) {
|
||||
entry->mGlobalName) &&
|
||||
(!entry->mGlobalName.mConstructorEnabled ||
|
||||
entry->mGlobalName.mConstructorEnabled(aCx, wrapper))) {
|
||||
aNames.AppendElement(entry->mKey);
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,7 @@
|
||||
#include "nsCRT.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/WebIDLGlobalNameHash.h"
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
@ -35,7 +34,6 @@
|
||||
#define NS_DOM_INTERFACE_PREFIX "nsIDOM"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
static PLDHashNumber
|
||||
GlobalNameHashHashKey(const void *key)
|
||||
@ -97,7 +95,7 @@ static const PLDHashTableOps hash_table_ops =
|
||||
GlobalNameHashInitEntry
|
||||
};
|
||||
|
||||
#define GLOBALNAME_HASHTABLE_INITIAL_LENGTH 32
|
||||
#define GLOBALNAME_HASHTABLE_INITIAL_LENGTH 512
|
||||
|
||||
nsScriptNameSpaceManager::nsScriptNameSpaceManager()
|
||||
: mGlobalNames(&hash_table_ops, sizeof(GlobalNameMapEntry),
|
||||
@ -113,17 +111,14 @@ nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
|
||||
}
|
||||
|
||||
nsGlobalNameStruct *
|
||||
nsScriptNameSpaceManager::AddToHash(const char *aKey,
|
||||
nsScriptNameSpaceManager::AddToHash(const nsAString *aKey,
|
||||
const char16_t **aClassName)
|
||||
{
|
||||
NS_ConvertASCIItoUTF16 key(aKey);
|
||||
auto entry = static_cast<GlobalNameMapEntry*>(mGlobalNames.Add(&key, fallible));
|
||||
auto entry = static_cast<GlobalNameMapEntry*>(mGlobalNames.Add(aKey, fallible));
|
||||
if (!entry) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WebIDLGlobalNameHash::Remove(aKey, key.Length());
|
||||
|
||||
if (aClassName) {
|
||||
*aClassName = entry->mKey.get();
|
||||
}
|
||||
@ -235,7 +230,8 @@ nsScriptNameSpaceManager::RegisterClassName(const char *aClassName,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized,
|
||||
NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
|
||||
s->mType == nsGlobalNameStruct::eTypeNewDOMBinding,
|
||||
"Whaaa, JS environment name clash!");
|
||||
|
||||
s->mType = nsGlobalNameStruct::eTypeClassConstructor;
|
||||
@ -258,7 +254,8 @@ nsScriptNameSpaceManager::RegisterClassProto(const char *aClassName,
|
||||
nsGlobalNameStruct *s = AddToHash(aClassName);
|
||||
NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
if (s->mType != nsGlobalNameStruct::eTypeNotInitialized) {
|
||||
if (s->mType != nsGlobalNameStruct::eTypeNotInitialized &&
|
||||
s->mType != nsGlobalNameStruct::eTypeNewDOMBinding) {
|
||||
*aFoundOld = true;
|
||||
|
||||
return NS_OK;
|
||||
@ -352,7 +349,8 @@ nsScriptNameSpaceManager::OperateCategoryEntryHash(nsICategoryManager* aCategory
|
||||
nsGlobalNameStruct *s = AddToHash(categoryEntry.get());
|
||||
NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
|
||||
if (s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
|
||||
s->mType == nsGlobalNameStruct::eTypeNewDOMBinding) {
|
||||
s->mType = type;
|
||||
s->mCID = cid;
|
||||
s->mChromeOnly =
|
||||
@ -416,6 +414,21 @@ nsScriptNameSpaceManager::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsScriptNameSpaceManager::RegisterDefineDOMInterface(const nsAFlatString& aName,
|
||||
mozilla::dom::DefineInterface aDefineDOMInterface,
|
||||
mozilla::dom::ConstructorEnabled* aConstructorEnabled)
|
||||
{
|
||||
nsGlobalNameStruct *s = AddToHash(&aName);
|
||||
if (s) {
|
||||
if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
|
||||
s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
|
||||
}
|
||||
s->mDefineDOMInterface = aDefineDOMInterface;
|
||||
s->mConstructorEnabled = aConstructorEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(ScriptNameSpaceManagerMallocSizeOf)
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -33,24 +33,35 @@
|
||||
#include "nsWeakReference.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
|
||||
struct nsGlobalNameStruct
|
||||
{
|
||||
enum nametype {
|
||||
eTypeNotInitialized,
|
||||
eTypeNewDOMBinding,
|
||||
eTypeProperty,
|
||||
eTypeExternalConstructor,
|
||||
eTypeClassConstructor,
|
||||
eTypeClassProto,
|
||||
} mType;
|
||||
|
||||
// mChromeOnly is only used for structs that define non-WebIDL things
|
||||
// (possibly in addition to WebIDL ones). In particular, it's not even
|
||||
// initialized for eTypeNewDOMBinding structs.
|
||||
bool mChromeOnly : 1;
|
||||
bool mAllowXBL : 1;
|
||||
|
||||
union {
|
||||
int32_t mDOMClassInfoID; // eTypeClassConstructor
|
||||
nsIID mIID; // eTypeClassProto
|
||||
nsCID mCID; // All other types
|
||||
nsCID mCID; // All other types except eTypeNewDOMBinding
|
||||
};
|
||||
|
||||
// For new style DOM bindings.
|
||||
mozilla::dom::DefineInterface mDefineDOMInterface;
|
||||
|
||||
// May be null if enabled unconditionally
|
||||
mozilla::dom::ConstructorEnabled* mConstructorEnabled;
|
||||
};
|
||||
|
||||
class GlobalNameMapEntry : public PLDHashEntryHdr
|
||||
@ -101,6 +112,19 @@ public:
|
||||
const nsIID *aConstructorProtoIID,
|
||||
bool *aFoundOld);
|
||||
|
||||
void RegisterDefineDOMInterface(const nsAFlatString& aName,
|
||||
mozilla::dom::DefineInterface aDefineDOMInterface,
|
||||
mozilla::dom::ConstructorEnabled* aConstructorEnabled);
|
||||
template<size_t N>
|
||||
void RegisterDefineDOMInterface(const char16_t (&aKey)[N],
|
||||
mozilla::dom::DefineInterface aDefineDOMInterface,
|
||||
mozilla::dom::ConstructorEnabled* aConstructorEnabled)
|
||||
{
|
||||
nsLiteralString key(aKey);
|
||||
return RegisterDefineDOMInterface(key, aDefineDOMInterface,
|
||||
aConstructorEnabled);
|
||||
}
|
||||
|
||||
class NameIterator : public PLDHashTable::Iterator
|
||||
{
|
||||
public:
|
||||
@ -131,14 +155,22 @@ private:
|
||||
// that aKey will be mapped to. If mType in the returned
|
||||
// nsGlobalNameStruct is != eTypeNotInitialized, an entry for aKey
|
||||
// already existed.
|
||||
nsGlobalNameStruct *AddToHash(const char *aKey,
|
||||
nsGlobalNameStruct *AddToHash(const nsAString *aKey,
|
||||
const char16_t **aClassName = nullptr);
|
||||
|
||||
nsGlobalNameStruct *AddToHash(const char *aKey,
|
||||
const char16_t **aClassName = nullptr)
|
||||
{
|
||||
NS_ConvertASCIItoUTF16 key(aKey);
|
||||
return AddToHash(&key, aClassName);
|
||||
}
|
||||
// Removes an existing entry from the hash.
|
||||
void RemoveFromHash(const nsAString *aKey);
|
||||
|
||||
nsresult FillHash(nsICategoryManager *aCategoryManager,
|
||||
const char *aCategory);
|
||||
nsresult RegisterInterface(const char* aIfName,
|
||||
const nsIID *aIfIID,
|
||||
bool* aFoundOld);
|
||||
|
||||
/**
|
||||
* Add a new category entry into the hash table.
|
||||
|
@ -45,7 +45,6 @@
|
||||
#include "mozilla/dom/HTMLAppletElementBinding.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/ResolveSystemBinding.h"
|
||||
#include "mozilla/dom/WebIDLGlobalNameHash.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/dom/WorkerScope.h"
|
||||
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
||||
@ -2937,15 +2936,20 @@ RegisterDOMNames()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Register new DOM bindings
|
||||
WebIDLGlobalNameHash::Init();
|
||||
|
||||
nsresult rv = nsDOMClassInfo::Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Could not initialize nsDOMClassInfo");
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Register new DOM bindings
|
||||
nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager();
|
||||
if (!nameSpaceManager) {
|
||||
NS_ERROR("Could not initialize nsScriptNameSpaceManager");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mozilla::dom::Register(nameSpaceManager);
|
||||
|
||||
sRegisteredDOMNames = true;
|
||||
|
||||
return NS_OK;
|
||||
|
@ -12057,14 +12057,14 @@ class CGDescriptor(CGThing):
|
||||
if descriptor.interface.hasInterfacePrototypeObject():
|
||||
cgThings.append(CGPrototypeJSClass(descriptor, properties))
|
||||
|
||||
if descriptor.interface.hasInterfaceObject():
|
||||
cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
|
||||
|
||||
if ((descriptor.interface.hasInterfaceObject() or descriptor.interface.isNavigatorProperty()) and
|
||||
not descriptor.interface.isExternal() and
|
||||
descriptor.isExposedConditionally()):
|
||||
cgThings.append(CGConstructorEnabled(descriptor))
|
||||
|
||||
if descriptor.registersGlobalNamesOnWindow:
|
||||
cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
|
||||
|
||||
if (descriptor.interface.hasMembersInSlots() and
|
||||
descriptor.interface.hasChildInterfaces()):
|
||||
raise TypeError("We don't support members in slots on "
|
||||
@ -13057,53 +13057,48 @@ class CGResolveSystemBinding(CGAbstractMethod):
|
||||
"\n").define()
|
||||
|
||||
|
||||
def getGlobalNames(config):
|
||||
names = []
|
||||
for desc in config.getDescriptors(registersGlobalNamesOnWindow=True):
|
||||
names.append((desc.name, desc))
|
||||
names.extend((n.identifier.name, desc) for n in desc.interface.namedConstructors)
|
||||
return names
|
||||
|
||||
class CGGlobalNamesString(CGGeneric):
|
||||
class CGRegisterProtos(CGAbstractMethod):
|
||||
def __init__(self, config):
|
||||
globalNames = getGlobalNames(config)
|
||||
currentOffset = 0
|
||||
strings = []
|
||||
for (name, _) in globalNames:
|
||||
strings.append('/* %i */ "%s\\0"' % (currentOffset, name))
|
||||
currentOffset += len(name) + 1 # Add trailing null.
|
||||
define = fill("""
|
||||
const uint32_t WebIDLGlobalNameHash::sCount = ${count};
|
||||
|
||||
const char WebIDLGlobalNameHash::sNames[] =
|
||||
$*{strings}
|
||||
|
||||
""",
|
||||
count=len(globalNames),
|
||||
strings="\n".join(strings) + ";\n")
|
||||
|
||||
CGGeneric.__init__(self, define=define)
|
||||
|
||||
|
||||
class CGRegisterGlobalNames(CGAbstractMethod):
|
||||
def __init__(self, config):
|
||||
CGAbstractMethod.__init__(self, None, 'RegisterWebIDLGlobalNames',
|
||||
'void', [])
|
||||
CGAbstractMethod.__init__(self, None, 'Register', 'void',
|
||||
[Argument('nsScriptNameSpaceManager*', 'aNameSpaceManager')])
|
||||
self.config = config
|
||||
|
||||
def definition_body(self):
|
||||
def _defineMacro(self):
|
||||
return dedent("""
|
||||
#define REGISTER_PROTO(_dom_class, _ctor_check) \\
|
||||
aNameSpaceManager->RegisterDefineDOMInterface(MOZ_UTF16(#_dom_class), _dom_class##Binding::DefineDOMInterface, _ctor_check);
|
||||
#define REGISTER_CONSTRUCTOR(_dom_constructor, _dom_class, _ctor_check) \\
|
||||
aNameSpaceManager->RegisterDefineDOMInterface(MOZ_UTF16(#_dom_constructor), _dom_class##Binding::DefineDOMInterface, _ctor_check);
|
||||
""")
|
||||
|
||||
def _undefineMacro(self):
|
||||
return dedent("""
|
||||
#undef REGISTER_CONSTRUCTOR
|
||||
#undef REGISTER_PROTO
|
||||
""")
|
||||
|
||||
def _registerProtos(self):
|
||||
def getCheck(desc):
|
||||
if not desc.isExposedConditionally():
|
||||
return "nullptr"
|
||||
return "%sBinding::ConstructorEnabled" % desc.name
|
||||
lines = []
|
||||
for desc in self.config.getDescriptors(hasInterfaceObject=True,
|
||||
isExternal=False,
|
||||
workers=False,
|
||||
isExposedInWindow=True,
|
||||
register=True):
|
||||
lines.append("REGISTER_PROTO(%s, %s);\n" % (desc.name, getCheck(desc)))
|
||||
lines.extend("REGISTER_CONSTRUCTOR(%s, %s, %s);\n" % (n.identifier.name, desc.name, getCheck(desc))
|
||||
for n in desc.interface.namedConstructors)
|
||||
return ''.join(lines)
|
||||
|
||||
define = ""
|
||||
currentOffset = 0
|
||||
for (name, desc) in getGlobalNames(self.config):
|
||||
length = len(name)
|
||||
define += "WebIDLGlobalNameHash::Register(%i, %i, %sBinding::DefineDOMInterface, %s);\n" % (currentOffset, length, desc.name, getCheck(desc))
|
||||
currentOffset += length + 1 # Add trailing null.
|
||||
return define
|
||||
def indent_body(self, body):
|
||||
# Don't indent the body of this method, as it's all preprocessor gunk.
|
||||
return body
|
||||
|
||||
def definition_body(self):
|
||||
return "\n" + self._defineMacro() + "\n" + self._registerProtos() + "\n" + self._undefineMacro()
|
||||
|
||||
|
||||
def dependencySortObjects(objects, dependencyGetter, nameGetter):
|
||||
@ -16213,7 +16208,7 @@ class GlobalGenRoots():
|
||||
@staticmethod
|
||||
def RegisterBindings(config):
|
||||
|
||||
curr = CGList([CGGlobalNamesString(config), CGRegisterGlobalNames(config)])
|
||||
curr = CGRegisterProtos(config)
|
||||
|
||||
# Wrap all of that in our namespaces.
|
||||
curr = CGNamespace.build(['mozilla', 'dom'],
|
||||
@ -16226,7 +16221,7 @@ class GlobalGenRoots():
|
||||
workers=False,
|
||||
isExposedInWindow=True,
|
||||
register=True)]
|
||||
defineIncludes.append('mozilla/dom/WebIDLGlobalNameHash.h')
|
||||
defineIncludes.append('nsScriptNameSpaceManager.h')
|
||||
defineIncludes.extend([CGHeaders.getDeclarationFilename(desc.interface)
|
||||
for desc in config.getDescriptors(isNavigatorProperty=True,
|
||||
workers=False,
|
||||
|
@ -810,14 +810,6 @@ class Descriptor(DescriptorProvider):
|
||||
return (self.interface.getExtendedAttribute("Global") or
|
||||
self.interface.getExtendedAttribute("PrimaryGlobal"))
|
||||
|
||||
@property
|
||||
def registersGlobalNamesOnWindow(self):
|
||||
return (not self.interface.isExternal() and
|
||||
self.interface.hasInterfaceObject() and
|
||||
not self.workers and
|
||||
self.interface.isExposedInWindow() and
|
||||
self.register)
|
||||
|
||||
|
||||
# Some utility methods
|
||||
def getTypesFromDescriptor(descriptor):
|
||||
|
@ -1,302 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#include "WebIDLGlobalNameHash.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/dom/DOMJSProxyHandler.h"
|
||||
#include "mozilla/dom/RegisterBindings.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsTHashtable.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct MOZ_STACK_CLASS WebIDLNameTableKey
|
||||
{
|
||||
explicit WebIDLNameTableKey(JSFlatString* aJSString)
|
||||
: mLength(js::GetFlatStringLength(aJSString))
|
||||
{
|
||||
JSLinearString* jsString = js::FlatStringToLinearString(aJSString);
|
||||
if (js::LinearStringHasLatin1Chars(jsString)) {
|
||||
mLatin1String = reinterpret_cast<const char*>(
|
||||
js::GetLatin1LinearStringChars(mNogc, jsString));
|
||||
mTwoBytesString = nullptr;
|
||||
mHash = mLatin1String ? HashString(mLatin1String, mLength) : 0;
|
||||
} else {
|
||||
mLatin1String = nullptr;
|
||||
mTwoBytesString = js::GetTwoByteLinearStringChars(mNogc, jsString);
|
||||
mHash = mTwoBytesString ? HashString(mTwoBytesString, mLength) : 0;
|
||||
}
|
||||
}
|
||||
explicit WebIDLNameTableKey(const char* aString, size_t aLength)
|
||||
: mLatin1String(aString),
|
||||
mTwoBytesString(nullptr),
|
||||
mLength(aLength),
|
||||
mHash(HashString(aString, aLength))
|
||||
{
|
||||
MOZ_ASSERT(aString[aLength] == '\0');
|
||||
}
|
||||
|
||||
JS::AutoCheckCannotGC mNogc;
|
||||
const char* mLatin1String;
|
||||
const char16_t* mTwoBytesString;
|
||||
size_t mLength;
|
||||
uint32_t mHash;
|
||||
};
|
||||
|
||||
struct WebIDLNameTableEntry : public PLDHashEntryHdr
|
||||
{
|
||||
typedef const WebIDLNameTableKey& KeyType;
|
||||
typedef const WebIDLNameTableKey* KeyTypePointer;
|
||||
|
||||
explicit WebIDLNameTableEntry(KeyTypePointer aKey)
|
||||
{}
|
||||
WebIDLNameTableEntry(WebIDLNameTableEntry&& aEntry)
|
||||
: mNameOffset(aEntry.mNameOffset),
|
||||
mNameLength(aEntry.mNameLength),
|
||||
mDefine(aEntry.mDefine),
|
||||
mEnabled(aEntry.mEnabled)
|
||||
{}
|
||||
~WebIDLNameTableEntry()
|
||||
{}
|
||||
|
||||
bool KeyEquals(KeyTypePointer aKey) const
|
||||
{
|
||||
if (mNameLength != aKey->mLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* name = WebIDLGlobalNameHash::sNames + mNameOffset;
|
||||
|
||||
if (aKey->mLatin1String) {
|
||||
return PodEqual(aKey->mLatin1String, name, aKey->mLength);
|
||||
}
|
||||
|
||||
return nsCharTraits<char16_t>::compareASCII(aKey->mTwoBytesString, name,
|
||||
aKey->mLength) == 0;
|
||||
}
|
||||
|
||||
static KeyTypePointer KeyToPointer(KeyType aKey)
|
||||
{
|
||||
return &aKey;
|
||||
}
|
||||
|
||||
static PLDHashNumber HashKey(KeyTypePointer aKey)
|
||||
{
|
||||
return aKey->mHash;
|
||||
}
|
||||
|
||||
enum { ALLOW_MEMMOVE = true };
|
||||
|
||||
uint16_t mNameOffset;
|
||||
uint16_t mNameLength;
|
||||
WebIDLGlobalNameHash::DefineGlobalName mDefine;
|
||||
// May be null if enabled unconditionally
|
||||
WebIDLGlobalNameHash::ConstructorEnabled* mEnabled;
|
||||
};
|
||||
|
||||
static nsTHashtable<WebIDLNameTableEntry>* sWebIDLGlobalNames;
|
||||
|
||||
class WebIDLGlobalNamesHashReporter final : public nsIMemoryReporter
|
||||
{
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
|
||||
|
||||
~WebIDLGlobalNamesHashReporter() {}
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aData, bool aAnonymize) override
|
||||
{
|
||||
int64_t amount =
|
||||
sWebIDLGlobalNames ?
|
||||
sWebIDLGlobalNames->ShallowSizeOfIncludingThis(MallocSizeOf) : 0;
|
||||
|
||||
return MOZ_COLLECT_REPORT("explicit/dom/webidl-globalnames", KIND_HEAP,
|
||||
UNITS_BYTES, amount,
|
||||
"Memory used by the hash table for WebIDL's "
|
||||
"global names.");
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(WebIDLGlobalNamesHashReporter, nsIMemoryReporter)
|
||||
|
||||
/* static */
|
||||
void
|
||||
WebIDLGlobalNameHash::Init()
|
||||
{
|
||||
sWebIDLGlobalNames = new nsTHashtable<WebIDLNameTableEntry>(sCount);
|
||||
RegisterWebIDLGlobalNames();
|
||||
|
||||
RegisterStrongMemoryReporter(new WebIDLGlobalNamesHashReporter());
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
WebIDLGlobalNameHash::Shutdown()
|
||||
{
|
||||
delete sWebIDLGlobalNames;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
WebIDLGlobalNameHash::Register(uint16_t aNameOffset, uint16_t aNameLength,
|
||||
DefineGlobalName aDefine,
|
||||
ConstructorEnabled* aEnabled)
|
||||
{
|
||||
const char* name = sNames + aNameOffset;
|
||||
WebIDLNameTableKey key(name, aNameLength);
|
||||
WebIDLNameTableEntry* entry = sWebIDLGlobalNames->PutEntry(key);
|
||||
entry->mNameOffset = aNameOffset;
|
||||
entry->mNameLength = aNameLength;
|
||||
entry->mDefine = aDefine;
|
||||
entry->mEnabled = aEnabled;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
WebIDLGlobalNameHash::Remove(const char* aName, uint32_t aLength)
|
||||
{
|
||||
WebIDLNameTableKey key(aName, aLength);
|
||||
sWebIDLGlobalNames->RemoveEntry(key);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
WebIDLGlobalNameHash::DefineIfEnabled(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aObj,
|
||||
JS::Handle<jsid> aId,
|
||||
JS::MutableHandle<JS::PropertyDescriptor> aDesc,
|
||||
bool* aFound)
|
||||
{
|
||||
MOZ_ASSERT(JSID_IS_STRING(aId), "Check for string id before calling this!");
|
||||
|
||||
const WebIDLNameTableEntry* entry;
|
||||
{
|
||||
WebIDLNameTableKey key(JSID_TO_FLAT_STRING(aId));
|
||||
entry = sWebIDLGlobalNames->GetEntry(key);
|
||||
}
|
||||
|
||||
if (!entry) {
|
||||
*aFound = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
*aFound = true;
|
||||
|
||||
ConstructorEnabled* checkEnabledForScope = entry->mEnabled;
|
||||
// We do the enabled check on the current compartment of aCx, but for the
|
||||
// actual object we pass in the underlying object in the Xray case. That
|
||||
// way the callee can decide whether to allow access based on the caller
|
||||
// or the window being touched.
|
||||
JS::Rooted<JSObject*> global(aCx,
|
||||
js::CheckedUnwrap(aObj, /* stopAtWindowProxy = */ false));
|
||||
if (!global) {
|
||||
return Throw(aCx, NS_ERROR_DOM_SECURITY_ERR);
|
||||
}
|
||||
|
||||
{
|
||||
DebugOnly<nsGlobalWindow*> win;
|
||||
MOZ_ASSERT(NS_SUCCEEDED(UNWRAP_OBJECT(Window, global, win)));
|
||||
}
|
||||
|
||||
if (checkEnabledForScope && !checkEnabledForScope(aCx, global)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The DOM constructor resolve machinery interacts with Xrays in tricky
|
||||
// ways, and there are some asymmetries that are important to understand.
|
||||
//
|
||||
// In the regular (non-Xray) case, we only want to resolve constructors
|
||||
// once (so that if they're deleted, they don't reappear). We do this by
|
||||
// stashing the constructor in a slot on the global, such that we can see
|
||||
// during resolve whether we've created it already. This is rather
|
||||
// memory-intensive, so we don't try to maintain these semantics when
|
||||
// manipulating a global over Xray (so the properties just re-resolve if
|
||||
// they've been deleted).
|
||||
//
|
||||
// Unfortunately, there's a bit of an impedance-mismatch between the Xray
|
||||
// and non-Xray machinery. The Xray machinery wants an API that returns a
|
||||
// JS::PropertyDescriptor, so that the resolve hook doesn't have to get
|
||||
// snared up with trying to define a property on the Xray holder. At the
|
||||
// same time, the DefineInterface callbacks are set up to define things
|
||||
// directly on the global. And re-jiggering them to return property
|
||||
// descriptors is tricky, because some DefineInterface callbacks define
|
||||
// multiple things (like the Image() alias for HTMLImageElement).
|
||||
//
|
||||
// So the setup is as-follows:
|
||||
//
|
||||
// * The resolve function takes a JS::PropertyDescriptor, but in the
|
||||
// non-Xray case, callees may define things directly on the global, and
|
||||
// set the value on the property descriptor to |undefined| to indicate
|
||||
// that there's nothing more for the caller to do. We assert against
|
||||
// this behavior in the Xray case.
|
||||
//
|
||||
// * We make sure that we do a non-Xray resolve first, so that all the
|
||||
// slots are set up. In the Xray case, this means unwrapping and doing
|
||||
// a non-Xray resolve before doing the Xray resolve.
|
||||
//
|
||||
// This all could use some grand refactoring, but for now we just limp
|
||||
// along.
|
||||
if (xpc::WrapperFactory::IsXrayWrapper(aObj)) {
|
||||
JS::Rooted<JSObject*> interfaceObject(aCx);
|
||||
{
|
||||
JSAutoCompartment ac(aCx, global);
|
||||
interfaceObject = entry->mDefine(aCx, global, aId, false);
|
||||
}
|
||||
if (NS_WARN_IF(!interfaceObject)) {
|
||||
return Throw(aCx, NS_ERROR_FAILURE);
|
||||
}
|
||||
if (!JS_WrapObject(aCx, &interfaceObject)) {
|
||||
return Throw(aCx, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
FillPropertyDescriptor(aDesc, aObj, 0, JS::ObjectValue(*interfaceObject));
|
||||
return true;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> interfaceObject(aCx,
|
||||
entry->mDefine(aCx, aObj, aId, true));
|
||||
if (NS_WARN_IF(!interfaceObject)) {
|
||||
return Throw(aCx, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
// We've already defined the property. We indicate this to the caller
|
||||
// by filling a property descriptor with JS::UndefinedValue() as the
|
||||
// value. We still have to fill in a property descriptor, though, so
|
||||
// that the caller knows the property is in fact on this object. It
|
||||
// doesn't matter what we pass for the "readonly" argument here.
|
||||
FillPropertyDescriptor(aDesc, aObj, JS::UndefinedValue(), false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
WebIDLGlobalNameHash::MayResolve(jsid aId)
|
||||
{
|
||||
WebIDLNameTableKey key(JSID_TO_FLAT_STRING(aId));
|
||||
return sWebIDLGlobalNames->Contains(key);
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
WebIDLGlobalNameHash::GetNames(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
||||
nsTArray<nsString>& aNames)
|
||||
{
|
||||
for (auto iter = sWebIDLGlobalNames->Iter(); !iter.Done(); iter.Next()) {
|
||||
const WebIDLNameTableEntry* entry = iter.Get();
|
||||
if (!entry->mEnabled || entry->mEnabled(aCx, aObj)) {
|
||||
AppendASCIItoUTF16(nsDependentCString(sNames + entry->mNameOffset,
|
||||
entry->mNameLength),
|
||||
*aNames.AppendElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -1,70 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_WebIDLGlobalNameHash_h__
|
||||
#define mozilla_dom_WebIDLGlobalNameHash_h__
|
||||
|
||||
#include "js/RootingAPI.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct WebIDLNameTableEntry;
|
||||
|
||||
class WebIDLGlobalNameHash
|
||||
{
|
||||
public:
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
typedef JSObject*
|
||||
(*DefineGlobalName)(JSContext* cx, JS::Handle<JSObject*> global,
|
||||
JS::Handle<jsid> id, bool defineOnGlobal);
|
||||
|
||||
// Check whether a constructor should be enabled for the given object.
|
||||
// Note that the object should NOT be an Xray, since Xrays will end up
|
||||
// defining constructors on the underlying object.
|
||||
// This is a typedef for the function type itself, not the function
|
||||
// pointer, so it's more obvious that pointers to a ConstructorEnabled
|
||||
// can be null.
|
||||
typedef bool
|
||||
(ConstructorEnabled)(JSContext* cx, JS::Handle<JSObject*> obj);
|
||||
|
||||
static void Register(uint16_t aNameOffset, uint16_t aNameLength,
|
||||
DefineGlobalName aDefine, ConstructorEnabled* aEnabled);
|
||||
|
||||
static void Remove(const char* aName, uint32_t aLength);
|
||||
|
||||
// Returns false if something failed. aFound is set to true if the name is in
|
||||
// the hash, whether it's enabled or not.
|
||||
static bool DefineIfEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
||||
JS::Handle<jsid> aId,
|
||||
JS::MutableHandle<JS::PropertyDescriptor> aDesc,
|
||||
bool* aFound);
|
||||
|
||||
static bool MayResolve(jsid aId);
|
||||
|
||||
static void GetNames(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
||||
nsTArray<nsString>& aNames);
|
||||
|
||||
private:
|
||||
friend struct WebIDLNameTableEntry;
|
||||
|
||||
// The total number of names that we will add to the hash.
|
||||
// The value of sCount is generated by Codegen.py in RegisterBindings.cpp.
|
||||
static const uint32_t sCount;
|
||||
|
||||
// The names that will be registered in the hash, concatenated as one big
|
||||
// string with \0 as a separator between names.
|
||||
// The value of sNames is generated by Codegen.py in RegisterBindings.cpp.
|
||||
static const char sNames[];
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_WebIDLGlobalNameHash_h__
|
@ -39,7 +39,6 @@ EXPORTS.mozilla.dom += [
|
||||
'ToJSValue.h',
|
||||
'TypedArray.h',
|
||||
'UnionMember.h',
|
||||
'WebIDLGlobalNameHash.h',
|
||||
]
|
||||
|
||||
# Generated bindings reference *Binding.h, not mozilla/dom/*Binding.h. And,
|
||||
@ -90,7 +89,6 @@ UNIFIED_SOURCES += [
|
||||
'IterableIterator.cpp',
|
||||
'SimpleGlobalObject.cpp',
|
||||
'ToJSValue.cpp',
|
||||
'WebIDLGlobalNameHash.cpp',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
|
@ -578,6 +578,25 @@ void RemoveGCCallback(xpcGCCallback cb);
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
typedef JSObject*
|
||||
(*DefineInterface)(JSContext* cx, JS::Handle<JSObject*> global,
|
||||
JS::Handle<jsid> id, bool defineOnGlobal);
|
||||
|
||||
typedef JSObject*
|
||||
(*ConstructNavigatorProperty)(JSContext* cx, JS::Handle<JSObject*> naviObj);
|
||||
|
||||
// Check whether a constructor should be enabled for the given object.
|
||||
// Note that the object should NOT be an Xray, since Xrays will end up
|
||||
// defining constructors on the underlying object.
|
||||
// This is a typedef for the function type itself, not the function
|
||||
// pointer, so it's more obvious that pointers to a ConstructorEnabled
|
||||
// can be null.
|
||||
typedef bool
|
||||
(ConstructorEnabled)(JSContext* cx, JS::Handle<JSObject*> obj);
|
||||
|
||||
void
|
||||
Register(nsScriptNameSpaceManager* aNameSpaceManager);
|
||||
|
||||
/**
|
||||
* A test for whether WebIDL methods that should only be visible to
|
||||
* chrome or XBL scopes should be exposed.
|
||||
|
@ -131,7 +131,6 @@ using namespace mozilla::system;
|
||||
#include "mozilla/dom/devicestorage/DeviceStorageStatics.h"
|
||||
#include "mozilla/ServoBindings.h"
|
||||
#include "mozilla/StaticPresData.h"
|
||||
#include "mozilla/dom/WebIDLGlobalNameHash.h"
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
#include "mozilla/dom/BluetoothUUID.h"
|
||||
@ -385,7 +384,6 @@ nsLayoutStatics::Shutdown()
|
||||
ShutdownJSEnvironment();
|
||||
nsGlobalWindow::ShutDown();
|
||||
nsDOMClassInfo::ShutDown();
|
||||
WebIDLGlobalNameHash::Shutdown();
|
||||
nsListControlFrame::Shutdown();
|
||||
nsXBLService::Shutdown();
|
||||
nsAutoCopyListener::Shutdown();
|
||||
|
Loading…
Reference in New Issue
Block a user