mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 12:37:37 +00:00
a903aefdc0
Backed out changeset 85486c4aa3d8 (bug 936964) Backed out changeset 25312eb71998 (bug 936964) Backed out changeset 6dbb8333960c (bug 936964) Backed out changeset da6465ad476f (bug 936964) Backed out changeset a87ffc992f38 (bug 936964) Backed out changeset 4ae3a61182db (bug 936964) Backed out changeset 34e9c3137804 (bug 936964) Backed out changeset fd1459e71585 (bug 936964) Backed out changeset 3e8a701d8bdc (bug 943660) Landed on a CLOSED TREE --HG-- rename : content/canvas/src/WebGLMemoryTracker.h => content/canvas/src/WebGLMemoryReporterWrapper.h
886 lines
27 KiB
C++
886 lines
27 KiB
C++
/* -*- 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 "nsScriptNameSpaceManager.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsIComponentManager.h"
|
|
#include "nsIComponentRegistrar.h"
|
|
#include "nsICategoryManager.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsXPCOM.h"
|
|
#include "nsISupportsPrimitives.h"
|
|
#include "nsIScriptExternalNameSet.h"
|
|
#include "nsIScriptNameSpaceManager.h"
|
|
#include "nsIScriptContext.h"
|
|
#include "nsIInterfaceInfoManager.h"
|
|
#include "nsIInterfaceInfo.h"
|
|
#include "xptinfo.h"
|
|
#include "nsXPIDLString.h"
|
|
#include "nsPrintfCString.h"
|
|
#include "nsReadableUtils.h"
|
|
#include "nsHashKeys.h"
|
|
#include "nsDOMClassInfo.h"
|
|
#include "nsCRT.h"
|
|
#include "nsIObserverService.h"
|
|
#include "nsISimpleEnumerator.h"
|
|
|
|
#include "mozilla/MemoryReporting.h"
|
|
#include "mozilla/Preferences.h"
|
|
#include "mozilla/Services.h"
|
|
|
|
#define NS_INTERFACE_PREFIX "nsI"
|
|
#define NS_DOM_INTERFACE_PREFIX "nsIDOM"
|
|
|
|
using namespace mozilla;
|
|
|
|
// Our extended PLDHashEntryHdr
|
|
class GlobalNameMapEntry : public PLDHashEntryHdr
|
|
{
|
|
public:
|
|
// Our hash table ops don't care about the order of these members
|
|
nsString mKey;
|
|
nsGlobalNameStruct mGlobalName;
|
|
|
|
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) {
|
|
// Measurement of the following members may be added later if DMD finds it
|
|
// is worthwhile:
|
|
// - mGlobalName
|
|
return mKey.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf);
|
|
}
|
|
};
|
|
|
|
|
|
static PLDHashNumber
|
|
GlobalNameHashHashKey(PLDHashTable *table, const void *key)
|
|
{
|
|
const nsAString *str = static_cast<const nsAString *>(key);
|
|
return HashString(*str);
|
|
}
|
|
|
|
static bool
|
|
GlobalNameHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry,
|
|
const void *key)
|
|
{
|
|
const GlobalNameMapEntry *e =
|
|
static_cast<const GlobalNameMapEntry *>(entry);
|
|
const nsAString *str = static_cast<const nsAString *>(key);
|
|
|
|
return str->Equals(e->mKey);
|
|
}
|
|
|
|
static void
|
|
GlobalNameHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
|
|
{
|
|
GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry);
|
|
|
|
// An entry is being cleared, let the key (nsString) do its own
|
|
// cleanup.
|
|
e->mKey.~nsString();
|
|
if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
|
|
nsIClassInfo* ci = GET_CLEAN_CI_PTR(e->mGlobalName.mData->mCachedClassInfo);
|
|
|
|
// If we constructed an internal helper, we'll let the helper delete
|
|
// the nsDOMClassInfoData structure, if not we do it here.
|
|
if (!ci || e->mGlobalName.mData->u.mExternalConstructorFptr) {
|
|
delete e->mGlobalName.mData;
|
|
}
|
|
|
|
// Release our pointer to the helper.
|
|
NS_IF_RELEASE(ci);
|
|
}
|
|
else if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) {
|
|
delete e->mGlobalName.mAlias;
|
|
}
|
|
|
|
// This will set e->mGlobalName.mType to
|
|
// nsGlobalNameStruct::eTypeNotInitialized
|
|
memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
|
|
}
|
|
|
|
static bool
|
|
GlobalNameHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
|
|
const void *key)
|
|
{
|
|
GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry);
|
|
const nsAString *keyStr = static_cast<const nsAString *>(key);
|
|
|
|
// Initialize the key in the entry with placement new
|
|
new (&e->mKey) nsString(*keyStr);
|
|
|
|
// This will set e->mGlobalName.mType to
|
|
// nsGlobalNameStruct::eTypeNotInitialized
|
|
memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
|
|
return true;
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED2(
|
|
nsScriptNameSpaceManager,
|
|
MemoryUniReporter,
|
|
nsIObserver,
|
|
nsISupportsWeakReference)
|
|
|
|
nsScriptNameSpaceManager::nsScriptNameSpaceManager()
|
|
: MemoryUniReporter("explicit/script-namespace-manager",
|
|
KIND_HEAP, UNITS_BYTES,
|
|
"Memory used for the script namespace manager.")
|
|
, mIsInitialized(false)
|
|
{
|
|
MOZ_COUNT_CTOR(nsScriptNameSpaceManager);
|
|
}
|
|
|
|
nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
|
|
{
|
|
if (mIsInitialized) {
|
|
UnregisterWeakMemoryReporter(this);
|
|
// Destroy the hash
|
|
PL_DHashTableFinish(&mGlobalNames);
|
|
PL_DHashTableFinish(&mNavigatorNames);
|
|
}
|
|
MOZ_COUNT_DTOR(nsScriptNameSpaceManager);
|
|
}
|
|
|
|
nsGlobalNameStruct *
|
|
nsScriptNameSpaceManager::AddToHash(PLDHashTable *aTable, const nsAString *aKey,
|
|
const PRUnichar **aClassName)
|
|
{
|
|
GlobalNameMapEntry *entry =
|
|
static_cast<GlobalNameMapEntry *>
|
|
(PL_DHashTableOperate(aTable, aKey, PL_DHASH_ADD));
|
|
|
|
if (!entry) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (aClassName) {
|
|
*aClassName = entry->mKey.get();
|
|
}
|
|
|
|
return &entry->mGlobalName;
|
|
}
|
|
|
|
void
|
|
nsScriptNameSpaceManager::RemoveFromHash(PLDHashTable *aTable,
|
|
const nsAString *aKey)
|
|
{
|
|
PL_DHashTableOperate(aTable, aKey, PL_DHASH_REMOVE);
|
|
}
|
|
|
|
nsGlobalNameStruct*
|
|
nsScriptNameSpaceManager::GetConstructorProto(const nsGlobalNameStruct* aStruct)
|
|
{
|
|
NS_ASSERTION(aStruct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias,
|
|
"This function only works on constructor aliases!");
|
|
if (!aStruct->mAlias->mProto) {
|
|
GlobalNameMapEntry *proto =
|
|
static_cast<GlobalNameMapEntry *>
|
|
(PL_DHashTableOperate(&mGlobalNames,
|
|
&aStruct->mAlias->mProtoName,
|
|
PL_DHASH_LOOKUP));
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(proto)) {
|
|
aStruct->mAlias->mProto = &proto->mGlobalName;
|
|
}
|
|
}
|
|
return aStruct->mAlias->mProto;
|
|
}
|
|
|
|
nsresult
|
|
nsScriptNameSpaceManager::FillHash(nsICategoryManager *aCategoryManager,
|
|
const char *aCategory)
|
|
{
|
|
nsCOMPtr<nsISimpleEnumerator> e;
|
|
nsresult rv = aCategoryManager->EnumerateCategory(aCategory,
|
|
getter_AddRefs(e));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsISupports> entry;
|
|
while (NS_SUCCEEDED(e->GetNext(getter_AddRefs(entry)))) {
|
|
rv = AddCategoryEntryToHash(aCategoryManager, aCategory, entry);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsScriptNameSpaceManager::RegisterExternalInterfaces(bool aAsProto)
|
|
{
|
|
nsresult rv;
|
|
nsCOMPtr<nsICategoryManager> cm =
|
|
do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsIInterfaceInfoManager>
|
|
iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
|
|
NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
|
|
|
|
nsCOMPtr<nsISimpleEnumerator> enumerator;
|
|
rv = cm->EnumerateCategory(JAVASCRIPT_DOM_INTERFACE,
|
|
getter_AddRefs(enumerator));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsXPIDLCString IID_string;
|
|
nsAutoCString category_entry;
|
|
const char* if_name;
|
|
nsCOMPtr<nsISupports> entry;
|
|
nsCOMPtr<nsIInterfaceInfo> if_info;
|
|
bool found_old, dom_prefix;
|
|
|
|
while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(entry)))) {
|
|
nsCOMPtr<nsISupportsCString> category(do_QueryInterface(entry));
|
|
|
|
if (!category) {
|
|
NS_WARNING("Category entry not an nsISupportsCString!");
|
|
|
|
continue;
|
|
}
|
|
|
|
rv = category->GetData(category_entry);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = cm->GetCategoryEntry(JAVASCRIPT_DOM_INTERFACE, category_entry.get(),
|
|
getter_Copies(IID_string));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsIID primary_IID;
|
|
if (!primary_IID.Parse(IID_string) ||
|
|
primary_IID.Equals(NS_GET_IID(nsISupports))) {
|
|
NS_ERROR("Invalid IID registered with the script namespace manager!");
|
|
continue;
|
|
}
|
|
|
|
iim->GetInfoForIID(&primary_IID, getter_AddRefs(if_info));
|
|
|
|
while (if_info) {
|
|
const nsIID *iid;
|
|
if_info->GetIIDShared(&iid);
|
|
NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
|
|
|
|
if (iid->Equals(NS_GET_IID(nsISupports))) {
|
|
break;
|
|
}
|
|
|
|
if_info->GetNameShared(&if_name);
|
|
dom_prefix = (strncmp(if_name, NS_DOM_INTERFACE_PREFIX,
|
|
sizeof(NS_DOM_INTERFACE_PREFIX) - 1) == 0);
|
|
|
|
const char* name;
|
|
if (dom_prefix) {
|
|
name = if_name + sizeof(NS_DOM_INTERFACE_PREFIX) - 1;
|
|
} else {
|
|
name = if_name + sizeof(NS_INTERFACE_PREFIX) - 1;
|
|
}
|
|
|
|
if (aAsProto) {
|
|
RegisterClassProto(name, iid, &found_old);
|
|
} else {
|
|
RegisterInterface(name, iid, &found_old);
|
|
}
|
|
|
|
if (found_old) {
|
|
break;
|
|
}
|
|
|
|
nsCOMPtr<nsIInterfaceInfo> tmp(if_info);
|
|
tmp->GetParent(getter_AddRefs(if_info));
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsScriptNameSpaceManager::RegisterInterface(const char* aIfName,
|
|
const nsIID *aIfIID,
|
|
bool* aFoundOld)
|
|
{
|
|
*aFoundOld = false;
|
|
|
|
nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aIfName);
|
|
NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
if (s->mType != nsGlobalNameStruct::eTypeNotInitialized &&
|
|
s->mType != nsGlobalNameStruct::eTypeNewDOMBinding) {
|
|
*aFoundOld = true;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
s->mType = nsGlobalNameStruct::eTypeInterface;
|
|
s->mIID = *aIfIID;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
#define GLOBALNAME_HASHTABLE_INITIAL_SIZE 1024
|
|
|
|
nsresult
|
|
nsScriptNameSpaceManager::Init()
|
|
{
|
|
static const PLDHashTableOps hash_table_ops =
|
|
{
|
|
PL_DHashAllocTable,
|
|
PL_DHashFreeTable,
|
|
GlobalNameHashHashKey,
|
|
GlobalNameHashMatchEntry,
|
|
PL_DHashMoveEntryStub,
|
|
GlobalNameHashClearEntry,
|
|
PL_DHashFinalizeStub,
|
|
GlobalNameHashInitEntry
|
|
};
|
|
|
|
mIsInitialized = PL_DHashTableInit(&mGlobalNames, &hash_table_ops, nullptr,
|
|
sizeof(GlobalNameMapEntry),
|
|
GLOBALNAME_HASHTABLE_INITIAL_SIZE);
|
|
NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
mIsInitialized = PL_DHashTableInit(&mNavigatorNames, &hash_table_ops, nullptr,
|
|
sizeof(GlobalNameMapEntry),
|
|
GLOBALNAME_HASHTABLE_INITIAL_SIZE);
|
|
if (!mIsInitialized) {
|
|
PL_DHashTableFinish(&mGlobalNames);
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
RegisterWeakMemoryReporter(this);
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
rv = RegisterExternalInterfaces(false);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsICategoryManager> cm =
|
|
do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = FillHash(cm, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = FillHash(cm, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = FillHash(cm, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = FillHash(cm, JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = FillHash(cm, JAVASCRIPT_GLOBAL_DYNAMIC_NAMESET_CATEGORY);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = FillHash(cm, JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// Initial filling of the has table has been done.
|
|
// Now, listen for changes.
|
|
nsCOMPtr<nsIObserverService> serv =
|
|
mozilla::services::GetObserverService();
|
|
|
|
if (serv) {
|
|
serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID, true);
|
|
serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID, true);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
struct NameSetClosure {
|
|
nsIScriptContext* ctx;
|
|
nsresult rv;
|
|
};
|
|
|
|
static PLDHashOperator
|
|
NameSetInitCallback(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
|
uint32_t number, void *arg)
|
|
{
|
|
GlobalNameMapEntry *entry = static_cast<GlobalNameMapEntry *>(hdr);
|
|
|
|
if (entry->mGlobalName.mType == nsGlobalNameStruct::eTypeStaticNameSet) {
|
|
nsresult rv = NS_OK;
|
|
nsCOMPtr<nsIScriptExternalNameSet> ns =
|
|
do_CreateInstance(entry->mGlobalName.mCID, &rv);
|
|
NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
|
|
|
|
NameSetClosure *closure = static_cast<NameSetClosure *>(arg);
|
|
closure->rv = ns->InitializeNameSet(closure->ctx);
|
|
if (NS_FAILED(closure->rv)) {
|
|
NS_ERROR("Initing external script classes failed!");
|
|
return PL_DHASH_STOP;
|
|
}
|
|
}
|
|
|
|
return PL_DHASH_NEXT;
|
|
}
|
|
|
|
nsresult
|
|
nsScriptNameSpaceManager::InitForContext(nsIScriptContext *aContext)
|
|
{
|
|
NameSetClosure closure;
|
|
closure.ctx = aContext;
|
|
closure.rv = NS_OK;
|
|
PL_DHashTableEnumerate(&mGlobalNames, NameSetInitCallback, &closure);
|
|
|
|
return closure.rv;
|
|
}
|
|
|
|
nsGlobalNameStruct*
|
|
nsScriptNameSpaceManager::LookupNameInternal(const nsAString& aName,
|
|
const PRUnichar **aClassName)
|
|
{
|
|
GlobalNameMapEntry *entry =
|
|
static_cast<GlobalNameMapEntry *>
|
|
(PL_DHashTableOperate(&mGlobalNames, &aName,
|
|
PL_DHASH_LOOKUP));
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(entry) &&
|
|
!((&entry->mGlobalName)->mDisabled)) {
|
|
if (aClassName) {
|
|
*aClassName = entry->mKey.get();
|
|
}
|
|
return &entry->mGlobalName;
|
|
}
|
|
|
|
if (aClassName) {
|
|
*aClassName = nullptr;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const nsGlobalNameStruct*
|
|
nsScriptNameSpaceManager::LookupNavigatorName(const nsAString& aName)
|
|
{
|
|
GlobalNameMapEntry *entry =
|
|
static_cast<GlobalNameMapEntry *>
|
|
(PL_DHashTableOperate(&mNavigatorNames, &aName,
|
|
PL_DHASH_LOOKUP));
|
|
|
|
if (!PL_DHASH_ENTRY_IS_BUSY(entry) ||
|
|
entry->mGlobalName.mDisabled) {
|
|
return nullptr;
|
|
}
|
|
|
|
return &entry->mGlobalName;
|
|
}
|
|
|
|
nsresult
|
|
nsScriptNameSpaceManager::RegisterClassName(const char *aClassName,
|
|
int32_t aDOMClassInfoID,
|
|
bool aPrivileged,
|
|
bool aXBLAllowed,
|
|
bool aDisabled,
|
|
const PRUnichar **aResult)
|
|
{
|
|
if (!nsCRT::IsAscii(aClassName)) {
|
|
NS_ERROR("Trying to register a non-ASCII class name");
|
|
return NS_OK;
|
|
}
|
|
nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName, aResult);
|
|
NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
if (s->mType == nsGlobalNameStruct::eTypeClassConstructor) {
|
|
return NS_OK;
|
|
}
|
|
|
|
// If a external constructor is already defined with aClassName we
|
|
// won't overwrite it.
|
|
|
|
if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
|
|
s->mType == nsGlobalNameStruct::eTypeNewDOMBinding ||
|
|
s->mType == nsGlobalNameStruct::eTypeInterface,
|
|
"Whaaa, JS environment name clash!");
|
|
|
|
s->mType = nsGlobalNameStruct::eTypeClassConstructor;
|
|
s->mDOMClassInfoID = aDOMClassInfoID;
|
|
s->mChromeOnly = aPrivileged;
|
|
s->mAllowXBL = aXBLAllowed;
|
|
s->mDisabled = aDisabled;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsScriptNameSpaceManager::RegisterClassProto(const char *aClassName,
|
|
const nsIID *aConstructorProtoIID,
|
|
bool *aFoundOld)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aConstructorProtoIID);
|
|
|
|
*aFoundOld = false;
|
|
|
|
nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName);
|
|
NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
if (s->mType != nsGlobalNameStruct::eTypeNotInitialized &&
|
|
s->mType != nsGlobalNameStruct::eTypeNewDOMBinding &&
|
|
s->mType != nsGlobalNameStruct::eTypeInterface) {
|
|
*aFoundOld = true;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
s->mType = nsGlobalNameStruct::eTypeClassProto;
|
|
s->mIID = *aConstructorProtoIID;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsScriptNameSpaceManager::RegisterExternalClassName(const char *aClassName,
|
|
nsCID& aCID)
|
|
{
|
|
nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName);
|
|
NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
// If an external constructor is already defined with aClassName we
|
|
// won't overwrite it.
|
|
|
|
if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
|
|
s->mType == nsGlobalNameStruct::eTypeNewDOMBinding ||
|
|
s->mType == nsGlobalNameStruct::eTypeInterface,
|
|
"Whaaa, JS environment name clash!");
|
|
|
|
s->mType = nsGlobalNameStruct::eTypeExternalClassInfoCreator;
|
|
s->mCID = aCID;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsScriptNameSpaceManager::RegisterDOMCIData(const char *aName,
|
|
nsDOMClassInfoExternalConstructorFnc aConstructorFptr,
|
|
const nsIID *aProtoChainInterface,
|
|
const nsIID **aInterfaces,
|
|
uint32_t aScriptableFlags,
|
|
bool aHasClassInterface,
|
|
const nsCID *aConstructorCID)
|
|
{
|
|
const PRUnichar* className;
|
|
nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aName, &className);
|
|
NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
// If an external constructor is already defined with aClassName we
|
|
// won't overwrite it.
|
|
|
|
if (s->mType == nsGlobalNameStruct::eTypeClassConstructor ||
|
|
s->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
|
|
return NS_OK;
|
|
}
|
|
|
|
// XXX Should we bail out here?
|
|
NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
|
|
s->mType == nsGlobalNameStruct::eTypeNewDOMBinding ||
|
|
s->mType == nsGlobalNameStruct::eTypeExternalClassInfoCreator,
|
|
"Someone tries to register classinfo data for a class that isn't new or external!");
|
|
|
|
s->mData = new nsExternalDOMClassInfoData;
|
|
NS_ENSURE_TRUE(s->mData, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
s->mType = nsGlobalNameStruct::eTypeExternalClassInfo;
|
|
s->mData->mName = aName;
|
|
s->mData->mNameUTF16 = className;
|
|
if (aConstructorFptr)
|
|
s->mData->u.mExternalConstructorFptr = aConstructorFptr;
|
|
else
|
|
// null constructor will cause us to use nsDOMGenericSH::doCreate
|
|
s->mData->u.mExternalConstructorFptr = nullptr;
|
|
s->mData->mCachedClassInfo = nullptr;
|
|
s->mData->mProtoChainInterface = aProtoChainInterface;
|
|
s->mData->mInterfaces = aInterfaces;
|
|
s->mData->mScriptableFlags = aScriptableFlags;
|
|
s->mData->mHasClassInterface = aHasClassInterface;
|
|
s->mData->mConstructorCID = aConstructorCID;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsScriptNameSpaceManager::OperateCategoryEntryHash(nsICategoryManager* aCategoryManager,
|
|
const char* aCategory,
|
|
nsISupports* aEntry,
|
|
bool aRemove)
|
|
{
|
|
MOZ_ASSERT(aCategoryManager);
|
|
// Get the type from the category name.
|
|
// NOTE: we could have passed the type in FillHash() and guessed it in
|
|
// Observe() but this way, we have only one place to update and this is
|
|
// not performance sensitive.
|
|
nsGlobalNameStruct::nametype type;
|
|
if (strcmp(aCategory, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY) == 0) {
|
|
type = nsGlobalNameStruct::eTypeExternalConstructor;
|
|
} else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY) == 0 ||
|
|
strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0) {
|
|
type = nsGlobalNameStruct::eTypeProperty;
|
|
} else if (strcmp(aCategory, JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY) == 0) {
|
|
type = nsGlobalNameStruct::eTypeNavigatorProperty;
|
|
} else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY) == 0) {
|
|
type = nsGlobalNameStruct::eTypeStaticNameSet;
|
|
} else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_DYNAMIC_NAMESET_CATEGORY) == 0) {
|
|
type = nsGlobalNameStruct::eTypeDynamicNameSet;
|
|
} else {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsCOMPtr<nsISupportsCString> strWrapper = do_QueryInterface(aEntry);
|
|
|
|
if (!strWrapper) {
|
|
NS_WARNING("Category entry not an nsISupportsCString!");
|
|
return NS_OK;
|
|
}
|
|
|
|
nsAutoCString categoryEntry;
|
|
nsresult rv = strWrapper->GetData(categoryEntry);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
PLDHashTable *table;
|
|
if (type == nsGlobalNameStruct::eTypeNavigatorProperty) {
|
|
table = &mNavigatorNames;
|
|
} else {
|
|
table = &mGlobalNames;
|
|
}
|
|
|
|
// We need to handle removal before calling GetCategoryEntry
|
|
// because the category entry is already removed before we are
|
|
// notified.
|
|
if (aRemove) {
|
|
NS_ConvertASCIItoUTF16 entry(categoryEntry);
|
|
const nsGlobalNameStruct *s =
|
|
type == nsGlobalNameStruct::eTypeNavigatorProperty ?
|
|
LookupNavigatorName(entry) : LookupNameInternal(entry);
|
|
// Verify mType so that this API doesn't remove names
|
|
// registered by others.
|
|
if (!s || s->mType != type) {
|
|
return NS_OK;
|
|
}
|
|
|
|
RemoveFromHash(table, &entry);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsXPIDLCString contractId;
|
|
rv = aCategoryManager->GetCategoryEntry(aCategory, categoryEntry.get(),
|
|
getter_Copies(contractId));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (type == nsGlobalNameStruct::eTypeNavigatorProperty ||
|
|
type == nsGlobalNameStruct::eTypeExternalConstructor) {
|
|
bool isNavProperty = type == nsGlobalNameStruct::eTypeNavigatorProperty;
|
|
nsPrintfCString prefName("dom.%s.disable.%s",
|
|
isNavProperty ? "navigator-property" : "global-constructor",
|
|
categoryEntry.get());
|
|
if (Preferences::GetType(prefName.get()) == nsIPrefBranch::PREF_BOOL &&
|
|
Preferences::GetBool(prefName.get(), false)) {
|
|
return NS_OK;
|
|
}
|
|
}
|
|
|
|
nsCOMPtr<nsIComponentRegistrar> registrar;
|
|
rv = NS_GetComponentRegistrar(getter_AddRefs(registrar));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCID *cidPtr;
|
|
rv = registrar->ContractIDToCID(contractId, &cidPtr);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
NS_WARNING("Bad contract id registed with the script namespace manager");
|
|
return NS_OK;
|
|
}
|
|
|
|
// Copy CID onto the stack, so we can free it right away and avoid having
|
|
// to add cleanup code at every exit point from this function.
|
|
nsCID cid = *cidPtr;
|
|
nsMemory::Free(cidPtr);
|
|
|
|
if (type == nsGlobalNameStruct::eTypeExternalConstructor) {
|
|
nsXPIDLCString constructorProto;
|
|
rv = aCategoryManager->GetCategoryEntry(JAVASCRIPT_GLOBAL_CONSTRUCTOR_PROTO_ALIAS_CATEGORY,
|
|
categoryEntry.get(),
|
|
getter_Copies(constructorProto));
|
|
if (NS_SUCCEEDED(rv)) {
|
|
nsGlobalNameStruct *s = AddToHash(&mGlobalNames, categoryEntry.get());
|
|
NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
if (s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
|
|
s->mType == nsGlobalNameStruct::eTypeNewDOMBinding) {
|
|
s->mAlias = new nsGlobalNameStruct::ConstructorAlias;
|
|
s->mType = nsGlobalNameStruct::eTypeExternalConstructorAlias;
|
|
s->mChromeOnly = false;
|
|
s->mAlias->mCID = cid;
|
|
AppendASCIItoUTF16(constructorProto, s->mAlias->mProtoName);
|
|
s->mAlias->mProto = nullptr;
|
|
} else {
|
|
NS_WARNING("Global script name not overwritten!");
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
}
|
|
|
|
nsGlobalNameStruct *s = AddToHash(table, categoryEntry.get());
|
|
NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
if (s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
|
|
s->mType == nsGlobalNameStruct::eTypeNewDOMBinding) {
|
|
s->mType = type;
|
|
s->mCID = cid;
|
|
s->mChromeOnly =
|
|
strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0;
|
|
} else {
|
|
NS_WARNING("Global script name not overwritten!");
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsScriptNameSpaceManager::AddCategoryEntryToHash(nsICategoryManager* aCategoryManager,
|
|
const char* aCategory,
|
|
nsISupports* aEntry)
|
|
{
|
|
return OperateCategoryEntryHash(aCategoryManager, aCategory, aEntry,
|
|
/* aRemove = */ false);
|
|
}
|
|
|
|
nsresult
|
|
nsScriptNameSpaceManager::RemoveCategoryEntryFromHash(nsICategoryManager* aCategoryManager,
|
|
const char* aCategory,
|
|
nsISupports* aEntry)
|
|
{
|
|
return OperateCategoryEntryHash(aCategoryManager, aCategory, aEntry,
|
|
/* aRemove = */ true);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsScriptNameSpaceManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|
const PRUnichar* aData)
|
|
{
|
|
if (!aData) {
|
|
return NS_OK;
|
|
}
|
|
|
|
if (!strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID)) {
|
|
nsCOMPtr<nsICategoryManager> cm =
|
|
do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
|
|
if (!cm) {
|
|
return NS_OK;
|
|
}
|
|
|
|
return AddCategoryEntryToHash(cm, NS_ConvertUTF16toUTF8(aData).get(),
|
|
aSubject);
|
|
} else if (!strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID)) {
|
|
nsCOMPtr<nsICategoryManager> cm =
|
|
do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
|
|
if (!cm) {
|
|
return NS_OK;
|
|
}
|
|
|
|
return RemoveCategoryEntryFromHash(cm, NS_ConvertUTF16toUTF8(aData).get(),
|
|
aSubject);
|
|
}
|
|
|
|
// TODO: we could observe NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID
|
|
// but we are safe without it. See bug 600460.
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsScriptNameSpaceManager::RegisterDefineDOMInterface(const nsAFlatString& aName,
|
|
mozilla::dom::DefineInterface aDefineDOMInterface,
|
|
mozilla::dom::ConstructorEnabled* aConstructorEnabled)
|
|
{
|
|
nsGlobalNameStruct *s = AddToHash(&mGlobalNames, &aName);
|
|
if (s) {
|
|
if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
|
|
s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
|
|
}
|
|
s->mDefineDOMInterface = aDefineDOMInterface;
|
|
s->mConstructorEnabled = aConstructorEnabled;
|
|
}
|
|
}
|
|
|
|
void
|
|
nsScriptNameSpaceManager::RegisterNavigatorDOMConstructor(
|
|
const nsAFlatString& aName,
|
|
mozilla::dom::ConstructNavigatorProperty aNavConstructor,
|
|
mozilla::dom::ConstructorEnabled* aConstructorEnabled)
|
|
{
|
|
nsGlobalNameStruct *s = AddToHash(&mNavigatorNames, &aName);
|
|
if (s) {
|
|
if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
|
|
s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
|
|
}
|
|
s->mConstructNavigatorProperty = aNavConstructor;
|
|
s->mConstructorEnabled = aConstructorEnabled;
|
|
}
|
|
}
|
|
|
|
struct NameClosure
|
|
{
|
|
nsScriptNameSpaceManager::NameEnumerator enumerator;
|
|
void* closure;
|
|
};
|
|
|
|
static PLDHashOperator
|
|
EnumerateName(PLDHashTable*, PLDHashEntryHdr *hdr, uint32_t, void* aClosure)
|
|
{
|
|
GlobalNameMapEntry *entry = static_cast<GlobalNameMapEntry *>(hdr);
|
|
NameClosure* closure = static_cast<NameClosure*>(aClosure);
|
|
return closure->enumerator(entry->mKey, closure->closure);
|
|
}
|
|
|
|
void
|
|
nsScriptNameSpaceManager::EnumerateGlobalNames(NameEnumerator aEnumerator,
|
|
void* aClosure)
|
|
{
|
|
NameClosure closure = { aEnumerator, aClosure };
|
|
PL_DHashTableEnumerate(&mGlobalNames, EnumerateName, &closure);
|
|
}
|
|
|
|
void
|
|
nsScriptNameSpaceManager::EnumerateNavigatorNames(NameEnumerator aEnumerator,
|
|
void* aClosure)
|
|
{
|
|
NameClosure closure = { aEnumerator, aClosure };
|
|
PL_DHashTableEnumerate(&mNavigatorNames, EnumerateName, &closure);
|
|
}
|
|
|
|
static size_t
|
|
SizeOfEntryExcludingThis(PLDHashEntryHdr *aHdr, MallocSizeOf aMallocSizeOf,
|
|
void *aArg)
|
|
{
|
|
GlobalNameMapEntry* entry = static_cast<GlobalNameMapEntry*>(aHdr);
|
|
return entry->SizeOfExcludingThis(aMallocSizeOf);
|
|
}
|
|
|
|
int64_t
|
|
nsScriptNameSpaceManager::Amount()
|
|
{
|
|
return SizeOfIncludingThis(MallocSizeOf);
|
|
}
|
|
|
|
size_t
|
|
nsScriptNameSpaceManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
|
{
|
|
size_t n = 0;
|
|
n += PL_DHashTableSizeOfExcludingThis(&mGlobalNames,
|
|
SizeOfEntryExcludingThis, aMallocSizeOf);
|
|
n += PL_DHashTableSizeOfExcludingThis(&mNavigatorNames,
|
|
SizeOfEntryExcludingThis, aMallocSizeOf);
|
|
return n;
|
|
}
|