gecko-dev/dom/bindings/BindingUtils.h

3482 строки
107 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/. */
Bug 742217. Reduce the use of nested namespaces in our binding code. r=peterv,bent In the new setup, all per-interface DOM binding files are exported into mozilla/dom. General files not specific to an interface are also exported into mozilla/dom. In terms of namespaces, most things now live in mozilla::dom. Each interface Foo that has generated code has a mozilla::dom::FooBinding namespace for said generated code (and possibly a mozilla::bindings::FooBinding_workers if there's separate codegen for workers). IDL enums are a bit weird: since the name of the enum and the names of its entries all end up in the same namespace, we still generate a C++ namespace with the name of the IDL enum type with "Values" appended to it, with a ::valuelist inside for the actual C++ enum. We then typedef EnumFooValues::valuelist to EnumFoo. That makes it a bit more difficult to refer to the values, but means that values from different enums don't collide with each other. The enums with the proto and constructor IDs in them now live under the mozilla::dom::prototypes and mozilla::dom::constructors namespaces respectively. Again, this lets us deal sanely with the whole "enum value names are flattened into the namespace the enum is in" deal. The main benefit of this setup (and the reason "Binding" got appended to the per-interface namespaces) is that this way "using mozilla::dom" should Just Work for consumers and still allow C++ code to sanely use the IDL interface names for concrete classes, which is fairly desirable. --HG-- rename : dom/bindings/Utils.cpp => dom/bindings/BindingUtils.cpp rename : dom/bindings/Utils.h => dom/bindings/BindingUtils.h
2012-05-03 08:35:38 +04:00
#ifndef mozilla_dom_BindingUtils_h__
#define mozilla_dom_BindingUtils_h__
#include "jsfriendapi.h"
#include "js/CharacterEncoding.h"
#include "js/Wrapper.h"
#include "js/Conversions.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Alignment.h"
#include "mozilla/Array.h"
#include "mozilla/Assertions.h"
#include "mozilla/DeferredFinalize.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/CallbackObject.h"
Bug 742217. Reduce the use of nested namespaces in our binding code. r=peterv,bent In the new setup, all per-interface DOM binding files are exported into mozilla/dom. General files not specific to an interface are also exported into mozilla/dom. In terms of namespaces, most things now live in mozilla::dom. Each interface Foo that has generated code has a mozilla::dom::FooBinding namespace for said generated code (and possibly a mozilla::bindings::FooBinding_workers if there's separate codegen for workers). IDL enums are a bit weird: since the name of the enum and the names of its entries all end up in the same namespace, we still generate a C++ namespace with the name of the IDL enum type with "Values" appended to it, with a ::valuelist inside for the actual C++ enum. We then typedef EnumFooValues::valuelist to EnumFoo. That makes it a bit more difficult to refer to the values, but means that values from different enums don't collide with each other. The enums with the proto and constructor IDs in them now live under the mozilla::dom::prototypes and mozilla::dom::constructors namespaces respectively. Again, this lets us deal sanely with the whole "enum value names are flattened into the namespace the enum is in" deal. The main benefit of this setup (and the reason "Binding" got appended to the per-interface namespaces) is that this way "using mozilla::dom" should Just Work for consumers and still allow C++ code to sanely use the IDL interface names for concrete classes, which is fairly desirable. --HG-- rename : dom/bindings/Utils.cpp => dom/bindings/BindingUtils.cpp rename : dom/bindings/Utils.h => dom/bindings/BindingUtils.h
2012-05-03 08:35:38 +04:00
#include "mozilla/dom/DOMJSClass.h"
#include "mozilla/dom/DOMJSProxyHandler.h"
#include "mozilla/dom/Exceptions.h"
#include "mozilla/dom/NonRefcountedDOMObject.h"
#include "mozilla/dom/Nullable.h"
#include "mozilla/dom/PrototypeList.h"
#include "mozilla/dom/RootedDictionary.h"
#include "mozilla/SegmentedVector.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/Likely.h"
#include "mozilla/MemoryReporting.h"
#include "nsAutoPtr.h"
#include "nsIDocument.h"
#include "nsIGlobalObject.h"
#include "nsIXPConnect.h"
#include "nsJSUtils.h"
#include "nsISupportsImpl.h"
#include "xpcObjectHelper.h"
#include "xpcpublic.h"
#include "nsIVariant.h"
#include "mozilla/dom/FakeString.h"
#include "nsWrapperCacheInlines.h"
class nsGenericHTMLElement;
class nsIJSID;
class nsIDocument;
namespace mozilla {
enum UseCounter : int16_t;
namespace dom {
class CustomElementReactionsStack;
class MessageManagerGlobal;
template<typename KeyType, typename ValueType> class Record;
class Location;
nsresult
UnwrapArgImpl(JSContext* cx, JS::Handle<JSObject*> src, const nsIID& iid,
void** ppArg);
nsresult
UnwrapWindowProxyImpl(JSContext* cx, JS::Handle<JSObject*> src,
nsPIDOMWindowOuter** ppArg);
/** Convert a jsval to an XPCOM pointer. Caller must not assume that src will
keep the XPCOM pointer rooted. */
template <class Interface>
inline nsresult
UnwrapArg(JSContext* cx, JS::Handle<JSObject*> src, Interface** ppArg)
{
return UnwrapArgImpl(cx, src, NS_GET_TEMPLATE_IID(Interface),
reinterpret_cast<void**>(ppArg));
}
template <>
inline nsresult
UnwrapArg<nsPIDOMWindowOuter>(JSContext* cx, JS::Handle<JSObject*> src,
nsPIDOMWindowOuter** ppArg)
{
return UnwrapWindowProxyImpl(cx, src, ppArg);
}
bool
ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
bool aSecurityError, const char* aInterfaceName);
bool
ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
bool aSecurityError, prototypes::ID aProtoId);
// Returns true if the JSClass is used for DOM objects.
inline bool
IsDOMClass(const JSClass* clasp)
{
return clasp->flags & JSCLASS_IS_DOMJSCLASS;
}
inline bool
IsDOMClass(const js::Class* clasp)
{
return IsDOMClass(Jsvalify(clasp));
}
// Return true if the JSClass is used for non-proxy DOM objects.
inline bool
IsNonProxyDOMClass(const js::Class* clasp)
{
return IsDOMClass(clasp) && !clasp->isProxy();
}
inline bool
IsNonProxyDOMClass(const JSClass* clasp)
{
return IsNonProxyDOMClass(js::Valueify(clasp));
}
// Returns true if the JSClass is used for DOM interface and interface
// prototype objects.
inline bool
IsDOMIfaceAndProtoClass(const JSClass* clasp)
{
return clasp->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS;
}
inline bool
IsDOMIfaceAndProtoClass(const js::Class* clasp)
{
return IsDOMIfaceAndProtoClass(Jsvalify(clasp));
}
static_assert(DOM_OBJECT_SLOT == 0,
"DOM_OBJECT_SLOT doesn't match the proxy private slot. "
Bug 895322 - Part 1: Replace the usages of MOZ_STATIC_ASSERT with C++11 static_assert; r=Waldo This patch was mostly generated by running the following scripts on the codebase, with some manual changes made afterwards: # static_assert.sh #!/bin/bash # Command to convert an NSPR integer type to the equivalent standard integer type function convert() { echo "Converting $1 to $2..." find . ! -wholename "*nsprpub*" \ ! -wholename "*security/nss*" \ ! -wholename "*/.hg*" \ ! -wholename "obj-ff-dbg*" \ ! -name nsXPCOMCID.h \ ! -name prtypes.h \ -type f \ \( -iname "*.cpp" \ -o -iname "*.h" \ -o -iname "*.cc" \ -o -iname "*.mm" \) | \ xargs -n 1 `dirname $0`/assert_replacer.py #sed -i -e "s/\b$1\b/$2/g" } convert MOZ_STATIC_ASSERT static_assert hg rev --no-backup mfbt/Assertions.h \ media/webrtc/signaling/src/sipcc/core/includes/ccapi.h \ modules/libmar/src/mar_private.h \ modules/libmar/src/mar.h # assert_replacer.py #!/usr/bin/python import sys import re pattern = re.compile(r"\bMOZ_STATIC_ASSERT\b") def replaceInPlace(fname): print fname f = open(fname, "rw+") lines = f.readlines() for i in range(0, len(lines)): while True: index = re.search(pattern, lines[i]) if index != None: index = index.start() lines[i] = lines[i][0:index] + "static_assert" + lines[i][index+len("MOZ_STATIC_ASSERT"):] for j in range(i + 1, len(lines)): if lines[j].find(" ", index) == index: lines[j] = lines[j][0:index] + lines[j][index+4:] else: break else: break f.seek(0, 0) f.truncate() f.write("".join(lines)) f.close() argc = len(sys.argv) for i in range(1, argc): replaceInPlace(sys.argv[i]) --HG-- extra : rebase_source : 4b4a4047d82f2c205b9fad8d56dfc3f1afc0b045
2013-07-18 21:59:53 +04:00
"Expect bad things");
template <class T>
inline T*
UnwrapDOMObject(JSObject* obj)
{
MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
"Don't pass non-DOM objects to this function");
JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
return static_cast<T*>(val.toPrivate());
}
template <class T>
inline T*
UnwrapPossiblyNotInitializedDOMObject(JSObject* obj)
{
// This is used by the OjectMoved JSClass hook which can be called before
// JS_NewObject has returned and so before we have a chance to set
// DOM_OBJECT_SLOT to anything useful.
MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
"Don't pass non-DOM objects to this function");
JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
if (val.isUndefined()) {
return nullptr;
}
return static_cast<T*>(val.toPrivate());
}
inline const DOMJSClass*
GetDOMClass(const js::Class* clasp)
{
return IsDOMClass(clasp) ? DOMJSClass::FromJSClass(clasp) : nullptr;
}
inline const DOMJSClass*
GetDOMClass(JSObject* obj)
{
return GetDOMClass(js::GetObjectClass(obj));
}
inline nsISupports*
UnwrapDOMObjectToISupports(JSObject* aObject)
{
const DOMJSClass* clasp = GetDOMClass(aObject);
if (!clasp || !clasp->mDOMObjectIsISupports) {
return nullptr;
}
return UnwrapPossiblyNotInitializedDOMObject<nsISupports>(aObject);
}
inline bool
IsDOMObject(JSObject* obj)
{
return IsDOMClass(js::GetObjectClass(obj));
}
// There are two valid ways to use UNWRAP_OBJECT: Either obj needs to
// be a MutableHandle<JSObject*>, or value needs to be a strong-reference
// smart pointer type (OwningNonNull or RefPtr or nsCOMPtr), in which case obj
// can be anything that converts to JSObject*.
#define UNWRAP_OBJECT(Interface, obj, value) \
mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Interface, \
mozilla::dom::Interface##_Binding::NativeType>(obj, value)
// Test whether the given object is an instance of the given interface.
#define IS_INSTANCE_OF(Interface, obj) \
mozilla::dom::IsInstanceOf<mozilla::dom::prototypes::id::Interface, \
mozilla::dom::Interface##_Binding::NativeType>(obj)
// Unwrap the given non-wrapper object. This can be used with any obj that
// converts to JSObject*; as long as that JSObject* is live the return value
// will be valid.
#define UNWRAP_NON_WRAPPER_OBJECT(Interface, obj, value) \
mozilla::dom::UnwrapNonWrapperObject<mozilla::dom::prototypes::id::Interface, \
mozilla::dom::Interface##_Binding::NativeType>(obj, value)
// Some callers don't want to set an exception when unwrapping fails
// (for example, overload resolution uses unwrapping to tell what sort
// of thing it's looking at).
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
// U must be something that a T* can be assigned to (e.g. T* or an RefPtr<T>).
//
// The obj argument will be mutated to point to CheckedUnwrap of itself if the
// passed-in value is not a DOM object and CheckedUnwrap succeeds.
//
// If mayBeWrapper is true, there are three valid ways to invoke
// UnwrapObjectInternal: Either obj needs to be a class wrapping a
// MutableHandle<JSObject*>, with an assignment operator that sets the handle to
// the given object, or U needs to be a strong-reference smart pointer type
// (OwningNonNull or RefPtr or nsCOMPtr), or the value being stored in "value"
// must not escape past being tested for falsiness immediately after the
// UnwrapObjectInternal call.
//
// If mayBeWrapper is false, obj can just be a JSObject*, and U anything that a
// T* can be assigned to.
namespace binding_detail {
template <class T, bool mayBeWrapper, typename U, typename V>
MOZ_ALWAYS_INLINE nsresult
UnwrapObjectInternal(V& obj, U& value, prototypes::ID protoID,
uint32_t protoDepth)
{
/* First check to see whether we have a DOM object */
const DOMJSClass* domClass = GetDOMClass(obj);
if (domClass) {
/* This object is a DOM object. Double-check that it is safely
castable to T by checking whether it claims to inherit from the
class identified by protoID. */
if (domClass->mInterfaceChain[protoDepth] == protoID) {
value = UnwrapDOMObject<T>(obj);
return NS_OK;
}
}
/* Maybe we have a security wrapper or outer window? */
if (!mayBeWrapper || !js::IsWrapper(obj)) {
/* Not a DOM object, not a wrapper, just bail */
return NS_ERROR_XPC_BAD_CONVERT_JS;
}
JSObject* unwrappedObj =
js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
if (!unwrappedObj) {
return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
}
MOZ_ASSERT(!js::IsWrapper(unwrappedObj));
// Recursive call is OK, because now we're using false for mayBeWrapper and
// we never reach this code if that boolean is false, so can't keep calling
// ourselves.
//
// Unwrap into a temporary pointer, because in general unwrapping into
// something of type U might trigger GC (e.g. release the value currently
// stored in there, with arbitrary consequences) and invalidate the
// "unwrappedObj" pointer.
T* tempValue = nullptr;
nsresult rv = UnwrapObjectInternal<T, false>(unwrappedObj, tempValue,
protoID, protoDepth);
if (NS_SUCCEEDED(rv)) {
// It's very important to not update "obj" with the "unwrappedObj" value
// until we know the unwrap has succeeded. Otherwise, in a situation in
// which we have an overload of object and primitive we could end up
// converting to the primitive from the unwrappedObj, whereas we want to do
// it from the original object.
obj = unwrappedObj;
// And now assign to "value"; at this point we don't care if a GC happens
// and invalidates unwrappedObj.
value = tempValue;
return NS_OK;
}
/* It's the wrong sort of DOM object */
return NS_ERROR_XPC_BAD_CONVERT_JS;
}
struct MutableObjectHandleWrapper {
explicit MutableObjectHandleWrapper(JS::MutableHandle<JSObject*> aHandle)
: mHandle(aHandle)
{
}
void operator=(JSObject* aObject)
{
MOZ_ASSERT(aObject);
mHandle.set(aObject);
}
operator JSObject*() const
{
return mHandle;
}
private:
JS::MutableHandle<JSObject*> mHandle;
};
struct MutableValueHandleWrapper {
explicit MutableValueHandleWrapper(JS::MutableHandle<JS::Value> aHandle)
: mHandle(aHandle)
{
}
void operator=(JSObject* aObject)
{
MOZ_ASSERT(aObject);
mHandle.setObject(*aObject);
}
operator JSObject*() const
{
return &mHandle.toObject();
}
private:
JS::MutableHandle<JS::Value> mHandle;
};
} // namespace binding_detail
// UnwrapObject overloads that ensure we have a MutableHandle to keep it alive.
template<prototypes::ID PrototypeID, class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JS::MutableHandle<JSObject*> obj, U& value)
{
binding_detail::MutableObjectHandleWrapper wrapper(obj);
return binding_detail::UnwrapObjectInternal<T, true>(
wrapper, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
}
template<prototypes::ID PrototypeID, class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JS::MutableHandle<JS::Value> obj, U& value)
{
MOZ_ASSERT(obj.isObject());
binding_detail::MutableValueHandleWrapper wrapper(obj);
return binding_detail::UnwrapObjectInternal<T, true>(
wrapper, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
}
// UnwrapObject overloads that ensure we have a strong ref to keep it alive.
template<prototypes::ID PrototypeID, class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JSObject* obj, RefPtr<U>& value)
{
return binding_detail::UnwrapObjectInternal<T, true>(
obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
}
template<prototypes::ID PrototypeID, class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JSObject* obj, nsCOMPtr<U>& value)
{
return binding_detail::UnwrapObjectInternal<T, true>(
obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
}
template<prototypes::ID PrototypeID, class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JSObject* obj, OwningNonNull<U>& value)
{
return binding_detail::UnwrapObjectInternal<T, true>(
obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
}
// An UnwrapObject overload that just calls one of the JSObject* ones.
template<prototypes::ID PrototypeID, class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JS::Handle<JS::Value> obj, U& value)
{
MOZ_ASSERT(obj.isObject());
return UnwrapObject<PrototypeID, T>(&obj.toObject(), value);
}
template<prototypes::ID PrototypeID, class T>
MOZ_ALWAYS_INLINE bool
IsInstanceOf(JSObject* obj)
{
void* ignored;
nsresult unwrapped = binding_detail::UnwrapObjectInternal<T, true>(
obj, ignored, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
return NS_SUCCEEDED(unwrapped);
}
template<prototypes::ID PrototypeID, class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapNonWrapperObject(JSObject* obj, U& value)
{
MOZ_ASSERT(!js::IsWrapper(obj));
return binding_detail::UnwrapObjectInternal<T, false>(
obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
}
MOZ_ALWAYS_INLINE bool
IsConvertibleToDictionary(JS::Handle<JS::Value> val)
{
return val.isNullOrUndefined() || val.isObject();
}
// The items in the protoAndIfaceCache are indexed by the prototypes::id::ID,
// constructors::id::ID and namedpropertiesobjects::id::ID enums, in that order.
// The end of the prototype objects should be the start of the interface
// objects, and the end of the interface objects should be the start of the
// named properties objects.
Bug 895322 - Part 1: Replace the usages of MOZ_STATIC_ASSERT with C++11 static_assert; r=Waldo This patch was mostly generated by running the following scripts on the codebase, with some manual changes made afterwards: # static_assert.sh #!/bin/bash # Command to convert an NSPR integer type to the equivalent standard integer type function convert() { echo "Converting $1 to $2..." find . ! -wholename "*nsprpub*" \ ! -wholename "*security/nss*" \ ! -wholename "*/.hg*" \ ! -wholename "obj-ff-dbg*" \ ! -name nsXPCOMCID.h \ ! -name prtypes.h \ -type f \ \( -iname "*.cpp" \ -o -iname "*.h" \ -o -iname "*.cc" \ -o -iname "*.mm" \) | \ xargs -n 1 `dirname $0`/assert_replacer.py #sed -i -e "s/\b$1\b/$2/g" } convert MOZ_STATIC_ASSERT static_assert hg rev --no-backup mfbt/Assertions.h \ media/webrtc/signaling/src/sipcc/core/includes/ccapi.h \ modules/libmar/src/mar_private.h \ modules/libmar/src/mar.h # assert_replacer.py #!/usr/bin/python import sys import re pattern = re.compile(r"\bMOZ_STATIC_ASSERT\b") def replaceInPlace(fname): print fname f = open(fname, "rw+") lines = f.readlines() for i in range(0, len(lines)): while True: index = re.search(pattern, lines[i]) if index != None: index = index.start() lines[i] = lines[i][0:index] + "static_assert" + lines[i][index+len("MOZ_STATIC_ASSERT"):] for j in range(i + 1, len(lines)): if lines[j].find(" ", index) == index: lines[j] = lines[j][0:index] + lines[j][index+4:] else: break else: break f.seek(0, 0) f.truncate() f.write("".join(lines)) f.close() argc = len(sys.argv) for i in range(1, argc): replaceInPlace(sys.argv[i]) --HG-- extra : rebase_source : 4b4a4047d82f2c205b9fad8d56dfc3f1afc0b045
2013-07-18 21:59:53 +04:00
static_assert((size_t)constructors::id::_ID_Start ==
(size_t)prototypes::id::_ID_Count &&
(size_t)namedpropertiesobjects::id::_ID_Start ==
(size_t)constructors::id::_ID_Count,
Bug 895322 - Part 1: Replace the usages of MOZ_STATIC_ASSERT with C++11 static_assert; r=Waldo This patch was mostly generated by running the following scripts on the codebase, with some manual changes made afterwards: # static_assert.sh #!/bin/bash # Command to convert an NSPR integer type to the equivalent standard integer type function convert() { echo "Converting $1 to $2..." find . ! -wholename "*nsprpub*" \ ! -wholename "*security/nss*" \ ! -wholename "*/.hg*" \ ! -wholename "obj-ff-dbg*" \ ! -name nsXPCOMCID.h \ ! -name prtypes.h \ -type f \ \( -iname "*.cpp" \ -o -iname "*.h" \ -o -iname "*.cc" \ -o -iname "*.mm" \) | \ xargs -n 1 `dirname $0`/assert_replacer.py #sed -i -e "s/\b$1\b/$2/g" } convert MOZ_STATIC_ASSERT static_assert hg rev --no-backup mfbt/Assertions.h \ media/webrtc/signaling/src/sipcc/core/includes/ccapi.h \ modules/libmar/src/mar_private.h \ modules/libmar/src/mar.h # assert_replacer.py #!/usr/bin/python import sys import re pattern = re.compile(r"\bMOZ_STATIC_ASSERT\b") def replaceInPlace(fname): print fname f = open(fname, "rw+") lines = f.readlines() for i in range(0, len(lines)): while True: index = re.search(pattern, lines[i]) if index != None: index = index.start() lines[i] = lines[i][0:index] + "static_assert" + lines[i][index+len("MOZ_STATIC_ASSERT"):] for j in range(i + 1, len(lines)): if lines[j].find(" ", index) == index: lines[j] = lines[j][0:index] + lines[j][index+4:] else: break else: break f.seek(0, 0) f.truncate() f.write("".join(lines)) f.close() argc = len(sys.argv) for i in range(1, argc): replaceInPlace(sys.argv[i]) --HG-- extra : rebase_source : 4b4a4047d82f2c205b9fad8d56dfc3f1afc0b045
2013-07-18 21:59:53 +04:00
"Overlapping or discontiguous indexes.");
const size_t kProtoAndIfaceCacheCount = namedpropertiesobjects::id::_ID_Count;
class ProtoAndIfaceCache
{
// The caching strategy we use depends on what sort of global we're dealing
// with. For a window-like global, we want everything to be as fast as
// possible, so we use a flat array, indexed by prototype/constructor ID.
// For everything else (e.g. globals for JSMs), space is more important than
// speed, so we use a two-level lookup table.
class ArrayCache : public Array<JS::Heap<JSObject*>, kProtoAndIfaceCacheCount>
{
public:
bool HasEntryInSlot(size_t i) {
return (*this)[i];
}
JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
return (*this)[i];
}
JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
return (*this)[i];
}
void Trace(JSTracer* aTracer) {
for (size_t i = 0; i < ArrayLength(*this); ++i) {
JS::TraceEdge(aTracer, &(*this)[i], "protoAndIfaceCache[i]");
}
}
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
return aMallocSizeOf(this);
}
};
class PageTableCache
{
public:
PageTableCache() {
memset(mPages.begin(), 0, sizeof(mPages));
}
~PageTableCache() {
for (size_t i = 0; i < ArrayLength(mPages); ++i) {
delete mPages[i];
}
}
bool HasEntryInSlot(size_t i) {
MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
size_t pageIndex = i / kPageSize;
size_t leafIndex = i % kPageSize;
Page* p = mPages[pageIndex];
if (!p) {
return false;
}
return (*p)[leafIndex];
}
JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
size_t pageIndex = i / kPageSize;
size_t leafIndex = i % kPageSize;
Page* p = mPages[pageIndex];
if (!p) {
p = new Page;
mPages[pageIndex] = p;
}
return (*p)[leafIndex];
}
JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
size_t pageIndex = i / kPageSize;
size_t leafIndex = i % kPageSize;
Page* p = mPages[pageIndex];
MOZ_ASSERT(p);
return (*p)[leafIndex];
}
void Trace(JSTracer* trc) {
for (size_t i = 0; i < ArrayLength(mPages); ++i) {
Page* p = mPages[i];
if (p) {
for (size_t j = 0; j < ArrayLength(*p); ++j) {
JS::TraceEdge(trc, &(*p)[j], "protoAndIfaceCache[i]");
}
}
}
}
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
size_t n = aMallocSizeOf(this);
for (size_t i = 0; i < ArrayLength(mPages); ++i) {
n += aMallocSizeOf(mPages[i]);
}
return n;
}
private:
static const size_t kPageSize = 16;
typedef Array<JS::Heap<JSObject*>, kPageSize> Page;
static const size_t kNPages = kProtoAndIfaceCacheCount / kPageSize +
size_t(bool(kProtoAndIfaceCacheCount % kPageSize));
Array<Page*, kNPages> mPages;
};
public:
enum Kind {
WindowLike,
NonWindowLike
};
explicit ProtoAndIfaceCache(Kind aKind) : mKind(aKind) {
MOZ_COUNT_CTOR(ProtoAndIfaceCache);
if (aKind == WindowLike) {
mArrayCache = new ArrayCache();
} else {
mPageTableCache = new PageTableCache();
}
}
~ProtoAndIfaceCache() {
if (mKind == WindowLike) {
delete mArrayCache;
} else {
delete mPageTableCache;
}
MOZ_COUNT_DTOR(ProtoAndIfaceCache);
}
#define FORWARD_OPERATION(opName, args) \
do { \
if (mKind == WindowLike) { \
return mArrayCache->opName args; \
} else { \
return mPageTableCache->opName args; \
} \
} while(0)
// Return whether slot i contains an object. This doesn't return the object
// itself because in practice consumers just want to know whether it's there
// or not, and that doesn't require barriering, which returning the object
// pointer does.
bool HasEntryInSlot(size_t i) {
FORWARD_OPERATION(HasEntryInSlot, (i));
}
// Return a reference to slot i, creating it if necessary. There
// may not be an object in the returned slot.
JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
FORWARD_OPERATION(EntrySlotOrCreate, (i));
}
// Return a reference to slot i, which is guaranteed to already
// exist. There may not be an object in the slot, if prototype and
// constructor initialization for one of our bindings failed.
JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
FORWARD_OPERATION(EntrySlotMustExist, (i));
}
void Trace(JSTracer *aTracer) {
FORWARD_OPERATION(Trace, (aTracer));
}
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
size_t n = aMallocSizeOf(this);
n += (mKind == WindowLike
? mArrayCache->SizeOfIncludingThis(aMallocSizeOf)
: mPageTableCache->SizeOfIncludingThis(aMallocSizeOf));
return n;
}
#undef FORWARD_OPERATION
private:
union {
ArrayCache *mArrayCache;
PageTableCache *mPageTableCache;
};
Kind mKind;
};
inline void
AllocateProtoAndIfaceCache(JSObject* obj, ProtoAndIfaceCache::Kind aKind)
{
MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined());
ProtoAndIfaceCache* protoAndIfaceCache = new ProtoAndIfaceCache(aKind);
js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT,
JS::PrivateValue(protoAndIfaceCache));
}
#ifdef DEBUG
struct VerifyTraceProtoAndIfaceCacheCalledTracer : public JS::CallbackTracer
{
bool ok;
explicit VerifyTraceProtoAndIfaceCacheCalledTracer(JSContext* cx)
: JS::CallbackTracer(cx), ok(false)
{}
void onChild(const JS::GCCellPtr&) override {
// We don't do anything here, we only want to verify that
// TraceProtoAndIfaceCache was called.
}
TracerKind getTracerKind() const override { return TracerKind::VerifyTraceProtoAndIface; }
};
#endif
inline void
TraceProtoAndIfaceCache(JSTracer* trc, JSObject* obj)
{
MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
#ifdef DEBUG
if (trc->isCallbackTracer() &&
(trc->asCallbackTracer()->getTracerKind() ==
JS::CallbackTracer::TracerKind::VerifyTraceProtoAndIface)) {
// We don't do anything here, we only want to verify that
// TraceProtoAndIfaceCache was called.
static_cast<VerifyTraceProtoAndIfaceCacheCalledTracer*>(trc)->ok = true;
return;
}
#endif
if (!DOMGlobalHasProtoAndIFaceCache(obj))
return;
ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
protoAndIfaceCache->Trace(trc);
}
inline void
DestroyProtoAndIfaceCache(JSObject* obj)
{
MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
if (!DOMGlobalHasProtoAndIFaceCache(obj)) {
return;
}
ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
delete protoAndIfaceCache;
}
/**
* Add constants to an object.
*/
bool
DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
const ConstantSpec* cs);
struct JSNativeHolder
{
JSNative mNative;
const NativePropertyHooks* mPropertyHooks;
};
struct NamedConstructor
{
const char* mName;
const JSNativeHolder mHolder;
unsigned mNargs;
};
/*
* Create a DOM interface object (if constructorClass is non-null) and/or a
* DOM interface prototype object (if protoClass is non-null).
*
* global is used as the parent of the interface object and the interface
* prototype object
* protoProto is the prototype to use for the interface prototype object.
* interfaceProto is the prototype to use for the interface object. This can be
* null if both constructorClass and constructor are null (as in,
* if we're not creating an interface object at all).
* protoClass is the JSClass to use for the interface prototype object.
* This is null if we should not create an interface prototype
* object.
* protoCache a pointer to a JSObject pointer where we should cache the
* interface prototype object. This must be null if protoClass is and
* vice versa.
* toStringTag if not null, a string to define as @@toStringTag on the prototype.
* Must be null if protoClass is.
* constructorClass is the JSClass to use for the interface object.
* This is null if we should not create an interface object or
* if it should be a function object.
* constructor holds the JSNative to back the interface object which should be a
* Function, unless constructorClass is non-null in which case it is
* ignored. If this is null and constructorClass is also null then
* we should not create an interface object at all.
* ctorNargs is the length of the constructor function; 0 if no constructor
* constructorCache a pointer to a JSObject pointer where we should cache the
* interface object. This must be null if both constructorClass
* and constructor are null, and non-null otherwise.
* properties contains the methods, attributes and constants to be defined on
* objects in any compartment.
* chromeProperties contains the methods, attributes and constants to be defined
* on objects in chrome compartments. This must be null if the
* interface doesn't have any ChromeOnly properties or if the
* object is being created in non-chrome compartment.
* defineOnGlobal controls whether properties should be defined on the given
* global for the interface object (if any) and named
* constructors (if any) for this interface. This can be
* false in situations where we want the properties to only
* appear on privileged Xrays but not on the unprivileged
* underlying global.
* unscopableNames if not null it points to a null-terminated list of const
* char* names of the unscopable properties for this interface.
* isGlobal if true, we're creating interface objects for a [Global] or
* [PrimaryGlobal] interface, and hence shouldn't define properties on
* the prototype object.
*
* At least one of protoClass, constructorClass or constructor should be
* non-null. If constructorClass or constructor are non-null, the resulting
* interface object will be defined on the given global with property name
* |name|, which must also be non-null.
*/
void
CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
JS::Handle<JSObject*> protoProto,
const js::Class* protoClass, JS::Heap<JSObject*>* protoCache,
const char* toStringTag,
JS::Handle<JSObject*> interfaceProto,
const js::Class* constructorClass,
unsigned ctorNargs, const NamedConstructor* namedConstructors,
JS::Heap<JSObject*>* constructorCache,
const NativeProperties* regularProperties,
const NativeProperties* chromeOnlyProperties,
const char* name, bool defineOnGlobal,
const char* const* unscopableNames,
bool isGlobal);
/**
* Define the properties (regular and chrome-only) on obj.
*
* obj the object to instal the properties on. This should be the interface
* prototype object for regular interfaces and the instance object for
* interfaces marked with Global.
* properties contains the methods, attributes and constants to be defined on
* objects in any compartment.
* chromeProperties contains the methods, attributes and constants to be defined
* on objects in chrome compartments. This must be null if the
* interface doesn't have any ChromeOnly properties or if the
* object is being created in non-chrome compartment.
*/
bool
DefineProperties(JSContext* cx, JS::Handle<JSObject*> obj,
const NativeProperties* properties,
const NativeProperties* chromeOnlyProperties);
/*
* Define the unforgeable methods on an object.
*/
bool
DefineUnforgeableMethods(JSContext* cx, JS::Handle<JSObject*> obj,
const Prefable<const JSFunctionSpec>* props);
/*
* Define the unforgeable attributes on an object.
*/
bool
DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
const Prefable<const JSPropertySpec>* props);
#define HAS_MEMBER_TYPEDEFS \
private: \
typedef char yes[1]; \
typedef char no[2]
#ifdef _MSC_VER
#define HAS_MEMBER_CHECK(_name) \
template<typename V> static yes& Check##_name(char (*)[(&V::_name == 0) + 1])
#else
#define HAS_MEMBER_CHECK(_name) \
template<typename V> static yes& Check##_name(char (*)[sizeof(&V::_name) + 1])
#endif
#define HAS_MEMBER(_memberName, _valueName) \
private: \
HAS_MEMBER_CHECK(_memberName); \
template<typename V> static no& Check##_memberName(...); \
\
public: \
static bool const _valueName = \
sizeof(Check##_memberName<T>(nullptr)) == sizeof(yes)
template<class T>
struct NativeHasMember
{
HAS_MEMBER_TYPEDEFS;
HAS_MEMBER(GetParentObject, GetParentObject);
HAS_MEMBER(WrapObject, WrapObject);
};
template<class T>
struct IsSmartPtr
{
HAS_MEMBER_TYPEDEFS;
HAS_MEMBER(get, value);
};
template<class T>
struct IsRefcounted
{
HAS_MEMBER_TYPEDEFS;
HAS_MEMBER(AddRef, HasAddref);
HAS_MEMBER(Release, HasRelease);
public:
static bool const value = HasAddref && HasRelease;
private:
// This struct only works if T is fully declared (not just forward declared).
// The IsBaseOf check will ensure that, we don't really need it for any other
// reason (the static assert will of course always be true).
static_assert(!IsBaseOf<nsISupports, T>::value || IsRefcounted::value,
"Classes derived from nsISupports are refcounted!");
};
#undef HAS_MEMBER
#undef HAS_MEMBER_CHECK
#undef HAS_MEMBER_TYPEDEFS
#ifdef DEBUG
template <class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
struct
CheckWrapperCacheCast
{
static bool Check()
{
return reinterpret_cast<uintptr_t>(
static_cast<nsWrapperCache*>(
reinterpret_cast<T*>(1))) == 1;
}
};
template <class T>
struct
CheckWrapperCacheCast<T, true>
{
static bool Check()
{
return true;
}
};
#endif
inline bool
TryToOuterize(JS::MutableHandle<JS::Value> rval)
{
if (js::IsWindow(&rval.toObject())) {
JSObject* obj = js::ToWindowProxyIfWindow(&rval.toObject());
MOZ_ASSERT(obj);
rval.set(JS::ObjectValue(*obj));
}
return true;
}
// Make sure to wrap the given string value into the right compartment, as
// needed.
MOZ_ALWAYS_INLINE
bool
MaybeWrapStringValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
{
MOZ_ASSERT(rval.isString());
JSString* str = rval.toString();
if (JS::GetStringZone(str) != js::GetContextZone(cx)) {
return JS_WrapValue(cx, rval);
}
return true;
}
// Make sure to wrap the given object value into the right compartment as
// needed. This will work correctly, but possibly slowly, on all objects.
MOZ_ALWAYS_INLINE
bool
MaybeWrapObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
{
MOZ_ASSERT(rval.isObject());
// Cross-compartment always requires wrapping.
JSObject* obj = &rval.toObject();
if (js::GetObjectCompartment(obj) != js::GetContextCompartment(cx)) {
return JS_WrapValue(cx, rval);
}
// We're same-compartment, but even then we might need to wrap
// objects specially. Check for that.
if (IsDOMObject(obj)) {
return TryToOuterize(rval);
}
// It's not a WebIDL object, so it's OK to just leave it as-is: only WebIDL
// objects (specifically only windows) require outerization.
return true;
}
// Like MaybeWrapObjectValue, but also allows null
MOZ_ALWAYS_INLINE
bool
MaybeWrapObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
{
MOZ_ASSERT(rval.isObjectOrNull());
if (rval.isNull()) {
return true;
}
return MaybeWrapObjectValue(cx, rval);
}
// Wrapping for objects that are known to not be DOM or XPConnect objects
MOZ_ALWAYS_INLINE
bool
MaybeWrapNonDOMObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
{
MOZ_ASSERT(rval.isObject());
MOZ_ASSERT(!GetDOMClass(&rval.toObject()));
MOZ_ASSERT(!(js::GetObjectClass(&rval.toObject())->flags &
JSCLASS_PRIVATE_IS_NSISUPPORTS));
JSObject* obj = &rval.toObject();
if (js::GetObjectCompartment(obj) == js::GetContextCompartment(cx)) {
return true;
}
return JS_WrapValue(cx, rval);
}
// Like MaybeWrapNonDOMObjectValue but allows null
MOZ_ALWAYS_INLINE
bool
MaybeWrapNonDOMObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
{
MOZ_ASSERT(rval.isObjectOrNull());
if (rval.isNull()) {
return true;
}
return MaybeWrapNonDOMObjectValue(cx, rval);
}
// If rval is a gcthing and is not in the compartment of cx, wrap rval
// into the compartment of cx (typically by replacing it with an Xray or
// cross-compartment wrapper around the original object).
MOZ_ALWAYS_INLINE bool
MaybeWrapValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
{
if (rval.isGCThing()) {
if (rval.isString()) {
return MaybeWrapStringValue(cx, rval);
}
if (rval.isObject()) {
return MaybeWrapObjectValue(cx, rval);
}
#ifdef ENABLE_BIGINT
// This could be optimized by checking the zone first, similar to
// the way strings are handled. At present, this is used primarily
// for structured cloning, so avoiding the overhead of JS_WrapValue
// calls is less important than for other types.
if (rval.isBigInt()) {
return JS_WrapValue(cx, rval);
}
#endif
MOZ_ASSERT(rval.isSymbol());
JS_MarkCrossZoneId(cx, SYMBOL_TO_JSID(rval.toSymbol()));
}
return true;
}
namespace binding_detail {
enum GetOrCreateReflectorWrapBehavior {
eWrapIntoContextCompartment,
eDontWrapIntoContextCompartment
};
template <class T>
struct TypeNeedsOuterization
{
// We only need to outerize Window objects, so anything inheriting from
// nsGlobalWindow (which inherits from EventTarget itself).
static const bool value =
IsBaseOf<nsGlobalWindowInner, T>::value ||
IsBaseOf<nsGlobalWindowOuter, T>::value ||
IsSame<EventTarget, T>::value;
};
#ifdef DEBUG
template<typename T, bool isISupports=IsBaseOf<nsISupports, T>::value>
struct CheckWrapperCacheTracing
{
static inline void Check(T* aObject)
{
}
};
template<typename T>
struct CheckWrapperCacheTracing<T, true>
{
static void Check(T* aObject)
{
// Rooting analysis thinks QueryInterface may GC, but we're dealing with
// a subset of QueryInterface, C++ only types here.
JS::AutoSuppressGCAnalysis nogc;
nsWrapperCache* wrapperCacheFromQI = nullptr;
aObject->QueryInterface(NS_GET_IID(nsWrapperCache),
reinterpret_cast<void**>(&wrapperCacheFromQI));
MOZ_ASSERT(wrapperCacheFromQI,
"Missing nsWrapperCache from QueryInterface implementation?");
if (!wrapperCacheFromQI->GetWrapperPreserveColor()) {
// Can't assert that we trace the wrapper, since we don't have any
// wrapper to trace.
return;
}
nsISupports* ccISupports = nullptr;
aObject->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
reinterpret_cast<void**>(&ccISupports));
MOZ_ASSERT(ccISupports,
"nsWrapperCache object which isn't cycle collectable?");
nsXPCOMCycleCollectionParticipant* participant = nullptr;
CallQueryInterface(ccISupports, &participant);
MOZ_ASSERT(participant, "Can't QI to CycleCollectionParticipant?");
bool wasPreservingWrapper = wrapperCacheFromQI->PreservingWrapper();
wrapperCacheFromQI->SetPreservingWrapper(true);
wrapperCacheFromQI->CheckCCWrapperTraversal(ccISupports, participant);
wrapperCacheFromQI->SetPreservingWrapper(wasPreservingWrapper);
}
};
void
AssertReflectorHasGivenProto(JSContext* aCx, JSObject* aReflector,
JS::Handle<JSObject*> aGivenProto);
#endif // DEBUG
template <class T>
MOZ_ALWAYS_INLINE void
CrashIfDocumentOrLocationWrapFailed()
{
// Do nothing.
}
template<>
MOZ_ALWAYS_INLINE void
CrashIfDocumentOrLocationWrapFailed<nsIDocument>()
{
MOZ_CRASH("Looks like bug 1488480/1405521, with WrapObject() on nsIDocument throwing");
}
template<>
MOZ_ALWAYS_INLINE void
CrashIfDocumentOrLocationWrapFailed<Location>()
{
MOZ_CRASH("Looks like bug 1488480/1405521, with WrapObject() on Location throwing");
}
template <class T, GetOrCreateReflectorWrapBehavior wrapBehavior>
MOZ_ALWAYS_INLINE bool
DoGetOrCreateDOMReflector(JSContext* cx, T* value,
JS::Handle<JSObject*> givenProto,
JS::MutableHandle<JS::Value> rval)
{
MOZ_ASSERT(value);
MOZ_ASSERT_IF(givenProto, js::IsObjectInContextCompartment(givenProto, cx));
JSObject* obj = value->GetWrapper();
if (obj) {
#ifdef DEBUG
AssertReflectorHasGivenProto(cx, obj, givenProto);
// Have to reget obj because AssertReflectorHasGivenProto can
// trigger gc so the pointer may now be invalid.
obj = value->GetWrapper();
#endif
} else {
obj = value->WrapObject(cx, givenProto);
if (!obj) {
// At this point, obj is null, so just return false.
// Callers seem to be testing JS_IsExceptionPending(cx) to
// figure out whether WrapObject() threw.
CrashIfDocumentOrLocationWrapFailed<T>();
return false;
}
#ifdef DEBUG
if (IsBaseOf<nsWrapperCache, T>::value) {
CheckWrapperCacheTracing<T>::Check(value);
}
#endif
}
#ifdef DEBUG
const DOMJSClass* clasp = GetDOMClass(obj);
// clasp can be null if the cache contained a non-DOM object.
if (clasp) {
// Some sanity asserts about our object. Specifically:
// 1) If our class claims we're nsISupports, we better be nsISupports
// XXXbz ideally, we could assert that reinterpret_cast to nsISupports
// does the right thing, but I don't see a way to do it. :(
// 2) If our class doesn't claim we're nsISupports we better be
// reinterpret_castable to nsWrapperCache.
MOZ_ASSERT(clasp, "What happened here?");
MOZ_ASSERT_IF(clasp->mDOMObjectIsISupports, (IsBaseOf<nsISupports, T>::value));
MOZ_ASSERT(CheckWrapperCacheCast<T>::Check());
}
#endif
rval.set(JS::ObjectValue(*obj));
if (js::GetObjectCompartment(obj) == js::GetContextCompartment(cx)) {
if (!TypeNeedsOuterization<T>::value) {
return true;
}
if (TryToOuterize(rval)) {
return true;
}
return false;
}
if (wrapBehavior == eDontWrapIntoContextCompartment) {
if (TypeNeedsOuterization<T>::value) {
JSAutoRealm ar(cx, obj);
if (TryToOuterize(rval)) {
return true;
}
return false;
}
return true;
}
if (JS_WrapValue(cx, rval)) {
return true;
}
MOZ_CRASH("Looks like bug 1488480/1405521, with JS_WrapValue failing");
return false;
}
} // namespace binding_detail
// Create a JSObject wrapping "value", if there isn't one already, and store it
// in rval. "value" must be a concrete class that implements a
// GetWrapperPreserveColor() which can return its existing wrapper, if any, and
// a WrapObject() which will try to create a wrapper. Typically, this is done by
// having "value" inherit from nsWrapperCache.
//
// The value stored in rval will be ready to be exposed to whatever JS
// is running on cx right now. In particular, it will be in the
// compartment of cx, and outerized as needed.
template <class T>
MOZ_ALWAYS_INLINE bool
GetOrCreateDOMReflector(JSContext* cx, T* value,
JS::MutableHandle<JS::Value> rval,
JS::Handle<JSObject*> givenProto = nullptr)
{
using namespace binding_detail;
return DoGetOrCreateDOMReflector<T, eWrapIntoContextCompartment>(cx, value,
givenProto,
rval);
}
// Like GetOrCreateDOMReflector but doesn't wrap into the context compartment,
// and hence does not actually require cx to be in a compartment.
template <class T>
MOZ_ALWAYS_INLINE bool
GetOrCreateDOMReflectorNoWrap(JSContext* cx, T* value,
JS::MutableHandle<JS::Value> rval)
{
using namespace binding_detail;
return DoGetOrCreateDOMReflector<T, eDontWrapIntoContextCompartment>(cx,
value,
nullptr,
rval);
}
// Create a JSObject wrapping "value", for cases when "value" is a
// non-wrapper-cached object using WebIDL bindings. "value" must implement a
// WrapObject() method taking a JSContext and a prototype (possibly null) and
// returning the resulting object via a MutableHandle<JSObject*> outparam.
template <class T>
inline bool
WrapNewBindingNonWrapperCachedObject(JSContext* cx,
JS::Handle<JSObject*> scopeArg,
T* value,
JS::MutableHandle<JS::Value> rval,
JS::Handle<JSObject*> givenProto = nullptr)
{
static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
MOZ_ASSERT(value);
// We try to wrap in the realm of the underlying object of "scope"
JS::Rooted<JSObject*> obj(cx);
{
// scope for the JSAutoRealm so that we restore the realm
// before we call JS_WrapValue.
Maybe<JSAutoRealm> ar;
// Maybe<Handle> doesn't so much work, and in any case, adding
// more Maybe (one for a Rooted and one for a Handle) adds more
// code (and branches!) than just adding a single rooted.
JS::Rooted<JSObject*> scope(cx, scopeArg);
JS::Rooted<JSObject*> proto(cx, givenProto);
if (js::IsWrapper(scope)) {
scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
if (!scope)
return false;
ar.emplace(cx, scope);
if (!JS_WrapObject(cx, &proto)) {
return false;
}
}
MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
if (!value->WrapObject(cx, proto, &obj)) {
return false;
}
}
// We can end up here in all sorts of compartments, per above. Make
// sure to JS_WrapValue!
rval.set(JS::ObjectValue(*obj));
return MaybeWrapObjectValue(cx, rval);
}
// Create a JSObject wrapping "value", for cases when "value" is a
// non-wrapper-cached owned object using WebIDL bindings. "value" must
// implement a WrapObject() method taking a taking a JSContext and a prototype
// (possibly null) and returning two pieces of information: the resulting object
// via a MutableHandle<JSObject*> outparam and a boolean return value that is
// true if the JSObject took ownership
template <class T>
inline bool
WrapNewBindingNonWrapperCachedObject(JSContext* cx,
JS::Handle<JSObject*> scopeArg,
nsAutoPtr<T>& value,
JS::MutableHandle<JS::Value> rval,
JS::Handle<JSObject*> givenProto = nullptr)
{
static_assert(!IsRefcounted<T>::value, "Only pass owned classes in here.");
// We do a runtime check on value, because otherwise we might in
// fact end up wrapping a null and invoking methods on it later.
if (!value) {
MOZ_CRASH("Don't try to wrap null objects");
}
// We try to wrap in the realm of the underlying object of "scope"
JS::Rooted<JSObject*> obj(cx);
{
// scope for the JSAutoRealm so that we restore the realm
// before we call JS_WrapValue.
Maybe<JSAutoRealm> ar;
// Maybe<Handle> doesn't so much work, and in any case, adding
// more Maybe (one for a Rooted and one for a Handle) adds more
// code (and branches!) than just adding a single rooted.
JS::Rooted<JSObject*> scope(cx, scopeArg);
JS::Rooted<JSObject*> proto(cx, givenProto);
if (js::IsWrapper(scope)) {
scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
if (!scope)
return false;
ar.emplace(cx, scope);
if (!JS_WrapObject(cx, &proto)) {
return false;
}
}
MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
if (!value->WrapObject(cx, proto, &obj)) {
return false;
}
value.forget();
}
// We can end up here in all sorts of compartments, per above. Make
// sure to JS_WrapValue!
rval.set(JS::ObjectValue(*obj));
return MaybeWrapObjectValue(cx, rval);
}
// Helper for smart pointers (nsRefPtr/nsCOMPtr).
template <template <typename> class SmartPtr, typename T,
typename U=typename EnableIf<IsRefcounted<T>::value, T>::Type,
typename V=typename EnableIf<IsSmartPtr<SmartPtr<T>>::value, T>::Type>
inline bool
WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
const SmartPtr<T>& value,
JS::MutableHandle<JS::Value> rval,
JS::Handle<JSObject*> givenProto = nullptr)
{
return WrapNewBindingNonWrapperCachedObject(cx, scope, value.get(), rval,
givenProto);
}
// Helper for object references (as opposed to pointers).
template <typename T,
typename U=typename EnableIf<!IsSmartPtr<T>::value, T>::Type>
inline bool
WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
T& value,
JS::MutableHandle<JS::Value> rval,
JS::Handle<JSObject*> givenProto = nullptr)
{
return WrapNewBindingNonWrapperCachedObject(cx, scope, &value, rval,
givenProto);
}
template<bool Fatal>
inline bool
EnumValueNotFound(JSContext* cx, JS::HandleString str, const char* type,
const char* sourceDescription);
template<>
inline bool
EnumValueNotFound<false>(JSContext* cx, JS::HandleString str, const char* type,
const char* sourceDescription)
{
// TODO: Log a warning to the console.
return true;
}
template<>
inline bool
EnumValueNotFound<true>(JSContext* cx, JS::HandleString str, const char* type,
const char* sourceDescription)
{
JS::UniqueChars deflated = JS_EncodeStringToUTF8(cx, str);
if (!deflated) {
return false;
}
return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, sourceDescription,
deflated.get(), type);
}
template<typename CharT>
inline int
FindEnumStringIndexImpl(const CharT* chars, size_t length, const EnumEntry* values)
{
int i = 0;
for (const EnumEntry* value = values; value->value; ++value, ++i) {
if (length != value->length) {
continue;
}
bool equal = true;
const char* val = value->value;
for (size_t j = 0; j != length; ++j) {
if (unsigned(val[j]) != unsigned(chars[j])) {
equal = false;
break;
}
}
if (equal) {
return i;
}
}
return -1;
}
template<bool InvalidValueFatal>
inline bool
FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* values,
const char* type, const char* sourceDescription, int* index)
{
// JS_StringEqualsAscii is slow as molasses, so don't use it here.
JS::RootedString str(cx, JS::ToString(cx, v));
if (!str) {
return false;
}
{
size_t length;
JS::AutoCheckCannotGC nogc;
if (js::StringHasLatin1Chars(str)) {
const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str,
&length);
if (!chars) {
return false;
}
*index = FindEnumStringIndexImpl(chars, length, values);
} else {
const char16_t* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, str,
&length);
if (!chars) {
return false;
}
*index = FindEnumStringIndexImpl(chars, length, values);
}
if (*index >= 0) {
return true;
}
}
return EnumValueNotFound<InvalidValueFatal>(cx, str, type, sourceDescription);
}
inline nsWrapperCache*
GetWrapperCache(const ParentObject& aParentObject)
{
return aParentObject.mWrapperCache;
}
template<class T>
inline T*
GetParentPointer(T* aObject)
{
return aObject;
}
inline nsISupports*
GetParentPointer(const ParentObject& aObject)
{
return aObject.mObject;
}
template <typename T>
inline mozilla::dom::ReflectionScope
GetReflectionScope(T* aParentObject)
{
return mozilla::dom::ReflectionScope::Content;
}
inline mozilla::dom::ReflectionScope
GetReflectionScope(const ParentObject& aParentObject)
{
return aParentObject.mReflectionScope;
}
template<class T>
inline void
ClearWrapper(T* p, nsWrapperCache* cache, JSObject* obj)
{
JS::AutoAssertGCCallback inCallback;
// Skip clearing the wrapper when replaying. This method is called during
// finalization of |obj|, and when replaying a strong reference is kept on
// the contents of the cache: since |obj| is being finalized, the cache
// cannot point to |obj|, and clearing here won't do anything.
// Additionally, the reference held on the cache may have already been
// released, if we are finalizing later than we did while recording, and the
// cache may have already been deleted.
if (!recordreplay::IsReplaying()) {
cache->ClearWrapper(obj);
}
}
template<class T>
inline void
ClearWrapper(T* p, void*, JSObject* obj)
{
JS::AutoAssertGCCallback inCallback;
// Skip clearing the wrapper when replaying, for the same reason as in the
// overload above: |p| may have been deleted and we cannot QI it.
if (!recordreplay::IsReplaying()) {
nsWrapperCache* cache;
CallQueryInterface(p, &cache);
ClearWrapper(p, cache, obj);
}
}
template<class T>
inline void
UpdateWrapper(T* p, nsWrapperCache* cache, JSObject* obj, const JSObject* old)
{
JS::AutoAssertGCCallback inCallback;
cache->UpdateWrapper(obj, old);
}
template<class T>
inline void
UpdateWrapper(T* p, void*, JSObject* obj, const JSObject* old)
{
JS::AutoAssertGCCallback inCallback;
nsWrapperCache* cache;
CallQueryInterface(p, &cache);
UpdateWrapper(p, cache, obj, old);
}
// Attempt to preserve the wrapper, if any, for a Paris DOM bindings object.
// Return true if we successfully preserved the wrapper, or there is no wrapper
// to preserve. In the latter case we don't need to preserve the wrapper, because
// the object can only be obtained by JS once, or they cannot be meaningfully
// owned from the native side.
//
// This operation will return false only for non-nsISupports cycle-collected
// objects, because we cannot determine if they are wrappercached or not.
bool
TryPreserveWrapper(JS::Handle<JSObject*> obj);
// Can only be called with a DOM JSClass.
bool
InstanceClassHasProtoAtDepth(const js::Class* clasp,
uint32_t protoID, uint32_t depth);
// Only set allowNativeWrapper to false if you really know you need it; if in
// doubt use true. Setting it to false disables security wrappers.
bool
XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
xpcObjectHelper& helper, const nsIID* iid,
bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval);
// Special-cased wrapping for variants
bool
VariantToJsval(JSContext* aCx, nsIVariant* aVariant,
JS::MutableHandle<JS::Value> aRetval);
// Wrap an object "p" which is not using WebIDL bindings yet. This _will_
// actually work on WebIDL binding objects that are wrappercached, but will be
// much slower than GetOrCreateDOMReflector. "cache" must either be null or be
// the nsWrapperCache for "p".
template<class T>
inline bool
WrapObject(JSContext* cx, T* p, nsWrapperCache* cache, const nsIID* iid,
JS::MutableHandle<JS::Value> rval)
{
if (xpc_FastGetCachedWrapper(cx, cache, rval))
return true;
xpcObjectHelper helper(ToSupports(p), cache);
JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
return XPCOMObjectToJsval(cx, scope, helper, iid, true, rval);
}
// A specialization of the above for nsIVariant, because that needs to
// do something different.
template<>
inline bool
WrapObject<nsIVariant>(JSContext* cx, nsIVariant* p,
nsWrapperCache* cache, const nsIID* iid,
JS::MutableHandle<JS::Value> rval)
{
MOZ_ASSERT(iid);
MOZ_ASSERT(iid->Equals(NS_GET_IID(nsIVariant)));
return VariantToJsval(cx, p, rval);
}
// Wrap an object "p" which is not using WebIDL bindings yet. Just like the
// variant that takes an nsWrapperCache above, but will try to auto-derive the
// nsWrapperCache* from "p".
template<class T>
inline bool
WrapObject(JSContext* cx, T* p, const nsIID* iid,
JS::MutableHandle<JS::Value> rval)
{
return WrapObject(cx, p, GetWrapperCache(p), iid, rval);
}
// Just like the WrapObject above, but without requiring you to pick which
// interface you're wrapping as. This should only be used for objects that have
// classinfo, for which it doesn't matter what IID is used to wrap.
template<class T>
inline bool
WrapObject(JSContext* cx, T* p, JS::MutableHandle<JS::Value> rval)
{
return WrapObject(cx, p, nullptr, rval);
}
// Helper to make it possible to wrap directly out of an nsCOMPtr
template<class T>
inline bool
WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
const nsIID* iid, JS::MutableHandle<JS::Value> rval)
{
return WrapObject(cx, p.get(), iid, rval);
}
// Helper to make it possible to wrap directly out of an nsCOMPtr
template<class T>
inline bool
WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
JS::MutableHandle<JS::Value> rval)
{
return WrapObject(cx, p, nullptr, rval);
}
// Helper to make it possible to wrap directly out of an nsRefPtr
template<class T>
inline bool
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
WrapObject(JSContext* cx, const RefPtr<T>& p,
const nsIID* iid, JS::MutableHandle<JS::Value> rval)
{
return WrapObject(cx, p.get(), iid, rval);
}
// Helper to make it possible to wrap directly out of an nsRefPtr
template<class T>
inline bool
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
WrapObject(JSContext* cx, const RefPtr<T>& p,
JS::MutableHandle<JS::Value> rval)
{
return WrapObject(cx, p, nullptr, rval);
}
// Specialization to make it easy to use WrapObject in codegen.
template<>
inline bool
WrapObject<JSObject>(JSContext* cx, JSObject* p,
JS::MutableHandle<JS::Value> rval)
{
rval.set(JS::ObjectOrNullValue(p));
return true;
}
inline bool
WrapObject(JSContext* cx, JSObject& p, JS::MutableHandle<JS::Value> rval)
{
rval.set(JS::ObjectValue(p));
return true;
}
// Given an object "p" that inherits from nsISupports, wrap it and return the
// result. Null is returned on wrapping failure. This is somewhat similar to
// WrapObject() above, but does NOT allow Xrays around the result, since we
// don't want those for our parent object.
template<typename T>
static inline JSObject*
WrapNativeISupports(JSContext* cx, T* p, nsWrapperCache* cache)
{
xpcObjectHelper helper(ToSupports(p), cache);
JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
JS::Rooted<JS::Value> v(cx);
return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, &v) ?
v.toObjectOrNull() :
nullptr;
}
// Wrapping of our native parent, for cases when it's a WebIDL object.
template<typename T, bool hasWrapObject=NativeHasMember<T>::WrapObject>
struct WrapNativeHelper
{
static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
{
MOZ_ASSERT(cache);
JSObject* obj;
if ((obj = cache->GetWrapper())) {
// GetWrapper always unmarks gray.
MOZ_ASSERT(JS::ObjectIsNotGray(obj));
return obj;
}
// WrapObject never returns a gray thing.
obj = parent->WrapObject(cx, nullptr);
MOZ_ASSERT(JS::ObjectIsNotGray(obj));
return obj;
}
};
// Wrapping of our native parent, for cases when it's not a WebIDL object. In
// this case it must be nsISupports.
template<typename T>
struct WrapNativeHelper<T, false>
{
static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
{
JSObject* obj;
if (cache && (obj = cache->GetWrapper())) {
#ifdef DEBUG
JS::Rooted<JSObject*> rootedObj(cx, obj);
NS_ASSERTION(WrapNativeISupports(cx, parent, cache) == rootedObj,
"Unexpected object in nsWrapperCache");
obj = rootedObj;
#endif
MOZ_ASSERT(JS::ObjectIsNotGray(obj));
return obj;
}
obj = WrapNativeISupports(cx, parent, cache);
MOZ_ASSERT(JS::ObjectIsNotGray(obj));
return obj;
}
};
// Finding the associated global for an object.
template<typename T>
static inline JSObject*
FindAssociatedGlobal(JSContext* cx, T* p, nsWrapperCache* cache,
mozilla::dom::ReflectionScope scope = mozilla::dom::ReflectionScope::Content)
{
if (!p) {
return JS::CurrentGlobalOrNull(cx);
}
JSObject* obj = WrapNativeHelper<T>::Wrap(cx, p, cache);
if (!obj) {
return nullptr;
}
MOZ_ASSERT(JS::ObjectIsNotGray(obj));
// The object is never a CCW but it may not be in the current compartment of
// the JSContext.
obj = JS::GetNonCCWObjectGlobal(obj);
switch (scope) {
case mozilla::dom::ReflectionScope::XBL: {
// If scope is set to XBLScope, it means that the canonical reflector for this
// native object should live in the content XBL scope. Note that we never put
// anonymous content inside an add-on scope.
if (xpc::IsInContentXBLScope(obj)) {
return obj;
}
JS::Rooted<JSObject*> rootedObj(cx, obj);
JSObject* xblScope = xpc::GetXBLScope(cx, rootedObj);
MOZ_ASSERT_IF(xblScope, JS_IsGlobalObject(xblScope));
MOZ_ASSERT(JS::ObjectIsNotGray(xblScope));
return xblScope;
}
case mozilla::dom::ReflectionScope::UAWidget: {
// If scope is set to UAWidgetScope, it means that the canonical reflector
// for this native object should live in the UA widget scope.
if (xpc::IsInUAWidgetScope(obj)) {
return obj;
}
JS::Rooted<JSObject*> rootedObj(cx, obj);
JSObject* uaWidgetScope = xpc::GetUAWidgetScope(cx, rootedObj);
MOZ_ASSERT_IF(uaWidgetScope, JS_IsGlobalObject(uaWidgetScope));
MOZ_ASSERT(JS::ObjectIsNotGray(uaWidgetScope));
return uaWidgetScope;
}
case ReflectionScope::Content:
return obj;
}
MOZ_CRASH("Unknown ReflectionScope variant");
return nullptr;
}
// Finding of the associated global for an object, when we don't want to
// explicitly pass in things like the nsWrapperCache for it.
template<typename T>
static inline JSObject*
FindAssociatedGlobal(JSContext* cx, const T& p)
{
return FindAssociatedGlobal(cx, GetParentPointer(p), GetWrapperCache(p), GetReflectionScope(p));
}
// Specialization for the case of nsIGlobalObject, since in that case
// we can just get the JSObject* directly.
template<>
inline JSObject*
FindAssociatedGlobal(JSContext* cx, nsIGlobalObject* const& p)
{
if (!p) {
return JS::CurrentGlobalOrNull(cx);
}
JSObject* global = p->GetGlobalJSObject();
if (!global) {
// nsIGlobalObject doesn't have a JS object anymore,
// fallback to the current global.
return JS::CurrentGlobalOrNull(cx);
}
MOZ_ASSERT(JS_IsGlobalObject(global));
// This object could be gray if the nsIGlobalObject is the only thing keeping
// it alive.
JS::ExposeObjectToActiveJS(global);
return global;
}
template<typename T,
bool hasAssociatedGlobal=NativeHasMember<T>::GetParentObject>
struct FindAssociatedGlobalForNative
{
static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
{
MOZ_ASSERT(js::IsObjectInContextCompartment(obj, cx));
T* native = UnwrapDOMObject<T>(obj);
return FindAssociatedGlobal(cx, native->GetParentObject());
}
};
template<typename T>
struct FindAssociatedGlobalForNative<T, false>
{
static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
{
MOZ_CRASH();
return nullptr;
}
};
// Helper for calling GetOrCreateDOMReflector with smart pointers
// (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
struct GetOrCreateDOMReflectorHelper
{
static inline bool GetOrCreate(JSContext* cx, const T& value,
JS::Handle<JSObject*> givenProto,
JS::MutableHandle<JS::Value> rval)
{
return GetOrCreateDOMReflector(cx, value.get(), rval, givenProto);
}
};
template <class T>
struct GetOrCreateDOMReflectorHelper<T, false>
{
static inline bool GetOrCreate(JSContext* cx, T& value,
JS::Handle<JSObject*> givenProto,
JS::MutableHandle<JS::Value> rval)
{
static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
return GetOrCreateDOMReflector(cx, &value, rval, givenProto);
}
};
template<class T>
inline bool
GetOrCreateDOMReflector(JSContext* cx, T& value,
JS::MutableHandle<JS::Value> rval,
JS::Handle<JSObject*> givenProto = nullptr)
{
return GetOrCreateDOMReflectorHelper<T>::GetOrCreate(cx, value, givenProto,
rval);
}
// Helper for calling GetOrCreateDOMReflectorNoWrap with smart pointers
// (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
struct GetOrCreateDOMReflectorNoWrapHelper
{
static inline bool GetOrCreate(JSContext* cx, const T& value,
JS::MutableHandle<JS::Value> rval)
{
return GetOrCreateDOMReflectorNoWrap(cx, value.get(), rval);
}
};
template <class T>
struct GetOrCreateDOMReflectorNoWrapHelper<T, false>
{
static inline bool GetOrCreate(JSContext* cx, T& value,
JS::MutableHandle<JS::Value> rval)
{
return GetOrCreateDOMReflectorNoWrap(cx, &value, rval);
}
};
template<class T>
inline bool
GetOrCreateDOMReflectorNoWrap(JSContext* cx, T& value,
JS::MutableHandle<JS::Value> rval)
{
return
GetOrCreateDOMReflectorNoWrapHelper<T>::GetOrCreate(cx, value, rval);
}
template <class T>
inline JSObject*
GetCallbackFromCallbackObject(JSContext* aCx, T* aObj)
{
return aObj->Callback(aCx);
}
// Helper for getting the callback JSObject* of a smart ptr around a
// CallbackObject or a reference to a CallbackObject or something like
// that.
template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
struct GetCallbackFromCallbackObjectHelper
{
static inline JSObject* Get(JSContext* aCx, const T& aObj)
{
return GetCallbackFromCallbackObject(aCx, aObj.get());
}
};
template <class T>
struct GetCallbackFromCallbackObjectHelper<T, false>
{
static inline JSObject* Get(JSContext* aCx, T& aObj)
{
return GetCallbackFromCallbackObject(aCx, &aObj);
}
};
template<class T>
inline JSObject*
GetCallbackFromCallbackObject(JSContext* aCx, T& aObj)
{
return GetCallbackFromCallbackObjectHelper<T>::Get(aCx, aObj);
}
static inline bool
AtomizeAndPinJSString(JSContext* cx, jsid& id, const char* chars)
{
if (JSString *str = ::JS_AtomizeAndPinString(cx, chars)) {
id = INTERNED_STRING_TO_JSID(cx, str);
return true;
}
return false;
}
Bug 1348099 part 1 - Binary search property id when resolve DOM Xrays own property. r=bz Currently we resolve a property by iterating every prefable and check whether it is enabled. If it is, we linear search the ids that it manages. This patch changes that to binary searching to find whether the id being resolved is present first, and checking whether its prefable is enabled only when we find it. This improves the performance of property resolution, especially when the property is not present. The patch stores 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. The index array requires 2 bytes for each property, which is ~20k across all our bindings. The extra information stored in each PropertyInfo requires 4 bytes for each property, which is about 40k across all our bindings in 32-bit builds, or 80k in 64-bit builds due to alignment requirements on PropertyInfo. However we save a bit of memory from changing NativePropertiesN's trios to duos. The array of unsorted ids is kept because XrayOwnPropertyKeys() includes only properties that are enabled. Without it, we will need to check every single property to know whether its prefable is enabled or not, which is inefficient. With this patch, initializing property ids takes longer because of the sorting. I measured also insertion sort because I thought the ids should be nearly sorted as they are generated sequentially at run time, but that's not the case and NS_QuickSort() runs faster. MozReview-Commit-ID: Lc4Z1ui3t0o --HG-- extra : rebase_source : 314efe467a14428c57f90af2ecc0ec5c47a31993
2017-06-12 07:13:38 +03:00
bool
InitIds(JSContext* cx, const NativeProperties* properties);
bool
QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
template <class T>
struct
WantsQueryInterface
{
static_assert(IsBaseOf<nsISupports, T>::value,
"QueryInterface can't work without an nsISupports.");
static bool Enabled(JSContext* aCx, JSObject* aGlobal)
{
return NS_IsMainThread() && IsChromeOrXBL(aCx, aGlobal);
}
};
void
GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
nsWrapperCache* aCache, nsIJSID* aIID,
JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError);
template<class T>
void
GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID,
JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
{
GetInterfaceImpl(aCx, aThis, aThis, aIID, aRetval, aError);
}
bool
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
bool
ThrowConstructorWithoutNew(JSContext* cx, const char* name);
bool
GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
bool* found, JS::MutableHandle<JS::Value> vp);
//
bool
HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id, bool* has);
// Append the property names in "names" to "props". If
// shadowPrototypeProperties is false then skip properties that are also
// present on the proto chain of proxy. If shadowPrototypeProperties is true,
// then the "proxy" argument is ignored.
bool
AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
nsTArray<nsString>& names,
bool shadowPrototypeProperties, JS::AutoIdVector& props);
enum StringificationBehavior {
eStringify,
eEmpty,
eNull
};
template<typename T>
static inline bool
ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
StringificationBehavior nullBehavior,
StringificationBehavior undefinedBehavior,
T& result)
{
JSString *s;
if (v.isString()) {
s = v.toString();
} else {
StringificationBehavior behavior;
if (v.isNull()) {
behavior = nullBehavior;
} else if (v.isUndefined()) {
behavior = undefinedBehavior;
} else {
behavior = eStringify;
}
if (behavior != eStringify) {
if (behavior == eEmpty) {
result.Truncate();
} else {
result.SetIsVoid(true);
}
return true;
}
s = JS::ToString(cx, v);
if (!s) {
return false;
}
}
return AssignJSString(cx, result, s);
}
template<typename T>
static inline bool
ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v, T& result)
{
return ConvertJSValueToString(cx, v, eStringify, eStringify, result);
}
void
NormalizeUSVString(nsAString& aString);
void
NormalizeUSVString(binding_detail::FakeString& aString);
template<typename T>
static inline bool
ConvertJSValueToUSVString(JSContext* cx, JS::Handle<JS::Value> v, T& result)
{
if (!ConvertJSValueToString(cx, v, eStringify, eStringify, result)) {
return false;
}
NormalizeUSVString(result);
return true;
}
template<typename T>
inline bool
ConvertIdToString(JSContext* cx, JS::HandleId id, T& result, bool& isSymbol)
{
if (MOZ_LIKELY(JSID_IS_STRING(id))) {
if (!AssignJSString(cx, result, JSID_TO_STRING(id))) {
return false;
}
} else if (JSID_IS_SYMBOL(id)) {
isSymbol = true;
return true;
} else {
JS::RootedValue nameVal(cx, js::IdToValue(id));
if (!ConvertJSValueToString(cx, nameVal, eStringify, eStringify, result)) {
return false;
}
}
isSymbol = false;
return true;
}
bool
ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
bool nullable, nsACString& result);
inline bool
ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
nsACString& result)
{
return ConvertJSValueToByteString(cx, v, false, result);
}
template<typename T>
void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
template<typename T>
void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq);
// Class used to trace sequences, with specializations for various
// sequence types.
template<typename T,
bool isDictionary=IsBaseOf<DictionaryBase, T>::value,
bool isTypedArray=IsBaseOf<AllTypedArraysBase, T>::value,
bool isOwningUnion=IsBaseOf<AllOwningUnionBase, T>::value>
class SequenceTracer
{
explicit SequenceTracer() = delete; // Should never be instantiated
};
// sequence<object> or sequence<object?>
template<>
class SequenceTracer<JSObject*, false, false, false>
{
explicit SequenceTracer() = delete; // Should never be instantiated
public:
static void TraceSequence(JSTracer* trc, JSObject** objp, JSObject** end) {
for (; objp != end; ++objp) {
JS::UnsafeTraceRoot(trc, objp, "sequence<object>");
}
}
};
// sequence<any>
template<>
class SequenceTracer<JS::Value, false, false, false>
{
explicit SequenceTracer() = delete; // Should never be instantiated
public:
static void TraceSequence(JSTracer* trc, JS::Value* valp, JS::Value* end) {
for (; valp != end; ++valp) {
JS::UnsafeTraceRoot(trc, valp, "sequence<any>");
}
}
};
// sequence<sequence<T>>
template<typename T>
class SequenceTracer<Sequence<T>, false, false, false>
{
explicit SequenceTracer() = delete; // Should never be instantiated
public:
static void TraceSequence(JSTracer* trc, Sequence<T>* seqp, Sequence<T>* end) {
for (; seqp != end; ++seqp) {
DoTraceSequence(trc, *seqp);
}
}
};
// sequence<sequence<T>> as return value
template<typename T>
class SequenceTracer<nsTArray<T>, false, false, false>
{
explicit SequenceTracer() = delete; // Should never be instantiated
public:
static void TraceSequence(JSTracer* trc, nsTArray<T>* seqp, nsTArray<T>* end) {
for (; seqp != end; ++seqp) {
DoTraceSequence(trc, *seqp);
}
}
};
// sequence<someDictionary>
template<typename T>
class SequenceTracer<T, true, false, false>
{
explicit SequenceTracer() = delete; // Should never be instantiated
public:
static void TraceSequence(JSTracer* trc, T* dictp, T* end) {
for (; dictp != end; ++dictp) {
dictp->TraceDictionary(trc);
}
}
};
// sequence<SomeTypedArray>
template<typename T>
class SequenceTracer<T, false, true, false>
{
explicit SequenceTracer() = delete; // Should never be instantiated
public:
static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
for (; arrayp != end; ++arrayp) {
arrayp->TraceSelf(trc);
}
}
};
// sequence<SomeOwningUnion>
template<typename T>
class SequenceTracer<T, false, false, true>
{
explicit SequenceTracer() = delete; // Should never be instantiated
public:
static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
for (; arrayp != end; ++arrayp) {
arrayp->TraceUnion(trc);
}
}
};
// sequence<T?> with T? being a Nullable<T>
template<typename T>
class SequenceTracer<Nullable<T>, false, false, false>
{
explicit SequenceTracer() = delete; // Should never be instantiated
public:
static void TraceSequence(JSTracer* trc, Nullable<T>* seqp,
Nullable<T>* end) {
for (; seqp != end; ++seqp) {
if (!seqp->IsNull()) {
// Pretend like we actually have a length-one sequence here so
// we can do template instantiation correctly for T.
T& val = seqp->Value();
T* ptr = &val;
SequenceTracer<T>::TraceSequence(trc, ptr, ptr+1);
}
}
}
};
template<typename K, typename V>
void TraceRecord(JSTracer* trc, Record<K, V>& record)
{
for (auto& entry : record.Entries()) {
// Act like it's a one-element sequence to leverage all that infrastructure.
SequenceTracer<V>::TraceSequence(trc, &entry.mValue, &entry.mValue + 1);
}
}
// sequence<record>
template<typename K, typename V>
class SequenceTracer<Record<K, V>, false, false, false>
{
explicit SequenceTracer() = delete; // Should never be instantiated
public:
static void TraceSequence(JSTracer* trc, Record<K, V>* seqp,
Record<K, V>* end) {
for (; seqp != end; ++seqp) {
TraceRecord(trc, *seqp);
}
}
};
template<typename T>
void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq)
{
SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
seq.Elements() + seq.Length());
}
template<typename T>
void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq)
{
SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
seq.Elements() + seq.Length());
}
// Rooter class for sequences; this is what we mostly use in the codegen
template<typename T>
class MOZ_RAII SequenceRooter final : private JS::CustomAutoRooter
{
public:
SequenceRooter(JSContext *aCx, FallibleTArray<T>* aSequence
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
mFallibleArray(aSequence),
mSequenceType(eFallibleArray)
{
}
SequenceRooter(JSContext *aCx, InfallibleTArray<T>* aSequence
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
mInfallibleArray(aSequence),
mSequenceType(eInfallibleArray)
{
}
SequenceRooter(JSContext *aCx, Nullable<nsTArray<T> >* aSequence
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
mNullableArray(aSequence),
mSequenceType(eNullableArray)
{
}
private:
enum SequenceType {
eInfallibleArray,
eFallibleArray,
eNullableArray
};
virtual void trace(JSTracer *trc) override
{
if (mSequenceType == eFallibleArray) {
DoTraceSequence(trc, *mFallibleArray);
} else if (mSequenceType == eInfallibleArray) {
DoTraceSequence(trc, *mInfallibleArray);
} else {
MOZ_ASSERT(mSequenceType == eNullableArray);
if (!mNullableArray->IsNull()) {
DoTraceSequence(trc, mNullableArray->Value());
}
}
}
union {
InfallibleTArray<T>* mInfallibleArray;
FallibleTArray<T>* mFallibleArray;
Nullable<nsTArray<T> >* mNullableArray;
};
SequenceType mSequenceType;
};
// Rooter class for Record; this is what we mostly use in the codegen.
template<typename K, typename V>
class MOZ_RAII RecordRooter final : private JS::CustomAutoRooter
{
public:
RecordRooter(JSContext *aCx, Record<K, V>* aRecord
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
mRecord(aRecord),
mRecordType(eRecord)
{
}
RecordRooter(JSContext *aCx, Nullable<Record<K, V>>* aRecord
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
mNullableRecord(aRecord),
mRecordType(eNullableRecord)
{
}
private:
enum RecordType {
eRecord,
eNullableRecord
};
virtual void trace(JSTracer *trc) override
{
if (mRecordType == eRecord) {
TraceRecord(trc, *mRecord);
} else {
MOZ_ASSERT(mRecordType == eNullableRecord);
if (!mNullableRecord->IsNull()) {
TraceRecord(trc, mNullableRecord->Value());
}
}
}
union {
Record<K, V>* mRecord;
Nullable<Record<K, V>>* mNullableRecord;
};
RecordType mRecordType;
};
template<typename T>
class MOZ_RAII RootedUnion : public T,
private JS::CustomAutoRooter
{
public:
explicit RootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
T(),
JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
{
}
virtual void trace(JSTracer *trc) override
{
this->TraceUnion(trc);
}
};
template<typename T>
class MOZ_STACK_CLASS NullableRootedUnion : public Nullable<T>,
private JS::CustomAutoRooter
{
public:
explicit NullableRootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
Nullable<T>(),
JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
{
}
virtual void trace(JSTracer *trc) override
{
if (!this->IsNull()) {
this->Value().TraceUnion(trc);
}
}
};
inline bool
IdEquals(jsid id, const char* string)
{
return JSID_IS_STRING(id) &&
JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), string);
}
inline bool
AddStringToIDVector(JSContext* cx, JS::AutoIdVector& vector, const char* name)
{
return vector.growBy(1) &&
AtomizeAndPinJSString(cx, *(vector[vector.length() - 1]).address(), name);
}
// We use one constructor JSNative to represent all DOM interface objects (so
// we can easily detect when we need to wrap them in an Xray wrapper). We store
// the real JSNative in the mNative member of a JSNativeHolder in the
// CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction object for a
// specific interface object. We also store the NativeProperties in the
// JSNativeHolder.
// Note that some interface objects are not yet a JSFunction but a normal
// JSObject with a DOMJSClass, those do not use these slots.
enum {
CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT = 0
};
bool
Constructor(JSContext* cx, unsigned argc, JS::Value* vp);
// Implementation of the bits that XrayWrapper needs
/**
* This resolves operations, attributes and constants of the interfaces for obj.
*
* wrapper is the Xray JS object.
* obj is the target object of the Xray, a binding's instance object or a
* interface or interface prototype object.
*/
bool
XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj,
JS::Handle<jsid> id,
JS::MutableHandle<JS::PropertyDescriptor> desc,
bool& cacheOnHolder);
/**
* Define a property on obj through an Xray wrapper.
*
* wrapper is the Xray JS object.
* obj is the target object of the Xray, a binding's instance object or a
* interface or interface prototype object.
* id and desc are the parameters for the property to be defined.
* result is the out-parameter indicating success (read it only if
* this returns true and also sets *defined to true).
* defined will be set to true if a property was set as a result of this call.
*/
bool
XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
JS::Handle<JS::PropertyDescriptor> desc,
JS::ObjectOpResult &result,
bool *defined);
/**
* Add to props the property keys of all indexed or named properties of obj and
* operations, attributes and constants of the interfaces for obj.
*
* wrapper is the Xray JS object.
* obj is the target object of the Xray, a binding's instance object or a
* interface or interface prototype object.
* flags are JSITER_* flags.
*/
bool
XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj,
unsigned flags, JS::AutoIdVector& props);
/**
* Returns the prototype to use for an Xray for a DOM object, wrapped in cx's
* compartment. This always returns the prototype that would be used for a DOM
* object if we ignore any changes that might have been done to the prototype
* chain by JS, the XBL code or plugins.
*
* cx should be in the Xray's compartment.
* obj is the target object of the Xray, a binding's instance object or an
* interface or interface prototype object.
*/
inline bool
XrayGetNativeProto(JSContext* cx, JS::Handle<JSObject*> obj,
JS::MutableHandle<JSObject*> protop)
{
JS::Rooted<JSObject*> global(cx, JS::GetNonCCWObjectGlobal(obj));
{
JSAutoRealm ar(cx, global);
const DOMJSClass* domClass = GetDOMClass(obj);
if (domClass) {
ProtoHandleGetter protoGetter = domClass->mGetProto;
if (protoGetter) {
protop.set(protoGetter(cx));
} else {
protop.set(JS::GetRealmObjectPrototype(cx));
}
} else if (JS_ObjectIsFunction(cx, obj)) {
MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
protop.set(JS::GetRealmFunctionPrototype(cx));
} else {
const js::Class* clasp = js::GetObjectClass(obj);
MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
ProtoGetter protoGetter =
DOMIfaceAndProtoJSClass::FromJSClass(clasp)->mGetParentProto;
protop.set(protoGetter(cx));
}
}
return JS_WrapObject(cx, protop);
}
/**
* Get the Xray expando class to use for the given DOM object.
*/
const JSClass*
XrayGetExpandoClass(JSContext* cx, JS::Handle<JSObject*> obj);
/**
* Delete a named property, if any. Return value is false if exception thrown,
* true otherwise. The caller should not do any more work after calling this
* function, because it has no way whether a deletion was performed and hence
* opresult already has state set on it. If callers ever need to change that,
* add a "bool* found" argument and change the generated DeleteNamedProperty to
* use it instead of a local variable.
*/
bool
XrayDeleteNamedProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
JS::ObjectOpResult& opresult);
/**
* Get the object which should be used to cache the return value of a property
* getter in the case of a [Cached] or [StoreInSlot] property. `obj` is the
* `this` value for our property getter that we're working with.
*
* This function can return null on failure to allocate the object, throwing on
* the JSContext in the process.
*
* The isXray outparam will be set to true if obj is an Xray and false
* otherwise.
*
* Note that the Slow version should only be called from
* GetCachedSlotStorageObject.
*/
JSObject*
GetCachedSlotStorageObjectSlow(JSContext* cx, JS::Handle<JSObject*> obj,
bool* isXray);
inline JSObject*
GetCachedSlotStorageObject(JSContext* cx, JS::Handle<JSObject*> obj,
bool* isXray) {
if (IsDOMObject(obj)) {
*isXray = false;
return obj;
}
return GetCachedSlotStorageObjectSlow(cx, obj, isXray);
}
extern NativePropertyHooks sEmptyNativePropertyHooks;
extern const js::ClassOps sBoringInterfaceObjectClassClassOps;
extern const js::ObjectOps sInterfaceObjectClassObjectOps;
inline bool
UseDOMXray(JSObject* obj)
{
const js::Class* clasp = js::GetObjectClass(obj);
return IsDOMClass(clasp) ||
JS_IsNativeFunction(obj, Constructor) ||
IsDOMIfaceAndProtoClass(clasp);
}
inline bool
IsDOMConstructor(JSObject* obj)
{
if (JS_IsNativeFunction(obj, dom::Constructor)) {
// NamedConstructor, like Image
return true;
}
const js::Class* clasp = js::GetObjectClass(obj);
// Check for a DOM interface object.
return dom::IsDOMIfaceAndProtoClass(clasp) &&
dom::DOMIfaceAndProtoJSClass::FromJSClass(clasp)->mType == dom::eInterface;
}
#ifdef DEBUG
inline bool
HasConstructor(JSObject* obj)
{
return JS_IsNativeFunction(obj, Constructor) ||
js::GetObjectClass(obj)->getConstruct();
}
#endif
// Helpers for creating a const version of a type.
template<typename T>
const T& Constify(T& arg)
{
return arg;
}
// Helper for turning (Owning)NonNull<T> into T&
template<typename T>
T& NonNullHelper(T& aArg)
{
return aArg;
}
template<typename T>
T& NonNullHelper(NonNull<T>& aArg)
{
return aArg;
}
template<typename T>
const T& NonNullHelper(const NonNull<T>& aArg)
{
return aArg;
}
template<typename T>
T& NonNullHelper(OwningNonNull<T>& aArg)
{
return aArg;
}
template<typename T>
const T& NonNullHelper(const OwningNonNull<T>& aArg)
{
return aArg;
}
inline
void NonNullHelper(NonNull<binding_detail::FakeString>& aArg)
{
// This overload is here to make sure that we never end up applying
// NonNullHelper to a NonNull<binding_detail::FakeString>. If we
// try to, it should fail to compile, since presumably the caller will try to
// use our nonexistent return value.
}
inline
void NonNullHelper(const NonNull<binding_detail::FakeString>& aArg)
{
// This overload is here to make sure that we never end up applying
// NonNullHelper to a NonNull<binding_detail::FakeString>. If we
// try to, it should fail to compile, since presumably the caller will try to
// use our nonexistent return value.
}
inline
void NonNullHelper(binding_detail::FakeString& aArg)
{
// This overload is here to make sure that we never end up applying
// NonNullHelper to a FakeString before we've constified it. If we
// try to, it should fail to compile, since presumably the caller will try to
// use our nonexistent return value.
}
MOZ_ALWAYS_INLINE
const nsAString& NonNullHelper(const binding_detail::FakeString& aArg)
{
return aArg;
}
// Reparent the wrapper of aObj to whatever its native now thinks its
// parent should be.
void
ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObj, ErrorResult& aError);
/**
* Used to implement the Symbol.hasInstance property of an interface object.
*/
bool
InterfaceHasInstance(JSContext* cx, unsigned argc, JS::Value* vp);
bool
InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
JS::Handle<JSObject*> instance,
bool* bp);
// Used to implement the cross-context <Interface>.isInstance static method.
bool
InterfaceIsInstance(JSContext* cx, unsigned argc, JS::Value* vp);
// Helper for lenient getters/setters to report to console. If this
// returns false, we couldn't even get a global.
bool
ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj);
// Given a JSObject* that represents the chrome side of a JS-implemented WebIDL
// interface, get the nsIGlobalObject corresponding to the content side, if any.
// A false return means an exception was thrown.
bool
GetContentGlobalForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
nsIGlobalObject** global);
void
ConstructJSImplementation(const char* aContractId,
nsIGlobalObject* aGlobal,
JS::MutableHandle<JSObject*> aObject,
ErrorResult& aRv);
already_AddRefed<nsIGlobalObject>
ConstructJSImplementation(const char* aContractId,
const GlobalObject& aGlobal,
JS::MutableHandle<JSObject*> aObject,
ErrorResult& aRv);
/**
* Convert an nsCString to jsval, returning true on success.
* These functions are intended for ByteString implementations.
* As such, the string is not UTF-8 encoded. Any UTF8 strings passed to these
* methods will be mangled.
*/
bool NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
JS::MutableHandle<JS::Value> rval);
inline bool ByteStringToJsval(JSContext *cx, const nsACString &str,
JS::MutableHandle<JS::Value> rval)
{
if (str.IsVoid()) {
rval.setNull();
return true;
}
return NonVoidByteStringToJsval(cx, str, rval);
}
template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
struct PreserveWrapperHelper
{
static void PreserveWrapper(T* aObject)
{
aObject->PreserveWrapper(aObject, NS_CYCLE_COLLECTION_PARTICIPANT(T));
}
};
template<class T>
struct PreserveWrapperHelper<T, true>
{
static void PreserveWrapper(T* aObject)
{
aObject->PreserveWrapper(reinterpret_cast<nsISupports*>(aObject));
}
};
template<class T>
void PreserveWrapper(T* aObject)
{
PreserveWrapperHelper<T>::PreserveWrapper(aObject);
}
template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
struct CastingAssertions
{
static bool ToSupportsIsCorrect(T*)
{
return true;
}
static bool ToSupportsIsOnPrimaryInheritanceChain(T*, nsWrapperCache*)
{
return true;
}
};
template<class T>
struct CastingAssertions<T, true>
{
static bool ToSupportsIsCorrect(T* aObject)
{
return ToSupports(aObject) == reinterpret_cast<nsISupports*>(aObject);
}
static bool ToSupportsIsOnPrimaryInheritanceChain(T* aObject,
nsWrapperCache* aCache)
{
return reinterpret_cast<void*>(aObject) != aCache;
}
};
template<class T>
bool
ToSupportsIsCorrect(T* aObject)
{
return CastingAssertions<T>::ToSupportsIsCorrect(aObject);
}
template<class T>
bool
ToSupportsIsOnPrimaryInheritanceChain(T* aObject, nsWrapperCache* aCache)
{
return CastingAssertions<T>::ToSupportsIsOnPrimaryInheritanceChain(aObject,
aCache);
}
// Get the size of allocated memory to associate with a binding JSObject for a
// native object. This is supplied to the JS engine to allow it to schedule GC
// when necessary.
//
// This function supplies a default value and is overloaded for specific native
// object types.
inline size_t
BindingJSObjectMallocBytes(void *aNativePtr)
{
return 0;
}
// Register a thing which DeferredFinalize might be called on during GC
// finalization. See DeferredFinalize.h
template<class T>
static void
RecordReplayRegisterDeferredFinalize(T* aObject);
// The BindingJSObjectCreator class is supposed to be used by a caller that
// wants to create and initialise a binding JSObject. After initialisation has
// been successfully completed it should call ForgetObject().
// The BindingJSObjectCreator object will root the JSObject until ForgetObject()
// is called on it. If the native object for the binding is refcounted it will
// also hold a strong reference to it, that reference is transferred to the
// JSObject (which holds the native in a slot) when ForgetObject() is called. If
// the BindingJSObjectCreator object is destroyed and ForgetObject() was never
// called on it then the JSObject's slot holding the native will be set to
// undefined, and for a refcounted native the strong reference will be released.
template<class T>
class MOZ_STACK_CLASS BindingJSObjectCreator
{
public:
explicit BindingJSObjectCreator(JSContext* aCx)
: mReflector(aCx)
{
}
~BindingJSObjectCreator()
{
if (mReflector) {
js::SetReservedSlot(mReflector, DOM_OBJECT_SLOT, JS::UndefinedValue());
}
}
void
CreateProxyObject(JSContext* aCx, const js::Class* aClass,
const DOMProxyHandler* aHandler,
JS::Handle<JSObject*> aProto, T* aNative,
JS::Handle<JS::Value> aExpandoValue,
JS::MutableHandle<JSObject*> aReflector)
{
js::ProxyOptions options;
options.setClass(aClass);
aReflector.set(js::NewProxyObject(aCx, aHandler, aExpandoValue, aProto,
options));
if (aReflector) {
js::SetProxyReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
mNative = aNative;
mReflector = aReflector;
RecordReplayRegisterDeferredFinalize<T>(aNative);
}
if (size_t mallocBytes = BindingJSObjectMallocBytes(aNative)) {
JS_updateMallocCounter(aCx, mallocBytes);
}
}
void
CreateObject(JSContext* aCx, const JSClass* aClass,
JS::Handle<JSObject*> aProto,
T* aNative, JS::MutableHandle<JSObject*> aReflector)
{
aReflector.set(JS_NewObjectWithGivenProto(aCx, aClass, aProto));
if (aReflector) {
js::SetReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
mNative = aNative;
mReflector = aReflector;
RecordReplayRegisterDeferredFinalize<T>(aNative);
}
if (size_t mallocBytes = BindingJSObjectMallocBytes(aNative)) {
JS_updateMallocCounter(aCx, mallocBytes);
}
}
void
InitializationSucceeded()
{
void* dummy;
mNative.forget(&dummy);
mReflector = nullptr;
}
private:
struct OwnedNative
{
// Make sure the native objects inherit from NonRefcountedDOMObject so
// that we log their ctor and dtor.
static_assert(IsBaseOf<NonRefcountedDOMObject, T>::value,
"Non-refcounted objects with DOM bindings should inherit "
"from NonRefcountedDOMObject.");
OwnedNative&
operator=(T* aNative)
{
return *this;
}
// This signature sucks, but it's the only one that will make a nsRefPtr
// just forget about its pointer without warning.
void
forget(void**)
{
}
};
JS::Rooted<JSObject*> mReflector;
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
typename Conditional<IsRefcounted<T>::value, RefPtr<T>, OwnedNative>::Type mNative;
};
template<class T>
struct DeferredFinalizerImpl
{
typedef typename Conditional<IsSame<T, nsISupports>::value,
nsCOMPtr<T>,
typename Conditional<IsRefcounted<T>::value,
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
RefPtr<T>,
nsAutoPtr<T>>::Type>::Type SmartPtr;
typedef SegmentedVector<SmartPtr> SmartPtrArray;
static_assert(IsSame<T, nsISupports>::value || !IsBaseOf<nsISupports, T>::value,
"nsISupports classes should all use the nsISupports instantiation");
static inline void
AppendAndTake(SegmentedVector<nsCOMPtr<nsISupports>>& smartPtrArray, nsISupports* ptr)
{
smartPtrArray.InfallibleAppend(dont_AddRef(ptr));
}
template<class U>
static inline void
AppendAndTake(SegmentedVector<RefPtr<U>>& smartPtrArray, U* ptr)
{
smartPtrArray.InfallibleAppend(dont_AddRef(ptr));
}
template<class U>
static inline void
AppendAndTake(SegmentedVector<nsAutoPtr<U>>& smartPtrArray, U* ptr)
{
smartPtrArray.InfallibleAppend(ptr);
}
static void*
AppendDeferredFinalizePointer(void* aData, void* aObject)
{
SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
if (!pointers) {
pointers = new SmartPtrArray();
}
AppendAndTake(*pointers, static_cast<T*>(aObject));
return pointers;
}
static bool
DeferredFinalize(uint32_t aSlice, void* aData)
{
MOZ_ASSERT(aSlice > 0, "nonsensical/useless call with aSlice == 0");
SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
uint32_t oldLen = pointers->Length();
if (oldLen < aSlice) {
aSlice = oldLen;
}
uint32_t newLen = oldLen - aSlice;
pointers->PopLastN(aSlice);
if (newLen == 0) {
delete pointers;
return true;
}
return false;
}
};
template<class T,
bool isISupports=IsBaseOf<nsISupports, T>::value>
struct DeferredFinalizer
{
static void
AddForDeferredFinalization(T* aObject)
{
typedef DeferredFinalizerImpl<T> Impl;
DeferredFinalize(Impl::AppendDeferredFinalizePointer,
Impl::DeferredFinalize, aObject);
}
static void
RecordReplayRegisterDeferredFinalize(T* aObject)
{
typedef DeferredFinalizerImpl<T> Impl;
RecordReplayRegisterDeferredFinalizeThing(Impl::AppendDeferredFinalizePointer,
Impl::DeferredFinalize,
aObject);
}
};
template<class T>
struct DeferredFinalizer<T, true>
{
static void
AddForDeferredFinalization(T* aObject)
{
DeferredFinalize(reinterpret_cast<nsISupports*>(aObject));
}
static void
RecordReplayRegisterDeferredFinalize(T* aObject)
{
RecordReplayRegisterDeferredFinalizeThing(nullptr, nullptr, aObject);
}
};
template<class T>
static void
AddForDeferredFinalization(T* aObject)
{
DeferredFinalizer<T>::AddForDeferredFinalization(aObject);
}
template<class T>
static void
RecordReplayRegisterDeferredFinalize(T* aObject)
{
DeferredFinalizer<T>::RecordReplayRegisterDeferredFinalize(aObject);
}
// This returns T's CC participant if it participates in CC or null if it
// doesn't. This also returns null for classes that don't inherit from
// nsISupports (QI should be used to get the participant for those).
template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
class GetCCParticipant
{
// Helper for GetCCParticipant for classes that participate in CC.
template<class U>
static constexpr nsCycleCollectionParticipant*
GetHelper(int, typename U::NS_CYCLE_COLLECTION_INNERCLASS* dummy=nullptr)
{
return T::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant();
}
// Helper for GetCCParticipant for classes that don't participate in CC.
template<class U>
static constexpr nsCycleCollectionParticipant*
GetHelper(double)
{
return nullptr;
}
public:
static constexpr nsCycleCollectionParticipant*
Get()
{
// Passing int() here will try to call the GetHelper that takes an int as
// its firt argument. If T doesn't participate in CC then substitution for
// the second argument (with a default value) will fail and because of
// SFINAE the next best match (the variant taking a double) will be called.
return GetHelper<T>(int());
}
};
template<class T>
class GetCCParticipant<T, true>
{
public:
static constexpr nsCycleCollectionParticipant*
Get()
{
return nullptr;
}
};
void
FinalizeGlobal(JSFreeOp* aFop, JSObject* aObj);
bool
ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
JS::Handle<jsid> aId, bool* aResolvedp);
bool
MayResolveGlobal(const JSAtomState& aNames, jsid aId, JSObject* aMaybeObj);
bool
EnumerateGlobal(JSContext* aCx, JS::HandleObject aObj,
JS::AutoIdVector& aProperties, bool aEnumerableOnly);
struct CreateGlobalOptionsGeneric
{
static void TraceGlobal(JSTracer* aTrc, JSObject* aObj)
{
mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
}
static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
{
MOZ_ALWAYS_TRUE(TryPreserveWrapper(aGlobal));
return true;
}
};
struct CreateGlobalOptionsWithXPConnect
{
static void TraceGlobal(JSTracer* aTrc, JSObject* aObj);
static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
};
template <class T>
using IsGlobalWithXPConnect =
IntegralConstant<bool,
IsBaseOf<nsGlobalWindowInner, T>::value ||
IsBaseOf<MessageManagerGlobal, T>::value>;
template <class T>
struct CreateGlobalOptions
: Conditional<IsGlobalWithXPConnect<T>::value,
CreateGlobalOptionsWithXPConnect,
CreateGlobalOptionsGeneric>::Type
{
static constexpr ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
ProtoAndIfaceCache::NonWindowLike;
};
template <>
struct CreateGlobalOptions<nsGlobalWindowInner>
: public CreateGlobalOptionsWithXPConnect
{
static constexpr ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
ProtoAndIfaceCache::WindowLike;
static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
};
// The return value is true if we created and successfully performed our part of
// the setup for the global, false otherwise.
//
// Typically this method's caller will want to ensure that
// xpc::InitGlobalObjectOptions is called before, and xpc::InitGlobalObject is
// called after, this method, to ensure that this global object and its
// compartment are consistent with other global objects.
template <class T, ProtoHandleGetter GetProto>
bool
CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
const JSClass* aClass, JS::RealmOptions& aOptions,
JSPrincipals* aPrincipal, bool aInitStandardClasses,
JS::MutableHandle<JSObject*> aGlobal)
{
aOptions.creationOptions().setTrace(CreateGlobalOptions<T>::TraceGlobal);
if (xpc::SharedMemoryEnabled()) {
aOptions.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
}
aGlobal.set(JS_NewGlobalObject(aCx, aClass, aPrincipal,
JS::DontFireOnNewGlobalHook, aOptions));
if (!aGlobal) {
NS_WARNING("Failed to create global");
return false;
}
JSAutoRealm ar(aCx, aGlobal);
{
js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
NS_ADDREF(aNative);
aCache->SetWrapper(aGlobal);
RecordReplayRegisterDeferredFinalize<T>(aNative);
dom::AllocateProtoAndIfaceCache(aGlobal,
CreateGlobalOptions<T>::ProtoAndIfaceCacheKind);
if (!CreateGlobalOptions<T>::PostCreateGlobal(aCx, aGlobal)) {
return false;
}
}
if (aInitStandardClasses && !JS::InitRealmStandardClasses(aCx)) {
NS_WARNING("Failed to init standard classes");
return false;
}
JS::Handle<JSObject*> proto = GetProto(aCx);
if (!proto || !JS_SplicePrototype(aCx, aGlobal, proto)) {
NS_WARNING("Failed to set proto");
return false;
}
bool succeeded;
if (!JS_SetImmutablePrototype(aCx, aGlobal, &succeeded)) {
return false;
}
MOZ_ASSERT(succeeded,
"making a fresh global object's [[Prototype]] immutable can "
"internally fail, but it should never be unsuccessful");
return true;
}
/*
* Holds a jsid that is initialized to a pinned string, with automatic
* conversion to Handle<jsid>, as it is held live forever by pinning.
*/
class PinnedStringId
{
jsid id;
public:
constexpr PinnedStringId() : id(JSID_VOID) {}
bool init(JSContext *cx, const char *string) {
JSString* str = JS_AtomizeAndPinString(cx, string);
if (!str)
return false;
id = INTERNED_STRING_TO_JSID(cx, str);
return true;
}
operator const jsid& () const {
return id;
}
operator JS::Handle<jsid> () const {
/* This is safe because we have pinned the string. */
return JS::Handle<jsid>::fromMarkedLocation(&id);
}
} JS_HAZ_ROOTED;
namespace binding_detail {
/**
* WebIDL getters have a "generic" JSNative that is responsible for the
* following things:
*
* 1) Determining the "this" pointer for the C++ call.
* 2) Extracting the "specialized" getter from the jitinfo on the JSFunction.
* 3) Calling the specialized getter.
* 4) Handling exceptions as needed.
*
* There are several variants of (1) depending on the interface involved and
* there are two variants of (4) depending on whether the return type is a
* Promise. We handle this by templating our generic getter on a
* this-determination policy and an exception handling policy, then explicitly
* instantiating the relevant template specializations.
*/
template<typename ThisPolicy, typename ExceptionPolicy>
bool
GenericGetter(JSContext* cx, unsigned argc, JS::Value* vp);
/**
* WebIDL setters have a "generic" JSNative that is responsible for the
* following things:
*
* 1) Determining the "this" pointer for the C++ call.
* 2) Extracting the "specialized" setter from the jitinfo on the JSFunction.
* 3) Calling the specialized setter.
*
* There are several variants of (1) depending on the interface
* involved. We handle this by templating our generic setter on a
* this-determination policy, then explicitly instantiating the
* relevant template specializations.
*/
template<typename ThisPolicy>
bool
GenericSetter(JSContext* cx, unsigned argc, JS::Value* vp);
/**
* WebIDL methods have a "generic" JSNative that is responsible for the
* following things:
*
* 1) Determining the "this" pointer for the C++ call.
* 2) Extracting the "specialized" method from the jitinfo on the JSFunction.
* 3) Calling the specialized methodx.
* 4) Handling exceptions as needed.
*
* There are several variants of (1) depending on the interface involved and
* there are two variants of (4) depending on whether the return type is a
* Promise. We handle this by templating our generic method on a
* this-determination policy and an exception handling policy, then explicitly
* instantiating the relevant template specializations.
*/
template<typename ThisPolicy, typename ExceptionPolicy>
bool
GenericMethod(JSContext* cx, unsigned argc, JS::Value* vp);
// A this-extraction policy for normal getters/setters/methods.
struct NormalThisPolicy;
// A this-extraction policy for getters/setters/methods on interfaces
// that are on some global's proto chain.
struct MaybeGlobalThisPolicy;
// A this-extraction policy for lenient getters/setters.
struct LenientThisPolicy;
// A this-extraction policy for cross-origin getters/setters/methods.
struct CrossOriginThisPolicy;
// An exception-reporting policy for normal getters/setters/methods.
struct ThrowExceptions;
// An exception-handling policy for Promise-returning getters/methods.
struct ConvertExceptionsToPromises;
} // namespace binding_detail
bool
StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp);
// ConvertExceptionToPromise should only be called when we have an error
// condition (e.g. returned false from a JSAPI method). Note that there may be
// no exception on cx, in which case this is an uncatchable failure that will
// simply be propagated. Otherwise this method will attempt to convert the
// exception to a Promise rejected with the exception that it will store in
// rval.
bool
ConvertExceptionToPromise(JSContext* cx,
JS::MutableHandle<JS::Value> rval);
#ifdef DEBUG
void
AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo,
JS::Handle<JS::Value> aValue);
#endif
bool
CallerSubsumes(JSObject* aObject);
MOZ_ALWAYS_INLINE bool
CallerSubsumes(JS::Handle<JS::Value> aValue)
{
if (!aValue.isObject()) {
return true;
}
return CallerSubsumes(&aValue.toObject());
}
template<class T, class S>
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
inline RefPtr<T>
StrongOrRawPtr(already_AddRefed<S>&& aPtr)
{
return std::move(aPtr);
}
template<class T,
class ReturnType=typename Conditional<IsRefcounted<T>::value, T*,
nsAutoPtr<T>>::Type>
inline ReturnType
StrongOrRawPtr(T* aPtr)
{
return ReturnType(aPtr);
}
template<class T, template<typename> class SmartPtr, class S>
inline void
StrongOrRawPtr(SmartPtr<S>&& aPtr) = delete;
template<class T>
struct StrongPtrForMember
{
typedef typename Conditional<IsRefcounted<T>::value,
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
RefPtr<T>, nsAutoPtr<T>>::Type Type;
};
namespace binding_detail {
inline
JSObject*
GetHackedNamespaceProtoObject(JSContext* aCx)
{
return JS_NewPlainObject(aCx);
}
} // namespace binding_detail
// Resolve an id on the given global object that wants to be included in
// Exposed=System webidl annotations. False return value means exception
// thrown.
bool SystemGlobalResolve(JSContext* cx, JS::Handle<JSObject*> obj,
JS::Handle<jsid> id, bool* resolvedp);
// Enumerate all ids on the given global object that wants to be included in
// Exposed=System webidl annotations. False return value means exception
// thrown.
bool SystemGlobalEnumerate(JSContext* cx, JS::Handle<JSObject*> obj);
// Slot indexes for maplike/setlike forEach functions
#define FOREACH_CALLBACK_SLOT 0
#define FOREACH_MAPLIKEORSETLIKEOBJ_SLOT 1
// Backing function for running .forEach() on maplike/setlike interfaces.
// Unpacks callback and maplike/setlike object from reserved slots, then runs
// callback for each key (and value, for maplikes)
bool ForEachHandler(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
// Unpacks backing object (ES6 map/set) from the reserved slot of a reflector
// for a maplike/setlike interface. If backing object does not exist, creates
// backing object in the compartment of the reflector involved, making this safe
// to use across compartments/via xrays. Return values of these methods will
// always be in the context compartment.
bool GetMaplikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
size_t aSlotIndex,
JS::MutableHandle<JSObject*> aBackingObj,
bool* aBackingObjCreated);
bool GetSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
size_t aSlotIndex,
JS::MutableHandle<JSObject*> aBackingObj,
bool* aBackingObjCreated);
// Get the desired prototype object for an object construction from the given
// CallArgs. Null is returned if the default prototype should be used.
bool
GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
JS::MutableHandle<JSObject*> aDesiredProto);
// This function is expected to be called from the constructor function for an
// HTML or XUL element interface; the global/callargs need to be whatever was
// passed to that constructor function.
already_AddRefed<Element>
CreateXULOrHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv);
void
SetDocumentAndPageUseCounter(JSObject* aObject, UseCounter aUseCounter);
// Warnings
void
DeprecationWarning(JSContext* aCx, JSObject* aObject,
nsIDocument::DeprecatedOperations aOperation);
void
DeprecationWarning(const GlobalObject& aGlobal,
nsIDocument::DeprecatedOperations aOperation);
// A callback to perform funToString on an interface object
JSString*
InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
unsigned /* indent */);
namespace binding_detail {
// Get a JS global object that can be used for some temporary allocations. The
// idea is that this should be used for situations when you need to operate in
// _some_ compartment but don't care which one. A typical example is when you
// have non-JS input, non-JS output, but have to go through some sort of JS
// representation in the middle, so need a compartment to allocate things in.
//
// It's VERY important that any consumers of this function only do things that
// are guaranteed to be side-effect-free, even in the face of a script
// environment controlled by a hostile adversary. This is because in the worker
// case the global is in fact the worker global, so it and its standard objects
// are controlled by the worker script. This is why this function is in the
// binding_detail namespace. Any use of this function MUST be very carefully
// reviewed by someone who is sufficiently devious and has a very good
// understanding of all the code that will run while we're using the return
// value, including the SpiderMonkey parts.
JSObject* UnprivilegedJunkScopeOrWorkerGlobal();
// Implementation of the [HTMLConstructor] extended attribute.
bool
HTMLConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
constructors::id::ID aConstructorId,
prototypes::id::ID aProtoId,
CreateInterfaceObjectsMethod aCreator);
// A method to test whether an attribute with the given JSJitGetterOp getter is
// enabled in the given set of prefable proeprty specs. For use for toJSON
// conversions. aObj is the object that would be used as the "this" value.
bool
IsGetterEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj,
JSJitGetterOp aGetter,
const Prefable<const JSPropertySpec>* aAttributes);
} // namespace binding_detail
} // namespace dom
} // namespace mozilla
Bug 742217. Reduce the use of nested namespaces in our binding code. r=peterv,bent In the new setup, all per-interface DOM binding files are exported into mozilla/dom. General files not specific to an interface are also exported into mozilla/dom. In terms of namespaces, most things now live in mozilla::dom. Each interface Foo that has generated code has a mozilla::dom::FooBinding namespace for said generated code (and possibly a mozilla::bindings::FooBinding_workers if there's separate codegen for workers). IDL enums are a bit weird: since the name of the enum and the names of its entries all end up in the same namespace, we still generate a C++ namespace with the name of the IDL enum type with "Values" appended to it, with a ::valuelist inside for the actual C++ enum. We then typedef EnumFooValues::valuelist to EnumFoo. That makes it a bit more difficult to refer to the values, but means that values from different enums don't collide with each other. The enums with the proto and constructor IDs in them now live under the mozilla::dom::prototypes and mozilla::dom::constructors namespaces respectively. Again, this lets us deal sanely with the whole "enum value names are flattened into the namespace the enum is in" deal. The main benefit of this setup (and the reason "Binding" got appended to the per-interface namespaces) is that this way "using mozilla::dom" should Just Work for consumers and still allow C++ code to sanely use the IDL interface names for concrete classes, which is fairly desirable. --HG-- rename : dom/bindings/Utils.cpp => dom/bindings/BindingUtils.cpp rename : dom/bindings/Utils.h => dom/bindings/BindingUtils.h
2012-05-03 08:35:38 +04:00
#endif /* mozilla_dom_BindingUtils_h__ */