зеркало из https://github.com/mozilla/gecko-dev.git
merge m-c to fx-team
This commit is contained in:
Коммит
7ddfa23f22
|
@ -602,41 +602,55 @@ HyperTextAccessible::HypertextOffsetsToDOMRange(int32_t aStartHTOffset,
|
|||
}
|
||||
|
||||
int32_t
|
||||
HyperTextAccessible::GetRelativeOffset(nsIPresShell* aPresShell,
|
||||
nsIFrame* aFromFrame,
|
||||
int32_t aFromOffset,
|
||||
Accessible* aFromAccessible,
|
||||
nsSelectionAmount aAmount,
|
||||
nsDirection aDirection,
|
||||
bool aNeedsStart,
|
||||
EWordMovementType aWordMovementType)
|
||||
HyperTextAccessible::FindOffset(int32_t aOffset, nsDirection aDirection,
|
||||
nsSelectionAmount aAmount,
|
||||
EWordMovementType aWordMovementType)
|
||||
{
|
||||
const bool kIsJumpLinesOk = true; // okay to jump lines
|
||||
const bool kIsScrollViewAStop = false; // do not stop at scroll views
|
||||
const bool kIsKeyboardSelect = true; // is keyboard selection
|
||||
const bool kIsVisualBidi = false; // use visual order for bidi text
|
||||
// Convert hypertext offset to frame-relative offset.
|
||||
int32_t offsetInFrame = aOffset, notUsedOffset = aOffset;
|
||||
nsRefPtr<Accessible> accAtOffset;
|
||||
nsIFrame* frameAtOffset =
|
||||
GetPosAndText(offsetInFrame, notUsedOffset, nullptr, nullptr,
|
||||
getter_AddRefs(accAtOffset));
|
||||
if (!frameAtOffset) {
|
||||
if (aOffset == CharacterCount()) {
|
||||
// Asking for start of line, while on last character.
|
||||
if (accAtOffset)
|
||||
frameAtOffset = accAtOffset->GetFrame();
|
||||
}
|
||||
NS_ASSERTION(frameAtOffset, "No start frame for text getting!");
|
||||
if (!frameAtOffset)
|
||||
return -1;
|
||||
|
||||
// Ask layout for the new node and offset, after moving the appropriate amount
|
||||
// We're on the last continuation since we're on the last character.
|
||||
frameAtOffset = frameAtOffset->LastContinuation();
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
int32_t contentOffset = aFromOffset;
|
||||
nsIFrame *frame = aFromAccessible->GetFrame();
|
||||
NS_ENSURE_TRUE(frame, -1);
|
||||
// Return hypertext offset of the boundary of the found word.
|
||||
int32_t contentOffset = offsetInFrame;
|
||||
nsIFrame* primaryFrame = accAtOffset->GetFrame();
|
||||
NS_ENSURE_TRUE(primaryFrame, -1);
|
||||
|
||||
if (frame->GetType() == nsGkAtoms::textFrame) {
|
||||
rv = RenderedToContentOffset(frame, aFromOffset, &contentOffset);
|
||||
nsresult rv = NS_OK;
|
||||
if (primaryFrame->GetType() == nsGkAtoms::textFrame) {
|
||||
rv = RenderedToContentOffset(primaryFrame, offsetInFrame, &contentOffset);
|
||||
NS_ENSURE_SUCCESS(rv, -1);
|
||||
}
|
||||
|
||||
const bool kIsJumpLinesOk = true; // okay to jump lines
|
||||
const bool kIsScrollViewAStop = false; // do not stop at scroll views
|
||||
const bool kIsKeyboardSelect = true; // is keyboard selection
|
||||
const bool kIsVisualBidi = false; // use visual order for bidi text
|
||||
nsPeekOffsetStruct pos(aAmount, aDirection, contentOffset,
|
||||
0, kIsJumpLinesOk, kIsScrollViewAStop, kIsKeyboardSelect, kIsVisualBidi,
|
||||
0, kIsJumpLinesOk, kIsScrollViewAStop,
|
||||
kIsKeyboardSelect, kIsVisualBidi,
|
||||
aWordMovementType);
|
||||
rv = aFromFrame->PeekOffset(&pos);
|
||||
rv = frameAtOffset->PeekOffset(&pos);
|
||||
|
||||
// PeekOffset fails on last/first lines of the text in certain cases.
|
||||
if (NS_FAILED(rv) && aAmount == eSelectLine) {
|
||||
pos.mAmount = (aDirection == eDirNext) ? eSelectEndLine : eSelectBeginLine;
|
||||
aFromFrame->PeekOffset(&pos);
|
||||
frameAtOffset->PeekOffset(&pos);
|
||||
}
|
||||
if (!pos.mResultContent)
|
||||
return -1;
|
||||
|
@ -663,7 +677,8 @@ HyperTextAccessible::GetRelativeOffset(nsIPresShell* aPresShell,
|
|||
// XXX Bullet hack -- we should remove this once list bullets use anonymous content
|
||||
hyperTextOffset = 0;
|
||||
}
|
||||
if (!aNeedsStart && hyperTextOffset > 0) {
|
||||
if (aWordMovementType != eStartWord && aAmount != eSelectBeginLine &&
|
||||
hyperTextOffset > 0) {
|
||||
-- hyperTextOffset;
|
||||
}
|
||||
}
|
||||
|
@ -671,38 +686,6 @@ HyperTextAccessible::GetRelativeOffset(nsIPresShell* aPresShell,
|
|||
return hyperTextOffset;
|
||||
}
|
||||
|
||||
int32_t
|
||||
HyperTextAccessible::FindOffset(int32_t aOffset, nsDirection aDirection,
|
||||
nsSelectionAmount aAmount,
|
||||
EWordMovementType aWordMovementType)
|
||||
{
|
||||
// Convert hypertext offset to frame-relative offset.
|
||||
int32_t offsetInFrame = aOffset, notUsedOffset = aOffset;
|
||||
nsRefPtr<Accessible> accAtOffset;
|
||||
nsIFrame* frameAtOffset =
|
||||
GetPosAndText(offsetInFrame, notUsedOffset, nullptr, nullptr,
|
||||
getter_AddRefs(accAtOffset));
|
||||
if (!frameAtOffset) {
|
||||
if (aOffset == CharacterCount()) {
|
||||
// Asking for start of line, while on last character.
|
||||
if (accAtOffset)
|
||||
frameAtOffset = accAtOffset->GetFrame();
|
||||
}
|
||||
NS_ASSERTION(frameAtOffset, "No start frame for text getting!");
|
||||
if (!frameAtOffset)
|
||||
return -1;
|
||||
|
||||
// We're on the last continuation since we're on the last character.
|
||||
frameAtOffset = frameAtOffset->LastContinuation();
|
||||
}
|
||||
|
||||
// Return hypertext offset of the boundary of the found word.
|
||||
return GetRelativeOffset(mDoc->PresShell(), frameAtOffset, offsetInFrame,
|
||||
accAtOffset, aAmount, aDirection,
|
||||
(aWordMovementType == eStartWord || aAmount == eSelectBeginLine),
|
||||
aWordMovementType);
|
||||
}
|
||||
|
||||
int32_t
|
||||
HyperTextAccessible::FindLineBoundary(int32_t aOffset,
|
||||
EWhichLineBoundary aWhichLineBoundary)
|
||||
|
|
|
@ -436,26 +436,6 @@ protected:
|
|||
nsSelectionAmount aAmount,
|
||||
EWordMovementType aWordMovementType = eDefaultBehavior);
|
||||
|
||||
/**
|
||||
* Used by FindOffset() to move backward/forward from a given point
|
||||
* by word/line/etc.
|
||||
*
|
||||
* @param aPresShell the current presshell we're moving in
|
||||
* @param aFromFrame the starting frame we're moving from
|
||||
* @param aFromOffset the starting offset we're moving from
|
||||
* @param aFromAccessible the starting accessible we're moving from
|
||||
* @param aAmount how much are we moving (word/line/etc.) ?
|
||||
* @param aDirection forward or backward?
|
||||
* @param aNeedsStart for word and line cases, are we basing this on
|
||||
* the start or end?
|
||||
* @return the resulting offset into this hypertext
|
||||
*/
|
||||
int32_t GetRelativeOffset(nsIPresShell *aPresShell, nsIFrame *aFromFrame,
|
||||
int32_t aFromOffset, Accessible* aFromAccessible,
|
||||
nsSelectionAmount aAmount, nsDirection aDirection,
|
||||
bool aNeedsStart,
|
||||
EWordMovementType aWordMovementType);
|
||||
|
||||
/**
|
||||
* Provides information for substring that is defined by the given start
|
||||
* and end offsets for this hyper text.
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "States.h"
|
||||
|
||||
#include "nsContentList.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "mozilla/dom/HTMLInputElement.h"
|
||||
#include "nsIAccessibleRelation.h"
|
||||
#include "nsIDOMNSEditableElement.h"
|
||||
|
@ -26,6 +25,7 @@
|
|||
#include "nsISelectionController.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsITextControlFrame.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
@ -470,8 +470,7 @@ HTMLTextFieldAccessible::GetEditor() const
|
|||
// nsGenericHTMLElement::GetEditor has a security check.
|
||||
// Make sure we're not restricted by the permissions of
|
||||
// whatever script is currently running.
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
mozilla::dom::AutoSystemCaller asc;
|
||||
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
editableElt->GetEditor(getter_AddRefs(editor));
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#define mozilla_a11y_IUnknownImpl_h_
|
||||
|
||||
#include <windows.h>
|
||||
#undef CreateEvent // thank you windows you're such a helper
|
||||
#include "nsError.h"
|
||||
|
||||
// Avoid warning C4509 like "nonstandard extension used:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"revision": "63d432c3395f95c0ba19578487b796c1707042bd",
|
||||
"revision": "961def304c067c112f9f3c149431dba70887c5e0",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -35,8 +35,10 @@ support-files =
|
|||
[browser_styleeditor_new.js]
|
||||
[browser_styleeditor_nostyle.js]
|
||||
[browser_styleeditor_pretty.js]
|
||||
# Disabled because of intermittent failures - See Bug 942473
|
||||
skip-if = true
|
||||
[browser_styleeditor_private_perwindowpb.js]
|
||||
[browser_styleeditor_reload.js]
|
||||
[browser_styleeditor_sv_keynav.js]
|
||||
[browser_styleeditor_sv_resize.js]
|
||||
[browser_styleeditor_selectstylesheet.js]
|
||||
[browser_styleeditor_selectstylesheet.js]
|
||||
|
|
|
@ -8,14 +8,6 @@
|
|||
# libstdc++-compat is not built yet.
|
||||
MOZ_LIBSTDCXX_HOST_VERSION =
|
||||
|
||||
ifndef CROSS_COMPILE
|
||||
ifdef COMPILE_ENVIRONMENT
|
||||
ifdef USE_ELF_DYNSTR_GC
|
||||
export:: elf-dynstr-gc
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# IMPORTANT: Disable NSBUILDROOT for this directory only, otherwise we have
|
||||
# a recursive rule for finding nsinstall and the Perl scripts.
|
||||
ifdef NSBUILDROOT
|
||||
|
@ -114,13 +106,6 @@ endif
|
|||
GARBAGE += \
|
||||
$(FINAL_LINK_COMPS) $(FINAL_LINK_LIBS) $(FINAL_LINK_COMP_NAMES) buildid $(srcdir)/*.pyc *.pyc
|
||||
|
||||
ifndef CROSS_COMPILE
|
||||
ifdef USE_ELF_DYNSTR_GC
|
||||
elf-dynstr-gc: elf-dynstr-gc.c $(GLOBAL_DEPS) $(call mkdir_deps,$(MDDEPDIR))
|
||||
$(CC) $(COMPILE_CFLAGS) $(GLIB_CFLAGS) -DELFDYNSTRGC_BUILD -o $@ $< $(LDFLAGS) $(GLIB_LIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
FORCE:
|
||||
|
||||
check-preqs = \
|
||||
|
|
|
@ -631,20 +631,6 @@ DEPENDENCIES = .md
|
|||
|
||||
MOZ_COMPONENT_LIBS=$(XPCOM_LIBS) $(MOZ_COMPONENT_NSPR_LIBS)
|
||||
|
||||
ifeq ($(OS_ARCH),OS2)
|
||||
ELF_DYNSTR_GC = echo
|
||||
else
|
||||
ELF_DYNSTR_GC = :
|
||||
endif
|
||||
|
||||
ifndef CROSS_COMPILE
|
||||
ifdef USE_ELF_DYNSTR_GC
|
||||
ifdef MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS
|
||||
ELF_DYNSTR_GC = $(DEPTH)/config/elf-dynstr-gc
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef MACOSX_DEPLOYMENT_TARGET
|
||||
export MACOSX_DEPLOYMENT_TARGET
|
||||
endif # MACOSX_DEPLOYMENT_TARGET
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -23,7 +23,6 @@ ifndef NO_DIST_INSTALL
|
|||
ifdef SHARED_LIBRARY
|
||||
ifdef IS_COMPONENT
|
||||
$(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(FINAL_TARGET)/components
|
||||
$(ELF_DYNSTR_GC) $(FINAL_TARGET)/components/$(SHARED_LIBRARY)
|
||||
ifndef NO_COMPONENTS_MANIFEST
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/chrome.manifest 'manifest components/components.manifest')
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/components/components.manifest 'binary-component $(SHARED_LIBRARY)')
|
||||
|
|
19
configure.in
19
configure.in
|
@ -1999,9 +1999,6 @@ ia64*-hpux*)
|
|||
CFLAGS="$CFLAGS -mieee"
|
||||
CXXFLAGS="$CXXFLAGS -mieee"
|
||||
;;
|
||||
i*86)
|
||||
USE_ELF_DYNSTR_GC=1
|
||||
;;
|
||||
esac
|
||||
|
||||
if test -z "$MC"; then
|
||||
|
@ -4349,7 +4346,6 @@ cairo-qt)
|
|||
fi
|
||||
|
||||
MOZ_WEBGL=1
|
||||
USE_ELF_DYNSTR_GC=
|
||||
USE_FC_FREETYPE=1
|
||||
TK_CFLAGS='$(MOZ_QT_CFLAGS)'
|
||||
TK_LIBS='$(MOZ_QT_LIBS)'
|
||||
|
@ -5401,7 +5397,7 @@ if test -n "$MOZ_VP8"; then
|
|||
dnl === libvpx Version check ===
|
||||
dnl ============================
|
||||
dnl Check to see if we have a system libvpx package.
|
||||
PKG_CHECK_MODULES(MOZ_LIBVPX, vpx >= 1.0.0)
|
||||
PKG_CHECK_MODULES(MOZ_LIBVPX, vpx >= 1.3.0)
|
||||
|
||||
MOZ_CHECK_HEADER([vpx/vpx_decoder.h], [],
|
||||
[AC_MSG_ERROR([Couldn't find vpx/vpx_decoder.h which is required for build with system libvpx. Use --without-system-libvpx to build with in-tree libvpx.])])
|
||||
|
@ -6779,7 +6775,6 @@ MOZ_ARG_ENABLE_BOOL(trace-malloc,
|
|||
if test "$NS_TRACE_MALLOC"; then
|
||||
# Please, Mr. Linker Man, don't take away our symbol names
|
||||
MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS=
|
||||
USE_ELF_DYNSTR_GC=
|
||||
AC_DEFINE(NS_TRACE_MALLOC)
|
||||
fi
|
||||
AC_SUBST(NS_TRACE_MALLOC)
|
||||
|
@ -6799,7 +6794,6 @@ if test "$NS_TRACE_MALLOC" -a "$MOZ_DMD"; then
|
|||
fi
|
||||
|
||||
if test "$MOZ_DMD"; then
|
||||
USE_ELF_DYNSTR_GC=
|
||||
AC_DEFINE(MOZ_DMD)
|
||||
|
||||
if test "${CPU_ARCH}" = "arm"; then
|
||||
|
@ -7168,14 +7162,6 @@ MOZ_ARG_ENABLE_BOOL(install-strip,
|
|||
PKG_SKIP_STRIP= ,
|
||||
PKG_SKIP_STRIP=1)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = --enable-elf-dynstr-gc
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(elf-dynstr-gc,
|
||||
[ --enable-elf-dynstr-gc Enable elf dynstr garbage collector (opt builds only)],
|
||||
USE_ELF_DYNSTR_GC=1,
|
||||
USE_ELF_DYNSTR_GC= )
|
||||
|
||||
dnl ========================================================
|
||||
dnl = --disable-elf-hack
|
||||
dnl ========================================================
|
||||
|
@ -7774,7 +7760,7 @@ dnl ========================================================
|
|||
|
||||
if test -z "$SKIP_PATH_CHECKS"; then
|
||||
if test -z "${GLIB_CFLAGS}" -o -z "${GLIB_LIBS}" ; then
|
||||
if test "$MOZ_ENABLE_GTK2" -o "$USE_ELF_DYNSTR_GC" ; then
|
||||
if test "$MOZ_ENABLE_GTK2" ; then
|
||||
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 1.3.7 gobject-2.0)
|
||||
fi
|
||||
fi
|
||||
|
@ -8340,7 +8326,6 @@ AC_SUBST(MOZ_DISABLE_GECKOVIEW)
|
|||
AC_SUBST(ENABLE_STRIP)
|
||||
AC_SUBST(PKG_SKIP_STRIP)
|
||||
AC_SUBST(STRIP_FLAGS)
|
||||
AC_SUBST(USE_ELF_DYNSTR_GC)
|
||||
AC_SUBST(USE_ELF_HACK)
|
||||
AC_SUBST(INCREMENTAL_LINKER)
|
||||
AC_SUBST(MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS)
|
||||
|
|
|
@ -263,6 +263,7 @@ public:
|
|||
static bool CanSkip(nsINode* aNode, bool aRemovingAllowed);
|
||||
static bool CanSkipInCC(nsINode* aNode);
|
||||
static bool CanSkipThis(nsINode* aNode);
|
||||
static void RemoveBlackMarkedNode(nsINode* aNode);
|
||||
static void MarkNodeChildren(nsINode* aNode);
|
||||
static void InitCCCallbacks();
|
||||
static void MarkUserData(void* aObject, nsIAtom* aKey, void* aChild,
|
||||
|
|
|
@ -1545,6 +1545,7 @@ public:
|
|||
|
||||
static JSContext *GetCurrentJSContext();
|
||||
static JSContext *GetSafeJSContext();
|
||||
static JSContext *GetCurrentJSContextForThread();
|
||||
static JSContext *GetDefaultJSContextForThread();
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,9 +10,10 @@
|
|||
* utility methods for subclasses, and so forth.
|
||||
*/
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/Util.h"
|
||||
|
||||
#include "mozilla/dom/FragmentOrElement.h"
|
||||
|
||||
|
@ -1319,31 +1320,44 @@ FindOptimizableSubtreeRoot(nsINode* aNode)
|
|||
}
|
||||
aNode = p;
|
||||
}
|
||||
|
||||
|
||||
if (aNode->UnoptimizableCCNode()) {
|
||||
return nullptr;
|
||||
}
|
||||
return aNode;
|
||||
}
|
||||
|
||||
nsAutoTArray<nsINode*, 1020>* gCCBlackMarkedNodes = nullptr;
|
||||
StaticAutoPtr<nsTHashtable<nsPtrHashKey<nsINode>>> gCCBlackMarkedNodes;
|
||||
|
||||
void
|
||||
static PLDHashOperator
|
||||
VisitBlackMarkedNode(nsPtrHashKey<nsINode>* aEntry, void*)
|
||||
{
|
||||
nsINode* n = aEntry->GetKey();
|
||||
n->SetCCMarkedRoot(false);
|
||||
n->SetInCCBlackTree(false);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static void
|
||||
ClearBlackMarkedNodes()
|
||||
{
|
||||
if (!gCCBlackMarkedNodes) {
|
||||
return;
|
||||
}
|
||||
uint32_t len = gCCBlackMarkedNodes->Length();
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
nsINode* n = gCCBlackMarkedNodes->ElementAt(i);
|
||||
n->SetCCMarkedRoot(false);
|
||||
n->SetInCCBlackTree(false);
|
||||
}
|
||||
delete gCCBlackMarkedNodes;
|
||||
gCCBlackMarkedNodes->EnumerateEntries(VisitBlackMarkedNode, nullptr);
|
||||
gCCBlackMarkedNodes = nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
FragmentOrElement::RemoveBlackMarkedNode(nsINode* aNode)
|
||||
{
|
||||
if (!gCCBlackMarkedNodes) {
|
||||
return;
|
||||
}
|
||||
gCCBlackMarkedNodes->RemoveEntry(aNode);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
FragmentOrElement::CanSkipInCC(nsINode* aNode)
|
||||
|
@ -1371,14 +1385,14 @@ FragmentOrElement::CanSkipInCC(nsINode* aNode)
|
|||
if (!root) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Subtree has been traversed already.
|
||||
if (root->CCMarkedRoot()) {
|
||||
return root->InCCBlackTree() && !NeedsScriptTraverse(aNode);
|
||||
}
|
||||
|
||||
if (!gCCBlackMarkedNodes) {
|
||||
gCCBlackMarkedNodes = new nsAutoTArray<nsINode*, 1020>;
|
||||
gCCBlackMarkedNodes = new nsTHashtable<nsPtrHashKey<nsINode> >(1020);
|
||||
}
|
||||
|
||||
// nodesToUnpurple contains nodes which will be removed
|
||||
|
@ -1422,7 +1436,7 @@ FragmentOrElement::CanSkipInCC(nsINode* aNode)
|
|||
|
||||
root->SetCCMarkedRoot(true);
|
||||
root->SetInCCBlackTree(foundBlack);
|
||||
gCCBlackMarkedNodes->AppendElement(root);
|
||||
gCCBlackMarkedNodes->PutEntry(root);
|
||||
|
||||
if (!foundBlack) {
|
||||
return false;
|
||||
|
@ -1437,8 +1451,8 @@ FragmentOrElement::CanSkipInCC(nsINode* aNode)
|
|||
for (uint32_t i = 0; i < grayNodes.Length(); ++i) {
|
||||
nsINode* node = grayNodes[i];
|
||||
node->SetInCCBlackTree(true);
|
||||
gCCBlackMarkedNodes->PutEntry(node);
|
||||
}
|
||||
gCCBlackMarkedNodes->AppendElements(grayNodes);
|
||||
}
|
||||
|
||||
// Subtree is black, we can remove non-gray purple nodes from
|
||||
|
|
|
@ -5262,6 +5262,17 @@ nsContentUtils::GetDefaultJSContextForThread()
|
|||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
JSContext *
|
||||
nsContentUtils::GetCurrentJSContextForThread()
|
||||
{
|
||||
if (MOZ_LIKELY(NS_IsMainThread())) {
|
||||
return GetCurrentJSContext();
|
||||
} else {
|
||||
return workers::GetCurrentThreadJSContext();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsContentUtils::ASCIIToLower(nsAString& aStr)
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include "nsIDOMNode.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
|
@ -47,6 +46,7 @@
|
|||
|
||||
#include "mozAutoDocUpdate.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// Undefine LoadImage to prevent naming conflict with Windows.
|
||||
|
@ -1194,12 +1194,6 @@ nsImageLoadingContent::ClearPendingRequest(nsresult aReason,
|
|||
if (!mPendingRequest)
|
||||
return;
|
||||
|
||||
// Push a null JSContext on the stack so that code that runs within
|
||||
// the below code doesn't think it's being called by JS. See bug
|
||||
// 604262.
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
|
||||
// Deregister this image from the refresh driver so it no longer receives
|
||||
// notifications.
|
||||
nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mPendingRequest,
|
||||
|
@ -1259,11 +1253,6 @@ nsImageLoadingContent::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
if (!aDocument)
|
||||
return;
|
||||
|
||||
// Push a null JSContext on the stack so that callbacks triggered by the
|
||||
// below code won't think they're being called from JS.
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
|
||||
TrackImage(mCurrentRequest);
|
||||
TrackImage(mPendingRequest);
|
||||
|
||||
|
@ -1279,11 +1268,6 @@ nsImageLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
|
|||
if (!doc)
|
||||
return;
|
||||
|
||||
// Push a null JSContext on the stack so that callbacks triggered by the
|
||||
// below code won't think they're being called from JS.
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
|
||||
UntrackImage(mCurrentRequest);
|
||||
UntrackImage(mPendingRequest);
|
||||
|
||||
|
|
|
@ -253,7 +253,7 @@ nsNodeUtils::LastRelease(nsINode* aNode)
|
|||
nsIDocument* ownerDoc = aNode->OwnerDoc();
|
||||
Element* elem = aNode->AsElement();
|
||||
ownerDoc->ClearBoxObjectFor(elem);
|
||||
|
||||
|
||||
NS_ASSERTION(aNode->HasFlag(NODE_FORCE_XBL_BINDINGS) ||
|
||||
!elem->GetXBLBinding(),
|
||||
"Non-forced node has binding on destruction");
|
||||
|
@ -267,6 +267,8 @@ nsNodeUtils::LastRelease(nsINode* aNode)
|
|||
}
|
||||
|
||||
aNode->ReleaseWrapper(aNode);
|
||||
|
||||
FragmentOrElement::RemoveBlackMarkedNode(aNode);
|
||||
}
|
||||
|
||||
struct MOZ_STACK_CLASS nsHandlerData
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "nsIDocument.h"
|
||||
#include "prprf.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "ScriptSettings.h"
|
||||
#include "mozilla/Likely.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -274,7 +275,7 @@ nsDOMEventTargetHelper::SetEventHandler(nsIAtom* aType,
|
|||
JSObject* callable;
|
||||
if (aValue.isObject() &&
|
||||
JS_ObjectIsCallable(aCx, callable = &aValue.toObject())) {
|
||||
handler = new EventHandlerNonNull(callable);
|
||||
handler = new EventHandlerNonNull(callable, mozilla::dom::GetIncumbentGlobal());
|
||||
}
|
||||
SetEventHandler(aType, EmptyString(), handler);
|
||||
return NS_OK;
|
||||
|
|
|
@ -883,19 +883,23 @@ nsEventListenerManager::CompileEventHandlerInternal(nsListenerStruct *aListenerS
|
|||
JS::Rooted<JSObject*> scope(cx, listener->GetEventScope());
|
||||
context->BindCompiledEventHandler(mTarget, scope, handler, &boundHandler);
|
||||
aListenerStruct = nullptr;
|
||||
// Note - We pass null for aIncumbentGlobal below. We could also pass the
|
||||
// compilation global, but since the handler is guaranteed to be scripted,
|
||||
// there's no need to use an override, since the JS engine will always give
|
||||
// us the right answer.
|
||||
if (!boundHandler) {
|
||||
listener->ForgetHandler();
|
||||
} else if (listener->EventName() == nsGkAtoms::onerror && win) {
|
||||
nsRefPtr<OnErrorEventHandlerNonNull> handlerCallback =
|
||||
new OnErrorEventHandlerNonNull(boundHandler);
|
||||
new OnErrorEventHandlerNonNull(boundHandler, /* aIncumbentGlobal = */ nullptr);
|
||||
listener->SetHandler(handlerCallback);
|
||||
} else if (listener->EventName() == nsGkAtoms::onbeforeunload && win) {
|
||||
nsRefPtr<OnBeforeUnloadEventHandlerNonNull> handlerCallback =
|
||||
new OnBeforeUnloadEventHandlerNonNull(boundHandler);
|
||||
new OnBeforeUnloadEventHandlerNonNull(boundHandler, /* aIncumbentGlobal = */ nullptr);
|
||||
listener->SetHandler(handlerCallback);
|
||||
} else {
|
||||
nsRefPtr<EventHandlerNonNull> handlerCallback =
|
||||
new EventHandlerNonNull(boundHandler);
|
||||
new EventHandlerNonNull(boundHandler, /* aIncumbentGlobal = */ nullptr);
|
||||
listener->SetHandler(handlerCallback);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,11 +38,11 @@
|
|||
#include "mozilla/Selection.h"
|
||||
#include "nsEventListenerManager.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsTextNode.h"
|
||||
#include "nsIController.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -1283,13 +1283,12 @@ nsTextEditorState::PrepareEditor(const nsAString *aValue)
|
|||
|
||||
// What follows is a bit of a hack. The editor uses the public DOM APIs
|
||||
// for its content manipulations, and it causes it to fail some security
|
||||
// checks deep inside when initializing. So we push a null JSContext
|
||||
// on the JS stack here to make it clear that we're native code.
|
||||
// checks deep inside when initializing. So we explictly make it clear that
|
||||
// we're native code.
|
||||
// Note that any script that's directly trying to access our value
|
||||
// has to be going through some scriptable object to do that and that
|
||||
// already does the relevant security checks.
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
AutoSystemCaller asc;
|
||||
|
||||
rv = newEditor->Init(domdoc, GetRootNode(), mSelCon, editorFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -1777,9 +1776,8 @@ nsTextEditorState::GetValue(nsAString& aValue, bool aIgnoreWrap) const
|
|||
// XXXbz if we could just get the textContent of our anonymous content (eg
|
||||
// if plaintext editor didn't create <br> nodes all over), we wouldn't need
|
||||
// this.
|
||||
{ /* Scope for context pusher */
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
{ /* Scope for AutoSystemCaller. */
|
||||
AutoSystemCaller asc;
|
||||
|
||||
mEditor->OutputToString(NS_LITERAL_STRING("text/plain"), flags,
|
||||
aValue);
|
||||
|
@ -1857,9 +1855,8 @@ nsTextEditorState::SetValue(const nsAString& aValue, bool aUserInput,
|
|||
// Time to mess with our security context... See comments in GetValue()
|
||||
// for why this is needed. Note that we have to do this up here, because
|
||||
// otherwise SelectAll() will fail.
|
||||
{ /* Scope for context pusher */
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
{
|
||||
AutoSystemCaller asc;
|
||||
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
nsCOMPtr<nsISelectionPrivate> selPriv;
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#if defined(ANDROID) || defined(LINUX) || defined(XP_MACOSX)
|
||||
#include <sys/time.h>
|
||||
|
@ -323,10 +322,6 @@ LoadMonitor::GetSystemLoad() {
|
|||
nsresult
|
||||
LoadMonitor::Init(nsRefPtr<LoadMonitor> &self)
|
||||
{
|
||||
if (!Preferences::GetBool("media.navigator.load_adapt", false)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
if (!gLoadMonitorLog)
|
||||
gLoadMonitorLog = PR_NewLogModule("LoadMonitor");
|
||||
|
|
|
@ -45,6 +45,7 @@ public:
|
|||
static const int DEFAULT_VIDEO_WIDTH = 640;
|
||||
static const int DEFAULT_VIDEO_HEIGHT = 480;
|
||||
static const int DEFAULT_AUDIO_TIMER_MS = 10;
|
||||
static const bool DEFAULT_LOAD_ADAPT = false;
|
||||
|
||||
/* Populate an array of video sources in the nsTArray. Also include devices
|
||||
* that are currently unavailable. */
|
||||
|
@ -130,6 +131,7 @@ struct MediaEnginePrefs {
|
|||
int32_t mHeight;
|
||||
int32_t mFPS;
|
||||
int32_t mMinFPS;
|
||||
bool mLoadAdapt;
|
||||
};
|
||||
|
||||
class MediaEngineVideoSource : public MediaEngineSource
|
||||
|
|
|
@ -43,7 +43,7 @@ GetUserMediaLog()
|
|||
|
||||
namespace mozilla {
|
||||
#ifndef MOZ_B2G_CAMERA
|
||||
MediaEngineWebRTC::MediaEngineWebRTC()
|
||||
MediaEngineWebRTC::MediaEngineWebRTC(MediaEnginePrefs &aPrefs)
|
||||
: mMutex("mozilla::MediaEngineWebRTC")
|
||||
, mVideoEngine(nullptr)
|
||||
, mVoiceEngine(nullptr)
|
||||
|
@ -56,8 +56,10 @@ MediaEngineWebRTC::MediaEngineWebRTC()
|
|||
if (compMgr) {
|
||||
compMgr->IsContractIDRegistered(NS_TABSOURCESERVICE_CONTRACTID, &mHasTabVideoSource);
|
||||
}
|
||||
mLoadMonitor = new LoadMonitor();
|
||||
mLoadMonitor->Init(mLoadMonitor);
|
||||
if (aPrefs.mLoadAdapt) {
|
||||
mLoadMonitor = new LoadMonitor();
|
||||
mLoadMonitor->Init(mLoadMonitor);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -359,7 +361,8 @@ MediaEngineWebRTC::Shutdown()
|
|||
mVideoEngine = nullptr;
|
||||
mVoiceEngine = nullptr;
|
||||
|
||||
mLoadMonitor->Shutdown();
|
||||
if (mLoadMonitor)
|
||||
mLoadMonitor->Shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -367,7 +367,7 @@ public:
|
|||
mLoadMonitor->Init(mLoadMonitor);
|
||||
}
|
||||
#else
|
||||
MediaEngineWebRTC();
|
||||
MediaEngineWebRTC(MediaEnginePrefs &aPrefs);
|
||||
#endif
|
||||
~MediaEngineWebRTC() {
|
||||
Shutdown();
|
||||
|
|
|
@ -322,7 +322,7 @@ nsXBLPrototypeHandler::ExecuteHandler(EventTarget* aTarget,
|
|||
}
|
||||
|
||||
nsRefPtr<EventHandlerNonNull> handlerCallback =
|
||||
new EventHandlerNonNull(bound);
|
||||
new EventHandlerNonNull(bound, /* aIncumbentGlobal = */ nullptr);
|
||||
|
||||
nsEventHandler eventHandler(handlerCallback);
|
||||
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// vim: ft=cpp tw=78 sw=2 et ts=2
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/ThreadLocal.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ScriptSettingsStack;
|
||||
static mozilla::ThreadLocal<ScriptSettingsStack*> sScriptSettingsTLS;
|
||||
|
||||
ScriptSettingsStackEntry ScriptSettingsStackEntry::SystemSingleton;
|
||||
|
||||
class ScriptSettingsStack {
|
||||
public:
|
||||
static ScriptSettingsStack& Ref() {
|
||||
return *sScriptSettingsTLS.get();
|
||||
}
|
||||
ScriptSettingsStack() {};
|
||||
|
||||
void Push(ScriptSettingsStackEntry* aSettings) {
|
||||
// The bottom-most entry must always be a candidate entry point.
|
||||
MOZ_ASSERT_IF(mStack.Length() == 0 || mStack.LastElement()->IsSystemSingleton(),
|
||||
aSettings->mIsCandidateEntryPoint);
|
||||
mStack.AppendElement(aSettings);
|
||||
}
|
||||
|
||||
void PushSystem() {
|
||||
mStack.AppendElement(&ScriptSettingsStackEntry::SystemSingleton);
|
||||
}
|
||||
|
||||
void Pop() {
|
||||
MOZ_ASSERT(mStack.Length() > 0);
|
||||
mStack.RemoveElementAt(mStack.Length() - 1);
|
||||
}
|
||||
|
||||
nsIGlobalObject* Incumbent() {
|
||||
if (!mStack.Length()) {
|
||||
return nullptr;
|
||||
}
|
||||
return mStack.LastElement()->mGlobalObject;
|
||||
}
|
||||
|
||||
nsIGlobalObject* EntryPoint() {
|
||||
if (!mStack.Length())
|
||||
return nullptr;
|
||||
for (int i = mStack.Length() - 1; i >= 0; --i) {
|
||||
if (mStack[i]->mIsCandidateEntryPoint) {
|
||||
return mStack[i]->mGlobalObject;
|
||||
}
|
||||
}
|
||||
MOZ_ASSUME_UNREACHABLE("Non-empty stack should always have an entry point");
|
||||
}
|
||||
|
||||
private:
|
||||
// These pointers are caller-owned.
|
||||
nsTArray<ScriptSettingsStackEntry*> mStack;
|
||||
};
|
||||
|
||||
void
|
||||
InitScriptSettings()
|
||||
{
|
||||
if (!sScriptSettingsTLS.initialized()) {
|
||||
bool success = sScriptSettingsTLS.init();
|
||||
if (!success) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
ScriptSettingsStack* ptr = new ScriptSettingsStack();
|
||||
sScriptSettingsTLS.set(ptr);
|
||||
}
|
||||
|
||||
void DestroyScriptSettings()
|
||||
{
|
||||
ScriptSettingsStack* ptr = sScriptSettingsTLS.get();
|
||||
MOZ_ASSERT(ptr);
|
||||
sScriptSettingsTLS.set(nullptr);
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
// Note: When we're ready to expose it, GetEntryGlobal will look similar to
|
||||
// GetIncumbentGlobal below.
|
||||
|
||||
nsIGlobalObject*
|
||||
GetIncumbentGlobal()
|
||||
{
|
||||
// We need the current JSContext in order to check the JS for
|
||||
// scripted frames that may have appeared since anyone last
|
||||
// manipulated the stack. If it's null, that means that there
|
||||
// must be no entry point on the stack, and therefore no incumbent
|
||||
// global either.
|
||||
JSContext *cx = nsContentUtils::GetCurrentJSContextForThread();
|
||||
if (!cx) {
|
||||
MOZ_ASSERT(ScriptSettingsStack::Ref().EntryPoint() == nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// See what the JS engine has to say. If we've got a scripted caller
|
||||
// override in place, the JS engine will lie to us and pretend that
|
||||
// there's nothing on the JS stack, which will cause us to check the
|
||||
// incumbent script stack below.
|
||||
JS::RootedScript script(cx);
|
||||
if (JS_DescribeScriptedCaller(cx, &script, nullptr)) {
|
||||
JS::RootedObject global(cx, JS_GetGlobalFromScript(script));
|
||||
MOZ_ASSERT(global);
|
||||
return xpc::GetNativeForGlobal(global);
|
||||
}
|
||||
|
||||
// Ok, nothing from the JS engine. Let's use whatever's on the
|
||||
// explicit stack.
|
||||
return ScriptSettingsStack::Ref().Incumbent();
|
||||
}
|
||||
|
||||
AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
bool aIsMainThread,
|
||||
JSContext* aCx)
|
||||
: mStack(ScriptSettingsStack::Ref())
|
||||
, mEntry(aGlobalObject, /* aCandidate = */ true)
|
||||
{
|
||||
MOZ_ASSERT(aGlobalObject);
|
||||
if (!aCx) {
|
||||
// If the caller didn't provide a cx, hunt one down. This isn't exactly
|
||||
// fast, but the callers that care about performance can pass an explicit
|
||||
// cx for now. Eventually, the whole cx pushing thing will go away
|
||||
// entirely.
|
||||
MOZ_ASSERT(aIsMainThread, "cx is mandatory off-main-thread");
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aGlobalObject);
|
||||
if (sgo && sgo->GetScriptContext()) {
|
||||
aCx = sgo->GetScriptContext()->GetNativeContext();
|
||||
}
|
||||
if (!aCx) {
|
||||
aCx = nsContentUtils::GetSafeJSContext();
|
||||
}
|
||||
}
|
||||
if (aIsMainThread) {
|
||||
mCxPusher.Push(aCx);
|
||||
}
|
||||
mAc.construct(aCx, aGlobalObject->GetGlobalJSObject());
|
||||
mStack.Push(&mEntry);
|
||||
}
|
||||
|
||||
AutoEntryScript::~AutoEntryScript()
|
||||
{
|
||||
MOZ_ASSERT(mStack.Incumbent() == mEntry.mGlobalObject);
|
||||
mStack.Pop();
|
||||
}
|
||||
|
||||
AutoIncumbentScript::AutoIncumbentScript(nsIGlobalObject* aGlobalObject)
|
||||
: mStack(ScriptSettingsStack::Ref())
|
||||
, mEntry(aGlobalObject, /* aCandidate = */ false)
|
||||
, mCallerOverride(nsContentUtils::GetCurrentJSContextForThread())
|
||||
{
|
||||
mStack.Push(&mEntry);
|
||||
}
|
||||
|
||||
AutoIncumbentScript::~AutoIncumbentScript()
|
||||
{
|
||||
MOZ_ASSERT(mStack.Incumbent() == mEntry.mGlobalObject);
|
||||
mStack.Pop();
|
||||
}
|
||||
|
||||
AutoSystemCaller::AutoSystemCaller(bool aIsMainThread)
|
||||
: mStack(ScriptSettingsStack::Ref())
|
||||
{
|
||||
if (aIsMainThread) {
|
||||
mCxPusher.PushNull();
|
||||
}
|
||||
mStack.PushSystem();
|
||||
}
|
||||
|
||||
AutoSystemCaller::~AutoSystemCaller()
|
||||
{
|
||||
mStack.Pop();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,115 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// vim: ft=cpp tw=78 sw=2 et ts=2
|
||||
/* 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/. */
|
||||
|
||||
/* Utilities for managing the script settings object stack defined in webapps */
|
||||
|
||||
#ifndef mozilla_dom_ScriptSettings_h
|
||||
#define mozilla_dom_ScriptSettings_h
|
||||
|
||||
#include "nsCxPusher.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/*
|
||||
* System-wide setup/teardown routines. Init and Destroy should be invoked
|
||||
* once each, at startup and shutdown (respectively).
|
||||
*/
|
||||
void InitScriptSettings();
|
||||
void DestroyScriptSettings();
|
||||
|
||||
// Note: We don't yet expose GetEntryGlobal, because in order for it to be
|
||||
// correct, we first need to replace a bunch of explicit cx pushing in the
|
||||
// browser with AutoEntryScript. But GetIncumbentGlobal is simpler, because it
|
||||
// can mostly be inferred from the JS stack.
|
||||
nsIGlobalObject* GetIncumbentGlobal();
|
||||
|
||||
class ScriptSettingsStack;
|
||||
struct ScriptSettingsStackEntry {
|
||||
nsCOMPtr<nsIGlobalObject> mGlobalObject;
|
||||
bool mIsCandidateEntryPoint;
|
||||
|
||||
ScriptSettingsStackEntry(nsIGlobalObject *aGlobal, bool aCandidate)
|
||||
: mGlobalObject(aGlobal)
|
||||
, mIsCandidateEntryPoint(aCandidate)
|
||||
{
|
||||
MOZ_ASSERT(mGlobalObject);
|
||||
MOZ_ASSERT(mGlobalObject->GetGlobalJSObject(),
|
||||
"Must have an actual JS global for the duration on the stack");
|
||||
MOZ_ASSERT(JS_IsGlobalObject(mGlobalObject->GetGlobalJSObject()),
|
||||
"No outer windows allowed");
|
||||
}
|
||||
|
||||
~ScriptSettingsStackEntry() {
|
||||
// We must have an actual JS global for the entire time this is on the stack.
|
||||
MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->GetGlobalJSObject());
|
||||
}
|
||||
|
||||
bool IsSystemSingleton() { return this == &SystemSingleton; }
|
||||
static ScriptSettingsStackEntry SystemSingleton;
|
||||
|
||||
private:
|
||||
ScriptSettingsStackEntry() : mGlobalObject(nullptr)
|
||||
, mIsCandidateEntryPoint(true)
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* A class that represents a new script entry point.
|
||||
*/
|
||||
class AutoEntryScript {
|
||||
public:
|
||||
AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
bool aIsMainThread = NS_IsMainThread(),
|
||||
// Note: aCx is mandatory off-main-thread.
|
||||
JSContext* aCx = nullptr);
|
||||
~AutoEntryScript();
|
||||
|
||||
private:
|
||||
dom::ScriptSettingsStack& mStack;
|
||||
dom::ScriptSettingsStackEntry mEntry;
|
||||
nsCxPusher mCxPusher;
|
||||
mozilla::Maybe<JSAutoCompartment> mAc; // This can de-Maybe-fy when mCxPusher
|
||||
// goes away.
|
||||
};
|
||||
|
||||
/*
|
||||
* A class that can be used to force a particular incumbent script on the stack.
|
||||
*/
|
||||
class AutoIncumbentScript {
|
||||
public:
|
||||
AutoIncumbentScript(nsIGlobalObject* aGlobalObject);
|
||||
~AutoIncumbentScript();
|
||||
private:
|
||||
dom::ScriptSettingsStack& mStack;
|
||||
dom::ScriptSettingsStackEntry mEntry;
|
||||
JS::AutoHideScriptedCaller mCallerOverride;
|
||||
};
|
||||
|
||||
/*
|
||||
* A class used for C++ to indicate that existing entry and incumbent scripts
|
||||
* should not apply to anything in scope, and that callees should act as if
|
||||
* they were invoked "from C++".
|
||||
*/
|
||||
class AutoSystemCaller {
|
||||
public:
|
||||
AutoSystemCaller(bool aIsMainThread = NS_IsMainThread());
|
||||
~AutoSystemCaller();
|
||||
private:
|
||||
dom::ScriptSettingsStack& mStack;
|
||||
nsCxPusher mCxPusher;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_ScriptSettings_h
|
|
@ -59,6 +59,7 @@ EXPORTS.mozilla.dom += [
|
|||
'MessagePortList.h',
|
||||
'Navigator.h',
|
||||
'ScreenOrientation.h',
|
||||
'ScriptSettings.h',
|
||||
'StructuredCloneTags.h',
|
||||
'URL.h',
|
||||
]
|
||||
|
@ -94,6 +95,7 @@ UNIFIED_SOURCES += [
|
|||
'nsWindowMemoryReporter.cpp',
|
||||
'nsWindowRoot.cpp',
|
||||
'nsWrapperCache.cpp',
|
||||
'ScriptSettings.cpp',
|
||||
'URL.cpp',
|
||||
'WindowNamedPropertiesHandler.cpp',
|
||||
]
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "nsReadableUtils.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsJSEnvironment.h"
|
||||
#include "ScriptSettings.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Likely.h"
|
||||
|
||||
|
@ -211,6 +212,7 @@
|
|||
#include "nsITabChild.h"
|
||||
#include "nsIDOMMediaQueryList.h"
|
||||
#include "mozilla/dom/DOMJSClass.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
#include "mozilla/dom/SpeechSynthesis.h"
|
||||
|
@ -4938,7 +4940,7 @@ nsGlobalWindow::RequestAnimationFrame(const JS::Value& aCallback,
|
|||
}
|
||||
|
||||
nsRefPtr<FrameRequestCallback> callback =
|
||||
new FrameRequestCallback(&aCallback.toObject());
|
||||
new FrameRequestCallback(&aCallback.toObject(), GetIncumbentGlobal());
|
||||
|
||||
ErrorResult rv;
|
||||
*aHandle = RequestAnimationFrame(*callback, rv);
|
||||
|
@ -11202,18 +11204,18 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
|
|||
aDialog, aNavigate, argv,
|
||||
getter_AddRefs(domReturn));
|
||||
} else {
|
||||
// Push a null JSContext here so that the window watcher won't screw us
|
||||
// Force a system caller here so that the window watcher won't screw us
|
||||
// up. We do NOT want this case looking at the JS context on the stack
|
||||
// when searching. Compare comments on
|
||||
// nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
|
||||
|
||||
// Note: Because nsWindowWatcher is so broken, it's actually important
|
||||
// that we don't push a null cx here, because that screws it up when it
|
||||
// tries to compute the caller principal to associate with dialog
|
||||
// that we don't force a system caller here, because that screws it up
|
||||
// when it tries to compute the caller principal to associate with dialog
|
||||
// arguments. That whole setup just really needs to be rewritten. :-(
|
||||
nsCxPusher pusher;
|
||||
Maybe<AutoSystemCaller> asc;
|
||||
if (!aContentModal) {
|
||||
pusher.PushNull();
|
||||
asc.construct();
|
||||
}
|
||||
|
||||
|
||||
|
@ -13225,7 +13227,7 @@ nsGlobalWindow::DisableNetworkEvent(uint32_t aType)
|
|||
JSObject *callable; \
|
||||
if (v.isObject() && \
|
||||
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
|
||||
handler = new EventHandlerNonNull(callable); \
|
||||
handler = new EventHandlerNonNull(callable, GetIncumbentGlobal()); \
|
||||
} \
|
||||
SetOn##name_(handler); \
|
||||
return NS_OK; \
|
||||
|
@ -13255,7 +13257,7 @@ nsGlobalWindow::DisableNetworkEvent(uint32_t aType)
|
|||
JSObject *callable; \
|
||||
if (v.isObject() && \
|
||||
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
|
||||
handler = new OnErrorEventHandlerNonNull(callable); \
|
||||
handler = new OnErrorEventHandlerNonNull(callable, GetIncumbentGlobal()); \
|
||||
} \
|
||||
elm->SetEventHandler(handler); \
|
||||
return NS_OK; \
|
||||
|
@ -13286,7 +13288,7 @@ nsGlobalWindow::DisableNetworkEvent(uint32_t aType)
|
|||
JSObject *callable; \
|
||||
if (v.isObject() && \
|
||||
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
|
||||
handler = new OnBeforeUnloadEventHandlerNonNull(callable); \
|
||||
handler = new OnBeforeUnloadEventHandlerNonNull(callable, GetIncumbentGlobal()); \
|
||||
} \
|
||||
elm->SetEventHandler(handler); \
|
||||
return NS_OK; \
|
||||
|
|
|
@ -360,7 +360,7 @@ nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, bool *aIsInterval,
|
|||
|
||||
mozilla::HoldJSObjects(this);
|
||||
|
||||
mFunction = new Function(funobj);
|
||||
mFunction = new Function(funobj, GetIncumbentGlobal());
|
||||
|
||||
// Create our arg array. argc is the number of arguments passed
|
||||
// to setTimeout or setInterval; the first two are our callback
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "nsPrintfCString.h"
|
||||
#include "prprf.h"
|
||||
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/DOMError.h"
|
||||
#include "mozilla/dom/DOMErrorBinding.h"
|
||||
#include "mozilla/dom/HTMLObjectElement.h"
|
||||
|
@ -2015,12 +2016,12 @@ ConstructJSImplementation(JSContext* aCx, const char* aContractId,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Make sure to have nothing on the JS context stack while creating and
|
||||
// Make sure to divorce ourselves from the calling JS while creating and
|
||||
// initializing the object, so exceptions from that will get reported
|
||||
// properly, since those are never exceptions that a spec wants to be thrown.
|
||||
{ // Scope for the nsCxPusher
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
{
|
||||
AutoSystemCaller asc;
|
||||
|
||||
// Get the XPCOM component containing the JS implementation.
|
||||
nsCOMPtr<nsISupports> implISupports = do_CreateInstance(aContractId);
|
||||
if (!implISupports) {
|
||||
|
|
|
@ -25,8 +25,9 @@ namespace dom {
|
|||
class CallbackFunction : public CallbackObject
|
||||
{
|
||||
public:
|
||||
explicit CallbackFunction(JSObject* aCallable)
|
||||
: CallbackObject(aCallable)
|
||||
explicit CallbackFunction(JSObject* aCallable,
|
||||
nsIGlobalObject* aIncumbentGlobal)
|
||||
: CallbackObject(aCallable, aIncumbentGlobal)
|
||||
{
|
||||
MOZ_ASSERT(JS_ObjectIsCallable(nullptr, mCallback));
|
||||
}
|
||||
|
|
|
@ -24,8 +24,9 @@ namespace dom {
|
|||
class CallbackInterface : public CallbackObject
|
||||
{
|
||||
public:
|
||||
explicit CallbackInterface(JSObject* aCallback)
|
||||
: CallbackObject(aCallback)
|
||||
explicit CallbackInterface(JSObject* aCallback,
|
||||
nsIGlobalObject *aIncumbentGlobal)
|
||||
: CallbackObject(aCallback, aIncumbentGlobal)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "xpcprivate.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "WorkerScope.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -35,15 +36,17 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(CallbackObject)
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CallbackObject)
|
||||
tmp->DropCallback();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIncumbentGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CallbackObject)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIncumbentGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CallbackObject)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCallback)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
|
||||
CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
||||
ErrorResult& aRv,
|
||||
ExceptionHandling aExceptionHandling,
|
||||
JSCompartment* aCompartment)
|
||||
|
@ -63,8 +66,9 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
|
|||
// callable.
|
||||
|
||||
// First, find the real underlying callback.
|
||||
JSObject* realCallback = js::UncheckedUnwrap(aCallback);
|
||||
JSObject* realCallback = js::UncheckedUnwrap(aCallback->CallbackPreserveColor());
|
||||
JSContext* cx = nullptr;
|
||||
nsIGlobalObject* globalObject = nullptr;
|
||||
|
||||
if (mIsMainThread) {
|
||||
// Now get the global and JSContext for this callback.
|
||||
|
@ -85,18 +89,26 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
|
|||
// This happens - Removing it causes
|
||||
// test_bug293235.xul to go orange.
|
||||
: nsContentUtils::GetSafeJSContext();
|
||||
globalObject = win;
|
||||
} else {
|
||||
// No DOM Window. Use the SafeJSContext.
|
||||
// No DOM Window. Store the global and use the SafeJSContext.
|
||||
JSObject* glob = js::GetGlobalForObjectCrossCompartment(realCallback);
|
||||
globalObject = xpc::GetNativeForGlobal(glob);
|
||||
MOZ_ASSERT(globalObject);
|
||||
cx = nsContentUtils::GetSafeJSContext();
|
||||
}
|
||||
|
||||
// Make sure our JSContext is pushed on the stack.
|
||||
mCxPusher.Push(cx);
|
||||
} else {
|
||||
cx = workers::GetCurrentThreadJSContext();
|
||||
globalObject = workers::GetCurrentThreadWorkerPrivate()->GlobalScope();
|
||||
}
|
||||
|
||||
// Unmark the callable, and stick it in a Rooted before it can go gray again.
|
||||
mAutoEntryScript.construct(globalObject, mIsMainThread, cx);
|
||||
if (aCallback->IncumbentGlobalOrNull()) {
|
||||
mAutoIncumbentScript.construct(aCallback->IncumbentGlobalOrNull());
|
||||
}
|
||||
|
||||
// Unmark the callable (by invoking Callback() and not the CallbackPreserveColor()
|
||||
// variant), and stick it in a Rooted before it can go gray again.
|
||||
// Nothing before us in this function can trigger a CC, so it's safe to wait
|
||||
// until here it do the unmark. This allows us to order the following two
|
||||
// operations _after_ the Push() above, which lets us take advantage of the
|
||||
|
@ -104,15 +116,14 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
|
|||
//
|
||||
// We can do this even though we're not in the right compartment yet, because
|
||||
// Rooted<> does not care about compartments.
|
||||
JS::ExposeObjectToActiveJS(aCallback);
|
||||
mRootedCallable.construct(cx, aCallback);
|
||||
mRootedCallable.construct(cx, aCallback->Callback());
|
||||
|
||||
if (mIsMainThread) {
|
||||
// Check that it's ok to run this callback at all.
|
||||
// Make sure to unwrap aCallback before passing it in to get the global of
|
||||
// the callback object, not the wrapper.
|
||||
// Make sure to use realCallback to get the global of the callback object,
|
||||
// not the wrapper.
|
||||
bool allowed = nsContentUtils::GetSecurityManager()->
|
||||
ScriptAllowed(js::GetGlobalForObjectCrossCompartment(js::UncheckedUnwrap(aCallback)));
|
||||
ScriptAllowed(js::GetGlobalForObjectCrossCompartment(realCallback));
|
||||
|
||||
if (!allowed) {
|
||||
return;
|
||||
|
@ -120,7 +131,11 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
|
|||
}
|
||||
|
||||
// Enter the compartment of our callback, so we can actually work with it.
|
||||
mAc.construct(cx, aCallback);
|
||||
//
|
||||
// Note that if the callback is a wrapper, this will not be the same
|
||||
// compartment that we ended up in with mAutoEntryScript above, because the
|
||||
// entry point is based off of the unwrapped callback (realCallback).
|
||||
mAc.construct(cx, mRootedCallable.ref());
|
||||
|
||||
// And now we're ready to go.
|
||||
mCx = cx;
|
||||
|
@ -194,17 +209,11 @@ CallbackObject::CallSetup::~CallSetup()
|
|||
// But be careful: it might not have been constructed at all!
|
||||
mAc.destroyIfConstructed();
|
||||
|
||||
// XXXbz For that matter why do we need to manually call ScriptEvaluated at
|
||||
// all? nsCxPusher::Pop will do that nowadays if !mScriptIsRunning, so the
|
||||
// concerns from bug 295983 don't seem relevant anymore. Do we want to make
|
||||
// sure it's still called when !mScriptIsRunning? I guess play it safe for
|
||||
// now and do what CallEventHandler did, which is call always.
|
||||
|
||||
// Popping an nsCxPusher is safe even if it never got pushed.
|
||||
mCxPusher.Pop();
|
||||
mAutoIncumbentScript.destroyIfConstructed();
|
||||
mAutoEntryScript.destroyIfConstructed();
|
||||
|
||||
// It is important that this is the last thing we do, after leaving the
|
||||
// compartment and popping the context.
|
||||
// compartment and undoing all our entry/incumbent script changes
|
||||
if (mIsMainThread) {
|
||||
nsContentUtils::LeaveMicroTask();
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsJSEnvironment.h"
|
||||
#include "xpcpublic.h"
|
||||
|
@ -46,9 +46,13 @@ public:
|
|||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CallbackObject)
|
||||
|
||||
explicit CallbackObject(JSObject* aCallback)
|
||||
// The caller may pass a global object which will act as an override for the
|
||||
// incumbent script settings object when the callback is invoked (overriding
|
||||
// the entry point computed from aCallback). If no override is required, the
|
||||
// caller should pass null.
|
||||
explicit CallbackObject(JSObject* aCallback, nsIGlobalObject *aIncumbentGlobal)
|
||||
{
|
||||
Init(aCallback);
|
||||
Init(aCallback, aIncumbentGlobal);
|
||||
}
|
||||
|
||||
virtual ~CallbackObject()
|
||||
|
@ -77,6 +81,11 @@ public:
|
|||
return JS::Handle<JSObject*>::fromMarkedLocation(mCallback.address());
|
||||
}
|
||||
|
||||
nsIGlobalObject* IncumbentGlobalOrNull() const
|
||||
{
|
||||
return mIncumbentGlobal;
|
||||
}
|
||||
|
||||
enum ExceptionHandling {
|
||||
// Report any exception and don't throw it to the caller code.
|
||||
eReportExceptions,
|
||||
|
@ -91,17 +100,19 @@ public:
|
|||
protected:
|
||||
explicit CallbackObject(CallbackObject* aCallbackObject)
|
||||
{
|
||||
Init(aCallbackObject->mCallback);
|
||||
Init(aCallbackObject->mCallback, aCallbackObject->mIncumbentGlobal);
|
||||
}
|
||||
|
||||
private:
|
||||
inline void Init(JSObject* aCallback)
|
||||
inline void Init(JSObject* aCallback, nsIGlobalObject* aIncumbentGlobal)
|
||||
{
|
||||
MOZ_ASSERT(aCallback && !mCallback);
|
||||
// Set mCallback before we hold, on the off chance that a GC could somehow
|
||||
// happen in there... (which would be pretty odd, granted).
|
||||
mCallback = aCallback;
|
||||
mozilla::HoldJSObjects(this);
|
||||
|
||||
mIncumbentGlobal = aIncumbentGlobal;
|
||||
}
|
||||
|
||||
CallbackObject(const CallbackObject&) MOZ_DELETE;
|
||||
|
@ -117,6 +128,7 @@ protected:
|
|||
}
|
||||
|
||||
JS::Heap<JSObject*> mCallback;
|
||||
nsCOMPtr<nsIGlobalObject> mIncumbentGlobal;
|
||||
|
||||
class MOZ_STACK_CLASS CallSetup
|
||||
{
|
||||
|
@ -129,7 +141,7 @@ protected:
|
|||
public:
|
||||
// If aExceptionHandling == eRethrowContentExceptions then aCompartment
|
||||
// needs to be set to the caller's compartment.
|
||||
CallSetup(JS::Handle<JSObject*> aCallable, ErrorResult& aRv,
|
||||
CallSetup(CallbackObject* aCallback, ErrorResult& aRv,
|
||||
ExceptionHandling aExceptionHandling,
|
||||
JSCompartment* aCompartment = nullptr);
|
||||
~CallSetup();
|
||||
|
@ -153,17 +165,17 @@ protected:
|
|||
JSCompartment* mCompartment;
|
||||
|
||||
// And now members whose construction/destruction order we need to control.
|
||||
|
||||
nsCxPusher mCxPusher;
|
||||
Maybe<AutoEntryScript> mAutoEntryScript;
|
||||
Maybe<AutoIncumbentScript> mAutoIncumbentScript;
|
||||
|
||||
// Constructed the rooter within the scope of mCxPusher above, so that it's
|
||||
// always within a request during its lifetime.
|
||||
Maybe<JS::Rooted<JSObject*> > mRootedCallable;
|
||||
|
||||
// Can't construct a JSAutoCompartment without a JSContext either. Also,
|
||||
// Put mAc after mCxPusher so that we exit the compartment before we pop the
|
||||
// JSContext. Though in practice we'll often manually order those two
|
||||
// things.
|
||||
// Put mAc after mAutoEntryScript so that we exit the compartment before
|
||||
// we pop the JSContext. Though in practice we'll often manually order
|
||||
// those two things.
|
||||
Maybe<JSAutoCompartment> mAc;
|
||||
|
||||
// An ErrorResult to possibly re-throw exceptions on and whether
|
||||
|
@ -337,28 +349,7 @@ public:
|
|||
nsRefPtr<WebIDLCallbackT> callback = GetWebIDLCallback();
|
||||
return callback.forget();
|
||||
}
|
||||
|
||||
XPCOMCallbackT* callback = GetXPCOMCallback();
|
||||
if (!callback) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(callback);
|
||||
if (!wrappedJS) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
|
||||
JS::Rooted<JSObject*> obj(cx, wrappedJS->GetJSObject());
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSAutoCompartment ac(cx, obj);
|
||||
|
||||
nsRefPtr<WebIDLCallbackT> newCallback = new WebIDLCallbackT(obj);
|
||||
return newCallback.forget();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -3343,7 +3343,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
|||
else:
|
||||
declType = CGGeneric("OwningNonNull<%s>" % name)
|
||||
conversion = (
|
||||
"${declName} = new %s(&${val}.toObject());\n" % name)
|
||||
"${declName} = new %s(&${val}.toObject(), mozilla::dom::GetIncumbentGlobal());\n" % name)
|
||||
|
||||
template = wrapObjectTemplate(conversion, type,
|
||||
"${declName} = nullptr",
|
||||
|
@ -3676,7 +3676,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
|||
else:
|
||||
declType = CGGeneric("OwningNonNull<%s>" % name)
|
||||
conversion = (
|
||||
" ${declName} = new %s(&${val}.toObject());\n" % name)
|
||||
" ${declName} = new %s(&${val}.toObject(), mozilla::dom::GetIncumbentGlobal());\n" % name)
|
||||
|
||||
if allowTreatNonCallableAsNull and type.treatNonCallableAsNull():
|
||||
haveCallable = "JS_ObjectIsCallable(cx, &${val}.toObject())"
|
||||
|
@ -10421,7 +10421,7 @@ class CGJSImplClass(CGBindingImplClass):
|
|||
decorators = "MOZ_FINAL"
|
||||
destructor = None
|
||||
|
||||
baseConstructors=["mImpl(new %s(aJSImplObject))" % jsImplName(descriptor.name),
|
||||
baseConstructors=["mImpl(new %s(aJSImplObject, /* aIncumbentGlobal = */ nullptr))" % jsImplName(descriptor.name),
|
||||
"mParent(aParent)"]
|
||||
parentInterface = descriptor.interface.parent
|
||||
while parentInterface:
|
||||
|
@ -10548,12 +10548,12 @@ class CGCallback(CGClass):
|
|||
|
||||
def getConstructors(self):
|
||||
return [ClassConstructor(
|
||||
[Argument("JSObject*", "aCallback")],
|
||||
[Argument("JSObject*", "aCallback"), Argument("nsIGlobalObject*", "aIncumbentGlobal")],
|
||||
bodyInHeader=True,
|
||||
visibility="public",
|
||||
explicit=True,
|
||||
baseConstructors=[
|
||||
"%s(aCallback)" % self.baseName
|
||||
"%s(aCallback, aIncumbentGlobal)" % self.baseName,
|
||||
])]
|
||||
|
||||
def getMethodImpls(self, method):
|
||||
|
@ -10578,7 +10578,7 @@ class CGCallback(CGClass):
|
|||
argsWithoutThis = list(args)
|
||||
args.insert(0, Argument("const T&", "thisObj"))
|
||||
|
||||
setupCall = ("CallSetup s(CallbackPreserveColor(), aRv, aExceptionHandling);\n"
|
||||
setupCall = ("CallSetup s(this, aRv, aExceptionHandling);\n"
|
||||
"if (!s.GetContext()) {\n"
|
||||
" aRv.Throw(NS_ERROR_UNEXPECTED);\n"
|
||||
" return${errorReturn};\n"
|
||||
|
@ -10868,7 +10868,7 @@ class CallbackMember(CGNativeMember):
|
|||
if self.needThisHandling:
|
||||
# It's been done for us already
|
||||
return ""
|
||||
callSetup = "CallSetup s(CallbackPreserveColor(), aRv"
|
||||
callSetup = "CallSetup s(this, aRv"
|
||||
if self.rethrowContentException:
|
||||
# getArgs doesn't add the aExceptionHandling argument but does add
|
||||
# aCompartment for us.
|
||||
|
|
|
@ -2492,6 +2492,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TabChildGlobal)
|
|||
NS_INTERFACE_MAP_ENTRY(nsISyncMessageSender)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIContentFrameMessageManager)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ContentFrameMessageManager)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
|
||||
|
@ -2556,10 +2557,20 @@ TabChildGlobal::GetJSContextForEventHandlers()
|
|||
return nsContentUtils::GetSafeJSContext();
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
nsIPrincipal*
|
||||
TabChildGlobal::GetPrincipal()
|
||||
{
|
||||
if (!mTabChild)
|
||||
return nullptr;
|
||||
return mTabChild->GetPrincipal();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
TabChildGlobal::GetGlobalJSObject()
|
||||
{
|
||||
NS_ENSURE_TRUE(mTabChild, nullptr);
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> ref = mTabChild->GetGlobal();
|
||||
NS_ENSURE_TRUE(ref, nullptr);
|
||||
return ref->GetJSObject();
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,8 @@ class ClonedMessageData;
|
|||
|
||||
class TabChildGlobal : public nsDOMEventTargetHelper,
|
||||
public nsIContentFrameMessageManager,
|
||||
public nsIScriptObjectPrincipal
|
||||
public nsIScriptObjectPrincipal,
|
||||
public nsIGlobalObject
|
||||
{
|
||||
public:
|
||||
TabChildGlobal(TabChild* aTabChild);
|
||||
|
@ -127,6 +128,7 @@ public:
|
|||
|
||||
virtual JSContext* GetJSContextForEventHandlers() MOZ_OVERRIDE;
|
||||
virtual nsIPrincipal* GetPrincipal() MOZ_OVERRIDE;
|
||||
virtual JSObject* GetGlobalJSObject() MOZ_OVERRIDE;
|
||||
|
||||
nsCOMPtr<nsIContentFrameMessageManager> mMessageManager;
|
||||
TabChild* mTabChild;
|
||||
|
|
|
@ -1044,6 +1044,7 @@ MediaManager::MediaManager()
|
|||
mPrefs.mHeight = MediaEngine::DEFAULT_VIDEO_HEIGHT;
|
||||
mPrefs.mFPS = MediaEngine::DEFAULT_VIDEO_FPS;
|
||||
mPrefs.mMinFPS = MediaEngine::DEFAULT_VIDEO_MIN_FPS;
|
||||
mPrefs.mLoadAdapt = MediaEngine::DEFAULT_LOAD_ADAPT;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
|
||||
|
@ -1088,6 +1089,7 @@ MediaManager::Get() {
|
|||
prefs->AddObserver("media.navigator.video.default_height", sSingleton, false);
|
||||
prefs->AddObserver("media.navigator.video.default_fps", sSingleton, false);
|
||||
prefs->AddObserver("media.navigator.video.default_minfps", sSingleton, false);
|
||||
prefs->AddObserver("media.navigator.load_adapt", sSingleton, false);
|
||||
}
|
||||
}
|
||||
return sSingleton;
|
||||
|
@ -1411,7 +1413,7 @@ MediaManager::GetBackend(uint64_t aWindowId)
|
|||
if (!mBackend) {
|
||||
#if defined(MOZ_WEBRTC)
|
||||
#ifndef MOZ_B2G_CAMERA
|
||||
mBackend = new MediaEngineWebRTC();
|
||||
mBackend = new MediaEngineWebRTC(mPrefs);
|
||||
#else
|
||||
mBackend = new MediaEngineWebRTC(mCameraManager, aWindowId);
|
||||
#endif
|
||||
|
@ -1509,6 +1511,18 @@ MediaManager::GetPref(nsIPrefBranch *aBranch, const char *aPref,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaManager::GetPrefBool(nsIPrefBranch *aBranch, const char *aPref,
|
||||
const char *aData, bool *aVal)
|
||||
{
|
||||
bool temp;
|
||||
if (aData == nullptr || strcmp(aPref,aData) == 0) {
|
||||
if (NS_SUCCEEDED(aBranch->GetBoolPref(aPref, &temp))) {
|
||||
*aVal = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaManager::GetPrefs(nsIPrefBranch *aBranch, const char *aData)
|
||||
{
|
||||
|
@ -1516,6 +1530,7 @@ MediaManager::GetPrefs(nsIPrefBranch *aBranch, const char *aData)
|
|||
GetPref(aBranch, "media.navigator.video.default_height", aData, &mPrefs.mHeight);
|
||||
GetPref(aBranch, "media.navigator.video.default_fps", aData, &mPrefs.mFPS);
|
||||
GetPref(aBranch, "media.navigator.video.default_minfps", aData, &mPrefs.mMinFPS);
|
||||
GetPrefBool(aBranch, "media.navigator.load_adapt", aData, &mPrefs.mLoadAdapt);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -1544,6 +1559,7 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
prefs->RemoveObserver("media.navigator.video.default_height", this);
|
||||
prefs->RemoveObserver("media.navigator.video.default_fps", this);
|
||||
prefs->RemoveObserver("media.navigator.video.default_minfps", this);
|
||||
prefs->RemoveObserver("media.navigator.load_adapt", this);
|
||||
}
|
||||
|
||||
// Close off any remaining active windows.
|
||||
|
|
|
@ -506,6 +506,8 @@ private:
|
|||
|
||||
void GetPref(nsIPrefBranch *aBranch, const char *aPref,
|
||||
const char *aData, int32_t *aVal);
|
||||
void GetPrefBool(nsIPrefBranch *aBranch, const char *aPref,
|
||||
const char *aData, bool *aVal);
|
||||
void GetPrefs(nsIPrefBranch *aBranch, const char *aData);
|
||||
|
||||
// Make private because we want only one instance of this class
|
||||
|
|
|
@ -248,6 +248,23 @@ MmsConnection.prototype = {
|
|||
|
||||
this.connected = this.radioInterface.getDataCallStateByType("mms") ==
|
||||
Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED;
|
||||
// If the MMS network is connected during the initialization, it means the
|
||||
// MMS network must share the same APN with the mobile network by default.
|
||||
// Under this case, |networkManager.active| should keep the mobile network,
|
||||
// which is supposed be an instance of |nsIRilNetworkInterface| for sure.
|
||||
if (this.connected) {
|
||||
let networkManager =
|
||||
Cc["@mozilla.org/network/manager;1"].getService(Ci.nsINetworkManager);
|
||||
let activeNetwork = networkManager.active;
|
||||
if (activeNetwork.serviceId != this.serviceId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let rilNetwork = activeNetwork.QueryInterface(Ci.nsIRilNetworkInterface);
|
||||
// Set up the MMS APN setting based on the connected MMS network,
|
||||
// which is going to be used for the HTTP requests later.
|
||||
this.setApnSetting(rilNetwork);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -1007,11 +1007,8 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle<JSObject*> obj)
|
|||
}
|
||||
}
|
||||
|
||||
nsJSObjWrapperKey key(obj, npp);
|
||||
|
||||
JSObjWrapperTable::AddPtr p = sJSObjWrappers.lookupForAdd(key);
|
||||
|
||||
if (p/* && p->value()*/) {
|
||||
JSObjWrapperTable::Ptr p = sJSObjWrappers.lookupForAdd(nsJSObjWrapperKey(obj, npp));
|
||||
if (p) {
|
||||
MOZ_ASSERT(p->value());
|
||||
// Found a live nsJSObjWrapper, return it.
|
||||
|
||||
|
@ -1030,7 +1027,8 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle<JSObject*> obj)
|
|||
|
||||
wrapper->mJSObj = obj;
|
||||
|
||||
if (!sJSObjWrappers.add(p, key, wrapper)) {
|
||||
nsJSObjWrapperKey key(obj, npp);
|
||||
if (!sJSObjWrappers.putNew(key, wrapper)) {
|
||||
// Out of memory, free the wrapper we created.
|
||||
_releaseobject(wrapper);
|
||||
return nullptr;
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
@ -294,10 +293,6 @@ PositionError::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
|||
void
|
||||
PositionError::NotifyCallback(const GeoPositionErrorCallback& aCallback)
|
||||
{
|
||||
// Ensure that the proper context is on the stack (bug 452762)
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
|
||||
nsAutoMicroTask mt;
|
||||
if (aCallback.HasWebIDLCallback()) {
|
||||
PositionErrorCallback* callback = aCallback.GetWebIDLCallback();
|
||||
|
@ -529,9 +524,6 @@ nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition)
|
|||
Shutdown();
|
||||
}
|
||||
|
||||
// Ensure that the proper context is on the stack (bug 452762)
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
nsAutoMicroTask mt;
|
||||
if (mCallback.HasWebIDLCallback()) {
|
||||
ErrorResult err;
|
||||
|
|
|
@ -952,7 +952,6 @@ private:
|
|||
mDrawable(aDrawable),
|
||||
mDeleteDrawable(aDeleteDrawable),
|
||||
mDoubleBuffered(aDoubleBuffered),
|
||||
mLibType(libType),
|
||||
mGLX(&sGLXLibrary[libType]),
|
||||
mPixmap(aPixmap)
|
||||
{
|
||||
|
@ -967,7 +966,6 @@ private:
|
|||
bool mDeleteDrawable;
|
||||
bool mDoubleBuffered;
|
||||
|
||||
LibType mLibType;
|
||||
GLXLibrary* mGLX;
|
||||
|
||||
nsRefPtr<gfxXlibSurface> mPixmap;
|
||||
|
|
|
@ -38,7 +38,7 @@ load 393822-1.html
|
|||
load 394384-1.html
|
||||
load 394246-1.html
|
||||
load 394246-2.html
|
||||
skip-if(Android&&AndroidVersion<15) load 394751.xhtml # bug 922976
|
||||
skip-if(Android&&(AndroidVersion<15||AndroidVersion>=17)) load 394751.xhtml # bug 922976
|
||||
load 395335-1.xhtml
|
||||
load 395458-1.html
|
||||
load 396321-1.svg
|
||||
|
|
|
@ -36,10 +36,11 @@
|
|||
#include "SandboxPrivate.h"
|
||||
#include "nsJSPrincipals.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
using mozilla::AutoSafeJSContext;
|
||||
using mozilla::AutoPushJSContext;
|
||||
using mozilla::dom::AutoSystemCaller;
|
||||
|
||||
/*
|
||||
* defining CAUTIOUS_SCRIPTHOOK makes jsds disable GC while calling out to the
|
||||
|
@ -3004,8 +3005,7 @@ jsdService::EnterNestedEventLoop (jsdINestCallback *callback, uint32_t *_rval)
|
|||
// Nesting event queues is a thing of the past. Now, we just spin the
|
||||
// current event loop.
|
||||
nsresult rv = NS_OK;
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
AutoSystemCaller asc;
|
||||
uint32_t nestLevel = ++mNestedLoopLevel;
|
||||
nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
|
||||
|
||||
|
|
|
@ -631,20 +631,6 @@ DEPENDENCIES = .md
|
|||
|
||||
MOZ_COMPONENT_LIBS=$(XPCOM_LIBS) $(MOZ_COMPONENT_NSPR_LIBS)
|
||||
|
||||
ifeq ($(OS_ARCH),OS2)
|
||||
ELF_DYNSTR_GC = echo
|
||||
else
|
||||
ELF_DYNSTR_GC = :
|
||||
endif
|
||||
|
||||
ifndef CROSS_COMPILE
|
||||
ifdef USE_ELF_DYNSTR_GC
|
||||
ifdef MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS
|
||||
ELF_DYNSTR_GC = $(DEPTH)/config/elf-dynstr-gc
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef MACOSX_DEPLOYMENT_TARGET
|
||||
export MACOSX_DEPLOYMENT_TARGET
|
||||
endif # MACOSX_DEPLOYMENT_TARGET
|
||||
|
|
|
@ -23,7 +23,6 @@ ifndef NO_DIST_INSTALL
|
|||
ifdef SHARED_LIBRARY
|
||||
ifdef IS_COMPONENT
|
||||
$(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(FINAL_TARGET)/components
|
||||
$(ELF_DYNSTR_GC) $(FINAL_TARGET)/components/$(SHARED_LIBRARY)
|
||||
ifndef NO_COMPONENTS_MANIFEST
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/chrome.manifest 'manifest components/components.manifest')
|
||||
$(call py_action,buildlist,$(FINAL_TARGET)/components/components.manifest 'binary-component $(SHARED_LIBRARY)')
|
||||
|
|
|
@ -5510,7 +5510,7 @@ EmitCallOrNew(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
* will just cause the inner scripts to be repeatedly cloned.
|
||||
*/
|
||||
JS_ASSERT(!bce->emittingRunOnceLambda);
|
||||
if (bce->checkSingletonContext()) {
|
||||
if (bce->checkSingletonContext() || (!bce->isInLoop() && bce->isRunOnceLambda())) {
|
||||
bce->emittingRunOnceLambda = true;
|
||||
if (!EmitTree(cx, bce, pn2))
|
||||
return false;
|
||||
|
|
|
@ -10,7 +10,12 @@ function callback(obj) {
|
|||
if (incallback)
|
||||
return null;
|
||||
incallback = true;
|
||||
var res = {count:++count, location:Error().stack};
|
||||
var res =
|
||||
{
|
||||
count: ++count,
|
||||
location: Error().stack,
|
||||
message: Error().message // no .message => Error.prototype.message => ""
|
||||
};
|
||||
incallback = false;
|
||||
return res;
|
||||
}
|
||||
|
@ -40,3 +45,4 @@ assertEq(xc > wc, true);
|
|||
assertEq(yc > xc, true);
|
||||
assertEq(zc > yc, true);
|
||||
assertEq(/\.js/.test(getObjectMetadata(x).location), true);
|
||||
assertEq(getObjectMetadata(x).message, "");
|
||||
|
|
|
@ -11,6 +11,6 @@ dbg.onDebuggerStatement = function (frame) {
|
|||
throw new Error("deleteProperty should throw");
|
||||
};
|
||||
|
||||
g.eval("function h(x) { debugger; }");
|
||||
g.eval("function h(obj) { debugger; }");
|
||||
g.eval("h(Proxy.create({delete: function () { throw Error.prototype; }}));");
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
var g = newGlobal();
|
||||
var dbg = Debugger(g);
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
try {
|
||||
frame.arguments[0].deleteProperty("x");
|
||||
} catch (exc) {
|
||||
assertEq(exc instanceof ReferenceError, true);
|
||||
assertEq(exc.message, "diaf");
|
||||
assertEq(exc.fileName, "fail");
|
||||
assertEq(exc.lineNumber, 4);
|
||||
|
||||
// Arrant nonsense? Sure -- but different from lineNumber is all this
|
||||
// test exists to verify. If you're the person to make column numbers
|
||||
// actually work, change this accordingly.
|
||||
assertEq(exc.columnNumber, 0);
|
||||
return;
|
||||
}
|
||||
throw new Error("deleteProperty should throw");
|
||||
};
|
||||
|
||||
g.evaluate("function h(obj) { debugger; } \n" +
|
||||
"h(new Proxy({}, \n" +
|
||||
" { deleteProperty: function () { \n" +
|
||||
" var e = new ReferenceError('diaf', 'fail'); \n" +
|
||||
" throw e; \n" +
|
||||
" } \n" +
|
||||
" }));");
|
|
@ -4981,6 +4981,13 @@ GenerateCode(ModuleCompiler &m, ModuleCompiler::Func &func, MIRGenerator &mir, L
|
|||
{
|
||||
int64_t before = PRMJ_Now();
|
||||
|
||||
// A single MacroAssembler is reused for all function compilations so
|
||||
// that there is a single linear code segment for each module. To avoid
|
||||
// spiking memory, a LifoAllocScope in the caller frees all MIR/LIR
|
||||
// after each function is compiled. This method is responsible for cleaning
|
||||
// out any dangling pointers that the MacroAssembler may have kept.
|
||||
m.masm().resetForNewCodeGenerator(mir.alloc());
|
||||
|
||||
m.masm().bind(func.code());
|
||||
|
||||
ScopedJSDeletePtr<CodeGenerator> codegen(jit::GenerateCode(&mir, &lir, &m.masm()));
|
||||
|
@ -5011,13 +5018,6 @@ GenerateCode(ModuleCompiler &m, ModuleCompiler::Func &func, MIRGenerator &mir, L
|
|||
}
|
||||
#endif
|
||||
|
||||
// A single MacroAssembler is reused for all function compilations so
|
||||
// that there is a single linear code segment for each module. To avoid
|
||||
// spiking memory, a LifoAllocScope in the caller frees all MIR/LIR
|
||||
// after each function is compiled. This method is responsible for cleaning
|
||||
// out any dangling pointers that the MacroAssembler may have kept.
|
||||
m.masm().resetForNewCodeGenerator();
|
||||
|
||||
// Align internal function headers.
|
||||
m.masm().align(CodeAlignment);
|
||||
|
||||
|
@ -6402,6 +6402,8 @@ FinishModule(ModuleCompiler &m,
|
|||
TempAllocator alloc(&lifo);
|
||||
IonContext ionContext(m.cx(), &alloc);
|
||||
|
||||
m.masm().resetForNewCodeGenerator(alloc);
|
||||
|
||||
if (!GenerateStubs(m))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -682,7 +682,7 @@ static const mach_msg_id_t sExceptionId = 2405;
|
|||
// The choice of id here is arbitrary, the only constraint is that sQuitId != sExceptionId.
|
||||
static const mach_msg_id_t sQuitId = 42;
|
||||
|
||||
void *
|
||||
void
|
||||
AsmJSMachExceptionHandlerThread(void *threadArg)
|
||||
{
|
||||
JSRuntime *rt = reinterpret_cast<JSRuntime*>(threadArg);
|
||||
|
@ -733,8 +733,6 @@ AsmJSMachExceptionHandlerThread(void *threadArg)
|
|||
mach_msg(&reply.Head, MACH_SEND_MSG, sizeof(reply), 0, MACH_PORT_NULL,
|
||||
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AsmJSMachExceptionHandler::AsmJSMachExceptionHandler()
|
||||
|
@ -775,7 +773,7 @@ AsmJSMachExceptionHandler::uninstall()
|
|||
}
|
||||
|
||||
// Wait for the handler thread to complete before deallocating the port.
|
||||
pthread_join(thread_, nullptr);
|
||||
PR_JoinThread(thread_);
|
||||
thread_ = nullptr;
|
||||
}
|
||||
if (port_ != MACH_PORT_NULL) {
|
||||
|
@ -801,7 +799,9 @@ AsmJSMachExceptionHandler::install(JSRuntime *rt)
|
|||
goto error;
|
||||
|
||||
// Create a thread to block on reading port_.
|
||||
if (pthread_create(&thread_, nullptr, AsmJSMachExceptionHandlerThread, rt))
|
||||
thread_ = PR_CreateThread(PR_USER_THREAD, AsmJSMachExceptionHandlerThread, rt,
|
||||
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
|
||||
if (!thread_)
|
||||
goto error;
|
||||
|
||||
// Direct exceptions on this thread to port_ (and thus our handler thread).
|
||||
|
|
|
@ -11,7 +11,7 @@ struct JSRuntime;
|
|||
|
||||
#ifdef XP_MACOSX
|
||||
# include <mach/mach.h>
|
||||
# include <pthread.h>
|
||||
# include "jslock.h"
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
|
@ -36,7 +36,7 @@ TriggerOperationCallbackForAsmJSCode(JSRuntime *rt);
|
|||
class AsmJSMachExceptionHandler
|
||||
{
|
||||
bool installed_;
|
||||
pthread_t thread_;
|
||||
PRThread *thread_;
|
||||
mach_port_t port_;
|
||||
|
||||
void uninstall();
|
||||
|
|
|
@ -176,27 +176,24 @@ struct TempObject
|
|||
}
|
||||
};
|
||||
|
||||
// Deprecated, don't use for (new) classes. Will be removed when all classes have
|
||||
// been converted to placement new/TempObject (bug 937540).
|
||||
struct OldTempObject
|
||||
: public TempObject
|
||||
{
|
||||
using TempObject::operator new;
|
||||
|
||||
inline void *operator new(size_t nbytes) {
|
||||
return GetIonContext()->temp->allocateInfallible(nbytes);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TempObjectPool
|
||||
{
|
||||
TempAllocator *alloc_;
|
||||
InlineForwardList<T> freed_;
|
||||
|
||||
public:
|
||||
TempObjectPool()
|
||||
: alloc_(nullptr)
|
||||
{}
|
||||
void setAllocator(TempAllocator &alloc) {
|
||||
JS_ASSERT(freed_.empty());
|
||||
alloc_ = &alloc;
|
||||
}
|
||||
T *allocate() {
|
||||
JS_ASSERT(alloc_);
|
||||
if (freed_.empty())
|
||||
return new T();
|
||||
return new(*alloc_) T();
|
||||
return freed_.popFront();
|
||||
}
|
||||
void free(T *obj) {
|
||||
|
|
|
@ -4792,9 +4792,11 @@ IonBuilder::jsop_funcall(uint32_t argc)
|
|||
// Shimmy the slots down to remove the native 'call' function.
|
||||
current->shimmySlots(funcDepth - 1);
|
||||
|
||||
bool zeroArguments = (argc == 0);
|
||||
|
||||
// If no |this| argument was provided, explicitly pass Undefined.
|
||||
// Pushing is safe here, since one stack slot has been removed.
|
||||
if (argc == 0) {
|
||||
if (zeroArguments) {
|
||||
MConstant *undef = MConstant::New(alloc(), UndefinedValue());
|
||||
current->add(undef);
|
||||
MPassArg *pass = MPassArg::New(alloc(), undef);
|
||||
|
@ -4810,7 +4812,7 @@ IonBuilder::jsop_funcall(uint32_t argc)
|
|||
return false;
|
||||
|
||||
// Try to inline the call.
|
||||
if (argc > 0) {
|
||||
if (!zeroArguments) {
|
||||
InliningDecision decision = makeInliningDecision(target, callInfo);
|
||||
switch (decision) {
|
||||
case InliningDecision_Error:
|
||||
|
|
|
@ -193,18 +193,20 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
embedsNurseryPointers_(false),
|
||||
sps_(nullptr)
|
||||
{
|
||||
JSContext *cx = GetIonContext()->cx;
|
||||
IonContext *icx = GetIonContext();
|
||||
JSContext *cx = icx->cx;
|
||||
if (cx)
|
||||
constructRoot(cx);
|
||||
|
||||
if (!GetIonContext()->temp) {
|
||||
if (!icx->temp) {
|
||||
JS_ASSERT(cx);
|
||||
alloc_.construct(cx);
|
||||
}
|
||||
|
||||
moveResolver_.setAllocator(*icx->temp);
|
||||
#ifdef JS_CPU_ARM
|
||||
initWithAllocator();
|
||||
m_buffer.id = GetIonContext()->getNextAssemblerId();
|
||||
m_buffer.id = icx->getNextAssemblerId();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -218,6 +220,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
constructRoot(cx);
|
||||
ionContext_.construct(cx, (js::jit::TempAllocator *)nullptr);
|
||||
alloc_.construct(cx);
|
||||
moveResolver_.setAllocator(*ionContext_.ref().temp);
|
||||
#ifdef JS_CPU_ARM
|
||||
initWithAllocator();
|
||||
m_buffer.id = GetIonContext()->getNextAssemblerId();
|
||||
|
@ -237,28 +240,14 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
#endif
|
||||
}
|
||||
|
||||
MacroAssembler(JSContext *cx, IonScript *ion)
|
||||
: enoughMemory_(true),
|
||||
embedsNurseryPointers_(false),
|
||||
sps_(nullptr)
|
||||
{
|
||||
constructRoot(cx);
|
||||
ionContext_.construct(cx, (js::jit::TempAllocator *)nullptr);
|
||||
alloc_.construct(cx);
|
||||
#ifdef JS_CPU_ARM
|
||||
initWithAllocator();
|
||||
m_buffer.id = GetIonContext()->getNextAssemblerId();
|
||||
#endif
|
||||
setFramePushed(ion->frameSize());
|
||||
}
|
||||
|
||||
void setInstrumentation(IonInstrumentation *sps) {
|
||||
sps_ = sps;
|
||||
}
|
||||
|
||||
void resetForNewCodeGenerator() {
|
||||
void resetForNewCodeGenerator(TempAllocator &alloc) {
|
||||
setFramePushed(0);
|
||||
moveResolver_.clearTempObjectPool();
|
||||
moveResolver_.setAllocator(alloc);
|
||||
}
|
||||
|
||||
void constructRoot(JSContext *cx) {
|
||||
|
|
|
@ -157,7 +157,7 @@ class MoveResolver
|
|||
private:
|
||||
struct PendingMove
|
||||
: public Move,
|
||||
public OldTempObject,
|
||||
public TempObject,
|
||||
public InlineListNode<PendingMove>
|
||||
{
|
||||
PendingMove()
|
||||
|
@ -215,6 +215,9 @@ class MoveResolver
|
|||
void clearTempObjectPool() {
|
||||
movePool_.clear();
|
||||
}
|
||||
void setAllocator(TempAllocator &alloc) {
|
||||
movePool_.setAllocator(alloc);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
|
|
@ -3662,13 +3662,24 @@ MacroAssemblerARMCompat::callWithABIPost(uint32_t stackAdjust, Result result)
|
|||
if (secondScratchReg_ != lr)
|
||||
ma_mov(secondScratchReg_, lr);
|
||||
|
||||
if (result == DOUBLE) {
|
||||
#ifdef JS_CPU_ARM_HARDFP
|
||||
as_vmov(ReturnFloatReg, d0);
|
||||
#else
|
||||
switch (result) {
|
||||
case DOUBLE:
|
||||
#ifndef JS_CPU_ARM_HARDFP
|
||||
// Move double from r0/r1 to ReturnFloatReg.
|
||||
as_vxfer(r0, r1, ReturnFloatReg, CoreToFloat);
|
||||
break;
|
||||
#endif
|
||||
case FLOAT:
|
||||
#ifndef JS_CPU_ARM_HARDFP
|
||||
// Move float32 from r0 to ReturnFloatReg.
|
||||
as_vxfer(r0, InvalidReg, VFPRegister(d0).singleOverlay(), CoreToFloat);
|
||||
break;
|
||||
#endif
|
||||
case GENERAL:
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("unexpected callWithABI result");
|
||||
}
|
||||
|
||||
freeStack(stackAdjust);
|
||||
|
|
|
@ -4501,17 +4501,7 @@ JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optio
|
|||
JS_PUBLIC_API(bool)
|
||||
JS::CanCompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options)
|
||||
{
|
||||
if (!cx->runtime()->canUseParallelParsing())
|
||||
return false;
|
||||
|
||||
// Off thread compilation can't occur during incremental collections on the
|
||||
// atoms compartment, to avoid triggering barriers. Outside the atoms
|
||||
// compartment, the compilation will use a new zone which doesn't require
|
||||
// barriers itself.
|
||||
if (cx->runtime()->activeGCInAtomsZone())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return cx->runtime()->canUseParallelParsing();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
|
@ -6108,12 +6098,44 @@ JS_DescribeScriptedCaller(JSContext *cx, MutableHandleScript script, unsigned *l
|
|||
if (i.done())
|
||||
return false;
|
||||
|
||||
// If the caller is hidden, the embedding wants us to return null here so
|
||||
// that it can check its own stack.
|
||||
if (i.activation()->scriptedCallerIsHidden())
|
||||
return false;
|
||||
|
||||
script.set(i.script());
|
||||
if (lineno)
|
||||
*lineno = js::PCToLineNumber(i.script(), i.pc());
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace JS {
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
HideScriptedCaller(JSContext *cx)
|
||||
{
|
||||
MOZ_ASSERT(cx);
|
||||
|
||||
// If there's no accessible activation on the stack, we'll return null from
|
||||
// JS_DescribeScriptedCaller anyway, so there's no need to annotate
|
||||
// anything.
|
||||
Activation *act = cx->runtime()->mainThread.activation();
|
||||
if (!act)
|
||||
return;
|
||||
act->hideScriptedCaller();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
UnhideScriptedCaller(JSContext *cx)
|
||||
{
|
||||
Activation *act = cx->runtime()->mainThread.activation();
|
||||
if (!act)
|
||||
return;
|
||||
act->unhideScriptedCaller();
|
||||
}
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
static PRStatus
|
||||
CallOnce(void *func)
|
||||
|
|
|
@ -4576,10 +4576,53 @@ JS_IsIdentifier(JSContext *cx, JS::HandleString str, bool *isIdentifier);
|
|||
/*
|
||||
* Return the current script and line number of the most currently running
|
||||
* frame. Returns true if a scripted frame was found, false otherwise.
|
||||
*
|
||||
* If a the embedding has hidden the scripted caller for the topmost activation
|
||||
* record, this will also return false.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DescribeScriptedCaller(JSContext *cx, JS::MutableHandleScript script, unsigned *lineno);
|
||||
|
||||
namespace JS {
|
||||
|
||||
/*
|
||||
* Informs the JS engine that the scripted caller should be hidden. This can be
|
||||
* used by the embedding to maintain an override of the scripted caller in its
|
||||
* calculations, by hiding the scripted caller in the JS engine and pushing data
|
||||
* onto a separate stack, which it inspects when JS_DescribeScriptedCaller
|
||||
* returns null.
|
||||
*
|
||||
* We maintain a counter on each activation record. Add() increments the counter
|
||||
* of the topmost activation, and Remove() decrements it. The count may never
|
||||
* drop below zero, and must always be exactly zero when the activation is
|
||||
* popped from the stack.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
HideScriptedCaller(JSContext *cx);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
UnhideScriptedCaller(JSContext *cx);
|
||||
|
||||
class AutoHideScriptedCaller
|
||||
{
|
||||
public:
|
||||
AutoHideScriptedCaller(JSContext *cx
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: mContext(cx)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
HideScriptedCaller(mContext);
|
||||
}
|
||||
~AutoHideScriptedCaller() {
|
||||
UnhideScriptedCaller(mContext);
|
||||
}
|
||||
|
||||
protected:
|
||||
JSContext *mContext;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
} /* namepsace JS */
|
||||
|
||||
/*
|
||||
* Encode/Decode interpreted scripts and functions to/from memory.
|
||||
|
|
595
js/src/jsexn.cpp
595
js/src/jsexn.cpp
|
@ -40,66 +40,28 @@ using mozilla::ArrayLength;
|
|||
using mozilla::PodArrayZero;
|
||||
using mozilla::PodZero;
|
||||
|
||||
/* Forward declarations for ErrorObject::class_'s initializer. */
|
||||
static bool
|
||||
Exception(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static void
|
||||
exn_trace(JSTracer *trc, JSObject *obj);
|
||||
|
||||
static void
|
||||
exn_finalize(FreeOp *fop, JSObject *obj);
|
||||
|
||||
static bool
|
||||
exn_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
|
||||
MutableHandleObject objp);
|
||||
|
||||
const Class ErrorObject::class_ = {
|
||||
js_Error_str,
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_NEW_RESOLVE |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Error),
|
||||
JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Error) |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_DeletePropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
(JSResolveOp)exn_resolve,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub,
|
||||
exn_finalize,
|
||||
nullptr, /* checkAccess */
|
||||
nullptr, /* call */
|
||||
nullptr, /* hasInstance */
|
||||
nullptr, /* construct */
|
||||
exn_trace
|
||||
nullptr /* construct */
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct JSStackTraceElemImpl
|
||||
{
|
||||
T funName;
|
||||
const char *filename;
|
||||
unsigned ulineno;
|
||||
};
|
||||
|
||||
typedef JSStackTraceElemImpl<HeapPtrString> JSStackTraceElem;
|
||||
typedef JSStackTraceElemImpl<JSString *> JSStackTraceStackElem;
|
||||
|
||||
struct JSExnPrivate
|
||||
{
|
||||
/* A copy of the JSErrorReport originally generated. */
|
||||
JSErrorReport *errorReport;
|
||||
js::HeapPtrString message;
|
||||
js::HeapPtrString filename;
|
||||
unsigned lineno;
|
||||
unsigned column;
|
||||
size_t stackDepth;
|
||||
int exnType;
|
||||
JSStackTraceElem stackElems[1];
|
||||
};
|
||||
|
||||
static JSString *
|
||||
StackTraceToString(JSContext *cx, JSExnPrivate *priv);
|
||||
|
||||
static JSErrorReport *
|
||||
CopyErrorReport(JSContext *cx, JSErrorReport *report)
|
||||
{
|
||||
|
@ -242,25 +204,18 @@ struct SuppressErrorsGuard
|
|||
}
|
||||
};
|
||||
|
||||
static void
|
||||
SetExnPrivate(ErrorObject &exnObject, JSExnPrivate *priv);
|
||||
|
||||
static bool
|
||||
InitExnPrivate(JSContext *cx, HandleObject exnObject, HandleString message,
|
||||
HandleString filename, unsigned lineno, unsigned column,
|
||||
JSErrorReport *report, int exnType)
|
||||
static JSString *
|
||||
ComputeStackString(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(exnObject->is<ErrorObject>());
|
||||
JS_ASSERT(!exnObject->getPrivate());
|
||||
|
||||
JSCheckAccessOp checkAccess = cx->runtime()->securityCallbacks->checkObjectAccess;
|
||||
|
||||
Vector<JSStackTraceStackElem> frames(cx);
|
||||
StringBuffer sb(cx);
|
||||
|
||||
{
|
||||
RootedAtom atom(cx);
|
||||
SuppressErrorsGuard seg(cx);
|
||||
for (NonBuiltinScriptFrameIter i(cx); !i.done(); ++i) {
|
||||
|
||||
/* Ask the crystal CAPS ball whether we can see across compartments. */
|
||||
// Cut off the stack if this callee crosses a trust boundary.
|
||||
if (checkAccess && i.isNonEvalFunctionFrame()) {
|
||||
RootedValue v(cx);
|
||||
RootedId callerid(cx, NameToId(cx->names().caller));
|
||||
|
@ -269,194 +224,57 @@ InitExnPrivate(JSContext *cx, HandleObject exnObject, HandleString message,
|
|||
break;
|
||||
}
|
||||
|
||||
if (!frames.growBy(1))
|
||||
return false;
|
||||
JSStackTraceStackElem &frame = frames.back();
|
||||
if (i.isNonEvalFunctionFrame()) {
|
||||
JSAtom *atom = i.callee()->displayAtom();
|
||||
if (atom == nullptr)
|
||||
atom = cx->runtime()->emptyString;
|
||||
frame.funName = atom;
|
||||
} else {
|
||||
frame.funName = nullptr;
|
||||
}
|
||||
/* First append the function name, if any. */
|
||||
atom = nullptr;
|
||||
if (i.isNonEvalFunctionFrame() && i.callee()->displayAtom())
|
||||
atom = i.callee()->displayAtom();
|
||||
if (atom && !sb.append(atom))
|
||||
return nullptr;
|
||||
|
||||
/* Next a @ separating function name from source location. */
|
||||
if (!sb.append('@'))
|
||||
return nullptr;
|
||||
|
||||
/* Now the filename. */
|
||||
RootedScript script(cx, i.script());
|
||||
const char *cfilename = script->filename();
|
||||
if (!cfilename)
|
||||
cfilename = "";
|
||||
frame.filename = cfilename;
|
||||
frame.ulineno = PCToLineNumber(script, i.pc());
|
||||
if (!sb.appendInflated(cfilename, strlen(cfilename)))
|
||||
return nullptr;
|
||||
|
||||
/* Finally, : followed by the line number and a newline. */
|
||||
uint32_t line = PCToLineNumber(script, i.pc());
|
||||
if (!sb.append(':') || !NumberValueToStringBuffer(cx, NumberValue(line), sb) ||
|
||||
!sb.append('\n'))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cut off the stack if it gets too deep (most commonly for
|
||||
* infinite recursion errors).
|
||||
*/
|
||||
const size_t MaxReportedStackDepth = 1u << 20;
|
||||
if (sb.length() > MaxReportedStackDepth)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do not need overflow check: the vm stack is already bigger. */
|
||||
JS_STATIC_ASSERT(sizeof(JSStackTraceElem) <= sizeof(StackFrame));
|
||||
|
||||
size_t nbytes = offsetof(JSExnPrivate, stackElems) +
|
||||
frames.length() * sizeof(JSStackTraceElem);
|
||||
|
||||
JSExnPrivate *priv = (JSExnPrivate *)cx->malloc_(nbytes);
|
||||
if (!priv)
|
||||
return false;
|
||||
|
||||
/* Initialize to zero so that write barriers don't witness undefined values. */
|
||||
memset(priv, 0, nbytes);
|
||||
|
||||
if (report) {
|
||||
/*
|
||||
* Construct a new copy of the error report struct. We can't use the
|
||||
* error report struct that was passed in, because it's allocated on
|
||||
* the stack, and also because it may point to transient data in the
|
||||
* TokenStream.
|
||||
*/
|
||||
priv->errorReport = CopyErrorReport(cx, report);
|
||||
if (!priv->errorReport) {
|
||||
js_free(priv);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
priv->errorReport = nullptr;
|
||||
}
|
||||
|
||||
priv->message.init(message);
|
||||
priv->filename.init(filename);
|
||||
priv->lineno = lineno;
|
||||
priv->column = column;
|
||||
priv->stackDepth = frames.length();
|
||||
priv->exnType = exnType;
|
||||
for (size_t i = 0; i < frames.length(); ++i) {
|
||||
priv->stackElems[i].funName.init(frames[i].funName);
|
||||
priv->stackElems[i].filename = JS_strdup(cx, frames[i].filename);
|
||||
if (!priv->stackElems[i].filename)
|
||||
return false;
|
||||
priv->stackElems[i].ulineno = frames[i].ulineno;
|
||||
}
|
||||
|
||||
SetExnPrivate(exnObject->as<ErrorObject>(), priv);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
exn_trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
if (JSExnPrivate *priv = obj->as<ErrorObject>().getExnPrivate()) {
|
||||
if (priv->message)
|
||||
MarkString(trc, &priv->message, "exception message");
|
||||
if (priv->filename)
|
||||
MarkString(trc, &priv->filename, "exception filename");
|
||||
|
||||
for (size_t i = 0; i != priv->stackDepth; ++i) {
|
||||
JSStackTraceElem &elem = priv->stackElems[i];
|
||||
if (elem.funName)
|
||||
MarkString(trc, &elem.funName, "stack trace function name");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* NB: An error object's private must be set through this function. */
|
||||
static void
|
||||
SetExnPrivate(ErrorObject &exnObject, JSExnPrivate *priv)
|
||||
{
|
||||
JS_ASSERT(!exnObject.getExnPrivate());
|
||||
if (JSErrorReport *report = priv->errorReport) {
|
||||
if (JSPrincipals *prin = report->originPrincipals)
|
||||
JS_HoldPrincipals(prin);
|
||||
}
|
||||
exnObject.setPrivate(priv);
|
||||
return sb.finishString();
|
||||
}
|
||||
|
||||
static void
|
||||
exn_finalize(FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
if (JSExnPrivate *priv = obj->as<ErrorObject>().getExnPrivate()) {
|
||||
if (JSErrorReport *report = priv->errorReport) {
|
||||
/* HOLD called by SetExnPrivate. */
|
||||
if (JSPrincipals *prin = report->originPrincipals)
|
||||
JS_DropPrincipals(fop->runtime(), prin);
|
||||
fop->free_(report);
|
||||
}
|
||||
for (size_t i = 0; i < priv->stackDepth; i++)
|
||||
js_free(const_cast<char *>(priv->stackElems[i].filename));
|
||||
fop->free_(priv);
|
||||
if (JSErrorReport *report = obj->as<ErrorObject>().getErrorReport()) {
|
||||
/* These were held by ErrorObject::init. */
|
||||
if (JSPrincipals *prin = report->originPrincipals)
|
||||
JS_DropPrincipals(fop->runtime(), prin);
|
||||
fop->free_(report);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
exn_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
|
||||
MutableHandleObject objp)
|
||||
{
|
||||
JSExnPrivate *priv;
|
||||
const char *prop;
|
||||
jsval v;
|
||||
unsigned attrs;
|
||||
|
||||
objp.set(nullptr);
|
||||
priv = obj->as<ErrorObject>().getExnPrivate();
|
||||
if (priv && JSID_IS_ATOM(id)) {
|
||||
RootedString str(cx, JSID_TO_STRING(id));
|
||||
|
||||
RootedAtom atom(cx, cx->names().message);
|
||||
if (str == atom) {
|
||||
prop = js_message_str;
|
||||
|
||||
/*
|
||||
* Per ES5 15.11.1.1, if Error is called with no argument or with
|
||||
* undefined as the argument, it returns an Error object with no
|
||||
* own message property.
|
||||
*/
|
||||
if (!priv->message)
|
||||
return true;
|
||||
|
||||
v = STRING_TO_JSVAL(priv->message);
|
||||
attrs = 0;
|
||||
goto define;
|
||||
}
|
||||
|
||||
atom = cx->names().fileName;
|
||||
if (str == atom) {
|
||||
prop = js_fileName_str;
|
||||
v = STRING_TO_JSVAL(priv->filename);
|
||||
attrs = JSPROP_ENUMERATE;
|
||||
goto define;
|
||||
}
|
||||
|
||||
atom = cx->names().lineNumber;
|
||||
if (str == atom) {
|
||||
prop = js_lineNumber_str;
|
||||
v = UINT_TO_JSVAL(priv->lineno);
|
||||
attrs = JSPROP_ENUMERATE;
|
||||
goto define;
|
||||
}
|
||||
|
||||
atom = cx->names().columnNumber;
|
||||
if (str == atom) {
|
||||
prop = js_columnNumber_str;
|
||||
v = UINT_TO_JSVAL(priv->column);
|
||||
attrs = JSPROP_ENUMERATE;
|
||||
goto define;
|
||||
}
|
||||
|
||||
atom = cx->names().stack;
|
||||
if (str == atom) {
|
||||
JSString *stack = StackTraceToString(cx, priv);
|
||||
if (!stack)
|
||||
return false;
|
||||
|
||||
prop = js_stack_str;
|
||||
v = STRING_TO_JSVAL(stack);
|
||||
attrs = JSPROP_ENUMERATE;
|
||||
goto define;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
define:
|
||||
if (!JS_DefineProperty(cx, obj, prop, v, nullptr, nullptr, attrs))
|
||||
return false;
|
||||
objp.set(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSErrorReport *
|
||||
js_ErrorFromException(jsval exn)
|
||||
{
|
||||
|
@ -473,92 +291,20 @@ js_ErrorFromException(jsval exn)
|
|||
if (!obj->is<ErrorObject>())
|
||||
return nullptr;
|
||||
|
||||
JSExnPrivate *priv = obj->as<ErrorObject>().getExnPrivate();
|
||||
if (!priv)
|
||||
return nullptr;
|
||||
|
||||
return priv->errorReport;
|
||||
}
|
||||
|
||||
static JSString *
|
||||
StackTraceToString(JSContext *cx, JSExnPrivate *priv)
|
||||
{
|
||||
StringBuffer sb(cx);
|
||||
|
||||
JSStackTraceElem *element = priv->stackElems, *end = element + priv->stackDepth;
|
||||
for (; element < end; element++) {
|
||||
/* Try to reserve required space upfront, so we don't fail inbetween. */
|
||||
size_t length = ((element->funName ? element->funName->length() : 0) +
|
||||
(element->filename ? strlen(element->filename) * 2 : 0) +
|
||||
13); /* "@" + ":" + "4294967295" + "\n" */
|
||||
|
||||
if (!sb.reserve(length) || sb.length() > JS_BIT(20))
|
||||
break; /* Return as much as we got. */
|
||||
|
||||
if (element->funName) {
|
||||
if (!sb.append(element->funName))
|
||||
return nullptr;
|
||||
}
|
||||
if (!sb.append('@'))
|
||||
return nullptr;
|
||||
if (element->filename) {
|
||||
if (!sb.appendInflated(element->filename, strlen(element->filename)))
|
||||
return nullptr;
|
||||
}
|
||||
if (!sb.append(':') || !NumberValueToStringBuffer(cx, NumberValue(element->ulineno), sb) ||
|
||||
!sb.append('\n'))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return sb.finishString();
|
||||
}
|
||||
|
||||
/* XXXbe Consolidate the ugly truth that we don't treat filename as UTF-8
|
||||
with these two functions. */
|
||||
static JSString *
|
||||
FilenameToString(JSContext *cx, const char *filename)
|
||||
{
|
||||
return JS_NewStringCopyZ(cx, filename);
|
||||
return obj->as<ErrorObject>().getErrorReport();
|
||||
}
|
||||
|
||||
static bool
|
||||
Exception(JSContext *cx, unsigned argc, Value *vp)
|
||||
Error(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
/*
|
||||
* ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
|
||||
* called as functions, without operator new. But as we do not give
|
||||
* each constructor a distinct JSClass, whose .name member is used by
|
||||
* NewNativeClassInstance to find the class prototype, we must get the
|
||||
* class prototype ourselves.
|
||||
*/
|
||||
RootedObject callee(cx, &args.callee());
|
||||
RootedValue protov(cx);
|
||||
if (!JSObject::getProperty(cx, callee, callee, cx->names().prototype, &protov))
|
||||
return false;
|
||||
|
||||
if (!protov.isObject()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_PROTOTYPE, "Error");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject obj(cx, NewObjectWithGivenProto(cx, &ErrorObject::class_, &protov.toObject(),
|
||||
nullptr));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
/* Set the 'message' property. */
|
||||
RootedString message(cx);
|
||||
/* Compute the error message, if any. */
|
||||
RootedString message(cx, nullptr);
|
||||
if (args.hasDefined(0)) {
|
||||
message = ToString<CanGC>(cx, args[0]);
|
||||
if (!message)
|
||||
return false;
|
||||
args[0].setString(message);
|
||||
} else {
|
||||
message = nullptr;
|
||||
}
|
||||
|
||||
/* Find the scripted caller. */
|
||||
|
@ -566,34 +312,43 @@ Exception(JSContext *cx, unsigned argc, Value *vp)
|
|||
|
||||
/* Set the 'fileName' property. */
|
||||
RootedScript script(cx, iter.done() ? nullptr : iter.script());
|
||||
RootedString filename(cx);
|
||||
RootedString fileName(cx);
|
||||
if (args.length() > 1) {
|
||||
filename = ToString<CanGC>(cx, args[1]);
|
||||
if (!filename)
|
||||
return false;
|
||||
args[1].setString(filename);
|
||||
fileName = ToString<CanGC>(cx, args[1]);
|
||||
} else {
|
||||
filename = cx->runtime()->emptyString;
|
||||
fileName = cx->runtime()->emptyString;
|
||||
if (!iter.done()) {
|
||||
if (const char *cfilename = script->filename()) {
|
||||
filename = FilenameToString(cx, cfilename);
|
||||
if (!filename)
|
||||
return false;
|
||||
}
|
||||
if (const char *cfilename = script->filename())
|
||||
fileName = JS_NewStringCopyZ(cx, cfilename);
|
||||
}
|
||||
}
|
||||
if (!fileName)
|
||||
return false;
|
||||
|
||||
/* Set the 'lineNumber' property. */
|
||||
uint32_t lineno, column = 0;
|
||||
uint32_t lineNumber, columnNumber = 0;
|
||||
if (args.length() > 2) {
|
||||
if (!ToUint32(cx, args[2], &lineno))
|
||||
if (!ToUint32(cx, args[2], &lineNumber))
|
||||
return false;
|
||||
} else {
|
||||
lineno = iter.done() ? 0 : PCToLineNumber(script, iter.pc(), &column);
|
||||
lineNumber = iter.done() ? 0 : PCToLineNumber(script, iter.pc(), &columnNumber);
|
||||
}
|
||||
|
||||
int exnType = args.callee().as<JSFunction>().getExtendedSlot(0).toInt32();
|
||||
if (!InitExnPrivate(cx, obj, message, filename, lineno, column, nullptr, exnType))
|
||||
Rooted<JSString*> stack(cx, ComputeStackString(cx));
|
||||
if (!stack)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
|
||||
* called as functions, without operator new. But as we do not give
|
||||
* each constructor a distinct JSClass, we must get the exception type
|
||||
* ourselves.
|
||||
*/
|
||||
JSExnType exnType = JSExnType(args.callee().as<JSFunction>().getExtendedSlot(0).toInt32());
|
||||
|
||||
RootedObject obj(cx, ErrorObject::create(cx, exnType, stack, fileName,
|
||||
lineNumber, columnNumber, nullptr, message));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
args.rval().setObject(*obj);
|
||||
|
@ -774,54 +529,45 @@ JS_STATIC_ASSERT(JSProto_Error + JSEXN_SYNTAXERR == JSProto_SyntaxError);
|
|||
JS_STATIC_ASSERT(JSProto_Error + JSEXN_TYPEERR == JSProto_TypeError);
|
||||
JS_STATIC_ASSERT(JSProto_Error + JSEXN_URIERR == JSProto_URIError);
|
||||
|
||||
static JSObject *
|
||||
InitErrorClass(JSContext *cx, Handle<GlobalObject*> global, int type, HandleObject proto)
|
||||
/* static */ ErrorObject *
|
||||
ErrorObject::createProto(JSContext *cx, JS::Handle<GlobalObject*> global, JSExnType type,
|
||||
JS::HandleObject proto)
|
||||
{
|
||||
JSProtoKey key = GetExceptionProtoKey(type);
|
||||
RootedAtom name(cx, ClassName(key, cx));
|
||||
RootedObject errorProto(cx, global->createBlankPrototypeInheriting(cx, &ErrorObject::class_,
|
||||
*proto));
|
||||
RootedObject errorProto(cx);
|
||||
errorProto = global->createBlankPrototypeInheriting(cx, &ErrorObject::class_, *proto);
|
||||
if (!errorProto)
|
||||
return nullptr;
|
||||
|
||||
Rooted<ErrorObject*> err(cx, &errorProto->as<ErrorObject>());
|
||||
RootedString emptyStr(cx, cx->names().empty);
|
||||
if (!ErrorObject::init(cx, err, type, nullptr, emptyStr, emptyStr, 0, 0, emptyStr))
|
||||
return nullptr;
|
||||
|
||||
// The various prototypes also have .name in addition to the normal error
|
||||
// instance properties.
|
||||
JSProtoKey key = GetExceptionProtoKey(type);
|
||||
RootedPropertyName name(cx, ClassName(key, cx));
|
||||
RootedValue nameValue(cx, StringValue(name));
|
||||
RootedValue zeroValue(cx, Int32Value(0));
|
||||
RootedValue empty(cx, StringValue(cx->runtime()->emptyString));
|
||||
RootedId nameId(cx, NameToId(cx->names().name));
|
||||
RootedId messageId(cx, NameToId(cx->names().message));
|
||||
RootedId fileNameId(cx, NameToId(cx->names().fileName));
|
||||
RootedId lineNumberId(cx, NameToId(cx->names().lineNumber));
|
||||
RootedId columnNumberId(cx, NameToId(cx->names().columnNumber));
|
||||
if (!DefineNativeProperty(cx, errorProto, nameId, nameValue,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, 0, 0, 0) ||
|
||||
!DefineNativeProperty(cx, errorProto, messageId, empty,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, 0, 0, 0) ||
|
||||
!DefineNativeProperty(cx, errorProto, fileNameId, empty,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE, 0, 0) ||
|
||||
!DefineNativeProperty(cx, errorProto, lineNumberId, zeroValue,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE, 0, 0) ||
|
||||
!DefineNativeProperty(cx, errorProto, columnNumberId, zeroValue,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE, 0, 0))
|
||||
if (!JSObject::defineProperty(cx, err, cx->names().name, nameValue,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, 0))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Create the corresponding constructor. */
|
||||
RootedFunction ctor(cx, global->createConstructor(cx, Exception, name, 1,
|
||||
// Create the corresponding constructor.
|
||||
RootedFunction ctor(cx, global->createConstructor(cx, Error, name, 1,
|
||||
JSFunction::ExtendedFinalizeKind));
|
||||
if (!ctor)
|
||||
return nullptr;
|
||||
ctor->setExtendedSlot(0, Int32Value(int32_t(type)));
|
||||
|
||||
if (!LinkConstructorAndPrototype(cx, ctor, errorProto))
|
||||
if (!LinkConstructorAndPrototype(cx, ctor, err))
|
||||
return nullptr;
|
||||
|
||||
if (!DefineConstructorAndPrototype(cx, global, key, ctor, errorProto))
|
||||
if (!DefineConstructorAndPrototype(cx, global, key, ctor, err))
|
||||
return nullptr;
|
||||
|
||||
JS_ASSERT(!errorProto->getPrivate());
|
||||
|
||||
return errorProto;
|
||||
return err;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
@ -832,12 +578,12 @@ js_InitExceptionClasses(JSContext *cx, HandleObject obj)
|
|||
|
||||
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
|
||||
|
||||
RootedObject objectProto(cx, global->getOrCreateObjectPrototype(cx));
|
||||
if (!objectProto)
|
||||
RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
|
||||
if (!objProto)
|
||||
return nullptr;
|
||||
|
||||
/* Initialize the base Error class first. */
|
||||
RootedObject errorProto(cx, InitErrorClass(cx, global, JSEXN_ERR, objectProto));
|
||||
RootedObject errorProto(cx, ErrorObject::createProto(cx, global, JSEXN_ERR, objProto));
|
||||
if (!errorProto)
|
||||
return nullptr;
|
||||
|
||||
|
@ -847,7 +593,7 @@ js_InitExceptionClasses(JSContext *cx, HandleObject obj)
|
|||
|
||||
/* Define all remaining *Error constructors. */
|
||||
for (int i = JSEXN_ERR + 1; i < JSEXN_LIMIT; i++) {
|
||||
if (!InitErrorClass(cx, global, i, errorProto))
|
||||
if (!ErrorObject::createProto(cx, global, JSExnType(i), errorProto))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -888,29 +634,14 @@ js::GetErrorTypeName(JSRuntime* rt, int16_t exnType)
|
|||
{
|
||||
return nullptr;
|
||||
}
|
||||
JSProtoKey key = GetExceptionProtoKey(exnType);
|
||||
JSProtoKey key = GetExceptionProtoKey(JSExnType(exnType));
|
||||
return ClassName(key, rt)->chars();
|
||||
}
|
||||
|
||||
#if defined ( DEBUG_mccabe ) && defined ( PRINTNAMES )
|
||||
/* For use below... get character strings for error name and exception name */
|
||||
static const struct exnname { char *name; char *exception; } errortoexnname[] = {
|
||||
#define MSG_DEF(name, number, count, exception, format) \
|
||||
{#name, #exception},
|
||||
#include "js.msg"
|
||||
#undef MSG_DEF
|
||||
};
|
||||
#endif /* DEBUG */
|
||||
|
||||
bool
|
||||
js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp,
|
||||
JSErrorCallback callback, void *userRef)
|
||||
{
|
||||
JSErrNum errorNumber;
|
||||
const JSErrorFormatString *errorString;
|
||||
JSExnType exn;
|
||||
jsval tv[4];
|
||||
|
||||
/*
|
||||
* Tell our caller to report immediately if this report is just a warning.
|
||||
*/
|
||||
|
@ -919,26 +650,20 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp,
|
|||
return false;
|
||||
|
||||
/* Find the exception index associated with this error. */
|
||||
errorNumber = (JSErrNum) reportp->errorNumber;
|
||||
JSErrNum errorNumber = static_cast<JSErrNum>(reportp->errorNumber);
|
||||
const JSErrorFormatString *errorString;
|
||||
if (!callback || callback == js_GetErrorMessage)
|
||||
errorString = js_GetLocalizedErrorMessage(cx, nullptr, nullptr, errorNumber);
|
||||
else
|
||||
errorString = callback(userRef, nullptr, errorNumber);
|
||||
exn = errorString ? (JSExnType) errorString->exnType : JSEXN_NONE;
|
||||
JS_ASSERT(exn < JSEXN_LIMIT);
|
||||
|
||||
#if defined( DEBUG_mccabe ) && defined ( PRINTNAMES )
|
||||
/* Print the error name and the associated exception name to stderr */
|
||||
fprintf(stderr, "%s\t%s\n",
|
||||
errortoexnname[errorNumber].name,
|
||||
errortoexnname[errorNumber].exception);
|
||||
#endif
|
||||
JSExnType exnType = errorString ? static_cast<JSExnType>(errorString->exnType) : JSEXN_NONE;
|
||||
MOZ_ASSERT(exnType < JSEXN_LIMIT);
|
||||
|
||||
/*
|
||||
* Return false (no exception raised) if no exception is associated
|
||||
* with the given error number.
|
||||
*/
|
||||
if (exn == JSEXN_NONE)
|
||||
if (exnType == JSEXN_NONE)
|
||||
return false;
|
||||
|
||||
/* Prevent infinite recursion. */
|
||||
|
@ -946,43 +671,33 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp,
|
|||
return false;
|
||||
AutoScopedAssign<bool> asa(&cx->generatingError, true);
|
||||
|
||||
/* Protect the newly-created strings below from nesting GCs. */
|
||||
PodArrayZero(tv);
|
||||
AutoArrayRooter tvr(cx, ArrayLength(tv), tv);
|
||||
|
||||
/*
|
||||
* Try to get an appropriate prototype by looking up the corresponding
|
||||
* exception constructor name in the scope chain of the current context's
|
||||
* top stack frame, or in the global object if no frame is active.
|
||||
*/
|
||||
RootedObject errProto(cx);
|
||||
if (!js_GetClassPrototype(cx, GetExceptionProtoKey(exn), &errProto))
|
||||
return false;
|
||||
tv[0] = OBJECT_TO_JSVAL(errProto);
|
||||
|
||||
RootedObject errObject(cx, NewObjectWithGivenProto(cx, &ErrorObject::class_,
|
||||
errProto, nullptr));
|
||||
if (!errObject)
|
||||
return false;
|
||||
tv[1] = OBJECT_TO_JSVAL(errObject);
|
||||
|
||||
RootedString messageStr(cx, reportp->ucmessage ? JS_NewUCStringCopyZ(cx, reportp->ucmessage)
|
||||
: JS_NewStringCopyZ(cx, message));
|
||||
if (!messageStr)
|
||||
return false;
|
||||
tv[2] = STRING_TO_JSVAL(messageStr);
|
||||
|
||||
RootedString filenameStr(cx, JS_NewStringCopyZ(cx, reportp->filename));
|
||||
if (!filenameStr)
|
||||
RootedString fileName(cx, JS_NewStringCopyZ(cx, reportp->filename));
|
||||
if (!fileName)
|
||||
return false;
|
||||
tv[3] = STRING_TO_JSVAL(filenameStr);
|
||||
|
||||
if (!InitExnPrivate(cx, errObject, messageStr, filenameStr,
|
||||
reportp->lineno, reportp->column, reportp, exn)) {
|
||||
uint32_t lineNumber = reportp->lineno;
|
||||
uint32_t columnNumber = reportp->column;
|
||||
|
||||
RootedString stack(cx, ComputeStackString(cx));
|
||||
if (!stack)
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedValue errValue(cx, OBJECT_TO_JSVAL(errObject));
|
||||
js::ScopedJSFreePtr<JSErrorReport> report(CopyErrorReport(cx, reportp));
|
||||
if (!report)
|
||||
return false;
|
||||
|
||||
RootedObject errObject(cx, ErrorObject::create(cx, exnType, stack, fileName,
|
||||
lineNumber, columnNumber, &report,
|
||||
messageStr));
|
||||
if (!errObject)
|
||||
return false;
|
||||
|
||||
RootedValue errValue(cx, ObjectValue(*errObject));
|
||||
JS_SetPendingException(cx, errValue);
|
||||
|
||||
/* Flag the error report passed in to indicate an exception was raised. */
|
||||
|
@ -1015,8 +730,6 @@ IsDuckTypedErrorObject(JSContext *cx, HandleObject exnObject, const char **filen
|
|||
bool
|
||||
js_ReportUncaughtException(JSContext *cx)
|
||||
{
|
||||
JSErrorReport *reportp, report;
|
||||
|
||||
if (!cx->isExceptionPending())
|
||||
return true;
|
||||
|
||||
|
@ -1039,13 +752,15 @@ js_ReportUncaughtException(JSContext *cx)
|
|||
}
|
||||
|
||||
JS_ClearPendingException(cx);
|
||||
reportp = js_ErrorFromException(exn);
|
||||
JSErrorReport *reportp = js_ErrorFromException(exn);
|
||||
|
||||
/* XXX L10N angels cry once again. see also everywhere else */
|
||||
RootedString str(cx, ToString<CanGC>(cx, exn));
|
||||
if (str)
|
||||
roots[1] = StringValue(str);
|
||||
|
||||
JSErrorReport report;
|
||||
|
||||
const char *filename_str = js_fileName_str;
|
||||
JSAutoByteString filename;
|
||||
if (!reportp && exnObject &&
|
||||
|
@ -1130,50 +845,32 @@ js_ReportUncaughtException(JSContext *cx)
|
|||
return true;
|
||||
}
|
||||
|
||||
extern JSObject *
|
||||
js_CopyErrorObject(JSContext *cx, HandleObject errobj, HandleObject scope)
|
||||
JSObject *
|
||||
js_CopyErrorObject(JSContext *cx, Handle<ErrorObject*> err, HandleObject scope)
|
||||
{
|
||||
assertSameCompartment(cx, scope);
|
||||
JSExnPrivate *priv = errobj->as<ErrorObject>().getExnPrivate();
|
||||
|
||||
size_t size = offsetof(JSExnPrivate, stackElems) +
|
||||
priv->stackDepth * sizeof(JSStackTraceElem);
|
||||
|
||||
ScopedJSFreePtr<JSExnPrivate> copy(static_cast<JSExnPrivate *>(cx->malloc_(size)));
|
||||
if (!copy)
|
||||
return nullptr;
|
||||
|
||||
if (priv->errorReport) {
|
||||
copy->errorReport = CopyErrorReport(cx, priv->errorReport);
|
||||
if (!copy->errorReport)
|
||||
js::ScopedJSFreePtr<JSErrorReport> copyReport;
|
||||
if (JSErrorReport *errorReport = err->getErrorReport()) {
|
||||
copyReport = CopyErrorReport(cx, errorReport);
|
||||
if (!copyReport)
|
||||
return nullptr;
|
||||
} else {
|
||||
copy->errorReport = nullptr;
|
||||
}
|
||||
ScopedJSFreePtr<JSErrorReport> autoFreeErrorReport(copy->errorReport);
|
||||
|
||||
copy->message.init(priv->message);
|
||||
if (!cx->compartment()->wrap(cx, ©->message))
|
||||
RootedString message(cx, err->getMessage());
|
||||
if (message && !cx->compartment()->wrap(cx, message.address()))
|
||||
return nullptr;
|
||||
JS::Anchor<JSString *> messageAnchor(copy->message);
|
||||
copy->filename.init(priv->filename);
|
||||
if (!cx->compartment()->wrap(cx, ©->filename))
|
||||
RootedString fileName(cx, err->fileName());
|
||||
if (!cx->compartment()->wrap(cx, fileName.address()))
|
||||
return nullptr;
|
||||
JS::Anchor<JSString *> filenameAnchor(copy->filename);
|
||||
copy->lineno = priv->lineno;
|
||||
copy->column = priv->column;
|
||||
copy->stackDepth = 0;
|
||||
copy->exnType = priv->exnType;
|
||||
RootedString stack(cx, err->stack());
|
||||
if (!cx->compartment()->wrap(cx, stack.address()))
|
||||
return nullptr;
|
||||
uint32_t lineNumber = err->lineNumber();
|
||||
uint32_t columnNumber = err->columnNumber();
|
||||
JSExnType errorType = err->type();
|
||||
|
||||
// Create the Error object.
|
||||
RootedObject proto(cx, scope->global().getOrCreateCustomErrorPrototype(cx, copy->exnType));
|
||||
if (!proto)
|
||||
return nullptr;
|
||||
RootedObject copyobj(cx, NewObjectWithGivenProto(cx, &ErrorObject::class_, proto, nullptr));
|
||||
if (!copyobj)
|
||||
return nullptr;
|
||||
SetExnPrivate(copyobj->as<ErrorObject>(), copy);
|
||||
copy.forget();
|
||||
autoFreeErrorReport.forget();
|
||||
return copyobj;
|
||||
return ErrorObject::create(cx, errorType, stack, fileName,
|
||||
lineNumber, columnNumber, ©Report, message);
|
||||
}
|
||||
|
|
|
@ -14,11 +14,9 @@
|
|||
#include "jsapi.h"
|
||||
#include "NamespaceImports.h"
|
||||
|
||||
/*
|
||||
* Initialize the exception constructor/prototype hierarchy.
|
||||
*/
|
||||
extern JSObject *
|
||||
js_InitExceptionClasses(JSContext *cx, js::HandleObject obj);
|
||||
namespace js {
|
||||
class ErrorObject;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a JSErrorReport, check to see if there is an exception associated with
|
||||
|
@ -67,14 +65,14 @@ js_GetLocalizedErrorMessage(js::ExclusiveContext *cx, void *userRef, const char
|
|||
* (errobj->getPrivate() must not be nullptr).
|
||||
*/
|
||||
extern JSObject *
|
||||
js_CopyErrorObject(JSContext *cx, js::HandleObject errobj, js::HandleObject scope);
|
||||
js_CopyErrorObject(JSContext *cx, JS::Handle<js::ErrorObject*> errobj, js::HandleObject scope);
|
||||
|
||||
static inline JSProtoKey
|
||||
GetExceptionProtoKey(int exn)
|
||||
GetExceptionProtoKey(JSExnType exn)
|
||||
{
|
||||
JS_ASSERT(JSEXN_ERR <= exn);
|
||||
JS_ASSERT(exn < JSEXN_LIMIT);
|
||||
return JSProtoKey(JSProto_Error + exn);
|
||||
return JSProtoKey(JSProto_Error + int(exn));
|
||||
}
|
||||
|
||||
#endif /* jsexn_h */
|
||||
|
|
|
@ -4946,6 +4946,12 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget,
|
|||
*/
|
||||
repeat = (rt->gcPoke && rt->gcShouldCleanUpEverything) || wasReset;
|
||||
} while (repeat);
|
||||
|
||||
if (rt->gcIncrementalState == NO_INCREMENTAL) {
|
||||
#ifdef JS_WORKER_THREADS
|
||||
EnqueuePendingParseTasksAfterGC(rt);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -5406,6 +5412,23 @@ js::PurgeJITCaches(Zone *zone)
|
|||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ArenaLists::normalizeBackgroundFinalizeState(AllocKind thingKind)
|
||||
{
|
||||
volatile uintptr_t *bfs = &backgroundFinalizeState[thingKind];
|
||||
switch (*bfs) {
|
||||
case BFS_DONE:
|
||||
break;
|
||||
case BFS_JUST_FINISHED:
|
||||
// No allocations between end of last sweep and now.
|
||||
// Transfering over arenas is a kind of allocation.
|
||||
*bfs = BFS_DONE;
|
||||
break;
|
||||
default:
|
||||
JS_ASSERT(!"Background finalization in progress, but it should not be.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ArenaLists::adoptArenas(JSRuntime *rt, ArenaLists *fromArenaLists)
|
||||
|
@ -5422,21 +5445,9 @@ ArenaLists::adoptArenas(JSRuntime *rt, ArenaLists *fromArenaLists)
|
|||
// When we enter a parallel section, we join the background
|
||||
// thread, and we do not run GC while in the parallel section,
|
||||
// so no finalizer should be active!
|
||||
volatile uintptr_t *bfs = &backgroundFinalizeState[thingKind];
|
||||
switch (*bfs) {
|
||||
case BFS_DONE:
|
||||
break;
|
||||
case BFS_JUST_FINISHED:
|
||||
// No allocations between end of last sweep and now.
|
||||
// Transfering over arenas is a kind of allocation.
|
||||
*bfs = BFS_DONE;
|
||||
break;
|
||||
default:
|
||||
JS_ASSERT(!"Background finalization in progress, but it should not be.");
|
||||
break;
|
||||
}
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
||||
normalizeBackgroundFinalizeState(AllocKind(thingKind));
|
||||
fromArenaLists->normalizeBackgroundFinalizeState(AllocKind(thingKind));
|
||||
#endif
|
||||
ArenaList *fromList = &fromArenaLists->arenaLists[thingKind];
|
||||
ArenaList *toList = &arenaLists[thingKind];
|
||||
while (fromList->head != nullptr) {
|
||||
|
|
|
@ -616,6 +616,8 @@ class ArenaLists
|
|||
void *allocateFromArena(JS::Zone *zone, AllocKind thingKind);
|
||||
inline void *allocateFromArenaInline(JS::Zone *zone, AllocKind thingKind);
|
||||
|
||||
inline void normalizeBackgroundFinalizeState(AllocKind thingKind);
|
||||
|
||||
friend class js::Nursery;
|
||||
};
|
||||
|
||||
|
|
|
@ -3848,6 +3848,13 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto_, JSFunction
|
|||
|
||||
if (obj->is<StringObject>())
|
||||
AddTypeProperty(this, type, "length", Type::Int32Type());
|
||||
|
||||
if (obj->is<ErrorObject>()) {
|
||||
AddTypeProperty(this, type, "fileName", types::Type::StringType());
|
||||
AddTypeProperty(this, type, "lineNumber", types::Type::Int32Type());
|
||||
AddTypeProperty(this, type, "columnNumber", types::Type::Int32Type());
|
||||
AddTypeProperty(this, type, "stack", types::Type::StringType());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1470,7 +1470,7 @@ js::NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb)
|
|||
return sb.appendInflated(cstr, cstrlen);
|
||||
}
|
||||
|
||||
static void
|
||||
static bool
|
||||
CharsToNumber(ThreadSafeContext *cx, const jschar *chars, size_t length, double *result)
|
||||
{
|
||||
if (length == 1) {
|
||||
|
@ -1481,7 +1481,7 @@ CharsToNumber(ThreadSafeContext *cx, const jschar *chars, size_t length, double
|
|||
*result = 0.0;
|
||||
else
|
||||
*result = GenericNaN();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
const jschar *end = chars + length;
|
||||
|
@ -1504,7 +1504,7 @@ CharsToNumber(ThreadSafeContext *cx, const jschar *chars, size_t length, double
|
|||
} else {
|
||||
*result = d;
|
||||
}
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1516,10 +1516,17 @@ CharsToNumber(ThreadSafeContext *cx, const jschar *chars, size_t length, double
|
|||
*/
|
||||
const jschar *ep;
|
||||
double d;
|
||||
if (!js_strtod(cx, bp, end, &ep, &d) || SkipSpace(ep, end) != end)
|
||||
if (!js_strtod(cx, bp, end, &ep, &d)) {
|
||||
*result = GenericNaN();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SkipSpace(ep, end) != end)
|
||||
*result = GenericNaN();
|
||||
else
|
||||
*result = d;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1528,8 +1535,8 @@ js::StringToNumber(ThreadSafeContext *cx, JSString *str, double *result)
|
|||
ScopedThreadSafeStringInspector inspector(str);
|
||||
if (!inspector.ensureChars(cx))
|
||||
return false;
|
||||
CharsToNumber(cx, inspector.chars(), str->length(), result);
|
||||
return true;
|
||||
|
||||
return CharsToNumber(cx, inspector.chars(), str->length(), result);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -3801,13 +3801,13 @@ static const JSFunctionSpec string_static_methods[] = {
|
|||
JS_FS_END
|
||||
};
|
||||
|
||||
Shape *
|
||||
StringObject::assignInitialShape(JSContext *cx)
|
||||
/* static */ Shape *
|
||||
StringObject::assignInitialShape(ExclusiveContext *cx, Handle<StringObject*> obj)
|
||||
{
|
||||
JS_ASSERT(nativeEmpty());
|
||||
JS_ASSERT(obj->nativeEmpty());
|
||||
|
||||
return addDataProperty(cx, cx->names().length, LENGTH_SLOT,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY);
|
||||
return obj->addDataProperty(cx, cx->names().length, LENGTH_SLOT,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
|
|
@ -176,18 +176,20 @@ static const JSClass workerGlobalClass = {
|
|||
JS_ConvertStub, nullptr
|
||||
};
|
||||
|
||||
ParseTask::ParseTask(ExclusiveContext *cx, JSContext *initCx,
|
||||
ParseTask::ParseTask(ExclusiveContext *cx, JSObject *exclusiveContextGlobal, JSContext *initCx,
|
||||
const jschar *chars, size_t length, JSObject *scopeChain,
|
||||
JS::OffThreadCompileCallback callback, void *callbackData)
|
||||
: cx(cx), options(initCx), chars(chars), length(length),
|
||||
alloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), scopeChain(scopeChain),
|
||||
callback(callback), callbackData(callbackData), script(nullptr),
|
||||
errors(cx), overRecursed(false)
|
||||
exclusiveContextGlobal(exclusiveContextGlobal), callback(callback),
|
||||
callbackData(callbackData), script(nullptr), errors(cx), overRecursed(false)
|
||||
{
|
||||
JSRuntime *rt = scopeChain->runtimeFromMainThread();
|
||||
|
||||
if (!AddObjectRoot(rt, &this->scopeChain, "ParseTask::scopeChain"))
|
||||
MOZ_CRASH();
|
||||
if (!AddObjectRoot(rt, &this->exclusiveContextGlobal, "ParseTask::exclusiveContextGlobal"))
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -196,11 +198,19 @@ ParseTask::init(JSContext *cx, const ReadOnlyCompileOptions &options)
|
|||
return this->options.copy(cx, options);
|
||||
}
|
||||
|
||||
void
|
||||
ParseTask::activate(JSRuntime *rt)
|
||||
{
|
||||
rt->setUsedByExclusiveThread(exclusiveContextGlobal->zone());
|
||||
cx->enterCompartment(exclusiveContextGlobal->compartment());
|
||||
}
|
||||
|
||||
ParseTask::~ParseTask()
|
||||
{
|
||||
JSRuntime *rt = scopeChain->runtimeFromMainThread();
|
||||
|
||||
JS_RemoveObjectRootRT(rt, &scopeChain);
|
||||
JS_RemoveObjectRootRT(rt, &exclusiveContextGlobal);
|
||||
|
||||
// ParseTask takes over ownership of its input exclusive context.
|
||||
js_delete(cx);
|
||||
|
@ -257,38 +267,75 @@ js::StartOffThreadParseScript(JSContext *cx, const ReadOnlyCompileOptions &optio
|
|||
}
|
||||
}
|
||||
|
||||
cx->runtime()->setUsedByExclusiveThread(global->zone());
|
||||
|
||||
ScopedJSDeletePtr<ExclusiveContext> workercx(
|
||||
cx->new_<ExclusiveContext>(cx->runtime(), (PerThreadData *) nullptr,
|
||||
ThreadSafeContext::Context_Exclusive));
|
||||
if (!workercx)
|
||||
return false;
|
||||
|
||||
workercx->enterCompartment(global->compartment());
|
||||
|
||||
ScopedJSDeletePtr<ParseTask> task(
|
||||
cx->new_<ParseTask>(workercx.get(), cx, chars, length,
|
||||
cx->new_<ParseTask>(workercx.get(), global, cx, chars, length,
|
||||
scopeChain, callback, callbackData));
|
||||
if (!task || !task->init(cx, options))
|
||||
if (!task)
|
||||
return false;
|
||||
|
||||
workercx.forget();
|
||||
|
||||
if (!task->init(cx, options))
|
||||
return false;
|
||||
|
||||
WorkerThreadState &state = *cx->runtime()->workerThreadState;
|
||||
JS_ASSERT(state.numThreads);
|
||||
|
||||
AutoLockWorkerThreadState lock(state);
|
||||
// Off thread parsing can't occur during incremental collections on the
|
||||
// atoms compartment, to avoid triggering barriers. (Outside the atoms
|
||||
// compartment, the compilation will use a new zone which doesn't require
|
||||
// barriers itself.) If an atoms-zone GC is in progress, hold off on
|
||||
// executing the parse task until the atoms-zone GC completes (see
|
||||
// EnqueuePendingParseTasksAfterGC).
|
||||
if (cx->runtime()->activeGCInAtomsZone()) {
|
||||
if (!state.parseWaitingOnGC.append(task.get()))
|
||||
return false;
|
||||
} else {
|
||||
task->activate(cx->runtime());
|
||||
|
||||
if (!state.parseWorklist.append(task.get()))
|
||||
return false;
|
||||
AutoLockWorkerThreadState lock(state);
|
||||
|
||||
if (!state.parseWorklist.append(task.get()))
|
||||
return false;
|
||||
|
||||
state.notifyAll(WorkerThreadState::PRODUCER);
|
||||
}
|
||||
|
||||
task.forget();
|
||||
|
||||
state.notifyAll(WorkerThreadState::PRODUCER);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
js::EnqueuePendingParseTasksAfterGC(JSRuntime *rt)
|
||||
{
|
||||
JS_ASSERT(!rt->activeGCInAtomsZone());
|
||||
|
||||
if (!rt->workerThreadState || rt->workerThreadState->parseWaitingOnGC.empty())
|
||||
return;
|
||||
|
||||
// This logic should mirror the contents of the !activeGCInAtomsZone()
|
||||
// branch in StartOffThreadParseScript:
|
||||
|
||||
WorkerThreadState &state = *rt->workerThreadState;
|
||||
|
||||
for (size_t i = 0; i < state.parseWaitingOnGC.length(); i++)
|
||||
state.parseWaitingOnGC[i]->activate(rt);
|
||||
|
||||
AutoLockWorkerThreadState lock(state);
|
||||
|
||||
JS_ASSERT(state.parseWorklist.empty());
|
||||
state.parseWorklist.swap(state.parseWaitingOnGC);
|
||||
|
||||
state.notifyAll(WorkerThreadState::PRODUCER);
|
||||
}
|
||||
|
||||
void
|
||||
js::WaitForOffThreadParsingToFinish(JSRuntime *rt)
|
||||
{
|
||||
|
|
|
@ -71,6 +71,9 @@ class WorkerThreadState
|
|||
/* Shared worklist for parsing/emitting scripts on worker threads. */
|
||||
Vector<ParseTask*, 0, SystemAllocPolicy> parseWorklist, parseFinishedList;
|
||||
|
||||
/* Main-thread-only list of parse tasks waiting for an atoms-zone GC to complete. */
|
||||
Vector<ParseTask*, 0, SystemAllocPolicy> parseWaitingOnGC;
|
||||
|
||||
/* Worklist for source compression worker threads. */
|
||||
Vector<SourceCompressionTask *, 0, SystemAllocPolicy> compressionWorklist;
|
||||
|
||||
|
@ -230,6 +233,13 @@ StartOffThreadParseScript(JSContext *cx, const ReadOnlyCompileOptions &options,
|
|||
const jschar *chars, size_t length, HandleObject scopeChain,
|
||||
JS::OffThreadCompileCallback callback, void *callbackData);
|
||||
|
||||
/*
|
||||
* Called at the end of GC to enqueue any Parse tasks that were waiting on an
|
||||
* atoms-zone GC to finish.
|
||||
*/
|
||||
void
|
||||
EnqueuePendingParseTasksAfterGC(JSRuntime *rt);
|
||||
|
||||
/* Block until in progress and pending off thread parse jobs have finished. */
|
||||
void
|
||||
WaitForOffThreadParsingToFinish(JSRuntime *rt);
|
||||
|
@ -329,6 +339,9 @@ struct ParseTask
|
|||
// main thread.
|
||||
JSObject *scopeChain;
|
||||
|
||||
// Rooted pointer to the global object used by 'cx'.
|
||||
JSObject *exclusiveContextGlobal;
|
||||
|
||||
// Callback invoked off the main thread when the parse finishes.
|
||||
JS::OffThreadCompileCallback callback;
|
||||
void *callbackData;
|
||||
|
@ -343,11 +356,13 @@ struct ParseTask
|
|||
Vector<frontend::CompileError *> errors;
|
||||
bool overRecursed;
|
||||
|
||||
ParseTask(ExclusiveContext *cx, JSContext *initCx,
|
||||
ParseTask(ExclusiveContext *cx, JSObject *exclusiveContextGlobal, JSContext *initCx,
|
||||
const jschar *chars, size_t length, JSObject *scopeChain,
|
||||
JS::OffThreadCompileCallback callback, void *callbackData);
|
||||
bool init(JSContext *cx, const ReadOnlyCompileOptions &options);
|
||||
|
||||
void activate(JSRuntime *rt);
|
||||
|
||||
~ParseTask();
|
||||
};
|
||||
|
||||
|
|
|
@ -149,12 +149,10 @@ ErrorCopier::~ErrorCopier()
|
|||
JSContext *cx = ac.ref().context()->asJSContext();
|
||||
if (ac.ref().origin() != cx->compartment() && cx->isExceptionPending()) {
|
||||
RootedValue exc(cx, cx->getPendingException());
|
||||
if (exc.isObject() && exc.toObject().is<ErrorObject>() &&
|
||||
exc.toObject().as<ErrorObject>().getExnPrivate())
|
||||
{
|
||||
if (exc.isObject() && exc.toObject().is<ErrorObject>()) {
|
||||
cx->clearPendingException();
|
||||
ac.destroy();
|
||||
Rooted<JSObject*> errObj(cx, &exc.toObject());
|
||||
Rooted<ErrorObject*> errObj(cx, &exc.toObject().as<ErrorObject>());
|
||||
JSObject *copyobj = js_CopyErrorObject(cx, errObj, scope);
|
||||
if (copyobj)
|
||||
cx->setPendingException(ObjectValue(*copyobj));
|
||||
|
|
|
@ -160,6 +160,7 @@ UNIFIED_SOURCES += [
|
|||
'vm/CharacterEncoding.cpp',
|
||||
'vm/DateTime.cpp',
|
||||
'vm/Debugger.cpp',
|
||||
'vm/ErrorObject.cpp',
|
||||
'vm/ForkJoin.cpp',
|
||||
'vm/GlobalObject.cpp',
|
||||
'vm/Id.cpp',
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "vm/ErrorObject.h"
|
||||
|
||||
#include "vm/GlobalObject.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/Shape-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
/* static */ Shape *
|
||||
js::ErrorObject::assignInitialShape(ExclusiveContext *cx, Handle<ErrorObject*> obj)
|
||||
{
|
||||
MOZ_ASSERT(obj->nativeEmpty());
|
||||
|
||||
if (!obj->addDataProperty(cx, cx->names().fileName, FILENAME_SLOT, 0))
|
||||
return nullptr;
|
||||
if (!obj->addDataProperty(cx, cx->names().lineNumber, LINENUMBER_SLOT, 0))
|
||||
return nullptr;
|
||||
if (!obj->addDataProperty(cx, cx->names().columnNumber, COLUMNNUMBER_SLOT, 0))
|
||||
return nullptr;
|
||||
return obj->addDataProperty(cx, cx->names().stack, STACK_SLOT, 0);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
js::ErrorObject::init(JSContext *cx, Handle<ErrorObject*> obj, JSExnType type,
|
||||
ScopedJSFreePtr<JSErrorReport> *errorReport, HandleString fileName,
|
||||
HandleString stack, uint32_t lineNumber, uint32_t columnNumber,
|
||||
HandleString message)
|
||||
{
|
||||
// Null out early in case of error, for exn_finalize's sake.
|
||||
obj->initReservedSlot(ERROR_REPORT_SLOT, PrivateValue(nullptr));
|
||||
|
||||
if (!EmptyShape::ensureInitialCustomShape<ErrorObject>(cx, obj))
|
||||
return false;
|
||||
|
||||
// The .message property isn't part of the initial shape because it's
|
||||
// present in some error objects -- |Error.prototype|, |new Error("f")|,
|
||||
// |new Error("")| -- but not in others -- |new Error(undefined)|,
|
||||
// |new Error()|.
|
||||
RootedShape messageShape(cx);
|
||||
if (message) {
|
||||
messageShape = obj->addDataProperty(cx, cx->names().message, MESSAGE_SLOT, 0);
|
||||
if (!messageShape)
|
||||
return false;
|
||||
MOZ_ASSERT(messageShape->slot() == MESSAGE_SLOT);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(obj->nativeLookupPure(NameToId(cx->names().fileName))->slot() == FILENAME_SLOT);
|
||||
MOZ_ASSERT(obj->nativeLookupPure(NameToId(cx->names().lineNumber))->slot() == LINENUMBER_SLOT);
|
||||
MOZ_ASSERT(obj->nativeLookupPure(NameToId(cx->names().columnNumber))->slot() ==
|
||||
COLUMNNUMBER_SLOT);
|
||||
MOZ_ASSERT(obj->nativeLookupPure(NameToId(cx->names().stack))->slot() == STACK_SLOT);
|
||||
MOZ_ASSERT_IF(message,
|
||||
obj->nativeLookupPure(NameToId(cx->names().message))->slot() == MESSAGE_SLOT);
|
||||
|
||||
MOZ_ASSERT(JSEXN_ERR <= type && type < JSEXN_LIMIT);
|
||||
|
||||
JSErrorReport *report = errorReport ? errorReport->forget() : nullptr;
|
||||
obj->initReservedSlot(EXNTYPE_SLOT, Int32Value(type));
|
||||
obj->setReservedSlot(ERROR_REPORT_SLOT, PrivateValue(report));
|
||||
obj->initReservedSlot(FILENAME_SLOT, StringValue(fileName));
|
||||
obj->initReservedSlot(LINENUMBER_SLOT, Int32Value(lineNumber));
|
||||
obj->initReservedSlot(COLUMNNUMBER_SLOT, Int32Value(columnNumber));
|
||||
obj->initReservedSlot(STACK_SLOT, StringValue(stack));
|
||||
if (message)
|
||||
obj->nativeSetSlotWithType(cx, messageShape, StringValue(message));
|
||||
|
||||
if (report && report->originPrincipals)
|
||||
JS_HoldPrincipals(report->originPrincipals);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ ErrorObject *
|
||||
js::ErrorObject::create(JSContext *cx, JSExnType errorType, HandleString stack,
|
||||
HandleString fileName, uint32_t lineNumber, uint32_t columnNumber,
|
||||
ScopedJSFreePtr<JSErrorReport> *report, HandleString message)
|
||||
{
|
||||
Rooted<JSObject*> proto(cx, cx->global()->getOrCreateCustomErrorPrototype(cx, errorType));
|
||||
if (!proto)
|
||||
return nullptr;
|
||||
|
||||
Rooted<ErrorObject*> errObject(cx);
|
||||
{
|
||||
JSObject* obj = NewObjectWithGivenProto(cx, &ErrorObject::class_, proto, nullptr);
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
errObject = &obj->as<ErrorObject>();
|
||||
}
|
||||
|
||||
if (!ErrorObject::init(cx, errObject, errorType, report, fileName, stack,
|
||||
lineNumber, columnNumber, message))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return errObject;
|
||||
}
|
|
@ -9,16 +9,98 @@
|
|||
|
||||
#include "jsobj.h"
|
||||
|
||||
#include "vm/Shape.h"
|
||||
|
||||
struct JSExnPrivate;
|
||||
|
||||
/*
|
||||
* Initialize the exception constructor/prototype hierarchy.
|
||||
*/
|
||||
extern JSObject *
|
||||
js_InitExceptionClasses(JSContext *cx, JS::HandleObject obj);
|
||||
|
||||
namespace js {
|
||||
|
||||
class ErrorObject : public JSObject
|
||||
{
|
||||
static ErrorObject *
|
||||
createProto(JSContext *cx, JS::Handle<GlobalObject*> global, JSExnType type,
|
||||
JS::HandleObject proto);
|
||||
|
||||
/* For access to createProto. */
|
||||
friend JSObject *
|
||||
::js_InitExceptionClasses(JSContext *cx, JS::HandleObject global);
|
||||
|
||||
/* For access to assignInitialShape. */
|
||||
friend bool
|
||||
EmptyShape::ensureInitialCustomShape<ErrorObject>(ExclusiveContext *cx,
|
||||
Handle<ErrorObject*> obj);
|
||||
|
||||
/*
|
||||
* Assign the initial error shape to the empty object. (This shape does
|
||||
* *not* include .message, which must be added separately if needed; see
|
||||
* ErrorObject::init.)
|
||||
*/
|
||||
static Shape *
|
||||
assignInitialShape(ExclusiveContext *cx, Handle<ErrorObject*> obj);
|
||||
|
||||
static bool
|
||||
init(JSContext *cx, Handle<ErrorObject*> obj, JSExnType type,
|
||||
ScopedJSFreePtr<JSErrorReport> *errorReport, HandleString fileName, HandleString stack,
|
||||
uint32_t lineNumber, uint32_t columnNumber, HandleString message);
|
||||
|
||||
protected:
|
||||
static const uint32_t EXNTYPE_SLOT = 0;
|
||||
static const uint32_t ERROR_REPORT_SLOT = EXNTYPE_SLOT + 1;
|
||||
static const uint32_t FILENAME_SLOT = ERROR_REPORT_SLOT + 1;
|
||||
static const uint32_t LINENUMBER_SLOT = FILENAME_SLOT + 1;
|
||||
static const uint32_t COLUMNNUMBER_SLOT = LINENUMBER_SLOT + 1;
|
||||
static const uint32_t STACK_SLOT = COLUMNNUMBER_SLOT + 1;
|
||||
static const uint32_t MESSAGE_SLOT = STACK_SLOT + 1;
|
||||
|
||||
static const uint32_t RESERVED_SLOTS = MESSAGE_SLOT + 1;
|
||||
|
||||
public:
|
||||
static const Class class_;
|
||||
|
||||
JSExnPrivate *getExnPrivate() { return static_cast<JSExnPrivate*>(getPrivate()); }
|
||||
// Create an error of the given type corresponding to the provided location
|
||||
// info. If |message| is non-null, then the error will have a .message
|
||||
// property with that value; otherwise the error will have no .message
|
||||
// property.
|
||||
static ErrorObject *
|
||||
create(JSContext *cx, JSExnType type, HandleString stack, HandleString fileName,
|
||||
uint32_t lineNumber, uint32_t columnNumber, ScopedJSFreePtr<JSErrorReport> *report,
|
||||
HandleString message);
|
||||
|
||||
JSExnType type() const {
|
||||
return JSExnType(getReservedSlot(EXNTYPE_SLOT).toInt32());
|
||||
}
|
||||
|
||||
JSErrorReport * getErrorReport() const {
|
||||
void *priv = getReservedSlot(ERROR_REPORT_SLOT).toPrivate();
|
||||
return static_cast<JSErrorReport*>(priv);
|
||||
}
|
||||
|
||||
JSString * fileName() const {
|
||||
return getReservedSlot(FILENAME_SLOT).toString();
|
||||
}
|
||||
|
||||
uint32_t lineNumber() const {
|
||||
return getReservedSlot(LINENUMBER_SLOT).toInt32();
|
||||
}
|
||||
|
||||
uint32_t columnNumber() const {
|
||||
return getReservedSlot(COLUMNNUMBER_SLOT).toInt32();
|
||||
}
|
||||
|
||||
JSString * stack() const {
|
||||
return getReservedSlot(STACK_SLOT).toString();
|
||||
}
|
||||
|
||||
JSString * getMessage() const {
|
||||
HeapSlot &slot = const_cast<ErrorObject*>(this)->getReservedSlotRef(MESSAGE_SLOT);
|
||||
return slot.isString() ? slot.toString() : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
|
|
@ -560,7 +560,7 @@ CreateBlankProto(JSContext *cx, const Class *clasp, JSObject &proto, GlobalObjec
|
|||
JS_ASSERT(clasp != &JSFunction::class_);
|
||||
|
||||
RootedObject blankProto(cx, NewObjectWithGivenProto(cx, clasp, &proto, &global, SingletonObject));
|
||||
if (!blankProto)
|
||||
if (!blankProto || !blankProto->setDelegate(cx))
|
||||
return nullptr;
|
||||
|
||||
return blankProto;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "builtin/RegExp.h"
|
||||
#include "js/Vector.h"
|
||||
#include "vm/ErrorObject.h"
|
||||
|
||||
extern JSObject *
|
||||
js_InitObjectClass(JSContext *cx, js::HandleObject obj);
|
||||
|
@ -397,7 +398,7 @@ class GlobalObject : public JSObject
|
|||
return &self->getPrototype(JSProto_ArrayBuffer).toObject();
|
||||
}
|
||||
|
||||
JSObject *getOrCreateCustomErrorPrototype(JSContext *cx, int exnType) {
|
||||
JSObject *getOrCreateCustomErrorPrototype(JSContext *cx, JSExnType exnType) {
|
||||
JSProtoKey key = GetExceptionProtoKey(exnType);
|
||||
if (errorClassesInitialized())
|
||||
return &getPrototype(key).toObject();
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/Shape-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using js::frontend::TokenStream;
|
||||
|
||||
|
@ -273,10 +275,9 @@ RegExpObject::createShared(ExclusiveContext *cx, RegExpGuard *g)
|
|||
}
|
||||
|
||||
Shape *
|
||||
RegExpObject::assignInitialShape(ExclusiveContext *cx)
|
||||
RegExpObject::assignInitialShape(ExclusiveContext *cx, Handle<RegExpObject*> self)
|
||||
{
|
||||
JS_ASSERT(is<RegExpObject>());
|
||||
JS_ASSERT(nativeEmpty());
|
||||
JS_ASSERT(self->nativeEmpty());
|
||||
|
||||
JS_STATIC_ASSERT(LAST_INDEX_SLOT == 0);
|
||||
JS_STATIC_ASSERT(SOURCE_SLOT == LAST_INDEX_SLOT + 1);
|
||||
|
@ -285,10 +286,8 @@ RegExpObject::assignInitialShape(ExclusiveContext *cx)
|
|||
JS_STATIC_ASSERT(MULTILINE_FLAG_SLOT == IGNORE_CASE_FLAG_SLOT + 1);
|
||||
JS_STATIC_ASSERT(STICKY_FLAG_SLOT == MULTILINE_FLAG_SLOT + 1);
|
||||
|
||||
RootedObject self(cx, this);
|
||||
|
||||
/* The lastIndex property alone is writable but non-configurable. */
|
||||
if (!addDataProperty(cx, cx->names().lastIndex, LAST_INDEX_SLOT, JSPROP_PERMANENT))
|
||||
if (!self->addDataProperty(cx, cx->names().lastIndex, LAST_INDEX_SLOT, JSPROP_PERMANENT))
|
||||
return nullptr;
|
||||
|
||||
/* Remaining instance properties are non-writable and non-configurable. */
|
||||
|
@ -309,19 +308,8 @@ RegExpObject::init(ExclusiveContext *cx, HandleAtom source, RegExpFlag flags)
|
|||
{
|
||||
Rooted<RegExpObject *> self(cx, this);
|
||||
|
||||
if (nativeEmpty()) {
|
||||
if (isDelegate()) {
|
||||
if (!assignInitialShape(cx))
|
||||
return false;
|
||||
} else {
|
||||
RootedShape shape(cx, assignInitialShape(cx));
|
||||
if (!shape)
|
||||
return false;
|
||||
RootedObject proto(cx, self->getProto());
|
||||
EmptyShape::insertInitialShape(cx, shape, proto);
|
||||
}
|
||||
JS_ASSERT(!self->nativeEmpty());
|
||||
}
|
||||
if (!EmptyShape::ensureInitialCustomShape<RegExpObject>(cx, self))
|
||||
return false;
|
||||
|
||||
JS_ASSERT(self->nativeLookup(cx, NameToId(cx->names().lastIndex))->slot() ==
|
||||
LAST_INDEX_SLOT);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "gc/Marking.h"
|
||||
#include "gc/Zone.h"
|
||||
#include "vm/Shape.h"
|
||||
#if ENABLE_YARR_JIT
|
||||
#include "yarr/YarrJIT.h"
|
||||
#else
|
||||
|
@ -438,12 +439,18 @@ class RegExpObject : public JSObject
|
|||
private:
|
||||
friend class RegExpObjectBuilder;
|
||||
|
||||
/* For access to assignInitialShape. */
|
||||
friend bool
|
||||
EmptyShape::ensureInitialCustomShape<RegExpObject>(ExclusiveContext *cx,
|
||||
Handle<RegExpObject*> obj);
|
||||
|
||||
/*
|
||||
* Compute the initial shape to associate with fresh RegExp objects,
|
||||
* encoding their initial properties. Return the shape after
|
||||
* changing this regular expression object's last property to it.
|
||||
* changing |obj|'s last property to it.
|
||||
*/
|
||||
Shape *assignInitialShape(ExclusiveContext *cx);
|
||||
static Shape *
|
||||
assignInitialShape(ExclusiveContext *cx, Handle<RegExpObject*> obj);
|
||||
|
||||
bool init(ExclusiveContext *cx, HandleAtom source, RegExpFlag flags);
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include "vm/Shape.h"
|
||||
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
#include "jsobj.h"
|
||||
|
||||
#include "vm/Interpreter.h"
|
||||
|
@ -178,6 +180,39 @@ Shape::search(ExclusiveContext *cx, Shape *start, jsid id, Shape ***pspp, bool a
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
template<class ObjectSubclass>
|
||||
/* static */ inline bool
|
||||
EmptyShape::ensureInitialCustomShape(ExclusiveContext *cx, Handle<ObjectSubclass*> obj)
|
||||
{
|
||||
static_assert(mozilla::IsBaseOf<JSObject, ObjectSubclass>::value,
|
||||
"ObjectSubclass must be a subclass of JSObject");
|
||||
|
||||
// If the provided object has a non-empty shape, it was given the cached
|
||||
// initial shape when created: nothing to do.
|
||||
if (!obj->nativeEmpty())
|
||||
return true;
|
||||
|
||||
// If no initial shape was assigned, do so.
|
||||
RootedShape shape(cx, ObjectSubclass::assignInitialShape(cx, obj));
|
||||
if (!shape)
|
||||
return false;
|
||||
MOZ_ASSERT(!obj->nativeEmpty());
|
||||
|
||||
// If the object is a standard prototype -- |RegExp.prototype|,
|
||||
// |String.prototype|, |RangeError.prototype|, &c. -- GlobalObject.cpp's
|
||||
// |CreateBlankProto| marked it as a delegate. These are the only objects
|
||||
// of this class that won't use the standard prototype, and there's no
|
||||
// reason to pollute the initial shape cache with entries for them.
|
||||
if (obj->isDelegate())
|
||||
return true;
|
||||
|
||||
// Cache the initial shape for non-prototype objects, however, so that
|
||||
// future instances will begin life with that shape.
|
||||
RootedObject proto(cx, obj->getProto());
|
||||
EmptyShape::insertInitialShape(cx, shape, proto);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
AutoRooterGetterSetter::Inner::Inner(ThreadSafeContext *cx, uint8_t attrs,
|
||||
PropertyOp *pgetter_, StrictPropertyOp *psetter_)
|
||||
|
|
|
@ -1382,6 +1382,19 @@ struct EmptyShape : public js::Shape
|
|||
* and the table entry is purged.
|
||||
*/
|
||||
static void insertInitialShape(ExclusiveContext *cx, HandleShape shape, HandleObject proto);
|
||||
|
||||
/*
|
||||
* Some object subclasses are allocated with a built-in set of properties.
|
||||
* The first time such an object is created, these built-in properties must
|
||||
* be set manually, to compute an initial shape. Afterward, that initial
|
||||
* shape can be reused for newly-created objects that use the subclass's
|
||||
* standard prototype. This method should be used in a post-allocation
|
||||
* init method, to ensure that objects of such subclasses compute and cache
|
||||
* the initial shape, if it hasn't already been computed.
|
||||
*/
|
||||
template<class ObjectSubclass>
|
||||
static inline bool
|
||||
ensureInitialCustomShape(ExclusiveContext *cx, Handle<ObjectSubclass*> obj);
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -833,6 +833,7 @@ Activation::Activation(JSContext *cx, Kind kind)
|
|||
compartment_(cx->compartment()),
|
||||
prev_(cx->mainThread().activation_),
|
||||
savedFrameChain_(0),
|
||||
hideScriptedCallerCount_(0),
|
||||
kind_(kind)
|
||||
{
|
||||
cx->mainThread().activation_ = this;
|
||||
|
@ -841,6 +842,7 @@ Activation::Activation(JSContext *cx, Kind kind)
|
|||
Activation::~Activation()
|
||||
{
|
||||
JS_ASSERT(cx_->mainThread().activation_ == this);
|
||||
JS_ASSERT(hideScriptedCallerCount_ == 0);
|
||||
cx_->mainThread().activation_ = prev_;
|
||||
}
|
||||
|
||||
|
|
|
@ -1167,6 +1167,13 @@ class Activation
|
|||
// set).
|
||||
size_t savedFrameChain_;
|
||||
|
||||
// Counter incremented by JS::HideScriptedCaller and decremented by
|
||||
// JS::UnhideScriptedCaller. If > 0 for the top activation,
|
||||
// JS_DescribeScriptedCaller will return null instead of querying that
|
||||
// activation, which should prompt the caller to consult embedding-specific
|
||||
// data structures instead.
|
||||
size_t hideScriptedCallerCount_;
|
||||
|
||||
enum Kind { Interpreter, Jit, ForkJoin };
|
||||
Kind kind_;
|
||||
|
||||
|
@ -1218,6 +1225,17 @@ class Activation
|
|||
return savedFrameChain_ > 0;
|
||||
}
|
||||
|
||||
void hideScriptedCaller() {
|
||||
hideScriptedCallerCount_++;
|
||||
}
|
||||
void unhideScriptedCaller() {
|
||||
JS_ASSERT(hideScriptedCallerCount_ > 0);
|
||||
hideScriptedCallerCount_--;
|
||||
}
|
||||
bool scriptedCallerIsHidden() const {
|
||||
return hideScriptedCallerCount_ > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
Activation(const Activation &other) MOZ_DELETE;
|
||||
void operator=(const Activation &other) MOZ_DELETE;
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/Shape-inl.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
inline bool
|
||||
|
@ -20,18 +22,8 @@ StringObject::init(JSContext *cx, HandleString str)
|
|||
|
||||
Rooted<StringObject *> self(cx, this);
|
||||
|
||||
if (nativeEmpty()) {
|
||||
if (isDelegate()) {
|
||||
if (!assignInitialShape(cx))
|
||||
return false;
|
||||
} else {
|
||||
RootedShape shape(cx, assignInitialShape(cx));
|
||||
if (!shape)
|
||||
return false;
|
||||
RootedObject proto(cx, self->getProto());
|
||||
EmptyShape::insertInitialShape(cx, shape, proto);
|
||||
}
|
||||
}
|
||||
if (!EmptyShape::ensureInitialCustomShape<StringObject>(cx, self))
|
||||
return false;
|
||||
|
||||
JS_ASSERT(self->nativeLookup(cx, NameToId(cx->names().length))->slot() == LENGTH_SLOT);
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "jsobj.h"
|
||||
#include "jsstr.h"
|
||||
|
||||
#include "vm/Shape.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
class StringObject : public JSObject
|
||||
|
@ -57,12 +59,18 @@ class StringObject : public JSObject
|
|||
friend JSObject *
|
||||
::js_InitStringClass(JSContext *cx, js::HandleObject global);
|
||||
|
||||
/* For access to assignInitialShape. */
|
||||
friend bool
|
||||
EmptyShape::ensureInitialCustomShape<StringObject>(ExclusiveContext *cx,
|
||||
Handle<StringObject*> obj);
|
||||
|
||||
/*
|
||||
* Compute the initial shape to associate with fresh String objects, which
|
||||
* encodes the initial length property. Return the shape after changing
|
||||
* this String object's last property to it.
|
||||
* |obj|'s last property to it.
|
||||
*/
|
||||
Shape *assignInitialShape(JSContext *cx);
|
||||
static Shape *
|
||||
assignInitialShape(ExclusiveContext *cx, Handle<StringObject*> obj);
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
|
|
@ -120,7 +120,7 @@ interface ScheduledGCCallback : nsISupports
|
|||
/**
|
||||
* interface of Components.utils
|
||||
*/
|
||||
[scriptable, uuid(ef621cac-c818-464a-9fb1-9a35731a7f32)]
|
||||
[scriptable, uuid(e14f588b-63aa-4091-be82-a459a52f8ca6)]
|
||||
interface nsIXPCComponents_Utils : nsISupports
|
||||
{
|
||||
|
||||
|
@ -507,6 +507,17 @@ interface nsIXPCComponents_Utils : nsISupports
|
|||
*/
|
||||
nsIClassInfo getDOMClassInfo(in AString aClassName);
|
||||
|
||||
/**
|
||||
* Gets the incument global for the execution of this function. For internal
|
||||
* and testing use only.
|
||||
*
|
||||
* If |callback| is passed, it is invoked with the incumbent global as its
|
||||
* sole argument. This allows the incumbent global to be measured in callback
|
||||
* environments with no scripted frames on the stack.
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
jsval getIncumbentGlobal([optional] in jsval callback);
|
||||
|
||||
/**
|
||||
* Retrieve the last time, in microseconds since epoch, that a given
|
||||
* watchdog-related event occured.
|
||||
|
|
|
@ -3487,6 +3487,33 @@ nsXPCComponents_Utils::GetDOMClassInfo(const nsAString& aClassName,
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Utils::GetIncumbentGlobal(const Value &aCallback,
|
||||
JSContext *aCx, Value *aOut)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = mozilla::dom::GetIncumbentGlobal();
|
||||
RootedValue globalVal(aCx);
|
||||
|
||||
if (!global) {
|
||||
globalVal = NullValue();
|
||||
} else {
|
||||
// Note: We rely on the wrap call for outerization.
|
||||
globalVal = ObjectValue(*global->GetGlobalJSObject());
|
||||
if (!JS_WrapValue(aCx, &globalVal))
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Invoke the callback, if passed.
|
||||
if (aCallback.isObject()) {
|
||||
Value ignored;
|
||||
if (!JS_CallFunctionValue(aCx, nullptr, aCallback, 1, globalVal.address(), &ignored))
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aOut = globalVal;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Utils::GetWatchdogTimestamp(const nsAString& aCategory, PRTime *aOut)
|
||||
{
|
||||
|
|
|
@ -67,6 +67,7 @@ support-files =
|
|||
[test_paris_weakmap_keys.xul]
|
||||
[test_precisegc.xul]
|
||||
[test_sandboxImport.xul]
|
||||
[test_scriptSettings.xul]
|
||||
[test_weakmap_keys_preserved.xul]
|
||||
[test_weakmap_keys_preserved2.xul]
|
||||
[test_weakref.xul]
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=937317
|
||||
-->
|
||||
<window title="Mozilla Bug 937317"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=937317"
|
||||
target="_blank">Mozilla Bug 937317</a>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<iframe></iframe>
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
/** Test for the script settings stack. **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
const Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
var iwin = window[0];
|
||||
|
||||
// Smoketest.
|
||||
is(Cu.getIncumbentGlobal(), window, "smoketest");
|
||||
|
||||
// Calling a cross-compartment non-scripted function changes the
|
||||
// compartment, but not the incumbent script settings object.
|
||||
var sb = new Cu.Sandbox(window, { wantComponents: true });
|
||||
is(sb.Components.utils.getIncumbentGlobal(), window, "cross-compartment sb non-scripted");
|
||||
is(iwin.Components.utils.getIncumbentGlobal(), window, "cross-compartment win non-scripted");
|
||||
|
||||
// If we call a scripted function in the other compartment, that becomes
|
||||
// the incumbent script.
|
||||
function gib() { return Components.utils.getIncumbentGlobal(); };
|
||||
Cu.evalInSandbox(gib.toSource(), sb);
|
||||
iwin.eval(gib.toSource());
|
||||
is(sb.gib(), sb, "cross-compartment sb scripted");
|
||||
is(iwin.gib(), iwin, "cross-compartment win scripted");
|
||||
|
||||
// Eval-ing top-level script in another component makes that compartment the
|
||||
// incumbent script.
|
||||
is(Cu.evalInSandbox('Components.utils.getIncumbentGlobal()', sb), sb, 'eval sb');
|
||||
is(iwin.eval('Components.utils.getIncumbentGlobal()'), iwin, 'eval iwin');
|
||||
|
||||
// Make sure that the callback mechanism works.
|
||||
function makeCallback(expectedGlobal, deferred, kind) {
|
||||
function cb(incumbentGlobal) {
|
||||
is(incumbentGlobal, expectedGlobal, "Callback got the right incumbent global: " + kind);
|
||||
if (deferred)
|
||||
deferred.resolve();
|
||||
}
|
||||
info("Generated callback: " + kind);
|
||||
return cb;
|
||||
}
|
||||
|
||||
var bound = Cu.getIncumbentGlobal.bind(Cu, makeCallback(window, undefined, "simple bound"));
|
||||
is(bound(), window, "Bound method returns the right global");
|
||||
|
||||
// Callbacks grab the incumbent script at the time of invocation.
|
||||
//
|
||||
// Note - We avoid calling the initial defer |d| so that it's not in-scope for everything below.
|
||||
let initialDefer = Promise.defer();
|
||||
setTimeout(Cu.getIncumbentGlobal.bind(Cu, makeCallback(window, initialDefer, "same-global setTimeout")), 0);
|
||||
initialDefer.promise.then(function() {
|
||||
|
||||
// Try cross-global setTimeout where |window| is the incumbent script when the callback is created.
|
||||
let d = Promise.defer();
|
||||
iwin.setTimeout(Cu.getIncumbentGlobal.bind(Cu, makeCallback(window, d, "cross-global setTimeout by |window|")), 0);
|
||||
return d.promise;
|
||||
}).then(function() {
|
||||
|
||||
// Try cross-global setTimeout where |iwin| is the incumbent script when the callback is created.
|
||||
let d = Promise.defer();
|
||||
iwin.wrappedJSObject.timeoutFun = Cu.getIncumbentGlobal.bind(Cu, makeCallback(iwin, d, "cross-global setTimeout by |iwin|"));
|
||||
iwin.eval('setTimeout(timeoutFun, 0);');
|
||||
return d.promise;
|
||||
}).then(function() {
|
||||
|
||||
// The incumbent script override doesn't take effect if the callback is scripted.
|
||||
let d = Promise.defer();
|
||||
iwin.wrappedJSObject.timeoutFun2 = Cu.getIncumbentGlobal.bind(Cu, makeCallback(iwin, d, "cross-global setTimeout of scripted function"));
|
||||
iwin.eval('let timeoutFun2Wrapper = function() { timeoutFun2(); }');
|
||||
setTimeout(iwin.wrappedJSObject.timeoutFun2Wrapper, 0);
|
||||
return d.promise;
|
||||
}).then(function() {
|
||||
|
||||
// Try event listeners.
|
||||
let d = Promise.defer();
|
||||
let body = iwin.document.body;
|
||||
body.addEventListener('click', Cu.getIncumbentGlobal.bind(Cu, makeCallback(window, d, "cross-global event listener")));
|
||||
body.dispatchEvent(new iwin.MouseEvent('click'));
|
||||
return d.promise;
|
||||
|
||||
}).then(function() {
|
||||
|
||||
// Try an event handler set by |iwin|.
|
||||
let d = Promise.defer();
|
||||
let body = iwin.document.body;
|
||||
iwin.wrappedJSObject.handler = Cu.getIncumbentGlobal.bind(Cu, makeCallback(iwin, d, "cross-global event handler"));
|
||||
iwin.eval('document.body.onmousemove = handler');
|
||||
body.dispatchEvent(new iwin.MouseEvent('mousemove'));
|
||||
return d.promise;
|
||||
|
||||
}).then(function() {
|
||||
|
||||
// Try an event handler compiled by a content attribute.
|
||||
let d = Promise.defer();
|
||||
let body = iwin.document.body;
|
||||
iwin.wrappedJSObject.innerHandler = Cu.getIncumbentGlobal.bind(Cu, makeCallback(iwin, d, "cross-global compiled event handler"));
|
||||
iwin.eval("document.body.setAttribute('onmouseout', 'innerHandler()')");
|
||||
body.dispatchEvent(new iwin.MouseEvent('mouseout'));
|
||||
return d.promise;
|
||||
}).then(function() {
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -33,6 +33,9 @@
|
|||
#include "nsIDOMHTMLElement.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsLayoutStylesheetCache.h"
|
||||
#ifdef ACCESSIBILITY
|
||||
#include "mozilla/a11y/DocAccessible.h"
|
||||
#endif
|
||||
#include "mozilla/BasicEvents.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
|
@ -1565,6 +1568,16 @@ nsDocumentViewer::Destroy()
|
|||
// cache ourselves.
|
||||
shEntry->SyncPresentationState();
|
||||
|
||||
// Shut down accessibility for the document before we start to tear it down.
|
||||
#ifdef ACCESSIBILITY
|
||||
if (mPresShell) {
|
||||
a11y::DocAccessible* docAcc = mPresShell->GetDocAccessible();
|
||||
if (docAcc) {
|
||||
docAcc->Shutdown();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Break the link from the document/presentation to the docshell, so that
|
||||
// link traversals cannot affect the currently-loaded document.
|
||||
// When the presentation is restored, Open() and InitInternal() will reset
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "nsRenderingContext.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsCSSRendering.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsThemeConstants.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsIDocShell.h"
|
||||
|
@ -4775,12 +4774,6 @@ nsLayoutUtils::SurfaceFromElement(nsIImageLoadingContent* aElement,
|
|||
wantImageSurface = true;
|
||||
}
|
||||
|
||||
// Push a null JSContext on the stack so that code that runs within
|
||||
// the below code doesn't think it's being called by JS. See bug
|
||||
// 604262.
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
|
||||
nsCOMPtr<imgIRequest> imgRequest;
|
||||
rv = aElement->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
|
||||
getter_AddRefs(imgRequest));
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
#include "nsIDocument.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsViewManager.h"
|
||||
#include "GeckoProfiler.h"
|
||||
|
@ -48,6 +47,7 @@
|
|||
#include "Layers.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "nsIFrameRequestCallback.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::widget;
|
||||
|
@ -722,8 +722,7 @@ nsRefreshDriver::AdvanceTimeAndRefresh(int64_t aMilliseconds)
|
|||
mMostRecentRefreshEpochTime += aMilliseconds * 1000;
|
||||
mMostRecentRefresh += TimeDuration::FromMilliseconds((double) aMilliseconds);
|
||||
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
mozilla::dom::AutoSystemCaller asc;
|
||||
DoTick();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<script type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestLongerTimeout(2);
|
||||
|
||||
var canvases = [];
|
||||
function callbackTestCanvas(canvas)
|
||||
|
|
|
@ -42,9 +42,9 @@
|
|||
#include "nsAttrValueInlines.h"
|
||||
#include "mozilla/Selection.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsTextNode.h"
|
||||
#include "nsStyleSet.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
#define DEFAULT_COLUMN_WIDTH 20
|
||||
|
||||
|
@ -274,8 +274,7 @@ nsTextControlFrame::EnsureEditorInitialized()
|
|||
|
||||
// Time to mess with our security context... See comments in GetValue()
|
||||
// for why this is needed.
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
mozilla::dom::AutoSystemCaller asc;
|
||||
|
||||
// Make sure that we try to focus the content even if the method fails
|
||||
class EnsureSetFocus {
|
||||
|
|
|
@ -2352,13 +2352,12 @@ SumLineCrossSizes(const nsTArray<FlexLine>& aLines)
|
|||
}
|
||||
|
||||
nscoord
|
||||
nsFlexContainerFrame::ComputeFlexContainerCrossSize(
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
const FlexboxAxisTracker& aAxisTracker,
|
||||
const nsTArray<FlexLine>& aLines,
|
||||
nscoord aAvailableHeightForContent,
|
||||
bool* aIsDefinite,
|
||||
nsReflowStatus& aStatus)
|
||||
nsFlexContainerFrame::ComputeCrossSize(const nsHTMLReflowState& aReflowState,
|
||||
const FlexboxAxisTracker& aAxisTracker,
|
||||
const nsTArray<FlexLine>& aLines,
|
||||
nscoord aAvailableHeightForContent,
|
||||
bool* aIsDefinite,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
MOZ_ASSERT(aIsDefinite, "outparam pointer must be non-null");
|
||||
|
||||
|
@ -2691,10 +2690,8 @@ nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
|
|||
|
||||
bool isCrossSizeDefinite;
|
||||
const nscoord contentBoxCrossSize =
|
||||
ComputeFlexContainerCrossSize(aReflowState, axisTracker,
|
||||
lines,
|
||||
availableHeightForContent,
|
||||
&isCrossSizeDefinite, aStatus);
|
||||
ComputeCrossSize(aReflowState, axisTracker, lines,
|
||||
availableHeightForContent, &isCrossSizeDefinite, aStatus);
|
||||
|
||||
// Set up state for cross-axis alignment, at a high level (outside the
|
||||
// scope of a particular flex line)
|
||||
|
|
|
@ -104,12 +104,12 @@ protected:
|
|||
nscoord GetMainSizeFromReflowState(const nsHTMLReflowState& aReflowState,
|
||||
const FlexboxAxisTracker& aAxisTracker);
|
||||
|
||||
nscoord ComputeFlexContainerCrossSize(const nsHTMLReflowState& aReflowState,
|
||||
const FlexboxAxisTracker& aAxisTracker,
|
||||
const nsTArray<FlexLine>& aLines,
|
||||
nscoord aAvailableHeightForContent,
|
||||
bool* aIsDefinite,
|
||||
nsReflowStatus& aStatus);
|
||||
nscoord ComputeCrossSize(const nsHTMLReflowState& aReflowState,
|
||||
const FlexboxAxisTracker& aAxisTracker,
|
||||
const nsTArray<FlexLine>& aLines,
|
||||
nscoord aAvailableHeightForContent,
|
||||
bool* aIsDefinite,
|
||||
nsReflowStatus& aStatus);
|
||||
|
||||
nsresult SizeItemInCrossAxis(nsPresContext* aPresContext,
|
||||
const FlexboxAxisTracker& aAxisTracker,
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "nsImageFrame.h"
|
||||
#include "nsIImageLoadingContent.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "nsContentList.h"
|
||||
|
@ -75,12 +74,6 @@ nsVideoFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
|
|||
mPosterImage = element;
|
||||
NS_ENSURE_TRUE(mPosterImage, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
// Push a null JSContext on the stack so that code that runs
|
||||
// within the below code doesn't think it's being called by
|
||||
// JS. See bug 604262.
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
|
||||
// Set the nsImageLoadingContent::ImageState() to 0. This means that the
|
||||
// image will always report its state as 0, so it will never be reframed
|
||||
// to show frames for loading or the broken image icon. This is important,
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
<style>
|
||||
.flexContainer {
|
||||
display: inline-block;
|
||||
flex-wrap: wrap;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: lightblue;
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
<style>
|
||||
.flexContainer {
|
||||
display: inline-block;
|
||||
flex-wrap: wrap;
|
||||
width: 40px;
|
||||
/* Split testcase's 40px height into 20px of padding-top and 20px of
|
||||
height, to set aside space for the testcase's (invisible) second line
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
div.flexbox {
|
||||
border: 1px dashed blue;
|
||||
font-size: 10px;
|
||||
flex-direction: column;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
div.a, div.b, div.c { float: left }
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче