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/. */
|
|
|
|
|
2013-08-14 10:56:21 +04:00
|
|
|
#include "BindingUtils.h"
|
|
|
|
|
2012-11-07 03:23:14 +04:00
|
|
|
#include <algorithm>
|
2012-07-18 14:36:08 +04:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
2016-08-03 15:37:31 +03:00
|
|
|
#include "mozilla/Assertions.h"
|
2012-12-15 03:58:45 +04:00
|
|
|
#include "mozilla/DebugOnly.h"
|
2013-05-02 22:38:19 +04:00
|
|
|
#include "mozilla/FloatingPoint.h"
|
2014-05-09 01:16:00 +04:00
|
|
|
#include "mozilla/Preferences.h"
|
2016-08-23 07:09:32 +03:00
|
|
|
#include "mozilla/Unused.h"
|
2015-02-05 20:53:01 +03:00
|
|
|
#include "mozilla/UseCounter.h"
|
2012-12-15 03:58:45 +04:00
|
|
|
|
2012-10-09 22:50:05 +04:00
|
|
|
#include "AccessCheck.h"
|
2013-06-01 10:56:23 +04:00
|
|
|
#include "jsfriendapi.h"
|
2016-11-17 18:31:50 +03:00
|
|
|
#include "nsContentCreatorFunctions.h"
|
2014-02-05 22:38:17 +04:00
|
|
|
#include "nsContentUtils.h"
|
2014-05-25 22:31:07 +04:00
|
|
|
#include "nsGlobalWindow.h"
|
2017-09-05 13:19:06 +03:00
|
|
|
#include "nsHTMLTags.h"
|
2015-01-09 02:06:33 +03:00
|
|
|
#include "nsIDocShell.h"
|
2013-06-01 10:56:23 +04:00
|
|
|
#include "nsIDOMGlobalPropertyInitializer.h"
|
2018-01-30 07:10:53 +03:00
|
|
|
#include "nsINode.h"
|
2014-05-25 22:31:07 +04:00
|
|
|
#include "nsIPermissionManager.h"
|
2014-02-05 22:38:17 +04:00
|
|
|
#include "nsIPrincipal.h"
|
2012-09-26 18:17:46 +04:00
|
|
|
#include "nsIXPConnect.h"
|
2014-08-02 00:23:48 +04:00
|
|
|
#include "nsUTF8Utils.h"
|
2016-06-01 13:15:34 +03:00
|
|
|
#include "WorkerPrivate.h"
|
|
|
|
#include "WorkerRunnable.h"
|
2012-05-22 17:46:20 +04:00
|
|
|
#include "WrapperFactory.h"
|
2012-05-18 12:29:40 +04:00
|
|
|
#include "xpcprivate.h"
|
2012-09-26 18:17:46 +04:00
|
|
|
#include "XrayWrapper.h"
|
2013-07-04 17:24:49 +04:00
|
|
|
#include "nsPrintfCString.h"
|
2016-08-15 09:43:21 +03:00
|
|
|
#include "mozilla/Sprintf.h"
|
2015-02-05 20:53:01 +03:00
|
|
|
#include "nsGlobalWindow.h"
|
2012-05-18 12:29:40 +04:00
|
|
|
|
2013-12-12 05:51:58 +04:00
|
|
|
#include "mozilla/dom/ScriptSettings.h"
|
2016-11-17 18:31:50 +03:00
|
|
|
#include "mozilla/dom/CustomElementRegistry.h"
|
2015-10-09 23:48:10 +03:00
|
|
|
#include "mozilla/dom/DOMException.h"
|
2014-09-15 18:51:40 +04:00
|
|
|
#include "mozilla/dom/ElementBinding.h"
|
2013-01-07 03:55:14 +04:00
|
|
|
#include "mozilla/dom/HTMLObjectElement.h"
|
|
|
|
#include "mozilla/dom/HTMLObjectElementBinding.h"
|
2017-07-29 07:35:43 +03:00
|
|
|
#include "mozilla/dom/HTMLEmbedElement.h"
|
2016-11-17 18:31:50 +03:00
|
|
|
#include "mozilla/dom/HTMLElementBinding.h"
|
2013-03-17 18:42:05 +04:00
|
|
|
#include "mozilla/dom/HTMLEmbedElementBinding.h"
|
2017-10-11 01:25:10 +03:00
|
|
|
#include "mozilla/dom/XULElementBinding.h"
|
2018-05-11 22:44:46 +03:00
|
|
|
#include "mozilla/dom/XULPopupElementBinding.h"
|
2014-03-21 20:18:24 +04:00
|
|
|
#include "mozilla/dom/Promise.h"
|
2015-03-06 09:08:06 +03:00
|
|
|
#include "mozilla/dom/ResolveSystemBinding.h"
|
2016-05-09 18:08:31 +03:00
|
|
|
#include "mozilla/dom/WebIDLGlobalNameHash.h"
|
2016-02-11 07:31:33 +03:00
|
|
|
#include "mozilla/dom/WorkerPrivate.h"
|
|
|
|
#include "mozilla/dom/WorkerScope.h"
|
2016-10-11 01:16:25 +03:00
|
|
|
#include "mozilla/dom/XrayExpandoClass.h"
|
2015-01-27 00:32:18 +03:00
|
|
|
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
2015-04-07 04:36:55 +03:00
|
|
|
#include "ipc/ErrorIPCUtils.h"
|
2015-02-05 20:53:01 +03:00
|
|
|
#include "mozilla/UseCounter.h"
|
2017-03-08 12:11:48 +03:00
|
|
|
#include "mozilla/dom/DocGroup.h"
|
2017-10-11 01:25:10 +03:00
|
|
|
#include "nsXULElement.h"
|
2013-01-07 03:55:14 +04:00
|
|
|
|
2012-03-31 08:42:20 +04:00
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
|
|
|
|
2016-11-17 18:31:50 +03:00
|
|
|
// Forward declare GetConstructorObject methods.
|
|
|
|
#define HTML_TAG(_tag, _classname, _interfacename) \
|
|
|
|
namespace HTML##_interfacename##ElementBinding { \
|
|
|
|
JSObject* GetConstructorObject(JSContext*); \
|
|
|
|
}
|
|
|
|
#define HTML_OTHER(_tag)
|
|
|
|
#include "nsHTMLTagList.h"
|
|
|
|
#undef HTML_TAG
|
|
|
|
#undef HTML_OTHER
|
|
|
|
|
|
|
|
typedef JSObject* (*constructorGetterCallback)(JSContext*);
|
|
|
|
|
|
|
|
// Mapping of html tag and GetConstructorObject methods.
|
|
|
|
#define HTML_TAG(_tag, _classname, _interfacename) HTML##_interfacename##ElementBinding::GetConstructorObject,
|
|
|
|
#define HTML_OTHER(_tag) nullptr,
|
|
|
|
// We use eHTMLTag_foo (where foo is the tag) which is defined in nsHTMLTags.h
|
|
|
|
// to index into this array.
|
|
|
|
static const constructorGetterCallback sConstructorGetterCallback[] = {
|
|
|
|
HTMLUnknownElementBinding::GetConstructorObject,
|
|
|
|
#include "nsHTMLTagList.h"
|
|
|
|
#undef HTML_TAG
|
|
|
|
#undef HTML_OTHER
|
|
|
|
};
|
|
|
|
|
2016-03-11 05:05:10 +03:00
|
|
|
const JSErrorFormatString ErrorFormatString[] = {
|
2015-02-04 14:46:26 +03:00
|
|
|
#define MSG_DEF(_name, _argc, _exn, _str) \
|
2016-03-04 23:21:57 +03:00
|
|
|
{ #_name, _str, _argc, _exn },
|
2012-07-18 14:36:08 +04:00
|
|
|
#include "mozilla/dom/Errors.msg"
|
|
|
|
#undef MSG_DEF
|
|
|
|
};
|
|
|
|
|
2015-09-15 21:47:04 +03:00
|
|
|
#define MSG_DEF(_name, _argc, _exn, _str) \
|
|
|
|
static_assert(_argc < JS::MaxNumErrorArguments, \
|
|
|
|
#_name " must only have as many error arguments as the JS engine can support");
|
|
|
|
#include "mozilla/dom/Errors.msg"
|
|
|
|
#undef MSG_DEF
|
|
|
|
|
2012-07-18 14:36:08 +04:00
|
|
|
const JSErrorFormatString*
|
2014-07-15 17:14:38 +04:00
|
|
|
GetErrorMessage(void* aUserRef, const unsigned aErrorNumber)
|
2012-07-18 14:36:08 +04:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(aErrorNumber < ArrayLength(ErrorFormatString));
|
|
|
|
return &ErrorFormatString[aErrorNumber];
|
|
|
|
}
|
|
|
|
|
2015-09-15 21:47:04 +03:00
|
|
|
uint16_t
|
|
|
|
GetErrorArgCount(const ErrNum aErrorNumber)
|
|
|
|
{
|
|
|
|
return GetErrorMessage(nullptr, aErrorNumber)->argCount;
|
|
|
|
}
|
|
|
|
|
2016-07-21 01:06:48 +03:00
|
|
|
void
|
|
|
|
binding_detail::ThrowErrorMessage(JSContext* aCx, const unsigned aErrorNumber, ...)
|
2012-07-18 14:36:08 +04:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, aErrorNumber);
|
2016-08-14 14:39:30 +03:00
|
|
|
JS_ReportErrorNumberUTF8VA(aCx, GetErrorMessage, nullptr, aErrorNumber, ap);
|
2012-07-18 14:36:08 +04:00
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
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)
|
2013-06-17 21:07:03 +04:00
|
|
|
{
|
|
|
|
NS_ConvertASCIItoUTF16 ifaceName(aInterfaceName);
|
2013-06-18 00:31:13 +04:00
|
|
|
// This should only be called for DOM methods/getters/setters, which
|
|
|
|
// are JSNative-backed functions, so we can assume that
|
|
|
|
// JS_ValueToFunction and JS_GetFunctionDisplayId will both return
|
|
|
|
// non-null and that JS_GetStringCharsZ returns non-null.
|
2013-06-17 21:07:03 +04:00
|
|
|
JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, aArgs.calleev()));
|
|
|
|
MOZ_ASSERT(func);
|
|
|
|
JS::Rooted<JSString*> funcName(aCx, JS_GetFunctionDisplayId(func));
|
|
|
|
MOZ_ASSERT(funcName);
|
2014-07-12 11:43:06 +04:00
|
|
|
nsAutoJSString funcNameStr;
|
|
|
|
if (!funcNameStr.init(aCx, funcName)) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-01-06 11:54:00 +03:00
|
|
|
const ErrNum errorNumber = aSecurityError ?
|
|
|
|
MSG_METHOD_THIS_UNWRAPPING_DENIED :
|
|
|
|
MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
|
|
|
|
MOZ_RELEASE_ASSERT(GetErrorArgCount(errorNumber) <= 2);
|
2013-06-17 21:07:03 +04:00
|
|
|
JS_ReportErrorNumberUC(aCx, GetErrorMessage, nullptr,
|
2017-12-12 17:13:55 +03:00
|
|
|
static_cast<unsigned>(errorNumber),
|
2014-07-12 11:43:06 +04:00
|
|
|
funcNameStr.get(), ifaceName.get());
|
2013-06-17 21:07:03 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
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,
|
2014-02-08 00:56:14 +04:00
|
|
|
prototypes::ID aProtoId)
|
|
|
|
{
|
2016-01-06 11:54:00 +03:00
|
|
|
return ThrowInvalidThis(aCx, aArgs, aSecurityError,
|
2014-02-10 19:24:38 +04:00
|
|
|
NamesOfInterfacesWithProtos(aProtoId));
|
2014-02-08 00:56:14 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ThrowNoSetterArg(JSContext* aCx, prototypes::ID aProtoId)
|
|
|
|
{
|
|
|
|
nsPrintfCString errorMessage("%s attribute setter",
|
2014-02-10 19:24:38 +04:00
|
|
|
NamesOfInterfacesWithProtos(aProtoId));
|
2014-02-08 00:56:14 +04:00
|
|
|
return ThrowErrorMessage(aCx, MSG_MISSING_ARGUMENTS, errorMessage.get());
|
|
|
|
}
|
|
|
|
|
2012-11-07 03:23:14 +04:00
|
|
|
} // namespace dom
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
namespace binding_danger {
|
|
|
|
|
|
|
|
template<typename CleanupPolicy>
|
|
|
|
struct TErrorResult<CleanupPolicy>::Message {
|
2018-04-13 16:01:28 +03:00
|
|
|
Message() { MOZ_COUNT_CTOR(TErrorResult::Message); }
|
2016-07-16 05:35:13 +03:00
|
|
|
~Message() { MOZ_COUNT_DTOR(TErrorResult::Message); }
|
2015-10-26 16:50:00 +03:00
|
|
|
|
2012-11-07 03:23:14 +04:00
|
|
|
nsTArray<nsString> mArgs;
|
|
|
|
dom::ErrNum mErrorNumber;
|
2015-09-15 21:47:04 +03:00
|
|
|
|
|
|
|
bool HasCorrectNumberOfArguments()
|
|
|
|
{
|
|
|
|
return GetErrorArgCount(mErrorNumber) == mArgs.Length();
|
|
|
|
}
|
2018-04-26 23:50:56 +03:00
|
|
|
|
|
|
|
bool operator==(const TErrorResult<CleanupPolicy>::Message& aRight)
|
|
|
|
{
|
|
|
|
return mErrorNumber == aRight.mErrorNumber &&
|
|
|
|
mArgs == aRight.mArgs;
|
|
|
|
}
|
2012-11-07 03:23:14 +04:00
|
|
|
};
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2015-09-15 21:47:04 +03:00
|
|
|
nsTArray<nsString>&
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::CreateErrorMessageHelper(const dom::ErrNum errorNumber,
|
|
|
|
nsresult errorType)
|
2015-09-15 21:47:04 +03:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2015-09-15 21:47:04 +03:00
|
|
|
mResult = errorType;
|
|
|
|
|
2018-04-26 05:40:09 +03:00
|
|
|
Message* message = InitMessage(new Message());
|
|
|
|
message->mErrorNumber = errorNumber;
|
|
|
|
return message->mArgs;
|
2015-09-15 21:47:04 +03:00
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2015-04-07 04:36:55 +03:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::SerializeMessage(IPC::Message* aMsg) const
|
2015-04-07 04:36:55 +03:00
|
|
|
{
|
|
|
|
using namespace IPC;
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2015-10-09 23:48:10 +03:00
|
|
|
MOZ_ASSERT(mUnionState == HasMessage);
|
2018-04-26 05:40:09 +03:00
|
|
|
MOZ_ASSERT(mExtra.mMessage);
|
|
|
|
WriteParam(aMsg, mExtra.mMessage->mArgs);
|
|
|
|
WriteParam(aMsg, mExtra.mMessage->mErrorNumber);
|
2015-04-07 04:36:55 +03:00
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2015-04-07 04:36:55 +03:00
|
|
|
bool
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::DeserializeMessage(const IPC::Message* aMsg,
|
|
|
|
PickleIterator* aIter)
|
2015-04-07 04:36:55 +03:00
|
|
|
{
|
|
|
|
using namespace IPC;
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2015-04-07 04:36:55 +03:00
|
|
|
nsAutoPtr<Message> readMessage(new Message());
|
|
|
|
if (!ReadParam(aMsg, aIter, &readMessage->mArgs) ||
|
|
|
|
!ReadParam(aMsg, aIter, &readMessage->mErrorNumber)) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-09-15 21:47:04 +03:00
|
|
|
if (!readMessage->HasCorrectNumberOfArguments()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-09 23:48:10 +03:00
|
|
|
MOZ_ASSERT(mUnionState == HasNothing);
|
2018-04-26 05:40:09 +03:00
|
|
|
InitMessage(readMessage.forget());
|
2015-04-15 21:09:28 +03:00
|
|
|
#ifdef DEBUG
|
2015-10-09 23:48:10 +03:00
|
|
|
mUnionState = HasMessage;
|
|
|
|
#endif // DEBUG
|
2015-04-07 04:36:55 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2012-11-07 03:23:14 +04:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::SetPendingExceptionWithMessage(JSContext* aCx)
|
2012-11-07 03:23:14 +04:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2015-10-09 23:48:10 +03:00
|
|
|
MOZ_ASSERT(mUnionState == HasMessage);
|
2018-04-26 05:40:09 +03:00
|
|
|
MOZ_ASSERT(mExtra.mMessage,
|
|
|
|
"SetPendingExceptionWithMessage() can be called only once");
|
2012-11-07 03:23:14 +04:00
|
|
|
|
2018-04-26 05:40:09 +03:00
|
|
|
Message* message = mExtra.mMessage;
|
2015-09-15 21:47:04 +03:00
|
|
|
MOZ_RELEASE_ASSERT(message->HasCorrectNumberOfArguments());
|
2012-11-07 03:23:14 +04:00
|
|
|
const uint32_t argCount = message->mArgs.Length();
|
2015-09-15 21:47:04 +03:00
|
|
|
const char16_t* args[JS::MaxNumErrorArguments + 1];
|
2012-11-07 03:23:14 +04:00
|
|
|
for (uint32_t i = 0; i < argCount; ++i) {
|
|
|
|
args[i] = message->mArgs.ElementAt(i).get();
|
|
|
|
}
|
|
|
|
args[argCount] = nullptr;
|
|
|
|
|
|
|
|
JS_ReportErrorNumberUCArray(aCx, dom::GetErrorMessage, nullptr,
|
2017-12-12 17:13:55 +03:00
|
|
|
static_cast<unsigned>(message->mErrorNumber),
|
2012-11-07 03:23:14 +04:00
|
|
|
argCount > 0 ? args : nullptr);
|
|
|
|
|
2013-02-19 17:30:28 +04:00
|
|
|
ClearMessage();
|
2015-11-21 00:29:41 +03:00
|
|
|
mResult = NS_OK;
|
2013-02-19 17:30:28 +04:00
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2013-02-19 17:30:28 +04:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::ClearMessage()
|
2013-02-19 17:30:28 +04:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2015-04-27 05:38:17 +03:00
|
|
|
MOZ_ASSERT(IsErrorWithMessage());
|
2018-04-26 05:40:09 +03:00
|
|
|
MOZ_ASSERT(mUnionState == HasMessage);
|
|
|
|
delete mExtra.mMessage;
|
|
|
|
mExtra.mMessage = nullptr;
|
2015-04-15 21:09:28 +03:00
|
|
|
#ifdef DEBUG
|
2015-10-09 23:48:10 +03:00
|
|
|
mUnionState = HasNothing;
|
|
|
|
#endif // DEBUG
|
2012-11-07 03:23:14 +04:00
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2013-02-19 20:54:40 +04:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::ThrowJSException(JSContext* cx, JS::Handle<JS::Value> exn)
|
2013-02-19 20:54:40 +04:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2013-02-19 20:54:40 +04:00
|
|
|
MOZ_ASSERT(mMightHaveUnreportedJSException,
|
|
|
|
"Why didn't you tell us you planned to throw a JS exception?");
|
|
|
|
|
2015-10-09 23:48:10 +03:00
|
|
|
ClearUnionData();
|
2013-02-19 20:54:40 +04:00
|
|
|
|
2018-04-26 05:40:09 +03:00
|
|
|
// Make sure mExtra.mJSException is initialized _before_ we try to root it.
|
|
|
|
// But don't set it to exn yet, because we don't want to do that until after
|
|
|
|
// we root.
|
|
|
|
JS::Value& exc = InitJSException();
|
|
|
|
if (!js::AddRawValueRoot(cx, &exc, "TErrorResult::mExtra::mJSException")) {
|
2017-02-15 08:02:35 +03:00
|
|
|
// Don't use NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION, because that
|
2018-04-26 05:40:09 +03:00
|
|
|
// indicates we have in fact rooted mExtra.mJSException.
|
2013-02-19 20:54:40 +04:00
|
|
|
mResult = NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
} else {
|
2018-04-26 05:40:09 +03:00
|
|
|
exc = exn;
|
2017-02-15 08:02:35 +03:00
|
|
|
mResult = NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION;
|
2015-10-09 23:48:10 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
mUnionState = HasJSException;
|
|
|
|
#endif // DEBUG
|
2013-02-19 20:54:40 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2013-02-19 20:54:40 +04:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::SetPendingJSException(JSContext* cx)
|
2013-02-19 20:54:40 +04:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2013-02-19 20:54:40 +04:00
|
|
|
MOZ_ASSERT(!mMightHaveUnreportedJSException,
|
|
|
|
"Why didn't you tell us you planned to handle JS exceptions?");
|
2015-10-09 23:48:10 +03:00
|
|
|
MOZ_ASSERT(mUnionState == HasJSException);
|
2013-10-26 20:19:05 +04:00
|
|
|
|
2018-04-26 05:40:09 +03:00
|
|
|
JS::Rooted<JS::Value> exception(cx, mExtra.mJSException);
|
2013-10-26 20:19:05 +04:00
|
|
|
if (JS_WrapValue(cx, &exception)) {
|
2013-09-19 11:54:01 +04:00
|
|
|
JS_SetPendingException(cx, exception);
|
2013-02-19 20:54:40 +04:00
|
|
|
}
|
2018-04-26 05:40:09 +03:00
|
|
|
mExtra.mJSException = exception;
|
2013-02-19 20:54:40 +04:00
|
|
|
// If JS_WrapValue failed, not much we can do about it... No matter
|
2018-04-26 05:40:09 +03:00
|
|
|
// what, go ahead and unroot mExtra.mJSException.
|
|
|
|
js::RemoveRawValueRoot(cx, &mExtra.mJSException);
|
2015-01-03 01:08:33 +03:00
|
|
|
|
2015-11-21 00:29:41 +03:00
|
|
|
mResult = NS_OK;
|
2015-10-09 23:48:10 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
mUnionState = HasNothing;
|
|
|
|
#endif // DEBUG
|
2013-02-19 20:54:40 +04:00
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
|
|
|
struct TErrorResult<CleanupPolicy>::DOMExceptionInfo {
|
2015-10-09 23:48:10 +03:00
|
|
|
DOMExceptionInfo(nsresult rv, const nsACString& message)
|
|
|
|
: mMessage(message)
|
|
|
|
, mRv(rv)
|
|
|
|
{}
|
|
|
|
|
|
|
|
nsCString mMessage;
|
|
|
|
nsresult mRv;
|
2018-04-26 23:50:56 +03:00
|
|
|
|
|
|
|
bool operator==(const TErrorResult<CleanupPolicy>::DOMExceptionInfo& aRight)
|
|
|
|
{
|
|
|
|
return mRv == aRight.mRv &&
|
|
|
|
mMessage == aRight.mMessage;
|
|
|
|
}
|
2015-10-09 23:48:10 +03:00
|
|
|
};
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2015-10-09 23:48:10 +03:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::SerializeDOMExceptionInfo(IPC::Message* aMsg) const
|
2015-10-09 23:48:10 +03:00
|
|
|
{
|
|
|
|
using namespace IPC;
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2015-10-09 23:48:10 +03:00
|
|
|
MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
|
2018-04-26 05:40:09 +03:00
|
|
|
MOZ_ASSERT(mExtra.mDOMExceptionInfo);
|
|
|
|
WriteParam(aMsg, mExtra.mDOMExceptionInfo->mMessage);
|
|
|
|
WriteParam(aMsg, mExtra.mDOMExceptionInfo->mRv);
|
2015-10-09 23:48:10 +03:00
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2015-10-09 23:48:10 +03:00
|
|
|
bool
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::DeserializeDOMExceptionInfo(const IPC::Message* aMsg,
|
|
|
|
PickleIterator* aIter)
|
2015-10-09 23:48:10 +03:00
|
|
|
{
|
|
|
|
using namespace IPC;
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2015-10-09 23:48:10 +03:00
|
|
|
nsCString message;
|
|
|
|
nsresult rv;
|
|
|
|
if (!ReadParam(aMsg, aIter, &message) ||
|
|
|
|
!ReadParam(aMsg, aIter, &rv)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-09 23:48:10 +03:00
|
|
|
MOZ_ASSERT(mUnionState == HasNothing);
|
2015-10-09 23:48:10 +03:00
|
|
|
MOZ_ASSERT(IsDOMException());
|
2018-04-26 05:40:09 +03:00
|
|
|
InitDOMExceptionInfo(new DOMExceptionInfo(rv, message));
|
2015-10-09 23:48:10 +03:00
|
|
|
#ifdef DEBUG
|
2015-10-09 23:48:10 +03:00
|
|
|
mUnionState = HasDOMExceptionInfo;
|
|
|
|
#endif // DEBUG
|
2015-10-09 23:48:10 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2015-10-09 23:48:10 +03:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::ThrowDOMException(nsresult rv,
|
|
|
|
const nsACString& message)
|
2015-10-09 23:48:10 +03:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2015-10-09 23:48:10 +03:00
|
|
|
ClearUnionData();
|
|
|
|
|
2017-02-15 08:02:35 +03:00
|
|
|
mResult = NS_ERROR_INTERNAL_ERRORRESULT_DOMEXCEPTION;
|
2018-04-26 05:40:09 +03:00
|
|
|
InitDOMExceptionInfo(new DOMExceptionInfo(rv, message));
|
2015-10-09 23:48:10 +03:00
|
|
|
#ifdef DEBUG
|
2015-10-09 23:48:10 +03:00
|
|
|
mUnionState = HasDOMExceptionInfo;
|
2015-10-09 23:48:10 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2015-10-09 23:48:10 +03:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::SetPendingDOMException(JSContext* cx)
|
2015-10-09 23:48:10 +03:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2015-10-09 23:48:10 +03:00
|
|
|
MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
|
2018-04-26 05:40:09 +03:00
|
|
|
MOZ_ASSERT(mExtra.mDOMExceptionInfo,
|
|
|
|
"SetPendingDOMException() can be called only once");
|
2015-10-09 23:48:10 +03:00
|
|
|
|
2018-04-26 05:40:09 +03:00
|
|
|
dom::Throw(cx, mExtra.mDOMExceptionInfo->mRv,
|
|
|
|
mExtra.mDOMExceptionInfo->mMessage);
|
2015-10-09 23:48:10 +03:00
|
|
|
|
|
|
|
ClearDOMExceptionInfo();
|
2015-11-21 00:29:41 +03:00
|
|
|
mResult = NS_OK;
|
2015-10-09 23:48:10 +03:00
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2015-10-09 23:48:10 +03:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::ClearDOMExceptionInfo()
|
2015-10-09 23:48:10 +03:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2015-10-09 23:48:10 +03:00
|
|
|
MOZ_ASSERT(IsDOMException());
|
2018-04-26 05:40:09 +03:00
|
|
|
MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
|
|
|
|
delete mExtra.mDOMExceptionInfo;
|
|
|
|
mExtra.mDOMExceptionInfo = nullptr;
|
2015-10-09 23:48:10 +03:00
|
|
|
#ifdef DEBUG
|
2015-10-09 23:48:10 +03:00
|
|
|
mUnionState = HasNothing;
|
|
|
|
#endif // DEBUG
|
2015-10-09 23:48:10 +03:00
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2015-10-09 23:48:10 +03:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::ClearUnionData()
|
2015-10-09 23:48:10 +03:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2015-10-09 23:48:10 +03:00
|
|
|
if (IsJSException()) {
|
2016-08-11 15:39:23 +03:00
|
|
|
JSContext* cx = dom::danger::GetJSContext();
|
2015-10-09 23:48:10 +03:00
|
|
|
MOZ_ASSERT(cx);
|
2018-04-26 05:40:09 +03:00
|
|
|
mExtra.mJSException.setUndefined();
|
|
|
|
js::RemoveRawValueRoot(cx, &mExtra.mJSException);
|
2015-10-09 23:48:10 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
mUnionState = HasNothing;
|
|
|
|
#endif // DEBUG
|
2015-10-09 23:48:10 +03:00
|
|
|
} else if (IsErrorWithMessage()) {
|
|
|
|
ClearMessage();
|
2015-10-09 23:48:10 +03:00
|
|
|
} else if (IsDOMException()) {
|
|
|
|
ClearDOMExceptionInfo();
|
2015-10-09 23:48:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2015-04-27 16:18:52 +03:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::SetPendingGenericErrorException(JSContext* cx)
|
2015-04-27 16:18:52 +03:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2015-04-27 16:18:52 +03:00
|
|
|
MOZ_ASSERT(!IsErrorWithMessage());
|
|
|
|
MOZ_ASSERT(!IsJSException());
|
2015-10-09 23:48:10 +03:00
|
|
|
MOZ_ASSERT(!IsDOMException());
|
2015-04-27 16:18:52 +03:00
|
|
|
dom::Throw(cx, ErrorCode());
|
2015-11-21 00:29:41 +03:00
|
|
|
mResult = NS_OK;
|
2013-07-04 17:24:49 +04:00
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
|
|
|
TErrorResult<CleanupPolicy>&
|
|
|
|
TErrorResult<CleanupPolicy>::operator=(TErrorResult<CleanupPolicy>&& aRHS)
|
2015-04-07 05:22:03 +03:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
|
|
|
aRHS.AssertInOwningThread();
|
2015-10-09 23:48:10 +03:00
|
|
|
// Clear out any union members we may have right now, before we
|
|
|
|
// start writing to it.
|
|
|
|
ClearUnionData();
|
|
|
|
|
2015-04-07 05:22:03 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
mMightHaveUnreportedJSException = aRHS.mMightHaveUnreportedJSException;
|
|
|
|
aRHS.mMightHaveUnreportedJSException = false;
|
|
|
|
#endif
|
|
|
|
if (aRHS.IsErrorWithMessage()) {
|
2018-04-26 05:40:09 +03:00
|
|
|
InitMessage(aRHS.mExtra.mMessage);
|
|
|
|
aRHS.mExtra.mMessage = nullptr;
|
2015-04-07 05:22:03 +03:00
|
|
|
} else if (aRHS.IsJSException()) {
|
2016-08-11 15:39:23 +03:00
|
|
|
JSContext* cx = dom::danger::GetJSContext();
|
2015-04-07 05:22:03 +03:00
|
|
|
MOZ_ASSERT(cx);
|
2018-04-26 05:40:09 +03:00
|
|
|
JS::Value& exn = InitJSException();
|
|
|
|
if (!js::AddRawValueRoot(cx, &exn,
|
|
|
|
"TErrorResult::mExtra::mJSException")) {
|
|
|
|
MOZ_CRASH("Could not root mExtra.mJSException, we're about to OOM");
|
2015-04-07 05:22:03 +03:00
|
|
|
}
|
2018-04-26 05:40:09 +03:00
|
|
|
mExtra.mJSException = aRHS.mExtra.mJSException;
|
|
|
|
aRHS.mExtra.mJSException.setUndefined();
|
|
|
|
js::RemoveRawValueRoot(cx, &aRHS.mExtra.mJSException);
|
2015-10-09 23:48:10 +03:00
|
|
|
} else if (aRHS.IsDOMException()) {
|
2018-04-26 05:40:09 +03:00
|
|
|
InitDOMExceptionInfo(aRHS.mExtra.mDOMExceptionInfo);
|
|
|
|
aRHS.mExtra.mDOMExceptionInfo = nullptr;
|
2015-04-07 05:22:03 +03:00
|
|
|
} else {
|
2018-04-26 05:40:09 +03:00
|
|
|
// Null out the union on both sides for hygiene purposes. This is purely
|
|
|
|
// precautionary, so InitMessage/placement-new is unnecessary.
|
|
|
|
mExtra.mMessage = aRHS.mExtra.mMessage = nullptr;
|
2015-04-07 05:22:03 +03:00
|
|
|
}
|
2015-10-09 23:48:10 +03:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
mUnionState = aRHS.mUnionState;
|
|
|
|
aRHS.mUnionState = HasNothing;
|
|
|
|
#endif // DEBUG
|
|
|
|
|
2015-04-07 05:22:03 +03:00
|
|
|
// Note: It's important to do this last, since this affects the condition
|
|
|
|
// checks above!
|
|
|
|
mResult = aRHS.mResult;
|
|
|
|
aRHS.mResult = NS_OK;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2015-11-18 22:07:58 +03:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::CloneTo(TErrorResult& aRv) const
|
2015-11-18 22:07:58 +03:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
|
|
|
aRv.AssertInOwningThread();
|
2015-11-18 22:07:58 +03:00
|
|
|
aRv.ClearUnionData();
|
|
|
|
aRv.mResult = mResult;
|
|
|
|
#ifdef DEBUG
|
|
|
|
aRv.mMightHaveUnreportedJSException = mMightHaveUnreportedJSException;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (IsErrorWithMessage()) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
aRv.mUnionState = HasMessage;
|
|
|
|
#endif
|
2018-04-26 05:40:09 +03:00
|
|
|
Message* message = aRv.InitMessage(new Message());
|
|
|
|
message->mArgs = mExtra.mMessage->mArgs;
|
|
|
|
message->mErrorNumber = mExtra.mMessage->mErrorNumber;
|
2015-11-18 22:07:58 +03:00
|
|
|
} else if (IsDOMException()) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
aRv.mUnionState = HasDOMExceptionInfo;
|
|
|
|
#endif
|
2018-04-26 05:40:09 +03:00
|
|
|
auto* exnInfo = new DOMExceptionInfo(mExtra.mDOMExceptionInfo->mRv,
|
|
|
|
mExtra.mDOMExceptionInfo->mMessage);
|
|
|
|
aRv.InitDOMExceptionInfo(exnInfo);
|
2015-11-18 22:07:58 +03:00
|
|
|
} else if (IsJSException()) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
aRv.mUnionState = HasJSException;
|
|
|
|
#endif
|
2016-08-11 15:39:23 +03:00
|
|
|
JSContext* cx = dom::danger::GetJSContext();
|
2018-04-26 05:40:09 +03:00
|
|
|
JS::Rooted<JS::Value> exception(cx, mExtra.mJSException);
|
2015-11-18 22:07:58 +03:00
|
|
|
aRv.ThrowJSException(cx, exception);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2015-04-27 05:38:17 +03:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::SuppressException()
|
2015-04-27 05:38:17 +03:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2015-04-27 05:38:17 +03:00
|
|
|
WouldReportJSException();
|
2015-10-09 23:48:10 +03:00
|
|
|
ClearUnionData();
|
2015-04-27 05:38:17 +03:00
|
|
|
// We don't use AssignErrorCode, because we want to override existing error
|
|
|
|
// states, which AssignErrorCode is not allowed to do.
|
|
|
|
mResult = NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2015-11-21 00:29:40 +03:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::SetPendingException(JSContext* cx)
|
2015-11-21 00:29:40 +03:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2015-11-21 00:29:40 +03:00
|
|
|
if (IsUncatchableException()) {
|
|
|
|
// Nuke any existing exception on cx, to make sure we're uncatchable.
|
|
|
|
JS_ClearPendingException(cx);
|
|
|
|
// Don't do any reporting. Just return, to create an
|
|
|
|
// uncatchable exception.
|
2015-11-21 00:29:41 +03:00
|
|
|
mResult = NS_OK;
|
2015-11-21 00:29:40 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (IsJSContextException()) {
|
2016-03-10 12:50:56 +03:00
|
|
|
// Whatever we need to throw is on the JSContext already.
|
|
|
|
MOZ_ASSERT(JS_IsExceptionPending(cx));
|
2015-11-21 00:29:41 +03:00
|
|
|
mResult = NS_OK;
|
2015-11-21 00:29:40 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (IsErrorWithMessage()) {
|
2015-11-21 00:29:41 +03:00
|
|
|
SetPendingExceptionWithMessage(cx);
|
2015-11-21 00:29:40 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (IsJSException()) {
|
2015-11-21 00:29:41 +03:00
|
|
|
SetPendingJSException(cx);
|
2015-11-21 00:29:40 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (IsDOMException()) {
|
2015-11-21 00:29:41 +03:00
|
|
|
SetPendingDOMException(cx);
|
2015-11-21 00:29:40 +03:00
|
|
|
return;
|
|
|
|
}
|
2015-11-21 00:29:41 +03:00
|
|
|
SetPendingGenericErrorException(cx);
|
2015-11-21 00:29:40 +03:00
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2016-02-24 18:38:31 +03:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::StealExceptionFromJSContext(JSContext* cx)
|
2016-02-24 18:38:31 +03:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2016-02-24 18:38:31 +03:00
|
|
|
MOZ_ASSERT(mMightHaveUnreportedJSException,
|
|
|
|
"Why didn't you tell us you planned to throw a JS exception?");
|
|
|
|
|
|
|
|
JS::Rooted<JS::Value> exn(cx);
|
|
|
|
if (!JS_GetPendingException(cx, &exn)) {
|
|
|
|
ThrowUncatchableException();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ThrowJSException(cx, exn);
|
|
|
|
JS_ClearPendingException(cx);
|
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template<typename CleanupPolicy>
|
2016-03-10 12:50:56 +03:00
|
|
|
void
|
2016-07-16 05:35:13 +03:00
|
|
|
TErrorResult<CleanupPolicy>::NoteJSContextException(JSContext* aCx)
|
2016-03-10 12:50:56 +03:00
|
|
|
{
|
2016-07-16 05:35:13 +03:00
|
|
|
AssertInOwningThread();
|
2016-03-10 12:50:56 +03:00
|
|
|
if (JS_IsExceptionPending(aCx)) {
|
2017-02-15 08:02:35 +03:00
|
|
|
mResult = NS_ERROR_INTERNAL_ERRORRESULT_EXCEPTION_ON_JSCONTEXT;
|
2016-03-10 12:50:56 +03:00
|
|
|
} else {
|
|
|
|
mResult = NS_ERROR_UNCATCHABLE_EXCEPTION;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-16 05:35:13 +03:00
|
|
|
template class TErrorResult<JustAssertCleanupPolicy>;
|
2016-07-16 05:35:13 +03:00
|
|
|
template class TErrorResult<AssertAndSuppressCleanupPolicy>;
|
|
|
|
template class TErrorResult<JustSuppressCleanupPolicy>;
|
2018-04-26 23:50:56 +03:00
|
|
|
template class TErrorResult<ThreadSafeJustSuppressCleanupPolicy>;
|
2016-07-16 05:35:13 +03:00
|
|
|
|
|
|
|
} // namespace binding_danger
|
|
|
|
|
2012-11-07 03:23:14 +04:00
|
|
|
namespace dom {
|
|
|
|
|
2012-05-09 14:00:48 +04:00
|
|
|
bool
|
2013-05-08 06:34:56 +04:00
|
|
|
DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
|
|
|
|
const ConstantSpec* cs)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
2014-01-22 06:11:17 +04:00
|
|
|
JS::Rooted<JS::Value> value(cx);
|
2012-03-31 08:42:20 +04:00
|
|
|
for (; cs->name; ++cs) {
|
2014-01-22 06:11:17 +04:00
|
|
|
value = cs->value;
|
2013-08-09 02:53:04 +04:00
|
|
|
bool ok =
|
2014-01-22 06:11:17 +04:00
|
|
|
JS_DefineProperty(cx, obj, cs->name, value,
|
2012-03-31 08:42:20 +04:00
|
|
|
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
|
|
|
|
if (!ok) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-05-23 20:44:48 +04:00
|
|
|
static inline bool
|
2013-05-08 06:34:56 +04:00
|
|
|
Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSFunctionSpec* spec) {
|
2012-05-23 20:44:48 +04:00
|
|
|
return JS_DefineFunctions(cx, obj, spec);
|
|
|
|
}
|
|
|
|
static inline bool
|
2013-05-08 06:34:56 +04:00
|
|
|
Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSPropertySpec* spec) {
|
2012-05-23 20:44:48 +04:00
|
|
|
return JS_DefineProperties(cx, obj, spec);
|
|
|
|
}
|
|
|
|
static inline bool
|
2013-05-08 06:34:56 +04:00
|
|
|
Define(JSContext* cx, JS::Handle<JSObject*> obj, const ConstantSpec* spec) {
|
2012-05-23 20:44:48 +04:00
|
|
|
return DefineConstants(cx, obj, spec);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
bool
|
2013-05-04 03:29:08 +04:00
|
|
|
DefinePrefable(JSContext* cx, JS::Handle<JSObject*> obj,
|
|
|
|
const Prefable<T>* props)
|
2012-05-23 20:44:48 +04:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(props);
|
|
|
|
MOZ_ASSERT(props->specs);
|
|
|
|
do {
|
|
|
|
// Define if enabled
|
2013-02-19 20:54:40 +04:00
|
|
|
if (props->isEnabled(cx, obj)) {
|
2012-05-23 20:44:48 +04:00
|
|
|
if (!Define(cx, obj, props->specs)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while ((++props)->specs);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-07-04 17:02:10 +04:00
|
|
|
bool
|
|
|
|
DefineUnforgeableMethods(JSContext* cx, JS::Handle<JSObject*> obj,
|
|
|
|
const Prefable<const JSFunctionSpec>* props)
|
|
|
|
{
|
|
|
|
return DefinePrefable(cx, obj, props);
|
|
|
|
}
|
|
|
|
|
2012-10-25 00:10:49 +04:00
|
|
|
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
|
|
|
{
|
|
|
|
return DefinePrefable(cx, obj, props);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-02 17:28:17 +04:00
|
|
|
// We should use JSFunction objects for interface objects, but we need a custom
|
|
|
|
// hasInstance hook because we have new interface objects on prototype chains of
|
2015-10-27 23:25:14 +03:00
|
|
|
// old (XPConnect-based) bindings. We also need Xrays and arbitrary numbers of
|
|
|
|
// reserved slots (e.g. for named constructors). So we define a custom
|
|
|
|
// funToString ObjectOps member for interface objects.
|
|
|
|
JSString*
|
|
|
|
InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
|
2017-07-25 14:22:11 +03:00
|
|
|
bool /* isToSource */)
|
2012-05-02 17:28:17 +04:00
|
|
|
{
|
2015-10-27 23:25:14 +03:00
|
|
|
const js::Class* clasp = js::GetObjectClass(aObject);
|
|
|
|
MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
|
2012-05-02 17:28:17 +04:00
|
|
|
|
2014-09-15 18:45:38 +04:00
|
|
|
const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
|
|
|
|
DOMIfaceAndProtoJSClass::FromJSClass(clasp);
|
2015-10-27 23:25:14 +03:00
|
|
|
return JS_NewStringCopyZ(aCx, ifaceAndProtoJSClass->mToString);
|
2012-05-02 17:28:17 +04:00
|
|
|
}
|
|
|
|
|
2013-08-02 11:41:57 +04:00
|
|
|
bool
|
2012-10-09 22:50:27 +04:00
|
|
|
Constructor(JSContext* cx, unsigned argc, JS::Value* vp)
|
|
|
|
{
|
2014-03-19 21:05:04 +04:00
|
|
|
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
2012-10-09 22:50:27 +04:00
|
|
|
const JS::Value& v =
|
2014-03-19 21:05:04 +04:00
|
|
|
js::GetFunctionNativeReserved(&args.callee(),
|
2012-10-09 22:50:27 +04:00
|
|
|
CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);
|
2013-01-22 14:51:15 +04:00
|
|
|
const JSNativeHolder* nativeHolder =
|
|
|
|
static_cast<const JSNativeHolder*>(v.toPrivate());
|
2012-10-09 22:50:27 +04:00
|
|
|
return (nativeHolder->mNative)(cx, argc, vp);
|
|
|
|
}
|
|
|
|
|
2013-01-22 14:51:15 +04:00
|
|
|
static JSObject*
|
2013-05-02 07:44:12 +04:00
|
|
|
CreateConstructor(JSContext* cx, JS::Handle<JSObject*> global, const char* name,
|
2013-01-22 14:51:15 +04:00
|
|
|
const JSNativeHolder* nativeHolder, unsigned ctorNargs)
|
|
|
|
{
|
|
|
|
JSFunction* fun = js::NewFunctionWithReserved(cx, Constructor, ctorNargs,
|
2015-03-09 19:50:07 +03:00
|
|
|
JSFUN_CONSTRUCTOR, name);
|
2013-01-22 14:51:15 +04:00
|
|
|
if (!fun) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObject* constructor = JS_GetFunctionObject(fun);
|
|
|
|
js::SetFunctionNativeReserved(constructor,
|
|
|
|
CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT,
|
|
|
|
js::PrivateValue(const_cast<JSNativeHolder*>(nativeHolder)));
|
|
|
|
return constructor;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2013-05-02 07:44:12 +04:00
|
|
|
DefineConstructor(JSContext* cx, JS::Handle<JSObject*> global, const char* name,
|
2013-05-02 07:44:11 +04:00
|
|
|
JS::Handle<JSObject*> constructor)
|
2013-01-22 14:51:15 +04:00
|
|
|
{
|
2013-08-09 02:53:04 +04:00
|
|
|
bool alreadyDefined;
|
2013-01-22 14:51:15 +04:00
|
|
|
if (!JS_AlreadyHasOwnProperty(cx, global, name, &alreadyDefined)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is Enumerable: False per spec.
|
|
|
|
return alreadyDefined ||
|
2015-05-01 22:03:17 +03:00
|
|
|
JS_DefineProperty(cx, global, name, constructor, JSPROP_RESOLVING);
|
2013-01-22 14:51:15 +04:00
|
|
|
}
|
|
|
|
|
2012-03-31 08:42:20 +04:00
|
|
|
static JSObject*
|
2013-05-02 07:44:12 +04:00
|
|
|
CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
|
2013-05-02 22:38:19 +04:00
|
|
|
JS::Handle<JSObject*> constructorProto,
|
2014-08-05 14:46:42 +04:00
|
|
|
const js::Class* constructorClass,
|
2013-01-22 14:51:15 +04:00
|
|
|
unsigned ctorNargs, const NamedConstructor* namedConstructors,
|
2013-05-02 07:44:11 +04:00
|
|
|
JS::Handle<JSObject*> proto,
|
2012-10-09 22:50:05 +04:00
|
|
|
const NativeProperties* properties,
|
|
|
|
const NativeProperties* chromeOnlyProperties,
|
2018-04-12 07:06:05 +03:00
|
|
|
const char* name, bool isChrome, bool defineOnGlobal)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
2013-05-02 07:44:11 +04:00
|
|
|
JS::Rooted<JSObject*> constructor(cx);
|
2016-08-04 04:32:06 +03:00
|
|
|
MOZ_ASSERT(constructorProto);
|
|
|
|
MOZ_ASSERT(constructorClass);
|
|
|
|
constructor = JS_NewObjectWithGivenProto(cx, Jsvalify(constructorClass),
|
|
|
|
constructorProto);
|
2012-03-31 08:42:20 +04:00
|
|
|
if (!constructor) {
|
2013-10-28 18:04:12 +04:00
|
|
|
return nullptr;
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2016-08-04 04:32:06 +03:00
|
|
|
if (!JS_DefineProperty(cx, constructor, "length", ctorNargs,
|
|
|
|
JSPROP_READONLY)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2014-10-25 08:50:28 +04:00
|
|
|
|
2016-08-04 04:32:06 +03:00
|
|
|
// Might as well intern, since we're going to need an atomized
|
|
|
|
// version of name anyway when we stick our constructor on the
|
|
|
|
// global.
|
|
|
|
JS::Rooted<JSString*> nameStr(cx, JS_AtomizeAndPinString(cx, name));
|
|
|
|
if (!nameStr) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2014-10-25 08:50:28 +04:00
|
|
|
|
2016-08-04 04:32:06 +03:00
|
|
|
if (!JS_DefineProperty(cx, constructor, "name", nameStr, JSPROP_READONLY)) {
|
|
|
|
return nullptr;
|
2012-05-02 17:28:17 +04:00
|
|
|
}
|
|
|
|
|
2016-08-04 04:32:07 +03:00
|
|
|
if (DOMIfaceAndProtoJSClass::FromJSClass(constructorClass)->wantsInterfaceHasInstance) {
|
|
|
|
JS::Rooted<jsid> hasInstanceId(cx,
|
|
|
|
SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::hasInstance)));
|
|
|
|
if (!JS_DefineFunctionById(cx, constructor, hasInstanceId,
|
|
|
|
InterfaceHasInstance, 1,
|
|
|
|
// Flags match those of Function[Symbol.hasInstance]
|
|
|
|
JSPROP_READONLY | JSPROP_PERMANENT)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2018-04-12 07:06:07 +03:00
|
|
|
|
|
|
|
if (isChrome && !JS_DefineFunction(cx, constructor, "isInstance",
|
2018-04-26 08:38:07 +03:00
|
|
|
InterfaceIsInstance, 1,
|
2018-04-12 07:06:07 +03:00
|
|
|
// Don't bother making it enumerable
|
|
|
|
0)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2016-08-04 04:32:07 +03:00
|
|
|
}
|
|
|
|
|
2012-10-09 22:50:05 +04:00
|
|
|
if (properties) {
|
2016-03-31 01:57:20 +03:00
|
|
|
if (properties->HasStaticMethods() &&
|
|
|
|
!DefinePrefable(cx, constructor, properties->StaticMethods())) {
|
2012-10-09 22:50:05 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-03-31 01:57:20 +03:00
|
|
|
if (properties->HasStaticAttributes() &&
|
|
|
|
!DefinePrefable(cx, constructor, properties->StaticAttributes())) {
|
2012-10-19 11:34:28 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-03-31 01:57:20 +03:00
|
|
|
if (properties->HasConstants() &&
|
|
|
|
!DefinePrefable(cx, constructor, properties->Constants())) {
|
2012-10-09 22:50:05 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-12 07:06:05 +03:00
|
|
|
if (chromeOnlyProperties && isChrome) {
|
2016-03-31 01:57:20 +03:00
|
|
|
if (chromeOnlyProperties->HasStaticMethods() &&
|
|
|
|
!DefinePrefable(cx, constructor,
|
|
|
|
chromeOnlyProperties->StaticMethods())) {
|
2012-10-09 22:50:05 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-03-31 01:57:20 +03:00
|
|
|
if (chromeOnlyProperties->HasStaticAttributes() &&
|
2012-10-19 11:34:28 +04:00
|
|
|
!DefinePrefable(cx, constructor,
|
2016-03-31 01:57:20 +03:00
|
|
|
chromeOnlyProperties->StaticAttributes())) {
|
2012-10-19 11:34:28 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-03-31 01:57:20 +03:00
|
|
|
if (chromeOnlyProperties->HasConstants() &&
|
|
|
|
!DefinePrefable(cx, constructor, chromeOnlyProperties->Constants())) {
|
2012-10-09 22:50:05 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (proto && !JS_LinkConstructorAndPrototype(cx, constructor, proto)) {
|
2013-10-28 18:04:12 +04:00
|
|
|
return nullptr;
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2013-08-08 01:40:00 +04:00
|
|
|
if (defineOnGlobal && !DefineConstructor(cx, global, name, constructor)) {
|
2013-01-22 14:51:15 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (namedConstructors) {
|
|
|
|
int namedConstructorSlot = DOM_INTERFACE_SLOTS_BASE;
|
|
|
|
while (namedConstructors->mName) {
|
2013-05-02 07:44:11 +04:00
|
|
|
JS::Rooted<JSObject*> namedConstructor(cx,
|
|
|
|
CreateConstructor(cx, global, namedConstructors->mName,
|
|
|
|
&namedConstructors->mHolder,
|
|
|
|
namedConstructors->mNargs));
|
2013-01-22 14:51:15 +04:00
|
|
|
if (!namedConstructor ||
|
|
|
|
!JS_DefineProperty(cx, namedConstructor, "prototype",
|
2014-10-29 22:06:31 +03:00
|
|
|
proto,
|
2017-08-28 11:39:57 +03:00
|
|
|
JSPROP_PERMANENT | JSPROP_READONLY) ||
|
2013-08-08 01:40:00 +04:00
|
|
|
(defineOnGlobal &&
|
|
|
|
!DefineConstructor(cx, global, namedConstructors->mName,
|
|
|
|
namedConstructor))) {
|
2013-01-22 14:51:15 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
js::SetReservedSlot(constructor, namedConstructorSlot++,
|
|
|
|
JS::ObjectValue(*namedConstructor));
|
|
|
|
++namedConstructors;
|
|
|
|
}
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return constructor;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSObject*
|
2013-05-02 07:44:12 +04:00
|
|
|
CreateInterfacePrototypeObject(JSContext* cx, JS::Handle<JSObject*> global,
|
2013-05-02 07:44:11 +04:00
|
|
|
JS::Handle<JSObject*> parentProto,
|
2014-08-05 14:46:42 +04:00
|
|
|
const js::Class* protoClass,
|
2012-10-09 22:50:05 +04:00
|
|
|
const NativeProperties* properties,
|
2016-03-29 22:50:38 +03:00
|
|
|
const NativeProperties* chromeOnlyProperties,
|
2016-08-04 04:32:06 +03:00
|
|
|
const char* const* unscopableNames,
|
2018-05-18 06:45:35 +03:00
|
|
|
const char* toStringTag,
|
2016-08-04 04:32:06 +03:00
|
|
|
bool isGlobal)
|
2012-03-31 08:42:20 +04:00
|
|
|
{
|
2013-05-02 07:44:11 +04:00
|
|
|
JS::Rooted<JSObject*> ourProto(cx,
|
2015-03-09 19:49:50 +03:00
|
|
|
JS_NewObjectWithUniqueType(cx, Jsvalify(protoClass), parentProto));
|
2014-02-16 01:12:34 +04:00
|
|
|
if (!ourProto ||
|
2016-08-04 04:32:06 +03:00
|
|
|
// We don't try to define properties on the global's prototype; those
|
|
|
|
// properties go on the global itself.
|
|
|
|
(!isGlobal &&
|
|
|
|
!DefineProperties(cx, ourProto, properties, chromeOnlyProperties))) {
|
2013-10-28 18:04:12 +04:00
|
|
|
return nullptr;
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2016-03-29 22:50:38 +03:00
|
|
|
if (unscopableNames) {
|
2018-02-12 23:46:11 +03:00
|
|
|
JS::Rooted<JSObject*> unscopableObj(cx,
|
|
|
|
JS_NewObjectWithGivenProto(cx, nullptr, nullptr));
|
2016-03-29 22:50:38 +03:00
|
|
|
if (!unscopableObj) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; *unscopableNames; ++unscopableNames) {
|
|
|
|
if (!JS_DefineProperty(cx, unscopableObj, *unscopableNames,
|
|
|
|
JS::TrueHandleValue, JSPROP_ENUMERATE)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::Rooted<jsid> unscopableId(cx,
|
|
|
|
SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::unscopables)));
|
|
|
|
// Readonly and non-enumerable to match Array.prototype.
|
|
|
|
if (!JS_DefinePropertyById(cx, ourProto, unscopableId, unscopableObj,
|
|
|
|
JSPROP_READONLY)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-18 06:45:35 +03:00
|
|
|
if (toStringTag) {
|
|
|
|
JS::Rooted<JSString*> toStringTagStr(cx,
|
|
|
|
JS_NewStringCopyZ(cx, toStringTag));
|
|
|
|
if (!toStringTagStr) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::Rooted<jsid> toStringTagId(cx,
|
|
|
|
SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::toStringTag)));
|
|
|
|
if (!JS_DefinePropertyById(cx, ourProto, toStringTagId, toStringTagStr,
|
|
|
|
JSPROP_READONLY)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-16 01:12:34 +04:00
|
|
|
return ourProto;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
DefineProperties(JSContext* cx, JS::Handle<JSObject*> obj,
|
|
|
|
const NativeProperties* properties,
|
|
|
|
const NativeProperties* chromeOnlyProperties)
|
|
|
|
{
|
2012-10-09 22:50:05 +04:00
|
|
|
if (properties) {
|
2016-03-31 01:57:20 +03:00
|
|
|
if (properties->HasMethods() &&
|
|
|
|
!DefinePrefable(cx, obj, properties->Methods())) {
|
2014-02-16 01:12:34 +04:00
|
|
|
return false;
|
2012-10-09 22:50:05 +04:00
|
|
|
}
|
2012-03-31 08:42:20 +04:00
|
|
|
|
2016-03-31 01:57:20 +03:00
|
|
|
if (properties->HasAttributes() &&
|
|
|
|
!DefinePrefable(cx, obj, properties->Attributes())) {
|
2014-02-16 01:12:34 +04:00
|
|
|
return false;
|
2012-10-09 22:50:05 +04:00
|
|
|
}
|
|
|
|
|
2016-03-31 01:57:20 +03:00
|
|
|
if (properties->HasConstants() &&
|
|
|
|
!DefinePrefable(cx, obj, properties->Constants())) {
|
2014-02-16 01:12:34 +04:00
|
|
|
return false;
|
2012-10-09 22:50:05 +04:00
|
|
|
}
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2012-10-09 22:50:05 +04:00
|
|
|
if (chromeOnlyProperties) {
|
2016-03-31 01:57:20 +03:00
|
|
|
if (chromeOnlyProperties->HasMethods() &&
|
|
|
|
!DefinePrefable(cx, obj, chromeOnlyProperties->Methods())) {
|
2014-02-16 01:12:34 +04:00
|
|
|
return false;
|
2012-10-09 22:50:05 +04:00
|
|
|
}
|
|
|
|
|
2016-03-31 01:57:20 +03:00
|
|
|
if (chromeOnlyProperties->HasAttributes() &&
|
|
|
|
!DefinePrefable(cx, obj, chromeOnlyProperties->Attributes())) {
|
2014-02-16 01:12:34 +04:00
|
|
|
return false;
|
2012-10-09 22:50:05 +04:00
|
|
|
}
|
|
|
|
|
2016-03-31 01:57:20 +03:00
|
|
|
if (chromeOnlyProperties->HasConstants() &&
|
|
|
|
!DefinePrefable(cx, obj, chromeOnlyProperties->Constants())) {
|
2014-02-16 01:12:34 +04:00
|
|
|
return false;
|
2012-10-09 22:50:05 +04:00
|
|
|
}
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2014-02-16 01:12:34 +04:00
|
|
|
return true;
|
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*> constructorProto,
|
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:05 +04:00
|
|
|
const NativeProperties* properties,
|
|
|
|
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
|
|
|
{
|
2016-08-04 04:32:06 +03:00
|
|
|
MOZ_ASSERT(protoClass || constructorClass,
|
|
|
|
"Need at least one class!");
|
2012-10-09 22:50:05 +04:00
|
|
|
MOZ_ASSERT(!((properties &&
|
2016-03-31 01:57:20 +03:00
|
|
|
(properties->HasMethods() || properties->HasAttributes())) ||
|
2012-10-09 22:50:05 +04:00
|
|
|
(chromeOnlyProperties &&
|
2016-03-31 01:57:20 +03:00
|
|
|
(chromeOnlyProperties->HasMethods() ||
|
|
|
|
chromeOnlyProperties->HasAttributes()))) || protoClass,
|
2012-03-31 08:42:20 +04:00
|
|
|
"Methods or properties but no protoClass!");
|
2012-10-19 11:34:28 +04:00
|
|
|
MOZ_ASSERT(!((properties &&
|
2016-03-31 01:57:20 +03:00
|
|
|
(properties->HasStaticMethods() ||
|
|
|
|
properties->HasStaticAttributes())) ||
|
2012-10-19 11:34:28 +04:00
|
|
|
(chromeOnlyProperties &&
|
2016-03-31 01:57:20 +03:00
|
|
|
(chromeOnlyProperties->HasStaticMethods() ||
|
|
|
|
chromeOnlyProperties->HasStaticAttributes()))) ||
|
2016-08-04 04:32:06 +03:00
|
|
|
constructorClass,
|
|
|
|
"Static methods but no constructorClass!");
|
|
|
|
MOZ_ASSERT(bool(name) == bool(constructorClass),
|
2012-03-31 08:42:20 +04:00
|
|
|
"Must have name precisely when we have an interface object");
|
2012-10-09 22:50:27 +04:00
|
|
|
MOZ_ASSERT(!protoClass == !protoCache,
|
|
|
|
"If, and only if, there is an interface prototype object we need "
|
|
|
|
"to cache it");
|
2016-08-04 04:32:06 +03:00
|
|
|
MOZ_ASSERT(bool(constructorClass) == bool(constructorCache),
|
2012-10-09 22:50:27 +04:00
|
|
|
"If, and only if, there is an interface object we need to cache "
|
|
|
|
"it");
|
2016-08-04 04:32:06 +03:00
|
|
|
MOZ_ASSERT(constructorProto || !constructorClass,
|
2016-04-21 01:04:56 +03:00
|
|
|
"Must have a constructor proto if we plan to create a constructor "
|
|
|
|
"object");
|
2018-05-18 06:45:35 +03:00
|
|
|
MOZ_ASSERT(protoClass || !toStringTag,
|
|
|
|
"Must have a prototype object if we have a @@toStringTag");
|
2012-03-31 08:42:20 +04:00
|
|
|
|
2018-04-12 07:06:07 +03:00
|
|
|
bool isChrome = nsContentUtils::ThreadsafeIsSystemCaller(cx);
|
2018-04-12 07:06:05 +03:00
|
|
|
|
2013-05-02 07:44:11 +04:00
|
|
|
JS::Rooted<JSObject*> proto(cx);
|
2012-03-31 08:42:20 +04:00
|
|
|
if (protoClass) {
|
2013-05-02 07:44:11 +04:00
|
|
|
proto =
|
|
|
|
CreateInterfacePrototypeObject(cx, global, protoProto, protoClass,
|
2018-04-12 07:06:05 +03:00
|
|
|
properties,
|
|
|
|
isChrome ? chromeOnlyProperties : nullptr,
|
2018-05-18 06:45:35 +03:00
|
|
|
unscopableNames, toStringTag, isGlobal);
|
2012-03-31 08:42:20 +04:00
|
|
|
if (!proto) {
|
2012-10-09 22:50:27 +04:00
|
|
|
return;
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
2012-08-08 09:26:18 +04:00
|
|
|
|
2012-10-09 22:50:27 +04:00
|
|
|
*protoCache = proto;
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
else {
|
2013-05-02 07:44:11 +04:00
|
|
|
MOZ_ASSERT(!proto);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
JSObject* interface;
|
2016-08-04 04:32:06 +03:00
|
|
|
if (constructorClass) {
|
2013-05-02 22:38:19 +04:00
|
|
|
interface = CreateInterfaceObject(cx, global, constructorProto,
|
2016-08-04 04:32:06 +03:00
|
|
|
constructorClass, ctorNargs,
|
|
|
|
namedConstructors, proto, properties,
|
|
|
|
chromeOnlyProperties, name,
|
2018-04-12 07:06:05 +03:00
|
|
|
isChrome,
|
2013-08-08 01:40:00 +04:00
|
|
|
defineOnGlobal);
|
2012-03-31 08:42:20 +04:00
|
|
|
if (!interface) {
|
2012-10-09 22:50:27 +04:00
|
|
|
if (protoCache) {
|
|
|
|
// If we fail we need to make sure to clear the value of protoCache we
|
|
|
|
// set above.
|
|
|
|
*protoCache = nullptr;
|
|
|
|
}
|
|
|
|
return;
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
2012-10-09 22:50:27 +04:00
|
|
|
*constructorCache = interface;
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-05 18:22:41 +03:00
|
|
|
// Only set aAllowNativeWrapper to false if you really know you need it; if in
|
|
|
|
// doubt use true. Setting it to false disables security wrappers.
|
|
|
|
static bool
|
2012-11-27 13:20:04 +04:00
|
|
|
NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
|
2013-04-30 01:33:42 +04:00
|
|
|
JS::Handle<JSObject*> aScope,
|
2013-10-12 09:02:39 +04:00
|
|
|
JS::MutableHandle<JS::Value> aRetval,
|
2012-03-31 08:42:20 +04:00
|
|
|
xpcObjectHelper& aHelper,
|
|
|
|
const nsIID* aIID,
|
|
|
|
bool aAllowNativeWrapper)
|
|
|
|
{
|
2014-04-09 02:27:18 +04:00
|
|
|
js::AssertSameCompartment(aCx, aScope);
|
2012-03-31 08:42:20 +04:00
|
|
|
nsresult rv;
|
2013-09-10 01:58:29 +04:00
|
|
|
// Inline some logic from XPCConvert::NativeInterfaceToJSObject that we need
|
|
|
|
// on all threads.
|
|
|
|
nsWrapperCache *cache = aHelper.GetWrapperCache();
|
|
|
|
|
2018-04-05 18:22:41 +03:00
|
|
|
if (cache) {
|
2013-10-16 02:34:13 +04:00
|
|
|
JS::Rooted<JSObject*> obj(aCx, cache->GetWrapper());
|
2013-09-10 01:58:29 +04:00
|
|
|
if (!obj) {
|
2015-05-14 00:07:34 +03:00
|
|
|
obj = cache->WrapObject(aCx, nullptr);
|
2018-04-05 18:22:41 +03:00
|
|
|
if (!obj) {
|
|
|
|
return Throw(aCx, NS_ERROR_UNEXPECTED);
|
|
|
|
}
|
2013-09-10 01:58:29 +04:00
|
|
|
}
|
|
|
|
|
2018-04-05 18:22:41 +03:00
|
|
|
if (aAllowNativeWrapper && !JS_WrapObject(aCx, &obj)) {
|
2013-09-10 01:58:29 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-04-05 18:22:41 +03:00
|
|
|
aRetval.setObject(*obj);
|
|
|
|
return true;
|
2013-09-10 01:58:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
2017-09-20 20:20:48 +03:00
|
|
|
if (!XPCConvert::NativeInterface2JSObject(aRetval, aHelper, aIID,
|
2016-07-27 20:11:40 +03:00
|
|
|
aAllowNativeWrapper, &rv)) {
|
2012-03-31 08:42:20 +04:00
|
|
|
// I can't tell if NativeInterface2JSObject throws JS exceptions
|
|
|
|
// or not. This is a sloppy stab at the right semantics; the
|
|
|
|
// method really ought to be fixed to behave consistently.
|
|
|
|
if (!JS_IsExceptionPending(aCx)) {
|
2013-09-09 07:29:21 +04:00
|
|
|
Throw(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-11-09 22:59:02 +04:00
|
|
|
bool
|
|
|
|
TryPreserveWrapper(JSObject* obj)
|
|
|
|
{
|
2013-07-01 11:14:36 +04:00
|
|
|
MOZ_ASSERT(IsDOMObject(obj));
|
|
|
|
|
2013-06-01 10:56:02 +04:00
|
|
|
if (nsISupports* native = UnwrapDOMObjectToISupports(obj)) {
|
2012-11-09 22:59:02 +04:00
|
|
|
nsWrapperCache* cache = nullptr;
|
|
|
|
CallQueryInterface(native, &cache);
|
|
|
|
if (cache) {
|
2013-06-23 11:15:42 +04:00
|
|
|
cache->PreserveWrapper(native);
|
2012-11-09 22:59:02 +04:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this DOMClass is not cycle collected, then it isn't wrappercached,
|
|
|
|
// so it does not need to be preserved. If it is cycle collected, then
|
|
|
|
// we can't tell if it is wrappercached or not, so we just return false.
|
2014-06-19 00:19:19 +04:00
|
|
|
const DOMJSClass* domClass = GetDOMClass(obj);
|
2012-11-09 22:59:02 +04:00
|
|
|
return domClass && !domClass->mParticipant;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2014-06-19 00:19:19 +04:00
|
|
|
const DOMJSClass* domClass = DOMJSClass::FromJSClass(clasp);
|
|
|
|
return static_cast<uint32_t>(domClass->mInterfaceChain[depth]) == protoID;
|
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
|
|
|
{
|
2012-11-27 13:20:04 +04:00
|
|
|
if (!NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval, helper, iid,
|
2012-03-31 08:42:20 +04:00
|
|
|
allowNativeWrapper)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2013-10-16 02:34:13 +04:00
|
|
|
JSObject* jsobj = rval.toObjectOrNull();
|
2015-03-07 00:33:31 +03:00
|
|
|
if (jsobj &&
|
|
|
|
js::GetGlobalForObjectCrossCompartment(jsobj) == jsobj) {
|
2012-03-31 08:42:20 +04:00
|
|
|
NS_ASSERTION(js::GetObjectClass(jsobj)->flags & JSCLASS_IS_GLOBAL,
|
|
|
|
"Why did we recreate this wrapper?");
|
2015-03-07 00:33:31 +03:00
|
|
|
}
|
2012-03-31 08:42:20 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-04-04 06:22:16 +04:00
|
|
|
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
|
|
|
{
|
|
|
|
nsresult rv;
|
2013-06-05 08:11:19 +04:00
|
|
|
if (!XPCVariant::VariantDataToJS(aVariant, &rv, aRetval)) {
|
2013-04-04 06:22:16 +04:00
|
|
|
// Does it throw? Who knows
|
|
|
|
if (!JS_IsExceptionPending(aCx)) {
|
2013-09-09 07:29:21 +04:00
|
|
|
Throw(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
|
2013-04-04 06:22:16 +04:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
static int
|
|
|
|
CompareIdsAtIndices(const void* aElement1, const void* aElement2, void* aClosure)
|
|
|
|
{
|
|
|
|
const uint16_t index1 = *static_cast<const uint16_t*>(aElement1);
|
|
|
|
const uint16_t index2 = *static_cast<const uint16_t*>(aElement2);
|
|
|
|
const PropertyInfo* infos = static_cast<PropertyInfo*>(aClosure);
|
|
|
|
|
2018-05-26 15:14:10 +03:00
|
|
|
MOZ_ASSERT(JSID_BITS(infos[index1].Id()) != JSID_BITS(infos[index2].Id()));
|
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
|
|
|
|
2018-05-26 15:14:10 +03:00
|
|
|
return JSID_BITS(infos[index1].Id()) < JSID_BITS(infos[index2].Id()) ? -1 : 1;
|
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
|
|
|
}
|
|
|
|
|
|
|
|
template <typename SpecT>
|
|
|
|
static bool
|
|
|
|
InitIdsInternal(JSContext* cx, const Prefable<SpecT>* pref, PropertyInfo* infos,
|
|
|
|
PropertyType type)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(pref);
|
|
|
|
MOZ_ASSERT(pref->specs);
|
|
|
|
|
|
|
|
// Index of the Prefable that contains the id for the current PropertyInfo.
|
|
|
|
uint32_t prefIndex = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
// We ignore whether the set of ids is enabled and just intern all the IDs,
|
|
|
|
// because this is only done once per application runtime.
|
|
|
|
const SpecT* spec = pref->specs;
|
|
|
|
// Index of the property/function/constant spec for our current PropertyInfo
|
|
|
|
// in the "specs" array of the relevant Prefable.
|
|
|
|
uint32_t specIndex = 0;
|
|
|
|
do {
|
2018-05-26 15:14:10 +03:00
|
|
|
jsid id;
|
|
|
|
if (!JS::PropertySpecNameToPermanentId(cx, spec->name, &id)) {
|
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
|
|
|
return false;
|
|
|
|
}
|
2018-05-26 15:14:10 +03:00
|
|
|
infos->SetId(id);
|
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
|
|
|
infos->type = type;
|
|
|
|
infos->prefIndex = prefIndex;
|
|
|
|
infos->specIndex = specIndex++;
|
|
|
|
++infos;
|
|
|
|
} while ((++spec)->name);
|
|
|
|
++prefIndex;
|
|
|
|
} while ((++pref)->specs);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define INIT_IDS_IF_DEFINED(TypeName) { \
|
|
|
|
if (nativeProperties->Has##TypeName##s() && \
|
|
|
|
!InitIdsInternal(cx, \
|
|
|
|
nativeProperties->TypeName##s(), \
|
|
|
|
nativeProperties->TypeName##PropertyInfos(), \
|
|
|
|
e##TypeName)) { \
|
|
|
|
return false; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
InitIds(JSContext* cx, const NativeProperties* nativeProperties)
|
|
|
|
{
|
|
|
|
INIT_IDS_IF_DEFINED(StaticMethod);
|
|
|
|
INIT_IDS_IF_DEFINED(StaticAttribute);
|
|
|
|
INIT_IDS_IF_DEFINED(Method);
|
|
|
|
INIT_IDS_IF_DEFINED(Attribute);
|
|
|
|
INIT_IDS_IF_DEFINED(UnforgeableMethod);
|
|
|
|
INIT_IDS_IF_DEFINED(UnforgeableAttribute);
|
|
|
|
INIT_IDS_IF_DEFINED(Constant);
|
|
|
|
|
|
|
|
// Initialize and sort the index array.
|
|
|
|
uint16_t* indices = nativeProperties->sortedPropertyIndices;
|
|
|
|
for (unsigned int i = 0; i < nativeProperties->propertyInfoCount; ++i) {
|
|
|
|
indices[i] = i;
|
|
|
|
}
|
|
|
|
// CompareIdsAtIndices() doesn't actually modify the PropertyInfo array, so
|
|
|
|
// the const_cast here is OK in spite of the signature of NS_QuickSort().
|
|
|
|
NS_QuickSort(indices, nativeProperties->propertyInfoCount, sizeof(uint16_t),
|
|
|
|
CompareIdsAtIndices,
|
|
|
|
const_cast<PropertyInfo*>(nativeProperties->PropertyInfos()));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef INIT_IDS_IF_DEFINED
|
|
|
|
|
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-06-08 06:45:46 +04:00
|
|
|
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
2018-03-07 16:35:22 +03:00
|
|
|
if (!args.thisv().isObject()) {
|
|
|
|
JS_ReportErrorASCII(cx, "QueryInterface called on incompatible non-object");
|
2012-03-31 08:42:20 +04:00
|
|
|
return false;
|
2018-03-07 16:35:22 +03:00
|
|
|
}
|
2012-03-31 08:42:20 +04:00
|
|
|
|
2012-06-12 17:44:21 +04:00
|
|
|
// Get the object. It might be a security wrapper, in which case we do a checked
|
|
|
|
// unwrap.
|
2018-03-07 16:35:22 +03:00
|
|
|
JS::Rooted<JSObject*> origObj(cx, &args.thisv().toObject());
|
2014-10-22 19:40:50 +04:00
|
|
|
JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(origObj,
|
2015-11-06 21:03:52 +03:00
|
|
|
/* stopAtWindowProxy = */ false));
|
2012-11-14 21:56:26 +04:00
|
|
|
if (!obj) {
|
2016-08-14 14:39:28 +03:00
|
|
|
JS_ReportErrorASCII(cx, "Permission denied to access object");
|
2012-06-12 17:44:21 +04:00
|
|
|
return false;
|
2012-11-14 21:56:26 +04:00
|
|
|
}
|
2012-06-12 17:44:21 +04:00
|
|
|
|
2018-04-04 21:39:52 +03:00
|
|
|
nsCOMPtr<nsISupports> native = UnwrapDOMObjectToISupports(obj);
|
2013-06-01 10:56:02 +04:00
|
|
|
if (!native) {
|
2013-09-09 07:29:21 +04:00
|
|
|
return Throw(cx, NS_ERROR_FAILURE);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (argc < 1) {
|
2013-09-09 07:29:21 +04:00
|
|
|
return Throw(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2013-10-16 02:34:13 +04:00
|
|
|
if (!args[0].isObject()) {
|
2013-09-09 07:29:21 +04:00
|
|
|
return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2014-10-22 19:40:51 +04:00
|
|
|
nsCOMPtr<nsIJSID> iid;
|
2014-10-22 19:40:50 +04:00
|
|
|
obj = &args[0].toObject();
|
2017-02-01 23:43:37 +03:00
|
|
|
if (NS_FAILED(UnwrapArg<nsIJSID>(cx, obj, getter_AddRefs(iid)))) {
|
2013-09-09 07:29:21 +04:00
|
|
|
return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
MOZ_ASSERT(iid);
|
|
|
|
|
|
|
|
if (iid->GetID()->Equals(NS_GET_IID(nsIClassInfo))) {
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIClassInfo> ci = do_QueryInterface(native, &rv);
|
|
|
|
if (NS_FAILED(rv)) {
|
2013-09-09 07:29:21 +04:00
|
|
|
return Throw(cx, rv);
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
|
|
|
|
2014-04-10 08:58:43 +04:00
|
|
|
return WrapObject(cx, ci, &NS_GET_IID(nsIClassInfo), args.rval());
|
2012-03-31 08:42:20 +04:00
|
|
|
}
|
2012-06-12 17:44:21 +04:00
|
|
|
|
2013-01-14 14:29:49 +04:00
|
|
|
nsCOMPtr<nsISupports> unused;
|
|
|
|
nsresult rv = native->QueryInterface(*iid->GetID(), getter_AddRefs(unused));
|
|
|
|
if (NS_FAILED(rv)) {
|
2013-09-09 07:29:21 +04:00
|
|
|
return Throw(cx, rv);
|
2013-01-14 14:29:49 +04:00
|
|
|
}
|
|
|
|
|
2018-03-07 16:35:22 +03:00
|
|
|
args.rval().set(args.thisv());
|
2012-03-31 08:42:20 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
|
|
|
const nsID* iid = aIID->GetID();
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsISupports> result;
|
2014-02-16 01:12:33 +04:00
|
|
|
aError = aRequestor->GetInterface(*iid, getter_AddRefs(result));
|
|
|
|
if (aError.Failed()) {
|
2014-06-12 00:26:52 +04:00
|
|
|
return;
|
2014-02-16 01:12:33 +04:00
|
|
|
}
|
|
|
|
|
2014-06-12 00:26:52 +04:00
|
|
|
if (!WrapObject(aCx, result, iid, aRetval)) {
|
2014-02-16 01:12:33 +04:00
|
|
|
aError.Throw(NS_ERROR_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-08-04 11:44:00 +04:00
|
|
|
return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
|
2012-05-03 08:35:38 +04:00
|
|
|
}
|
|
|
|
|
2014-03-11 01:38:31 +04:00
|
|
|
bool
|
|
|
|
ThrowConstructorWithoutNew(JSContext* cx, const char* name)
|
|
|
|
{
|
|
|
|
return ThrowErrorMessage(cx, MSG_CONSTRUCTOR_WITHOUT_NEW, name);
|
|
|
|
}
|
|
|
|
|
2015-07-31 20:30:55 +03:00
|
|
|
inline const NativePropertyHooks*
|
|
|
|
GetNativePropertyHooksFromConstructorFunction(JS::Handle<JSObject*> obj)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
|
|
|
|
const JS::Value& v =
|
|
|
|
js::GetFunctionNativeReserved(obj,
|
|
|
|
CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);
|
|
|
|
const JSNativeHolder* nativeHolder =
|
|
|
|
static_cast<const JSNativeHolder*>(v.toPrivate());
|
|
|
|
return nativeHolder->mPropertyHooks;
|
|
|
|
}
|
|
|
|
|
2012-10-09 22:50:27 +04:00
|
|
|
inline const NativePropertyHooks*
|
2013-05-04 03:29:08 +04:00
|
|
|
GetNativePropertyHooks(JSContext *cx, JS::Handle<JSObject*> obj,
|
2014-09-15 18:51:40 +04:00
|
|
|
DOMObjectType& type)
|
2012-10-09 22:50:27 +04:00
|
|
|
{
|
2014-08-22 13:25:35 +04:00
|
|
|
const js::Class* clasp = js::GetObjectClass(obj);
|
|
|
|
|
|
|
|
const DOMJSClass* domClass = GetDOMClass(clasp);
|
2012-12-07 00:21:19 +04:00
|
|
|
if (domClass) {
|
2014-09-15 18:51:40 +04:00
|
|
|
bool isGlobal = (clasp->flags & JSCLASS_DOM_GLOBAL) != 0;
|
|
|
|
type = isGlobal ? eGlobalInstance : eInstance;
|
2012-10-09 22:50:27 +04:00
|
|
|
return domClass->mNativeHooks;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (JS_ObjectIsFunction(cx, obj)) {
|
|
|
|
type = eInterface;
|
2015-07-31 20:30:55 +03:00
|
|
|
return GetNativePropertyHooksFromConstructorFunction(obj);
|
2012-10-09 22:50:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(obj)));
|
|
|
|
const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
|
|
|
|
DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
|
|
|
|
type = ifaceAndProtoJSClass->mType;
|
|
|
|
return ifaceAndProtoJSClass->mNativeHooks;
|
|
|
|
}
|
|
|
|
|
2015-03-07 00:33:31 +03:00
|
|
|
static JSObject*
|
|
|
|
XrayCreateFunction(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
|
|
|
JSNativeWrapper native, unsigned nargs, JS::Handle<jsid> id)
|
|
|
|
{
|
2016-08-04 04:32:07 +03:00
|
|
|
JSFunction* fun;
|
|
|
|
if (JSID_IS_STRING(id)) {
|
|
|
|
fun = js::NewFunctionByIdWithReserved(cx, native.op, nargs, 0, id);
|
|
|
|
} else {
|
|
|
|
// Can't pass this id (probably a symbol) to NewFunctionByIdWithReserved;
|
|
|
|
// just use an empty name for lack of anything better.
|
|
|
|
fun = js::NewFunctionWithReserved(cx, native.op, nargs, 0, nullptr);
|
|
|
|
}
|
|
|
|
|
2015-03-07 00:33:31 +03:00
|
|
|
if (!fun) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
SET_JITINFO(fun, native.info);
|
|
|
|
JSObject* obj = JS_GetFunctionObject(fun);
|
|
|
|
js::SetFunctionNativeReserved(obj, XRAY_DOM_FUNCTION_PARENT_WRAPPER_SLOT,
|
|
|
|
JS::ObjectValue(*wrapper));
|
|
|
|
#ifdef DEBUG
|
|
|
|
js::SetFunctionNativeReserved(obj, XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_SELF,
|
|
|
|
JS::ObjectValue(*obj));
|
|
|
|
#endif
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
struct IdToIndexComparator
|
|
|
|
{
|
|
|
|
// The id we're searching for.
|
|
|
|
const jsid& mId;
|
|
|
|
// The list of ids we're searching in.
|
|
|
|
const PropertyInfo* mInfos;
|
|
|
|
|
|
|
|
explicit IdToIndexComparator(const jsid& aId, const PropertyInfo* aInfos) :
|
|
|
|
mId(aId), mInfos(aInfos) {}
|
|
|
|
int operator()(const uint16_t aIndex) const {
|
2018-05-26 15:14:10 +03:00
|
|
|
if (JSID_BITS(mId) == JSID_BITS(mInfos[aIndex].Id())) {
|
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
|
|
|
return 0;
|
|
|
|
}
|
2018-05-26 15:14:10 +03:00
|
|
|
return JSID_BITS(mId) < JSID_BITS(mInfos[aIndex].Id()) ? -1 : 1;
|
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
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const PropertyInfo*
|
|
|
|
XrayFindOwnPropertyInfo(JSContext* cx, JS::Handle<jsid> id,
|
|
|
|
const NativeProperties* nativeProperties)
|
|
|
|
{
|
|
|
|
if (MOZ_UNLIKELY(nativeProperties->iteratorAliasMethodIndex >= 0) &&
|
|
|
|
id == SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::iterator))) {
|
|
|
|
return nativeProperties->MethodPropertyInfos() +
|
|
|
|
nativeProperties->iteratorAliasMethodIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t idx;
|
|
|
|
const uint16_t* sortedPropertyIndices = nativeProperties->sortedPropertyIndices;
|
|
|
|
const PropertyInfo* propertyInfos = nativeProperties->PropertyInfos();
|
|
|
|
|
|
|
|
if (BinarySearchIf(sortedPropertyIndices, 0,
|
|
|
|
nativeProperties->propertyInfoCount,
|
|
|
|
IdToIndexComparator(id, propertyInfos), &idx)) {
|
|
|
|
return propertyInfos + sortedPropertyIndices[idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2012-10-09 22:50:27 +04:00
|
|
|
static bool
|
2013-05-04 03:29:08 +04:00
|
|
|
XrayResolveAttribute(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
|
|
|
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
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
|
|
|
const Prefable<const JSPropertySpec>& pref,
|
|
|
|
const JSPropertySpec& attrSpec,
|
2016-01-28 13:28:04 +03:00
|
|
|
JS::MutableHandle<JS::PropertyDescriptor> desc,
|
2014-08-22 13:25:07 +04:00
|
|
|
bool& cacheOnHolder)
|
2012-10-09 22:50:27 +04:00
|
|
|
{
|
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
|
|
|
if (!pref.isEnabled(cx, obj)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
cacheOnHolder = true;
|
|
|
|
|
|
|
|
// Because of centralization, we need to make sure we fault in the JitInfos as
|
|
|
|
// well. At present, until the JSAPI changes, the easiest way to do this is
|
|
|
|
// wrap them up as functions ourselves.
|
|
|
|
desc.setAttributes(attrSpec.flags);
|
|
|
|
// They all have getters, so we can just make it.
|
|
|
|
JS::Rooted<JSObject*> funobj(cx,
|
|
|
|
XrayCreateFunction(cx, wrapper, attrSpec.accessors.getter.native, 0, id));
|
|
|
|
if (!funobj)
|
|
|
|
return false;
|
|
|
|
desc.setGetterObject(funobj);
|
|
|
|
desc.attributesRef() |= JSPROP_GETTER;
|
|
|
|
if (attrSpec.accessors.setter.native.op) {
|
|
|
|
// We have a setter! Make it.
|
|
|
|
funobj =
|
|
|
|
XrayCreateFunction(cx, wrapper, attrSpec.accessors.setter.native, 1, id);
|
|
|
|
if (!funobj)
|
|
|
|
return false;
|
|
|
|
desc.setSetterObject(funobj);
|
|
|
|
desc.attributesRef() |= JSPROP_SETTER;
|
|
|
|
} else {
|
|
|
|
desc.setSetter(nullptr);
|
2012-10-09 22:50:27 +04:00
|
|
|
}
|
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
|
|
|
desc.object().set(wrapper);
|
|
|
|
desc.value().setUndefined();
|
|
|
|
|
2012-10-09 22:50:27 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-07-12 03:32:16 +04:00
|
|
|
static bool
|
|
|
|
XrayResolveMethod(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
|
|
|
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
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
|
|
|
const Prefable<const JSFunctionSpec>& pref,
|
|
|
|
const JSFunctionSpec& methodSpec,
|
2016-01-28 13:28:04 +03:00
|
|
|
JS::MutableHandle<JS::PropertyDescriptor> desc,
|
2014-08-22 13:25:07 +04:00
|
|
|
bool& cacheOnHolder)
|
2014-07-12 03:32:16 +04:00
|
|
|
{
|
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
|
|
|
if (!pref.isEnabled(cx, obj)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
cacheOnHolder = true;
|
|
|
|
|
|
|
|
JSObject *funobj;
|
|
|
|
if (methodSpec.selfHostedName) {
|
|
|
|
JSFunction* fun =
|
|
|
|
JS::GetSelfHostedFunction(cx, methodSpec.selfHostedName, id,
|
|
|
|
methodSpec.nargs);
|
|
|
|
if (!fun) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
MOZ_ASSERT(!methodSpec.call.op, "Bad FunctionSpec declaration: non-null native");
|
|
|
|
MOZ_ASSERT(!methodSpec.call.info, "Bad FunctionSpec declaration: non-null jitinfo");
|
|
|
|
funobj = JS_GetFunctionObject(fun);
|
|
|
|
} else {
|
|
|
|
funobj = XrayCreateFunction(cx, wrapper, methodSpec.call,
|
|
|
|
methodSpec.nargs, id);
|
|
|
|
if (!funobj) {
|
|
|
|
return false;
|
2014-07-12 03:32:16 +04:00
|
|
|
}
|
|
|
|
}
|
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
|
|
|
desc.value().setObject(*funobj);
|
|
|
|
desc.setAttributes(methodSpec.flags);
|
|
|
|
desc.object().set(wrapper);
|
|
|
|
desc.setSetter(nullptr);
|
|
|
|
desc.setGetter(nullptr);
|
|
|
|
|
2014-07-12 03:32:16 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-09-15 18:51:40 +04:00
|
|
|
static bool
|
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
|
|
|
XrayResolveConstant(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
|
|
|
JS::Handle<JSObject*> obj, JS::Handle<jsid>,
|
|
|
|
const Prefable<const ConstantSpec>& pref,
|
|
|
|
const ConstantSpec& constantSpec,
|
|
|
|
JS::MutableHandle<JS::PropertyDescriptor> desc,
|
|
|
|
bool& cacheOnHolder)
|
2013-09-25 22:38:29 +04:00
|
|
|
{
|
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
|
|
|
if (!pref.isEnabled(cx, obj)) {
|
2014-07-12 03:32:16 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
cacheOnHolder = true;
|
2014-07-12 03:32:16 +04:00
|
|
|
|
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
|
|
|
desc.setAttributes(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
|
|
|
|
desc.object().set(wrapper);
|
|
|
|
desc.value().set(constantSpec.value);
|
2014-07-12 03:32:16 +04:00
|
|
|
|
|
|
|
return true;
|
2013-09-25 22:38:29 +04:00
|
|
|
}
|
|
|
|
|
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
|
|
|
#define RESOLVE_CASE(PropType, SpecType, Resolver) \
|
|
|
|
case e##PropType: { \
|
|
|
|
MOZ_ASSERT(nativeProperties->Has##PropType##s()); \
|
|
|
|
const Prefable<const SpecType>& pref = \
|
|
|
|
nativeProperties->PropType##s()[propertyInfo.prefIndex]; \
|
|
|
|
return Resolver(cx, wrapper, obj, id, pref, \
|
|
|
|
pref.specs[propertyInfo.specIndex], desc, cacheOnHolder); \
|
|
|
|
}
|
|
|
|
|
2012-10-09 22:50:05 +04:00
|
|
|
static bool
|
2013-05-04 03:29:08 +04:00
|
|
|
XrayResolveProperty(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, DOMObjectType type,
|
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
|
|
|
const NativeProperties* nativeProperties,
|
|
|
|
const PropertyInfo& propertyInfo)
|
2012-07-18 15:52:07 +04:00
|
|
|
{
|
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
|
|
|
MOZ_ASSERT(type != eGlobalInterfacePrototype);
|
|
|
|
|
|
|
|
// Make sure we resolve for matched object type.
|
|
|
|
switch (propertyInfo.type) {
|
|
|
|
case eStaticMethod:
|
|
|
|
case eStaticAttribute:
|
|
|
|
if (type != eInterface) {
|
|
|
|
return true;
|
2014-07-12 03:32:16 +04:00
|
|
|
}
|
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
|
|
|
break;
|
|
|
|
case eMethod:
|
|
|
|
case eAttribute:
|
|
|
|
if (type != eGlobalInstance && type != eInterfacePrototype) {
|
2014-07-12 03:32:16 +04:00
|
|
|
return true;
|
2012-07-18 15:52:07 +04:00
|
|
|
}
|
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
|
|
|
break;
|
|
|
|
case eUnforgeableMethod:
|
|
|
|
case eUnforgeableAttribute:
|
|
|
|
if (!IsInstance(type)) {
|
|
|
|
return true;
|
2012-10-19 11:34:28 +04:00
|
|
|
}
|
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
|
|
|
break;
|
|
|
|
case eConstant:
|
|
|
|
if (IsInstance(type)) {
|
|
|
|
return true;
|
2013-09-26 02:22:33 +04:00
|
|
|
}
|
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
|
|
|
break;
|
2012-07-18 15:52:07 +04:00
|
|
|
}
|
|
|
|
|
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
|
|
|
switch (propertyInfo.type) {
|
|
|
|
RESOLVE_CASE(StaticMethod, JSFunctionSpec, XrayResolveMethod)
|
|
|
|
RESOLVE_CASE(StaticAttribute, JSPropertySpec, XrayResolveAttribute)
|
|
|
|
RESOLVE_CASE(Method, JSFunctionSpec, XrayResolveMethod)
|
|
|
|
RESOLVE_CASE(Attribute, JSPropertySpec, XrayResolveAttribute)
|
|
|
|
RESOLVE_CASE(UnforgeableMethod, JSFunctionSpec, XrayResolveMethod)
|
|
|
|
RESOLVE_CASE(UnforgeableAttribute, JSPropertySpec, XrayResolveAttribute)
|
|
|
|
RESOLVE_CASE(Constant, ConstantSpec, XrayResolveConstant)
|
2012-07-18 15:52:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
#undef RESOLVE_CASE
|
|
|
|
|
2012-10-09 22:50:27 +04:00
|
|
|
static bool
|
2013-05-04 03:29:08 +04:00
|
|
|
ResolvePrototypeOrConstructor(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
|
|
|
JS::Handle<JSObject*> obj,
|
2014-03-22 21:04:09 +04:00
|
|
|
size_t protoAndIfaceCacheIndex, unsigned attrs,
|
2016-01-28 13:28:04 +03:00
|
|
|
JS::MutableHandle<JS::PropertyDescriptor> desc,
|
2014-09-02 16:17:43 +04:00
|
|
|
bool& cacheOnHolder)
|
2012-10-09 22:50:27 +04:00
|
|
|
{
|
2013-05-04 03:29:08 +04:00
|
|
|
JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj));
|
2012-10-09 22:50:27 +04:00
|
|
|
{
|
2018-05-16 11:53:16 +03:00
|
|
|
JSAutoRealm ar(cx, global);
|
2014-03-22 21:04:09 +04:00
|
|
|
ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
|
2017-06-07 19:56:27 +03:00
|
|
|
// This function is called when resolving the "constructor" and "prototype"
|
|
|
|
// properties of Xrays for DOM prototypes and constructors respectively.
|
|
|
|
// This means the relevant Xray exists, which means its _target_ exists.
|
|
|
|
// And that means we managed to successfullly create the prototype or
|
|
|
|
// constructor, respectively, and hence must have managed to create the
|
|
|
|
// thing it's pointing to as well. So our entry slot must exist.
|
2013-12-11 01:04:55 +04:00
|
|
|
JSObject* protoOrIface =
|
2017-06-07 19:56:27 +03:00
|
|
|
protoAndIfaceCache.EntrySlotMustExist(protoAndIfaceCacheIndex);
|
|
|
|
MOZ_RELEASE_ASSERT(protoOrIface, "How can this object not exist?");
|
2014-08-22 13:25:07 +04:00
|
|
|
|
|
|
|
cacheOnHolder = true;
|
|
|
|
|
2013-08-12 15:09:14 +04:00
|
|
|
desc.object().set(wrapper);
|
|
|
|
desc.setAttributes(attrs);
|
2014-11-22 21:23:39 +03:00
|
|
|
desc.setGetter(nullptr);
|
|
|
|
desc.setSetter(nullptr);
|
2013-08-12 15:09:14 +04:00
|
|
|
desc.value().set(JS::ObjectValue(*protoOrIface));
|
2012-10-09 22:50:27 +04:00
|
|
|
}
|
|
|
|
return JS_WrapPropertyDescriptor(cx, desc);
|
|
|
|
}
|
|
|
|
|
2013-10-18 15:22:08 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
|
|
static void
|
|
|
|
DEBUG_CheckXBLCallable(JSContext *cx, JSObject *obj)
|
|
|
|
{
|
|
|
|
// In general, we shouldn't have cross-compartment wrappers here, because
|
|
|
|
// we should be running in an XBL scope, and the content prototype should
|
|
|
|
// contain wrappers to functions defined in the XBL scope. But if the node
|
|
|
|
// has been adopted into another compartment, those prototypes will now point
|
|
|
|
// to a different XBL scope (which is ok).
|
|
|
|
MOZ_ASSERT_IF(js::IsCrossCompartmentWrapper(obj),
|
2017-07-12 23:00:47 +03:00
|
|
|
xpc::IsInContentXBLScope(js::UncheckedUnwrap(obj)));
|
2013-10-18 15:22:08 +04:00
|
|
|
MOZ_ASSERT(JS::IsCallable(obj));
|
|
|
|
}
|
|
|
|
|
2014-09-15 18:51:40 +04:00
|
|
|
static void
|
2016-01-28 13:28:04 +03:00
|
|
|
DEBUG_CheckXBLLookup(JSContext *cx, JS::PropertyDescriptor *desc)
|
2013-10-18 15:22:08 +04:00
|
|
|
{
|
|
|
|
if (!desc->obj)
|
|
|
|
return;
|
|
|
|
if (!desc->value.isUndefined()) {
|
|
|
|
MOZ_ASSERT(desc->value.isObject());
|
|
|
|
DEBUG_CheckXBLCallable(cx, &desc->value.toObject());
|
|
|
|
}
|
|
|
|
if (desc->getter) {
|
|
|
|
MOZ_ASSERT(desc->attrs & JSPROP_GETTER);
|
|
|
|
DEBUG_CheckXBLCallable(cx, JS_FUNC_TO_DATA_PTR(JSObject *, desc->getter));
|
|
|
|
}
|
|
|
|
if (desc->setter) {
|
|
|
|
MOZ_ASSERT(desc->attrs & JSPROP_SETTER);
|
|
|
|
DEBUG_CheckXBLCallable(cx, JS_FUNC_TO_DATA_PTR(JSObject *, desc->setter));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define DEBUG_CheckXBLLookup(a, b) {}
|
|
|
|
#endif
|
|
|
|
|
2014-09-15 18:51:40 +04:00
|
|
|
/* static */ bool
|
2013-10-18 15:22: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,
|
2013-10-18 15:22:08 +04:00
|
|
|
bool& cacheOnHolder)
|
|
|
|
{
|
|
|
|
cacheOnHolder = false;
|
|
|
|
|
|
|
|
DOMObjectType type;
|
|
|
|
const NativePropertyHooks *nativePropertyHooks =
|
2014-09-15 18:51:40 +04:00
|
|
|
GetNativePropertyHooks(cx, obj, type);
|
2014-09-09 17:19:10 +04:00
|
|
|
ResolveOwnProperty resolveOwnProperty =
|
|
|
|
nativePropertyHooks->mResolveOwnProperty;
|
2013-10-18 15:22:08 +04:00
|
|
|
|
2014-09-09 17:19:10 +04:00
|
|
|
if (type == eNamedPropertiesObject) {
|
2017-10-16 17:58:09 +03:00
|
|
|
MOZ_ASSERT(!resolveOwnProperty,
|
|
|
|
"Shouldn't have any Xray-visible properties");
|
|
|
|
return true;
|
2013-10-18 15:22:08 +04:00
|
|
|
}
|
|
|
|
|
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
|
|
|
const NativePropertiesHolder& nativePropertiesHolder =
|
|
|
|
nativePropertyHooks->mNativeProperties;
|
|
|
|
const NativeProperties* nativeProperties = nullptr;
|
|
|
|
const PropertyInfo* found = nullptr;
|
2014-09-09 17:19:10 +04:00
|
|
|
|
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
|
|
|
if ((nativeProperties = nativePropertiesHolder.regular)) {
|
|
|
|
found = XrayFindOwnPropertyInfo(cx, id, nativeProperties);
|
|
|
|
}
|
|
|
|
if (!found &&
|
|
|
|
(nativeProperties = nativePropertiesHolder.chromeOnly) &&
|
|
|
|
xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper))) {
|
|
|
|
found = XrayFindOwnPropertyInfo(cx, id, nativeProperties);
|
2013-10-18 15:22:08 +04:00
|
|
|
}
|
|
|
|
|
2014-09-15 18:51:40 +04:00
|
|
|
if (IsInstance(type)) {
|
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
|
|
|
// Check for unforgeable properties first to prevent names provided by
|
|
|
|
// resolveOwnProperty callback from shadowing them.
|
|
|
|
if (found && (found->type == eUnforgeableMethod ||
|
|
|
|
found->type == eUnforgeableAttribute)) {
|
|
|
|
if (!XrayResolveProperty(cx, wrapper, obj, id, desc, cacheOnHolder, type,
|
|
|
|
nativeProperties, *found)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (desc.object()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-09 17:19:10 +04:00
|
|
|
if (resolveOwnProperty) {
|
|
|
|
if (!resolveOwnProperty(cx, wrapper, obj, id, desc)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (desc.object()) {
|
|
|
|
// None of these should be cached on the holder, since they're dynamic.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-15 18:51:40 +04:00
|
|
|
// If we're a special scope for in-content XBL, our script expects to see
|
|
|
|
// the bound XBL methods and attributes when accessing content. However,
|
|
|
|
// these members are implemented in content via custom-spliced prototypes,
|
|
|
|
// and thus aren't visible through Xray wrappers unless we handle them
|
|
|
|
// explicitly. So we check if we're running in such a scope, and if so,
|
|
|
|
// whether the wrappee is a bound element. If it is, we do a lookup via
|
|
|
|
// specialized XBL machinery.
|
|
|
|
//
|
|
|
|
// While we have to do some sketchy walking through content land, we should
|
|
|
|
// be protected by read-only/non-configurable properties, and any functions
|
|
|
|
// we end up with should _always_ be living in our own scope (the XBL scope).
|
|
|
|
// Make sure to assert that.
|
2017-07-10 23:05:24 +03:00
|
|
|
JS::Rooted<JSObject*> maybeElement(cx, obj);
|
2014-09-15 18:51:40 +04:00
|
|
|
Element* element;
|
2017-07-12 23:00:47 +03:00
|
|
|
if (xpc::IsInContentXBLScope(wrapper) &&
|
2017-07-10 23:05:24 +03:00
|
|
|
NS_SUCCEEDED(UNWRAP_OBJECT(Element, &maybeElement, element))) {
|
2014-09-15 18:51:40 +04:00
|
|
|
if (!nsContentUtils::LookupBindingMember(cx, element, id, desc)) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-10-18 15:22:08 +04:00
|
|
|
|
2014-09-15 18:51:40 +04:00
|
|
|
DEBUG_CheckXBLLookup(cx, desc.address());
|
2014-09-09 17:19:10 +04:00
|
|
|
|
2014-09-15 18:51:40 +04:00
|
|
|
if (desc.object()) {
|
|
|
|
// XBL properties shouldn't be cached on the holder, as they might be
|
|
|
|
// shadowed by own properties returned from mResolveOwnProperty.
|
|
|
|
desc.object().set(wrapper);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// For non-global instance Xrays there are no other properties, so return
|
|
|
|
// here for them.
|
2015-11-20 12:00:00 +03:00
|
|
|
if (type != eGlobalInstance) {
|
2014-09-15 18:51:40 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else if (type == eInterface) {
|
2017-07-20 10:12:03 +03:00
|
|
|
if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_PROTOTYPE)) {
|
2014-09-15 18:45:38 +04:00
|
|
|
return nativePropertyHooks->mPrototypeID == prototypes::id::_ID_Count ||
|
|
|
|
ResolvePrototypeOrConstructor(cx, wrapper, obj,
|
|
|
|
nativePropertyHooks->mPrototypeID,
|
|
|
|
JSPROP_PERMANENT | JSPROP_READONLY,
|
|
|
|
desc, cacheOnHolder);
|
|
|
|
}
|
2016-08-04 04:32:07 +03:00
|
|
|
|
2018-04-12 07:06:07 +03:00
|
|
|
if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_ISINSTANCE) &&
|
|
|
|
DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj))->
|
|
|
|
wantsInterfaceHasInstance) {
|
|
|
|
cacheOnHolder = true;
|
|
|
|
JSNativeWrapper interfaceIsInstanceWrapper = { InterfaceIsInstance,
|
|
|
|
nullptr };
|
|
|
|
JSObject* funObj = XrayCreateFunction(cx, wrapper,
|
|
|
|
interfaceIsInstanceWrapper, 1, id);
|
|
|
|
if (!funObj) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
desc.value().setObject(*funObj);
|
|
|
|
desc.setAttributes(0);
|
|
|
|
desc.object().set(wrapper);
|
|
|
|
desc.setSetter(nullptr);
|
|
|
|
desc.setGetter(nullptr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-04 04:32:07 +03:00
|
|
|
if (id == SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::hasInstance)) &&
|
|
|
|
DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj))->
|
|
|
|
wantsInterfaceHasInstance) {
|
|
|
|
cacheOnHolder = true;
|
|
|
|
JSNativeWrapper interfaceHasInstanceWrapper = { InterfaceHasInstance,
|
|
|
|
nullptr };
|
|
|
|
JSObject* funObj = XrayCreateFunction(cx, wrapper,
|
|
|
|
interfaceHasInstanceWrapper, 1, id);
|
|
|
|
if (!funObj) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
desc.value().setObject(*funObj);
|
|
|
|
desc.setAttributes(JSPROP_READONLY | JSPROP_PERMANENT);
|
|
|
|
desc.object().set(wrapper);
|
|
|
|
desc.setSetter(nullptr);
|
|
|
|
desc.setGetter(nullptr);
|
|
|
|
return true;
|
|
|
|
}
|
2014-09-15 18:51:40 +04:00
|
|
|
} else {
|
|
|
|
MOZ_ASSERT(IsInterfacePrototype(type));
|
2012-10-09 22:50:27 +04:00
|
|
|
|
2017-07-20 10:12:03 +03:00
|
|
|
if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_CONSTRUCTOR)) {
|
2014-09-15 18:51:40 +04:00
|
|
|
return nativePropertyHooks->mConstructorID == constructors::id::_ID_Count ||
|
|
|
|
ResolvePrototypeOrConstructor(cx, wrapper, obj,
|
|
|
|
nativePropertyHooks->mConstructorID,
|
|
|
|
0, desc, cacheOnHolder);
|
|
|
|
}
|
2012-10-09 22:50:27 +04:00
|
|
|
|
2014-09-15 18:51:40 +04:00
|
|
|
// The properties for globals live on the instance, so return here as there
|
|
|
|
// are no properties on their interface prototype object.
|
2015-11-20 12:00:00 +03:00
|
|
|
if (type == eGlobalInterfacePrototype) {
|
2014-09-15 18:51:40 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2012-10-09 22:50:27 +04:00
|
|
|
|
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
|
|
|
if (found &&
|
2014-08-22 13:25:07 +04:00
|
|
|
!XrayResolveProperty(cx, wrapper, obj, id, desc, cacheOnHolder, type,
|
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
|
|
|
nativeProperties, *found)) {
|
2012-10-09 22:50:05 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-05-29 13:38:57 +04:00
|
|
|
bool
|
|
|
|
XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
|
|
|
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
|
|
|
{
|
|
|
|
if (!js::IsProxy(obj))
|
2015-01-30 20:37:07 +03:00
|
|
|
return true;
|
2013-05-29 13:38:57 +04:00
|
|
|
|
2014-06-27 15:44:08 +04:00
|
|
|
const DOMProxyHandler* handler = GetDOMProxyHandler(obj);
|
2015-01-30 20:37:07 +03:00
|
|
|
return handler->defineProperty(cx, wrapper, id, desc, result, defined);
|
2013-05-29 13:38:57 +04:00
|
|
|
}
|
|
|
|
|
2014-07-23 23:36:20 +04:00
|
|
|
template<typename SpecType>
|
2012-10-09 22:50:27 +04:00
|
|
|
bool
|
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
|
|
|
XrayAppendPropertyKeys(JSContext* cx, JS::Handle<JSObject*> obj,
|
|
|
|
const Prefable<const SpecType>* pref,
|
|
|
|
const PropertyInfo* infos, unsigned flags,
|
|
|
|
JS::AutoIdVector& props)
|
2012-10-09 22:50:27 +04:00
|
|
|
{
|
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
|
|
|
do {
|
|
|
|
bool prefIsEnabled = pref->isEnabled(cx, obj);
|
|
|
|
if (prefIsEnabled) {
|
|
|
|
const SpecType* spec = pref->specs;
|
|
|
|
do {
|
2018-05-26 15:14:10 +03:00
|
|
|
const jsid id = infos++->Id();
|
2012-11-05 20:58:03 +04:00
|
|
|
if (((flags & JSITER_HIDDEN) ||
|
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
|
|
|
(spec->flags & JSPROP_ENUMERATE)) &&
|
|
|
|
((flags & JSITER_SYMBOLS) || !JSID_IS_SYMBOL(id)) &&
|
|
|
|
!props.append(id)) {
|
2012-10-09 22:50:27 +04:00
|
|
|
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
|
|
|
} while ((++spec)->name);
|
2012-10-09 22:50:27 +04:00
|
|
|
}
|
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
|
|
|
// Break if we have reached the end of pref.
|
|
|
|
if (!(++pref)->specs) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Advance infos if the previous pref is disabled. The -1 is required
|
|
|
|
// because there is an end-of-list terminator between pref->specs and
|
|
|
|
// (pref - 1)->specs.
|
|
|
|
if (!prefIsEnabled) {
|
|
|
|
infos += pref->specs - (pref - 1)->specs - 1;
|
|
|
|
}
|
|
|
|
} while (1);
|
|
|
|
|
2012-10-09 22:50:27 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
template<>
|
|
|
|
bool
|
|
|
|
XrayAppendPropertyKeys<ConstantSpec>(JSContext* cx, JS::Handle<JSObject*> obj,
|
|
|
|
const Prefable<const ConstantSpec>* pref,
|
|
|
|
const PropertyInfo* infos, unsigned flags,
|
|
|
|
JS::AutoIdVector& props)
|
|
|
|
{
|
|
|
|
do {
|
|
|
|
bool prefIsEnabled = pref->isEnabled(cx, obj);
|
|
|
|
if (prefIsEnabled) {
|
|
|
|
const ConstantSpec* spec = pref->specs;
|
|
|
|
do {
|
2018-05-26 15:14:10 +03:00
|
|
|
if (!props.append(infos++->Id())) {
|
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
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} while ((++spec)->name);
|
|
|
|
}
|
|
|
|
// Break if we have reached the end of pref.
|
|
|
|
if (!(++pref)->specs) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Advance infos if the previous pref is disabled. The -1 is required
|
|
|
|
// because there is an end-of-list terminator between pref->specs and
|
|
|
|
// (pref - 1)->specs.
|
|
|
|
if (!prefIsEnabled) {
|
|
|
|
infos += pref->specs - (pref - 1)->specs - 1;
|
|
|
|
}
|
|
|
|
} while (1);
|
|
|
|
|
|
|
|
return true;
|
2014-07-23 23:36:21 +04:00
|
|
|
}
|
|
|
|
|
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
|
|
|
#define ADD_KEYS_IF_DEFINED(FieldName) { \
|
|
|
|
if (nativeProperties->Has##FieldName##s() && \
|
|
|
|
!XrayAppendPropertyKeys(cx, obj, \
|
|
|
|
nativeProperties->FieldName##s(), \
|
|
|
|
nativeProperties->FieldName##PropertyInfos(), \
|
|
|
|
flags, props)) { \
|
|
|
|
return false; \
|
|
|
|
} \
|
|
|
|
}
|
2014-07-23 23:36:21 +04:00
|
|
|
|
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,
|
|
|
|
DOMObjectType type,
|
|
|
|
const NativeProperties* nativeProperties)
|
2012-07-18 15:52:07 +04:00
|
|
|
{
|
2014-09-09 17:19:10 +04:00
|
|
|
MOZ_ASSERT(type != eNamedPropertiesObject);
|
|
|
|
|
2014-09-15 18:51:40 +04:00
|
|
|
if (IsInstance(type)) {
|
2016-03-31 01:57:20 +03:00
|
|
|
ADD_KEYS_IF_DEFINED(UnforgeableMethod);
|
|
|
|
ADD_KEYS_IF_DEFINED(UnforgeableAttribute);
|
2015-11-20 12:00:00 +03:00
|
|
|
if (type == eGlobalInstance) {
|
2016-03-31 01:57:20 +03:00
|
|
|
ADD_KEYS_IF_DEFINED(Method);
|
|
|
|
ADD_KEYS_IF_DEFINED(Attribute);
|
2014-09-15 18:51:40 +04:00
|
|
|
}
|
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
|
|
|
} else {
|
|
|
|
MOZ_ASSERT(type != eGlobalInterfacePrototype);
|
|
|
|
if (type == eInterface) {
|
|
|
|
ADD_KEYS_IF_DEFINED(StaticMethod);
|
|
|
|
ADD_KEYS_IF_DEFINED(StaticAttribute);
|
|
|
|
} else {
|
|
|
|
MOZ_ASSERT(type == eInterfacePrototype);
|
|
|
|
ADD_KEYS_IF_DEFINED(Method);
|
|
|
|
ADD_KEYS_IF_DEFINED(Attribute);
|
2012-07-18 15:52:07 +04:00
|
|
|
}
|
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
|
|
|
ADD_KEYS_IF_DEFINED(Constant);
|
2012-07-18 15:52:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-09-27 00:16:36 +04:00
|
|
|
#undef ADD_KEYS_IF_DEFINED
|
2014-07-23 23:36:21 +04:00
|
|
|
|
2012-10-09 22:50:05 +04:00
|
|
|
bool
|
2014-09-27 00:16:36 +04:00
|
|
|
XrayOwnNativePropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
|
|
|
const NativePropertyHooks* nativePropertyHooks,
|
|
|
|
DOMObjectType type, JS::Handle<JSObject*> obj,
|
|
|
|
unsigned flags, JS::AutoIdVector& props)
|
2012-10-09 22:50:05 +04:00
|
|
|
{
|
2014-09-09 17:19:10 +04:00
|
|
|
MOZ_ASSERT(type != eNamedPropertiesObject);
|
|
|
|
|
2012-10-09 22:50:27 +04:00
|
|
|
if (type == eInterface &&
|
|
|
|
nativePropertyHooks->mPrototypeID != prototypes::id::_ID_Count &&
|
|
|
|
!AddStringToIDVector(cx, props, "prototype")) {
|
2012-10-09 22:50:05 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-15 18:51:40 +04:00
|
|
|
if (IsInterfacePrototype(type) &&
|
2012-10-09 22:50:27 +04:00
|
|
|
nativePropertyHooks->mConstructorID != constructors::id::_ID_Count &&
|
2012-11-05 20:58:03 +04:00
|
|
|
(flags & JSITER_HIDDEN) &&
|
2012-10-09 22:50:27 +04:00
|
|
|
!AddStringToIDVector(cx, props, "constructor")) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const NativePropertiesHolder& nativeProperties =
|
|
|
|
nativePropertyHooks->mNativeProperties;
|
|
|
|
|
|
|
|
if (nativeProperties.regular &&
|
2014-09-27 00:16:36 +04:00
|
|
|
!XrayOwnPropertyKeys(cx, wrapper, obj, flags, props, type,
|
|
|
|
nativeProperties.regular)) {
|
2012-10-09 22:50:27 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nativeProperties.chromeOnly &&
|
2012-10-09 22:50:05 +04:00
|
|
|
xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
|
2014-09-27 00:16:36 +04:00
|
|
|
!XrayOwnPropertyKeys(cx, wrapper, obj, flags, props, type,
|
|
|
|
nativeProperties.chromeOnly)) {
|
2012-10-09 22:50:05 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
|
|
|
DOMObjectType type;
|
|
|
|
const NativePropertyHooks* nativePropertyHooks =
|
2014-09-15 18:51:40 +04:00
|
|
|
GetNativePropertyHooks(cx, obj, type);
|
2014-09-09 17:19:10 +04:00
|
|
|
EnumerateOwnProperties enumerateOwnProperties =
|
|
|
|
nativePropertyHooks->mEnumerateOwnProperties;
|
|
|
|
|
|
|
|
if (type == eNamedPropertiesObject) {
|
2017-10-16 17:58:09 +03:00
|
|
|
MOZ_ASSERT(!enumerateOwnProperties,
|
|
|
|
"Shouldn't have any Xray-visible properties");
|
|
|
|
return true;
|
2014-09-09 17:19:10 +04:00
|
|
|
}
|
2012-10-09 22:50:27 +04:00
|
|
|
|
2014-09-15 18:51:40 +04:00
|
|
|
if (IsInstance(type)) {
|
|
|
|
// FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=1071189
|
|
|
|
// Should do something about XBL properties too.
|
2014-09-09 17:19:10 +04:00
|
|
|
if (enumerateOwnProperties &&
|
|
|
|
!enumerateOwnProperties(cx, wrapper, obj, props)) {
|
2012-10-09 22:50:27 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-20 12:00:00 +03:00
|
|
|
return type == eGlobalInterfacePrototype ||
|
2014-09-27 00:16:36 +04:00
|
|
|
XrayOwnNativePropertyKeys(cx, wrapper, nativePropertyHooks, type,
|
|
|
|
obj, flags, props);
|
2012-10-09 22:50:27 +04:00
|
|
|
}
|
|
|
|
|
2016-10-11 01:16:26 +03:00
|
|
|
const JSClass*
|
|
|
|
XrayGetExpandoClass(JSContext* cx, JS::Handle<JSObject*> obj)
|
|
|
|
{
|
|
|
|
DOMObjectType type;
|
|
|
|
const NativePropertyHooks* nativePropertyHooks =
|
|
|
|
GetNativePropertyHooks(cx, obj, type);
|
|
|
|
if (!IsInstance(type)) {
|
|
|
|
// Non-instances don't need any special expando classes.
|
|
|
|
return &DefaultXrayExpandoObjectClass;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nativePropertyHooks->mXrayExpandoClass;
|
|
|
|
}
|
|
|
|
|
2016-11-04 19:41:26 +03:00
|
|
|
bool
|
|
|
|
XrayDeleteNamedProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
|
|
|
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
|
|
|
JS::ObjectOpResult& opresult)
|
|
|
|
{
|
|
|
|
DOMObjectType type;
|
|
|
|
const NativePropertyHooks* nativePropertyHooks =
|
|
|
|
GetNativePropertyHooks(cx, obj, type);
|
|
|
|
if (!IsInstance(type) || !nativePropertyHooks->mDeleteNamedProperty) {
|
2016-11-04 22:58:32 +03:00
|
|
|
return opresult.succeed();
|
2016-11-04 19:41:26 +03:00
|
|
|
}
|
|
|
|
return nativePropertyHooks->mDeleteNamedProperty(cx, wrapper, obj, id,
|
|
|
|
opresult);
|
|
|
|
}
|
|
|
|
|
2016-10-11 01:16:26 +03:00
|
|
|
JSObject*
|
|
|
|
GetCachedSlotStorageObjectSlow(JSContext* cx, JS::Handle<JSObject*> obj,
|
|
|
|
bool* isXray)
|
|
|
|
{
|
|
|
|
if (!xpc::WrapperFactory::IsXrayWrapper(obj)) {
|
|
|
|
JSObject* retval = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
|
|
|
|
MOZ_ASSERT(IsDOMObject(retval));
|
|
|
|
*isXray = false;
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
*isXray = true;
|
|
|
|
return xpc::EnsureXrayExpandoObject(cx, obj);;
|
|
|
|
}
|
|
|
|
|
2016-10-11 01:16:25 +03:00
|
|
|
DEFINE_XRAY_EXPANDO_CLASS(, DefaultXrayExpandoObjectClass, 0);
|
|
|
|
|
2015-02-26 17:40:08 +03:00
|
|
|
NativePropertyHooks sEmptyNativePropertyHooks = {
|
2016-11-04 19:41:26 +03:00
|
|
|
nullptr,
|
2012-10-09 22:50:27 +04:00
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
{
|
|
|
|
nullptr,
|
|
|
|
nullptr
|
|
|
|
},
|
|
|
|
prototypes::id::_ID_Count,
|
|
|
|
constructors::id::_ID_Count,
|
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
2016-04-01 03:00:01 +03:00
|
|
|
const js::ClassOps sBoringInterfaceObjectClassClassOps = {
|
|
|
|
nullptr, /* addProperty */
|
|
|
|
nullptr, /* delProperty */
|
|
|
|
nullptr, /* enumerate */
|
2017-06-14 11:37:44 +03:00
|
|
|
nullptr, /* newEnumerate */
|
2016-04-01 03:00:01 +03:00
|
|
|
nullptr, /* resolve */
|
|
|
|
nullptr, /* mayResolve */
|
|
|
|
nullptr, /* finalize */
|
|
|
|
ThrowingConstructor, /* call */
|
2016-08-04 04:32:07 +03:00
|
|
|
nullptr, /* hasInstance */
|
2016-04-01 03:00:01 +03:00
|
|
|
ThrowingConstructor, /* construct */
|
|
|
|
nullptr, /* trace */
|
|
|
|
};
|
|
|
|
|
2016-03-23 23:00:29 +03:00
|
|
|
const js::ObjectOps sInterfaceObjectClassObjectOps = {
|
|
|
|
nullptr, /* lookupProperty */
|
|
|
|
nullptr, /* defineProperty */
|
|
|
|
nullptr, /* hasProperty */
|
|
|
|
nullptr, /* getProperty */
|
|
|
|
nullptr, /* setProperty */
|
|
|
|
nullptr, /* getOwnPropertyDescriptor */
|
|
|
|
nullptr, /* deleteProperty */
|
|
|
|
nullptr, /* getElements */
|
|
|
|
InterfaceObjectToString, /* funToString */
|
|
|
|
};
|
|
|
|
|
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
|
|
|
{
|
2013-05-04 03:29:08 +04:00
|
|
|
JS::Rooted<JSObject*> proto(cx);
|
2013-05-05 11:03:14 +04:00
|
|
|
if (!js::GetObjectProto(cx, proxy, &proto)) {
|
2012-09-04 03:42:10 +04:00
|
|
|
return false;
|
|
|
|
}
|
2012-05-22 17:46:20 +04:00
|
|
|
if (!proto) {
|
|
|
|
*found = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-01-02 23:02:36 +03:00
|
|
|
if (!JS_HasPropertyById(cx, proto, id, found)) {
|
2012-05-22 17:46:20 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-01-02 23:02:36 +03:00
|
|
|
if (!*found) {
|
2012-05-22 17:46:20 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-18 01:14:41 +03:00
|
|
|
return JS_ForwardGetPropertyTo(cx, proto, id, receiver, vp);
|
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
|
|
|
{
|
2015-01-02 23:02:36 +03:00
|
|
|
JS::Rooted<JSObject*> proto(cx);
|
|
|
|
if (!js::GetObjectProto(cx, proxy, &proto)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!proto) {
|
|
|
|
*has = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return JS_HasPropertyById(cx, proto, id, has);
|
2013-07-09 18:45:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
|
|
|
|
nsTArray<nsString>& names,
|
|
|
|
bool shadowPrototypeProperties,
|
|
|
|
JS::AutoIdVector& props)
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < names.Length(); ++i) {
|
|
|
|
JS::Rooted<JS::Value> v(cx);
|
2013-10-12 09:02:39 +04:00
|
|
|
if (!xpc::NonVoidStringToJsval(cx, names[i], &v)) {
|
2013-07-09 18:45:13 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::Rooted<jsid> id(cx);
|
2014-01-17 22:08:51 +04:00
|
|
|
if (!JS_ValueToId(cx, v, &id)) {
|
2013-07-09 18:45:13 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-01-02 23:02:36 +03:00
|
|
|
bool shouldAppend = shadowPrototypeProperties;
|
|
|
|
if (!shouldAppend) {
|
|
|
|
bool has;
|
|
|
|
if (!HasPropertyOnPrototype(cx, proxy, id, &has)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
shouldAppend = !has;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shouldAppend) {
|
2013-07-09 18:45:13 +04:00
|
|
|
if (!props.append(id)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2012-05-22 17:46:20 +04:00
|
|
|
}
|
|
|
|
|
2013-05-08 01:18:03 +04:00
|
|
|
bool
|
2014-02-07 06:08:28 +04:00
|
|
|
DictionaryBase::ParseJSON(JSContext* aCx,
|
|
|
|
const nsAString& aJSON,
|
|
|
|
JS::MutableHandle<JS::Value> aVal)
|
2012-10-16 18:52:10 +04:00
|
|
|
{
|
2012-10-16 19:37:44 +04:00
|
|
|
if (aJSON.IsEmpty()) {
|
2013-05-08 01:18:03 +04:00
|
|
|
return true;
|
2012-10-16 18:52:10 +04:00
|
|
|
}
|
2014-07-22 08:43:21 +04:00
|
|
|
return JS_ParseJSON(aCx, PromiseFlatString(aJSON).get(), aJSON.Length(), aVal);
|
2012-10-16 18:52:10 +04:00
|
|
|
}
|
|
|
|
|
2014-08-01 07:50:19 +04:00
|
|
|
bool
|
|
|
|
DictionaryBase::StringifyToJSON(JSContext* aCx,
|
2016-02-11 07:31:33 +03:00
|
|
|
JS::Handle<JSObject*> aObj,
|
2014-09-09 22:00:22 +04:00
|
|
|
nsAString& aJSON) const
|
2014-08-01 07:50:19 +04:00
|
|
|
{
|
2016-02-11 07:31:33 +03:00
|
|
|
return JS::ToJSONMaybeSafely(aCx, aObj, AppendJSONToString, &aJSON);
|
2014-08-01 07:50:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
bool
|
2014-07-22 08:43:21 +04:00
|
|
|
DictionaryBase::AppendJSONToString(const char16_t* aJSONData,
|
2014-08-01 07:50:19 +04:00
|
|
|
uint32_t aDataLength,
|
|
|
|
void* aString)
|
|
|
|
{
|
|
|
|
nsAString* string = static_cast<nsAString*>(aString);
|
2014-07-22 08:43:21 +04:00
|
|
|
string->Append(aJSONData, aDataLength);
|
2014-08-01 07:50:19 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-09-13 20:34:55 +03:00
|
|
|
void
|
|
|
|
ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObjArg, ErrorResult& aError)
|
2012-09-26 18:17:46 +04:00
|
|
|
{
|
2014-04-09 02:27:15 +04:00
|
|
|
js::AssertSameCompartment(aCx, aObjArg);
|
|
|
|
|
2017-09-13 20:34:55 +03:00
|
|
|
aError.MightThrowJSException();
|
|
|
|
|
2014-11-13 23:23:11 +03:00
|
|
|
// Check if we're anywhere near the stack limit before we reach the
|
|
|
|
// transplanting code, since it has no good way to handle errors. This uses
|
|
|
|
// the untrusted script limit, which is not strictly necessary since no
|
|
|
|
// actual script should run.
|
2017-02-25 18:07:56 +03:00
|
|
|
if (!js::CheckRecursionLimitConservative(aCx)) {
|
2017-09-13 20:34:55 +03:00
|
|
|
aError.StealExceptionFromJSContext(aCx);
|
|
|
|
return;
|
2017-02-25 18:07:56 +03:00
|
|
|
}
|
2014-03-07 03:26:17 +04:00
|
|
|
|
2013-10-16 02:34:13 +04:00
|
|
|
JS::Rooted<JSObject*> aObj(aCx, aObjArg);
|
2014-06-19 00:19:19 +04:00
|
|
|
const DOMJSClass* domClass = GetDOMClass(aObj);
|
2012-09-26 18:17:46 +04:00
|
|
|
|
2015-02-26 17:40:07 +03:00
|
|
|
// DOM things are always parented to globals.
|
2015-03-07 00:33:31 +03:00
|
|
|
JS::Rooted<JSObject*> oldParent(aCx,
|
|
|
|
js::GetGlobalForObjectCrossCompartment(aObj));
|
2015-02-26 17:40:07 +03:00
|
|
|
MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(oldParent) == oldParent);
|
|
|
|
|
2016-07-27 18:05:36 +03:00
|
|
|
JS::Rooted<JSObject*> newParent(aCx,
|
|
|
|
domClass->mGetAssociatedGlobal(aCx, aObj));
|
|
|
|
MOZ_ASSERT(JS_IsGlobalObject(newParent));
|
2012-09-26 18:17:46 +04:00
|
|
|
|
2018-05-16 11:53:16 +03:00
|
|
|
JSAutoRealm oldAr(aCx, oldParent);
|
2012-09-26 18:17:46 +04:00
|
|
|
|
2013-10-23 16:02:42 +04:00
|
|
|
JSCompartment* oldCompartment = js::GetObjectCompartment(oldParent);
|
|
|
|
JSCompartment* newCompartment = js::GetObjectCompartment(newParent);
|
|
|
|
if (oldCompartment == newCompartment) {
|
2015-02-26 17:40:07 +03:00
|
|
|
MOZ_ASSERT(oldParent == newParent);
|
2017-09-13 20:34:55 +03:00
|
|
|
return;
|
2012-09-26 18:17:46 +04:00
|
|
|
}
|
|
|
|
|
2013-06-01 10:56:02 +04:00
|
|
|
nsISupports* native = UnwrapDOMObjectToISupports(aObj);
|
|
|
|
if (!native) {
|
2017-09-13 20:34:55 +03:00
|
|
|
return;
|
2012-09-26 18:17:46 +04:00
|
|
|
}
|
|
|
|
|
2013-04-16 21:02:57 +04:00
|
|
|
bool isProxy = js::IsProxy(aObj);
|
2013-05-04 03:29:08 +04:00
|
|
|
JS::Rooted<JSObject*> expandoObject(aCx);
|
2013-04-16 21:02:57 +04:00
|
|
|
if (isProxy) {
|
|
|
|
expandoObject = DOMProxyHandler::GetAndClearExpandoObject(aObj);
|
|
|
|
}
|
|
|
|
|
2018-05-16 11:53:16 +03:00
|
|
|
JSAutoRealm newAr(aCx, newParent);
|
2012-09-26 18:17:46 +04:00
|
|
|
|
|
|
|
// First we clone the reflector. We get a copy of its properties and clone its
|
2015-03-05 16:39:53 +03:00
|
|
|
// expando chain.
|
2012-09-26 18:17:46 +04:00
|
|
|
|
2016-07-09 07:19:52 +03:00
|
|
|
JS::Handle<JSObject*> proto = (domClass->mGetProto)(aCx);
|
2012-09-26 18:17:46 +04:00
|
|
|
if (!proto) {
|
2017-09-13 20:34:55 +03:00
|
|
|
aError.StealExceptionFromJSContext(aCx);
|
|
|
|
return;
|
2012-09-26 18:17:46 +04:00
|
|
|
}
|
|
|
|
|
2015-02-26 23:58:59 +03:00
|
|
|
JS::Rooted<JSObject*> newobj(aCx, JS_CloneObject(aCx, aObj, proto));
|
2012-09-26 18:17:46 +04:00
|
|
|
if (!newobj) {
|
2017-09-13 20:34:55 +03:00
|
|
|
aError.StealExceptionFromJSContext(aCx);
|
|
|
|
return;
|
2012-09-26 18:17:46 +04:00
|
|
|
}
|
|
|
|
|
2013-05-04 03:29:08 +04:00
|
|
|
JS::Rooted<JSObject*> propertyHolder(aCx);
|
2015-03-05 16:39:53 +03:00
|
|
|
JS::Rooted<JSObject*> copyFrom(aCx, isProxy ? expandoObject : aObj);
|
|
|
|
if (copyFrom) {
|
2015-05-14 00:07:34 +03:00
|
|
|
propertyHolder = JS_NewObjectWithGivenProto(aCx, nullptr, nullptr);
|
2015-03-05 16:39:53 +03:00
|
|
|
if (!propertyHolder) {
|
2017-09-13 20:34:55 +03:00
|
|
|
aError.StealExceptionFromJSContext(aCx);
|
|
|
|
return;
|
2012-09-26 18:17:46 +04:00
|
|
|
}
|
|
|
|
|
2015-03-05 16:39:53 +03:00
|
|
|
if (!JS_CopyPropertiesFrom(aCx, propertyHolder, copyFrom)) {
|
2017-09-13 20:34:55 +03:00
|
|
|
aError.StealExceptionFromJSContext(aCx);
|
|
|
|
return;
|
2012-09-26 18:17:46 +04:00
|
|
|
}
|
2015-03-05 16:39:53 +03:00
|
|
|
} else {
|
|
|
|
propertyHolder = nullptr;
|
|
|
|
}
|
2012-09-26 18:17:46 +04:00
|
|
|
|
2015-03-05 16:39:53 +03:00
|
|
|
// We've set up |newobj|, so we make it own the native by setting its reserved
|
|
|
|
// slot and nulling out the reserved slot of |obj|.
|
|
|
|
//
|
|
|
|
// NB: It's important to do this _after_ copying the properties to
|
|
|
|
// propertyHolder. Otherwise, an object with |foo.x === foo| will
|
|
|
|
// crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x.
|
2017-04-28 15:12:28 +03:00
|
|
|
js::SetReservedSlot(newobj, DOM_OBJECT_SLOT,
|
|
|
|
js::GetReservedSlot(aObj, DOM_OBJECT_SLOT));
|
|
|
|
js::SetReservedSlot(aObj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr));
|
2015-03-05 16:39:53 +03:00
|
|
|
|
2017-10-05 19:49:43 +03:00
|
|
|
aObj = xpc::TransplantObjectRetainingXrayExpandos(aCx, aObj, newobj);
|
2014-03-19 20:35:45 +04:00
|
|
|
if (!aObj) {
|
2013-10-17 12:00:02 +04:00
|
|
|
MOZ_CRASH();
|
2012-09-26 18:17:46 +04:00
|
|
|
}
|
|
|
|
|
2014-03-19 20:35:45 +04:00
|
|
|
nsWrapperCache* cache = nullptr;
|
|
|
|
CallQueryInterface(native, &cache);
|
2012-09-26 18:17:46 +04:00
|
|
|
bool preserving = cache->PreservingWrapper();
|
|
|
|
cache->SetPreservingWrapper(false);
|
|
|
|
cache->SetWrapper(aObj);
|
|
|
|
cache->SetPreservingWrapper(preserving);
|
2013-04-16 21:02:57 +04:00
|
|
|
|
|
|
|
if (propertyHolder) {
|
2014-03-17 20:17:58 +04:00
|
|
|
JS::Rooted<JSObject*> copyTo(aCx);
|
2013-04-16 21:02:57 +04:00
|
|
|
if (isProxy) {
|
|
|
|
copyTo = DOMProxyHandler::EnsureExpandoObject(aCx, aObj);
|
|
|
|
} else {
|
|
|
|
copyTo = aObj;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!copyTo || !JS_CopyPropertiesFrom(aCx, copyTo, propertyHolder)) {
|
|
|
|
MOZ_CRASH();
|
|
|
|
}
|
2012-09-26 18:17:46 +04:00
|
|
|
}
|
|
|
|
|
2017-07-10 23:05:24 +03:00
|
|
|
JS::Rooted<JSObject*> maybeObjLC(aCx, aObj);
|
2013-03-17 18:42:05 +04:00
|
|
|
nsObjectLoadingContent* htmlobject;
|
2017-07-10 23:05:24 +03:00
|
|
|
nsresult rv = UNWRAP_OBJECT(HTMLObjectElement, &maybeObjLC, htmlobject);
|
2013-03-17 18:42:05 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
2017-07-29 07:35:43 +03:00
|
|
|
rv = UNWRAP_OBJECT(HTMLEmbedElement, &maybeObjLC, htmlobject);
|
2013-03-17 18:42:05 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
2017-07-11 02:00:30 +03:00
|
|
|
htmlobject = nullptr;
|
2013-03-17 18:42:05 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (htmlobject) {
|
2013-01-07 03:55:14 +04:00
|
|
|
htmlobject->SetupProtoChain(aCx, aObj);
|
|
|
|
}
|
2012-09-26 18:17:46 +04:00
|
|
|
}
|
|
|
|
|
2013-08-23 09:17:08 +04:00
|
|
|
GlobalObject::GlobalObject(JSContext* aCx, JSObject* aObject)
|
|
|
|
: mGlobalJSObject(aCx),
|
|
|
|
mCx(aCx),
|
|
|
|
mGlobalObject(nullptr)
|
2012-12-03 20:07:49 +04:00
|
|
|
{
|
2014-06-16 22:08:00 +04:00
|
|
|
MOZ_ASSERT(mCx);
|
2013-05-04 03:29:08 +04:00
|
|
|
JS::Rooted<JSObject*> obj(aCx, aObject);
|
|
|
|
if (js::IsWrapper(obj)) {
|
2015-11-06 21:03:52 +03:00
|
|
|
obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
|
2013-05-04 03:29:08 +04:00
|
|
|
if (!obj) {
|
2013-08-23 09:17:08 +04:00
|
|
|
// We should never end up here on a worker thread, since there shouldn't
|
|
|
|
// be any security wrappers to worry about.
|
|
|
|
if (!MOZ_LIKELY(NS_IsMainThread())) {
|
|
|
|
MOZ_CRASH();
|
|
|
|
}
|
|
|
|
|
2013-09-09 07:29:21 +04:00
|
|
|
Throw(aCx, NS_ERROR_XPC_SECURITY_MANAGER_VETO);
|
2013-08-23 09:17:08 +04:00
|
|
|
return;
|
2012-12-03 20:07:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-21 07:19:43 +04:00
|
|
|
mGlobalJSObject = js::GetGlobalForObjectCrossCompartment(obj);
|
2012-12-03 20:07:49 +04:00
|
|
|
}
|
|
|
|
|
2013-08-23 09:17:08 +04:00
|
|
|
nsISupports*
|
|
|
|
GlobalObject::GetAsSupports() const
|
2012-12-03 20:07:49 +04:00
|
|
|
{
|
2013-08-23 09:17:08 +04:00
|
|
|
if (mGlobalObject) {
|
|
|
|
return mGlobalObject;
|
2012-12-03 20:07:49 +04:00
|
|
|
}
|
|
|
|
|
2014-10-22 19:40:50 +04:00
|
|
|
MOZ_ASSERT(!js::IsWrapper(mGlobalJSObject));
|
|
|
|
|
|
|
|
// Most of our globals are DOM objects. Try that first. Note that this
|
|
|
|
// assumes that either the first nsISupports in the object is the canonical
|
|
|
|
// one or that we don't care about the canonical nsISupports here.
|
|
|
|
mGlobalObject = UnwrapDOMObjectToISupports(mGlobalJSObject);
|
|
|
|
if (mGlobalObject) {
|
2014-03-07 01:05:11 +04:00
|
|
|
return mGlobalObject;
|
2014-02-26 01:34:55 +04:00
|
|
|
}
|
|
|
|
|
2014-10-22 19:40:50 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "All our worker globals are DOM objects");
|
2012-12-03 20:07:49 +04:00
|
|
|
|
2014-10-22 19:40:50 +04:00
|
|
|
// Remove everything below here once all our global objects are using new
|
|
|
|
// bindings. If that ever happens; it would need to include Sandbox and
|
|
|
|
// BackstagePass.
|
|
|
|
|
|
|
|
// See whether mGlobalJSObject is an XPCWrappedNative. This will redo the
|
|
|
|
// IsWrapper bit above and the UnwrapDOMObjectToISupports in the case when
|
|
|
|
// we're not actually an XPCWrappedNative, but this should be a rare-ish case
|
|
|
|
// anyway.
|
Bug 1371259 part 9. Make UnwrapReflectorToISupports return already_AddRefed<nsISupports>. r=peterv
The main reason to not do this would be performance (avoiding the
addref/release), but there are two main mitigating factors:
1) All calls to UnwrapReflectorToISupports that pass in a Web IDL object
already do the addref (and in fact QI). So this only affects the
XPCWrappedNative case.
2) The vast majority of the callers proceed to QI on the pointer anyway, and a
second addref is cheap; it's the first addref after a CC that can be
expensive on a cycle-collected object.
Going through the changes one by one:
* In GlobalObject::GetAsSupports, we do have a change that slightly slows down
precisely in the XPCWrappedNative global case. That's the message managers
and the backstagepass. And this really only affects calls to Web IDL statics
from those globals.
* In UnwrapArgImpl we're talking about a Web IDL method taking an "external
interface" type, and the UnwrapReflectorToISupports call is immediately
followed by QI anyway.
* In UnwrapXPConnectImpl we're talking about the case when we have a
non-WebIDL-object implementation of a Web IDL interface. Again, this is the
message manager globals, for EventTarget. And we have a QI call immediately
after the UnwrapReflectorToISupports.
* In the generated HasInstance hook for EventTarget we will be slightly slower
when the LHS of the instanceof is an XPCWrappedNative. And not much slower,
because again there's an immediate QI.
* In InstallXBLField we're never going to have an XPCWrappedNative as thisObj;
it's always an Element in practice. So this is no more expensive than before.
* In sandbox's GetPrincipalOrSOP we now have an extra addref. But it was
followed by various QIs anyway.
* In XPCConvert::JSValToXPCException we have an extra addref if someone throws
an XPCWrappedNative, which is fairly unlikely; our actual Exception objects
are on Web IDL bindings. Plus we have an immediate QI.
* In xpc::HasInstance we have an extra addred if the LHS of instanceof is an
XPCWrappedNative. But, again, there's an immediated QI after the
UnwrapReflectorToISupports.
* In xpcJSWeakReference::Init we are likely doing an extra addref, but again
immediately followed by QI.
I think it's worth making this change just to remove the footgun and that the
perf impact, if any, is pretty minimal.
2017-07-10 23:05:26 +03:00
|
|
|
nsCOMPtr<nsISupports> supp = xpc::UnwrapReflectorToISupports(mGlobalJSObject);
|
|
|
|
if (supp) {
|
|
|
|
// See documentation for mGlobalJSObject for why this assignment is OK.
|
|
|
|
mGlobalObject = supp;
|
2014-10-22 19:40:50 +04:00
|
|
|
return mGlobalObject;
|
|
|
|
}
|
|
|
|
|
|
|
|
// And now a final hack. Sandbox is not a reflector, but it does have an
|
|
|
|
// nsIGlobalObject hanging out in its private slot. Handle that case here,
|
|
|
|
// (though again, this will do the useless UnwrapDOMObjectToISupports if we
|
|
|
|
// got here for something that is somehow not a DOM object, not an
|
|
|
|
// XPCWrappedNative _and_ not a Sandbox).
|
|
|
|
if (XPCConvert::GetISupportsFromJSObject(mGlobalJSObject, &mGlobalObject)) {
|
|
|
|
return mGlobalObject;
|
2012-12-03 20:07:49 +04:00
|
|
|
}
|
|
|
|
|
2014-10-22 19:40:50 +04:00
|
|
|
MOZ_ASSERT(!mGlobalObject);
|
|
|
|
|
|
|
|
Throw(mCx, NS_ERROR_XPC_BAD_CONVERT_JS);
|
|
|
|
return nullptr;
|
2012-12-03 20:07:49 +04:00
|
|
|
}
|
|
|
|
|
2016-09-30 20:54:13 +03:00
|
|
|
nsIPrincipal*
|
|
|
|
GlobalObject::GetSubjectPrincipal() const
|
|
|
|
{
|
|
|
|
if (!NS_IsMainThread()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSCompartment* compartment = js::GetContextCompartment(mCx);
|
|
|
|
MOZ_ASSERT(compartment);
|
|
|
|
JSPrincipals* principals = JS_GetCompartmentPrincipals(compartment);
|
|
|
|
return nsJSPrincipals::get(principals);
|
|
|
|
}
|
|
|
|
|
2016-12-07 12:41:52 +03:00
|
|
|
CallerType
|
|
|
|
GlobalObject::CallerType() const
|
|
|
|
{
|
|
|
|
return nsContentUtils::ThreadsafeIsSystemCaller(mCx) ?
|
|
|
|
dom::CallerType::System : dom::CallerType::NonSystem;
|
|
|
|
}
|
|
|
|
|
2016-08-04 04:32:07 +03:00
|
|
|
static bool
|
|
|
|
CallOrdinaryHasInstance(JSContext* cx, JS::CallArgs& args)
|
|
|
|
{
|
|
|
|
JS::Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
|
|
|
bool isInstance;
|
|
|
|
if (!JS::OrdinaryHasInstance(cx, thisObj, args.get(0), &isInstance)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
args.rval().setBoolean(isInstance);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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-01-08 22:05:36 +04:00
|
|
|
{
|
2016-08-04 04:32:07 +03:00
|
|
|
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
|
|
|
// If the thing we were passed is not an object, return false like
|
|
|
|
// OrdinaryHasInstance does.
|
|
|
|
if (!args.get(0).isObject()) {
|
|
|
|
args.rval().setBoolean(false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If "this" is not an object, likewise return false (again, like
|
|
|
|
// OrdinaryHasInstance).
|
|
|
|
if (!args.thisv().isObject()) {
|
|
|
|
args.rval().setBoolean(false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If "this" doesn't have a DOMIfaceAndProtoJSClass, it's not a DOM
|
|
|
|
// constructor, so just fall back to OrdinaryHasInstance. But note that we
|
|
|
|
// should CheckedUnwrap here, because otherwise we won't get the right
|
|
|
|
// answers.
|
|
|
|
JS::Rooted<JSObject*> thisObj(cx, js::CheckedUnwrap(&args.thisv().toObject()));
|
|
|
|
if (!thisObj) {
|
|
|
|
// Just fall back on the normal thing, in case it still happens to work.
|
|
|
|
return CallOrdinaryHasInstance(cx, args);
|
|
|
|
}
|
|
|
|
|
|
|
|
const js::Class* thisClass = js::GetObjectClass(thisObj);
|
|
|
|
|
|
|
|
if (!IsDOMIfaceAndProtoClass(thisClass)) {
|
|
|
|
return CallOrdinaryHasInstance(cx, args);
|
|
|
|
}
|
|
|
|
|
2013-01-08 22:05:36 +04:00
|
|
|
const DOMIfaceAndProtoJSClass* clasp =
|
2016-08-04 04:32:07 +03:00
|
|
|
DOMIfaceAndProtoJSClass::FromJSClass(thisClass);
|
2013-01-08 22:05:36 +04:00
|
|
|
|
2016-08-04 04:32:07 +03:00
|
|
|
// If "this" isn't a DOM constructor or is a constructor for an interface
|
|
|
|
// without a prototype, just fall back to OrdinaryHasInstance.
|
|
|
|
if (clasp->mType != eInterface ||
|
|
|
|
clasp->mPrototypeID == prototypes::id::_ID_Count) {
|
|
|
|
return CallOrdinaryHasInstance(cx, args);
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> instance(cx, &args[0].toObject());
|
2015-11-06 21:03:52 +03:00
|
|
|
const DOMJSClass* domClass =
|
|
|
|
GetDOMClass(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
|
2013-01-08 22:05:36 +04:00
|
|
|
|
2013-02-22 13:25:24 +04:00
|
|
|
if (domClass &&
|
|
|
|
domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) {
|
2016-08-04 04:32:07 +03:00
|
|
|
args.rval().setBoolean(true);
|
2013-02-22 13:25:24 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-07-11 03:47:04 +04:00
|
|
|
if (jsipc::IsWrappedCPOW(instance)) {
|
2013-08-02 03:45:17 +04:00
|
|
|
bool boolp = false;
|
2016-05-28 00:48:51 +03:00
|
|
|
if (!jsipc::DOMInstanceOf(cx, js::UncheckedUnwrap(instance), clasp->mPrototypeID,
|
2014-07-11 03:47:04 +04:00
|
|
|
clasp->mDepth, &boolp)) {
|
2013-08-02 03:45:17 +04:00
|
|
|
return false;
|
|
|
|
}
|
2016-08-04 04:32:07 +03:00
|
|
|
args.rval().setBoolean(boolp);
|
2013-01-08 22:05:36 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-04 04:32:07 +03:00
|
|
|
return CallOrdinaryHasInstance(cx, args);
|
2013-01-08 22:05:36 +04:00
|
|
|
}
|
|
|
|
|
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-08-02 03:45:17 +04:00
|
|
|
{
|
2014-06-19 00:19:19 +04:00
|
|
|
const DOMJSClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance));
|
2013-08-02 03:45:17 +04:00
|
|
|
|
|
|
|
MOZ_ASSERT(!domClass || prototypeID != prototypes::id::_ID_Count,
|
|
|
|
"Why do we have a hasInstance hook if we don't have a prototype "
|
|
|
|
"ID?");
|
|
|
|
|
|
|
|
*bp = (domClass && domClass->mInterfaceChain[depth] == prototypeID);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-01-11 08:00:25 +03:00
|
|
|
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
|
|
|
{
|
|
|
|
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
2018-04-12 07:06:07 +03:00
|
|
|
|
|
|
|
// If the thing we were passed is not an object, return false.
|
|
|
|
if (!args.get(0).isObject()) {
|
|
|
|
args.rval().setBoolean(false);
|
|
|
|
return true;
|
2018-01-11 08:00:25 +03:00
|
|
|
}
|
|
|
|
|
2018-04-12 07:06:07 +03:00
|
|
|
// If "this" isn't a DOM constructor or is a constructor for an interface
|
|
|
|
// without a prototype, return false.
|
|
|
|
if (!args.thisv().isObject()) {
|
|
|
|
args.rval().setBoolean(false);
|
|
|
|
return true;
|
2018-01-11 08:00:25 +03:00
|
|
|
}
|
|
|
|
|
2018-04-12 07:06:07 +03:00
|
|
|
JS::Rooted<JSObject*> thisObj(cx, js::CheckedUnwrap(&args.thisv().toObject()));
|
|
|
|
if (!thisObj) {
|
|
|
|
args.rval().setBoolean(false);
|
|
|
|
return true;
|
|
|
|
}
|
2018-01-11 08:00:25 +03:00
|
|
|
|
2018-04-12 07:06:07 +03:00
|
|
|
const js::Class* thisClass = js::GetObjectClass(thisObj);
|
|
|
|
if (!IsDOMIfaceAndProtoClass(thisClass)) {
|
|
|
|
args.rval().setBoolean(false);
|
|
|
|
return true;
|
|
|
|
}
|
2018-01-11 08:00:25 +03:00
|
|
|
|
2018-04-12 07:06:07 +03:00
|
|
|
const DOMIfaceAndProtoJSClass* clasp =
|
|
|
|
DOMIfaceAndProtoJSClass::FromJSClass(thisClass);
|
|
|
|
|
|
|
|
if (clasp->mType != eInterface ||
|
|
|
|
clasp->mPrototypeID == prototypes::id::_ID_Count) {
|
|
|
|
args.rval().setBoolean(false);
|
2018-01-11 08:00:25 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-04-12 07:06:07 +03:00
|
|
|
JS::Rooted<JSObject*> instance(cx, &args[0].toObject());
|
|
|
|
const DOMJSClass* domClass =
|
|
|
|
GetDOMClass(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
|
|
|
|
|
|
|
|
bool isInstance =
|
|
|
|
domClass &&
|
|
|
|
domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID;
|
|
|
|
|
|
|
|
args.rval().setBoolean(isInstance);
|
2018-01-11 08:00:25 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-05-08 23:50:58 +04:00
|
|
|
bool
|
2013-09-25 22:38:30 +04:00
|
|
|
ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj)
|
2013-04-09 01:04:21 +04:00
|
|
|
{
|
2013-09-25 22:38:30 +04:00
|
|
|
JS::Rooted<JSObject*> rootedObj(cx, obj);
|
|
|
|
GlobalObject global(cx, rootedObj);
|
2013-05-08 23:50:58 +04:00
|
|
|
if (global.Failed()) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-01-30 20:05:36 +03:00
|
|
|
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global.GetAsSupports());
|
2013-04-09 01:04:21 +04:00
|
|
|
if (window && window->GetDoc()) {
|
|
|
|
window->GetDoc()->WarnOnceAbout(nsIDocument::eLenientThis);
|
|
|
|
}
|
2013-05-08 23:50:58 +04:00
|
|
|
return true;
|
2013-04-09 01:04:21 +04:00
|
|
|
}
|
|
|
|
|
2013-05-20 21:47:08 +04:00
|
|
|
bool
|
2015-01-08 19:57:19 +03:00
|
|
|
GetContentGlobalForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
|
|
|
|
nsIGlobalObject** globalObj)
|
2013-05-20 21:47:08 +04:00
|
|
|
{
|
|
|
|
// Be very careful to not get tricked here.
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (!xpc::AccessCheck::isChrome(js::GetObjectCompartment(obj))) {
|
2016-12-03 00:46:53 +03:00
|
|
|
MOZ_CRASH("Should have a chrome object here");
|
2013-05-20 21:47:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Look up the content-side object.
|
|
|
|
JS::Rooted<JS::Value> domImplVal(cx);
|
2013-07-26 13:00:38 +04:00
|
|
|
if (!JS_GetProperty(cx, obj, "__DOM_IMPL__", &domImplVal)) {
|
2013-05-20 21:47:08 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!domImplVal.isObject()) {
|
2013-06-17 21:07:03 +04:00
|
|
|
ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Value");
|
2013-05-20 21:47:08 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Go ahead and get the global from it. GlobalObject will handle
|
|
|
|
// doing unwrapping as needed.
|
|
|
|
GlobalObject global(cx, &domImplVal.toObject());
|
|
|
|
if (global.Failed()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-01-08 19:57:19 +03:00
|
|
|
DebugOnly<nsresult> rv = CallQueryInterface(global.GetAsSupports(), globalObj);
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
|
|
MOZ_ASSERT(*globalObj);
|
2013-05-20 21:47:08 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
2015-01-08 19:57:19 +03:00
|
|
|
// Get the global object to use as a parent and for initialization.
|
|
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
|
|
|
if (!global) {
|
2013-06-01 10:56:23 +04:00
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-03-12 00:43:31 +03:00
|
|
|
ConstructJSImplementation(aContractId, global, aObject, aRv);
|
2014-03-28 08:03:03 +04:00
|
|
|
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2015-01-08 19:57:19 +03:00
|
|
|
return global.forget();
|
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)
|
|
|
|
{
|
2016-03-12 00:43:31 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
2013-12-12 05:51:58 +04:00
|
|
|
// Make sure to divorce ourselves from the calling JS while creating and
|
2013-06-01 10:56:23 +04:00
|
|
|
// initializing the object, so exceptions from that will get reported
|
|
|
|
// properly, since those are never exceptions that a spec wants to be thrown.
|
2013-12-12 05:51:58 +04:00
|
|
|
{
|
2014-04-15 07:27:00 +04:00
|
|
|
AutoNoJSAPI nojsapi;
|
2013-12-12 05:51:58 +04:00
|
|
|
|
2013-06-01 10:56:23 +04:00
|
|
|
// Get the XPCOM component containing the JS implementation.
|
2014-10-02 04:37:50 +04:00
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsISupports> implISupports = do_CreateInstance(aContractId, &rv);
|
2013-06-01 10:56:23 +04:00
|
|
|
if (!implISupports) {
|
2014-11-24 19:57:49 +03:00
|
|
|
nsPrintfCString msg("Failed to get JS implementation for contract \"%s\"",
|
|
|
|
aContractId);
|
|
|
|
NS_WARNING(msg.get());
|
2014-10-02 04:37:50 +04:00
|
|
|
aRv.Throw(rv);
|
2014-03-28 08:03:03 +04:00
|
|
|
return;
|
2013-06-01 10:56:23 +04:00
|
|
|
}
|
2015-01-08 19:57:19 +03:00
|
|
|
// Initialize the object, if it implements nsIDOMGlobalPropertyInitializer
|
|
|
|
// and our global is a window.
|
2013-06-01 10:56:23 +04:00
|
|
|
nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi =
|
|
|
|
do_QueryInterface(implISupports);
|
2016-01-30 20:05:36 +03:00
|
|
|
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
|
2013-06-01 10:56:23 +04:00
|
|
|
if (gpi) {
|
2016-08-11 15:39:22 +03:00
|
|
|
JS::Rooted<JS::Value> initReturn(RootingCx());
|
2015-01-08 19:57:19 +03:00
|
|
|
rv = gpi->Init(window, &initReturn);
|
2013-06-01 10:56:23 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
2014-03-28 08:03:03 +04:00
|
|
|
return;
|
2013-06-01 10:56:23 +04:00
|
|
|
}
|
2013-09-27 03:46:42 +04:00
|
|
|
// With JS-implemented WebIDL, the return value of init() is not used to determine
|
|
|
|
// if init() failed, so init() should only return undefined. Any kind of permission
|
|
|
|
// or pref checking must happen by adding an attribute to the WebIDL interface.
|
|
|
|
if (!initReturn.isUndefined()) {
|
|
|
|
MOZ_ASSERT(false, "The init() method for JS-implemented WebIDL should not return anything");
|
|
|
|
MOZ_CRASH();
|
|
|
|
}
|
2013-06-01 10:56:23 +04:00
|
|
|
}
|
|
|
|
// Extract the JS implementation from the XPCOM object.
|
|
|
|
nsCOMPtr<nsIXPConnectWrappedJS> implWrapped =
|
2014-10-02 04:37:50 +04:00
|
|
|
do_QueryInterface(implISupports, &rv);
|
2013-06-01 10:56:23 +04:00
|
|
|
MOZ_ASSERT(implWrapped, "Failed to get wrapped JS from XPCOM component.");
|
|
|
|
if (!implWrapped) {
|
2014-10-02 04:37:50 +04:00
|
|
|
aRv.Throw(rv);
|
2014-03-28 08:03:03 +04:00
|
|
|
return;
|
2013-06-01 10:56:23 +04:00
|
|
|
}
|
|
|
|
aObject.set(implWrapped->GetJSObject());
|
|
|
|
if (!aObject) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-13 09:18:35 +04:00
|
|
|
bool
|
|
|
|
NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
|
|
|
|
JS::MutableHandle<JS::Value> rval)
|
|
|
|
{
|
|
|
|
// ByteStrings are not UTF-8 encoded.
|
|
|
|
JSString* jsStr = JS_NewStringCopyN(cx, str.Data(), str.Length());
|
|
|
|
|
|
|
|
if (!jsStr)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
rval.setString(jsStr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-08-02 00:23:48 +04:00
|
|
|
|
|
|
|
template<typename T> static void
|
2017-02-15 08:01:37 +03:00
|
|
|
NormalizeUSVStringInternal(T& aString)
|
2014-08-02 00:23:48 +04:00
|
|
|
{
|
|
|
|
char16_t* start = aString.BeginWriting();
|
|
|
|
// Must use const here because we can't pass char** to UTF16CharEnumerator as
|
|
|
|
// it expects const char**. Unclear why this is illegal...
|
|
|
|
const char16_t* nextChar = start;
|
|
|
|
const char16_t* end = aString.Data() + aString.Length();
|
|
|
|
while (nextChar < end) {
|
|
|
|
uint32_t enumerated = UTF16CharEnumerator::NextChar(&nextChar, end);
|
|
|
|
if (enumerated == UCS2_REPLACEMENT_CHAR) {
|
|
|
|
int32_t lastCharIndex = (nextChar - start) - 1;
|
|
|
|
start[lastCharIndex] = static_cast<char16_t>(enumerated);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-02-15 08:01:37 +03:00
|
|
|
NormalizeUSVString(nsAString& aString)
|
2014-08-02 00:23:48 +04:00
|
|
|
{
|
2017-02-15 08:01:37 +03:00
|
|
|
NormalizeUSVStringInternal(aString);
|
2014-08-02 00:23:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-02-15 08:01:37 +03:00
|
|
|
NormalizeUSVString(binding_detail::FakeString& aString)
|
2014-08-02 00:23:48 +04:00
|
|
|
{
|
2017-02-15 08:01:37 +03:00
|
|
|
NormalizeUSVStringInternal(aString);
|
2014-08-02 00:23:48 +04:00
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2013-09-30 18:29:10 +04:00
|
|
|
JS::Rooted<JSString*> s(cx);
|
2013-06-13 09:18:35 +04:00
|
|
|
if (v.isString()) {
|
|
|
|
s = v.toString();
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (nullable && v.isNullOrUndefined()) {
|
|
|
|
result.SetIsVoid(true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-11-16 16:31:36 +04:00
|
|
|
s = JS::ToString(cx, v);
|
2013-06-13 09:18:35 +04:00
|
|
|
if (!s) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-02 15:04:14 +04:00
|
|
|
// Conversion from Javascript string to ByteString is only valid if all
|
|
|
|
// characters < 256. This is always the case for Latin1 strings.
|
2013-06-13 09:18:35 +04:00
|
|
|
size_t length;
|
2014-07-03 15:05:03 +04:00
|
|
|
if (!js::StringHasLatin1Chars(s)) {
|
2014-07-02 15:04:14 +04:00
|
|
|
// ThrowErrorMessage can GC, so we first scan the string for bad chars
|
|
|
|
// and report the error outside the AutoCheckCannotGC scope.
|
|
|
|
bool foundBadChar = false;
|
|
|
|
size_t badCharIndex;
|
2014-07-22 08:43:21 +04:00
|
|
|
char16_t badChar;
|
2014-07-02 15:04:14 +04:00
|
|
|
{
|
|
|
|
JS::AutoCheckCannotGC nogc;
|
2014-07-22 08:43:21 +04:00
|
|
|
const char16_t* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, s, &length);
|
2014-07-02 15:04:14 +04:00
|
|
|
if (!chars) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-06-13 09:18:35 +04:00
|
|
|
|
2014-07-02 15:04:14 +04:00
|
|
|
for (size_t i = 0; i < length; i++) {
|
|
|
|
if (chars[i] > 255) {
|
|
|
|
badCharIndex = i;
|
|
|
|
badChar = chars[i];
|
|
|
|
foundBadChar = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (foundBadChar) {
|
|
|
|
MOZ_ASSERT(badCharIndex < length);
|
|
|
|
MOZ_ASSERT(badChar > 255);
|
2013-06-13 09:18:35 +04:00
|
|
|
// The largest unsigned 64 bit number (18,446,744,073,709,551,615) has
|
|
|
|
// 20 digits, plus one more for the null terminator.
|
|
|
|
char index[21];
|
2013-07-18 21:59:53 +04:00
|
|
|
static_assert(sizeof(size_t) <= 8, "index array too small");
|
2017-07-26 23:03:57 +03:00
|
|
|
SprintfLiteral(index, "%zu", badCharIndex);
|
2014-07-22 08:43:21 +04:00
|
|
|
// A char16_t is 16 bits long. The biggest unsigned 16 bit
|
2013-06-13 09:18:35 +04:00
|
|
|
// number (65,535) has 5 digits, plus one more for the null
|
|
|
|
// terminator.
|
2014-07-02 15:04:14 +04:00
|
|
|
char badCharArray[6];
|
2014-07-22 08:43:21 +04:00
|
|
|
static_assert(sizeof(char16_t) <= 2, "badCharArray too small");
|
2016-08-15 09:44:00 +03:00
|
|
|
SprintfLiteral(badCharArray, "%d", badChar);
|
2014-07-02 15:04:14 +04:00
|
|
|
ThrowErrorMessage(cx, MSG_INVALID_BYTESTRING, index, badCharArray);
|
2013-06-13 09:18:35 +04:00
|
|
|
return false;
|
|
|
|
}
|
2014-07-02 15:04:14 +04:00
|
|
|
} else {
|
2014-07-03 15:05:03 +04:00
|
|
|
length = js::GetStringLength(s);
|
2013-06-13 09:18:35 +04:00
|
|
|
}
|
|
|
|
|
2014-07-03 12:03:56 +04:00
|
|
|
static_assert(js::MaxStringLength < UINT32_MAX,
|
|
|
|
"length+1 shouldn't overflow");
|
|
|
|
|
2016-03-17 06:04:10 +03:00
|
|
|
if (!result.SetLength(length, fallible)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-07-19 17:23:19 +04:00
|
|
|
JS_EncodeStringToBuffer(cx, s, result.BeginWriting(), length);
|
2013-06-13 09:18:35 +04:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-11-19 10:05:42 +04:00
|
|
|
void
|
|
|
|
FinalizeGlobal(JSFreeOp* aFreeOp, JSObject* aObj)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(js::GetObjectClass(aObj)->flags & JSCLASS_DOM_GLOBAL);
|
|
|
|
mozilla::dom::DestroyProtoAndIfaceCache(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-03-06 09:08:06 +03:00
|
|
|
MOZ_ASSERT(JS_IsGlobalObject(aObj),
|
|
|
|
"Should have a global here, since we plan to resolve standard "
|
|
|
|
"classes!");
|
|
|
|
|
2014-11-08 03:07:12 +03:00
|
|
|
return JS_ResolveStandardClass(aCx, aObj, aId, 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)
|
|
|
|
{
|
|
|
|
return JS_MayResolveStandardClass(aNames, aId, 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
|
|
|
{
|
2015-03-06 09:08:06 +03:00
|
|
|
MOZ_ASSERT(JS_IsGlobalObject(aObj),
|
|
|
|
"Should have a global here, since we plan to enumerate standard "
|
|
|
|
"classes!");
|
|
|
|
|
2017-06-14 11:39:11 +03:00
|
|
|
return JS_NewEnumerateStandardClasses(aCx, aObj, aProperties,
|
|
|
|
aEnumerableOnly);
|
2013-11-05 18:16:26 +04:00
|
|
|
}
|
|
|
|
|
2014-05-25 22:31:07 +04:00
|
|
|
bool
|
2015-12-01 20:02:36 +03:00
|
|
|
IsNonExposedGlobal(JSContext* aCx, JSObject* aGlobal,
|
|
|
|
uint32_t aNonExposedGlobals)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aNonExposedGlobals, "Why did we get called?");
|
|
|
|
MOZ_ASSERT((aNonExposedGlobals &
|
|
|
|
~(GlobalNames::Window |
|
|
|
|
GlobalNames::BackstagePass |
|
|
|
|
GlobalNames::DedicatedWorkerGlobalScope |
|
|
|
|
GlobalNames::SharedWorkerGlobalScope |
|
|
|
|
GlobalNames::ServiceWorkerGlobalScope |
|
2016-11-06 11:54:29 +03:00
|
|
|
GlobalNames::WorkerDebuggerGlobalScope |
|
|
|
|
GlobalNames::WorkletGlobalScope)) == 0,
|
2015-12-01 20:02:36 +03:00
|
|
|
"Unknown non-exposed global type");
|
|
|
|
|
|
|
|
const char* name = js::GetObjectClass(aGlobal)->name;
|
|
|
|
|
|
|
|
if ((aNonExposedGlobals & GlobalNames::Window) &&
|
|
|
|
!strcmp(name, "Window")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((aNonExposedGlobals & GlobalNames::BackstagePass) &&
|
|
|
|
!strcmp(name, "BackstagePass")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((aNonExposedGlobals & GlobalNames::DedicatedWorkerGlobalScope) &&
|
|
|
|
!strcmp(name, "DedicatedWorkerGlobalScope")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((aNonExposedGlobals & GlobalNames::SharedWorkerGlobalScope) &&
|
|
|
|
!strcmp(name, "SharedWorkerGlobalScope")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((aNonExposedGlobals & GlobalNames::ServiceWorkerGlobalScope) &&
|
|
|
|
!strcmp(name, "ServiceWorkerGlobalScope")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((aNonExposedGlobals & GlobalNames::WorkerDebuggerGlobalScope) &&
|
|
|
|
!strcmp(name, "WorkerDebuggerGlobalScopex")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-11-06 11:54:29 +03:00
|
|
|
if ((aNonExposedGlobals & GlobalNames::WorkletGlobalScope) &&
|
|
|
|
!strcmp(name, "WorkletGlobalScope")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-12-01 20:02:36 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-04-06 03:29:40 +03:00
|
|
|
namespace binding_detail {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A ThisPolicy struct needs to provide the following methods:
|
|
|
|
*
|
|
|
|
* HasValidThisValue: Takes a CallArgs and returns a boolean indicating whether
|
|
|
|
* the thisv() is valid in the sense of being the right type
|
|
|
|
* of Value. It does not check whether it's the right sort
|
|
|
|
* of object if the Value is a JSObject*.
|
|
|
|
*
|
2018-04-06 03:29:40 +03:00
|
|
|
* ExtractThisObject: Takes a CallArgs for which HasValidThisValue was true and
|
|
|
|
* returns the JSObject* to use for getting |this|.
|
|
|
|
*
|
2018-04-06 03:29:41 +03:00
|
|
|
* MaybeUnwrapThisObject: If our |this| is a JSObject* that this policy wants to
|
|
|
|
* allow unchecked access to for this
|
|
|
|
* getter/setter/method, unwrap it. Otherwise just
|
|
|
|
* return the given object.
|
|
|
|
*
|
2018-04-06 03:29:40 +03:00
|
|
|
* HandleInvalidThis: If the |this| is not valid (wrong type of value, wrong
|
|
|
|
* object, etc), decide what to do about it. Returns a
|
|
|
|
* boolean to return from the JSNative (false for failure,
|
|
|
|
* true for succcess).
|
|
|
|
*/
|
|
|
|
struct NormalThisPolicy
|
|
|
|
{
|
|
|
|
// This needs to be inlined because it's called on no-exceptions fast-paths.
|
|
|
|
static MOZ_ALWAYS_INLINE bool HasValidThisValue(const JS::CallArgs& aArgs)
|
|
|
|
{
|
|
|
|
// Per WebIDL spec, all getters/setters/methods allow null/undefined "this"
|
|
|
|
// and coerce it to the global. Then the "is this the right interface?"
|
|
|
|
// check fails if the interface involved is not one that the global
|
|
|
|
// implements.
|
|
|
|
//
|
|
|
|
// As an optimization, we skip doing the null/undefined stuff if we know our
|
|
|
|
// interface is not implemented by the global.
|
|
|
|
return aArgs.thisv().isObject();
|
2014-02-08 00:56:14 +04:00
|
|
|
}
|
|
|
|
|
2018-04-06 03:29:40 +03:00
|
|
|
static MOZ_ALWAYS_INLINE JSObject* ExtractThisObject(const JS::CallArgs& aArgs)
|
|
|
|
{
|
|
|
|
return &aArgs.thisv().toObject();
|
|
|
|
}
|
|
|
|
|
2018-04-06 03:29:41 +03:00
|
|
|
static MOZ_ALWAYS_INLINE JSObject* MaybeUnwrapThisObject(JSObject* aObj)
|
|
|
|
{
|
|
|
|
return aObj;
|
|
|
|
}
|
|
|
|
|
2018-04-06 03:29:40 +03:00
|
|
|
static bool HandleInvalidThis(JSContext* aCx, JS::CallArgs& aArgs,
|
|
|
|
bool aSecurityError,
|
|
|
|
prototypes::ID aProtoId)
|
2014-02-08 00:56:14 +04:00
|
|
|
{
|
2018-04-06 03:29:40 +03:00
|
|
|
return ThrowInvalidThis(aCx, aArgs, aSecurityError, aProtoId);
|
2014-02-08 00:56:14 +04:00
|
|
|
}
|
2018-04-06 03:29:40 +03:00
|
|
|
};
|
2014-02-08 00:56:14 +04:00
|
|
|
|
2018-04-06 03:29:40 +03:00
|
|
|
struct MaybeGlobalThisPolicy : public NormalThisPolicy
|
|
|
|
{
|
|
|
|
static MOZ_ALWAYS_INLINE bool HasValidThisValue(const JS::CallArgs& aArgs)
|
|
|
|
{
|
|
|
|
// Here we have to allow null/undefined.
|
|
|
|
return aArgs.thisv().isObject() || aArgs.thisv().isNullOrUndefined();
|
|
|
|
}
|
|
|
|
|
|
|
|
static MOZ_ALWAYS_INLINE JSObject* ExtractThisObject(const JS::CallArgs& aArgs)
|
|
|
|
{
|
|
|
|
return aArgs.thisv().isObject() ?
|
|
|
|
&aArgs.thisv().toObject() :
|
|
|
|
js::GetGlobalForObjectCrossCompartment(&aArgs.callee());
|
|
|
|
}
|
|
|
|
|
2018-04-06 03:29:41 +03:00
|
|
|
// We want the MaybeUnwrapThisObject of NormalThisPolicy.
|
|
|
|
|
2018-04-06 03:29:40 +03:00
|
|
|
// We want the HandleInvalidThis of NormalThisPolicy.
|
|
|
|
};
|
|
|
|
|
2018-04-06 03:29:41 +03:00
|
|
|
// There are some LenientThis things on globals, so we inherit from
|
|
|
|
// MaybeGlobalThisPolicy.
|
|
|
|
struct LenientThisPolicy : public MaybeGlobalThisPolicy
|
|
|
|
{
|
|
|
|
// We want the HasValidThisValue of MaybeGlobalThisPolicy.
|
|
|
|
|
|
|
|
// We want the ExtractThisObject of MaybeGlobalThisPolicy.
|
|
|
|
|
2018-04-06 03:29:41 +03:00
|
|
|
// We want the MaybeUnwrapThisObject of MaybeGlobalThisPolicy.
|
|
|
|
|
2018-04-06 03:29:41 +03:00
|
|
|
static bool HandleInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
|
|
|
|
bool aSecurityError,
|
|
|
|
prototypes::ID aProtoId)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!JS_IsExceptionPending(aCx));
|
|
|
|
if (!ReportLenientThisUnwrappingFailure(aCx, &aArgs.callee())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
aArgs.rval().set(JS::UndefinedValue());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-04-06 03:29:41 +03:00
|
|
|
// There are some cross-origin things on globals, so we inherit from
|
|
|
|
// MaybeGlobalThisPolicy.
|
|
|
|
struct CrossOriginThisPolicy : public MaybeGlobalThisPolicy
|
|
|
|
{
|
|
|
|
// We want the HasValidThisValue of MaybeGlobalThisPolicy.
|
|
|
|
|
|
|
|
// We want the ExtractThisObject of MaybeGlobalThisPolicy.
|
|
|
|
|
|
|
|
static MOZ_ALWAYS_INLINE JSObject* MaybeUnwrapThisObject(JSObject* aObj)
|
|
|
|
{
|
|
|
|
if (xpc::WrapperFactory::IsXrayWrapper(aObj)) {
|
|
|
|
return js::UncheckedUnwrap(aObj);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Else just return aObj; our UnwrapObjectInternal call will try to
|
|
|
|
// CheckedUnwrap it, and eitehr succeed or get a security error as needed.
|
|
|
|
return aObj;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We want the HandleInvalidThis of MaybeGlobalThisPolicy.
|
|
|
|
};
|
|
|
|
|
2018-04-06 03:29:40 +03:00
|
|
|
/**
|
|
|
|
* An ExceptionPolicy struct provides a single HandleException method which is
|
|
|
|
* used to handle an exception, if any. The method is given the current
|
|
|
|
* success/failure boolean so it can decide whether there is in fact an
|
|
|
|
* exception involved.
|
|
|
|
*/
|
|
|
|
struct ThrowExceptions
|
|
|
|
{
|
|
|
|
// This needs to be inlined because it's called even on no-exceptions
|
|
|
|
// fast-paths.
|
|
|
|
static MOZ_ALWAYS_INLINE bool HandleException(JSContext* aCx,
|
|
|
|
JS::CallArgs& aArgs,
|
|
|
|
const JSJitInfo* aInfo,
|
|
|
|
bool aOK)
|
|
|
|
{
|
|
|
|
return aOK;
|
2014-05-15 21:26:23 +04:00
|
|
|
}
|
2018-04-06 03:29:40 +03:00
|
|
|
};
|
2014-02-08 00:56:14 +04:00
|
|
|
|
2018-04-06 03:29:40 +03:00
|
|
|
struct ConvertExceptionsToPromises
|
|
|
|
{
|
|
|
|
// This needs to be inlined because it's called even on no-exceptions
|
|
|
|
// fast-paths.
|
|
|
|
static MOZ_ALWAYS_INLINE bool HandleException(JSContext* aCx,
|
|
|
|
JS::CallArgs& aArgs,
|
|
|
|
const JSJitInfo* aInfo,
|
|
|
|
bool aOK)
|
|
|
|
{
|
2018-04-06 03:29:41 +03:00
|
|
|
// Promise-returning getters/methods always return objects.
|
2018-04-06 03:29:40 +03:00
|
|
|
MOZ_ASSERT(aInfo->returnType() == JSVAL_TYPE_OBJECT);
|
|
|
|
|
|
|
|
if (aOK) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ConvertExceptionToPromise(aCx, aArgs.rval());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename ThisPolicy, typename ExceptionPolicy>
|
2017-01-28 02:53:37 +03:00
|
|
|
bool
|
2018-04-06 03:29:40 +03:00
|
|
|
GenericGetter(JSContext* cx, unsigned argc, JS::Value* vp)
|
2017-01-28 02:53:37 +03:00
|
|
|
{
|
|
|
|
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
|
|
|
const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
|
|
|
|
prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
|
2018-04-06 03:29:40 +03:00
|
|
|
if (!ThisPolicy::HasValidThisValue(args)) {
|
|
|
|
bool ok = ThisPolicy::HandleInvalidThis(cx, args, false, protoID);
|
|
|
|
return ExceptionPolicy::HandleException(cx, args, info, ok);
|
2017-01-28 02:53:37 +03:00
|
|
|
}
|
2018-04-06 03:29:40 +03:00
|
|
|
JS::Rooted<JSObject*> obj(cx, ThisPolicy::ExtractThisObject(args));
|
2017-01-28 02:53:37 +03:00
|
|
|
|
2017-07-10 23:05:24 +03:00
|
|
|
// NOTE: we want to leave obj in its initial compartment, so don't want to
|
2018-04-06 03:29:41 +03:00
|
|
|
// pass it to UnwrapObjectInternal. Also, the thing we pass to
|
|
|
|
// UnwrapObjectInternal may be affected by our ThisPolicy.
|
|
|
|
JS::Rooted<JSObject*> rootSelf(cx, ThisPolicy::MaybeUnwrapThisObject(obj));
|
2017-01-28 02:53:37 +03:00
|
|
|
void* self;
|
|
|
|
{
|
2017-07-10 23:05:24 +03:00
|
|
|
binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
|
|
|
|
nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
|
|
|
|
self,
|
|
|
|
protoID,
|
|
|
|
info->depth);
|
2017-01-28 02:53:37 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
2018-04-06 03:29:40 +03:00
|
|
|
bool ok =
|
|
|
|
ThisPolicy::HandleInvalidThis(cx, args,
|
|
|
|
rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
|
|
|
|
protoID);
|
|
|
|
return ExceptionPolicy::HandleException(cx, args, info, ok);
|
2017-01-28 02:53:37 +03:00
|
|
|
}
|
|
|
|
}
|
2018-04-06 03:29:40 +03:00
|
|
|
|
2017-01-28 02:53:37 +03:00
|
|
|
MOZ_ASSERT(info->type() == JSJitInfo::Getter);
|
|
|
|
JSJitGetterOp getter = info->getter;
|
|
|
|
bool ok = getter(cx, obj, self, JSJitGetterCallArgs(args));
|
|
|
|
#ifdef DEBUG
|
2018-04-06 03:29:40 +03:00
|
|
|
if (ok) {
|
2017-01-28 02:53:37 +03:00
|
|
|
AssertReturnTypeMatchesJitinfo(info, args.rval());
|
|
|
|
}
|
2018-04-06 03:29:40 +03:00
|
|
|
#endif
|
|
|
|
return ExceptionPolicy::HandleException(cx, args, info, ok);
|
2017-01-28 02:53:37 +03:00
|
|
|
}
|
|
|
|
|
2018-04-06 03:29:40 +03:00
|
|
|
// Force instantiation of the specializations of GenericGetter we need here.
|
|
|
|
template bool
|
|
|
|
GenericGetter<NormalThisPolicy, ThrowExceptions>(
|
|
|
|
JSContext* cx, unsigned argc, JS::Value* vp);
|
|
|
|
template bool
|
|
|
|
GenericGetter<NormalThisPolicy, ConvertExceptionsToPromises>(
|
|
|
|
JSContext* cx, unsigned argc, JS::Value* vp);
|
2018-04-06 03:29:40 +03:00
|
|
|
template bool
|
|
|
|
GenericGetter<MaybeGlobalThisPolicy, ThrowExceptions>(
|
|
|
|
JSContext* cx, unsigned argc, JS::Value* vp);
|
|
|
|
template bool
|
|
|
|
GenericGetter<MaybeGlobalThisPolicy, ConvertExceptionsToPromises>(
|
|
|
|
JSContext* cx, unsigned argc, JS::Value* vp);
|
2018-04-06 03:29:41 +03:00
|
|
|
template bool
|
|
|
|
GenericGetter<LenientThisPolicy, ThrowExceptions>(
|
|
|
|
JSContext* cx, unsigned argc, JS::Value* vp);
|
|
|
|
// There aren't any [LenientThis] Promise-returning getters, so don't
|
|
|
|
// bother instantiating that specialization.
|
2018-04-06 03:29:41 +03:00
|
|
|
template bool
|
|
|
|
GenericGetter<CrossOriginThisPolicy, ThrowExceptions>(
|
|
|
|
JSContext* cx, unsigned argc, JS::Value* vp);
|
|
|
|
// There aren't any cross-origin Promise-returning getters, so don't
|
|
|
|
// bother instantiating that specialization.
|
2018-04-06 03:29:40 +03:00
|
|
|
|
2018-04-06 03:29:41 +03:00
|
|
|
template<typename ThisPolicy>
|
2014-02-08 00:56:14 +04:00
|
|
|
bool
|
2018-04-06 03:29:41 +03:00
|
|
|
GenericSetter(JSContext* cx, unsigned argc, JS::Value* vp)
|
2014-02-08 00:56:14 +04:00
|
|
|
{
|
|
|
|
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
|
|
|
const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
|
|
|
|
prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
|
2018-04-06 03:29:41 +03:00
|
|
|
if (!ThisPolicy::HasValidThisValue(args)) {
|
|
|
|
return ThisPolicy::HandleInvalidThis(cx, args, false, protoID);
|
2014-02-08 00:56:14 +04:00
|
|
|
}
|
2018-04-06 03:29:41 +03:00
|
|
|
JS::Rooted<JSObject*> obj(cx, ThisPolicy::ExtractThisObject(args));
|
2014-02-08 00:56:14 +04:00
|
|
|
|
2017-07-10 23:05:24 +03:00
|
|
|
// NOTE: we want to leave obj in its initial compartment, so don't want to
|
2018-04-06 03:29:41 +03:00
|
|
|
// pass it to UnwrapObject. Also the thing we pass to UnwrapObjectInternal
|
|
|
|
// may be affected by our ThisPolicy.
|
|
|
|
JS::Rooted<JSObject*> rootSelf(cx, ThisPolicy::MaybeUnwrapThisObject(obj));
|
2014-02-08 00:56:14 +04:00
|
|
|
void* self;
|
|
|
|
{
|
2017-07-10 23:05:24 +03:00
|
|
|
binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
|
|
|
|
nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
|
|
|
|
self,
|
|
|
|
protoID,
|
|
|
|
info->depth);
|
2014-02-08 00:56:14 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
2018-04-06 03:29:41 +03:00
|
|
|
return
|
|
|
|
ThisPolicy::HandleInvalidThis(cx, args,
|
|
|
|
rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
|
|
|
|
protoID);
|
2014-02-08 00:56:14 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (args.length() == 0) {
|
|
|
|
return ThrowNoSetterArg(cx, protoID);
|
|
|
|
}
|
|
|
|
MOZ_ASSERT(info->type() == JSJitInfo::Setter);
|
|
|
|
JSJitSetterOp setter = info->setter;
|
|
|
|
if (!setter(cx, obj, self, JSJitSetterCallArgs(args))) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-05-15 21:26:23 +04:00
|
|
|
args.rval().setUndefined();
|
|
|
|
#ifdef DEBUG
|
|
|
|
AssertReturnTypeMatchesJitinfo(info, args.rval());
|
|
|
|
#endif
|
2014-02-08 00:56:14 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-04-06 03:29:41 +03:00
|
|
|
// Force instantiation of the specializations of GenericSetter we need here.
|
|
|
|
template bool
|
|
|
|
GenericSetter<NormalThisPolicy>(JSContext* cx, unsigned argc, JS::Value* vp);
|
|
|
|
template bool
|
|
|
|
GenericSetter<MaybeGlobalThisPolicy>(JSContext* cx, unsigned argc,
|
|
|
|
JS::Value* vp);
|
|
|
|
template bool
|
|
|
|
GenericSetter<LenientThisPolicy>(JSContext* cx, unsigned argc, JS::Value* vp);
|
|
|
|
template bool
|
|
|
|
GenericSetter<CrossOriginThisPolicy>(JSContext* cx, unsigned argc,
|
|
|
|
JS::Value* vp);
|
|
|
|
|
2018-04-06 03:29:41 +03:00
|
|
|
template<typename ThisPolicy, typename ExceptionPolicy>
|
2014-02-08 00:56:14 +04:00
|
|
|
bool
|
2018-04-06 03:29:41 +03:00
|
|
|
GenericMethod(JSContext* cx, unsigned argc, JS::Value* vp)
|
2014-02-08 00:56:14 +04:00
|
|
|
{
|
|
|
|
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
|
|
|
const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
|
|
|
|
prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
|
2018-04-06 03:29:41 +03:00
|
|
|
if (!ThisPolicy::HasValidThisValue(args)) {
|
|
|
|
bool ok = ThisPolicy::HandleInvalidThis(cx, args, false, protoID);
|
|
|
|
return ExceptionPolicy::HandleException(cx, args, info, ok);
|
2014-02-08 00:56:14 +04:00
|
|
|
}
|
2018-04-06 03:29:41 +03:00
|
|
|
JS::Rooted<JSObject*> obj(cx, ThisPolicy::ExtractThisObject(args));
|
2014-02-08 00:56:14 +04:00
|
|
|
|
2017-07-10 23:05:24 +03:00
|
|
|
// NOTE: we want to leave obj in its initial compartment, so don't want to
|
2018-04-06 03:29:41 +03:00
|
|
|
// pass it to UnwrapObjectInternal. Also, the thing we pass to
|
|
|
|
// UnwrapObjectInternal may be affected by our ThisPolicy.
|
|
|
|
JS::Rooted<JSObject*> rootSelf(cx, ThisPolicy::MaybeUnwrapThisObject(obj));
|
2014-02-08 00:56:14 +04:00
|
|
|
void* self;
|
|
|
|
{
|
2017-07-10 23:05:24 +03:00
|
|
|
binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
|
|
|
|
nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
|
|
|
|
self,
|
|
|
|
protoID,
|
|
|
|
info->depth);
|
2014-02-08 00:56:14 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
2018-04-06 03:29:41 +03:00
|
|
|
bool ok =
|
|
|
|
ThisPolicy::HandleInvalidThis(cx, args,
|
|
|
|
rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
|
|
|
|
protoID);
|
|
|
|
return ExceptionPolicy::HandleException(cx, args, info, ok);
|
2014-02-08 00:56:14 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
MOZ_ASSERT(info->type() == JSJitInfo::Method);
|
|
|
|
JSJitMethodOp method = info->method;
|
2014-05-15 21:26:23 +04:00
|
|
|
bool ok = method(cx, obj, self, JSJitMethodCallArgs(args));
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (ok) {
|
|
|
|
AssertReturnTypeMatchesJitinfo(info, args.rval());
|
|
|
|
}
|
|
|
|
#endif
|
2018-04-06 03:29:41 +03:00
|
|
|
return ExceptionPolicy::HandleException(cx, args, info, ok);
|
2014-02-08 00:56:14 +04:00
|
|
|
}
|
|
|
|
|
2018-04-06 03:29:41 +03:00
|
|
|
// Force instantiation of the specializations of GenericMethod we need here.
|
|
|
|
template bool
|
|
|
|
GenericMethod<NormalThisPolicy, ThrowExceptions>(
|
|
|
|
JSContext* cx, unsigned argc, JS::Value* vp);
|
|
|
|
template bool
|
|
|
|
GenericMethod<NormalThisPolicy, ConvertExceptionsToPromises>(
|
|
|
|
JSContext* cx, unsigned argc, JS::Value* vp);
|
|
|
|
template bool
|
|
|
|
GenericMethod<MaybeGlobalThisPolicy, ThrowExceptions>(
|
|
|
|
JSContext* cx, unsigned argc, JS::Value* vp);
|
|
|
|
template bool
|
|
|
|
GenericMethod<MaybeGlobalThisPolicy, ConvertExceptionsToPromises>(
|
|
|
|
JSContext* cx, unsigned argc, JS::Value* vp);
|
|
|
|
template bool
|
|
|
|
GenericMethod<CrossOriginThisPolicy, ThrowExceptions>(
|
|
|
|
JSContext* cx, unsigned argc, JS::Value* vp);
|
|
|
|
// There aren't any cross-origin Promise-returning methods, so don't
|
|
|
|
// bother instantiating that specialization.
|
2014-03-21 20:18:24 +04:00
|
|
|
|
2018-04-06 03:29:41 +03:00
|
|
|
} // namespace binding_detail
|
2014-03-21 20:18:24 +04:00
|
|
|
|
|
|
|
bool
|
|
|
|
StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp)
|
|
|
|
{
|
|
|
|
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
|
|
|
|
|
|
|
const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
|
|
|
|
MOZ_ASSERT(info);
|
|
|
|
MOZ_ASSERT(info->type() == JSJitInfo::StaticMethod);
|
|
|
|
|
|
|
|
bool ok = info->staticMethod(cx, argc, vp);
|
|
|
|
if (ok) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-02-10 09:34:10 +03:00
|
|
|
return ConvertExceptionToPromise(cx, args.rval());
|
2014-03-21 20:18:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ConvertExceptionToPromise(JSContext* cx,
|
|
|
|
JS::MutableHandle<JS::Value> rval)
|
|
|
|
{
|
2018-02-10 09:34:10 +03:00
|
|
|
JS::Rooted<JS::Value> exn(cx);
|
|
|
|
if (!JS_GetPendingException(cx, &exn)) {
|
|
|
|
// This is very important: if there is no pending exception here but we're
|
|
|
|
// ending up in this code, that means the callee threw an uncatchable
|
|
|
|
// exception. Just propagate that out as-is.
|
|
|
|
return false;
|
|
|
|
}
|
2016-02-10 01:40:31 +03:00
|
|
|
|
2018-02-10 09:34:10 +03:00
|
|
|
JS_ClearPendingException(cx);
|
2016-02-10 01:40:31 +03:00
|
|
|
|
2018-02-10 09:34:10 +03:00
|
|
|
JSObject* promise = JS::CallOriginalPromiseReject(cx, exn);
|
|
|
|
if (!promise) {
|
|
|
|
// We just give up. Put the exception back.
|
|
|
|
JS_SetPendingException(cx, exn);
|
|
|
|
return false;
|
2016-02-10 01:40:31 +03:00
|
|
|
}
|
|
|
|
|
2018-02-10 09:34:10 +03:00
|
|
|
rval.setObject(*promise);
|
|
|
|
return true;
|
2014-03-21 20:18:24 +04:00
|
|
|
}
|
|
|
|
|
2014-04-08 22:48:37 +04:00
|
|
|
/* static */
|
|
|
|
void
|
2017-07-19 15:59:02 +03:00
|
|
|
CreateGlobalOptionsWithXPConnect::TraceGlobal(JSTracer* aTrc, JSObject* aObj)
|
2014-04-08 22:48:37 +04:00
|
|
|
{
|
2014-07-29 19:48:32 +04:00
|
|
|
xpc::TraceXPCGlobal(aTrc, aObj);
|
2014-04-08 22:48:37 +04:00
|
|
|
}
|
|
|
|
|
2017-07-19 15:59:02 +03:00
|
|
|
/* static */
|
|
|
|
bool
|
|
|
|
CreateGlobalOptionsWithXPConnect::PostCreateGlobal(JSContext* aCx,
|
|
|
|
JS::Handle<JSObject*> aGlobal)
|
|
|
|
{
|
|
|
|
// Invoking the XPCWrappedNativeScope constructor automatically hooks it
|
|
|
|
// up to the compartment of aGlobal.
|
|
|
|
(void) new XPCWrappedNativeScope(aCx, aGlobal);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-08-08 17:03:29 +04:00
|
|
|
static bool sRegisteredDOMNames = false;
|
|
|
|
|
2018-04-05 15:20:44 +03:00
|
|
|
static void
|
2014-08-08 17:03:29 +04:00
|
|
|
RegisterDOMNames()
|
|
|
|
{
|
|
|
|
if (sRegisteredDOMNames) {
|
2018-04-05 15:20:44 +03:00
|
|
|
return;
|
2014-08-08 17:03:29 +04:00
|
|
|
}
|
|
|
|
|
2016-05-09 18:08:31 +03:00
|
|
|
// Register new DOM bindings
|
|
|
|
WebIDLGlobalNameHash::Init();
|
|
|
|
|
2014-08-08 17:03:29 +04:00
|
|
|
sRegisteredDOMNames = true;
|
|
|
|
}
|
|
|
|
|
2014-04-08 22:48:37 +04:00
|
|
|
/* static */
|
|
|
|
bool
|
2017-11-07 01:52:14 +03:00
|
|
|
CreateGlobalOptions<nsGlobalWindowInner>::PostCreateGlobal(JSContext* aCx,
|
|
|
|
JS::Handle<JSObject*> aGlobal)
|
2014-04-08 22:48:37 +04:00
|
|
|
{
|
2018-04-05 15:20:44 +03:00
|
|
|
RegisterDOMNames();
|
2014-08-08 17:03:29 +04:00
|
|
|
|
2017-07-19 15:59:02 +03:00
|
|
|
return CreateGlobalOptionsWithXPConnect::PostCreateGlobal(aCx, aGlobal);
|
2014-04-08 22:48:37 +04:00
|
|
|
}
|
|
|
|
|
2014-05-15 21:26:23 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
|
|
AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitInfo,
|
|
|
|
JS::Handle<JS::Value> aValue)
|
|
|
|
{
|
|
|
|
switch (aJitInfo->returnType()) {
|
|
|
|
case JSVAL_TYPE_UNKNOWN:
|
|
|
|
// Any value is good.
|
|
|
|
break;
|
|
|
|
case JSVAL_TYPE_DOUBLE:
|
|
|
|
// The value could actually be an int32 value as well.
|
|
|
|
MOZ_ASSERT(aValue.isNumber());
|
|
|
|
break;
|
|
|
|
case JSVAL_TYPE_INT32:
|
|
|
|
MOZ_ASSERT(aValue.isInt32());
|
|
|
|
break;
|
|
|
|
case JSVAL_TYPE_UNDEFINED:
|
|
|
|
MOZ_ASSERT(aValue.isUndefined());
|
|
|
|
break;
|
|
|
|
case JSVAL_TYPE_BOOLEAN:
|
|
|
|
MOZ_ASSERT(aValue.isBoolean());
|
|
|
|
break;
|
|
|
|
case JSVAL_TYPE_STRING:
|
|
|
|
MOZ_ASSERT(aValue.isString());
|
|
|
|
break;
|
|
|
|
case JSVAL_TYPE_NULL:
|
|
|
|
MOZ_ASSERT(aValue.isNull());
|
|
|
|
break;
|
|
|
|
case JSVAL_TYPE_OBJECT:
|
|
|
|
MOZ_ASSERT(aValue.isObject());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// Someone messed up their jitinfo type.
|
|
|
|
MOZ_ASSERT(false, "Unexpected JSValueType stored in jitinfo");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-08-20 05:12:15 +04:00
|
|
|
bool
|
|
|
|
CallerSubsumes(JSObject *aObject)
|
|
|
|
{
|
|
|
|
nsIPrincipal* objPrin = nsContentUtils::ObjectPrincipal(js::UncheckedUnwrap(aObject));
|
|
|
|
return nsContentUtils::SubjectPrincipal()->Subsumes(objPrin);
|
|
|
|
}
|
|
|
|
|
2014-10-23 23:21:46 +04:00
|
|
|
nsresult
|
2017-02-01 23:43:37 +03:00
|
|
|
UnwrapArgImpl(JSContext* cx,
|
|
|
|
JS::Handle<JSObject*> src,
|
2014-10-23 23:21:46 +04:00
|
|
|
const nsIID &iid,
|
|
|
|
void **ppArg)
|
|
|
|
{
|
2016-01-30 20:05:36 +03:00
|
|
|
if (!NS_IsMainThread()) {
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
|
Bug 1371259 part 9. Make UnwrapReflectorToISupports return already_AddRefed<nsISupports>. r=peterv
The main reason to not do this would be performance (avoiding the
addref/release), but there are two main mitigating factors:
1) All calls to UnwrapReflectorToISupports that pass in a Web IDL object
already do the addref (and in fact QI). So this only affects the
XPCWrappedNative case.
2) The vast majority of the callers proceed to QI on the pointer anyway, and a
second addref is cheap; it's the first addref after a CC that can be
expensive on a cycle-collected object.
Going through the changes one by one:
* In GlobalObject::GetAsSupports, we do have a change that slightly slows down
precisely in the XPCWrappedNative global case. That's the message managers
and the backstagepass. And this really only affects calls to Web IDL statics
from those globals.
* In UnwrapArgImpl we're talking about a Web IDL method taking an "external
interface" type, and the UnwrapReflectorToISupports call is immediately
followed by QI anyway.
* In UnwrapXPConnectImpl we're talking about the case when we have a
non-WebIDL-object implementation of a Web IDL interface. Again, this is the
message manager globals, for EventTarget. And we have a QI call immediately
after the UnwrapReflectorToISupports.
* In the generated HasInstance hook for EventTarget we will be slightly slower
when the LHS of the instanceof is an XPCWrappedNative. And not much slower,
because again there's an immediate QI.
* In InstallXBLField we're never going to have an XPCWrappedNative as thisObj;
it's always an Element in practice. So this is no more expensive than before.
* In sandbox's GetPrincipalOrSOP we now have an extra addref. But it was
followed by various QIs anyway.
* In XPCConvert::JSValToXPCException we have an extra addref if someone throws
an XPCWrappedNative, which is fairly unlikely; our actual Exception objects
are on Web IDL bindings. Plus we have an immediate QI.
* In xpc::HasInstance we have an extra addred if the LHS of instanceof is an
XPCWrappedNative. But, again, there's an immediated QI after the
UnwrapReflectorToISupports.
* In xpcJSWeakReference::Init we are likely doing an extra addref, but again
immediately followed by QI.
I think it's worth making this change just to remove the footgun and that the
perf impact, if any, is pretty minimal.
2017-07-10 23:05:26 +03:00
|
|
|
nsCOMPtr<nsISupports> iface = xpc::UnwrapReflectorToISupports(src);
|
2016-01-30 20:05:36 +03:00
|
|
|
if (iface) {
|
|
|
|
if (NS_FAILED(iface->QueryInterface(iid, ppArg))) {
|
|
|
|
return NS_ERROR_XPC_BAD_CONVERT_JS;
|
2015-01-30 21:54:43 +03:00
|
|
|
}
|
|
|
|
|
2016-01-30 20:05:36 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2014-10-23 23:21:46 +04:00
|
|
|
|
2016-09-22 18:58:37 +03:00
|
|
|
// Only allow XPCWrappedJS stuff in system code. Ideally we would remove this
|
|
|
|
// even there, but that involves converting some things to WebIDL callback
|
|
|
|
// interfaces and making some other things builtinclass...
|
2017-02-01 23:43:37 +03:00
|
|
|
if (!nsContentUtils::IsSystemCaller(cx)) {
|
2016-09-22 18:58:37 +03:00
|
|
|
return NS_ERROR_XPC_BAD_CONVERT_JS;
|
|
|
|
}
|
|
|
|
|
2016-01-30 20:05:36 +03:00
|
|
|
RefPtr<nsXPCWrappedJS> wrappedJS;
|
|
|
|
nsresult rv = nsXPCWrappedJS::GetNewOrUsed(src, iid, getter_AddRefs(wrappedJS));
|
|
|
|
if (NS_FAILED(rv) || !wrappedJS) {
|
|
|
|
return rv;
|
|
|
|
}
|
2014-10-23 23:21:46 +04:00
|
|
|
|
2016-01-30 20:05:36 +03:00
|
|
|
// We need to go through the QueryInterface logic to make this return
|
|
|
|
// the right thing for the various 'special' interfaces; e.g.
|
|
|
|
// nsIPropertyBag. We must use AggregatedQueryInterface in cases where
|
|
|
|
// there is an outer to avoid nasty recursion.
|
|
|
|
return wrappedJS->QueryInterface(iid, 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,
|
2016-01-30 20:05:36 +03:00
|
|
|
nsPIDOMWindowOuter** ppArg)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsPIDOMWindowInner> inner;
|
2017-02-01 23:43:37 +03:00
|
|
|
nsresult rv = UnwrapArg<nsPIDOMWindowInner>(cx, src, getter_AddRefs(inner));
|
2016-01-30 20:05:36 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> outer = inner->GetOuterWindow();
|
|
|
|
outer.forget(ppArg);
|
|
|
|
return NS_OK;
|
2014-10-23 23:21:46 +04:00
|
|
|
}
|
|
|
|
|
2015-03-06 09:08:06 +03:00
|
|
|
bool
|
|
|
|
SystemGlobalResolve(JSContext* cx, JS::Handle<JSObject*> obj,
|
|
|
|
JS::Handle<jsid> id, bool* resolvedp)
|
|
|
|
{
|
|
|
|
if (!ResolveGlobal(cx, obj, id, resolvedp)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*resolvedp) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ResolveSystemBinding(cx, obj, id, resolvedp);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
SystemGlobalEnumerate(JSContext* cx, JS::Handle<JSObject*> obj)
|
|
|
|
{
|
|
|
|
bool ignored = false;
|
2017-06-14 11:39:11 +03:00
|
|
|
return JS_EnumerateStandardClasses(cx, obj) &&
|
2015-03-06 09:08:06 +03:00
|
|
|
ResolveSystemBinding(cx, obj, JSID_VOIDHANDLE, &ignored);
|
|
|
|
}
|
|
|
|
|
2015-05-06 09:42:27 +03:00
|
|
|
template<decltype(JS::NewMapObject) Method>
|
|
|
|
bool
|
|
|
|
GetMaplikeSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
|
|
|
size_t aSlotIndex,
|
|
|
|
JS::MutableHandle<JSObject*> aBackingObj,
|
|
|
|
bool* aBackingObjCreated)
|
|
|
|
{
|
|
|
|
JS::Rooted<JSObject*> reflector(aCx);
|
|
|
|
reflector = IsDOMObject(aObj) ? aObj : js::UncheckedUnwrap(aObj,
|
2015-11-06 21:03:52 +03:00
|
|
|
/* stopAtWindowProxy = */ false);
|
2015-05-06 09:42:27 +03:00
|
|
|
|
|
|
|
// Retrieve the backing object from the reserved slot on the maplike/setlike
|
|
|
|
// object. If it doesn't exist yet, create it.
|
|
|
|
JS::Rooted<JS::Value> slotValue(aCx);
|
|
|
|
slotValue = js::GetReservedSlot(reflector, aSlotIndex);
|
|
|
|
if (slotValue.isUndefined()) {
|
2018-05-16 11:53:16 +03:00
|
|
|
// Since backing object access can happen in non-originating realms,
|
|
|
|
// make sure to create the backing object in reflector realm.
|
2015-05-06 09:42:27 +03:00
|
|
|
{
|
2018-05-16 11:53:16 +03:00
|
|
|
JSAutoRealm ar(aCx, reflector);
|
2015-05-06 09:42:27 +03:00
|
|
|
JS::Rooted<JSObject*> newBackingObj(aCx);
|
|
|
|
newBackingObj.set(Method(aCx));
|
|
|
|
if (NS_WARN_IF(!newBackingObj)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
js::SetReservedSlot(reflector, aSlotIndex, JS::ObjectValue(*newBackingObj));
|
|
|
|
}
|
|
|
|
slotValue = js::GetReservedSlot(reflector, aSlotIndex);
|
|
|
|
*aBackingObjCreated = true;
|
|
|
|
} else {
|
|
|
|
*aBackingObjCreated = false;
|
|
|
|
}
|
|
|
|
if (!MaybeWrapNonDOMObjectValue(aCx, &slotValue)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
aBackingObj.set(&slotValue.toObject());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
GetMaplikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
|
|
|
size_t aSlotIndex,
|
|
|
|
JS::MutableHandle<JSObject*> aBackingObj,
|
|
|
|
bool* aBackingObjCreated)
|
|
|
|
{
|
|
|
|
return GetMaplikeSetlikeBackingObject<JS::NewMapObject>(aCx, aObj, aSlotIndex,
|
|
|
|
aBackingObj,
|
|
|
|
aBackingObjCreated);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
GetSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
|
|
|
size_t aSlotIndex,
|
|
|
|
JS::MutableHandle<JSObject*> aBackingObj,
|
|
|
|
bool* aBackingObjCreated)
|
|
|
|
{
|
|
|
|
return GetMaplikeSetlikeBackingObject<JS::NewSetObject>(aCx, aObj, aSlotIndex,
|
|
|
|
aBackingObj,
|
|
|
|
aBackingObjCreated);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ForEachHandler(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
|
|
|
|
{
|
|
|
|
JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
|
|
|
|
// Unpack callback and object from slots
|
|
|
|
JS::Rooted<JS::Value>
|
|
|
|
callbackFn(aCx, js::GetFunctionNativeReserved(&args.callee(),
|
|
|
|
FOREACH_CALLBACK_SLOT));
|
|
|
|
JS::Rooted<JS::Value>
|
|
|
|
maplikeOrSetlikeObj(aCx,
|
|
|
|
js::GetFunctionNativeReserved(&args.callee(),
|
|
|
|
FOREACH_MAPLIKEORSETLIKEOBJ_SLOT));
|
|
|
|
MOZ_ASSERT(aArgc == 3);
|
|
|
|
JS::AutoValueVector newArgs(aCx);
|
|
|
|
// Arguments are passed in as value, key, object. Keep value and key, replace
|
|
|
|
// object with the maplike/setlike object.
|
2016-06-01 08:49:04 +03:00
|
|
|
if (!newArgs.append(args.get(0))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!newArgs.append(args.get(1))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!newArgs.append(maplikeOrSetlikeObj)) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-05-06 09:42:27 +03:00
|
|
|
JS::Rooted<JS::Value> rval(aCx, JS::UndefinedValue());
|
|
|
|
// Now actually call the user specified callback
|
|
|
|
return JS::Call(aCx, args.thisv(), callbackFn, newArgs, &rval);
|
|
|
|
}
|
2015-07-13 18:25:42 +03:00
|
|
|
|
2015-07-31 20:30:55 +03:00
|
|
|
static inline prototypes::ID
|
|
|
|
GetProtoIdForNewtarget(JS::Handle<JSObject*> aNewTarget)
|
|
|
|
{
|
|
|
|
const js::Class* newTargetClass = js::GetObjectClass(aNewTarget);
|
|
|
|
if (IsDOMIfaceAndProtoClass(newTargetClass)) {
|
|
|
|
const DOMIfaceAndProtoJSClass* newTargetIfaceClass =
|
|
|
|
DOMIfaceAndProtoJSClass::FromJSClass(newTargetClass);
|
|
|
|
if (newTargetIfaceClass->mType == eInterface) {
|
|
|
|
return newTargetIfaceClass->mPrototypeID;
|
|
|
|
}
|
|
|
|
} else if (JS_IsNativeFunction(aNewTarget, Constructor)) {
|
|
|
|
return GetNativePropertyHooksFromConstructorFunction(aNewTarget)->mPrototypeID;
|
|
|
|
}
|
|
|
|
|
|
|
|
return prototypes::id::_ID_Count;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
|
|
|
|
JS::MutableHandle<JSObject*> aDesiredProto)
|
|
|
|
{
|
|
|
|
if (!aCallArgs.isConstructing()) {
|
|
|
|
aDesiredProto.set(nullptr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The desired prototype depends on the actual constructor that was invoked,
|
|
|
|
// which is passed to us as the newTarget in the callargs. We want to do
|
|
|
|
// something akin to the ES6 specification's GetProtototypeFromConstructor (so
|
|
|
|
// get .prototype on the newTarget, with a fallback to some sort of default).
|
|
|
|
|
|
|
|
// First, a fast path for the case when the the constructor is in fact one of
|
|
|
|
// our DOM constructors. This is safe because on those the "constructor"
|
|
|
|
// property is non-configurable and non-writable, so we don't have to do the
|
|
|
|
// slow JS_GetProperty call.
|
|
|
|
JS::Rooted<JSObject*> newTarget(aCx, &aCallArgs.newTarget().toObject());
|
|
|
|
JS::Rooted<JSObject*> originalNewTarget(aCx, newTarget);
|
|
|
|
// See whether we have a known DOM constructor here, such that we can take a
|
|
|
|
// fast path.
|
|
|
|
prototypes::ID protoID = GetProtoIdForNewtarget(newTarget);
|
|
|
|
if (protoID == prototypes::id::_ID_Count) {
|
|
|
|
// We might still have a cross-compartment wrapper for a known DOM
|
|
|
|
// constructor.
|
|
|
|
newTarget = js::CheckedUnwrap(newTarget);
|
|
|
|
if (newTarget && newTarget != originalNewTarget) {
|
|
|
|
protoID = GetProtoIdForNewtarget(newTarget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (protoID != prototypes::id::_ID_Count) {
|
|
|
|
ProtoAndIfaceCache& protoAndIfaceCache =
|
|
|
|
*GetProtoAndIfaceCache(js::GetGlobalForObjectCrossCompartment(newTarget));
|
|
|
|
aDesiredProto.set(protoAndIfaceCache.EntrySlotMustExist(protoID));
|
|
|
|
if (newTarget != originalNewTarget) {
|
|
|
|
return JS_WrapObject(aCx, aDesiredProto);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Slow path. This basically duplicates the ES6 spec's
|
|
|
|
// GetPrototypeFromConstructor except that instead of taking a string naming
|
|
|
|
// the fallback prototype we just fall back to using null and assume that our
|
|
|
|
// caller will then pick the right default. The actual defaulting behavior
|
|
|
|
// here still needs to be defined in the Web IDL specification.
|
|
|
|
//
|
|
|
|
// Note that it's very important to do this property get on originalNewTarget,
|
|
|
|
// not our unwrapped newTarget, since we want to get Xray behavior here as
|
|
|
|
// needed.
|
|
|
|
// XXXbz for speed purposes, using a preinterned id here sure would be nice.
|
|
|
|
JS::Rooted<JS::Value> protoVal(aCx);
|
|
|
|
if (!JS_GetProperty(aCx, originalNewTarget, "prototype", &protoVal)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!protoVal.isObject()) {
|
|
|
|
aDesiredProto.set(nullptr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
aDesiredProto.set(&protoVal.toObject());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-11-17 18:31:50 +03:00
|
|
|
// https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor
|
2018-03-27 22:49:02 +03:00
|
|
|
namespace binding_detail {
|
|
|
|
bool
|
|
|
|
HTMLConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
|
|
|
|
constructors::id::ID aConstructorId,
|
|
|
|
prototypes::id::ID aProtoId,
|
|
|
|
CreateInterfaceObjectsMethod aCreator)
|
|
|
|
{
|
|
|
|
JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
|
2018-03-27 22:49:02 +03:00
|
|
|
|
|
|
|
// Per spec, this is technically part of step 3, but doing the check
|
|
|
|
// directly lets us provide a better error message. And then in
|
|
|
|
// step 2 we can work with newTarget in a simpler way because we
|
|
|
|
// know it's an object.
|
2018-03-27 22:49:02 +03:00
|
|
|
if (!args.isConstructing()) {
|
|
|
|
return ThrowConstructorWithoutNew(aCx,
|
|
|
|
NamesOfInterfacesWithProtos(aProtoId));
|
|
|
|
}
|
|
|
|
|
2018-03-27 22:49:02 +03:00
|
|
|
JS::Rooted<JSObject*> callee(aCx, &args.callee());
|
|
|
|
// 'callee' is not a function here; it's either an Xray for our interface
|
|
|
|
// object or the interface object itself. So caling XrayAwareCalleeGlobal on
|
|
|
|
// it is not safe. But since in the Xray case it's a wrapper for our
|
|
|
|
// interface object, we can just construct our GlobalObject from it and end
|
|
|
|
// up with the right thing.
|
|
|
|
GlobalObject global(aCx, callee);
|
2018-03-27 22:49:02 +03:00
|
|
|
if (global.Failed()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-03-27 22:49:02 +03:00
|
|
|
// Now we start the [HTMLConstructor] algorithm steps from
|
|
|
|
// https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor
|
|
|
|
|
|
|
|
// Step 1.
|
|
|
|
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global.GetAsSupports());
|
|
|
|
if (!window) {
|
|
|
|
// This means we ended up with an HTML Element interface object defined in
|
|
|
|
// a non-Window scope. That's ... pretty unexpected.
|
|
|
|
return Throw(aCx, NS_ERROR_UNEXPECTED);
|
|
|
|
}
|
|
|
|
RefPtr<mozilla::dom::CustomElementRegistry> registry(window->CustomElements());
|
|
|
|
|
|
|
|
// Technically, per spec, a window always has a document. In Gecko, a
|
|
|
|
// sufficiently torn-down window might not, so check for that case. We're
|
|
|
|
// going to need a document to create an element.
|
|
|
|
nsIDocument* doc = window->GetExtantDoc();
|
|
|
|
if (!doc) {
|
|
|
|
return Throw(aCx, NS_ERROR_UNEXPECTED);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Step 2.
|
|
|
|
|
|
|
|
// The newTarget might be a cross-compartment wrapper. Get the underlying
|
|
|
|
// object so we can do the spec's object-identity checks. If we ever stop
|
|
|
|
// unwrapping here, carefully audit uses of newTarget below!
|
2018-03-27 22:49:02 +03:00
|
|
|
JS::Rooted<JSObject*> newTarget(aCx, js::CheckedUnwrap(&args.newTarget().toObject()));
|
|
|
|
if (!newTarget) {
|
|
|
|
return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Enter the compartment of our underlying newTarget object, so we end
|
|
|
|
// up comparing to the constructor object for our interface from that global.
|
2018-03-27 22:49:02 +03:00
|
|
|
// XXXbz This is not what the spec says to do, and it's not super-clear to me
|
|
|
|
// at this point why we're doing it. Why not just compare |newTarget| and
|
|
|
|
// |callee| if the intent is just to prevent registration of HTML interface
|
|
|
|
// objects as constructors? Of course it's not clear that the spec check
|
|
|
|
// makes sense to start with: https://github.com/whatwg/html/issues/3575
|
2018-03-27 22:49:02 +03:00
|
|
|
{
|
2018-05-16 11:53:16 +03:00
|
|
|
JSAutoRealm ar(aCx, newTarget);
|
2018-03-27 22:49:02 +03:00
|
|
|
JS::Handle<JSObject*> constructor =
|
|
|
|
GetPerInterfaceObjectHandle(aCx, aConstructorId, aCreator,
|
|
|
|
true);
|
|
|
|
if (!constructor) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (newTarget == constructor) {
|
|
|
|
return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-17 18:31:50 +03:00
|
|
|
// Step 3.
|
|
|
|
CustomElementDefinition* definition =
|
2018-03-27 22:49:02 +03:00
|
|
|
registry->LookupCustomElementDefinition(aCx, newTarget);
|
2016-11-17 18:31:50 +03:00
|
|
|
if (!definition) {
|
2018-03-27 22:49:02 +03:00
|
|
|
return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
|
2016-11-17 18:31:50 +03:00
|
|
|
}
|
|
|
|
|
2018-03-27 22:49:02 +03:00
|
|
|
// Steps 4 and 5 do some sanity checks on our callee. We add to those a
|
|
|
|
// determination of what sort of element we're planning to construct.
|
|
|
|
// Technically, this should happen (implicitly) in step 8, but this
|
|
|
|
// determination is side-effect-free, so it's OK.
|
|
|
|
int32_t ns = doc->GetDefaultNamespaceID();
|
|
|
|
if (ns != kNameSpaceID_XUL) {
|
|
|
|
ns = kNameSpaceID_XHTML;
|
2016-11-17 18:31:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int32_t tag = eHTMLTag_userdefined;
|
|
|
|
if (!definition->IsCustomBuiltIn()) {
|
|
|
|
// Step 4.
|
|
|
|
// If the definition is for an autonomous custom element, the active
|
2018-03-27 22:49:02 +03:00
|
|
|
// function should be HTMLElement or XULElement. We want to get the actual
|
2018-05-16 11:53:16 +03:00
|
|
|
// functions to compare to from our global's realm, not the caller
|
|
|
|
// realm.
|
|
|
|
JSAutoRealm ar(aCx, global.Get());
|
2018-03-27 22:49:02 +03:00
|
|
|
|
|
|
|
JS::Rooted<JSObject*> constructor(aCx);
|
2017-10-11 01:25:10 +03:00
|
|
|
if (ns == kNameSpaceID_XUL) {
|
2018-03-27 22:49:02 +03:00
|
|
|
constructor = XULElementBinding::GetConstructorObject(aCx);
|
2017-10-11 01:25:10 +03:00
|
|
|
} else {
|
2018-03-27 22:49:02 +03:00
|
|
|
constructor = HTMLElementBinding::GetConstructorObject(aCx);
|
2017-10-11 01:25:10 +03:00
|
|
|
}
|
|
|
|
|
2016-11-17 18:31:50 +03:00
|
|
|
if (!constructor) {
|
2018-03-27 22:49:02 +03:00
|
|
|
return false;
|
2016-11-17 18:31:50 +03:00
|
|
|
}
|
|
|
|
|
2018-03-27 22:49:02 +03:00
|
|
|
if (constructor != js::CheckedUnwrap(callee)) {
|
|
|
|
return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
|
2016-11-17 18:31:50 +03:00
|
|
|
}
|
|
|
|
} else {
|
2018-05-11 22:44:46 +03:00
|
|
|
constructorGetterCallback cb;
|
|
|
|
if (ns == kNameSpaceID_XHTML) {
|
|
|
|
// Step 5.
|
|
|
|
// If the definition is for a customized built-in element, the localName
|
|
|
|
// should be one of the ones defined in the specification for this interface.
|
|
|
|
tag = nsHTMLTags::CaseSensitiveAtomTagToId(definition->mLocalName);
|
|
|
|
if (tag == eHTMLTag_userdefined) {
|
|
|
|
return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
|
|
|
|
}
|
2017-10-11 01:25:10 +03:00
|
|
|
|
2018-05-11 22:44:46 +03:00
|
|
|
MOZ_ASSERT(tag <= NS_HTML_TAG_MAX, "tag is out of bounds");
|
|
|
|
|
|
|
|
// If the definition is for a customized built-in element, the active
|
|
|
|
// function should be the localname's element interface.
|
|
|
|
cb = sConstructorGetterCallback[tag];
|
|
|
|
} else { // kNameSpaceID_XUL
|
|
|
|
if (definition->mLocalName == nsGkAtoms::menupopup ||
|
|
|
|
definition->mLocalName == nsGkAtoms::popup ||
|
|
|
|
definition->mLocalName == nsGkAtoms::panel ||
|
|
|
|
definition->mLocalName == nsGkAtoms::tooltip) {
|
|
|
|
cb = XULPopupElementBinding::GetConstructorObject;
|
|
|
|
} else {
|
|
|
|
cb = XULElementBinding::GetConstructorObject;
|
|
|
|
}
|
2016-11-17 18:31:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!cb) {
|
2018-03-27 22:49:02 +03:00
|
|
|
return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
|
2016-11-17 18:31:50 +03:00
|
|
|
}
|
|
|
|
|
2018-05-16 11:53:16 +03:00
|
|
|
// We want to get the constructor from our global's realm, not the
|
|
|
|
// caller realm.
|
|
|
|
JSAutoRealm ar(aCx, global.Get());
|
2018-03-27 22:49:02 +03:00
|
|
|
JS::Rooted<JSObject*> constructor(aCx, cb(aCx));
|
2016-11-17 18:31:50 +03:00
|
|
|
if (!constructor) {
|
2018-03-27 22:49:02 +03:00
|
|
|
return false;
|
2016-11-17 18:31:50 +03:00
|
|
|
}
|
|
|
|
|
2018-03-27 22:49:02 +03:00
|
|
|
if (constructor != js::CheckedUnwrap(callee)) {
|
|
|
|
return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
|
2016-11-17 18:31:50 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-27 22:49:02 +03:00
|
|
|
// Step 6.
|
|
|
|
JS::Rooted<JSObject*> desiredProto(aCx);
|
|
|
|
if (!GetDesiredProto(aCx, args, &desiredProto)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Step 7.
|
|
|
|
if (!desiredProto) {
|
|
|
|
// This fallback behavior is designed to match analogous behavior for the
|
2018-05-16 11:53:16 +03:00
|
|
|
// JavaScript built-ins. So we enter the realm of our underlying newTarget
|
|
|
|
// object and fall back to the prototype object from that global.
|
2018-03-27 22:49:02 +03:00
|
|
|
// XXX The spec says to use GetFunctionRealm(), which is not actually
|
|
|
|
// the same thing as what we have here (e.g. in the case of scripted callable proxies
|
2018-05-16 11:53:16 +03:00
|
|
|
// whose target is not same-realm with the proxy, or bound functions, etc).
|
2018-03-27 22:49:02 +03:00
|
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1317658
|
|
|
|
{
|
2018-05-16 11:53:16 +03:00
|
|
|
JSAutoRealm ar(aCx, newTarget);
|
2018-03-27 22:49:02 +03:00
|
|
|
desiredProto = GetPerInterfaceObjectHandle(aCx, aProtoId, aCreator, true);
|
|
|
|
if (!desiredProto) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-16 11:53:16 +03:00
|
|
|
// desiredProto is in the realm of the underlying newTarget object.
|
|
|
|
// Wrap it into the context realm.
|
2018-03-27 22:49:02 +03:00
|
|
|
if (!JS_WrapObject(aCx, &desiredProto)) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-11-17 18:31:50 +03:00
|
|
|
}
|
|
|
|
|
2018-03-27 22:49:02 +03:00
|
|
|
// We need to do some work to actually return an Element, so we do step 8 on
|
|
|
|
// one branch and steps 9-12 on another branch, then common up the "return
|
|
|
|
// element" work.
|
|
|
|
RefPtr<Element> element;
|
2017-10-11 01:25:10 +03:00
|
|
|
nsTArray<RefPtr<Element>>& constructionStack =
|
2016-12-22 06:47:19 +03:00
|
|
|
definition->mConstructionStack;
|
|
|
|
if (constructionStack.IsEmpty()) {
|
2018-03-27 22:49:02 +03:00
|
|
|
// Step 8.
|
|
|
|
// Now we go to construct an element. We want to do this in global's
|
2018-05-16 11:53:16 +03:00
|
|
|
// realm, not caller realm (the normal constructor behavior),
|
2018-03-27 22:49:02 +03:00
|
|
|
// just in case those elements create JS things.
|
2018-05-16 11:53:16 +03:00
|
|
|
JSAutoRealm ar(aCx, global.Get());
|
2018-03-27 22:49:02 +03:00
|
|
|
|
|
|
|
RefPtr<NodeInfo> nodeInfo =
|
|
|
|
doc->NodeInfoManager()->GetNodeInfo(definition->mLocalName,
|
|
|
|
nullptr,
|
|
|
|
ns,
|
|
|
|
nsINode::ELEMENT_NODE);
|
|
|
|
MOZ_ASSERT(nodeInfo);
|
|
|
|
|
2017-10-11 01:25:10 +03:00
|
|
|
if (ns == kNameSpaceID_XUL) {
|
2018-04-27 18:04:37 +03:00
|
|
|
element = nsXULElement::Construct(nodeInfo.forget());
|
|
|
|
|
2016-12-22 06:47:19 +03:00
|
|
|
} else {
|
2017-10-11 01:25:10 +03:00
|
|
|
if (tag == eHTMLTag_userdefined) {
|
|
|
|
// Autonomous custom element.
|
2018-03-27 22:49:02 +03:00
|
|
|
element = NS_NewHTMLElement(nodeInfo.forget());
|
2017-10-11 01:25:10 +03:00
|
|
|
} else {
|
|
|
|
// Customized built-in element.
|
2018-03-27 22:49:02 +03:00
|
|
|
element = CreateHTMLElement(tag, nodeInfo.forget(), NOT_FROM_PARSER);
|
2017-10-11 01:25:10 +03:00
|
|
|
}
|
2016-12-22 06:47:19 +03:00
|
|
|
}
|
|
|
|
|
2018-03-27 22:49:02 +03:00
|
|
|
element->SetCustomElementData(
|
2016-12-22 06:47:19 +03:00
|
|
|
new CustomElementData(definition->mType, CustomElementData::State::eCustom));
|
|
|
|
|
2018-03-27 22:49:02 +03:00
|
|
|
element->SetCustomElementDefinition(definition);
|
|
|
|
} else {
|
|
|
|
// Step 9.
|
|
|
|
element = constructionStack.LastElement();
|
|
|
|
|
|
|
|
// Step 10.
|
|
|
|
if (element == ALREADY_CONSTRUCTED_MARKER) {
|
|
|
|
return Throw(aCx, NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Step 11.
|
|
|
|
// Do prototype swizzling for upgrading a custom element here, for cases
|
|
|
|
// when we have a reflector already. If we don't have one yet, we will
|
|
|
|
// create it with the right proto (by calling DoGetOrCreateDOMReflector with
|
|
|
|
// that proto).
|
|
|
|
JS::Rooted<JSObject*> reflector(aCx, element->GetWrapper());
|
|
|
|
if (reflector) {
|
2018-05-16 11:53:16 +03:00
|
|
|
// reflector might be in different realm.
|
|
|
|
JSAutoRealm ar(aCx, reflector);
|
2018-03-27 22:49:02 +03:00
|
|
|
JS::Rooted<JSObject*> givenProto(aCx, desiredProto);
|
|
|
|
if (!JS_WrapObject(aCx, &givenProto) ||
|
|
|
|
!JS_SetPrototype(aCx, reflector, givenProto)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2016-12-22 06:47:19 +03:00
|
|
|
|
2018-03-27 22:49:02 +03:00
|
|
|
// Step 12.
|
|
|
|
constructionStack.LastElement() = ALREADY_CONSTRUCTED_MARKER;
|
2016-12-22 06:47:19 +03:00
|
|
|
}
|
2016-12-28 06:43:29 +03:00
|
|
|
|
2018-03-27 22:49:02 +03:00
|
|
|
// Tail end of step 8 and step 13: returning the element. We want to do this
|
2018-05-16 11:53:16 +03:00
|
|
|
// part in the global's realm, though in practice it won't matter much
|
|
|
|
// because Element always knows which realm it should be created in.
|
|
|
|
JSAutoRealm ar(aCx, global.Get());
|
2018-03-27 22:49:02 +03:00
|
|
|
if (!js::IsObjectInContextCompartment(desiredProto, aCx) &&
|
|
|
|
!JS_WrapObject(aCx, &desiredProto)) {
|
|
|
|
return false;
|
2017-02-17 13:33:44 +03:00
|
|
|
}
|
|
|
|
|
2018-03-27 22:49:02 +03:00
|
|
|
return GetOrCreateDOMReflector(aCx, element, args.rval(), desiredProto);
|
2016-11-17 18:31:50 +03:00
|
|
|
}
|
2018-03-27 22:49:02 +03:00
|
|
|
} // namespace binding_detail
|
2016-11-17 18:31:50 +03:00
|
|
|
|
2015-07-31 20:30:55 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
namespace binding_detail {
|
|
|
|
void
|
|
|
|
AssertReflectorHasGivenProto(JSContext* aCx, JSObject* aReflector,
|
|
|
|
JS::Handle<JSObject*> aGivenProto)
|
|
|
|
{
|
|
|
|
if (!aGivenProto) {
|
|
|
|
// Nothing to assert here
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> reflector(aCx, aReflector);
|
2018-05-16 11:53:16 +03:00
|
|
|
JSAutoRealm ar(aCx, reflector);
|
2015-07-31 20:30:55 +03:00
|
|
|
JS::Rooted<JSObject*> reflectorProto(aCx);
|
|
|
|
bool ok = JS_GetPrototype(aCx, reflector, &reflectorProto);
|
|
|
|
MOZ_ASSERT(ok);
|
2018-05-16 11:53:16 +03:00
|
|
|
// aGivenProto may not be in the right realm here, so we
|
2015-07-31 20:30:55 +03:00
|
|
|
// have to wrap it to compare.
|
|
|
|
JS::Rooted<JSObject*> givenProto(aCx, aGivenProto);
|
|
|
|
ok = JS_WrapObject(aCx, &givenProto);
|
|
|
|
MOZ_ASSERT(ok);
|
|
|
|
MOZ_ASSERT(givenProto == reflectorProto,
|
|
|
|
"How are we supposed to change the proto now?");
|
|
|
|
}
|
|
|
|
} // namespace binding_detail
|
|
|
|
#endif // DEBUG
|
|
|
|
|
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
|
|
|
{
|
2017-11-04 01:25:38 +03:00
|
|
|
nsGlobalWindowInner* win = xpc::WindowGlobalOrNull(js::UncheckedUnwrap(aObject));
|
2015-02-05 20:53:01 +03:00
|
|
|
if (win && win->GetDocument()) {
|
|
|
|
win->GetDocument()->SetDocumentAndPageUseCounter(aUseCounter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-01 13:15:34 +03:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
// This runnable is used to write a deprecation message from a worker to the
|
|
|
|
// console running on the main-thread.
|
2016-07-04 09:19:10 +03:00
|
|
|
class DeprecationWarningRunnable final : public WorkerProxyToMainThreadRunnable
|
2016-06-01 13:15:34 +03:00
|
|
|
{
|
|
|
|
nsIDocument::DeprecatedOperations mOperation;
|
|
|
|
|
|
|
|
public:
|
|
|
|
DeprecationWarningRunnable(WorkerPrivate* aWorkerPrivate,
|
|
|
|
nsIDocument::DeprecatedOperations aOperation)
|
2016-07-04 09:19:10 +03:00
|
|
|
: WorkerProxyToMainThreadRunnable(aWorkerPrivate)
|
2016-06-01 13:15:34 +03:00
|
|
|
, mOperation(aOperation)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aWorkerPrivate);
|
2016-07-04 09:19:10 +03:00
|
|
|
aWorkerPrivate->AssertIsOnWorkerThread();
|
2016-06-01 13:15:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2016-07-04 09:19:10 +03:00
|
|
|
void
|
|
|
|
RunOnMainThread() override
|
2016-06-01 13:15:34 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
// Walk up to our containing page
|
|
|
|
WorkerPrivate* wp = mWorkerPrivate;
|
|
|
|
while (wp->GetParent()) {
|
|
|
|
wp = wp->GetParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsPIDOMWindowInner* window = wp->GetWindow();
|
|
|
|
if (window && window->GetExtantDoc()) {
|
|
|
|
window->GetExtantDoc()->WarnOnceAbout(mOperation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-06-02 12:05:27 +03:00
|
|
|
RunBackOnWorkerThreadForCleanup() override
|
2016-07-04 09:19:10 +03:00
|
|
|
{}
|
2016-06-01 13:15:34 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
2015-09-28 21:25:04 +03:00
|
|
|
void
|
|
|
|
DeprecationWarning(JSContext* aCx, JSObject* aObject,
|
|
|
|
nsIDocument::DeprecatedOperations aOperation)
|
|
|
|
{
|
|
|
|
GlobalObject global(aCx, aObject);
|
|
|
|
if (global.Failed()) {
|
|
|
|
NS_ERROR("Could not create global for DeprecationWarning");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-02-07 10:58:35 +03:00
|
|
|
DeprecationWarning(global, aOperation);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DeprecationWarning(const GlobalObject& aGlobal,
|
|
|
|
nsIDocument::DeprecatedOperations aOperation)
|
|
|
|
{
|
2016-06-01 13:15:34 +03:00
|
|
|
if (NS_IsMainThread()) {
|
2017-02-07 10:58:35 +03:00
|
|
|
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
|
2016-06-01 13:15:34 +03:00
|
|
|
if (window && window->GetExtantDoc()) {
|
|
|
|
window->GetExtantDoc()->WarnOnceAbout(aOperation);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-02-07 10:58:35 +03:00
|
|
|
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aGlobal.Context());
|
2016-06-01 13:15:34 +03:00
|
|
|
if (!workerPrivate) {
|
|
|
|
return;
|
2016-05-31 18:46:52 +03:00
|
|
|
}
|
2016-06-01 13:15:34 +03:00
|
|
|
|
|
|
|
RefPtr<DeprecationWarningRunnable> runnable =
|
|
|
|
new DeprecationWarningRunnable(workerPrivate, aOperation);
|
|
|
|
runnable->Dispatch();
|
2015-09-28 21:25:04 +03:00
|
|
|
}
|
|
|
|
|
2016-02-11 07:31:33 +03:00
|
|
|
namespace binding_detail {
|
|
|
|
JSObject*
|
|
|
|
UnprivilegedJunkScopeOrWorkerGlobal()
|
|
|
|
{
|
|
|
|
if (NS_IsMainThread()) {
|
|
|
|
return xpc::UnprivilegedJunkScope();
|
|
|
|
}
|
|
|
|
|
2016-06-01 13:15:34 +03:00
|
|
|
return GetCurrentThreadWorkerGlobal();
|
2016-02-11 07:31:33 +03:00
|
|
|
}
|
|
|
|
} // namespace binding_detail
|
|
|
|
|
2018-03-10 00:04:11 +03:00
|
|
|
JS::Handle<JSObject*>
|
|
|
|
GetPerInterfaceObjectHandle(JSContext* aCx,
|
|
|
|
size_t aSlotId,
|
|
|
|
CreateInterfaceObjectsMethod aCreator,
|
|
|
|
bool aDefineOnGlobal)
|
|
|
|
{
|
|
|
|
/* Make sure our global is sane. Hopefully we can remove this sometime */
|
|
|
|
JSObject* global = JS::CurrentGlobalOrNull(aCx);
|
|
|
|
if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check to see whether the interface objects are already installed */
|
|
|
|
ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
|
|
|
|
if (!protoAndIfaceCache.HasEntryInSlot(aSlotId)) {
|
|
|
|
JS::Rooted<JSObject*> rootedGlobal(aCx, global);
|
|
|
|
aCreator(aCx, rootedGlobal, protoAndIfaceCache, aDefineOnGlobal);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The object might _still_ be null, but that's OK.
|
|
|
|
*
|
|
|
|
* Calling fromMarkedLocation() is safe because protoAndIfaceCache is
|
|
|
|
* traced by TraceProtoAndIfaceCache() and its contents are never
|
|
|
|
* changed after they have been set.
|
|
|
|
*
|
|
|
|
* Calling address() avoids the read barrier that does gray unmarking, but
|
|
|
|
* it's not possible for the object to be gray here.
|
|
|
|
*/
|
|
|
|
|
|
|
|
const JS::Heap<JSObject*>& entrySlot =
|
|
|
|
protoAndIfaceCache.EntrySlotMustExist(aSlotId);
|
|
|
|
MOZ_ASSERT(JS::ObjectIsNotGray(entrySlot));
|
|
|
|
return JS::Handle<JSObject*>::fromMarkedLocation(entrySlot.address());
|
|
|
|
}
|
|
|
|
|
2018-05-18 06:39:52 +03:00
|
|
|
namespace binding_detail {
|
|
|
|
bool
|
|
|
|
IsGetterEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
|
|
|
JSJitGetterOp aGetter,
|
|
|
|
const Prefable<const JSPropertySpec>* aAttributes)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aAttributes);
|
|
|
|
MOZ_ASSERT(aAttributes->specs);
|
|
|
|
do {
|
|
|
|
if (aAttributes->isEnabled(aCx, aObj)) {
|
|
|
|
const JSPropertySpec* specs = aAttributes->specs;
|
|
|
|
do {
|
|
|
|
MOZ_ASSERT(specs->isAccessor());
|
|
|
|
if (specs->isSelfHosted()) {
|
|
|
|
// It won't have a JSJitGetterOp.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const JSJitInfo* info = specs->accessors.getter.native.info;
|
|
|
|
if (!info) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
MOZ_ASSERT(info->type() == JSJitInfo::OpType::Getter);
|
|
|
|
if (info->getter == aGetter) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} while ((++specs)->name);
|
|
|
|
}
|
|
|
|
} while ((++aAttributes)->specs);
|
|
|
|
|
|
|
|
// Didn't find it.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace binding_detail
|
|
|
|
|
2012-03-31 08:42:20 +04:00
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|