Compare commits

...
Author SHA1 Message Date
wolfbeast 4077c19d3d Port fix_bug_816784.patch for bug #816784 2018-06-11 21:13:24 +02:00
wolfbeast b64ff9dae6 Revert "Part 1 - Use a 2d hashmap to store cross compartment wrappers."
This reverts commit fb367661c3.
2018-06-11 16:17:44 +02:00
wolfbeast fb367661c3 Part 1 - Use a 2d hashmap to store cross compartment wrappers.
Now we use a flat hashmap to store CCWs, which when we want to nuke wrappers
to a target compartment, we need to iterate every single one to find them. But if we
use a 2d hashmap to store CCWs by their target compartment, we can walk through
only the wrappers that we're targeting.
2018-06-11 16:07:34 +02:00
2 changed files with 113 additions and 18 deletions

No files matched your search

+110 -16
View File
@@ -67,6 +67,7 @@
#include "mozilla/Likely.h"
#include "mozilla/Sprintf.h"
#include "mozilla/Unused.h"
#include "../../js/public/HashTable.h"
// Other Classes
#include "mozilla/dom/BarProps.h"
@@ -9450,6 +9451,96 @@ struct BrowserCompartmentMatcher : public js::CompartmentFilter {
}
};
class MultiCompartmentMatcher : public js::CompartmentFilter {
friend class WindowRequestCleanupEvent;
js::HashSet<JSCompartment*,js::DefaultHasher<JSCompartment*>,js::SystemAllocPolicy> compartments;
MultiCompartmentMatcher()
{
compartments.init();
}
public:
virtual bool match(JSCompartment* c) const override
{
return compartments.has(c);
}
};
class PendingWindows {
friend class WindowRequestCleanupEvent;
friend class WindowDestroyedEvent;
nsCOMArray<nsIWeakReference> windows;
};
// only to be accessed from main thread
static PendingWindows gPendingWindows;
// if set to >1, then not all js::NukeCrossCompartmentWrappers() happen soon
#define START_NUKING_WINDOWS_COUNT (10)
class WindowRequestCleanupEvent : public Runnable
{
friend class WindowDestroyedEvent;
WindowRequestCleanupEvent() {
}
public:
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread()); // accesses are only okay in main thread
if (gPendingWindows.windows.Count() >= START_NUKING_WINDOWS_COUNT) {
AutoSafeJSContext cx;
MultiCompartmentMatcher multiCompartmentMatchers[js::NUM_NukeReferencesToWindow];
#if defined(DEBUG)
printf_stderr("Nuking wrappers for %d compartments at once.\n",
gPendingWindows.windows.Count());
#endif
for (int i = 0; i<gPendingWindows.windows.Count(); i++) {
nsCOMPtr<nsISupports> window = do_QueryReferent(gPendingWindows.windows[i]);
if (window) {
nsGlobalWindow* win = nsGlobalWindow::FromSupports(window);
nsGlobalWindow* currentInner = win->IsInnerWindow() ? win : win->GetCurrentInnerWindowInternal();
NS_ENSURE_TRUE(currentInner, NS_OK);
JS::Rooted<JSObject*> obj(cx, currentInner->FastGetGlobalJSObject());
// We only want to nuke wrappers for the chrome->content case
if (obj && !js::IsSystemCompartment(js::GetObjectCompartment(obj))) {
multiCompartmentMatchers[
win->IsInnerWindow()
? js::DontNukeWindowReferences
: js::NukeWindowReferences
].compartments.putNew(js::GetObjectCompartment(obj));
}
}
}
for (int i = 0;i<js::NUM_NukeReferencesToWindow;i++) {
MultiCompartmentMatcher& multiCompartmentMatcher =
multiCompartmentMatchers[(js::NukeReferencesToWindow) i];
if (!multiCompartmentMatcher.compartments.empty()) {
js::NukeCrossCompartmentWrappers(cx,
BrowserCompartmentMatcher(),
multiCompartmentMatcher,
(js::NukeReferencesToWindow) i);
}
}
gPendingWindows.windows.Clear();
}
return NS_OK;
}
};
class WindowDestroyedEvent : public Runnable
{
@@ -9484,22 +9575,25 @@ public:
}
#endif
nsCOMPtr<nsISupports> window = do_QueryReferent(mWindow);
if (!skipNukeCrossCompartment && window) {
nsGlobalWindow* win = nsGlobalWindow::FromSupports(window);
nsGlobalWindow* currentInner = win->IsInnerWindow() ? win : win->GetCurrentInnerWindowInternal();
NS_ENSURE_TRUE(currentInner, NS_OK);
AutoSafeJSContext cx;
JS::Rooted<JSObject*> obj(cx, currentInner->FastGetGlobalJSObject());
// We only want to nuke wrappers for the chrome->content case
if (obj && !js::IsSystemCompartment(js::GetObjectCompartment(obj))) {
js::NukeCrossCompartmentWrappers(cx,
BrowserCompartmentMatcher(),
js::SingleCompartment(js::GetObjectCompartment(obj)),
win->IsInnerWindow() ? js::DontNukeWindowReferences
: js::NukeWindowReferences);
}
if (!skipNukeCrossCompartment) {
MOZ_ASSERT(NS_IsMainThread()); // accesses are only okay in main thread
/*
js::NukeCrossCompartmentWrappers() may be a very expensive operation
(its runtime is linear to the number of compartments). Thus,
do not call js::NukeCrossCompartmentWrappers() directly. Instead,
add all windows for such a call to the gPendingWindows list and emit
a WindowRequestCleanupEvent. In loaded situations, the
WindowRequestCleanupEvent needs some time to be actually processed.
During this time, more WindowDestroyedEvent come in, adding more
windows to the gPendingWindows list. Once the first
WindowRequestCleanupEvent is processed, the gPendingWindows list
has coalesced some windows to be processed. Hence, these windows can
be processed at once, reducing the impact of the expensive
js::NukeCrossCompartmentWrappers() operation.
*/
gPendingWindows.windows.AppendObject(mWindow);
nsCOMPtr<nsIRunnable> runnable = new WindowRequestCleanupEvent();
return NS_DispatchToCurrentThread(runnable);
}
return NS_OK;
+3 -2
View File
@@ -1160,8 +1160,9 @@ RegExpToSharedNonInline(JSContext* cx, JS::HandleObject regexp, RegExpGuard* sha
/* Implemented in jswrapper.cpp. */
typedef enum NukeReferencesToWindow {
NukeWindowReferences,
DontNukeWindowReferences
NukeWindowReferences = 0,
DontNukeWindowReferences,
NUM_NukeReferencesToWindow
} NukeReferencesToWindow;
/*