This commit is contained in:
Wes Kocher 2013-12-06 20:48:11 -06:00
Родитель b26cf505f9 7d835088c4
Коммит 7ddfa23f22
156 изменённых файлов: 3503 добавлений и 2414 удалений

Просмотреть файл

@ -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)')

Просмотреть файл

@ -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);

191
dom/base/ScriptSettings.cpp Normal file
Просмотреть файл

@ -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

115
dom/base/ScriptSettings.h Normal file
Просмотреть файл

@ -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.

Просмотреть файл

@ -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, &copy->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, &copy->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, &copyReport, 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',

106
js/src/vm/ErrorObject.cpp Normal file
Просмотреть файл

@ -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 }

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше