2015-05-03 22:32:37 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-03-31 08:42:20 +04:00
|
|
|
/* 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/. */
|
|
|
|
|
2012-05-03 08:35:38 +04:00
|
|
|
#ifndef mozilla_dom_BindingUtils_h__
|
|
|
|
#define mozilla_dom_BindingUtils_h__
|
2012-03-31 08:42:20 +04:00
|
|
|
|
2013-07-24 11:31:06 +04:00
|
|
|
#include "jsfriendapi.h"
|
2018-09-05 12:25:42 +03:00
|
|
|
#include "js/CharacterEncoding.h"
|
2018-02-21 19:30:19 +03:00
|
|
|
#include "js/Wrapper.h"
|
2014-12-18 00:50:20 +03:00
|
|
|
#include "js/Conversions.h"
|
2013-12-09 06:52:54 +04:00
|
|
|
#include "mozilla/ArrayUtils.h"
|
2013-08-14 11:00:52 +04:00
|
|
|
#include "mozilla/Alignment.h"
|
2013-11-19 23:28:09 +04:00
|
|
|
#include "mozilla/Array.h"
|
2014-01-23 13:18:35 +04:00
|
|
|
#include "mozilla/Assertions.h"
|
2015-03-18 21:36:03 +03:00
|
|
|
#include "mozilla/DeferredFinalize.h"
|
2013-07-24 11:31:06 +04:00
|
|
|
#include "mozilla/dom/BindingDeclarations.h"
|
|
|
|
#include "mozilla/dom/CallbackObject.h"
|
2012-05-03 08:35:38 +04:00
|
|
|
#include "mozilla/dom/DOMJSClass.h"
|
2012-05-22 17:46:20 +04:00
|
|
|
#include "mozilla/dom/DOMJSProxyHandler.h"
|
2013-09-09 07:29:21 +04:00
|
|
|
#include "mozilla/dom/Exceptions.h"
|
2012-09-19 17:02:37 +04:00
|
|
|
#include "mozilla/dom/NonRefcountedDOMObject.h"
|
2013-07-24 11:31:06 +04:00
|
|
|
#include "mozilla/dom/Nullable.h"
|
2018-03-27 22:49:02 +03:00
|
|
|
#include "mozilla/dom/PrototypeList.h"
|
2013-09-26 08:04:59 +04:00
|
|
|
#include "mozilla/dom/RootedDictionary.h"
|
2016-03-04 20:06:06 +03:00
|
|
|
#include "mozilla/SegmentedVector.h"
|
2012-05-06 05:15:11 +04:00
|
|
|
#include "mozilla/ErrorResult.h"
|
2013-07-24 11:31:06 +04:00
|
|
|
#include "mozilla/Likely.h"
|
2013-11-20 17:55:09 +04:00
|
|
|
#include "mozilla/MemoryReporting.h"
|
2016-06-07 23:10:18 +03:00
|
|
|
#include "nsAutoPtr.h"
|
2015-09-28 21:25:04 +03:00
|
|
|
#include "nsIDocument.h"
|
2015-02-23 18:03:40 +03:00
|
|
|
#include "nsIGlobalObject.h"
|
2012-05-18 12:29:40 +04:00
|
|
|
#include "nsIXPConnect.h"
|
2014-07-05 19:30:54 +04:00
|
|
|
#include "nsJSUtils.h"
|
2014-02-27 01:36:35 +04:00
|
|
|
#include "nsISupportsImpl.h"
|
2018-05-02 12:47:02 +03:00
|
|
|
#include "xpcObjectHelper.h"
|
2012-05-18 12:29:40 +04:00
|
|
|
#include "xpcpublic.h"
|
2013-09-06 21:50:24 +04:00
|
|
|
#include "nsIVariant.h"
|
2016-09-01 13:10:54 +03:00
|
|
|
#include "mozilla/dom/FakeString.h"
|
2013-07-24 11:31:06 +04:00
|
|
|
|
2012-03-31 08:42:20 +04:00
|
|
|
#include "nsWrapperCacheInlines.h"
|
|
|
|
|
2016-11-17 18:31:50 +03:00
|
|
|
class nsGenericHTMLElement;
|
2014-02-16 01:12:33 +04:00
|
|
|
class nsIJSID;
|
2018-09-18 05:31:03 +03:00
|
|
|
class nsIDocument;
|
2013-05-20 21:47:08 +04:00
|
|
|
|
2012-03-31 08:42:20 +04:00
|
|
|
namespace mozilla {
|
2015-02-05 20:53:01 +03:00
|
|
|
|
|
|
|
enum UseCounter : int16_t;
|
|
|
|
|
2012-03-31 08:42:20 +04:00
|
|
|
namespace dom {
|
2017-03-08 12:11:48 +03:00
|
|
|
class CustomElementReactionsStack;
|
2017-07-19 15:59:02 +03:00
|
|
|
class MessageManagerGlobal;
|
2017-02-15 08:01:35 +03:00
|
|
|
template<typename KeyType, typename ValueType> class Record;
|
2018-09-18 05:31:03 +03:00
|
|
|
class Location;
|
2012-03-31 08:42:20 +04:00
|
|
|
|
2014-10-23 23:21:46 +04:00
|
|
|
nsresult
|
2017-02-01 23:43:37 +03:00
|
|
|
UnwrapArgImpl(JSContext* cx, JS::Handle<JSObject*> src, const nsIID& iid,
|
|
|
|
void** ppArg);
|
2014-10-23 23:21:46 +04:00
|
|
|
|
2016-01-30 20:05:36 +03:00
|
|
|
nsresult
|
2017-02-01 23:43:37 +03:00
|
|
|
UnwrapWindowProxyImpl(JSContext* cx, JS::Handle<JSObject*> src,
|
|
|
|
nsPIDOMWindowOuter** ppArg);
|
2016-01-30 20:05:36 +03:00
|
|
|
|
2017-07-10 23:05:25 +03:00
|
|
|
/** Convert a jsval to an XPCOM pointer. Caller must not assume that src will
|
|
|
|
keep the XPCOM pointer rooted. */
|
2014-10-22 19:40:51 +04:00
|
|
|
template <class Interface>
|
2013-05-30 07:15:31 +04:00
|
|
|
inline nsresult
|
2017-02-01 23:43:37 +03:00
|
|
|
UnwrapArg(JSContext* cx, JS::Handle<JSObject*> src, Interface** ppArg)
|
2013-05-30 07:15:31 +04:00
|
|
|
{
|
2017-02-01 23:43:37 +03:00
|
|
|
return UnwrapArgImpl(cx, src, NS_GET_TEMPLATE_IID(Interface),
|
2014-10-23 23:21:46 +04:00
|
|
|
reinterpret_cast<void**>(ppArg));
|
2013-05-30 07:15:31 +04:00
|
|
|
}
|
|
|
|
|
2016-01-30 20:05:36 +03:00
|
|
|
template <>
|
|
|
|
inline nsresult
|
2017-02-01 23:43:37 +03:00
|
|
|
UnwrapArg<nsPIDOMWindowOuter>(JSContext* cx, JS::Handle<JSObject*> src,
|
|
|
|
nsPIDOMWindowOuter** ppArg)
|
2016-01-30 20:05:36 +03:00
|
|
|
{
|
2017-02-01 23:43:37 +03:00
|
|
|
return UnwrapWindowProxyImpl(cx, src, ppArg);
|
2016-01-30 20:05:36 +03:00
|
|
|
}
|
|
|
|
|
2013-06-17 21:07:03 +04:00
|
|
|
bool
|
2013-06-18 00:31:13 +04:00
|
|
|
ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
|
2016-01-06 11:54:00 +03:00
|
|
|
bool aSecurityError, const char* aInterfaceName);
|
2012-07-18 14:36:08 +04:00
|
|
|
|
2014-02-08 00:56:14 +04:00
|
|
|
bool
|
|
|
|
ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
|
2016-01-06 11:54:00 +03:00
|
|
|
bool aSecurityError, prototypes::ID aProtoId);
|
2014-02-08 00:56:14 +04:00
|
|
|
|
2012-10-09 22:50:27 +04:00
|
|
|
// Returns true if the JSClass is used for DOM objects.
|
2012-03-31 08:42:20 +04:00
|
|
|
inline bool
|
|
|
|
IsDOMClass(const JSClass* clasp)
|
|
|
|
{
|
|
|
|
return clasp->flags & JSCLASS_IS_DOMJSCLASS;
|
|
|
|
}
|
|
|
|
|
2012-06-06 23:59:46 +04:00
|
|
|
inline bool
|
|
|
|
IsDOMClass(const js::Class* clasp)
|
|
|
|
{
|
2012-06-01 20:24:52 +04:00
|
|
|
return IsDOMClass(Jsvalify(clasp));
|
2012-06-06 23:59:46 +04:00
|
|
|
}
|
|
|
|
|
2014-02-01 12:29:52 +04:00
|
|
|
// 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));
|
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
// Returns true if the JSClass is used for DOM interface and interface
|
2012-10-09 22:50:27 +04:00
|
|
|
// 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));
|
|
|
|
}
|
|
|
|
|
2014-10-18 03:57:52 +04:00
|
|
|
static_assert(DOM_OBJECT_SLOT == 0,
|
|
|
|
"DOM_OBJECT_SLOT doesn't match the proxy private slot. "
|
2013-07-18 21:59:53 +04:00
|
|
|
"Expect bad things");
|
2012-03-31 08:42:20 +04:00
|
|
|
template <class T>
|
|
|
|
inline T*
|
2012-12-07 00:21:19 +04:00
|
|
|
UnwrapDOMObject(JSObject* obj)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
2014-02-01 12:29:52 +04:00
|
|
|
MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
|
2012-05-22 17:46:20 +04:00
|
|
|
"Don't pass non-DOM objects to this function");
|
|
|
|
|
2017-04-28 15:12:28 +03:00
|
|
|
JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
|
2012-03-31 08:42:20 +04:00
|
|
|
return static_cast<T*>(val.toPrivate());
|
|
|
|
}
|
|
|
|
|
2014-10-28 13:18:36 +03:00
|
|
|
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");
|
|
|
|
|
2017-04-28 15:12:28 +03:00
|
|
|
JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
|
2014-10-28 13:18:36 +03:00
|
|
|
if (val.isUndefined()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return static_cast<T*>(val.toPrivate());
|
|
|
|
}
|
|
|
|
|
2014-08-22 13:25:35 +04:00
|
|
|
inline const DOMJSClass*
|
|
|
|
GetDOMClass(const js::Class* clasp)
|
|
|
|
{
|
|
|
|
return IsDOMClass(clasp) ? DOMJSClass::FromJSClass(clasp) : nullptr;
|
|
|
|
}
|
|
|
|
|
2014-06-19 00:19:19 +04:00
|
|
|
inline const DOMJSClass*
|
2012-05-22 17:46:20 +04:00
|
|
|
GetDOMClass(JSObject* obj)
|
|
|
|
{
|
2014-08-22 13:25:35 +04:00
|
|
|
return GetDOMClass(js::GetObjectClass(obj));
|
2012-05-22 17:46:20 +04:00
|
|
|
}
|
|
|
|
|
2013-06-01 10:56:02 +04:00
|
|
|
inline nsISupports*
|
|
|
|
UnwrapDOMObjectToISupports(JSObject* aObject)
|
2012-05-22 17:46:20 +04:00
|
|
|
{
|
2014-06-19 00:19:19 +04:00
|
|
|
const DOMJSClass* clasp = GetDOMClass(aObject);
|
2012-12-07 00:21:19 +04:00
|
|
|
if (!clasp || !clasp->mDOMObjectIsISupports) {
|
2013-06-01 10:56:02 +04:00
|
|
|
return nullptr;
|
2012-05-22 17:46:20 +04:00
|
|
|
}
|
2014-06-19 00:19:19 +04:00
|
|
|
|
2015-03-04 05:01:58 +03:00
|
|
|
return UnwrapPossiblyNotInitializedDOMObject<nsISupports>(aObject);
|
2012-05-22 17:46:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
IsDOMObject(JSObject* obj)
|
|
|
|
{
|
2014-02-01 12:29:52 +04:00
|
|
|
return IsDOMClass(js::GetObjectClass(obj));
|
2012-05-22 17:46:20 +04:00
|
|
|
}
|
|
|
|
|
2017-07-10 23:05:24 +03:00
|
|
|
// 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*.
|
2013-11-21 16:51:16 +04:00
|
|
|
#define UNWRAP_OBJECT(Interface, obj, value) \
|
2013-09-03 16:01:53 +04:00
|
|
|
mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Interface, \
|
2018-06-26 00:20:54 +03:00
|
|
|
mozilla::dom::Interface##_Binding::NativeType>(obj, value)
|
2013-08-24 06:42:41 +04:00
|
|
|
|
2017-07-10 23:05:24 +03:00
|
|
|
// 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, \
|
2018-06-26 00:20:54 +03:00
|
|
|
mozilla::dom::Interface##_Binding::NativeType>(obj)
|
2017-07-10 23:05:24 +03:00
|
|
|
|
|
|
|
// 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, \
|
2018-06-26 00:20:54 +03:00
|
|
|
mozilla::dom::Interface##_Binding::NativeType>(obj, value)
|
2017-07-10 23:05:24 +03:00
|
|
|
|
2012-09-12 20:24:58 +04:00
|
|
|
// Some callers don't want to set an exception when unwrapping fails
|
2012-03-31 08:42:20 +04:00
|
|
|
// (for example, overload resolution uses unwrapping to tell what sort
|
|
|
|
// of thing it's looking at).
|
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>).
|
2017-07-10 23:05:24 +03:00
|
|
|
//
|
|
|
|
// 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>
|
2012-11-27 13:20:05 +04:00
|
|
|
MOZ_ALWAYS_INLINE nsresult
|
2017-07-10 23:05:24 +03:00
|
|
|
UnwrapObjectInternal(V& obj, U& value, prototypes::ID protoID,
|
|
|
|
uint32_t protoDepth)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
|
|
|
/* First check to see whether we have a DOM object */
|
2014-06-19 00:19:19 +04:00
|
|
|
const DOMJSClass* domClass = GetDOMClass(obj);
|
2017-07-10 23:05:24 +03:00
|
|
|
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;
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
2017-07-10 23:05:24 +03:00
|
|
|
}
|
2012-03-31 08:42:20 +04:00
|
|
|
|
2017-07-10 23:05:24 +03:00
|
|
|
/* 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;
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2017-07-10 23:05:24 +03:00
|
|
|
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.
|
2017-07-11 01:04:49 +03:00
|
|
|
//
|
|
|
|
// 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.
|
2017-09-11 15:50:15 +03:00
|
|
|
T* tempValue = nullptr;
|
2017-07-11 01:04:49 +03:00
|
|
|
nsresult rv = UnwrapObjectInternal<T, false>(unwrappedObj, tempValue,
|
2017-07-10 23:05:24 +03:00
|
|
|
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;
|
2017-07-11 01:04:49 +03:00
|
|
|
// And now assign to "value"; at this point we don't care if a GC happens
|
|
|
|
// and invalidates unwrappedObj.
|
|
|
|
value = tempValue;
|
2012-03-31 08:42:20 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* It's the wrong sort of DOM object */
|
|
|
|
return NS_ERROR_XPC_BAD_CONVERT_JS;
|
|
|
|
}
|
|
|
|
|
2017-07-10 23:05:24 +03:00
|
|
|
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>
|
2014-02-08 00:56:14 +04:00
|
|
|
MOZ_ALWAYS_INLINE nsresult
|
2017-07-10 23:05:24 +03:00
|
|
|
UnwrapNonWrapperObject(JSObject* obj, U& value)
|
2014-02-08 00:56:14 +04:00
|
|
|
{
|
2017-07-10 23:05:24 +03:00
|
|
|
MOZ_ASSERT(!js::IsWrapper(obj));
|
|
|
|
return binding_detail::UnwrapObjectInternal<T, false>(
|
|
|
|
obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
|
2014-02-08 00:56:14 +04:00
|
|
|
}
|
|
|
|
|
2013-01-03 23:03:11 +04:00
|
|
|
MOZ_ALWAYS_INLINE bool
|
2016-11-24 06:57:29 +03:00
|
|
|
IsConvertibleToDictionary(JS::Handle<JS::Value> val)
|
2013-01-03 23:03:11 +04:00
|
|
|
{
|
2016-11-24 06:57:29 +03:00
|
|
|
return val.isNullOrUndefined() || val.isObject();
|
2013-01-03 23:03:11 +04:00
|
|
|
}
|
|
|
|
|
2014-09-15 18:51:33 +04:00
|
|
|
// 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.
|
2013-07-18 21:59:53 +04:00
|
|
|
static_assert((size_t)constructors::id::_ID_Start ==
|
2014-09-15 18:51:33 +04:00
|
|
|
(size_t)prototypes::id::_ID_Count &&
|
|
|
|
(size_t)namedpropertiesobjects::id::_ID_Start ==
|
|
|
|
(size_t)constructors::id::_ID_Count,
|
2013-07-18 21:59:53 +04:00
|
|
|
"Overlapping or discontiguous indexes.");
|
2014-09-15 18:51:33 +04:00
|
|
|
const size_t kProtoAndIfaceCacheCount = namedpropertiesobjects::id::_ID_Count;
|
2012-03-31 08:42:20 +04:00
|
|
|
|
2014-03-22 21:04:09 +04:00
|
|
|
class ProtoAndIfaceCache
|
2013-11-19 23:28:09 +04:00
|
|
|
{
|
2013-12-11 01:04:55 +04:00
|
|
|
// 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:
|
2017-06-07 19:56:27 +03:00
|
|
|
bool HasEntryInSlot(size_t i) {
|
|
|
|
return (*this)[i];
|
|
|
|
}
|
|
|
|
|
2013-12-11 01:04:55 +04:00
|
|
|
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) {
|
2016-01-13 00:07:54 +03:00
|
|
|
JS::TraceEdge(aTracer, &(*this)[i], "protoAndIfaceCache[i]");
|
2013-12-11 01:04:55 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
|
|
|
|
return aMallocSizeOf(this);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class PageTableCache
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
PageTableCache() {
|
2017-10-24 16:52:20 +03:00
|
|
|
memset(mPages.begin(), 0, sizeof(mPages));
|
2013-12-11 01:04:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
~PageTableCache() {
|
|
|
|
for (size_t i = 0; i < ArrayLength(mPages); ++i) {
|
|
|
|
delete mPages[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-07 19:56:27 +03:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
2013-12-11 01:04:55 +04:00
|
|
|
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) {
|
2016-01-13 00:07:54 +03:00
|
|
|
JS::TraceEdge(trc, &(*p)[j], "protoAndIfaceCache[i]");
|
2013-12-11 01:04:55 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2013-11-19 23:28:09 +04:00
|
|
|
public:
|
2013-12-11 01:04:55 +04:00
|
|
|
enum Kind {
|
|
|
|
WindowLike,
|
|
|
|
NonWindowLike
|
|
|
|
};
|
|
|
|
|
2014-07-28 21:17:51 +04:00
|
|
|
explicit ProtoAndIfaceCache(Kind aKind) : mKind(aKind) {
|
2014-03-22 21:04:09 +04:00
|
|
|
MOZ_COUNT_CTOR(ProtoAndIfaceCache);
|
2013-12-11 01:04:55 +04:00
|
|
|
if (aKind == WindowLike) {
|
|
|
|
mArrayCache = new ArrayCache();
|
|
|
|
} else {
|
|
|
|
mPageTableCache = new PageTableCache();
|
|
|
|
}
|
2013-11-19 23:28:09 +04:00
|
|
|
}
|
|
|
|
|
2014-03-22 21:04:09 +04:00
|
|
|
~ProtoAndIfaceCache() {
|
2013-12-11 01:04:55 +04:00
|
|
|
if (mKind == WindowLike) {
|
|
|
|
delete mArrayCache;
|
|
|
|
} else {
|
|
|
|
delete mPageTableCache;
|
|
|
|
}
|
2014-03-22 21:04:09 +04:00
|
|
|
MOZ_COUNT_DTOR(ProtoAndIfaceCache);
|
2013-11-19 23:28:09 +04:00
|
|
|
}
|
2013-11-20 17:55:09 +04:00
|
|
|
|
2013-12-11 01:04:55 +04:00
|
|
|
#define FORWARD_OPERATION(opName, args) \
|
|
|
|
do { \
|
|
|
|
if (mKind == WindowLike) { \
|
|
|
|
return mArrayCache->opName args; \
|
|
|
|
} else { \
|
|
|
|
return mPageTableCache->opName args; \
|
|
|
|
} \
|
|
|
|
} while(0)
|
|
|
|
|
2017-06-07 19:56:27 +03:00
|
|
|
// 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));
|
|
|
|
}
|
|
|
|
|
2015-03-07 00:33:30 +03:00
|
|
|
// Return a reference to slot i, creating it if necessary. There
|
|
|
|
// may not be an object in the returned slot.
|
2013-12-11 01:04:55 +04:00
|
|
|
JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
|
|
|
|
FORWARD_OPERATION(EntrySlotOrCreate, (i));
|
|
|
|
}
|
|
|
|
|
2015-03-07 00:33:30 +03:00
|
|
|
// 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.
|
2013-12-11 01:04:55 +04:00
|
|
|
JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
|
|
|
|
FORWARD_OPERATION(EntrySlotMustExist, (i));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Trace(JSTracer *aTracer) {
|
|
|
|
FORWARD_OPERATION(Trace, (aTracer));
|
|
|
|
}
|
|
|
|
|
2013-11-20 17:55:09 +04:00
|
|
|
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
|
2013-12-11 01:04:55 +04:00
|
|
|
size_t n = aMallocSizeOf(this);
|
|
|
|
n += (mKind == WindowLike
|
|
|
|
? mArrayCache->SizeOfIncludingThis(aMallocSizeOf)
|
|
|
|
: mPageTableCache->SizeOfIncludingThis(aMallocSizeOf));
|
|
|
|
return n;
|
2013-11-20 17:55:09 +04:00
|
|
|
}
|
2013-12-11 01:04:55 +04:00
|
|
|
#undef FORWARD_OPERATION
|
|
|
|
|
|
|
|
private:
|
|
|
|
union {
|
|
|
|
ArrayCache *mArrayCache;
|
|
|
|
PageTableCache *mPageTableCache;
|
|
|
|
};
|
|
|
|
Kind mKind;
|
2013-11-19 23:28:09 +04:00
|
|
|
};
|
|
|
|
|
2012-03-31 08:42:20 +04:00
|
|
|
inline void
|
2014-03-22 21:04:09 +04:00
|
|
|
AllocateProtoAndIfaceCache(JSObject* obj, ProtoAndIfaceCache::Kind aKind)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
|
|
|
|
MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined());
|
|
|
|
|
2014-03-22 21:04:09 +04:00
|
|
|
ProtoAndIfaceCache* protoAndIfaceCache = new ProtoAndIfaceCache(aKind);
|
2012-03-31 08:42:20 +04:00
|
|
|
|
|
|
|
js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT,
|
2014-03-22 21:04:09 +04:00
|
|
|
JS::PrivateValue(protoAndIfaceCache));
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2014-04-08 22:48:37 +04:00
|
|
|
#ifdef DEBUG
|
2015-02-26 00:11:37 +03:00
|
|
|
struct VerifyTraceProtoAndIfaceCacheCalledTracer : public JS::CallbackTracer
|
2014-04-08 22:48:37 +04:00
|
|
|
{
|
2015-05-29 02:35:08 +03:00
|
|
|
bool ok;
|
|
|
|
|
2016-08-11 15:39:22 +03:00
|
|
|
explicit VerifyTraceProtoAndIfaceCacheCalledTracer(JSContext* cx)
|
|
|
|
: JS::CallbackTracer(cx), ok(false)
|
2015-05-29 02:35:08 +03:00
|
|
|
{}
|
|
|
|
|
2015-06-11 20:03:33 +03:00
|
|
|
void onChild(const JS::GCCellPtr&) override {
|
2015-05-29 02:35:08 +03:00
|
|
|
// We don't do anything here, we only want to verify that
|
|
|
|
// TraceProtoAndIfaceCache was called.
|
|
|
|
}
|
2014-04-08 22:48:37 +04:00
|
|
|
|
2015-05-29 02:35:08 +03:00
|
|
|
TracerKind getTracerKind() const override { return TracerKind::VerifyTraceProtoAndIface; }
|
2014-04-08 22:48:37 +04:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2012-05-02 16:49:43 +04:00
|
|
|
inline void
|
2012-10-09 22:50:27 +04:00
|
|
|
TraceProtoAndIfaceCache(JSTracer* trc, JSObject* obj)
|
2012-05-02 16:49:43 +04:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
|
|
|
|
|
2014-04-08 22:48:37 +04:00
|
|
|
#ifdef DEBUG
|
2015-02-26 00:11:37 +03:00
|
|
|
if (trc->isCallbackTracer() &&
|
2015-05-29 02:35:08 +03:00
|
|
|
(trc->asCallbackTracer()->getTracerKind() ==
|
|
|
|
JS::CallbackTracer::TracerKind::VerifyTraceProtoAndIface)) {
|
2014-04-08 22:48:37 +04:00
|
|
|
// We don't do anything here, we only want to verify that
|
|
|
|
// TraceProtoAndIfaceCache was called.
|
|
|
|
static_cast<VerifyTraceProtoAndIfaceCacheCalledTracer*>(trc)->ok = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-05-14 03:21:40 +03:00
|
|
|
if (!DOMGlobalHasProtoAndIFaceCache(obj))
|
2012-06-19 04:04:38 +04:00
|
|
|
return;
|
2014-03-22 21:04:09 +04:00
|
|
|
ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
|
|
|
|
protoAndIfaceCache->Trace(trc);
|
2012-05-02 16:49:43 +04:00
|
|
|
}
|
|
|
|
|
2012-03-31 08:42:20 +04:00
|
|
|
inline void
|
2012-10-09 22:50:27 +04:00
|
|
|
DestroyProtoAndIfaceCache(JSObject* obj)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
|
|
|
|
|
2016-05-14 03:21:40 +03:00
|
|
|
if (!DOMGlobalHasProtoAndIFaceCache(obj)) {
|
2016-04-14 18:42:34 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-22 21:04:09 +04:00
|
|
|
ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
|
2013-11-19 10:05:42 +04:00
|
|
|
|
2014-03-22 21:04:09 +04:00
|
|
|
delete protoAndIfaceCache;
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2012-05-09 14:00:48 +04:00
|
|
|
/**
|
|
|
|
* Add constants to an object.
|
|
|
|
*/
|
|
|
|
bool
|
2013-05-08 06:34:56 +04:00
|
|
|
DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
|
|
|
|
const ConstantSpec* cs);
|
2012-05-09 14:00:48 +04:00
|
|
|
|
2012-10-09 22:50:27 +04:00
|
|
|
struct JSNativeHolder
|
|
|
|
{
|
|
|
|
JSNative mNative;
|
|
|
|
const NativePropertyHooks* mPropertyHooks;
|
|
|
|
};
|
|
|
|
|
2013-01-22 14:51:15 +04:00
|
|
|
struct NamedConstructor
|
|
|
|
{
|
|
|
|
const char* mName;
|
|
|
|
const JSNativeHolder mHolder;
|
|
|
|
unsigned mNargs;
|
|
|
|
};
|
|
|
|
|
2012-03-31 08:42:20 +04:00
|
|
|
/*
|
|
|
|
* Create a DOM interface object (if constructorClass is non-null) and/or a
|
|
|
|
* DOM interface prototype object (if protoClass is non-null).
|
|
|
|
*
|
2012-04-23 18:10:56 +04:00
|
|
|
* 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.
|
2016-04-21 01:04:56 +03:00
|
|
|
* 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).
|
2012-03-31 08:42:20 +04:00
|
|
|
* protoClass is the JSClass to use for the interface prototype object.
|
|
|
|
* This is null if we should not create an interface prototype
|
|
|
|
* object.
|
2012-10-09 22:50:27 +04:00
|
|
|
* 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.
|
2018-05-18 06:45:35 +03:00
|
|
|
* toStringTag if not null, a string to define as @@toStringTag on the prototype.
|
|
|
|
* Must be null if protoClass is.
|
2012-03-31 08:42:20 +04:00
|
|
|
* constructorClass is the JSClass to use for the interface object.
|
2012-05-03 08:35:38 +04:00
|
|
|
* This is null if we should not create an interface object or
|
|
|
|
* if it should be a function object.
|
2012-10-09 22:50:27 +04:00
|
|
|
* 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.
|
2012-05-03 08:35:38 +04:00
|
|
|
* ctorNargs is the length of the constructor function; 0 if no constructor
|
2012-10-09 22:50:27 +04:00
|
|
|
* 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.
|
2012-10-09 22:50:05 +04:00
|
|
|
* 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.
|
2013-08-08 01:40:00 +04:00
|
|
|
* 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.
|
2016-03-29 22:50:38 +03:00
|
|
|
* unscopableNames if not null it points to a null-terminated list of const
|
|
|
|
* char* names of the unscopable properties for this interface.
|
2016-08-04 04:32:06 +03:00
|
|
|
* isGlobal if true, we're creating interface objects for a [Global] or
|
|
|
|
* [PrimaryGlobal] interface, and hence shouldn't define properties on
|
|
|
|
* the prototype object.
|
2012-03-31 08:42:20 +04:00
|
|
|
*
|
2012-10-09 22:50:27 +04:00
|
|
|
* 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.
|
2012-03-31 08:42:20 +04:00
|
|
|
*/
|
2012-10-09 22:50:27 +04:00
|
|
|
void
|
2013-05-02 07:44:12 +04:00
|
|
|
CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
|
2013-05-02 07:44:11 +04:00
|
|
|
JS::Handle<JSObject*> protoProto,
|
2014-08-05 14:46:42 +04:00
|
|
|
const js::Class* protoClass, JS::Heap<JSObject*>* protoCache,
|
2018-05-18 06:45:35 +03:00
|
|
|
const char* toStringTag,
|
2013-05-02 22:38:19 +04:00
|
|
|
JS::Handle<JSObject*> interfaceProto,
|
2016-08-04 04:32:06 +03:00
|
|
|
const js::Class* constructorClass,
|
2013-01-22 14:51:15 +04:00
|
|
|
unsigned ctorNargs, const NamedConstructor* namedConstructors,
|
2014-05-20 00:37:59 +04:00
|
|
|
JS::Heap<JSObject*>* constructorCache,
|
2012-10-09 22:50:27 +04:00
|
|
|
const NativeProperties* regularProperties,
|
|
|
|
const NativeProperties* chromeOnlyProperties,
|
2016-03-29 22:50:38 +03:00
|
|
|
const char* name, bool defineOnGlobal,
|
2016-08-04 04:32:06 +03:00
|
|
|
const char* const* unscopableNames,
|
|
|
|
bool isGlobal);
|
2012-03-31 08:42:20 +04:00
|
|
|
|
2014-02-16 01:12:34 +04:00
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
|
2014-07-04 17:02:10 +04:00
|
|
|
/*
|
|
|
|
* Define the unforgeable methods on an object.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
DefineUnforgeableMethods(JSContext* cx, JS::Handle<JSObject*> obj,
|
|
|
|
const Prefable<const JSFunctionSpec>* props);
|
|
|
|
|
2012-10-25 00:10:49 +04:00
|
|
|
/*
|
|
|
|
* Define the unforgeable attributes on an object.
|
|
|
|
*/
|
|
|
|
bool
|
2013-05-04 03:29:08 +04:00
|
|
|
DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
|
2013-04-03 04:20:38 +04:00
|
|
|
const Prefable<const JSPropertySpec>* props);
|
2012-10-25 00:10:49 +04:00
|
|
|
|
2014-11-01 16:04:43 +03:00
|
|
|
#define HAS_MEMBER_TYPEDEFS \
|
|
|
|
private: \
|
|
|
|
typedef char yes[1]; \
|
|
|
|
typedef char no[2]
|
|
|
|
|
2012-11-09 11:48:42 +04:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#define HAS_MEMBER_CHECK(_name) \
|
2014-11-01 16:04:43 +03:00
|
|
|
template<typename V> static yes& Check##_name(char (*)[(&V::_name == 0) + 1])
|
2012-11-09 11:48:42 +04:00
|
|
|
#else
|
|
|
|
#define HAS_MEMBER_CHECK(_name) \
|
2014-11-01 16:04:43 +03:00
|
|
|
template<typename V> static yes& Check##_name(char (*)[sizeof(&V::_name) + 1])
|
2012-11-09 11:48:42 +04:00
|
|
|
#endif
|
|
|
|
|
2014-11-01 16:04:43 +03:00
|
|
|
#define HAS_MEMBER(_memberName, _valueName) \
|
|
|
|
private: \
|
|
|
|
HAS_MEMBER_CHECK(_memberName); \
|
|
|
|
template<typename V> static no& Check##_memberName(...); \
|
2012-11-09 11:48:42 +04:00
|
|
|
\
|
|
|
|
public: \
|
2014-11-01 16:04:43 +03:00
|
|
|
static bool const _valueName = \
|
|
|
|
sizeof(Check##_memberName<T>(nullptr)) == sizeof(yes)
|
2012-11-09 11:48:42 +04:00
|
|
|
|
2014-11-01 16:04:43 +03:00
|
|
|
template<class T>
|
|
|
|
struct NativeHasMember
|
|
|
|
{
|
|
|
|
HAS_MEMBER_TYPEDEFS;
|
2012-11-09 11:48:42 +04:00
|
|
|
|
2014-11-01 16:04:43 +03:00
|
|
|
HAS_MEMBER(GetParentObject, GetParentObject);
|
|
|
|
HAS_MEMBER(WrapObject, WrapObject);
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
struct IsSmartPtr
|
2012-11-09 11:48:42 +04:00
|
|
|
{
|
2014-11-01 16:04:43 +03:00
|
|
|
HAS_MEMBER_TYPEDEFS;
|
2012-11-09 11:48:42 +04:00
|
|
|
|
2014-11-01 16:04:43 +03:00
|
|
|
HAS_MEMBER(get, value);
|
2012-11-09 11:48:42 +04:00
|
|
|
};
|
|
|
|
|
2014-11-01 16:10:59 +03:00
|
|
|
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!");
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2014-11-01 16:04:43 +03:00
|
|
|
#undef HAS_MEMBER
|
|
|
|
#undef HAS_MEMBER_CHECK
|
|
|
|
#undef HAS_MEMBER_TYPEDEFS
|
|
|
|
|
2012-11-22 14:46:53 +04:00
|
|
|
#ifdef DEBUG
|
2013-07-04 19:24:59 +04:00
|
|
|
template <class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
|
2012-11-22 14:46:53 +04:00
|
|
|
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
|
|
|
|
|
2014-02-16 01:10:25 +04:00
|
|
|
inline bool
|
2015-12-08 01:03:18 +03:00
|
|
|
TryToOuterize(JS::MutableHandle<JS::Value> rval)
|
2014-02-16 01:10:25 +04:00
|
|
|
{
|
2015-11-06 21:03:51 +03:00
|
|
|
if (js::IsWindow(&rval.toObject())) {
|
|
|
|
JSObject* obj = js::ToWindowProxyIfWindow(&rval.toObject());
|
|
|
|
MOZ_ASSERT(obj);
|
2014-02-16 01:10:25 +04:00
|
|
|
rval.set(JS::ObjectValue(*obj));
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-07-11 19:58:29 +04:00
|
|
|
// 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)
|
2013-01-03 07:03:25 +04:00
|
|
|
{
|
2013-07-11 19:58:29 +04:00
|
|
|
MOZ_ASSERT(rval.isString());
|
|
|
|
JSString* str = rval.toString();
|
2015-06-02 00:11:08 +03:00
|
|
|
if (JS::GetStringZone(str) != js::GetContextZone(cx)) {
|
2013-10-26 20:19:05 +04:00
|
|
|
return JS_WrapValue(cx, rval);
|
2013-03-17 07:36:37 +04:00
|
|
|
}
|
2013-07-11 19:58:29 +04:00
|
|
|
return true;
|
|
|
|
}
|
2013-03-17 07:36:37 +04:00
|
|
|
|
2013-07-11 19:58:29 +04:00
|
|
|
// 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());
|
2013-02-22 06:23:47 +04:00
|
|
|
|
2014-03-26 17:59:20 +04:00
|
|
|
// Cross-compartment always requires wrapping.
|
2013-04-19 23:57:18 +04:00
|
|
|
JSObject* obj = &rval.toObject();
|
|
|
|
if (js::GetObjectCompartment(obj) != js::GetContextCompartment(cx)) {
|
2013-10-26 20:19:05 +04:00
|
|
|
return JS_WrapValue(cx, rval);
|
2013-04-19 23:57:18 +04:00
|
|
|
}
|
2013-03-17 07:36:37 +04:00
|
|
|
|
2014-02-16 01:10:25 +04:00
|
|
|
// We're same-compartment, but even then we might need to wrap
|
|
|
|
// objects specially. Check for that.
|
2014-03-26 17:59:20 +04:00
|
|
|
if (IsDOMObject(obj)) {
|
2015-12-08 01:03:18 +03:00
|
|
|
return TryToOuterize(rval);
|
2013-01-03 07:03:25 +04:00
|
|
|
}
|
|
|
|
|
2016-09-20 15:25:05 +03:00
|
|
|
// 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;
|
2013-01-03 07:03:25 +04:00
|
|
|
}
|
|
|
|
|
2013-07-11 19:58:29 +04:00
|
|
|
// 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;
|
|
|
|
}
|
2013-10-26 20:19:05 +04:00
|
|
|
return JS_WrapValue(cx, rval);
|
2013-07-11 19:58:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
{
|
2017-01-30 16:31:47 +03:00
|
|
|
if (rval.isGCThing()) {
|
|
|
|
if (rval.isString()) {
|
|
|
|
return MaybeWrapStringValue(cx, rval);
|
|
|
|
}
|
|
|
|
if (rval.isObject()) {
|
|
|
|
return MaybeWrapObjectValue(cx, rval);
|
|
|
|
}
|
2018-06-20 19:11:00 +03:00
|
|
|
#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
|
2017-01-30 16:31:47 +03:00
|
|
|
MOZ_ASSERT(rval.isSymbol());
|
|
|
|
JS_MarkCrossZoneId(cx, SYMBOL_TO_JSID(rval.toSymbol()));
|
2013-07-11 19:58:29 +04:00
|
|
|
}
|
2017-01-30 16:31:47 +03:00
|
|
|
return true;
|
2013-07-11 19:58:29 +04:00
|
|
|
}
|
|
|
|
|
2014-11-26 22:25:21 +03:00
|
|
|
namespace binding_detail {
|
|
|
|
enum GetOrCreateReflectorWrapBehavior {
|
|
|
|
eWrapIntoContextCompartment,
|
|
|
|
eDontWrapIntoContextCompartment
|
|
|
|
};
|
|
|
|
|
2012-03-31 08:42:20 +04:00
|
|
|
template <class T>
|
2014-11-26 22:25:21 +03:00
|
|
|
struct TypeNeedsOuterization
|
|
|
|
{
|
|
|
|
// We only need to outerize Window objects, so anything inheriting from
|
|
|
|
// nsGlobalWindow (which inherits from EventTarget itself).
|
|
|
|
static const bool value =
|
2017-11-15 19:33:39 +03:00
|
|
|
IsBaseOf<nsGlobalWindowInner, T>::value ||
|
|
|
|
IsBaseOf<nsGlobalWindowOuter, T>::value ||
|
|
|
|
IsSame<EventTarget, T>::value;
|
2014-11-26 22:25:21 +03:00
|
|
|
};
|
|
|
|
|
2015-07-29 13:28:45 +03:00
|
|
|
#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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-07-31 20:30:55 +03:00
|
|
|
void
|
|
|
|
AssertReflectorHasGivenProto(JSContext* aCx, JSObject* aReflector,
|
|
|
|
JS::Handle<JSObject*> aGivenProto);
|
2018-09-18 05:31:03 +03:00
|
|
|
|
2015-07-31 20:30:55 +03:00
|
|
|
#endif // DEBUG
|
2015-07-29 13:28:45 +03:00
|
|
|
|
2018-09-18 05:31:03 +03:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2014-11-26 22:25:21 +03:00
|
|
|
template <class T, GetOrCreateReflectorWrapBehavior wrapBehavior>
|
2012-11-20 20:36:06 +04:00
|
|
|
MOZ_ALWAYS_INLINE bool
|
2014-11-26 22:25:21 +03:00
|
|
|
DoGetOrCreateDOMReflector(JSContext* cx, T* value,
|
2015-07-31 20:30:55 +03:00
|
|
|
JS::Handle<JSObject*> givenProto,
|
2014-11-26 22:25:21 +03:00
|
|
|
JS::MutableHandle<JS::Value> rval)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
2013-04-24 22:59:15 +04:00
|
|
|
MOZ_ASSERT(value);
|
2016-12-09 05:41:45 +03:00
|
|
|
MOZ_ASSERT_IF(givenProto, js::IsObjectInContextCompartment(givenProto, cx));
|
2015-07-31 20:30:55 +03:00
|
|
|
JSObject* obj = value->GetWrapper();
|
2012-11-20 20:36:06 +04:00
|
|
|
if (obj) {
|
2015-07-31 20:30:55 +03:00
|
|
|
#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
|
2012-11-27 13:20:04 +04:00
|
|
|
} else {
|
2015-07-31 20:30:55 +03:00
|
|
|
obj = value->WrapObject(cx, givenProto);
|
2012-03-31 08:42:20 +04:00
|
|
|
if (!obj) {
|
2013-03-12 03:03:47 +04:00
|
|
|
// At this point, obj is null, so just return false.
|
|
|
|
// Callers seem to be testing JS_IsExceptionPending(cx) to
|
|
|
|
// figure out whether WrapObject() threw.
|
2018-09-18 05:31:03 +03:00
|
|
|
CrashIfDocumentOrLocationWrapFailed<T>();
|
2012-03-31 08:42:20 +04:00
|
|
|
return false;
|
|
|
|
}
|
2015-07-29 13:28:45 +03:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (IsBaseOf<nsWrapperCache, T>::value) {
|
|
|
|
CheckWrapperCacheTracing<T>::Check(value);
|
|
|
|
}
|
|
|
|
#endif
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2012-11-09 11:48:42 +04:00
|
|
|
#ifdef DEBUG
|
2014-06-19 00:19:19 +04:00
|
|
|
const DOMJSClass* clasp = GetDOMClass(obj);
|
2014-04-09 02:27:19 +04:00
|
|
|
// clasp can be null if the cache contained a non-DOM object.
|
2012-12-07 00:21:19 +04:00
|
|
|
if (clasp) {
|
2012-11-22 14:46:53 +04:00
|
|
|
// 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?");
|
2013-07-04 19:24:59 +04:00
|
|
|
MOZ_ASSERT_IF(clasp->mDOMObjectIsISupports, (IsBaseOf<nsISupports, T>::value));
|
2012-11-22 14:46:53 +04:00
|
|
|
MOZ_ASSERT(CheckWrapperCacheCast<T>::Check());
|
|
|
|
}
|
2012-09-13 00:29:30 +04:00
|
|
|
#endif
|
|
|
|
|
2014-02-16 01:10:25 +04:00
|
|
|
rval.set(JS::ObjectValue(*obj));
|
|
|
|
|
2018-04-05 18:22:41 +03:00
|
|
|
if (js::GetObjectCompartment(obj) == js::GetContextCompartment(cx)) {
|
2018-09-18 05:31:03 +03:00
|
|
|
if (!TypeNeedsOuterization<T>::value) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (TryToOuterize(rval)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2014-11-26 22:25:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (wrapBehavior == eDontWrapIntoContextCompartment) {
|
|
|
|
if (TypeNeedsOuterization<T>::value) {
|
2018-08-02 09:48:50 +03:00
|
|
|
JSAutoRealm ar(cx, obj);
|
2018-09-18 05:31:03 +03:00
|
|
|
if (TryToOuterize(rval)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2014-11-26 22:25:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2012-09-13 00:29:30 +04:00
|
|
|
}
|
|
|
|
|
2018-09-18 05:31:03 +03:00
|
|
|
if (JS_WrapValue(cx, rval)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_CRASH("Looks like bug 1488480/1405521, with JS_WrapValue failing");
|
|
|
|
return false;
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
2015-07-13 18:25:42 +03:00
|
|
|
|
2014-11-26 22:25:21 +03:00
|
|
|
} // 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,
|
2015-07-31 20:30:55 +03:00
|
|
|
JS::MutableHandle<JS::Value> rval,
|
|
|
|
JS::Handle<JSObject*> givenProto = nullptr)
|
2014-11-26 22:25:21 +03:00
|
|
|
{
|
|
|
|
using namespace binding_detail;
|
|
|
|
return DoGetOrCreateDOMReflector<T, eWrapIntoContextCompartment>(cx, value,
|
2015-07-31 20:30:55 +03:00
|
|
|
givenProto,
|
2014-11-26 22:25:21 +03:00
|
|
|
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,
|
2015-07-31 20:30:55 +03:00
|
|
|
nullptr,
|
2014-11-26 22:25:21 +03:00
|
|
|
rval);
|
|
|
|
}
|
2012-03-31 08:42:20 +04:00
|
|
|
|
2012-11-27 13:20:04 +04:00
|
|
|
// Create a JSObject wrapping "value", for cases when "value" is a
|
|
|
|
// non-wrapper-cached object using WebIDL bindings. "value" must implement a
|
2018-06-09 08:03:15 +03:00
|
|
|
// WrapObject() method taking a JSContext and a prototype (possibly null) and
|
|
|
|
// returning the resulting object via a MutableHandle<JSObject*> outparam.
|
2012-06-16 00:25:50 +04:00
|
|
|
template <class T>
|
|
|
|
inline bool
|
2013-04-25 20:29:53 +04:00
|
|
|
WrapNewBindingNonWrapperCachedObject(JSContext* cx,
|
|
|
|
JS::Handle<JSObject*> scopeArg,
|
2013-06-08 06:45:46 +04:00
|
|
|
T* value,
|
2015-07-31 20:30:55 +03:00
|
|
|
JS::MutableHandle<JS::Value> rval,
|
|
|
|
JS::Handle<JSObject*> givenProto = nullptr)
|
2012-06-16 00:25:50 +04:00
|
|
|
{
|
2014-11-01 17:00:47 +03:00
|
|
|
static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
|
2013-04-24 22:59:15 +04:00
|
|
|
MOZ_ASSERT(value);
|
2018-05-16 11:53:16 +03:00
|
|
|
// We try to wrap in the realm of the underlying object of "scope"
|
2013-05-04 03:29:09 +04:00
|
|
|
JS::Rooted<JSObject*> obj(cx);
|
2012-06-16 00:25:50 +04:00
|
|
|
{
|
2018-08-02 09:48:50 +03:00
|
|
|
// scope for the JSAutoRealm so that we restore the realm
|
2012-08-22 05:42:53 +04:00
|
|
|
// before we call JS_WrapValue.
|
2018-08-02 09:48:50 +03:00
|
|
|
Maybe<JSAutoRealm> ar;
|
2013-04-25 20:29:53 +04:00
|
|
|
// 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);
|
2015-07-31 20:30:55 +03:00
|
|
|
JS::Rooted<JSObject*> proto(cx, givenProto);
|
2012-06-16 00:25:50 +04:00
|
|
|
if (js::IsWrapper(scope)) {
|
2015-11-06 21:03:52 +03:00
|
|
|
scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
|
2012-08-22 05:42:53 +04:00
|
|
|
if (!scope)
|
2012-06-16 00:25:50 +04:00
|
|
|
return false;
|
2018-05-16 11:53:16 +03:00
|
|
|
ar.emplace(cx, scope);
|
2015-07-31 20:30:55 +03:00
|
|
|
if (!JS_WrapObject(cx, &proto)) {
|
|
|
|
return false;
|
|
|
|
}
|
2012-06-16 00:25:50 +04:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:27:18 +04:00
|
|
|
MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
|
2015-07-31 20:30:55 +03:00
|
|
|
if (!value->WrapObject(cx, proto, &obj)) {
|
2015-01-09 00:56:42 +03:00
|
|
|
return false;
|
|
|
|
}
|
2013-04-20 02:18:31 +04:00
|
|
|
}
|
|
|
|
|
2013-04-19 12:49:21 +04:00
|
|
|
// We can end up here in all sorts of compartments, per above. Make
|
|
|
|
// sure to JS_WrapValue!
|
2013-06-08 06:45:46 +04:00
|
|
|
rval.set(JS::ObjectValue(*obj));
|
2015-05-05 20:38:56 +03:00
|
|
|
return MaybeWrapObjectValue(cx, rval);
|
2013-04-19 12:49:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create a JSObject wrapping "value", for cases when "value" is a
|
2018-06-09 08:03:15 +03:00
|
|
|
// 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
|
2013-04-19 12:49:21 +04:00
|
|
|
template <class T>
|
|
|
|
inline bool
|
2014-11-01 17:00:47 +03:00
|
|
|
WrapNewBindingNonWrapperCachedObject(JSContext* cx,
|
|
|
|
JS::Handle<JSObject*> scopeArg,
|
|
|
|
nsAutoPtr<T>& value,
|
2015-07-31 20:30:55 +03:00
|
|
|
JS::MutableHandle<JS::Value> rval,
|
|
|
|
JS::Handle<JSObject*> givenProto = nullptr)
|
2013-04-19 12:49:21 +04:00
|
|
|
{
|
2014-11-01 17:00:47 +03:00
|
|
|
static_assert(!IsRefcounted<T>::value, "Only pass owned classes in here.");
|
2013-04-24 22:59:15 +04:00
|
|
|
// 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) {
|
2016-12-03 00:46:53 +03:00
|
|
|
MOZ_CRASH("Don't try to wrap null objects");
|
2013-04-24 22:59:15 +04:00
|
|
|
}
|
2018-05-16 11:53:16 +03:00
|
|
|
// We try to wrap in the realm of the underlying object of "scope"
|
2013-05-04 03:29:09 +04:00
|
|
|
JS::Rooted<JSObject*> obj(cx);
|
2013-04-19 12:49:21 +04:00
|
|
|
{
|
2018-08-02 09:48:50 +03:00
|
|
|
// scope for the JSAutoRealm so that we restore the realm
|
2013-04-19 12:49:21 +04:00
|
|
|
// before we call JS_WrapValue.
|
2018-08-02 09:48:50 +03:00
|
|
|
Maybe<JSAutoRealm> ar;
|
2013-04-25 20:29:53 +04:00
|
|
|
// 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);
|
2015-07-31 20:30:55 +03:00
|
|
|
JS::Rooted<JSObject*> proto(cx, givenProto);
|
2013-04-19 12:49:21 +04:00
|
|
|
if (js::IsWrapper(scope)) {
|
2015-11-06 21:03:52 +03:00
|
|
|
scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
|
2013-04-19 12:49:21 +04:00
|
|
|
if (!scope)
|
|
|
|
return false;
|
2018-05-16 11:53:16 +03:00
|
|
|
ar.emplace(cx, scope);
|
2015-07-31 20:30:55 +03:00
|
|
|
if (!JS_WrapObject(cx, &proto)) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-04-19 12:49:21 +04:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:27:18 +04:00
|
|
|
MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
|
2015-07-31 20:30:55 +03:00
|
|
|
if (!value->WrapObject(cx, proto, &obj)) {
|
2015-01-09 00:56:42 +03:00
|
|
|
return false;
|
2013-04-19 12:49:21 +04:00
|
|
|
}
|
|
|
|
|
2015-01-09 00:56:42 +03:00
|
|
|
value.forget();
|
2013-04-20 02:18:31 +04:00
|
|
|
}
|
|
|
|
|
2012-06-16 00:25:50 +04:00
|
|
|
// We can end up here in all sorts of compartments, per above. Make
|
|
|
|
// sure to JS_WrapValue!
|
2013-06-08 06:45:46 +04:00
|
|
|
rval.set(JS::ObjectValue(*obj));
|
2015-05-05 20:38:56 +03:00
|
|
|
return MaybeWrapObjectValue(cx, rval);
|
2012-06-16 00:25:50 +04:00
|
|
|
}
|
|
|
|
|
2014-11-01 17:00:47 +03:00
|
|
|
// Helper for smart pointers (nsRefPtr/nsCOMPtr).
|
|
|
|
template <template <typename> class SmartPtr, typename T,
|
2016-02-10 01:40:31 +03:00
|
|
|
typename U=typename EnableIf<IsRefcounted<T>::value, T>::Type,
|
|
|
|
typename V=typename EnableIf<IsSmartPtr<SmartPtr<T>>::value, T>::Type>
|
2012-06-16 00:25:50 +04:00
|
|
|
inline bool
|
2013-04-25 20:29:53 +04:00
|
|
|
WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
|
2013-06-08 06:45:46 +04:00
|
|
|
const SmartPtr<T>& value,
|
2015-07-31 20:30:55 +03:00
|
|
|
JS::MutableHandle<JS::Value> rval,
|
|
|
|
JS::Handle<JSObject*> givenProto = nullptr)
|
2012-06-16 00:25:50 +04:00
|
|
|
{
|
2015-07-31 20:30:55 +03:00
|
|
|
return WrapNewBindingNonWrapperCachedObject(cx, scope, value.get(), rval,
|
|
|
|
givenProto);
|
2012-06-16 00:25:50 +04:00
|
|
|
}
|
|
|
|
|
2016-02-10 01:40:31 +03:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2012-07-18 14:36:08 +04:00
|
|
|
template<bool Fatal>
|
|
|
|
inline bool
|
2016-08-14 14:39:30 +03:00
|
|
|
EnumValueNotFound(JSContext* cx, JS::HandleString str, const char* type,
|
|
|
|
const char* sourceDescription);
|
2012-07-18 14:36:08 +04:00
|
|
|
|
|
|
|
template<>
|
|
|
|
inline bool
|
2016-08-14 14:39:30 +03:00
|
|
|
EnumValueNotFound<false>(JSContext* cx, JS::HandleString str, const char* type,
|
2014-07-02 17:45:04 +04:00
|
|
|
const char* sourceDescription)
|
2012-07-18 14:36:08 +04:00
|
|
|
{
|
|
|
|
// TODO: Log a warning to the console.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
|
|
|
inline bool
|
2016-08-14 14:39:30 +03:00
|
|
|
EnumValueNotFound<true>(JSContext* cx, JS::HandleString str, const char* type,
|
2014-07-02 17:45:04 +04:00
|
|
|
const char* sourceDescription)
|
2012-07-18 14:36:08 +04:00
|
|
|
{
|
2018-09-05 12:25:42 +03:00
|
|
|
JS::UniqueChars deflated = JS_EncodeStringToUTF8(cx, str);
|
|
|
|
if (!deflated) {
|
2014-07-02 17:45:04 +04:00
|
|
|
return false;
|
|
|
|
}
|
2013-06-17 21:07:03 +04:00
|
|
|
return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, sourceDescription,
|
2018-09-05 12:25:42 +03:00
|
|
|
deflated.get(), type);
|
2012-07-18 14:36:08 +04:00
|
|
|
}
|
|
|
|
|
2014-07-02 17:45:04 +04:00
|
|
|
template<typename CharT>
|
2012-03-31 08:42:20 +04:00
|
|
|
inline int
|
2014-07-02 17:45:04 +04:00
|
|
|
FindEnumStringIndexImpl(const CharT* chars, size_t length, const EnumEntry* values)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-02 17:45:04 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<bool InvalidValueFatal>
|
2016-09-30 23:11:41 +03:00
|
|
|
inline bool
|
2014-07-02 17:45:04 +04:00
|
|
|
FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* values,
|
2016-09-30 23:11:41 +03:00
|
|
|
const char* type, const char* sourceDescription, int* index)
|
2014-07-02 17:45:04 +04:00
|
|
|
{
|
|
|
|
// JS_StringEqualsAscii is slow as molasses, so don't use it here.
|
2016-08-14 14:39:30 +03:00
|
|
|
JS::RootedString str(cx, JS::ToString(cx, v));
|
2014-07-02 17:45:04 +04:00
|
|
|
if (!str) {
|
2016-09-30 23:11:41 +03:00
|
|
|
return false;
|
2014-07-02 17:45:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
size_t length;
|
|
|
|
JS::AutoCheckCannotGC nogc;
|
2014-07-03 15:05:03 +04:00
|
|
|
if (js::StringHasLatin1Chars(str)) {
|
2014-07-02 17:45:04 +04:00
|
|
|
const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str,
|
|
|
|
&length);
|
|
|
|
if (!chars) {
|
2016-09-30 23:11:41 +03:00
|
|
|
return false;
|
2014-07-02 17:45:04 +04:00
|
|
|
}
|
2016-09-30 23:11:41 +03:00
|
|
|
*index = FindEnumStringIndexImpl(chars, length, values);
|
2014-07-02 17:45:04 +04:00
|
|
|
} else {
|
2014-07-22 08:43:21 +04:00
|
|
|
const char16_t* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, str,
|
|
|
|
&length);
|
2014-07-02 17:45:04 +04:00
|
|
|
if (!chars) {
|
2016-09-30 23:11:41 +03:00
|
|
|
return false;
|
2014-07-02 17:45:04 +04:00
|
|
|
}
|
2016-09-30 23:11:41 +03:00
|
|
|
*index = FindEnumStringIndexImpl(chars, length, values);
|
2014-07-02 17:45:04 +04:00
|
|
|
}
|
2016-09-30 23:11:41 +03:00
|
|
|
if (*index >= 0) {
|
|
|
|
return true;
|
2014-07-02 17:45:04 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-30 23:11:41 +03:00
|
|
|
return EnumValueNotFound<InvalidValueFatal>(cx, str, type, sourceDescription);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2012-05-10 23:24:59 +04:00
|
|
|
inline nsWrapperCache*
|
|
|
|
GetWrapperCache(const ParentObject& aParentObject)
|
|
|
|
{
|
|
|
|
return aParentObject.mWrapperCache;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
2012-10-09 22:50:26 +04:00
|
|
|
inline T*
|
2012-05-10 23:24:59 +04:00
|
|
|
GetParentPointer(T* aObject)
|
|
|
|
{
|
2012-10-09 22:50:26 +04:00
|
|
|
return aObject;
|
2012-05-10 23:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline nsISupports*
|
|
|
|
GetParentPointer(const ParentObject& aObject)
|
|
|
|
{
|
2012-10-09 22:50:26 +04:00
|
|
|
return aObject.mObject;
|
2012-05-10 23:24:59 +04:00
|
|
|
}
|
|
|
|
|
2014-03-19 20:35:45 +04:00
|
|
|
template <typename T>
|
2018-06-29 23:39:46 +03:00
|
|
|
inline mozilla::dom::ReflectionScope
|
|
|
|
GetReflectionScope(T* aParentObject)
|
2014-03-19 20:35:45 +04:00
|
|
|
{
|
2018-06-29 23:39:46 +03:00
|
|
|
return mozilla::dom::ReflectionScope::Content;
|
2014-03-19 20:35:45 +04:00
|
|
|
}
|
|
|
|
|
2018-06-29 23:39:46 +03:00
|
|
|
inline mozilla::dom::ReflectionScope
|
|
|
|
GetReflectionScope(const ParentObject& aParentObject)
|
2014-03-19 20:35:45 +04:00
|
|
|
{
|
2018-06-29 23:39:46 +03:00
|
|
|
return aParentObject.mReflectionScope;
|
2014-03-19 20:35:45 +04:00
|
|
|
}
|
|
|
|
|
2012-05-22 17:46:20 +04:00
|
|
|
template<class T>
|
|
|
|
inline void
|
2017-04-26 13:18:39 +03:00
|
|
|
ClearWrapper(T* p, nsWrapperCache* cache, JSObject* obj)
|
2012-05-22 17:46:20 +04:00
|
|
|
{
|
2017-04-26 13:18:39 +03:00
|
|
|
JS::AutoAssertGCCallback inCallback;
|
2018-07-31 22:28:39 +03:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
2012-05-22 17:46:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
inline void
|
2017-04-26 13:18:39 +03:00
|
|
|
ClearWrapper(T* p, void*, JSObject* obj)
|
2012-05-22 17:46:20 +04:00
|
|
|
{
|
2017-04-26 13:18:39 +03:00
|
|
|
JS::AutoAssertGCCallback inCallback;
|
2018-07-31 22:28:39 +03:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
2012-05-22 17:46:20 +04:00
|
|
|
}
|
|
|
|
|
2014-09-17 18:35:11 +04:00
|
|
|
template<class T>
|
|
|
|
inline void
|
|
|
|
UpdateWrapper(T* p, nsWrapperCache* cache, JSObject* obj, const JSObject* old)
|
|
|
|
{
|
2017-04-25 12:56:34 +03:00
|
|
|
JS::AutoAssertGCCallback inCallback;
|
2014-09-17 18:35:11 +04:00
|
|
|
cache->UpdateWrapper(obj, old);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
inline void
|
|
|
|
UpdateWrapper(T* p, void*, JSObject* obj, const JSObject* old)
|
|
|
|
{
|
2017-04-25 12:56:34 +03:00
|
|
|
JS::AutoAssertGCCallback inCallback;
|
2014-09-17 18:35:11 +04:00
|
|
|
nsWrapperCache* cache;
|
|
|
|
CallQueryInterface(p, &cache);
|
|
|
|
UpdateWrapper(p, cache, obj, old);
|
|
|
|
}
|
|
|
|
|
2012-11-09 22:59:02 +04:00
|
|
|
// 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
|
2018-09-21 21:20:33 +03:00
|
|
|
TryPreserveWrapper(JS::Handle<JSObject*> obj);
|
2012-11-09 22:59:02 +04:00
|
|
|
|
2014-05-20 00:37:59 +04:00
|
|
|
// Can only be called with a DOM JSClass.
|
2013-08-09 02:53:04 +04:00
|
|
|
bool
|
2014-05-20 00:37:59 +04:00
|
|
|
InstanceClassHasProtoAtDepth(const js::Class* clasp,
|
|
|
|
uint32_t protoID, uint32_t depth);
|
2012-08-08 09:26:18 +04:00
|
|
|
|
2018-04-05 18:22:41 +03:00
|
|
|
// Only set allowNativeWrapper to false if you really know you need it; if in
|
2012-03-31 08:42:20 +04:00
|
|
|
// doubt use true. Setting it to false disables security wrappers.
|
|
|
|
bool
|
2013-04-30 01:33:42 +04:00
|
|
|
XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
|
|
|
|
xpcObjectHelper& helper, const nsIID* iid,
|
2013-10-12 09:02:39 +04:00
|
|
|
bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval);
|
2012-03-31 08:42:20 +04:00
|
|
|
|
2013-04-04 06:22:16 +04:00
|
|
|
// Special-cased wrapping for variants
|
|
|
|
bool
|
2014-04-10 08:58:43 +04:00
|
|
|
VariantToJsval(JSContext* aCx, nsIVariant* aVariant,
|
|
|
|
JS::MutableHandle<JS::Value> aRetval);
|
2013-04-04 06:22:16 +04:00
|
|
|
|
2012-11-09 20:24:32 +04:00
|
|
|
// 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
|
2014-11-26 22:25:20 +03:00
|
|
|
// much slower than GetOrCreateDOMReflector. "cache" must either be null or be
|
|
|
|
// the nsWrapperCache for "p".
|
2012-03-31 08:42:20 +04:00
|
|
|
template<class T>
|
|
|
|
inline bool
|
2014-04-10 08:58:43 +04:00
|
|
|
WrapObject(JSContext* cx, T* p, nsWrapperCache* cache, const nsIID* iid,
|
2013-06-08 06:45:46 +04:00
|
|
|
JS::MutableHandle<JS::Value> rval)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
2014-04-10 08:58:42 +04:00
|
|
|
if (xpc_FastGetCachedWrapper(cx, cache, rval))
|
2012-03-31 08:42:20 +04:00
|
|
|
return true;
|
2018-05-02 12:47:02 +03:00
|
|
|
xpcObjectHelper helper(ToSupports(p), cache);
|
2014-04-10 08:58:43 +04:00
|
|
|
JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
|
2013-10-12 09:02:39 +04:00
|
|
|
return XPCOMObjectToJsval(cx, scope, helper, iid, true, rval);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2013-04-04 06:22:16 +04:00
|
|
|
// A specialization of the above for nsIVariant, because that needs to
|
|
|
|
// do something different.
|
|
|
|
template<>
|
|
|
|
inline bool
|
2014-04-10 08:58:43 +04:00
|
|
|
WrapObject<nsIVariant>(JSContext* cx, nsIVariant* p,
|
2013-06-08 06:45:46 +04:00
|
|
|
nsWrapperCache* cache, const nsIID* iid,
|
|
|
|
JS::MutableHandle<JS::Value> rval)
|
2013-04-04 06:22:16 +04:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(iid);
|
|
|
|
MOZ_ASSERT(iid->Equals(NS_GET_IID(nsIVariant)));
|
2014-04-10 08:58:43 +04:00
|
|
|
return VariantToJsval(cx, p, rval);
|
2013-04-04 06:22:16 +04:00
|
|
|
}
|
|
|
|
|
2012-11-09 20:24:32 +04:00
|
|
|
// 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".
|
2012-03-31 08:42:20 +04:00
|
|
|
template<class T>
|
|
|
|
inline bool
|
2014-04-10 08:58:43 +04:00
|
|
|
WrapObject(JSContext* cx, T* p, const nsIID* iid,
|
2013-06-08 06:45:46 +04:00
|
|
|
JS::MutableHandle<JS::Value> rval)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
2014-04-10 08:58:43 +04:00
|
|
|
return WrapObject(cx, p, GetWrapperCache(p), iid, rval);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2012-11-09 20:24:32 +04:00
|
|
|
// 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.
|
2012-03-31 08:42:20 +04:00
|
|
|
template<class T>
|
|
|
|
inline bool
|
2014-04-10 08:58:43 +04:00
|
|
|
WrapObject(JSContext* cx, T* p, JS::MutableHandle<JS::Value> rval)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
2014-04-10 08:58:43 +04:00
|
|
|
return WrapObject(cx, p, nullptr, rval);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2012-11-09 20:24:32 +04:00
|
|
|
// Helper to make it possible to wrap directly out of an nsCOMPtr
|
2012-03-31 08:42:20 +04:00
|
|
|
template<class T>
|
|
|
|
inline bool
|
2014-04-10 08:58:43 +04:00
|
|
|
WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
|
2013-06-08 06:45:46 +04:00
|
|
|
const nsIID* iid, JS::MutableHandle<JS::Value> rval)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
2014-04-10 08:58:43 +04:00
|
|
|
return WrapObject(cx, p.get(), iid, rval);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2012-11-09 20:24:32 +04:00
|
|
|
// Helper to make it possible to wrap directly out of an nsCOMPtr
|
2012-03-31 08:42:20 +04:00
|
|
|
template<class T>
|
|
|
|
inline bool
|
2014-04-10 08:58:43 +04:00
|
|
|
WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
|
2013-06-08 06:45:46 +04:00
|
|
|
JS::MutableHandle<JS::Value> rval)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
2014-04-10 08:58:43 +04:00
|
|
|
return WrapObject(cx, p, nullptr, rval);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2012-11-09 20:24:32 +04:00
|
|
|
// Helper to make it possible to wrap directly out of an nsRefPtr
|
2012-03-31 08:42:20 +04:00
|
|
|
template<class T>
|
|
|
|
inline bool
|
2015-10-18 08:24:48 +03:00
|
|
|
WrapObject(JSContext* cx, const RefPtr<T>& p,
|
2013-06-08 06:45:46 +04:00
|
|
|
const nsIID* iid, JS::MutableHandle<JS::Value> rval)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
2014-04-10 08:58:43 +04:00
|
|
|
return WrapObject(cx, p.get(), iid, rval);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2012-11-09 20:24:32 +04:00
|
|
|
// Helper to make it possible to wrap directly out of an nsRefPtr
|
2012-03-31 08:42:20 +04:00
|
|
|
template<class T>
|
|
|
|
inline bool
|
2015-10-18 08:24:48 +03:00
|
|
|
WrapObject(JSContext* cx, const RefPtr<T>& p,
|
2013-06-08 06:45:46 +04:00
|
|
|
JS::MutableHandle<JS::Value> rval)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
2014-04-10 08:58:43 +04:00
|
|
|
return WrapObject(cx, p, nullptr, rval);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2012-11-09 20:24:32 +04:00
|
|
|
// Specialization to make it easy to use WrapObject in codegen.
|
2012-03-31 08:42:20 +04:00
|
|
|
template<>
|
|
|
|
inline bool
|
2014-04-10 08:58:43 +04:00
|
|
|
WrapObject<JSObject>(JSContext* cx, JSObject* p,
|
2013-06-08 06:45:46 +04:00
|
|
|
JS::MutableHandle<JS::Value> rval)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
2013-06-08 06:45:46 +04:00
|
|
|
rval.set(JS::ObjectOrNullValue(p));
|
2012-03-31 08:42:20 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-09 15:34:29 +04:00
|
|
|
inline bool
|
2014-04-10 08:58:43 +04:00
|
|
|
WrapObject(JSContext* cx, JSObject& p, JS::MutableHandle<JS::Value> rval)
|
2013-03-09 15:34:29 +04:00
|
|
|
{
|
2013-06-08 06:45:46 +04:00
|
|
|
rval.set(JS::ObjectValue(p));
|
2013-03-09 15:34:29 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-11-09 20:24:32 +04:00
|
|
|
// 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.
|
2012-10-19 11:33:18 +04:00
|
|
|
template<typename T>
|
|
|
|
static inline JSObject*
|
2016-07-27 18:05:36 +03:00
|
|
|
WrapNativeISupports(JSContext* cx, T* p, nsWrapperCache* cache)
|
2012-10-19 11:33:18 +04:00
|
|
|
{
|
2018-05-02 12:47:02 +03:00
|
|
|
xpcObjectHelper helper(ToSupports(p), cache);
|
2014-04-09 02:27:15 +04:00
|
|
|
JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
|
2013-05-04 03:29:09 +04:00
|
|
|
JS::Rooted<JS::Value> v(cx);
|
2013-10-12 09:02:39 +04:00
|
|
|
return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, &v) ?
|
|
|
|
v.toObjectOrNull() :
|
2012-10-19 11:33:18 +04:00
|
|
|
nullptr;
|
|
|
|
}
|
|
|
|
|
2012-11-09 20:24:32 +04:00
|
|
|
|
2018-04-05 18:22:41 +03:00
|
|
|
// Wrapping of our native parent, for cases when it's a WebIDL object.
|
2014-11-01 16:04:43 +03:00
|
|
|
template<typename T, bool hasWrapObject=NativeHasMember<T>::WrapObject>
|
2016-07-27 18:05:36 +03:00
|
|
|
struct WrapNativeHelper
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
2014-04-09 02:27:15 +04:00
|
|
|
static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
|
2012-10-09 22:50:26 +04:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(cache);
|
2012-03-31 08:42:20 +04:00
|
|
|
|
2012-10-09 22:50:26 +04:00
|
|
|
JSObject* obj;
|
|
|
|
if ((obj = cache->GetWrapper())) {
|
2016-07-27 18:05:36 +03:00
|
|
|
// GetWrapper always unmarks gray.
|
2017-03-02 13:22:47 +03:00
|
|
|
MOZ_ASSERT(JS::ObjectIsNotGray(obj));
|
2012-10-09 22:50:26 +04:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2018-04-05 18:22:41 +03:00
|
|
|
// WrapObject never returns a gray thing.
|
|
|
|
obj = parent->WrapObject(cx, nullptr);
|
|
|
|
MOZ_ASSERT(JS::ObjectIsNotGray(obj));
|
2012-11-27 13:20:04 +04:00
|
|
|
|
2012-10-19 11:33:18 +04:00
|
|
|
return obj;
|
2012-10-09 22:50:26 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-11-09 20:24:32 +04:00
|
|
|
// Wrapping of our native parent, for cases when it's not a WebIDL object. In
|
|
|
|
// this case it must be nsISupports.
|
2012-10-09 22:50:26 +04:00
|
|
|
template<typename T>
|
2016-07-27 18:05:36 +03:00
|
|
|
struct WrapNativeHelper<T, false>
|
2012-10-09 22:50:26 +04:00
|
|
|
{
|
2014-04-09 02:27:15 +04:00
|
|
|
static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
|
2012-10-09 22:50:26 +04:00
|
|
|
{
|
|
|
|
JSObject* obj;
|
|
|
|
if (cache && (obj = cache->GetWrapper())) {
|
2012-03-31 08:42:20 +04:00
|
|
|
#ifdef DEBUG
|
2015-05-07 19:51:06 +03:00
|
|
|
JS::Rooted<JSObject*> rootedObj(cx, obj);
|
2016-07-27 18:05:36 +03:00
|
|
|
NS_ASSERTION(WrapNativeISupports(cx, parent, cache) == rootedObj,
|
2012-10-09 22:50:26 +04:00
|
|
|
"Unexpected object in nsWrapperCache");
|
2015-05-07 19:51:06 +03:00
|
|
|
obj = rootedObj;
|
2012-03-31 08:42:20 +04:00
|
|
|
#endif
|
2017-03-02 13:22:47 +03:00
|
|
|
MOZ_ASSERT(JS::ObjectIsNotGray(obj));
|
2012-10-09 22:50:26 +04:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2016-07-27 18:05:36 +03:00
|
|
|
obj = WrapNativeISupports(cx, parent, cache);
|
2017-03-02 13:22:47 +03:00
|
|
|
MOZ_ASSERT(JS::ObjectIsNotGray(obj));
|
2016-07-27 18:05:36 +03:00
|
|
|
return obj;
|
2012-10-09 22:50:26 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-07-27 18:05:36 +03:00
|
|
|
// Finding the associated global for an object.
|
2012-10-09 22:50:26 +04:00
|
|
|
template<typename T>
|
|
|
|
static inline JSObject*
|
2016-07-27 18:05:36 +03:00
|
|
|
FindAssociatedGlobal(JSContext* cx, T* p, nsWrapperCache* cache,
|
2018-06-29 23:39:46 +03:00
|
|
|
mozilla::dom::ReflectionScope scope = mozilla::dom::ReflectionScope::Content)
|
2012-10-09 22:50:26 +04:00
|
|
|
{
|
|
|
|
if (!p) {
|
2014-04-09 02:27:15 +04:00
|
|
|
return JS::CurrentGlobalOrNull(cx);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2016-07-27 18:05:36 +03:00
|
|
|
JSObject* obj = WrapNativeHelper<T>::Wrap(cx, p, cache);
|
2016-07-27 18:05:36 +03:00
|
|
|
if (!obj) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2017-03-02 13:22:47 +03:00
|
|
|
MOZ_ASSERT(JS::ObjectIsNotGray(obj));
|
2016-07-27 18:05:36 +03:00
|
|
|
|
2018-07-12 13:14:38 +03:00
|
|
|
// The object is never a CCW but it may not be in the current compartment of
|
|
|
|
// the JSContext.
|
|
|
|
obj = JS::GetNonCCWObjectGlobal(obj);
|
2016-07-27 18:05:36 +03:00
|
|
|
|
2018-06-29 23:39:46 +03:00
|
|
|
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;
|
|
|
|
}
|
2014-03-19 20:35:45 +04:00
|
|
|
|
2018-06-29 23:39:46 +03:00
|
|
|
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;
|
2014-03-19 20:35:45 +04:00
|
|
|
}
|
2018-06-29 23:39:46 +03:00
|
|
|
|
|
|
|
MOZ_CRASH("Unknown ReflectionScope variant");
|
|
|
|
|
|
|
|
return nullptr;
|
2012-10-09 22:50:26 +04:00
|
|
|
}
|
|
|
|
|
2016-07-27 18:05:36 +03:00
|
|
|
// Finding of the associated global for an object, when we don't want to
|
|
|
|
// explicitly pass in things like the nsWrapperCache for it.
|
2012-10-09 22:50:26 +04:00
|
|
|
template<typename T>
|
|
|
|
static inline JSObject*
|
2016-07-27 18:05:36 +03:00
|
|
|
FindAssociatedGlobal(JSContext* cx, const T& p)
|
2012-10-09 22:50:26 +04:00
|
|
|
{
|
2018-06-29 23:39:46 +03:00
|
|
|
return FindAssociatedGlobal(cx, GetParentPointer(p), GetWrapperCache(p), GetReflectionScope(p));
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2015-02-23 18:03:40 +03:00
|
|
|
// Specialization for the case of nsIGlobalObject, since in that case
|
|
|
|
// we can just get the JSObject* directly.
|
|
|
|
template<>
|
|
|
|
inline JSObject*
|
2016-07-27 18:05:36 +03:00
|
|
|
FindAssociatedGlobal(JSContext* cx, nsIGlobalObject* const& p)
|
2015-02-23 18:03:40 +03:00
|
|
|
{
|
2016-07-27 18:05:36 +03:00
|
|
|
if (!p) {
|
|
|
|
return JS::CurrentGlobalOrNull(cx);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObject* global = p->GetGlobalJSObject();
|
|
|
|
if (!global) {
|
2018-08-08 09:07:47 +03:00
|
|
|
// nsIGlobalObject doesn't have a JS object anymore,
|
|
|
|
// fallback to the current global.
|
|
|
|
return JS::CurrentGlobalOrNull(cx);
|
2016-07-27 18:05:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2015-02-23 18:03:40 +03:00
|
|
|
}
|
|
|
|
|
2016-07-27 18:05:36 +03:00
|
|
|
template<typename T,
|
|
|
|
bool hasAssociatedGlobal=NativeHasMember<T>::GetParentObject>
|
|
|
|
struct FindAssociatedGlobalForNative
|
2012-09-26 18:17:46 +04:00
|
|
|
{
|
2013-04-25 20:29:53 +04:00
|
|
|
static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
|
2012-09-26 18:17:46 +04:00
|
|
|
{
|
2014-04-09 02:27:15 +04:00
|
|
|
MOZ_ASSERT(js::IsObjectInContextCompartment(obj, cx));
|
2012-09-26 18:17:46 +04:00
|
|
|
T* native = UnwrapDOMObject<T>(obj);
|
2016-07-27 18:05:36 +03:00
|
|
|
return FindAssociatedGlobal(cx, native->GetParentObject());
|
2012-09-26 18:17:46 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T>
|
2016-07-27 18:05:36 +03:00
|
|
|
struct FindAssociatedGlobalForNative<T, false>
|
2012-09-26 18:17:46 +04:00
|
|
|
{
|
2013-04-25 20:29:53 +04:00
|
|
|
static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
|
2012-09-26 18:17:46 +04:00
|
|
|
{
|
|
|
|
MOZ_CRASH();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-11-26 22:25:20 +03:00
|
|
|
// Helper for calling GetOrCreateDOMReflector with smart pointers
|
2012-11-09 19:43:58 +04:00
|
|
|
// (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
|
2014-11-01 16:04:43 +03:00
|
|
|
template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
|
2014-11-26 22:25:20 +03:00
|
|
|
struct GetOrCreateDOMReflectorHelper
|
2012-11-09 19:43:58 +04:00
|
|
|
{
|
2014-11-26 22:25:20 +03:00
|
|
|
static inline bool GetOrCreate(JSContext* cx, const T& value,
|
2015-07-31 20:30:55 +03:00
|
|
|
JS::Handle<JSObject*> givenProto,
|
2014-11-26 22:25:20 +03:00
|
|
|
JS::MutableHandle<JS::Value> rval)
|
2012-11-09 19:43:58 +04:00
|
|
|
{
|
2015-07-31 20:30:55 +03:00
|
|
|
return GetOrCreateDOMReflector(cx, value.get(), rval, givenProto);
|
2012-11-09 19:43:58 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
2014-11-26 22:25:20 +03:00
|
|
|
struct GetOrCreateDOMReflectorHelper<T, false>
|
2012-11-09 19:43:58 +04:00
|
|
|
{
|
2014-11-26 22:25:20 +03:00
|
|
|
static inline bool GetOrCreate(JSContext* cx, T& value,
|
2015-07-31 20:30:55 +03:00
|
|
|
JS::Handle<JSObject*> givenProto,
|
2014-11-26 22:25:20 +03:00
|
|
|
JS::MutableHandle<JS::Value> rval)
|
2012-11-09 19:43:58 +04:00
|
|
|
{
|
2014-11-01 17:00:47 +03:00
|
|
|
static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
|
2015-07-31 20:30:55 +03:00
|
|
|
return GetOrCreateDOMReflector(cx, &value, rval, givenProto);
|
2012-11-09 19:43:58 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-04-09 02:27:19 +04:00
|
|
|
template<class T>
|
|
|
|
inline bool
|
2014-11-26 22:25:20 +03:00
|
|
|
GetOrCreateDOMReflector(JSContext* cx, T& value,
|
2015-07-31 20:30:55 +03:00
|
|
|
JS::MutableHandle<JS::Value> rval,
|
|
|
|
JS::Handle<JSObject*> givenProto = nullptr)
|
2014-04-09 02:27:19 +04:00
|
|
|
{
|
2015-07-31 20:30:55 +03:00
|
|
|
return GetOrCreateDOMReflectorHelper<T>::GetOrCreate(cx, value, givenProto,
|
|
|
|
rval);
|
2012-11-09 19:43:58 +04:00
|
|
|
}
|
|
|
|
|
2014-11-26 22:25:21 +03:00
|
|
|
// Helper for calling GetOrCreateDOMReflectorNoWrap with smart pointers
|
|
|
|
// (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
|
2014-11-01 16:04:43 +03:00
|
|
|
template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
|
2014-11-26 22:25:21 +03:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-01-28 17:34:31 +04:00
|
|
|
template <class T>
|
|
|
|
inline JSObject*
|
2017-09-05 03:21:06 +03:00
|
|
|
GetCallbackFromCallbackObject(JSContext* aCx, T* aObj)
|
2013-01-28 17:34:31 +04:00
|
|
|
{
|
2017-09-05 03:21:06 +03:00
|
|
|
return aObj->Callback(aCx);
|
2013-01-28 17:34:31 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Helper for getting the callback JSObject* of a smart ptr around a
|
|
|
|
// CallbackObject or a reference to a CallbackObject or something like
|
|
|
|
// that.
|
2014-11-01 16:04:43 +03:00
|
|
|
template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
|
2013-01-28 17:34:31 +04:00
|
|
|
struct GetCallbackFromCallbackObjectHelper
|
|
|
|
{
|
2017-09-05 03:21:06 +03:00
|
|
|
static inline JSObject* Get(JSContext* aCx, const T& aObj)
|
2013-01-28 17:34:31 +04:00
|
|
|
{
|
2017-09-05 03:21:06 +03:00
|
|
|
return GetCallbackFromCallbackObject(aCx, aObj.get());
|
2013-01-28 17:34:31 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
struct GetCallbackFromCallbackObjectHelper<T, false>
|
|
|
|
{
|
2017-09-05 03:21:06 +03:00
|
|
|
static inline JSObject* Get(JSContext* aCx, T& aObj)
|
2013-01-28 17:34:31 +04:00
|
|
|
{
|
2017-09-05 03:21:06 +03:00
|
|
|
return GetCallbackFromCallbackObject(aCx, &aObj);
|
2013-01-28 17:34:31 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
inline JSObject*
|
2017-09-05 03:21:06 +03:00
|
|
|
GetCallbackFromCallbackObject(JSContext* aCx, T& aObj)
|
2013-01-28 17:34:31 +04:00
|
|
|
{
|
2017-09-05 03:21:06 +03:00
|
|
|
return GetCallbackFromCallbackObjectHelper<T>::Get(aCx, aObj);
|
2013-01-28 17:34:31 +04:00
|
|
|
}
|
|
|
|
|
2012-06-12 18:22:05 +04:00
|
|
|
static inline bool
|
2015-06-30 17:58:31 +03:00
|
|
|
AtomizeAndPinJSString(JSContext* cx, jsid& id, const char* chars)
|
2012-06-12 18:22:05 +04:00
|
|
|
{
|
2015-06-30 17:58:31 +03:00
|
|
|
if (JSString *str = ::JS_AtomizeAndPinString(cx, chars)) {
|
2012-06-12 18:22:05 +04:00
|
|
|
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);
|
2012-03-31 08:42:20 +04:00
|
|
|
|
2013-08-02 11:41:57 +04:00
|
|
|
bool
|
2012-03-31 08:42:20 +04:00
|
|
|
QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
|
2013-07-04 19:24:59 +04:00
|
|
|
|
|
|
|
template <class T>
|
|
|
|
struct
|
2013-09-24 23:37:53 +04:00
|
|
|
WantsQueryInterface
|
2013-07-04 19:24:59 +04:00
|
|
|
{
|
2013-09-24 23:37:53 +04:00
|
|
|
static_assert(IsBaseOf<nsISupports, T>::value,
|
|
|
|
"QueryInterface can't work without an nsISupports.");
|
2013-07-04 19:24:59 +04:00
|
|
|
static bool Enabled(JSContext* aCx, JSObject* aGlobal)
|
|
|
|
{
|
2013-09-10 22:27:32 +04:00
|
|
|
return NS_IsMainThread() && IsChromeOrXBL(aCx, aGlobal);
|
2013-07-04 19:24:59 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-06-12 00:26:52 +04:00
|
|
|
void
|
2014-02-16 01:12:33 +04:00
|
|
|
GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
|
2014-06-12 00:26:52 +04:00
|
|
|
nsWrapperCache* aCache, nsIJSID* aIID,
|
|
|
|
JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError);
|
2014-02-16 01:12:33 +04:00
|
|
|
|
|
|
|
template<class T>
|
2014-06-12 00:26:52 +04:00
|
|
|
void
|
|
|
|
GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID,
|
|
|
|
JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
|
2014-02-16 01:12:33 +04:00
|
|
|
{
|
2014-06-12 00:26:52 +04:00
|
|
|
GetInterfaceImpl(aCx, aThis, aThis, aIID, aRetval, aError);
|
2014-02-16 01:12:33 +04:00
|
|
|
}
|
|
|
|
|
2013-08-02 11:41:57 +04:00
|
|
|
bool
|
2012-05-03 08:35:38 +04:00
|
|
|
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
|
2012-03-31 08:42:20 +04:00
|
|
|
|
2014-03-11 01:38:31 +04:00
|
|
|
bool
|
|
|
|
ThrowConstructorWithoutNew(JSContext* cx, const char* name);
|
|
|
|
|
2012-05-22 17:46:20 +04:00
|
|
|
bool
|
2013-05-04 03:29:08 +04:00
|
|
|
GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
|
2015-09-18 01:14:41 +03:00
|
|
|
JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
|
|
|
|
bool* found, JS::MutableHandle<JS::Value> vp);
|
2012-05-22 17:46:20 +04:00
|
|
|
|
2015-01-02 23:02:36 +03:00
|
|
|
//
|
2012-05-22 17:46:20 +04:00
|
|
|
bool
|
2013-05-04 03:29:08 +04:00
|
|
|
HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
|
2015-01-02 23:02:36 +03:00
|
|
|
JS::Handle<jsid> id, bool* has);
|
2012-05-22 17:46:20 +04:00
|
|
|
|
2013-07-09 18:45:13 +04:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
2012-05-19 01:25:46 +04:00
|
|
|
enum StringificationBehavior {
|
|
|
|
eStringify,
|
|
|
|
eEmpty,
|
|
|
|
eNull
|
|
|
|
};
|
|
|
|
|
2014-01-23 13:18:35 +04:00
|
|
|
template<typename T>
|
2012-05-19 01:25:46 +04:00
|
|
|
static inline bool
|
2013-05-24 17:16:00 +04:00
|
|
|
ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
|
2012-05-19 01:25:46 +04:00
|
|
|
StringificationBehavior nullBehavior,
|
|
|
|
StringificationBehavior undefinedBehavior,
|
2014-01-23 13:18:35 +04:00
|
|
|
T& result)
|
2012-05-19 01:25:46 +04:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-07-31 08:22:23 +04:00
|
|
|
if (behavior != eStringify) {
|
2012-07-17 20:18:53 +04:00
|
|
|
if (behavior == eEmpty) {
|
|
|
|
result.Truncate();
|
|
|
|
} else {
|
2014-01-23 13:18:35 +04:00
|
|
|
result.SetIsVoid(true);
|
2012-07-17 20:18:53 +04:00
|
|
|
}
|
2012-05-19 01:25:46 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-11-16 16:31:36 +04:00
|
|
|
s = JS::ToString(cx, v);
|
2012-05-19 01:25:46 +04:00
|
|
|
if (!s) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-05 19:30:54 +04:00
|
|
|
return AssignJSString(cx, result, s);
|
2012-05-19 01:25:46 +04:00
|
|
|
}
|
|
|
|
|
2017-02-15 08:01:37 +03:00
|
|
|
template<typename T>
|
|
|
|
static inline bool
|
|
|
|
ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v, T& result)
|
|
|
|
{
|
|
|
|
return ConvertJSValueToString(cx, v, eStringify, eStringify, result);
|
|
|
|
}
|
|
|
|
|
2014-08-02 00:23:48 +04:00
|
|
|
void
|
2017-02-15 08:01:37 +03:00
|
|
|
NormalizeUSVString(nsAString& aString);
|
2014-08-02 00:23:48 +04:00
|
|
|
|
|
|
|
void
|
2017-02-15 08:01:37 +03:00
|
|
|
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;
|
|
|
|
}
|
2014-08-02 00:23:48 +04:00
|
|
|
|
2014-08-04 23:20:57 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-06-13 09:18:35 +04:00
|
|
|
bool
|
|
|
|
ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
|
2014-07-03 15:05:03 +04:00
|
|
|
bool nullable, nsACString& result);
|
2013-06-13 09:18:35 +04:00
|
|
|
|
2017-02-15 08:01:37 +03:00
|
|
|
inline bool
|
|
|
|
ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
|
|
|
|
nsACString& result)
|
|
|
|
{
|
|
|
|
return ConvertJSValueToByteString(cx, v, false, result);
|
|
|
|
}
|
|
|
|
|
2013-05-16 20:36:55 +04:00
|
|
|
template<typename T>
|
|
|
|
void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
|
2013-05-16 20:36:56 +04:00
|
|
|
template<typename T>
|
|
|
|
void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq);
|
2013-05-16 20:36:55 +04:00
|
|
|
|
|
|
|
// Class used to trace sequences, with specializations for various
|
|
|
|
// sequence types.
|
2013-08-05 21:40:02 +04:00
|
|
|
template<typename T,
|
|
|
|
bool isDictionary=IsBaseOf<DictionaryBase, T>::value,
|
2014-03-14 22:51:22 +04:00
|
|
|
bool isTypedArray=IsBaseOf<AllTypedArraysBase, T>::value,
|
|
|
|
bool isOwningUnion=IsBaseOf<AllOwningUnionBase, T>::value>
|
2013-05-16 20:36:55 +04:00
|
|
|
class SequenceTracer
|
|
|
|
{
|
2015-01-07 02:35:02 +03:00
|
|
|
explicit SequenceTracer() = delete; // Should never be instantiated
|
2013-05-16 20:36:55 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
// sequence<object> or sequence<object?>
|
|
|
|
template<>
|
2014-03-14 22:51:22 +04:00
|
|
|
class SequenceTracer<JSObject*, false, false, false>
|
2013-05-16 20:36:55 +04:00
|
|
|
{
|
2015-01-07 02:35:02 +03:00
|
|
|
explicit SequenceTracer() = delete; // Should never be instantiated
|
2013-05-16 20:36:55 +04:00
|
|
|
|
|
|
|
public:
|
|
|
|
static void TraceSequence(JSTracer* trc, JSObject** objp, JSObject** end) {
|
2013-08-05 21:40:02 +04:00
|
|
|
for (; objp != end; ++objp) {
|
2015-12-30 22:31:16 +03:00
|
|
|
JS::UnsafeTraceRoot(trc, objp, "sequence<object>");
|
2013-05-16 20:36:55 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// sequence<any>
|
|
|
|
template<>
|
2014-03-14 22:51:22 +04:00
|
|
|
class SequenceTracer<JS::Value, false, false, false>
|
2013-05-16 20:36:55 +04:00
|
|
|
{
|
2015-01-07 02:35:02 +03:00
|
|
|
explicit SequenceTracer() = delete; // Should never be instantiated
|
2013-05-16 20:36:55 +04:00
|
|
|
|
|
|
|
public:
|
|
|
|
static void TraceSequence(JSTracer* trc, JS::Value* valp, JS::Value* end) {
|
2013-08-05 21:40:02 +04:00
|
|
|
for (; valp != end; ++valp) {
|
2015-12-30 22:31:16 +03:00
|
|
|
JS::UnsafeTraceRoot(trc, valp, "sequence<any>");
|
2013-05-16 20:36:55 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// sequence<sequence<T>>
|
|
|
|
template<typename T>
|
2014-03-14 22:51:22 +04:00
|
|
|
class SequenceTracer<Sequence<T>, false, false, false>
|
2013-05-16 20:36:55 +04:00
|
|
|
{
|
2015-01-07 02:35:02 +03:00
|
|
|
explicit SequenceTracer() = delete; // Should never be instantiated
|
2013-05-16 20:36:55 +04:00
|
|
|
|
|
|
|
public:
|
|
|
|
static void TraceSequence(JSTracer* trc, Sequence<T>* seqp, Sequence<T>* end) {
|
2013-08-05 21:40:02 +04:00
|
|
|
for (; seqp != end; ++seqp) {
|
2013-05-16 20:36:55 +04:00
|
|
|
DoTraceSequence(trc, *seqp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-05-16 20:36:56 +04:00
|
|
|
// sequence<sequence<T>> as return value
|
|
|
|
template<typename T>
|
2014-03-14 22:51:22 +04:00
|
|
|
class SequenceTracer<nsTArray<T>, false, false, false>
|
2013-05-16 20:36:56 +04:00
|
|
|
{
|
2015-01-07 02:35:02 +03:00
|
|
|
explicit SequenceTracer() = delete; // Should never be instantiated
|
2013-05-16 20:36:56 +04:00
|
|
|
|
|
|
|
public:
|
|
|
|
static void TraceSequence(JSTracer* trc, nsTArray<T>* seqp, nsTArray<T>* end) {
|
2013-08-05 21:40:02 +04:00
|
|
|
for (; seqp != end; ++seqp) {
|
2013-05-16 20:36:56 +04:00
|
|
|
DoTraceSequence(trc, *seqp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-05-16 20:36:55 +04:00
|
|
|
// sequence<someDictionary>
|
|
|
|
template<typename T>
|
2014-03-14 22:51:22 +04:00
|
|
|
class SequenceTracer<T, true, false, false>
|
2013-05-16 20:36:55 +04:00
|
|
|
{
|
2015-01-07 02:35:02 +03:00
|
|
|
explicit SequenceTracer() = delete; // Should never be instantiated
|
2013-05-16 20:36:55 +04:00
|
|
|
|
|
|
|
public:
|
|
|
|
static void TraceSequence(JSTracer* trc, T* dictp, T* end) {
|
2013-08-05 21:40:02 +04:00
|
|
|
for (; dictp != end; ++dictp) {
|
2013-05-16 20:36:55 +04:00
|
|
|
dictp->TraceDictionary(trc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-08-05 21:40:02 +04:00
|
|
|
// sequence<SomeTypedArray>
|
2013-05-16 20:36:55 +04:00
|
|
|
template<typename T>
|
2014-03-14 22:51:22 +04:00
|
|
|
class SequenceTracer<T, false, true, false>
|
2013-05-16 20:36:55 +04:00
|
|
|
{
|
2015-01-07 02:35:02 +03:00
|
|
|
explicit SequenceTracer() = delete; // Should never be instantiated
|
2013-05-16 20:36:55 +04:00
|
|
|
|
|
|
|
public:
|
2013-08-05 21:40:02 +04:00
|
|
|
static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
|
|
|
|
for (; arrayp != end; ++arrayp) {
|
|
|
|
arrayp->TraceSelf(trc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-03-14 22:51:22 +04:00
|
|
|
// sequence<SomeOwningUnion>
|
|
|
|
template<typename T>
|
|
|
|
class SequenceTracer<T, false, false, true>
|
|
|
|
{
|
2015-01-07 02:35:02 +03:00
|
|
|
explicit SequenceTracer() = delete; // Should never be instantiated
|
2014-03-14 22:51:22 +04:00
|
|
|
|
|
|
|
public:
|
|
|
|
static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
|
|
|
|
for (; arrayp != end; ++arrayp) {
|
|
|
|
arrayp->TraceUnion(trc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-08-05 21:40:02 +04:00
|
|
|
// sequence<T?> with T? being a Nullable<T>
|
|
|
|
template<typename T>
|
2014-03-14 22:51:22 +04:00
|
|
|
class SequenceTracer<Nullable<T>, false, false, false>
|
2013-08-05 21:40:02 +04:00
|
|
|
{
|
2015-01-07 02:35:02 +03:00
|
|
|
explicit SequenceTracer() = delete; // Should never be instantiated
|
2013-08-05 21:40:02 +04:00
|
|
|
|
|
|
|
public:
|
|
|
|
static void TraceSequence(JSTracer* trc, Nullable<T>* seqp,
|
|
|
|
Nullable<T>* end) {
|
|
|
|
for (; seqp != end; ++seqp) {
|
2013-05-16 20:36:55 +04:00
|
|
|
if (!seqp->IsNull()) {
|
2013-08-05 21:40:02 +04:00
|
|
|
// 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);
|
2013-05-16 20:36:55 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-02-15 08:01:35 +03:00
|
|
|
template<typename K, typename V>
|
|
|
|
void TraceRecord(JSTracer* trc, Record<K, V>& record)
|
2014-06-24 00:03:58 +04:00
|
|
|
{
|
2017-02-15 08:01:35 +03:00
|
|
|
for (auto& entry : record.Entries()) {
|
2017-02-15 08:00:00 +03:00
|
|
|
// Act like it's a one-element sequence to leverage all that infrastructure.
|
2017-02-15 08:01:35 +03:00
|
|
|
SequenceTracer<V>::TraceSequence(trc, &entry.mValue, &entry.mValue + 1);
|
2017-02-15 08:00:00 +03:00
|
|
|
}
|
2014-06-24 00:03:58 +04:00
|
|
|
}
|
|
|
|
|
2017-02-15 08:01:35 +03:00
|
|
|
// sequence<record>
|
|
|
|
template<typename K, typename V>
|
|
|
|
class SequenceTracer<Record<K, V>, false, false, false>
|
2014-05-24 01:32:38 +04:00
|
|
|
{
|
2015-01-07 02:35:02 +03:00
|
|
|
explicit SequenceTracer() = delete; // Should never be instantiated
|
2014-05-24 01:32:38 +04:00
|
|
|
|
|
|
|
public:
|
2017-02-15 08:01:35 +03:00
|
|
|
static void TraceSequence(JSTracer* trc, Record<K, V>* seqp,
|
|
|
|
Record<K, V>* end) {
|
2014-05-24 01:32:38 +04:00
|
|
|
for (; seqp != end; ++seqp) {
|
2017-02-15 08:01:35 +03:00
|
|
|
TraceRecord(trc, *seqp);
|
2014-05-24 01:32:38 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-05-16 20:36:55 +04:00
|
|
|
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>
|
2016-05-12 21:14:29 +03:00
|
|
|
class MOZ_RAII SequenceRooter final : private JS::CustomAutoRooter
|
2013-05-16 20:36:55 +04:00
|
|
|
{
|
|
|
|
public:
|
2013-05-18 05:48:25 +04:00
|
|
|
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)
|
2013-05-16 20:36:55 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-05-18 05:48:25 +04:00
|
|
|
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)
|
2013-05-16 20:36:55 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-05-18 05:48:25 +04:00
|
|
|
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)
|
2013-05-16 20:36:55 +04:00
|
|
|
{
|
2013-05-16 20:36:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2013-05-16 20:36:55 +04:00
|
|
|
enum SequenceType {
|
|
|
|
eInfallibleArray,
|
2013-05-16 20:36:56 +04:00
|
|
|
eFallibleArray,
|
|
|
|
eNullableArray
|
2013-05-16 20:36:55 +04:00
|
|
|
};
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
virtual void trace(JSTracer *trc) override
|
2013-05-16 20:36:55 +04:00
|
|
|
{
|
|
|
|
if (mSequenceType == eFallibleArray) {
|
|
|
|
DoTraceSequence(trc, *mFallibleArray);
|
|
|
|
} else if (mSequenceType == eInfallibleArray) {
|
|
|
|
DoTraceSequence(trc, *mInfallibleArray);
|
2013-05-18 05:48:25 +04:00
|
|
|
} else {
|
|
|
|
MOZ_ASSERT(mSequenceType == eNullableArray);
|
2013-05-16 20:36:56 +04:00
|
|
|
if (!mNullableArray->IsNull()) {
|
|
|
|
DoTraceSequence(trc, mNullableArray->Value());
|
|
|
|
}
|
2013-05-16 20:36:55 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
union {
|
|
|
|
InfallibleTArray<T>* mInfallibleArray;
|
|
|
|
FallibleTArray<T>* mFallibleArray;
|
2013-05-16 20:36:56 +04:00
|
|
|
Nullable<nsTArray<T> >* mNullableArray;
|
2013-05-16 20:36:55 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
SequenceType mSequenceType;
|
|
|
|
};
|
|
|
|
|
2017-02-15 08:01:35 +03:00
|
|
|
// 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
|
2014-05-24 01:32:38 +04:00
|
|
|
{
|
|
|
|
public:
|
2017-02-15 08:01:35 +03:00
|
|
|
RecordRooter(JSContext *aCx, Record<K, V>* aRecord
|
2014-05-24 01:32:38 +04:00
|
|
|
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
|
|
|
: JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
|
2017-02-15 08:01:35 +03:00
|
|
|
mRecord(aRecord),
|
|
|
|
mRecordType(eRecord)
|
2014-05-24 01:32:38 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-02-15 08:01:35 +03:00
|
|
|
RecordRooter(JSContext *aCx, Nullable<Record<K, V>>* aRecord
|
2014-05-24 01:32:38 +04:00
|
|
|
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
|
|
|
: JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
|
2017-02-15 08:01:35 +03:00
|
|
|
mNullableRecord(aRecord),
|
|
|
|
mRecordType(eNullableRecord)
|
2014-05-24 01:32:38 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2017-02-15 08:01:35 +03:00
|
|
|
enum RecordType {
|
|
|
|
eRecord,
|
|
|
|
eNullableRecord
|
2014-05-24 01:32:38 +04:00
|
|
|
};
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
virtual void trace(JSTracer *trc) override
|
2014-05-24 01:32:38 +04:00
|
|
|
{
|
2017-02-15 08:01:35 +03:00
|
|
|
if (mRecordType == eRecord) {
|
|
|
|
TraceRecord(trc, *mRecord);
|
2014-05-24 01:32:38 +04:00
|
|
|
} else {
|
2017-02-15 08:01:35 +03:00
|
|
|
MOZ_ASSERT(mRecordType == eNullableRecord);
|
|
|
|
if (!mNullableRecord->IsNull()) {
|
|
|
|
TraceRecord(trc, mNullableRecord->Value());
|
2014-05-24 01:32:38 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
union {
|
2017-02-15 08:01:35 +03:00
|
|
|
Record<K, V>* mRecord;
|
|
|
|
Nullable<Record<K, V>>* mNullableRecord;
|
2014-05-24 01:32:38 +04:00
|
|
|
};
|
|
|
|
|
2017-02-15 08:01:35 +03:00
|
|
|
RecordType mRecordType;
|
2014-05-24 01:32:38 +04:00
|
|
|
};
|
|
|
|
|
2013-09-13 06:34:16 +04:00
|
|
|
template<typename T>
|
2015-09-03 19:15:23 +03:00
|
|
|
class MOZ_RAII RootedUnion : public T,
|
|
|
|
private JS::CustomAutoRooter
|
2013-09-13 06:34:16 +04:00
|
|
|
{
|
|
|
|
public:
|
2014-07-28 21:17:51 +04:00
|
|
|
explicit RootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
|
2013-09-13 06:34:16 +04:00
|
|
|
T(),
|
|
|
|
JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
virtual void trace(JSTracer *trc) override
|
2013-09-13 06:34:16 +04:00
|
|
|
{
|
|
|
|
this->TraceUnion(trc);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
class MOZ_STACK_CLASS NullableRootedUnion : public Nullable<T>,
|
|
|
|
private JS::CustomAutoRooter
|
|
|
|
{
|
|
|
|
public:
|
2014-07-28 21:17:51 +04:00
|
|
|
explicit NullableRootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
|
2013-09-13 06:34:16 +04:00
|
|
|
Nullable<T>(),
|
|
|
|
JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
virtual void trace(JSTracer *trc) override
|
2013-09-13 06:34:16 +04:00
|
|
|
{
|
|
|
|
if (!this->IsNull()) {
|
|
|
|
this->Value().TraceUnion(trc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-10-09 22:50:27 +04:00
|
|
|
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) &&
|
2015-06-30 17:58:31 +03:00
|
|
|
AtomizeAndPinJSString(cx, *(vector[vector.length() - 1]).address(), name);
|
2012-10-09 22:50:27 +04:00
|
|
|
}
|
|
|
|
|
2016-11-24 00:58:59 +03:00
|
|
|
// 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);
|
|
|
|
|
2012-07-18 15:52:07 +04:00
|
|
|
// Implementation of the bits that XrayWrapper needs
|
2012-10-09 22:50:27 +04:00
|
|
|
|
|
|
|
/**
|
2014-09-15 18:51:40 +04:00
|
|
|
* This resolves operations, attributes and constants of the interfaces for obj.
|
2012-10-09 22:50:27 +04:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2012-07-18 15:52:07 +04:00
|
|
|
bool
|
2013-05-04 03:29:08 +04:00
|
|
|
XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
|
|
|
JS::Handle<JSObject*> obj,
|
|
|
|
JS::Handle<jsid> id,
|
2016-01-28 13:28:04 +03:00
|
|
|
JS::MutableHandle<JS::PropertyDescriptor> desc,
|
2014-08-22 13:25:07 +04:00
|
|
|
bool& cacheOnHolder);
|
2012-07-18 15:52:07 +04:00
|
|
|
|
2013-05-29 13:38:57 +04:00
|
|
|
/**
|
|
|
|
* 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.
|
2015-01-30 20:37:07 +03:00
|
|
|
* 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).
|
2013-05-29 13:38:57 +04:00
|
|
|
* defined will be set to true if a property was set as a result of this call.
|
|
|
|
*/
|
|
|
|
bool
|
2013-04-30 21:29:40 +04:00
|
|
|
XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
2013-05-29 13:38:57 +04:00
|
|
|
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
2016-01-28 13:28:04 +03:00
|
|
|
JS::Handle<JS::PropertyDescriptor> desc,
|
2015-01-30 20:37:07 +03:00
|
|
|
JS::ObjectOpResult &result,
|
|
|
|
bool *defined);
|
2013-05-29 13:38:57 +04:00
|
|
|
|
2012-10-09 22:50:27 +04:00
|
|
|
/**
|
2014-09-27 00:16:36 +04:00
|
|
|
* Add to props the property keys of all indexed or named properties of obj and
|
|
|
|
* operations, attributes and constants of the interfaces for obj.
|
2012-10-09 22:50:27 +04:00
|
|
|
*
|
|
|
|
* 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.
|
2012-11-05 20:58:03 +04:00
|
|
|
* flags are JSITER_* flags.
|
2012-10-09 22:50:27 +04:00
|
|
|
*/
|
|
|
|
bool
|
2014-09-27 00:16:36 +04:00
|
|
|
XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
|
|
|
JS::Handle<JSObject*> obj,
|
|
|
|
unsigned flags, JS::AutoIdVector& props);
|
2012-10-09 22:50:27 +04:00
|
|
|
|
2014-09-09 17:19:10 +04:00
|
|
|
/**
|
|
|
|
* 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)
|
|
|
|
{
|
2018-07-12 13:14:38 +03:00
|
|
|
JS::Rooted<JSObject*> global(cx, JS::GetNonCCWObjectGlobal(obj));
|
2014-09-09 17:19:10 +04:00
|
|
|
{
|
2018-08-02 09:48:50 +03:00
|
|
|
JSAutoRealm ar(cx, global);
|
2014-09-09 17:19:10 +04:00
|
|
|
const DOMJSClass* domClass = GetDOMClass(obj);
|
|
|
|
if (domClass) {
|
|
|
|
ProtoHandleGetter protoGetter = domClass->mGetProto;
|
|
|
|
if (protoGetter) {
|
2016-07-09 07:19:52 +03:00
|
|
|
protop.set(protoGetter(cx));
|
2014-09-09 17:19:10 +04:00
|
|
|
} else {
|
2016-07-09 07:19:52 +03:00
|
|
|
protop.set(JS::GetRealmObjectPrototype(cx));
|
2014-09-09 17:19:10 +04:00
|
|
|
}
|
2016-11-24 00:58:59 +03:00
|
|
|
} else if (JS_ObjectIsFunction(cx, obj)) {
|
|
|
|
MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
|
|
|
|
protop.set(JS::GetRealmFunctionPrototype(cx));
|
2014-09-09 17:19:10 +04:00
|
|
|
} else {
|
|
|
|
const js::Class* clasp = js::GetObjectClass(obj);
|
|
|
|
MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
|
|
|
|
ProtoGetter protoGetter =
|
|
|
|
DOMIfaceAndProtoJSClass::FromJSClass(clasp)->mGetParentProto;
|
2016-07-09 07:19:52 +03:00
|
|
|
protop.set(protoGetter(cx));
|
2014-09-09 17:19:10 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return JS_WrapObject(cx, protop);
|
|
|
|
}
|
|
|
|
|
2016-10-11 01:16:26 +03:00
|
|
|
/**
|
|
|
|
* Get the Xray expando class to use for the given DOM object.
|
|
|
|
*/
|
|
|
|
const JSClass*
|
|
|
|
XrayGetExpandoClass(JSContext* cx, JS::Handle<JSObject*> obj);
|
|
|
|
|
2016-11-04 19:41:26 +03:00
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
|
2016-10-11 01:16:26 +03:00
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
|
2015-02-26 17:40:08 +03:00
|
|
|
extern NativePropertyHooks sEmptyNativePropertyHooks;
|
2012-10-09 22:50:27 +04:00
|
|
|
|
2016-04-01 03:00:01 +03:00
|
|
|
extern const js::ClassOps sBoringInterfaceObjectClassClassOps;
|
|
|
|
|
2016-03-23 23:00:29 +03:00
|
|
|
extern const js::ObjectOps sInterfaceObjectClassObjectOps;
|
|
|
|
|
2012-10-09 22:50:27 +04:00
|
|
|
inline bool
|
|
|
|
UseDOMXray(JSObject* obj)
|
|
|
|
{
|
|
|
|
const js::Class* clasp = js::GetObjectClass(obj);
|
|
|
|
return IsDOMClass(clasp) ||
|
|
|
|
JS_IsNativeFunction(obj, Constructor) ||
|
|
|
|
IsDOMIfaceAndProtoClass(clasp);
|
|
|
|
}
|
|
|
|
|
2018-01-12 22:28:28 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-10-09 22:50:27 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
inline bool
|
|
|
|
HasConstructor(JSObject* obj)
|
|
|
|
{
|
|
|
|
return JS_IsNativeFunction(obj, Constructor) ||
|
2016-04-01 03:00:01 +03:00
|
|
|
js::GetObjectClass(obj)->getConstruct();
|
2012-10-09 22:50:27 +04:00
|
|
|
}
|
2016-11-24 00:58:59 +03:00
|
|
|
#endif
|
2013-03-18 05:47:12 +04:00
|
|
|
|
2013-04-26 03:03:06 +04:00
|
|
|
// Helpers for creating a const version of a type.
|
|
|
|
template<typename T>
|
|
|
|
const T& Constify(T& arg)
|
|
|
|
{
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
|
2013-07-22 16:15:43 +04:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2014-01-22 23:37:10 +04:00
|
|
|
inline
|
2014-07-03 12:03:56 +04:00
|
|
|
void NonNullHelper(NonNull<binding_detail::FakeString>& aArg)
|
2014-01-22 23:37:10 +04:00
|
|
|
{
|
|
|
|
// This overload is here to make sure that we never end up applying
|
2014-07-03 12:03:56 +04:00
|
|
|
// NonNullHelper to a NonNull<binding_detail::FakeString>. If we
|
2014-01-22 23:37:10 +04:00
|
|
|
// try to, it should fail to compile, since presumably the caller will try to
|
|
|
|
// use our nonexistent return value.
|
|
|
|
}
|
|
|
|
|
|
|
|
inline
|
2014-07-03 12:03:56 +04:00
|
|
|
void NonNullHelper(const NonNull<binding_detail::FakeString>& aArg)
|
2014-01-22 23:37:10 +04:00
|
|
|
{
|
|
|
|
// This overload is here to make sure that we never end up applying
|
2014-07-03 12:03:56 +04:00
|
|
|
// NonNullHelper to a NonNull<binding_detail::FakeString>. If we
|
2014-01-22 23:37:10 +04:00
|
|
|
// try to, it should fail to compile, since presumably the caller will try to
|
|
|
|
// use our nonexistent return value.
|
|
|
|
}
|
|
|
|
|
|
|
|
inline
|
2014-07-03 12:03:56 +04:00
|
|
|
void NonNullHelper(binding_detail::FakeString& aArg)
|
2014-01-22 23:37:10 +04:00
|
|
|
{
|
|
|
|
// This overload is here to make sure that we never end up applying
|
2014-07-03 12:03:56 +04:00
|
|
|
// NonNullHelper to a FakeString before we've constified it. If we
|
2014-01-22 23:37:10 +04:00
|
|
|
// try to, it should fail to compile, since presumably the caller will try to
|
|
|
|
// use our nonexistent return value.
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ALWAYS_INLINE
|
2014-07-03 12:03:56 +04:00
|
|
|
const nsAString& NonNullHelper(const binding_detail::FakeString& aArg)
|
2014-01-22 23:37:10 +04:00
|
|
|
{
|
|
|
|
return aArg;
|
|
|
|
}
|
|
|
|
|
2013-04-26 03:03:06 +04:00
|
|
|
// Reparent the wrapper of aObj to whatever its native now thinks its
|
|
|
|
// parent should be.
|
2017-09-13 20:34:55 +03:00
|
|
|
void
|
|
|
|
ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObj, ErrorResult& aError);
|
2012-09-26 18:17:46 +04:00
|
|
|
|
2013-01-08 22:05:36 +04:00
|
|
|
/**
|
2016-08-04 04:32:07 +03:00
|
|
|
* Used to implement the Symbol.hasInstance property of an interface object.
|
2013-01-08 22:05:36 +04:00
|
|
|
*/
|
2013-08-09 02:53:04 +04:00
|
|
|
bool
|
2016-08-04 04:32:07 +03:00
|
|
|
InterfaceHasInstance(JSContext* cx, unsigned argc, JS::Value* vp);
|
|
|
|
|
2013-08-09 02:53:04 +04:00
|
|
|
bool
|
2013-08-02 03:45:17 +04:00
|
|
|
InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
|
|
|
|
JS::Handle<JSObject*> instance,
|
2013-08-09 02:53:04 +04:00
|
|
|
bool* bp);
|
2013-01-08 22:05:36 +04:00
|
|
|
|
2018-01-11 08:00:25 +03:00
|
|
|
// Used to implement the cross-context <Interface>.isInstance static method.
|
|
|
|
bool
|
2018-04-12 07:06:07 +03:00
|
|
|
InterfaceIsInstance(JSContext* cx, unsigned argc, JS::Value* vp);
|
2018-01-11 08:00:25 +03:00
|
|
|
|
2013-05-08 23:50:58 +04:00
|
|
|
// Helper for lenient getters/setters to report to console. If this
|
|
|
|
// returns false, we couldn't even get a global.
|
|
|
|
bool
|
2013-09-25 22:38:30 +04:00
|
|
|
ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj);
|
2013-04-09 01:04:21 +04:00
|
|
|
|
2013-05-20 21:47:08 +04:00
|
|
|
// Given a JSObject* that represents the chrome side of a JS-implemented WebIDL
|
2015-01-08 19:57:19 +03:00
|
|
|
// interface, get the nsIGlobalObject corresponding to the content side, if any.
|
2013-05-20 21:47:08 +04:00
|
|
|
// A false return means an exception was thrown.
|
|
|
|
bool
|
2015-01-08 19:57:19 +03:00
|
|
|
GetContentGlobalForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
|
|
|
|
nsIGlobalObject** global);
|
2013-05-20 21:47:08 +04:00
|
|
|
|
2014-03-28 08:03:03 +04:00
|
|
|
void
|
2016-03-12 00:43:31 +03:00
|
|
|
ConstructJSImplementation(const char* aContractId,
|
2015-01-08 19:57:19 +03:00
|
|
|
nsIGlobalObject* aGlobal,
|
2014-03-28 08:03:03 +04:00
|
|
|
JS::MutableHandle<JSObject*> aObject,
|
|
|
|
ErrorResult& aRv);
|
|
|
|
|
2015-01-08 19:57:19 +03:00
|
|
|
already_AddRefed<nsIGlobalObject>
|
2016-03-12 00:43:31 +03:00
|
|
|
ConstructJSImplementation(const char* aContractId,
|
2013-06-01 10:56:23 +04:00
|
|
|
const GlobalObject& aGlobal,
|
|
|
|
JS::MutableHandle<JSObject*> aObject,
|
|
|
|
ErrorResult& aRv);
|
|
|
|
|
2013-06-13 09:18:35 +04:00
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
|
2013-07-04 19:24:59 +04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-09-12 12:46:51 +03:00
|
|
|
// 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.
|
2017-09-13 13:21:12 +03:00
|
|
|
inline size_t
|
2017-09-12 12:46:51 +03:00
|
|
|
BindingJSObjectMallocBytes(void *aNativePtr)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-07-23 17:46:37 +03:00
|
|
|
// Register a thing which DeferredFinalize might be called on during GC
|
|
|
|
// finalization. See DeferredFinalize.h
|
|
|
|
template<class T>
|
|
|
|
static void
|
|
|
|
RecordReplayRegisterDeferredFinalize(T* aObject);
|
|
|
|
|
2014-11-01 17:00:28 +03:00
|
|
|
// 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)
|
2015-01-09 00:56:42 +03:00
|
|
|
: mReflector(aCx)
|
2014-11-01 17:00:28 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
~BindingJSObjectCreator()
|
|
|
|
{
|
2015-01-09 00:56:42 +03:00
|
|
|
if (mReflector) {
|
2017-04-28 15:12:28 +03:00
|
|
|
js::SetReservedSlot(mReflector, DOM_OBJECT_SLOT, JS::UndefinedValue());
|
2014-11-01 17:00:28 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-09 00:56:42 +03:00
|
|
|
void
|
2014-11-01 17:00:28 +03:00
|
|
|
CreateProxyObject(JSContext* aCx, const js::Class* aClass,
|
|
|
|
const DOMProxyHandler* aHandler,
|
2015-02-26 17:40:07 +03:00
|
|
|
JS::Handle<JSObject*> aProto, T* aNative,
|
2017-04-28 15:12:28 +03:00
|
|
|
JS::Handle<JS::Value> aExpandoValue,
|
2015-01-09 00:56:42 +03:00
|
|
|
JS::MutableHandle<JSObject*> aReflector)
|
2014-11-01 17:00:28 +03:00
|
|
|
{
|
|
|
|
js::ProxyOptions options;
|
|
|
|
options.setClass(aClass);
|
2017-04-28 15:12:28 +03:00
|
|
|
aReflector.set(js::NewProxyObject(aCx, aHandler, aExpandoValue, aProto,
|
2015-02-26 23:58:59 +03:00
|
|
|
options));
|
2015-01-09 00:56:42 +03:00
|
|
|
if (aReflector) {
|
2017-04-28 15:12:28 +03:00
|
|
|
js::SetProxyReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
|
2014-11-01 17:00:28 +03:00
|
|
|
mNative = aNative;
|
2015-01-09 00:56:42 +03:00
|
|
|
mReflector = aReflector;
|
2018-07-23 17:46:37 +03:00
|
|
|
RecordReplayRegisterDeferredFinalize<T>(aNative);
|
2014-11-01 17:00:28 +03:00
|
|
|
}
|
2017-09-12 12:46:51 +03:00
|
|
|
|
2017-09-13 13:21:12 +03:00
|
|
|
if (size_t mallocBytes = BindingJSObjectMallocBytes(aNative)) {
|
2017-09-12 12:46:51 +03:00
|
|
|
JS_updateMallocCounter(aCx, mallocBytes);
|
|
|
|
}
|
2014-11-01 17:00:28 +03:00
|
|
|
}
|
|
|
|
|
2015-01-09 00:56:42 +03:00
|
|
|
void
|
2014-11-01 17:00:28 +03:00
|
|
|
CreateObject(JSContext* aCx, const JSClass* aClass,
|
2015-02-26 17:40:07 +03:00
|
|
|
JS::Handle<JSObject*> aProto,
|
2015-01-09 00:56:42 +03:00
|
|
|
T* aNative, JS::MutableHandle<JSObject*> aReflector)
|
2014-11-01 17:00:28 +03:00
|
|
|
{
|
2015-02-26 17:40:07 +03:00
|
|
|
aReflector.set(JS_NewObjectWithGivenProto(aCx, aClass, aProto));
|
2015-01-09 00:56:42 +03:00
|
|
|
if (aReflector) {
|
|
|
|
js::SetReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
|
2014-11-01 17:00:28 +03:00
|
|
|
mNative = aNative;
|
2015-01-09 00:56:42 +03:00
|
|
|
mReflector = aReflector;
|
2018-07-23 17:46:37 +03:00
|
|
|
RecordReplayRegisterDeferredFinalize<T>(aNative);
|
2014-11-01 17:00:28 +03:00
|
|
|
}
|
2017-09-12 12:46:51 +03:00
|
|
|
|
2017-09-13 13:21:12 +03:00
|
|
|
if (size_t mallocBytes = BindingJSObjectMallocBytes(aNative)) {
|
2017-09-12 12:46:51 +03:00
|
|
|
JS_updateMallocCounter(aCx, mallocBytes);
|
|
|
|
}
|
2014-11-01 17:00:28 +03:00
|
|
|
}
|
|
|
|
|
2015-01-09 00:56:42 +03:00
|
|
|
void
|
|
|
|
InitializationSucceeded()
|
2014-11-01 17:00:28 +03:00
|
|
|
{
|
|
|
|
void* dummy;
|
|
|
|
mNative.forget(&dummy);
|
2015-01-09 00:56:42 +03:00
|
|
|
mReflector = nullptr;
|
2014-11-01 17:00:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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**)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-01-09 00:56:42 +03:00
|
|
|
JS::Rooted<JSObject*> mReflector;
|
2015-10-18 08:24:48 +03:00
|
|
|
typename Conditional<IsRefcounted<T>::value, RefPtr<T>, OwnedNative>::Type mNative;
|
2014-11-01 17:00:28 +03:00
|
|
|
};
|
|
|
|
|
2015-03-10 18:35:47 +03:00
|
|
|
template<class T>
|
|
|
|
struct DeferredFinalizerImpl
|
2013-07-04 19:24:59 +04:00
|
|
|
{
|
2015-03-10 18:35:47 +03:00
|
|
|
typedef typename Conditional<IsSame<T, nsISupports>::value,
|
|
|
|
nsCOMPtr<T>,
|
|
|
|
typename Conditional<IsRefcounted<T>::value,
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<T>,
|
2015-03-10 18:35:47 +03:00
|
|
|
nsAutoPtr<T>>::Type>::Type SmartPtr;
|
2016-03-04 20:06:06 +03:00
|
|
|
typedef SegmentedVector<SmartPtr> SmartPtrArray;
|
2014-11-01 16:48:19 +03:00
|
|
|
|
2015-03-10 18:35:47 +03:00
|
|
|
static_assert(IsSame<T, nsISupports>::value || !IsBaseOf<nsISupports, T>::value,
|
|
|
|
"nsISupports classes should all use the nsISupports instantiation");
|
|
|
|
|
|
|
|
static inline void
|
2016-03-04 20:06:06 +03:00
|
|
|
AppendAndTake(SegmentedVector<nsCOMPtr<nsISupports>>& smartPtrArray, nsISupports* ptr)
|
2015-03-10 18:35:47 +03:00
|
|
|
{
|
2016-03-04 20:06:06 +03:00
|
|
|
smartPtrArray.InfallibleAppend(dont_AddRef(ptr));
|
2015-03-10 18:35:47 +03:00
|
|
|
}
|
2014-11-01 16:48:19 +03:00
|
|
|
template<class U>
|
|
|
|
static inline void
|
2016-03-04 20:06:06 +03:00
|
|
|
AppendAndTake(SegmentedVector<RefPtr<U>>& smartPtrArray, U* ptr)
|
2014-11-01 16:48:19 +03:00
|
|
|
{
|
2016-03-04 20:06:06 +03:00
|
|
|
smartPtrArray.InfallibleAppend(dont_AddRef(ptr));
|
2014-11-01 16:48:19 +03:00
|
|
|
}
|
|
|
|
template<class U>
|
|
|
|
static inline void
|
2016-03-04 20:06:06 +03:00
|
|
|
AppendAndTake(SegmentedVector<nsAutoPtr<U>>& smartPtrArray, U* ptr)
|
2014-11-01 16:48:19 +03:00
|
|
|
{
|
2016-03-04 20:06:06 +03:00
|
|
|
smartPtrArray.InfallibleAppend(ptr);
|
2014-11-01 16:48:19 +03:00
|
|
|
}
|
2013-07-04 19:24:59 +04:00
|
|
|
|
|
|
|
static void*
|
|
|
|
AppendDeferredFinalizePointer(void* aData, void* aObject)
|
|
|
|
{
|
|
|
|
SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
|
|
|
|
if (!pointers) {
|
|
|
|
pointers = new SmartPtrArray();
|
|
|
|
}
|
2014-11-01 16:48:19 +03:00
|
|
|
AppendAndTake(*pointers, static_cast<T*>(aObject));
|
2013-07-04 19:24:59 +04:00
|
|
|
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();
|
2013-09-19 02:50:32 +04:00
|
|
|
if (oldLen < aSlice) {
|
|
|
|
aSlice = oldLen;
|
|
|
|
}
|
2013-07-04 19:24:59 +04:00
|
|
|
uint32_t newLen = oldLen - aSlice;
|
2016-03-04 20:06:06 +03:00
|
|
|
pointers->PopLastN(aSlice);
|
2013-07-04 19:24:59 +04:00
|
|
|
if (newLen == 0) {
|
|
|
|
delete pointers;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2015-03-10 18:35:47 +03:00
|
|
|
};
|
2013-07-04 19:24:59 +04:00
|
|
|
|
2015-03-10 18:35:47 +03:00
|
|
|
template<class T,
|
|
|
|
bool isISupports=IsBaseOf<nsISupports, T>::value>
|
|
|
|
struct DeferredFinalizer
|
|
|
|
{
|
2013-07-04 19:24:59 +04:00
|
|
|
static void
|
|
|
|
AddForDeferredFinalization(T* aObject)
|
|
|
|
{
|
2015-03-10 18:35:47 +03:00
|
|
|
typedef DeferredFinalizerImpl<T> Impl;
|
2015-03-18 21:36:03 +03:00
|
|
|
DeferredFinalize(Impl::AppendDeferredFinalizePointer,
|
|
|
|
Impl::DeferredFinalize, aObject);
|
2013-07-04 19:24:59 +04:00
|
|
|
}
|
2018-07-23 17:46:37 +03:00
|
|
|
|
|
|
|
static void
|
|
|
|
RecordReplayRegisterDeferredFinalize(T* aObject)
|
|
|
|
{
|
|
|
|
typedef DeferredFinalizerImpl<T> Impl;
|
|
|
|
RecordReplayRegisterDeferredFinalizeThing(Impl::AppendDeferredFinalizePointer,
|
|
|
|
Impl::DeferredFinalize,
|
|
|
|
aObject);
|
|
|
|
}
|
2013-07-04 19:24:59 +04:00
|
|
|
};
|
|
|
|
|
2014-11-01 16:48:19 +03:00
|
|
|
template<class T>
|
2015-03-10 18:35:47 +03:00
|
|
|
struct DeferredFinalizer<T, true>
|
2013-07-04 19:24:59 +04:00
|
|
|
{
|
|
|
|
static void
|
|
|
|
AddForDeferredFinalization(T* aObject)
|
|
|
|
{
|
2015-03-18 21:36:03 +03:00
|
|
|
DeferredFinalize(reinterpret_cast<nsISupports*>(aObject));
|
2013-07-04 19:24:59 +04:00
|
|
|
}
|
2018-07-23 17:46:37 +03:00
|
|
|
|
|
|
|
static void
|
|
|
|
RecordReplayRegisterDeferredFinalize(T* aObject)
|
|
|
|
{
|
|
|
|
RecordReplayRegisterDeferredFinalizeThing(nullptr, nullptr, aObject);
|
|
|
|
}
|
2013-07-04 19:24:59 +04:00
|
|
|
};
|
|
|
|
|
2014-11-01 16:48:19 +03:00
|
|
|
template<class T>
|
2013-07-04 19:24:59 +04:00
|
|
|
static void
|
|
|
|
AddForDeferredFinalization(T* aObject)
|
|
|
|
{
|
2014-11-01 16:48:19 +03:00
|
|
|
DeferredFinalizer<T>::AddForDeferredFinalization(aObject);
|
2013-07-04 19:24:59 +04:00
|
|
|
}
|
|
|
|
|
2018-07-23 17:46:37 +03:00
|
|
|
template<class T>
|
|
|
|
static void
|
|
|
|
RecordReplayRegisterDeferredFinalize(T* aObject)
|
|
|
|
{
|
|
|
|
DeferredFinalizer<T>::RecordReplayRegisterDeferredFinalize(aObject);
|
|
|
|
}
|
|
|
|
|
2013-07-04 19:24:59 +04:00
|
|
|
// 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>
|
2016-07-09 00:39:53 +03:00
|
|
|
static constexpr nsCycleCollectionParticipant*
|
2013-07-04 19:24:59 +04:00
|
|
|
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>
|
2016-07-09 00:39:53 +03:00
|
|
|
static constexpr nsCycleCollectionParticipant*
|
2013-07-04 19:24:59 +04:00
|
|
|
GetHelper(double)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2016-07-09 00:39:53 +03:00
|
|
|
static constexpr nsCycleCollectionParticipant*
|
2013-07-04 19:24:59 +04:00
|
|
|
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:
|
2016-07-09 00:39:53 +03:00
|
|
|
static constexpr nsCycleCollectionParticipant*
|
2013-07-04 19:24:59 +04:00
|
|
|
Get()
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-11-19 10:05:42 +04:00
|
|
|
void
|
|
|
|
FinalizeGlobal(JSFreeOp* aFop, JSObject* aObj);
|
|
|
|
|
2013-11-05 18:16:26 +04:00
|
|
|
bool
|
|
|
|
ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
2014-11-08 03:07:12 +03:00
|
|
|
JS::Handle<jsid> aId, bool* aResolvedp);
|
2013-11-05 18:16:26 +04:00
|
|
|
|
2015-04-28 19:25:55 +03:00
|
|
|
bool
|
|
|
|
MayResolveGlobal(const JSAtomState& aNames, jsid aId, JSObject* aMaybeObj);
|
|
|
|
|
2013-11-05 18:16:26 +04:00
|
|
|
bool
|
2017-06-14 11:39:11 +03:00
|
|
|
EnumerateGlobal(JSContext* aCx, JS::HandleObject aObj,
|
|
|
|
JS::AutoIdVector& aProperties, bool aEnumerableOnly);
|
2013-11-05 18:16:26 +04:00
|
|
|
|
2017-07-19 15:59:02 +03:00
|
|
|
|
|
|
|
struct CreateGlobalOptionsGeneric
|
2014-04-08 22:48:37 +04:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-07-19 15:59:02 +03:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2014-04-08 22:48:37 +04:00
|
|
|
template <>
|
2017-11-07 01:52:14 +03:00
|
|
|
struct CreateGlobalOptions<nsGlobalWindowInner>
|
2017-07-19 15:59:02 +03:00
|
|
|
: public CreateGlobalOptionsWithXPConnect
|
2013-11-05 18:16:26 +04:00
|
|
|
{
|
2016-07-09 00:39:53 +03:00
|
|
|
static constexpr ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
|
2014-04-08 22:48:37 +04:00
|
|
|
ProtoAndIfaceCache::WindowLike;
|
|
|
|
static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
|
|
|
|
};
|
2013-11-05 18:16:26 +04:00
|
|
|
|
2016-09-03 00:55:38 +03:00
|
|
|
// The return value is true if we created and successfully performed our part of
|
|
|
|
// the setup for the global, false otherwise.
|
2016-02-01 23:48:03 +03:00
|
|
|
//
|
|
|
|
// 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.
|
2014-09-09 17:19:10 +04:00
|
|
|
template <class T, ProtoHandleGetter GetProto>
|
2016-09-03 00:55:38 +03:00
|
|
|
bool
|
2014-04-08 22:48:37 +04:00
|
|
|
CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
|
2018-05-17 11:59:45 +03:00
|
|
|
const JSClass* aClass, JS::RealmOptions& aOptions,
|
2014-04-08 22:48:37 +04:00
|
|
|
JSPrincipals* aPrincipal, bool aInitStandardClasses,
|
|
|
|
JS::MutableHandle<JSObject*> aGlobal)
|
|
|
|
{
|
2015-12-29 01:15:52 +03:00
|
|
|
aOptions.creationOptions().setTrace(CreateGlobalOptions<T>::TraceGlobal);
|
2016-01-06 18:31:38 +03:00
|
|
|
if (xpc::SharedMemoryEnabled()) {
|
|
|
|
aOptions.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
|
|
|
|
}
|
2014-04-05 03:58:08 +04:00
|
|
|
|
2014-04-08 22:48:37 +04:00
|
|
|
aGlobal.set(JS_NewGlobalObject(aCx, aClass, aPrincipal,
|
|
|
|
JS::DontFireOnNewGlobalHook, aOptions));
|
|
|
|
if (!aGlobal) {
|
2013-11-05 18:16:26 +04:00
|
|
|
NS_WARNING("Failed to create global");
|
2016-09-03 00:55:38 +03:00
|
|
|
return false;
|
2013-11-05 18:16:26 +04:00
|
|
|
}
|
|
|
|
|
2018-08-02 09:48:50 +03:00
|
|
|
JSAutoRealm ar(aCx, aGlobal);
|
2013-11-05 18:16:26 +04:00
|
|
|
|
2014-04-08 22:48:37 +04:00
|
|
|
{
|
2015-06-30 21:20:58 +03:00
|
|
|
js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
|
2014-04-08 22:48:37 +04:00
|
|
|
NS_ADDREF(aNative);
|
2013-11-05 18:16:26 +04:00
|
|
|
|
2014-04-08 22:48:37 +04:00
|
|
|
aCache->SetWrapper(aGlobal);
|
2018-07-23 17:46:37 +03:00
|
|
|
RecordReplayRegisterDeferredFinalize<T>(aNative);
|
2013-11-05 18:16:26 +04:00
|
|
|
|
2014-04-08 22:48:37 +04:00
|
|
|
dom::AllocateProtoAndIfaceCache(aGlobal,
|
|
|
|
CreateGlobalOptions<T>::ProtoAndIfaceCacheKind);
|
|
|
|
|
|
|
|
if (!CreateGlobalOptions<T>::PostCreateGlobal(aCx, aGlobal)) {
|
2016-09-03 00:55:38 +03:00
|
|
|
return false;
|
2014-04-08 22:48:37 +04:00
|
|
|
}
|
2013-11-05 18:16:26 +04:00
|
|
|
}
|
|
|
|
|
2018-06-13 22:47:47 +03:00
|
|
|
if (aInitStandardClasses && !JS::InitRealmStandardClasses(aCx)) {
|
2014-04-08 22:48:37 +04:00
|
|
|
NS_WARNING("Failed to init standard classes");
|
2016-09-03 00:55:38 +03:00
|
|
|
return false;
|
2014-04-08 22:48:37 +04:00
|
|
|
}
|
2013-11-05 18:16:26 +04:00
|
|
|
|
2016-07-09 07:19:52 +03:00
|
|
|
JS::Handle<JSObject*> proto = GetProto(aCx);
|
2014-04-08 22:48:37 +04:00
|
|
|
if (!proto || !JS_SplicePrototype(aCx, aGlobal, proto)) {
|
2013-11-05 18:16:26 +04:00
|
|
|
NS_WARNING("Failed to set proto");
|
2016-09-03 00:55:38 +03:00
|
|
|
return false;
|
2013-11-05 18:16:26 +04:00
|
|
|
}
|
|
|
|
|
2015-10-09 01:08:13 +03:00
|
|
|
bool succeeded;
|
|
|
|
if (!JS_SetImmutablePrototype(aCx, aGlobal, &succeeded)) {
|
2016-09-03 00:55:38 +03:00
|
|
|
return false;
|
2015-10-09 01:08:13 +03:00
|
|
|
}
|
|
|
|
MOZ_ASSERT(succeeded,
|
|
|
|
"making a fresh global object's [[Prototype]] immutable can "
|
|
|
|
"internally fail, but it should never be unsuccessful");
|
|
|
|
|
2016-09-03 00:55:38 +03:00
|
|
|
return true;
|
2013-11-05 18:16:26 +04:00
|
|
|
}
|
|
|
|
|
2014-01-22 15:28:06 +04:00
|
|
|
/*
|
2015-06-30 17:58:31 +03:00
|
|
|
* Holds a jsid that is initialized to a pinned string, with automatic
|
|
|
|
* conversion to Handle<jsid>, as it is held live forever by pinning.
|
2014-01-22 15:28:06 +04:00
|
|
|
*/
|
2015-06-30 17:58:31 +03:00
|
|
|
class PinnedStringId
|
2014-01-22 15:28:06 +04:00
|
|
|
{
|
|
|
|
jsid id;
|
|
|
|
|
|
|
|
public:
|
2018-03-07 23:50:24 +03:00
|
|
|
constexpr PinnedStringId() : id(JSID_VOID) {}
|
2014-01-22 15:28:06 +04:00
|
|
|
|
|
|
|
bool init(JSContext *cx, const char *string) {
|
2015-06-30 17:58:31 +03:00
|
|
|
JSString* str = JS_AtomizeAndPinString(cx, string);
|
2014-01-22 15:28:06 +04:00
|
|
|
if (!str)
|
|
|
|
return false;
|
|
|
|
id = INTERNED_STRING_TO_JSID(cx, str);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-07-19 16:04:14 +03:00
|
|
|
operator const jsid& () const {
|
2014-01-22 15:28:06 +04:00
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2017-07-19 16:04:14 +03:00
|
|
|
operator JS::Handle<jsid> () const {
|
2015-06-30 17:58:31 +03:00
|
|
|
/* This is safe because we have pinned the string. */
|
2014-01-22 15:28:06 +04:00
|
|
|
return JS::Handle<jsid>::fromMarkedLocation(&id);
|
|
|
|
}
|
2018-06-05 07:51:10 +03:00
|
|
|
} JS_HAZ_ROOTED;
|
2014-01-22 15:28:06 +04:00
|
|
|
|
2018-04-06 03:29:40 +03:00
|
|
|
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>
|
2014-02-08 00:56:14 +04:00
|
|
|
bool
|
2018-04-06 03:29:40 +03:00
|
|
|
GenericGetter(JSContext* cx, unsigned argc, JS::Value* vp);
|
2014-02-08 00:56:14 +04:00
|
|
|
|
2018-04-06 03:29:41 +03:00
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
|
2018-04-06 03:29:41 +03:00
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
|
2018-04-06 03:29:40 +03:00
|
|
|
// A this-extraction policy for normal getters/setters/methods.
|
|
|
|
struct NormalThisPolicy;
|
|
|
|
|
2018-04-06 03:29:40 +03:00
|
|
|
// A this-extraction policy for getters/setters/methods on interfaces
|
|
|
|
// that are on some global's proto chain.
|
|
|
|
struct MaybeGlobalThisPolicy;
|
|
|
|
|
2018-04-06 03:29:41 +03:00
|
|
|
// A this-extraction policy for lenient getters/setters.
|
|
|
|
struct LenientThisPolicy;
|
|
|
|
|
2018-04-06 03:29:41 +03:00
|
|
|
// A this-extraction policy for cross-origin getters/setters/methods.
|
|
|
|
struct CrossOriginThisPolicy;
|
|
|
|
|
2018-04-06 03:29:40 +03:00
|
|
|
// 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
|
2017-01-28 02:53:37 +03:00
|
|
|
|
2014-03-21 20:18:24 +04:00
|
|
|
bool
|
|
|
|
StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp);
|
|
|
|
|
2014-03-21 20:18:24 +04:00
|
|
|
// 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);
|
|
|
|
|
2014-05-15 21:26:23 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
|
|
AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo,
|
|
|
|
JS::Handle<JS::Value> aValue);
|
|
|
|
#endif
|
|
|
|
|
2014-08-20 05:12:15 +04:00
|
|
|
bool
|
|
|
|
CallerSubsumes(JSObject* aObject);
|
|
|
|
|
|
|
|
MOZ_ALWAYS_INLINE bool
|
|
|
|
CallerSubsumes(JS::Handle<JS::Value> aValue)
|
|
|
|
{
|
|
|
|
if (!aValue.isObject()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return CallerSubsumes(&aValue.toObject());
|
|
|
|
}
|
|
|
|
|
2014-08-28 02:43:56 +04:00
|
|
|
template<class T, class S>
|
2015-10-18 08:24:48 +03:00
|
|
|
inline RefPtr<T>
|
2014-08-28 02:43:56 +04:00
|
|
|
StrongOrRawPtr(already_AddRefed<S>&& aPtr)
|
|
|
|
{
|
2018-05-30 22:15:35 +03:00
|
|
|
return std::move(aPtr);
|
2014-08-28 02:43:56 +04:00
|
|
|
}
|
|
|
|
|
2014-11-01 17:08:00 +03:00
|
|
|
template<class T,
|
|
|
|
class ReturnType=typename Conditional<IsRefcounted<T>::value, T*,
|
|
|
|
nsAutoPtr<T>>::Type>
|
|
|
|
inline ReturnType
|
2014-08-28 02:43:56 +04:00
|
|
|
StrongOrRawPtr(T* aPtr)
|
|
|
|
{
|
2014-11-01 17:08:00 +03:00
|
|
|
return ReturnType(aPtr);
|
2014-08-28 02:43:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
template<class T, template<typename> class SmartPtr, class S>
|
|
|
|
inline void
|
2015-01-07 02:35:02 +03:00
|
|
|
StrongOrRawPtr(SmartPtr<S>&& aPtr) = delete;
|
2014-08-28 02:43:56 +04:00
|
|
|
|
2014-11-01 17:08:00 +03:00
|
|
|
template<class T>
|
|
|
|
struct StrongPtrForMember
|
|
|
|
{
|
|
|
|
typedef typename Conditional<IsRefcounted<T>::value,
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<T>, nsAutoPtr<T>>::Type Type;
|
2014-11-01 17:08:00 +03:00
|
|
|
};
|
|
|
|
|
2016-06-02 17:34:39 +03:00
|
|
|
namespace binding_detail {
|
|
|
|
inline
|
|
|
|
JSObject*
|
2016-07-09 07:19:52 +03:00
|
|
|
GetHackedNamespaceProtoObject(JSContext* aCx)
|
2016-06-02 17:34:39 +03:00
|
|
|
{
|
|
|
|
return JS_NewPlainObject(aCx);
|
|
|
|
}
|
|
|
|
} // namespace binding_detail
|
|
|
|
|
2015-03-06 09:08:06 +03:00
|
|
|
// 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);
|
|
|
|
|
2015-05-06 09:42:27 +03:00
|
|
|
// 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);
|
|
|
|
|
2015-07-31 20:30:55 +03:00
|
|
|
// 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);
|
2015-03-06 09:08:06 +03:00
|
|
|
|
2016-11-17 18:31:50 +03:00
|
|
|
// This function is expected to be called from the constructor function for an
|
2017-10-11 01:25:10 +03:00
|
|
|
// 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);
|
2016-11-17 18:31:50 +03:00
|
|
|
|
2015-02-05 20:53:01 +03:00
|
|
|
void
|
2017-08-18 17:02:15 +03:00
|
|
|
SetDocumentAndPageUseCounter(JSObject* aObject, UseCounter aUseCounter);
|
2015-02-05 20:53:01 +03:00
|
|
|
|
2015-09-28 21:25:04 +03:00
|
|
|
// Warnings
|
|
|
|
void
|
|
|
|
DeprecationWarning(JSContext* aCx, JSObject* aObject,
|
|
|
|
nsIDocument::DeprecatedOperations aOperation);
|
|
|
|
|
2017-02-07 10:58:35 +03:00
|
|
|
void
|
|
|
|
DeprecationWarning(const GlobalObject& aGlobal,
|
|
|
|
nsIDocument::DeprecatedOperations aOperation);
|
|
|
|
|
2015-10-27 23:25:14 +03:00
|
|
|
// A callback to perform funToString on an interface object
|
|
|
|
JSString*
|
|
|
|
InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
|
|
|
|
unsigned /* indent */);
|
2016-02-11 07:31:33 +03:00
|
|
|
|
|
|
|
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();
|
2018-03-27 22:49:02 +03:00
|
|
|
|
|
|
|
// 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);
|
2018-05-18 06:39:52 +03:00
|
|
|
|
|
|
|
// 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);
|
2016-02-11 07:31:33 +03:00
|
|
|
} // namespace binding_detail
|
|
|
|
|
2012-03-31 08:42:20 +04:00
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|
|
|
|
|
2012-05-03 08:35:38 +04:00
|
|
|
#endif /* mozilla_dom_BindingUtils_h__ */
|