зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
25a074d342
|
@ -0,0 +1,6 @@
|
|||
[source.crates-io]
|
||||
registry = 'https://github.com/rust-lang/crates.io-index'
|
||||
replace-with = 'vendored-sources'
|
||||
|
||||
[source.vendored-sources]
|
||||
directory = '@top_srcdir@/third_party/rust'
|
|
@ -445,9 +445,16 @@ EventTree::Mutated(AccMutationEvent* aEv)
|
|||
// discard those subtree mutations as we are no longer interested in them.
|
||||
UniquePtr<EventTree>* node = &mFirst;
|
||||
while (*node) {
|
||||
if ((*node)->mContainer == aEv->mAccessible) {
|
||||
*node = Move((*node)->mNext);
|
||||
break;
|
||||
Accessible* cntr = (*node)->mContainer;
|
||||
while (cntr != mContainer) {
|
||||
if (cntr == aEv->mAccessible) {
|
||||
*node = Move((*node)->mNext);
|
||||
break;
|
||||
}
|
||||
cntr = cntr->Parent();
|
||||
}
|
||||
if (cntr == aEv->mAccessible) {
|
||||
continue;
|
||||
}
|
||||
node = &(*node)->mNext;
|
||||
}
|
||||
|
|
|
@ -337,7 +337,7 @@ function eventQueue(aEventType)
|
|||
if (matchIdx == -1 || eventSeq.length > 0)
|
||||
matchIdx = scnIdx;
|
||||
|
||||
// Report everythign is ok.
|
||||
// Report everything is ok.
|
||||
for (var idx = 0; idx < eventSeq.length; idx++) {
|
||||
var checker = eventSeq[idx];
|
||||
|
||||
|
@ -346,15 +346,15 @@ function eventQueue(aEventType)
|
|||
"' succeed. ";
|
||||
|
||||
if (checker.unexpected) {
|
||||
if (checker.todo) {
|
||||
todo(false, "Event " + typeStr + " event is still missing");
|
||||
}
|
||||
else {
|
||||
ok(true, msg + "There's no unexpected " + typeStr + " event.");
|
||||
}
|
||||
ok(true, msg + `There's no unexpected '${typeStr}' event.`);
|
||||
}
|
||||
else {
|
||||
ok(true, msg + "Event " + typeStr + " was handled.");
|
||||
if (checker.todo) {
|
||||
todo(false, `Todo event '${typeStr}' was caught`);
|
||||
}
|
||||
else {
|
||||
ok(true, `${msg} Event '${typeStr}' was handled.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -378,15 +378,13 @@ function eventQueue(aEventType)
|
|||
ok(false, msg + "Dupe " + typeStr + " event.");
|
||||
|
||||
if (checker.unexpected) {
|
||||
if (checker.todo) {
|
||||
todo(checker.wasCaught,
|
||||
"Event " + typeStr + " event is still missing");
|
||||
}
|
||||
else if (checker.wasCaught) {
|
||||
if (checker.wasCaught) {
|
||||
ok(false, msg + "There's unexpected " + typeStr + " event.");
|
||||
}
|
||||
} else if (!checker.wasCaught) {
|
||||
ok(false, msg + typeStr + " event was missed.");
|
||||
}
|
||||
else if (!checker.wasCaught) {
|
||||
var rf = checker.todo ? todo : ok;
|
||||
rf(false, `${msg} '${typeStr} event is missed.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -596,6 +594,7 @@ function eventQueue(aEventType)
|
|||
|
||||
while (aEventSeq.idx < aEventSeq.length &&
|
||||
(aEventSeq[aEventSeq.idx].unexpected ||
|
||||
aEventSeq[aEventSeq.idx].todo ||
|
||||
aEventSeq[aEventSeq.idx].async ||
|
||||
aEventSeq[aEventSeq.idx].wasCaught > 0)) {
|
||||
aEventSeq.idx++;
|
||||
|
@ -612,7 +611,8 @@ function eventQueue(aEventType)
|
|||
// Check if we have unhandled async (can be anywhere in the sequance) or
|
||||
// sync expcected events yet.
|
||||
for (var idx = 0; idx < aEventSeq.length; idx++) {
|
||||
if (!aEventSeq[idx].unexpected && !aEventSeq[idx].wasCaught)
|
||||
if (!aEventSeq[idx].unexpected && !aEventSeq[idx].todo &&
|
||||
!aEventSeq[idx].wasCaught)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -636,7 +636,7 @@ function eventQueue(aEventType)
|
|||
for (var scnIdx = 0; scnIdx < this.mScenarios.length; scnIdx++) {
|
||||
var eventSeq = this.mScenarios[scnIdx];
|
||||
for (var idx = 0; idx < eventSeq.length; idx++) {
|
||||
if (eventSeq[idx].unexpected)
|
||||
if (eventSeq[idx].unexpected || eventSeq[idx].todo)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -648,7 +648,7 @@ function eventQueue(aEventType)
|
|||
function eventQueue_isUnexpectedEventsScenario(aScenario)
|
||||
{
|
||||
for (var idx = 0; idx < aScenario.length; idx++) {
|
||||
if (!aScenario[idx].unexpected)
|
||||
if (!aScenario[idx].unexpected && !aScenario[idx].todo)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1686,8 +1686,6 @@ function todo_invokerChecker(aEventType, aTargetOrFunc, aTargetFuncArg)
|
|||
{
|
||||
this.__proto__ = new invokerChecker(aEventType, aTargetOrFunc,
|
||||
aTargetFuncArg, true);
|
||||
|
||||
this.unexpected = true;
|
||||
this.todo = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -487,6 +487,41 @@
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert text nodes under direct and grand children, and then hide
|
||||
* their container by means of aria-owns.
|
||||
*
|
||||
* Markup:
|
||||
* <div id="t7_moveplace" aria-owns="t7_c"></div>
|
||||
* <div id="t7_c">
|
||||
* <div id="t7_c_directchild">ha</div>
|
||||
* <div><div id="t7_c_grandchild">ha</div></div>
|
||||
* </div>
|
||||
*/
|
||||
function test7()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new todo_invokerChecker(EVENT_HIDE, getNode('t7_c')),
|
||||
new invokerChecker(EVENT_SHOW, getNode('t7_c')),
|
||||
new invokerChecker(EVENT_REORDER, getNode('t7')),
|
||||
new unexpectedInvokerChecker(EVENT_REORDER, getNode('t7_c_directchild')),
|
||||
new unexpectedInvokerChecker(EVENT_REORDER, getNode('t7_c_grandchild')),
|
||||
new unexpectedInvokerChecker(EVENT_SHOW, () => getNode('t7_c_directchild').firstChild),
|
||||
new unexpectedInvokerChecker(EVENT_SHOW, () => getNode('t7_c_grandchild').firstChild)
|
||||
];
|
||||
|
||||
this.invoke = function test7_invoke()
|
||||
{
|
||||
getNode('t7_c_directchild').textContent = 'ha';
|
||||
getNode('t7_c_grandchild').textContent = 'ha';
|
||||
getNode('t7_moveplace').setAttribute('aria-owns', 't7_c');
|
||||
};
|
||||
|
||||
this.getID = function test7_getID() {
|
||||
return "Show child accessibles and then hide their container";
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Do tests.
|
||||
|
||||
|
@ -519,6 +554,7 @@
|
|||
gQueue.push(new test4());
|
||||
gQueue.push(new test5());
|
||||
gQueue.push(new test6());
|
||||
gQueue.push(new test7());
|
||||
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
|
@ -612,5 +648,13 @@
|
|||
|
||||
<div id="t6">
|
||||
</div>
|
||||
|
||||
<div id="t7">
|
||||
<div id="t7_moveplace"></div>
|
||||
<div id="t7_c">
|
||||
<div><div id="t7_c_grandchild"></div></div>
|
||||
<div id="t7_c_directchild"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -4,26 +4,23 @@
|
|||
const gBaseURL = "https://example.com/browser/browser/base/content/test/general/";
|
||||
|
||||
add_task(function *() {
|
||||
let tab = gBrowser.addTab();
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gBaseURL + "subtst_contextmenu.html");
|
||||
|
||||
gBrowser.selectedTab = tab;
|
||||
yield promiseTabLoadEvent(tab, gBaseURL + "subtst_contextmenu.html");
|
||||
|
||||
let popupShownPromise = promiseWaitForEvent(window, "popupshown", true);
|
||||
let contextMenu = document.getElementById("contentAreaContextMenu");
|
||||
|
||||
// Get the point of the element with the page menu (test-pagemenu) and
|
||||
// synthesize a right mouse click there.
|
||||
let eventDetails = { type : "contextmenu", button : 2 };
|
||||
let rect = browser.contentWindow.document.getElementById("test-pagemenu").getBoundingClientRect();
|
||||
EventUtils.synthesizeMouse(browser, rect.x + rect.width / 2, rect.y + rect.height / 2, eventDetails, window);
|
||||
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
|
||||
yield BrowserTestUtils.synthesizeMouse("#test-pagemenu", 5, 5, { type : "contextmenu", button : 2 }, tab.linkedBrowser);
|
||||
let event = yield popupShownPromise;
|
||||
|
||||
let contextMenu = document.getElementById("contentAreaContextMenu");
|
||||
checkMenu(contextMenu);
|
||||
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
|
||||
contextMenu.hidePopup();
|
||||
gBrowser.removeCurrentTab();
|
||||
yield popupHiddenPromise;
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
function checkItems(menuitem, arr)
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "js/UbiNodeDominatorTree.h"
|
||||
#include "js/UbiNodeShortestPaths.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/devtools/AutoMemMap.h"
|
||||
#include "mozilla/devtools/CoreDump.pb.h"
|
||||
#include "mozilla/devtools/DeserializedNode.h"
|
||||
|
@ -62,9 +62,9 @@ using JS::ubi::ShortestPaths;
|
|||
MallocSizeOf
|
||||
GetCurrentThreadDebuggerMallocSizeOf()
|
||||
{
|
||||
auto ccrt = CycleCollectedJSRuntime::Get();
|
||||
MOZ_ASSERT(ccrt);
|
||||
auto cx = ccrt->Context();
|
||||
auto ccjscx = CycleCollectedJSContext::Get();
|
||||
MOZ_ASSERT(ccjscx);
|
||||
auto cx = ccjscx->Context();
|
||||
MOZ_ASSERT(cx);
|
||||
auto mallocSizeOf = JS::dbg::GetDebuggerMallocSizeOf(cx);
|
||||
MOZ_ASSERT(mallocSizeOf);
|
||||
|
@ -555,9 +555,9 @@ HeapSnapshot::ComputeDominatorTree(ErrorResult& rv)
|
|||
{
|
||||
Maybe<JS::ubi::DominatorTree> maybeTree;
|
||||
{
|
||||
auto ccrt = CycleCollectedJSRuntime::Get();
|
||||
MOZ_ASSERT(ccrt);
|
||||
auto cx = ccrt->Context();
|
||||
auto ccjscx = CycleCollectedJSContext::Get();
|
||||
MOZ_ASSERT(ccjscx);
|
||||
auto cx = ccjscx->Context();
|
||||
MOZ_ASSERT(cx);
|
||||
JS::AutoCheckCannotGC nogc(cx);
|
||||
maybeTree = JS::ubi::DominatorTree::Create(cx, nogc, getRoot());
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "gmock/gmock.h"
|
||||
#include "mozilla/devtools/HeapSnapshot.h"
|
||||
#include "mozilla/dom/ChromeUtils.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "js/Principals.h"
|
||||
#include "js/UbiNode.h"
|
||||
|
@ -60,7 +60,7 @@ struct DevTools : public ::testing::Test {
|
|||
}
|
||||
|
||||
JSContext* getContext() {
|
||||
return CycleCollectedJSRuntime::Get()->Context();
|
||||
return CycleCollectedJSContext::Get()->Context();
|
||||
}
|
||||
|
||||
static void reportError(JSContext* cx, const char* message, JSErrorReport* report) {
|
||||
|
|
|
@ -1335,14 +1335,14 @@ Animation::GetRenderedDocument() const
|
|||
void
|
||||
Animation::DoFinishNotification(SyncNotifyFlag aSyncNotifyFlag)
|
||||
{
|
||||
CycleCollectedJSRuntime* runtime = CycleCollectedJSRuntime::Get();
|
||||
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
||||
|
||||
if (aSyncNotifyFlag == SyncNotifyFlag::Sync) {
|
||||
DoFinishNotificationImmediately();
|
||||
} else if (!mFinishNotificationTask.IsPending()) {
|
||||
RefPtr<nsRunnableMethod<Animation>> runnable =
|
||||
NewRunnableMethod(this, &Animation::DoFinishNotificationImmediately);
|
||||
runtime->DispatchToMicroTask(do_AddRef(runnable));
|
||||
context->DispatchToMicroTask(do_AddRef(runnable));
|
||||
mFinishNotificationTask = runnable.forget();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "jsfriendapi.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/CondVar.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/dom/asmjscache/PAsmJSCacheEntryChild.h"
|
||||
#include "mozilla/dom/asmjscache/PAsmJSCacheEntryParent.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/ThreadLocal.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "xpcpublic.h"
|
||||
|
@ -289,14 +289,14 @@ namespace danger {
|
|||
JSContext*
|
||||
GetJSContext()
|
||||
{
|
||||
return CycleCollectedJSRuntime::Get()->Context();
|
||||
return CycleCollectedJSContext::Get()->Context();
|
||||
}
|
||||
} // namespace danger
|
||||
|
||||
JS::RootingContext*
|
||||
RootingCx()
|
||||
{
|
||||
return CycleCollectedJSRuntime::Get()->RootingCx();
|
||||
return CycleCollectedJSContext::Get()->RootingCx();
|
||||
}
|
||||
|
||||
AutoJSAPI::AutoJSAPI()
|
||||
|
|
|
@ -5197,16 +5197,16 @@ nsContentUtils::AddScriptRunner(nsIRunnable* aRunnable) {
|
|||
void
|
||||
nsContentUtils::RunInStableState(already_AddRefed<nsIRunnable> aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(CycleCollectedJSRuntime::Get(), "Must be on a script thread!");
|
||||
CycleCollectedJSRuntime::Get()->RunInStableState(Move(aRunnable));
|
||||
MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!");
|
||||
CycleCollectedJSContext::Get()->RunInStableState(Move(aRunnable));
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsContentUtils::RunInMetastableState(already_AddRefed<nsIRunnable> aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(CycleCollectedJSRuntime::Get(), "Must be on a script thread!");
|
||||
CycleCollectedJSRuntime::Get()->RunInMetastableState(Move(aRunnable));
|
||||
MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!");
|
||||
CycleCollectedJSContext::Get()->RunInMetastableState(Move(aRunnable));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1717,7 +1717,7 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
|||
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JS::PropertyDescriptor> desc)
|
||||
{
|
||||
if (id == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_COMPONENTS)) {
|
||||
if (id == XPCJSContext::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS)) {
|
||||
return LookupComponentsShim(cx, obj, aWin->AsInner(), desc);
|
||||
}
|
||||
|
||||
|
@ -1725,7 +1725,7 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
|||
// Note: We use |obj| rather than |aWin| to get the principal here, because
|
||||
// this is called during Window setup when the Document isn't necessarily
|
||||
// hooked up yet.
|
||||
if (id == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_CONTROLLERS) &&
|
||||
if (id == XPCJSContext::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS) &&
|
||||
!xpc::IsXrayWrapper(obj) &&
|
||||
!nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(obj)))
|
||||
{
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIDOMClassInfo.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/IntentionalCrash.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
|
|
@ -149,6 +149,7 @@
|
|||
#include "mozilla/dom/CustomEvent.h"
|
||||
#include "nsIJARChannel.h"
|
||||
#include "nsIScreenManager.h"
|
||||
#include "nsIEffectiveTLDService.h"
|
||||
|
||||
#include "xpcprivate.h"
|
||||
|
||||
|
@ -1224,7 +1225,9 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
|
|||
mCleanedUp(false),
|
||||
mDialogAbuseCount(0),
|
||||
mAreDialogsEnabled(true),
|
||||
mCanSkipCCGeneration(0)
|
||||
mCanSkipCCGeneration(0),
|
||||
mStaticConstellation(0),
|
||||
mConstellation(NullCString())
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
|
@ -1259,6 +1262,11 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
|
|||
// remain frozen until they get an inner window, so freeze this
|
||||
// outer window here.
|
||||
Freeze();
|
||||
|
||||
// As an outer window, we may be the root of a constellation. This initial
|
||||
// static constellation may be overridden as this window is given a parent
|
||||
// window or an opener.
|
||||
mStaticConstellation = WindowID();
|
||||
}
|
||||
|
||||
// We could have failed the first time through trying
|
||||
|
@ -3029,6 +3037,12 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
|
|||
|
||||
mDocShell = aDocShell; // Weak Reference
|
||||
|
||||
// Copy over the static constellation from our new parent.
|
||||
nsCOMPtr<nsPIDOMWindowOuter> parentWindow = GetParent();
|
||||
if (parentWindow) {
|
||||
mStaticConstellation = Cast(parentWindow)->mStaticConstellation;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!mNavigator, "Non-null mNavigator in outer window!");
|
||||
|
||||
if (mFrames) {
|
||||
|
@ -3140,6 +3154,11 @@ nsGlobalWindow::SetOpenerWindow(nsPIDOMWindowOuter* aOpener,
|
|||
mOpener = do_GetWeakReference(aOpener);
|
||||
NS_ASSERTION(mOpener || !aOpener, "Opener must support weak references!");
|
||||
|
||||
// Copy over the static constellation from our new opener
|
||||
if (aOpener) {
|
||||
mStaticConstellation = Cast(aOpener)->mStaticConstellation;
|
||||
}
|
||||
|
||||
if (aOriginalOpener) {
|
||||
MOZ_ASSERT(!mHadOriginalOpener,
|
||||
"Probably too late to call ComputeIsSecureContext again");
|
||||
|
@ -4475,11 +4494,11 @@ nsGlobalWindow::MayResolve(jsid aId)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (aId == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_COMPONENTS)) {
|
||||
if (aId == XPCJSContext::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aId == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_CONTROLLERS)) {
|
||||
if (aId == XPCJSContext::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS)) {
|
||||
// We only resolve .controllers in release builds and on non-chrome windows,
|
||||
// but let's not worry about any of that stuff.
|
||||
return true;
|
||||
|
@ -14384,6 +14403,46 @@ nsGlobalWindow::CheckForDPIChange()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::GetConstellation(nsACString& aConstellation)
|
||||
{
|
||||
FORWARD_TO_INNER_VOID(GetConstellation, (aConstellation));
|
||||
|
||||
#ifdef DEBUG
|
||||
RefPtr<nsGlobalWindow> outer = GetOuterWindowInternal();
|
||||
MOZ_ASSERT(outer, "We should have an outer window");
|
||||
RefPtr<nsGlobalWindow> top = outer->GetTopInternal();
|
||||
RefPtr<nsPIDOMWindowOuter> opener = outer->GetOpener();
|
||||
MOZ_ASSERT(!top || (top->mStaticConstellation ==
|
||||
outer->mStaticConstellation));
|
||||
MOZ_ASSERT(!opener || (Cast(opener)->mStaticConstellation ==
|
||||
outer->mStaticConstellation));
|
||||
#endif
|
||||
|
||||
if (mConstellation.IsVoid()) {
|
||||
mConstellation.Truncate();
|
||||
// The dynamic constellation part comes from the eTLD+1 for the principal's URI.
|
||||
nsCOMPtr<nsIPrincipal> principal = GetPrincipal();
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = principal->GetURI(getter_AddRefs(uri));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIEffectiveTLDService> tldService =
|
||||
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
||||
if (tldService) {
|
||||
rv = tldService->GetBaseDomain(uri, 0, mConstellation);
|
||||
if (NS_FAILED(rv)) {
|
||||
mConstellation.Truncate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the static constellation from the outer window object.
|
||||
mConstellation.AppendPrintf("^%llu", GetOuterWindowInternal()->mStaticConstellation);
|
||||
}
|
||||
|
||||
aConstellation.Assign(mConstellation);
|
||||
}
|
||||
|
||||
nsGlobalWindow::TemporarilyDisableDialogs::TemporarilyDisableDialogs(
|
||||
nsGlobalWindow* aWindow MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
{
|
||||
|
|
|
@ -1709,6 +1709,10 @@ private:
|
|||
// IsSecureContext() for the inner window that corresponds to aDocument.
|
||||
bool ComputeIsSecureContext(nsIDocument* aDocument);
|
||||
|
||||
public:
|
||||
|
||||
void GetConstellation(nsACString& aConstellation);
|
||||
|
||||
protected:
|
||||
// This member is also used on both inner and outer windows, but
|
||||
// for slightly different purposes. On inner windows it means the
|
||||
|
@ -1926,6 +1930,9 @@ protected:
|
|||
|
||||
nsAutoPtr<mozilla::dom::VREventObserver> mVREventObserver;
|
||||
|
||||
uint64_t mStaticConstellation; // Only used on outer windows
|
||||
nsCString mConstellation; // Only used on inner windows
|
||||
|
||||
friend class nsDOMScriptableHelper;
|
||||
friend class nsDOMWindowUtils;
|
||||
friend class mozilla::dom::PostMessageEvent;
|
||||
|
|
|
@ -291,7 +291,7 @@ nsInProcessTabChildGlobal::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
|||
nsresult
|
||||
nsInProcessTabChildGlobal::InitTabChildGlobal()
|
||||
{
|
||||
// If you change this, please change GetCompartmentName() in XPCJSRuntime.cpp
|
||||
// If you change this, please change GetCompartmentName() in XPCJSContext.cpp
|
||||
// accordingly.
|
||||
nsAutoCString id;
|
||||
id.AssignLiteral("inProcessTabChildGlobal");
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
#include "mozilla/dom/DOMExceptionBinding.h"
|
||||
#include "mozilla/dom/ErrorEvent.h"
|
||||
#include "nsAXPCNativeCallContext.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
|
||||
#include "nsJSPrincipals.h"
|
||||
|
||||
|
@ -75,7 +75,7 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/asmjscache/AsmJSCache.h"
|
||||
#include "mozilla/dom/CanvasRenderingContext2DBinding.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/ContentEvents.h"
|
||||
|
||||
#include "nsCycleCollectionNoteRootCallback.h"
|
||||
|
@ -1208,7 +1208,7 @@ nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason,
|
|||
sNeedsFullGC = false;
|
||||
JS::PrepareForFullGC(sContext);
|
||||
} else {
|
||||
CycleCollectedJSRuntime::Get()->PrepareWaitingZonesForGC();
|
||||
CycleCollectedJSContext::Get()->PrepareWaitingZonesForGC();
|
||||
}
|
||||
|
||||
if (aIncremental == IncrementalGC) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "js/Class.h"
|
||||
#include "js/Proxy.h"
|
||||
#include "mozilla/dom/DOMJSProxyHandler.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
#include "nsCycleCollectionTraversalCallback.h"
|
||||
#include "nsCycleCollector.h"
|
||||
|
@ -31,7 +31,7 @@ nsWrapperCache::HoldJSObjects(void* aScriptObjectHolder,
|
|||
{
|
||||
cyclecollector::HoldJSObjectsImpl(aScriptObjectHolder, aTracer);
|
||||
if (mWrapper && !JS::ObjectIsTenured(mWrapper)) {
|
||||
CycleCollectedJSRuntime::Get()->NurseryWrapperPreserved(mWrapper);
|
||||
CycleCollectedJSContext::Get()->NurseryWrapperPreserved(mWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ nsWrapperCache::SetWrapperJSObject(JSObject* aWrapper)
|
|||
UnsetWrapperFlags(kWrapperFlagsMask & ~WRAPPER_IS_NOT_DOM_BINDING);
|
||||
|
||||
if (aWrapper && !JS::ObjectIsTenured(aWrapper)) {
|
||||
CycleCollectedJSRuntime::Get()->NurseryWrapperAdded(this);
|
||||
CycleCollectedJSContext::Get()->NurseryWrapperAdded(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "mozilla/Alignment.h"
|
||||
#include "mozilla/Array.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/DeferredFinalize.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/CallbackObject.h"
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "js/TypeDecls.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsprf.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
@ -145,12 +145,12 @@ Throw(JSContext* aCx, nsresult aRv, const nsACString& aMessage)
|
|||
return false;
|
||||
}
|
||||
|
||||
CycleCollectedJSRuntime* runtime = CycleCollectedJSRuntime::Get();
|
||||
nsCOMPtr<nsIException> existingException = runtime->GetPendingException();
|
||||
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
||||
nsCOMPtr<nsIException> existingException = context->GetPendingException();
|
||||
// Make sure to clear the pending exception now. Either we're going to reuse
|
||||
// it (and we already grabbed it), or we plan to throw something else and this
|
||||
// pending exception is no longer relevant.
|
||||
runtime->SetPendingException(nullptr);
|
||||
context->SetPendingException(nullptr);
|
||||
|
||||
// Ignore the pending exception if we have a non-default message passed in.
|
||||
if (aMessage.IsEmpty() && existingException) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include "mozilla/AddonPathService.h"
|
||||
#include "mozilla/BasicEvents.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/EventListenerManager.h"
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "nsDOMJSUtils.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "mozilla/ContentEvents.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
#include "mozilla/JSEventHandler.h"
|
||||
#include "mozilla/Likely.h"
|
||||
|
|
|
@ -850,7 +850,7 @@ ContentParent::SendAsyncUpdate(nsIWidget* aWidget)
|
|||
ContentParent* cp = reinterpret_cast<ContentParent*>(
|
||||
::GetPropW(hwnd, kPluginWidgetContentParentProperty));
|
||||
if (cp && !cp->IsDestroyed()) {
|
||||
cp->SendUpdateWindow((uintptr_t)hwnd);
|
||||
Unused << cp->SendUpdateWindow((uintptr_t)hwnd);
|
||||
}
|
||||
}
|
||||
#endif // defined(XP_WIN)
|
||||
|
|
|
@ -400,7 +400,8 @@ GonkVideoDecoderManager::CreateVideoDataFromGraphicBuffer(MediaBuffer* aSource,
|
|||
if (mNeedsCopyBuffer) {
|
||||
// Copy buffer contents for bug 1199809.
|
||||
if (!mCopyAllocator) {
|
||||
mCopyAllocator = new TextureClientRecycleAllocator(ImageBridgeChild::GetSingleton());
|
||||
RefPtr<layers::ImageBridgeChild> bridge = layers::ImageBridgeChild::GetSingleton();
|
||||
mCopyAllocator = new TextureClientRecycleAllocator(bridge);
|
||||
}
|
||||
if (!mCopyAllocator) {
|
||||
GVDM_LOG("Create buffer allocator failed!");
|
||||
|
|
|
@ -155,13 +155,15 @@ public:
|
|||
: ITextureClientRecycleAllocator()
|
||||
, mMonitor("GonkTextureClientRecycleHandler")
|
||||
{
|
||||
RefPtr<layers::ImageBridgeChild> bridge = layers::ImageBridgeChild::GetSingleton();
|
||||
|
||||
// Allocate Gralloc texture memory.
|
||||
layers::GrallocTextureData* textureData =
|
||||
layers::GrallocTextureData::Create(gfx::IntSize(aDef.nFrameWidth, aDef.nFrameHeight),
|
||||
aDef.eColorFormat,
|
||||
gfx::BackendType::NONE,
|
||||
GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_READ_OFTEN,
|
||||
layers::ImageBridgeChild::GetSingleton());
|
||||
bridge);
|
||||
|
||||
mGraphBuffer = textureData->GetGraphicBuffer();
|
||||
MOZ_ASSERT(mGraphBuffer.get());
|
||||
|
@ -169,7 +171,7 @@ public:
|
|||
mTextureClient =
|
||||
layers::TextureClient::CreateWithData(textureData,
|
||||
layers::TextureFlags::DEALLOCATE_CLIENT | layers::TextureFlags::RECYCLE,
|
||||
layers::ImageBridgeChild::GetSingleton());
|
||||
bridge);
|
||||
MOZ_ASSERT(mTextureClient);
|
||||
|
||||
mPromise.SetMonitor(&mMonitor);
|
||||
|
|
|
@ -413,8 +413,8 @@ MediaEngineGonkVideoSource::AllocImpl() {
|
|||
// to explicitly remove this--destroying the CameraControl object
|
||||
// in DeallocImpl() will do that for us.
|
||||
mCameraControl->AddListener(this);
|
||||
mTextureClientAllocator =
|
||||
new layers::TextureClientRecycleAllocator(layers::ImageBridgeChild::GetSingleton());
|
||||
RefPtr<layers::ImageBridgeChild> bridge = layers::ImageBridgeChild::GetSingleton();
|
||||
mTextureClientAllocator = new layers::TextureClientRecycleAllocator(bridge);
|
||||
mTextureClientAllocator->SetMaxPoolSize(WEBRTC_GONK_VIDEO_SOURCE_POOL_BUFFERS);
|
||||
}
|
||||
mCallbackMonitor.Notify();
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "js/Debug.h"
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/OwningNonNull.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
|
@ -62,7 +62,7 @@ public:
|
|||
const JS::Value& aValue)
|
||||
: mPromise(aPromise)
|
||||
, mCallback(aCallback)
|
||||
, mValue(CycleCollectedJSRuntime::Get()->Runtime(), aValue)
|
||||
, mValue(CycleCollectedJSContext::Get()->Context(), aValue)
|
||||
{
|
||||
MOZ_ASSERT(aPromise);
|
||||
MOZ_ASSERT(aCallback);
|
||||
|
@ -187,7 +187,7 @@ public:
|
|||
JS::Handle<JSObject*> aThenable,
|
||||
PromiseInit* aThen)
|
||||
: mPromise(aPromise)
|
||||
, mThenable(CycleCollectedJSRuntime::Get()->Runtime(), aThenable)
|
||||
, mThenable(CycleCollectedJSContext::Get()->Context(), aThenable)
|
||||
, mThen(aThen)
|
||||
{
|
||||
MOZ_ASSERT(aPromise);
|
||||
|
@ -1041,11 +1041,11 @@ Promise::PerformMicroTaskCheckpoint()
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
CycleCollectedJSRuntime* runtime = CycleCollectedJSRuntime::Get();
|
||||
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
||||
|
||||
// On the main thread, we always use the main promise micro task queue.
|
||||
std::queue<nsCOMPtr<nsIRunnable>>& microtaskQueue =
|
||||
runtime->GetPromiseMicroTaskQueue();
|
||||
context->GetPromiseMicroTaskQueue();
|
||||
|
||||
if (microtaskQueue.empty()) {
|
||||
return false;
|
||||
|
@ -1064,7 +1064,7 @@ Promise::PerformMicroTaskCheckpoint()
|
|||
return false;
|
||||
}
|
||||
aso.CheckForInterrupt();
|
||||
runtime->AfterProcessMicrotask();
|
||||
context->AfterProcessMicrotask();
|
||||
} while (!microtaskQueue.empty());
|
||||
|
||||
return true;
|
||||
|
@ -1075,17 +1075,17 @@ Promise::PerformWorkerMicroTaskCheckpoint()
|
|||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
CycleCollectedJSRuntime* runtime = CycleCollectedJSRuntime::Get();
|
||||
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
||||
|
||||
for (;;) {
|
||||
// For a normal microtask checkpoint, we try to use the debugger microtask
|
||||
// queue first. If the debugger queue is empty, we use the normal microtask
|
||||
// queue instead.
|
||||
std::queue<nsCOMPtr<nsIRunnable>>* microtaskQueue =
|
||||
&runtime->GetDebuggerPromiseMicroTaskQueue();
|
||||
&context->GetDebuggerPromiseMicroTaskQueue();
|
||||
|
||||
if (microtaskQueue->empty()) {
|
||||
microtaskQueue = &runtime->GetPromiseMicroTaskQueue();
|
||||
microtaskQueue = &context->GetPromiseMicroTaskQueue();
|
||||
if (microtaskQueue->empty()) {
|
||||
break;
|
||||
}
|
||||
|
@ -1100,7 +1100,7 @@ Promise::PerformWorkerMicroTaskCheckpoint()
|
|||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
runtime->AfterProcessMicrotask();
|
||||
context->AfterProcessMicrotask();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1109,13 +1109,13 @@ Promise::PerformWorkerDebuggerMicroTaskCheckpoint()
|
|||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
CycleCollectedJSRuntime* runtime = CycleCollectedJSRuntime::Get();
|
||||
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
||||
|
||||
for (;;) {
|
||||
// For a debugger microtask checkpoint, we always use the debugger microtask
|
||||
// queue.
|
||||
std::queue<nsCOMPtr<nsIRunnable>>* microtaskQueue =
|
||||
&runtime->GetDebuggerPromiseMicroTaskQueue();
|
||||
&context->GetDebuggerPromiseMicroTaskQueue();
|
||||
|
||||
if (microtaskQueue->empty()) {
|
||||
break;
|
||||
|
@ -1130,7 +1130,7 @@ Promise::PerformWorkerDebuggerMicroTaskCheckpoint()
|
|||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
runtime->AfterProcessMicrotask();
|
||||
context->AfterProcessMicrotask();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2715,7 +2715,7 @@ Promise::ResolveInternal(JSContext* aCx,
|
|||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Promise);
|
||||
|
||||
CycleCollectedJSRuntime* runtime = CycleCollectedJSRuntime::Get();
|
||||
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
||||
|
||||
mResolvePending = true;
|
||||
|
||||
|
@ -2757,7 +2757,7 @@ Promise::ResolveInternal(JSContext* aCx,
|
|||
new PromiseInit(nullptr, thenObj, mozilla::dom::GetIncumbentGlobal());
|
||||
RefPtr<PromiseResolveThenableJob> task =
|
||||
new PromiseResolveThenableJob(this, valueObj, thenCallback);
|
||||
runtime->DispatchToMicroTask(task.forget());
|
||||
context->DispatchToMicroTask(task.forget());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2861,7 +2861,7 @@ Promise::TriggerPromiseReactions()
|
|||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Promise);
|
||||
|
||||
CycleCollectedJSRuntime* runtime = CycleCollectedJSRuntime::Get();
|
||||
CycleCollectedJSContext* runtime = CycleCollectedJSContext::Get();
|
||||
|
||||
nsTArray<RefPtr<PromiseCallback>> callbacks;
|
||||
callbacks.SwapElements(mState == Resolved ? mResolveCallbacks
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "js/Value.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/ThreadLocal.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
|
@ -318,7 +318,7 @@ PromiseDebugging::GetTimeToSettle(GlobalObject&, JS::Handle<JSObject*> aPromise,
|
|||
PromiseDebugging::AddUncaughtRejectionObserver(GlobalObject&,
|
||||
UncaughtRejectionObserver& aObserver)
|
||||
{
|
||||
CycleCollectedJSRuntime* storage = CycleCollectedJSRuntime::Get();
|
||||
CycleCollectedJSContext* storage = CycleCollectedJSContext::Get();
|
||||
nsTArray<nsCOMPtr<nsISupports>>& observers = storage->mUncaughtRejectionObservers;
|
||||
observers.AppendElement(&aObserver);
|
||||
}
|
||||
|
@ -327,7 +327,7 @@ PromiseDebugging::AddUncaughtRejectionObserver(GlobalObject&,
|
|||
PromiseDebugging::RemoveUncaughtRejectionObserver(GlobalObject&,
|
||||
UncaughtRejectionObserver& aObserver)
|
||||
{
|
||||
CycleCollectedJSRuntime* storage = CycleCollectedJSRuntime::Get();
|
||||
CycleCollectedJSContext* storage = CycleCollectedJSContext::Get();
|
||||
nsTArray<nsCOMPtr<nsISupports>>& observers = storage->mUncaughtRejectionObservers;
|
||||
for (size_t i = 0; i < observers.Length(); ++i) {
|
||||
UncaughtRejectionObserver* observer = static_cast<UncaughtRejectionObserver*>(observers[i].get());
|
||||
|
@ -345,7 +345,7 @@ PromiseDebugging::RemoveUncaughtRejectionObserver(GlobalObject&,
|
|||
PromiseDebugging::AddUncaughtRejection(JS::HandleObject aPromise)
|
||||
{
|
||||
// This might OOM, but won't set a pending exception, so we'll just ignore it.
|
||||
if (CycleCollectedJSRuntime::Get()->mUncaughtRejections.append(aPromise)) {
|
||||
if (CycleCollectedJSContext::Get()->mUncaughtRejections.append(aPromise)) {
|
||||
FlushRejections::DispatchNeeded();
|
||||
}
|
||||
}
|
||||
|
@ -356,7 +356,7 @@ PromiseDebugging::AddConsumedRejection(JS::HandleObject aPromise)
|
|||
// If the promise is in our list of uncaught rejections, we haven't yet
|
||||
// reported it as unhandled. In that case, just remove it from the list
|
||||
// and don't add it to the list of consumed rejections.
|
||||
auto& uncaughtRejections = CycleCollectedJSRuntime::Get()->mUncaughtRejections;
|
||||
auto& uncaughtRejections = CycleCollectedJSContext::Get()->mUncaughtRejections;
|
||||
for (size_t i = 0; i < uncaughtRejections.length(); i++) {
|
||||
if (uncaughtRejections[i] == aPromise) {
|
||||
// To avoid large amounts of memmoves, we don't shrink the vector here.
|
||||
|
@ -366,7 +366,7 @@ PromiseDebugging::AddConsumedRejection(JS::HandleObject aPromise)
|
|||
}
|
||||
}
|
||||
// This might OOM, but won't set a pending exception, so we'll just ignore it.
|
||||
if (CycleCollectedJSRuntime::Get()->mConsumedRejections.append(aPromise)) {
|
||||
if (CycleCollectedJSContext::Get()->mConsumedRejections.append(aPromise)) {
|
||||
FlushRejections::DispatchNeeded();
|
||||
}
|
||||
}
|
||||
|
@ -374,7 +374,7 @@ PromiseDebugging::AddConsumedRejection(JS::HandleObject aPromise)
|
|||
/* static */ void
|
||||
PromiseDebugging::FlushUncaughtRejectionsInternal()
|
||||
{
|
||||
CycleCollectedJSRuntime* storage = CycleCollectedJSRuntime::Get();
|
||||
CycleCollectedJSContext* storage = CycleCollectedJSContext::Get();
|
||||
|
||||
auto& uncaught = storage->mUncaughtRejections;
|
||||
auto& consumed = storage->mConsumedRejections;
|
||||
|
@ -427,14 +427,14 @@ PromiseDebugging::FlushUncaughtRejectionsInternal()
|
|||
/* static */ void
|
||||
PromiseDebugging::AddUncaughtRejection(Promise& aPromise)
|
||||
{
|
||||
CycleCollectedJSRuntime::Get()->mUncaughtRejections.AppendElement(&aPromise);
|
||||
CycleCollectedJSContext::Get()->mUncaughtRejections.AppendElement(&aPromise);
|
||||
FlushRejections::DispatchNeeded();
|
||||
}
|
||||
|
||||
/* void */ void
|
||||
PromiseDebugging::AddConsumedRejection(Promise& aPromise)
|
||||
{
|
||||
CycleCollectedJSRuntime::Get()->mConsumedRejections.AppendElement(&aPromise);
|
||||
CycleCollectedJSContext::Get()->mConsumedRejections.AppendElement(&aPromise);
|
||||
FlushRejections::DispatchNeeded();
|
||||
}
|
||||
|
||||
|
@ -456,7 +456,7 @@ PromiseDebugging::GetPromiseID(GlobalObject&,
|
|||
/* static */ void
|
||||
PromiseDebugging::FlushUncaughtRejectionsInternal()
|
||||
{
|
||||
CycleCollectedJSRuntime* storage = CycleCollectedJSRuntime::Get();
|
||||
CycleCollectedJSContext* storage = CycleCollectedJSContext::Get();
|
||||
|
||||
// The Promise that have been left uncaught (rejected and last in
|
||||
// their chain) since the last call to this function.
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include "jsfriendapi.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/dom/asmjscache/AsmJSCache.h"
|
||||
|
@ -892,11 +892,11 @@ FinishAsyncTaskCallback(JS::AsyncTask* aTask)
|
|||
return true;
|
||||
}
|
||||
|
||||
class WorkerJSRuntime;
|
||||
class WorkerJSContext;
|
||||
|
||||
class WorkerThreadContextPrivate : private PerThreadAtomCache
|
||||
{
|
||||
friend class WorkerJSRuntime;
|
||||
friend class WorkerJSContext;
|
||||
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
|
@ -1043,18 +1043,18 @@ static const JSWrapObjectCallbacks WrapObjectCallbacks = {
|
|||
nullptr,
|
||||
};
|
||||
|
||||
class WorkerJSRuntime : public mozilla::CycleCollectedJSRuntime
|
||||
class MOZ_STACK_CLASS WorkerJSContext final : public mozilla::CycleCollectedJSContext
|
||||
{
|
||||
public:
|
||||
// The heap size passed here doesn't matter, we will change it later in the
|
||||
// call to JS_SetGCParameter inside InitJSContextForWorker.
|
||||
explicit WorkerJSRuntime(WorkerPrivate* aWorkerPrivate)
|
||||
explicit WorkerJSContext(WorkerPrivate* aWorkerPrivate)
|
||||
: mWorkerPrivate(aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
}
|
||||
|
||||
~WorkerJSRuntime()
|
||||
~WorkerJSContext()
|
||||
{
|
||||
JSContext* cx = MaybeContext();
|
||||
if (!cx) {
|
||||
|
@ -1078,7 +1078,7 @@ public:
|
|||
nsresult Initialize(JSContext* aParentContext)
|
||||
{
|
||||
nsresult rv =
|
||||
CycleCollectedJSRuntime::Initialize(aParentContext,
|
||||
CycleCollectedJSContext::Initialize(aParentContext,
|
||||
WORKER_DEFAULT_RUNTIME_HEAPSIZE,
|
||||
WORKER_DEFAULT_NURSERY_SIZE);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -1142,10 +1142,10 @@ public:
|
|||
// Only perform the Promise microtask checkpoint on the outermost event
|
||||
// loop. Don't run it, for example, during sync XHR or importScripts.
|
||||
if (aRecursionDepth == 2) {
|
||||
CycleCollectedJSRuntime::AfterProcessTask(aRecursionDepth);
|
||||
CycleCollectedJSContext::AfterProcessTask(aRecursionDepth);
|
||||
} else if (aRecursionDepth > 2) {
|
||||
AutoDisableMicroTaskCheckpoint disableMicroTaskCheckpoint;
|
||||
CycleCollectedJSRuntime::AfterProcessTask(aRecursionDepth);
|
||||
CycleCollectedJSContext::AfterProcessTask(aRecursionDepth);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1450,19 +1450,19 @@ GetCurrentThreadWorkerPrivate()
|
|||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
CycleCollectedJSRuntime* ccrt = CycleCollectedJSRuntime::Get();
|
||||
if (!ccrt) {
|
||||
CycleCollectedJSContext* ccjscx = CycleCollectedJSContext::Get();
|
||||
if (!ccjscx) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSContext* cx = ccrt->Context();
|
||||
JSContext* cx = ccjscx->Context();
|
||||
MOZ_ASSERT(cx);
|
||||
|
||||
void* cxPrivate = JS_GetContextPrivate(cx);
|
||||
if (!cxPrivate) {
|
||||
// This can happen if the nsCycleCollector_shutdown() in ~WorkerJSRuntime()
|
||||
// This can happen if the nsCycleCollector_shutdown() in ~WorkerJSContext()
|
||||
// triggers any calls to GetCurrentThreadWorkerPrivate(). At this stage
|
||||
// CycleCollectedJSRuntime::Get() will still return a runtime, but
|
||||
// CycleCollectedJSContext::Get() will still return a context, but
|
||||
// the context private has already been cleared.
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1883,7 +1883,7 @@ RuntimeService::ScheduleWorker(WorkerPrivate* aWorkerPrivate)
|
|||
NS_WARNING("Could not set the thread's priority!");
|
||||
}
|
||||
|
||||
JSContext* cx = CycleCollectedJSRuntime::Get()->Context();
|
||||
JSContext* cx = CycleCollectedJSContext::Get()->Context();
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
new WorkerThreadPrimaryRunnable(aWorkerPrivate, thread,
|
||||
JS_GetParentContext(cx));
|
||||
|
@ -2832,17 +2832,17 @@ WorkerThreadPrimaryRunnable::Run()
|
|||
{
|
||||
nsCycleCollector_startup();
|
||||
|
||||
WorkerJSRuntime runtime(mWorkerPrivate);
|
||||
nsresult rv = runtime.Initialize(mParentContext);
|
||||
WorkerJSContext context(mWorkerPrivate);
|
||||
nsresult rv = context.Initialize(mParentContext);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
JSContext* cx = runtime.Context();
|
||||
JSContext* cx = context.Context();
|
||||
|
||||
if (!InitJSContextForWorker(mWorkerPrivate, cx)) {
|
||||
// XXX need to fire an error at parent.
|
||||
NS_ERROR("Failed to create runtime and context!");
|
||||
NS_ERROR("Failed to create context!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -2889,7 +2889,7 @@ WorkerThreadPrimaryRunnable::Run()
|
|||
// cleanup.
|
||||
mWorkerPrivate->ClearMainEventQueue(WorkerPrivate::WorkerRan);
|
||||
|
||||
// Now WorkerJSRuntime goes out of scope and its destructor will shut
|
||||
// Now WorkerJSContext goes out of scope and its destructor will shut
|
||||
// down the cycle collector. This breaks any remaining cycles and collects
|
||||
// any remaining C++ objects.
|
||||
}
|
||||
|
|
|
@ -1508,16 +1508,16 @@ StartsWithExplicit(nsACString& s)
|
|||
}
|
||||
#endif
|
||||
|
||||
class WorkerJSRuntimeStats : public JS::RuntimeStats
|
||||
class MOZ_STACK_CLASS WorkerJSContextStats final : public JS::RuntimeStats
|
||||
{
|
||||
const nsACString& mRtPath;
|
||||
|
||||
public:
|
||||
explicit WorkerJSRuntimeStats(const nsACString& aRtPath)
|
||||
explicit WorkerJSContextStats(const nsACString& aRtPath)
|
||||
: JS::RuntimeStats(JsWorkerMallocSizeOf), mRtPath(aRtPath)
|
||||
{ }
|
||||
|
||||
~WorkerJSRuntimeStats()
|
||||
~WorkerJSContextStats()
|
||||
{
|
||||
for (size_t i = 0; i != zoneStatsVector.length(); i++) {
|
||||
delete static_cast<xpc::ZoneStatsExtras*>(zoneStatsVector[i].extra);
|
||||
|
@ -2027,10 +2027,10 @@ public:
|
|||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
// Assumes that WorkerJSRuntimeStats will hold a reference to |path|, and
|
||||
// Assumes that WorkerJSContextStats will hold a reference to |path|, and
|
||||
// not a copy, as TryToMapAddon() may later modify it.
|
||||
nsCString path;
|
||||
WorkerJSRuntimeStats rtStats(path);
|
||||
WorkerJSContextStats cxStats(path);
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
@ -2060,13 +2060,13 @@ public:
|
|||
|
||||
TryToMapAddon(path);
|
||||
|
||||
if (!mWorkerPrivate->BlockAndCollectRuntimeStats(&rtStats, aAnonymize)) {
|
||||
if (!mWorkerPrivate->BlockAndCollectRuntimeStats(&cxStats, aAnonymize)) {
|
||||
// Returning NS_OK here will effectively report 0 memory.
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
xpc::ReportJSRuntimeExplicitTreeStats(rtStats, path, aHandleReport, aData,
|
||||
xpc::ReportJSRuntimeExplicitTreeStats(cxStats, path, aHandleReport, aData,
|
||||
aAnonymize);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -4598,7 +4598,7 @@ WorkerPrivate::OnProcessNextEvent()
|
|||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
uint32_t recursionDepth = CycleCollectedJSRuntime::Get()->RecursionDepth();
|
||||
uint32_t recursionDepth = CycleCollectedJSContext::Get()->RecursionDepth();
|
||||
MOZ_ASSERT(recursionDepth);
|
||||
|
||||
// Normally we process control runnables in DoRunLoop or RunCurrentSyncLoop.
|
||||
|
@ -4617,7 +4617,7 @@ void
|
|||
WorkerPrivate::AfterProcessNextEvent()
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(CycleCollectedJSRuntime::Get()->RecursionDepth());
|
||||
MOZ_ASSERT(CycleCollectedJSContext::Get()->RecursionDepth());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -331,7 +331,7 @@ WorkerThread::Observer::OnProcessNextEvent(nsIThreadInternal* /* aThread */,
|
|||
// PrimaryWorkerRunnable::Run() and don't want to process the event in
|
||||
// mWorkerPrivate yet.
|
||||
if (aMayWait) {
|
||||
MOZ_ASSERT(CycleCollectedJSRuntime::Get()->RecursionDepth() == 2);
|
||||
MOZ_ASSERT(CycleCollectedJSContext::Get()->RecursionDepth() == 2);
|
||||
MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -163,13 +163,13 @@ Web browsers in general solve this problem by inserting a delay of up to 300ms b
|
|||
If web content takes longer than 300ms, or if it completes handling of the event without calling preventDefault, then the browser immediately starts processing the events.
|
||||
|
||||
The way the APZ implementation deals with this is that upon receiving a touch event, it immediately returns an untransformed version that can be dispatched to content.
|
||||
It also schedules a 300ms timeout during which content is allowed to prevent scrolling.
|
||||
It also schedules a 400ms timeout (600ms on Android) during which content is allowed to prevent scrolling.
|
||||
There is an API that allows the main-thread event dispatching code to notify the APZ as to whether or not the default action should be prevented.
|
||||
If the APZ content response timeout expires, or if the main-thread event dispatching code notifies the APZ of the preventDefault status, then the APZ continues with the processing of the events (which may involve discarding the events).
|
||||
|
||||
The touch-action CSS property from the pointer-events spec is intended to allow eliminating this 300ms delay in many cases (although for backwards compatibility it will still be needed for a while).
|
||||
The touch-action CSS property from the pointer-events spec is intended to allow eliminating this 400ms delay in many cases (although for backwards compatibility it will still be needed for a while).
|
||||
Note that even with touch-action implemented, there may be cases where the APZ code does not know the touch-action behaviour of the point the user touched.
|
||||
In such cases, the APZ code will still wait up to 300ms for the main thread to provide it with the touch-action behaviour information.
|
||||
In such cases, the APZ code will still wait up to 400ms for the main thread to provide it with the touch-action behaviour information.
|
||||
|
||||
## Technical details
|
||||
|
||||
|
@ -185,8 +185,8 @@ Input events arrive from the hardware/widget code into the APZ via APZCTreeManag
|
|||
The thread that invokes this is called the input thread, and may or may not be the same as the Gecko main thread.
|
||||
</li>
|
||||
<li value="2">
|
||||
Conceptually the first thing that the APZCTreeManager does is to group these events into "input blocks".
|
||||
An input block is a contiguous set of events that get handled together.
|
||||
Conceptually the first thing that the APZCTreeManager does is to associate these events with "input blocks".
|
||||
An input block is a set of events that share certain properties, and generally are intended to represent a single gesture.
|
||||
For example with touch events, all events following a touchstart up to but not including the next touchstart are in the same block.
|
||||
All of the events in a given block will go to the same APZC instance and will either all be processed or all be dropped.
|
||||
</li>
|
||||
|
@ -203,7 +203,7 @@ Otherwise, the input block is tagged with the hit APZC as a tentative target and
|
|||
These may trigger behaviours like scrolling or tap gestures.
|
||||
</li>
|
||||
<li value="ii">
|
||||
If the input events landed inside the dispatch-to-content event region for the layer, the events are left in the queue and a 300ms timeout is initiated.
|
||||
If the input events landed inside the dispatch-to-content event region for the layer, the events are left in the queue and a 400ms timeout is initiated.
|
||||
If the timeout expires before step 9 is completed, the APZ assumes the input block was not cancelled and the tentative target is correct, and processes them as part of step 10.
|
||||
</li>
|
||||
</ol>
|
||||
|
@ -223,9 +223,9 @@ It also activates inactive scrollframes that were hit by the input events.
|
|||
<li value="8">
|
||||
The call stack unwinds back to the widget code, which sends two notifications to the APZ code on the input thread.
|
||||
The first notification is via APZCTreeManager::ContentReceivedInputBlock, and informs the APZ whether the input block was cancelled.
|
||||
The second notification is via APZCTreeManager::SetTargetAPZC, and informs the APZ the results of the Gecko hit-test during event dispatch.
|
||||
The second notification is via APZCTreeManager::SetTargetAPZC, and informs the APZ of the results of the Gecko hit-test during event dispatch.
|
||||
Note that Gecko may report that the input event did not hit any scrollable frame at all.
|
||||
These notifications happen only once per input block.
|
||||
The SetTargetAPZC notification happens only once per input block, while the ContentReceivedInputBlock notification may happen once per block, or multiple times per block, depending on the input type.
|
||||
</li>
|
||||
<li value="9">
|
||||
<ol>
|
||||
|
@ -233,10 +233,10 @@ These notifications happen only once per input block.
|
|||
If the events were processed as part of step 4(i), the notifications from step 8 are ignored and step 10 is skipped.
|
||||
</li>
|
||||
<li value="ii">
|
||||
If events were queued as part of step 4(ii), and steps 5-8 take less than 300ms, the arrival of both notifications from step 8 will mark the input block ready for processing.
|
||||
If events were queued as part of step 4(ii), and steps 5-8 take less than 400ms, the arrival of both notifications from step 8 will mark the input block ready for processing.
|
||||
</li>
|
||||
<li value="iii">
|
||||
If events were queued as part of step 4(ii), but steps 5-8 take longer than 300ms, the notifications from step 8 will be ignored and step 10 will already have happened.
|
||||
If events were queued as part of step 4(ii), but steps 5-8 take longer than 400ms, the notifications from step 8 will be ignored and step 10 will already have happened.
|
||||
</li>
|
||||
</ol>
|
||||
</li>
|
||||
|
@ -250,7 +250,8 @@ Processing the events may trigger behaviours like scrolling or tap gestures.
|
|||
If the CSS touch-action property is enabled, the above steps are modified as follows:
|
||||
<ul>
|
||||
<li>
|
||||
In step 4, the APZC also requires the allowed touch-action behaviours for the input event. This is not available yet, so the events are always queued.
|
||||
In step 4, the APZC also requires the allowed touch-action behaviours for the input event.
|
||||
This might have been determined as part of the hit-test in APZCTreeManager; if not, the events are queued.
|
||||
</li>
|
||||
<li>
|
||||
In step 6, the widget code determines the content element at the point under the input element, and notifies the APZ code of the allowed touch-action behaviours.
|
||||
|
@ -266,7 +267,7 @@ If the CSS touch-action property is enabled, the above steps are modified as fol
|
|||
The bulk of the input processing in the APZ code happens on what we call "the input thread".
|
||||
In practice the input thread could be the Gecko main thread, the compositor thread, or some other thread.
|
||||
There are obvious downsides to using the Gecko main thread - that is, "asynchronous" panning and zooming is not really asynchronous as input events can only be processed while Gecko is idle.
|
||||
However, this is the current state of things on B2G.
|
||||
In an e10s environment, using the Gecko main thread of the chrome process is acceptable, because the code running in that process is more controllable and well-behaved than arbitrary web content.
|
||||
Using the compositor thread as the input thread could work on some platforms, but may be inefficient on others.
|
||||
For example, on Android (Fennec) we receive input events from the system on a dedicated UI thread.
|
||||
We would have to redispatch the input events to the compositor thread if we wanted to the input thread to be the same as the compositor thread.
|
||||
|
@ -289,7 +290,7 @@ The input block therefore has a tentative target of P when it goes into step 4(i
|
|||
When gecko processes the input event, it must detect the inactive scrollframe and activate it, as part of step 7.
|
||||
Finally, the widget code sends the SetTargetAPZC notification in step 8 to notify the APZ that the input block should really apply to this new layer.
|
||||
The issue here is that the layer transaction containing the new layer must reach the compositor and APZ before the SetTargetAPZC notification.
|
||||
If this does not occur within the 300ms timeout, the APZ code will be unable to update the tentative target, and will continue to use P for that input block.
|
||||
If this does not occur within the 400ms timeout, the APZ code will be unable to update the tentative target, and will continue to use P for that input block.
|
||||
Input blocks that start after the layer transaction will get correctly routed to the new layer as there will now be a layer and APZC instance for the active scrollframe.
|
||||
|
||||
This model implies that when the user initially attempts to scroll an inactive scrollframe, it may end up scrolling an ancestor scrollframe.
|
||||
|
|
|
@ -73,7 +73,7 @@ GrallocImage::SetData(const Data& aData)
|
|||
return false;
|
||||
}
|
||||
|
||||
ClientIPCAllocator* allocator = ImageBridgeChild::GetSingleton();
|
||||
RefPtr<ClientIPCAllocator> allocator = ImageBridgeChild::GetSingleton();
|
||||
GrallocTextureData* texData = GrallocTextureData::Create(mData.mYSize, HAL_PIXEL_FORMAT_YV12,
|
||||
gfx::BackendType::NONE,
|
||||
GraphicBuffer::USAGE_SW_READ_OFTEN |
|
||||
|
|
|
@ -1059,7 +1059,7 @@ void
|
|||
APZCTreeManager::UpdateWheelTransaction(LayoutDeviceIntPoint aRefPoint,
|
||||
EventMessage aEventMessage)
|
||||
{
|
||||
WheelBlockState* txn = mInputQueue->GetCurrentWheelTransaction();
|
||||
WheelBlockState* txn = mInputQueue->GetActiveWheelTransaction();
|
||||
if (!txn) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1087,15 +1087,17 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent
|
|||
case OVERSCROLL_ANIMATION:
|
||||
case WHEEL_SCROLL:
|
||||
case PAN_MOMENTUM:
|
||||
CurrentTouchBlock()->GetOverscrollHandoffChain()->CancelAnimations(ExcludeOverscroll);
|
||||
MOZ_ASSERT(GetCurrentTouchBlock());
|
||||
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->CancelAnimations(ExcludeOverscroll);
|
||||
MOZ_FALLTHROUGH;
|
||||
case NOTHING: {
|
||||
mX.StartTouch(point.x, aEvent.mTime);
|
||||
mY.StartTouch(point.y, aEvent.mTime);
|
||||
if (RefPtr<GeckoContentController> controller = GetGeckoContentController()) {
|
||||
MOZ_ASSERT(GetCurrentTouchBlock());
|
||||
controller->NotifyAPZStateChange(
|
||||
GetGuid(), APZStateChange::eStartTouch,
|
||||
CurrentTouchBlock()->GetOverscrollHandoffChain()->CanBePanned(this));
|
||||
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->CanBePanned(this));
|
||||
}
|
||||
SetState(TOUCHING);
|
||||
break;
|
||||
|
@ -1134,7 +1136,8 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
|
|||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
if (gfxPrefs::TouchActionEnabled() && CurrentTouchBlock()->TouchActionAllowsPanningXY()) {
|
||||
MOZ_ASSERT(GetCurrentTouchBlock());
|
||||
if (gfxPrefs::TouchActionEnabled() && GetCurrentTouchBlock()->TouchActionAllowsPanningXY()) {
|
||||
// User tries to trigger a touch behavior. If allowed touch behavior is vertical pan
|
||||
// + horizontal pan (touch-action value is equal to AUTO) we can return ConsumeNoDefault
|
||||
// status immediately to trigger cancel event further. It should happen independent of
|
||||
|
@ -1206,18 +1209,19 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
|
|||
// that were not big enough to trigger scrolling. Clear that out.
|
||||
mX.SetVelocity(0);
|
||||
mY.SetVelocity(0);
|
||||
MOZ_ASSERT(GetCurrentTouchBlock());
|
||||
APZC_LOG("%p still has %u touch points active\n", this,
|
||||
CurrentTouchBlock()->GetActiveTouchCount());
|
||||
GetCurrentTouchBlock()->GetActiveTouchCount());
|
||||
// In cases where the user is panning, then taps the second finger without
|
||||
// entering a pinch, we will arrive here when the second finger is lifted.
|
||||
// However the first finger is still down so we want to remain in state
|
||||
// TOUCHING.
|
||||
if (CurrentTouchBlock()->GetActiveTouchCount() == 0) {
|
||||
if (GetCurrentTouchBlock()->GetActiveTouchCount() == 0) {
|
||||
// It's possible we may be overscrolled if the user tapped during a
|
||||
// previous overscroll pan. Make sure to snap back in this situation.
|
||||
// An ancestor APZC could be overscrolled instead of this APZC, so
|
||||
// walk the handoff chain as well.
|
||||
CurrentTouchBlock()->GetOverscrollHandoffChain()->SnapBackOverscrolledApzc(this);
|
||||
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->SnapBackOverscrolledApzc(this);
|
||||
// SnapBackOverscrolledApzc() will put any APZC it causes to snap back
|
||||
// into the OVERSCROLL_ANIMATION state. If that's not us, since we're
|
||||
// done TOUCHING enter the NOTHING state.
|
||||
|
@ -1232,7 +1236,8 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
|
|||
case PANNING_LOCKED_Y:
|
||||
case PAN_MOMENTUM:
|
||||
{
|
||||
CurrentTouchBlock()->GetOverscrollHandoffChain()->FlushRepaints();
|
||||
MOZ_ASSERT(GetCurrentTouchBlock());
|
||||
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->FlushRepaints();
|
||||
mX.EndTouch(aEvent.mTime);
|
||||
mY.EndTouch(aEvent.mTime);
|
||||
ParentLayerPoint flingVelocity = GetVelocityVector();
|
||||
|
@ -1260,9 +1265,9 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
|
|||
// which nulls out mTreeManager, could be called concurrently.
|
||||
if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
|
||||
FlingHandoffState handoffState{flingVelocity,
|
||||
CurrentTouchBlock()->GetOverscrollHandoffChain(),
|
||||
GetCurrentTouchBlock()->GetOverscrollHandoffChain(),
|
||||
false /* not handoff */,
|
||||
CurrentTouchBlock()->GetScrolledApzc()};
|
||||
GetCurrentTouchBlock()->GetScrolledApzc()};
|
||||
treeManagerLocal->DispatchFling(this, handoffState);
|
||||
}
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
|
@ -1298,7 +1303,7 @@ nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEve
|
|||
mPinchPaintTimerSet = false;
|
||||
// Note that there may not be a touch block at this point, if we received the
|
||||
// PinchGestureEvent directly from widget code without any touch events.
|
||||
if (HasReadyTouchBlock() && !CurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
|
||||
if (HasReadyTouchBlock() && !GetCurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
|
@ -1312,8 +1317,8 @@ nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEve
|
|||
|
||||
nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
||||
APZC_LOG("%p got a scale in state %d\n", this, mState);
|
||||
|
||||
if (HasReadyTouchBlock() && !CurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
|
||||
|
||||
if (HasReadyTouchBlock() && !GetCurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
|
@ -1419,7 +1424,7 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent
|
|||
|
||||
mPinchPaintTimerSet = false;
|
||||
|
||||
if (HasReadyTouchBlock() && !CurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
|
||||
if (HasReadyTouchBlock() && !GetCurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
|
@ -1451,7 +1456,7 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent
|
|||
// further up in the handoff chain rather than on the current APZC, so
|
||||
// we need to clear overscroll along the entire handoff chain.
|
||||
if (HasReadyTouchBlock()) {
|
||||
CurrentTouchBlock()->GetOverscrollHandoffChain()->ClearOverscroll();
|
||||
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->ClearOverscroll();
|
||||
} else {
|
||||
ClearOverscroll();
|
||||
}
|
||||
|
@ -1625,7 +1630,7 @@ AsyncPanZoomController::AllowScrollHandoffInCurrentBlock() const
|
|||
{
|
||||
bool result = mInputQueue->AllowScrollHandoff();
|
||||
if (!gfxPrefs::APZAllowImmediateHandoff()) {
|
||||
if (InputBlockState* currentBlock = CurrentInputBlock()) {
|
||||
if (InputBlockState* currentBlock = GetCurrentInputBlock()) {
|
||||
// Do not allow handoff beyond the first APZC to scroll.
|
||||
if (currentBlock->GetScrolledApzc() == this) {
|
||||
result = false;
|
||||
|
@ -1670,7 +1675,7 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEve
|
|||
|
||||
if ((delta.x || delta.y) && !CanScrollWithWheel(delta)) {
|
||||
// We can't scroll this apz anymore, so we simply drop the event.
|
||||
if (mInputQueue->GetCurrentWheelTransaction() &&
|
||||
if (mInputQueue->GetActiveWheelTransaction() &&
|
||||
gfxPrefs::MouseScrollTestingEnabled()) {
|
||||
if (RefPtr<GeckoContentController> controller = GetGeckoContentController()) {
|
||||
controller->NotifyMozMouseScrollEvent(
|
||||
|
@ -1704,8 +1709,9 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEve
|
|||
|
||||
CancelAnimation();
|
||||
|
||||
MOZ_ASSERT(mInputQueue->GetCurrentWheelBlock());
|
||||
OverscrollHandoffState handoffState(
|
||||
*mInputQueue->CurrentWheelBlock()->GetOverscrollHandoffChain(),
|
||||
*mInputQueue->GetCurrentWheelBlock()->GetOverscrollHandoffChain(),
|
||||
distance,
|
||||
ScrollSource::Wheel);
|
||||
ParentLayerPoint startPoint = aEvent.mLocalOrigin;
|
||||
|
@ -1794,7 +1800,8 @@ nsEventStatus AsyncPanZoomController::OnPanMayBegin(const PanGestureInput& aEven
|
|||
|
||||
mX.StartTouch(aEvent.mLocalPanStartPoint.x, aEvent.mTime);
|
||||
mY.StartTouch(aEvent.mLocalPanStartPoint.y, aEvent.mTime);
|
||||
CurrentPanGestureBlock()->GetOverscrollHandoffChain()->CancelAnimations();
|
||||
MOZ_ASSERT(GetCurrentPanGestureBlock());
|
||||
GetCurrentPanGestureBlock()->GetOverscrollHandoffChain()->CancelAnimations();
|
||||
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
@ -1891,8 +1898,9 @@ nsEventStatus AsyncPanZoomController::OnPan(const PanGestureInput& aEvent, bool
|
|||
(uint32_t) ScrollInputMethod::ApzPanGesture);
|
||||
|
||||
ScreenPoint panDistance(fabs(physicalPanDisplacement.x), fabs(physicalPanDisplacement.y));
|
||||
MOZ_ASSERT(GetCurrentPanGestureBlock());
|
||||
OverscrollHandoffState handoffState(
|
||||
*CurrentPanGestureBlock()->GetOverscrollHandoffChain(),
|
||||
*GetCurrentPanGestureBlock()->GetOverscrollHandoffChain(),
|
||||
panDistance,
|
||||
ScrollSource::Wheel);
|
||||
|
||||
|
@ -1922,8 +1930,9 @@ nsEventStatus AsyncPanZoomController::OnPanEnd(const PanGestureInput& aEvent) {
|
|||
// Drop any velocity on axes where we don't have room to scroll anyways
|
||||
// (in this APZC, or an APZC further in the handoff chain).
|
||||
// This ensures that we don't enlarge the display port unnecessarily.
|
||||
MOZ_ASSERT(GetCurrentPanGestureBlock());
|
||||
RefPtr<const OverscrollHandoffChain> overscrollHandoffChain =
|
||||
CurrentPanGestureBlock()->GetOverscrollHandoffChain();
|
||||
GetCurrentPanGestureBlock()->GetOverscrollHandoffChain();
|
||||
if (!overscrollHandoffChain->CanScrollInDirection(this, Layer::HORIZONTAL)) {
|
||||
mX.SetVelocity(0);
|
||||
}
|
||||
|
@ -1982,13 +1991,12 @@ nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent)
|
|||
if (controller) {
|
||||
LayoutDevicePoint geckoScreenPoint;
|
||||
if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) {
|
||||
CancelableBlockState* block = CurrentInputBlock();
|
||||
MOZ_ASSERT(block);
|
||||
if (!block->AsTouchBlock()) {
|
||||
TouchBlockState* touch = GetCurrentTouchBlock();
|
||||
if (!touch) {
|
||||
APZC_LOG("%p dropping long-press because some non-touch block interrupted it\n", this);
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
if (block->AsTouchBlock()->IsDuringFastFling()) {
|
||||
if (touch->IsDuringFastFling()) {
|
||||
APZC_LOG("%p dropping long-press because of fast fling\n", this);
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
@ -2011,10 +2019,8 @@ nsEventStatus AsyncPanZoomController::GenerateSingleTap(TapType aType,
|
|||
if (controller) {
|
||||
LayoutDevicePoint geckoScreenPoint;
|
||||
if (ConvertToGecko(aPoint, &geckoScreenPoint)) {
|
||||
CancelableBlockState* block = CurrentInputBlock();
|
||||
MOZ_ASSERT(block);
|
||||
TouchBlockState* touch = block->AsTouchBlock();
|
||||
// |block| may be a non-touch block in the case where this function is
|
||||
TouchBlockState* touch = GetCurrentTouchBlock();
|
||||
// |touch| may be null in the case where this function is
|
||||
// invoked by GestureEventListener on a timeout. In that case we already
|
||||
// verified that the single tap is allowed so we let it through.
|
||||
// XXX there is a bug here that in such a case the touch block that
|
||||
|
@ -2049,8 +2055,9 @@ nsEventStatus AsyncPanZoomController::GenerateSingleTap(TapType aType,
|
|||
|
||||
void AsyncPanZoomController::OnTouchEndOrCancel() {
|
||||
if (RefPtr<GeckoContentController> controller = GetGeckoContentController()) {
|
||||
MOZ_ASSERT(GetCurrentTouchBlock());
|
||||
controller->NotifyAPZStateChange(
|
||||
GetGuid(), APZStateChange::eEndTouch, CurrentTouchBlock()->SingleTapOccurred());
|
||||
GetGuid(), APZStateChange::eEndTouch, GetCurrentTouchBlock()->SingleTapOccurred());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2058,7 +2065,8 @@ nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEven
|
|||
APZC_LOG("%p got a single-tap-up in state %d\n", this, mState);
|
||||
// If mZoomConstraints.mAllowDoubleTapZoom is true we wait for a call to OnSingleTapConfirmed before
|
||||
// sending event to content
|
||||
if (!(mZoomConstraints.mAllowDoubleTapZoom && CurrentTouchBlock()->TouchActionAllowsDoubleTapZoom())) {
|
||||
MOZ_ASSERT(GetCurrentTouchBlock());
|
||||
if (!(mZoomConstraints.mAllowDoubleTapZoom && GetCurrentTouchBlock()->TouchActionAllowsDoubleTapZoom())) {
|
||||
return GenerateSingleTap(TapType::eSingleTap, aEvent.mPoint, aEvent.modifiers);
|
||||
}
|
||||
return nsEventStatus_eIgnore;
|
||||
|
@ -2073,11 +2081,12 @@ nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent)
|
|||
APZC_LOG("%p got a double-tap in state %d\n", this, mState);
|
||||
RefPtr<GeckoContentController> controller = GetGeckoContentController();
|
||||
if (controller) {
|
||||
if (mZoomConstraints.mAllowDoubleTapZoom && CurrentTouchBlock()->TouchActionAllowsDoubleTapZoom()) {
|
||||
MOZ_ASSERT(GetCurrentTouchBlock());
|
||||
if (mZoomConstraints.mAllowDoubleTapZoom && GetCurrentTouchBlock()->TouchActionAllowsDoubleTapZoom()) {
|
||||
LayoutDevicePoint geckoScreenPoint;
|
||||
if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) {
|
||||
controller->HandleTap(TapType::eDoubleTap, geckoScreenPoint,
|
||||
aEvent.modifiers, GetGuid(), CurrentTouchBlock()->GetBlockId());
|
||||
aEvent.modifiers, GetGuid(), GetCurrentTouchBlock()->GetBlockId());
|
||||
}
|
||||
}
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
|
@ -2153,7 +2162,8 @@ void AsyncPanZoomController::SetVelocityVector(const ParentLayerPoint& aVelocity
|
|||
void AsyncPanZoomController::HandlePanningWithTouchAction(double aAngle) {
|
||||
// Handling of cross sliding will need to be added in this method after touch-action released
|
||||
// enabled by default.
|
||||
if (CurrentTouchBlock()->TouchActionAllowsPanningXY()) {
|
||||
MOZ_ASSERT(GetCurrentTouchBlock());
|
||||
if (GetCurrentTouchBlock()->TouchActionAllowsPanningXY()) {
|
||||
if (mX.CanScrollNow() && mY.CanScrollNow()) {
|
||||
if (IsCloseToHorizontal(aAngle, gfxPrefs::APZAxisLockAngle())) {
|
||||
mY.SetAxisLocked(true);
|
||||
|
@ -2169,7 +2179,7 @@ void AsyncPanZoomController::HandlePanningWithTouchAction(double aAngle) {
|
|||
} else {
|
||||
SetState(NOTHING);
|
||||
}
|
||||
} else if (CurrentTouchBlock()->TouchActionAllowsPanningX()) {
|
||||
} else if (GetCurrentTouchBlock()->TouchActionAllowsPanningX()) {
|
||||
// Using bigger angle for panning to keep behavior consistent
|
||||
// with IE.
|
||||
if (IsCloseToHorizontal(aAngle, gfxPrefs::APZAllowedDirectPanAngle())) {
|
||||
|
@ -2181,7 +2191,7 @@ void AsyncPanZoomController::HandlePanningWithTouchAction(double aAngle) {
|
|||
// requires it.
|
||||
SetState(NOTHING);
|
||||
}
|
||||
} else if (CurrentTouchBlock()->TouchActionAllowsPanningY()) {
|
||||
} else if (GetCurrentTouchBlock()->TouchActionAllowsPanningY()) {
|
||||
if (IsCloseToVertical(aAngle, gfxPrefs::APZAllowedDirectPanAngle())) {
|
||||
mX.SetAxisLocked(true);
|
||||
SetState(PANNING_LOCKED_Y);
|
||||
|
@ -2203,8 +2213,9 @@ void AsyncPanZoomController::HandlePanningWithTouchAction(double aAngle) {
|
|||
|
||||
void AsyncPanZoomController::HandlePanning(double aAngle) {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
MOZ_ASSERT(GetCurrentInputBlock());
|
||||
RefPtr<const OverscrollHandoffChain> overscrollHandoffChain =
|
||||
CurrentInputBlock()->GetOverscrollHandoffChain();
|
||||
GetCurrentInputBlock()->GetOverscrollHandoffChain();
|
||||
bool canScrollHorizontal = !mX.IsAxisLocked() &&
|
||||
overscrollHandoffChain->CanScrollInDirection(this, Layer::HORIZONTAL);
|
||||
bool canScrollVertical = !mY.IsAxisLocked() &&
|
||||
|
@ -2305,7 +2316,7 @@ bool AsyncPanZoomController::AttemptScroll(ParentLayerPoint& aStartPoint,
|
|||
// the earlier APZC was scrolled to its extent in the original direction).
|
||||
// We want to disallow this.
|
||||
bool scrollThisApzc = false;
|
||||
if (InputBlockState* block = CurrentInputBlock()) {
|
||||
if (InputBlockState* block = GetCurrentInputBlock()) {
|
||||
scrollThisApzc = !block->GetScrolledApzc() || block->IsDownchainOfScrolledApzc(this);
|
||||
}
|
||||
|
||||
|
@ -2326,7 +2337,7 @@ bool AsyncPanZoomController::AttemptScroll(ParentLayerPoint& aStartPoint,
|
|||
|
||||
if (!IsZero(adjustedDisplacement)) {
|
||||
ScrollBy(adjustedDisplacement / mFrameMetrics.GetZoom());
|
||||
if (CancelableBlockState* block = CurrentInputBlock()) {
|
||||
if (CancelableBlockState* block = GetCurrentInputBlock()) {
|
||||
if (block->AsTouchBlock() && (block->GetScrolledApzc() != this)) {
|
||||
RefPtr<GeckoContentController> controller = GetGeckoContentController();
|
||||
if (controller) {
|
||||
|
@ -2545,8 +2556,9 @@ void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
|
|||
if (prevTouchPoint != touchPoint) {
|
||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
|
||||
(uint32_t) ScrollInputMethod::ApzTouch);
|
||||
MOZ_ASSERT(GetCurrentTouchBlock());
|
||||
OverscrollHandoffState handoffState(
|
||||
*CurrentTouchBlock()->GetOverscrollHandoffChain(),
|
||||
*GetCurrentTouchBlock()->GetOverscrollHandoffChain(),
|
||||
panDistance,
|
||||
ScrollSource::Touch);
|
||||
CallDispatchScroll(prevTouchPoint, touchPoint, handoffState);
|
||||
|
@ -3611,21 +3623,21 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect, const uint32_t aFlags) {
|
|||
}
|
||||
|
||||
CancelableBlockState*
|
||||
AsyncPanZoomController::CurrentInputBlock() const
|
||||
AsyncPanZoomController::GetCurrentInputBlock() const
|
||||
{
|
||||
return GetInputQueue()->CurrentBlock();
|
||||
return GetInputQueue()->GetCurrentBlock();
|
||||
}
|
||||
|
||||
TouchBlockState*
|
||||
AsyncPanZoomController::CurrentTouchBlock() const
|
||||
AsyncPanZoomController::GetCurrentTouchBlock() const
|
||||
{
|
||||
return GetInputQueue()->CurrentTouchBlock();
|
||||
return GetInputQueue()->GetCurrentTouchBlock();
|
||||
}
|
||||
|
||||
PanGestureBlockState*
|
||||
AsyncPanZoomController::CurrentPanGestureBlock() const
|
||||
AsyncPanZoomController::GetCurrentPanGestureBlock() const
|
||||
{
|
||||
return GetInputQueue()->CurrentPanGestureBlock();
|
||||
return GetInputQueue()->GetCurrentPanGestureBlock();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3639,7 +3651,7 @@ AsyncPanZoomController::ResetTouchInputState()
|
|||
CancelAnimationAndGestureState();
|
||||
// Clear overscroll along the entire handoff chain, in case an APZC
|
||||
// later in the chain is overscrolled.
|
||||
if (TouchBlockState* block = CurrentInputBlock()->AsTouchBlock()) {
|
||||
if (TouchBlockState* block = GetCurrentTouchBlock()) {
|
||||
block->GetOverscrollHandoffChain()->ClearOverscroll();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -861,11 +861,11 @@ private:
|
|||
void CancelAnimationAndGestureState();
|
||||
|
||||
RefPtr<InputQueue> mInputQueue;
|
||||
CancelableBlockState* CurrentInputBlock() const;
|
||||
TouchBlockState* CurrentTouchBlock() const;
|
||||
CancelableBlockState* GetCurrentInputBlock() const;
|
||||
TouchBlockState* GetCurrentTouchBlock() const;
|
||||
bool HasReadyTouchBlock() const;
|
||||
|
||||
PanGestureBlockState* CurrentPanGestureBlock() const;
|
||||
PanGestureBlockState* GetCurrentPanGestureBlock() const;
|
||||
|
||||
private:
|
||||
/* ===================================================================
|
||||
|
|
|
@ -526,7 +526,8 @@ void GestureEventListener::CreateMaxTapTimeoutTask()
|
|||
{
|
||||
mLastTapInput = mLastTouchInput;
|
||||
|
||||
TouchBlockState* block = mAsyncPanZoomController->GetInputQueue()->CurrentTouchBlock();
|
||||
TouchBlockState* block = mAsyncPanZoomController->GetInputQueue()->GetCurrentTouchBlock();
|
||||
MOZ_ASSERT(block);
|
||||
RefPtr<CancelableRunnable> task =
|
||||
NewCancelableRunnableMethod<bool>(this,
|
||||
&GestureEventListener::HandleInputTimeoutMaxTap,
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "mozilla/Telemetry.h" // for Telemetry
|
||||
#include "mozilla/layers/APZCTreeManager.h" // for AllowedTouchBehavior
|
||||
#include "OverscrollHandoffState.h"
|
||||
#include "QueuedInput.h"
|
||||
|
||||
#define TBS_LOG(...)
|
||||
// #define TBS_LOG(...) printf_stderr("TBS: " __VA_ARGS__)
|
||||
|
@ -37,7 +38,8 @@ InputBlockState::InputBlockState(const RefPtr<AsyncPanZoomController>& aTargetAp
|
|||
|
||||
bool
|
||||
InputBlockState::SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
|
||||
TargetConfirmationState aState)
|
||||
TargetConfirmationState aState,
|
||||
InputData* aFirstInput)
|
||||
{
|
||||
MOZ_ASSERT(aState == TargetConfirmationState::eConfirmed
|
||||
|| aState == TargetConfirmationState::eTimedOut);
|
||||
|
@ -223,14 +225,6 @@ CancelableBlockState::IsReadyForHandling() const
|
|||
return mContentResponded || mContentResponseTimerExpired;
|
||||
}
|
||||
|
||||
void
|
||||
CancelableBlockState::DispatchImmediate(const InputData& aEvent) const
|
||||
{
|
||||
MOZ_ASSERT(!HasEvents());
|
||||
MOZ_ASSERT(GetTargetApzc());
|
||||
DispatchEvent(aEvent);
|
||||
}
|
||||
|
||||
void
|
||||
CancelableBlockState::DispatchEvent(const InputData& aEvent) const
|
||||
{
|
||||
|
@ -294,36 +288,6 @@ DragBlockState::DispatchEvent(const InputData& aEvent) const
|
|||
GetTargetApzc()->HandleDragEvent(mouseInput, mDragMetrics);
|
||||
}
|
||||
|
||||
void
|
||||
DragBlockState::AddEvent(const MouseInput& aEvent)
|
||||
{
|
||||
mEvents.AppendElement(aEvent);
|
||||
}
|
||||
|
||||
bool
|
||||
DragBlockState::HasEvents() const
|
||||
{
|
||||
return !mEvents.IsEmpty();
|
||||
}
|
||||
|
||||
void
|
||||
DragBlockState::DropEvents()
|
||||
{
|
||||
TBS_LOG("%p dropping %" PRIuSIZE " events\n", this, mEvents.Length());
|
||||
mEvents.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
DragBlockState::HandleEvents()
|
||||
{
|
||||
while (HasEvents()) {
|
||||
TBS_LOG("%p returning first of %" PRIuSIZE " events\n", this, mEvents.Length());
|
||||
MouseInput event = mEvents[0];
|
||||
mEvents.RemoveElementAt(0);
|
||||
DispatchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
DragBlockState::MustStayActive()
|
||||
{
|
||||
|
@ -379,18 +343,18 @@ WheelBlockState::SetContentResponse(bool aPreventDefault)
|
|||
|
||||
bool
|
||||
WheelBlockState::SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
|
||||
TargetConfirmationState aState)
|
||||
TargetConfirmationState aState,
|
||||
InputData* aFirstInput)
|
||||
{
|
||||
// The APZC that we find via APZCCallbackHelpers may not be the same APZC
|
||||
// ESM or OverscrollHandoff would have computed. Make sure we get the right
|
||||
// one by looking for the first apzc the next pending event can scroll.
|
||||
RefPtr<AsyncPanZoomController> apzc = aTargetApzc;
|
||||
if (apzc && mEvents.Length() > 0) {
|
||||
const ScrollWheelInput& event = mEvents.ElementAt(0);
|
||||
apzc = apzc->BuildOverscrollHandoffChain()->FindFirstScrollable(event);
|
||||
if (apzc && aFirstInput) {
|
||||
apzc = apzc->BuildOverscrollHandoffChain()->FindFirstScrollable(*aFirstInput);
|
||||
}
|
||||
|
||||
InputBlockState::SetConfirmedTargetApzc(apzc, aState);
|
||||
InputBlockState::SetConfirmedTargetApzc(apzc, aState, aFirstInput);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -433,36 +397,6 @@ WheelBlockState::Update(ScrollWheelInput& aEvent)
|
|||
mLastMouseMove = TimeStamp();
|
||||
}
|
||||
|
||||
void
|
||||
WheelBlockState::AddEvent(const ScrollWheelInput& aEvent)
|
||||
{
|
||||
mEvents.AppendElement(aEvent);
|
||||
}
|
||||
|
||||
bool
|
||||
WheelBlockState::HasEvents() const
|
||||
{
|
||||
return !mEvents.IsEmpty();
|
||||
}
|
||||
|
||||
void
|
||||
WheelBlockState::DropEvents()
|
||||
{
|
||||
TBS_LOG("%p dropping %" PRIuSIZE " events\n", this, mEvents.Length());
|
||||
mEvents.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
WheelBlockState::HandleEvents()
|
||||
{
|
||||
while (HasEvents()) {
|
||||
TBS_LOG("%p returning first of %" PRIuSIZE " events\n", this, mEvents.Length());
|
||||
ScrollWheelInput event = mEvents[0];
|
||||
mEvents.RemoveElementAt(0);
|
||||
DispatchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WheelBlockState::MustStayActive()
|
||||
{
|
||||
|
@ -624,55 +558,25 @@ PanGestureBlockState::PanGestureBlockState(const RefPtr<AsyncPanZoomController>&
|
|||
|
||||
bool
|
||||
PanGestureBlockState::SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
|
||||
TargetConfirmationState aState)
|
||||
TargetConfirmationState aState,
|
||||
InputData* aFirstInput)
|
||||
{
|
||||
// The APZC that we find via APZCCallbackHelpers may not be the same APZC
|
||||
// ESM or OverscrollHandoff would have computed. Make sure we get the right
|
||||
// one by looking for the first apzc the next pending event can scroll.
|
||||
RefPtr<AsyncPanZoomController> apzc = aTargetApzc;
|
||||
if (apzc && mEvents.Length() > 0) {
|
||||
const PanGestureInput& event = mEvents.ElementAt(0);
|
||||
if (apzc && aFirstInput) {
|
||||
RefPtr<AsyncPanZoomController> scrollableApzc =
|
||||
apzc->BuildOverscrollHandoffChain()->FindFirstScrollable(event);
|
||||
apzc->BuildOverscrollHandoffChain()->FindFirstScrollable(*aFirstInput);
|
||||
if (scrollableApzc) {
|
||||
apzc = scrollableApzc;
|
||||
}
|
||||
}
|
||||
|
||||
InputBlockState::SetConfirmedTargetApzc(apzc, aState);
|
||||
InputBlockState::SetConfirmedTargetApzc(apzc, aState, aFirstInput);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PanGestureBlockState::AddEvent(const PanGestureInput& aEvent)
|
||||
{
|
||||
mEvents.AppendElement(aEvent);
|
||||
}
|
||||
|
||||
bool
|
||||
PanGestureBlockState::HasEvents() const
|
||||
{
|
||||
return !mEvents.IsEmpty();
|
||||
}
|
||||
|
||||
void
|
||||
PanGestureBlockState::DropEvents()
|
||||
{
|
||||
TBS_LOG("%p dropping %" PRIuSIZE " events\n", this, mEvents.Length());
|
||||
mEvents.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
PanGestureBlockState::HandleEvents()
|
||||
{
|
||||
while (HasEvents()) {
|
||||
TBS_LOG("%p returning first of %" PRIuSIZE " events\n", this, mEvents.Length());
|
||||
PanGestureInput event = mEvents[0];
|
||||
mEvents.RemoveElementAt(0);
|
||||
DispatchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
PanGestureBlockState::MustStayActive()
|
||||
{
|
||||
|
@ -831,19 +735,6 @@ TouchBlockState::SingleTapOccurred() const
|
|||
return mSingleTapOccurred;
|
||||
}
|
||||
|
||||
bool
|
||||
TouchBlockState::HasEvents() const
|
||||
{
|
||||
return !mEvents.IsEmpty();
|
||||
}
|
||||
|
||||
void
|
||||
TouchBlockState::AddEvent(const MultiTouchInput& aEvent)
|
||||
{
|
||||
TBS_LOG("%p adding event of type %d\n", this, aEvent.mType);
|
||||
mEvents.AppendElement(aEvent);
|
||||
}
|
||||
|
||||
bool
|
||||
TouchBlockState::MustStayActive()
|
||||
{
|
||||
|
@ -856,24 +747,6 @@ TouchBlockState::Type()
|
|||
return "touch";
|
||||
}
|
||||
|
||||
void
|
||||
TouchBlockState::DropEvents()
|
||||
{
|
||||
TBS_LOG("%p dropping %" PRIuSIZE " events\n", this, mEvents.Length());
|
||||
mEvents.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
TouchBlockState::HandleEvents()
|
||||
{
|
||||
while (HasEvents()) {
|
||||
TBS_LOG("%p returning first of %" PRIuSIZE " events\n", this, mEvents.Length());
|
||||
MultiTouchInput event = mEvents[0];
|
||||
mEvents.RemoveElementAt(0);
|
||||
DispatchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TouchBlockState::DispatchEvent(const InputData& aEvent) const
|
||||
{
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#define mozilla_layers_InputBlockState_h
|
||||
|
||||
#include "InputData.h" // for MultiTouchInput
|
||||
#include "mozilla/RefCounted.h" // for RefCounted
|
||||
#include "mozilla/RefPtr.h" // for RefPtr
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
#include "mozilla/layers/APZUtils.h" // for TouchBehaviorFlags
|
||||
|
@ -29,14 +30,15 @@ class PanGestureBlockState;
|
|||
|
||||
/**
|
||||
* A base class that stores state common to various input blocks.
|
||||
* Currently, it just stores the overscroll handoff chain.
|
||||
* Note that the InputBlockState constructor acquires the tree lock, so callers
|
||||
* from inside AsyncPanZoomController should ensure that the APZC lock is not
|
||||
* held.
|
||||
*/
|
||||
class InputBlockState
|
||||
class InputBlockState : public RefCounted<InputBlockState>
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(InputBlockState)
|
||||
|
||||
static const uint64_t NO_BLOCK_ID = 0;
|
||||
|
||||
enum class TargetConfirmationState {
|
||||
|
@ -52,7 +54,8 @@ public:
|
|||
{}
|
||||
|
||||
virtual bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
|
||||
TargetConfirmationState aState);
|
||||
TargetConfirmationState aState,
|
||||
InputData* aFirstInput);
|
||||
const RefPtr<AsyncPanZoomController>& GetTargetApzc() const;
|
||||
const RefPtr<const OverscrollHandoffChain>& GetOverscrollHandoffChain() const;
|
||||
uint64_t GetBlockId() const;
|
||||
|
@ -161,13 +164,6 @@ public:
|
|||
*/
|
||||
bool IsDefaultPrevented() const;
|
||||
|
||||
/**
|
||||
* Process the given event using this input block's target apzc.
|
||||
* This input block must not have pending events, and its apzc must not be
|
||||
* nullptr.
|
||||
*/
|
||||
void DispatchImmediate(const InputData& aEvent) const;
|
||||
|
||||
/**
|
||||
* Dispatch the event to the target APZC. Mostly this is a hook for
|
||||
* subclasses to do any per-event processing they need to.
|
||||
|
@ -186,22 +182,6 @@ public:
|
|||
*/
|
||||
virtual bool IsReadyForHandling() const;
|
||||
|
||||
/**
|
||||
* Returns whether or not this block has pending events.
|
||||
*/
|
||||
virtual bool HasEvents() const = 0;
|
||||
|
||||
/**
|
||||
* Throw away all the events in this input block.
|
||||
*/
|
||||
virtual void DropEvents() = 0;
|
||||
|
||||
/**
|
||||
* Process all events using this input block's target apzc, leaving this
|
||||
* block depleted. This input block's apzc must not be nullptr.
|
||||
*/
|
||||
virtual void HandleEvents() = 0;
|
||||
|
||||
/**
|
||||
* Return true if this input block must stay active if it would otherwise
|
||||
* be removed as the last item in the pending queue.
|
||||
|
@ -231,15 +211,11 @@ public:
|
|||
const ScrollWheelInput& aEvent);
|
||||
|
||||
bool SetContentResponse(bool aPreventDefault) override;
|
||||
bool HasEvents() const override;
|
||||
void DropEvents() override;
|
||||
void HandleEvents() override;
|
||||
bool MustStayActive() override;
|
||||
const char* Type() override;
|
||||
bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
|
||||
TargetConfirmationState aState) override;
|
||||
|
||||
void AddEvent(const ScrollWheelInput& aEvent);
|
||||
TargetConfirmationState aState,
|
||||
InputData* aFirstInput) override;
|
||||
|
||||
WheelBlockState *AsWheelBlock() override {
|
||||
return this;
|
||||
|
@ -299,7 +275,6 @@ protected:
|
|||
void UpdateTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc) override;
|
||||
|
||||
private:
|
||||
nsTArray<ScrollWheelInput> mEvents;
|
||||
TimeStamp mLastEventTime;
|
||||
TimeStamp mLastMouseMove;
|
||||
uint32_t mScrollSeriesCounter;
|
||||
|
@ -316,17 +291,12 @@ public:
|
|||
bool aTargetConfirmed,
|
||||
const MouseInput& aEvent);
|
||||
|
||||
bool HasEvents() const override;
|
||||
void DropEvents() override;
|
||||
void HandleEvents() override;
|
||||
bool MustStayActive() override;
|
||||
const char* Type() override;
|
||||
|
||||
bool HasReceivedMouseUp();
|
||||
void MarkMouseUpReceived();
|
||||
|
||||
void AddEvent(const MouseInput& aEvent);
|
||||
|
||||
DragBlockState *AsDragBlock() override {
|
||||
return this;
|
||||
}
|
||||
|
@ -335,7 +305,6 @@ public:
|
|||
|
||||
void DispatchEvent(const InputData& aEvent) const override;
|
||||
private:
|
||||
nsTArray<MouseInput> mEvents;
|
||||
AsyncDragMetrics mDragMetrics;
|
||||
bool mReceivedMouseUp;
|
||||
};
|
||||
|
@ -353,15 +322,11 @@ public:
|
|||
bool SetContentResponse(bool aPreventDefault) override;
|
||||
bool HasReceivedAllContentNotifications() const override;
|
||||
bool IsReadyForHandling() const override;
|
||||
bool HasEvents() const override;
|
||||
void DropEvents() override;
|
||||
void HandleEvents() override;
|
||||
bool MustStayActive() override;
|
||||
const char* Type() override;
|
||||
bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
|
||||
TargetConfirmationState aState) override;
|
||||
|
||||
void AddEvent(const PanGestureInput& aEvent);
|
||||
TargetConfirmationState aState,
|
||||
InputData* aFirstInput) override;
|
||||
|
||||
PanGestureBlockState *AsPanGestureBlock() override {
|
||||
return this;
|
||||
|
@ -377,7 +342,6 @@ public:
|
|||
void SetNeedsToWaitForContentResponse(bool aWaitForContentResponse);
|
||||
|
||||
private:
|
||||
nsTArray<PanGestureInput> mEvents;
|
||||
bool mInterrupted;
|
||||
bool mWaitingForContentResponse;
|
||||
};
|
||||
|
@ -463,11 +427,6 @@ public:
|
|||
*/
|
||||
bool SingleTapOccurred() const;
|
||||
|
||||
/**
|
||||
* Add a new touch event to the queue of events in this input block.
|
||||
*/
|
||||
void AddEvent(const MultiTouchInput& aEvent);
|
||||
|
||||
/**
|
||||
* @return false iff touch-action is enabled and the allowed touch behaviors for
|
||||
* this touch block do not allow pinch-zooming.
|
||||
|
@ -503,9 +462,6 @@ public:
|
|||
*/
|
||||
uint32_t GetActiveTouchCount() const;
|
||||
|
||||
bool HasEvents() const override;
|
||||
void DropEvents() override;
|
||||
void HandleEvents() override;
|
||||
void DispatchEvent(const InputData& aEvent) const override;
|
||||
bool MustStayActive() override;
|
||||
const char* Type() override;
|
||||
|
@ -517,7 +473,6 @@ private:
|
|||
bool mSingleTapOccurred;
|
||||
bool mInSlop;
|
||||
ScreenIntPoint mSlopOrigin;
|
||||
nsTArray<MultiTouchInput> mEvents;
|
||||
// A reference to the InputQueue's touch counter
|
||||
TouchCounter& mTouchCounter;
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "LayersLogging.h"
|
||||
#include "mozilla/layers/APZThreadUtils.h"
|
||||
#include "OverscrollHandoffState.h"
|
||||
#include "QueuedInput.h"
|
||||
|
||||
#define INPQ_LOG(...)
|
||||
// #define INPQ_LOG(...) printf_stderr("INPQ: " __VA_ARGS__)
|
||||
|
@ -24,7 +25,7 @@ InputQueue::InputQueue()
|
|||
}
|
||||
|
||||
InputQueue::~InputQueue() {
|
||||
mInputBlockQueue.Clear();
|
||||
mQueuedInputs.Clear();
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
|
@ -64,23 +65,6 @@ InputQueue::ReceiveInputEvent(const RefPtr<AsyncPanZoomController>& aTarget,
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
InputQueue::MaybeHandleCurrentBlock(CancelableBlockState *block,
|
||||
const InputData& aEvent) {
|
||||
if (block == CurrentBlock() && block->IsReadyForHandling()) {
|
||||
const RefPtr<AsyncPanZoomController>& target = block->GetTargetApzc();
|
||||
INPQ_LOG("current block is ready with target %p preventdefault %d\n",
|
||||
target.get(), block->IsDefaultPrevented());
|
||||
if (!target || block->IsDefaultPrevented()) {
|
||||
return true;
|
||||
}
|
||||
UpdateActiveApzc(block->GetTargetApzc());
|
||||
block->DispatchImmediate(aEvent);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
InputQueue::ReceiveTouchInput(const RefPtr<AsyncPanZoomController>& aTarget,
|
||||
bool aTargetConfirmed,
|
||||
|
@ -92,13 +76,13 @@ InputQueue::ReceiveTouchInput(const RefPtr<AsyncPanZoomController>& aTarget,
|
|||
bool haveBehaviors = false;
|
||||
if (!gfxPrefs::TouchActionEnabled()) {
|
||||
haveBehaviors = true;
|
||||
} else if (!mInputBlockQueue.IsEmpty() && CurrentBlock()->AsTouchBlock()) {
|
||||
haveBehaviors = CurrentTouchBlock()->GetAllowedTouchBehaviors(currentBehaviors);
|
||||
} else if (mActiveTouchBlock) {
|
||||
haveBehaviors = mActiveTouchBlock->GetAllowedTouchBehaviors(currentBehaviors);
|
||||
// If the behaviours aren't set, but the main-thread response timer on
|
||||
// the block is expired we still treat it as though it has behaviors,
|
||||
// because in that case we still want to interrupt the fast-fling and
|
||||
// use the default behaviours.
|
||||
haveBehaviors |= CurrentTouchBlock()->IsContentResponseTimerExpired();
|
||||
haveBehaviors |= mActiveTouchBlock->IsContentResponseTimerExpired();
|
||||
}
|
||||
|
||||
block = StartNewTouchBlock(aTarget, aTargetConfirmed, false);
|
||||
|
@ -108,7 +92,7 @@ InputQueue::ReceiveTouchInput(const RefPtr<AsyncPanZoomController>& aTarget,
|
|||
// XXX using the chain from |block| here may be wrong in cases where the
|
||||
// target isn't confirmed and the real target turns out to be something
|
||||
// else. For now assume this is rare enough that it's not an issue.
|
||||
if (block == CurrentBlock() &&
|
||||
if (mQueuedInputs.IsEmpty() &&
|
||||
aEvent.mTouches.Length() == 1 &&
|
||||
block->GetOverscrollHandoffChain()->HasFastFlungApzc() &&
|
||||
haveBehaviors) {
|
||||
|
@ -119,7 +103,8 @@ InputQueue::ReceiveTouchInput(const RefPtr<AsyncPanZoomController>& aTarget,
|
|||
// the first finger is moving).
|
||||
block->SetDuringFastFling();
|
||||
block->SetConfirmedTargetApzc(aTarget,
|
||||
InputBlockState::TargetConfirmationState::eConfirmed);
|
||||
InputBlockState::TargetConfirmationState::eConfirmed,
|
||||
nullptr /* the block was just created so it has no events */);
|
||||
if (gfxPrefs::TouchActionEnabled()) {
|
||||
block->SetAllowedTouchBehaviors(currentBehaviors);
|
||||
}
|
||||
|
@ -130,10 +115,7 @@ InputQueue::ReceiveTouchInput(const RefPtr<AsyncPanZoomController>& aTarget,
|
|||
|
||||
MaybeRequestContentResponse(aTarget, block);
|
||||
} else {
|
||||
if (!mInputBlockQueue.IsEmpty()) {
|
||||
block = mInputBlockQueue.LastElement().get()->AsTouchBlock();
|
||||
}
|
||||
|
||||
block = mActiveTouchBlock.get();
|
||||
if (!block) {
|
||||
NS_WARNING("Received a non-start touch event while no touch blocks active!");
|
||||
return nsEventStatus_eIgnore;
|
||||
|
@ -160,20 +142,19 @@ InputQueue::ReceiveTouchInput(const RefPtr<AsyncPanZoomController>& aTarget,
|
|||
if (block->IsDuringFastFling()) {
|
||||
INPQ_LOG("dropping event due to block %p being in fast motion\n", block);
|
||||
result = nsEventStatus_eConsumeNoDefault;
|
||||
} else if (target && target->ArePointerEventsConsumable(block, aEvent.AsMultiTouchInput().mTouches.Length())) {
|
||||
if (block->UpdateSlopState(aEvent.AsMultiTouchInput(), true)) {
|
||||
} else if (target && target->ArePointerEventsConsumable(block, aEvent.mTouches.Length())) {
|
||||
if (block->UpdateSlopState(aEvent, true)) {
|
||||
INPQ_LOG("dropping event due to block %p being in slop\n", block);
|
||||
result = nsEventStatus_eConsumeNoDefault;
|
||||
} else {
|
||||
result = nsEventStatus_eConsumeDoDefault;
|
||||
}
|
||||
} else if (block->UpdateSlopState(aEvent.AsMultiTouchInput(), false)) {
|
||||
} else if (block->UpdateSlopState(aEvent, false)) {
|
||||
INPQ_LOG("dropping event due to block %p being in mini-slop\n", block);
|
||||
result = nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
if (!MaybeHandleCurrentBlock(block, aEvent)) {
|
||||
block->AddEvent(aEvent.AsMultiTouchInput());
|
||||
}
|
||||
mQueuedInputs.AppendElement(MakeUnique<QueuedInput>(aEvent, *block));
|
||||
ProcessQueue();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -186,11 +167,7 @@ InputQueue::ReceiveMouseInput(const RefPtr<AsyncPanZoomController>& aTarget,
|
|||
// with a new target.
|
||||
bool newBlock = DragTracker::StartsDrag(aEvent);
|
||||
|
||||
DragBlockState* block = nullptr;
|
||||
if (!newBlock && !mInputBlockQueue.IsEmpty()) {
|
||||
block = mInputBlockQueue.LastElement()->AsDragBlock();
|
||||
}
|
||||
|
||||
DragBlockState* block = newBlock ? nullptr : mActiveDragBlock.get();
|
||||
if (block && block->HasReceivedMouseUp()) {
|
||||
block = nullptr;
|
||||
}
|
||||
|
@ -218,8 +195,7 @@ InputQueue::ReceiveMouseInput(const RefPtr<AsyncPanZoomController>& aTarget,
|
|||
INPQ_LOG("started new drag block %p id %" PRIu64 " for %sconfirmed target %p\n",
|
||||
block, block->GetBlockId(), aTargetConfirmed ? "" : "un", aTarget.get());
|
||||
|
||||
SweepDepletedBlocks();
|
||||
mInputBlockQueue.AppendElement(block);
|
||||
mActiveDragBlock = block;
|
||||
|
||||
CancelAnimationsForNewBlock(block);
|
||||
MaybeRequestContentResponse(aTarget, block);
|
||||
|
@ -229,9 +205,8 @@ InputQueue::ReceiveMouseInput(const RefPtr<AsyncPanZoomController>& aTarget,
|
|||
*aOutInputBlockId = block->GetBlockId();
|
||||
}
|
||||
|
||||
if (!MaybeHandleCurrentBlock(block, aEvent)) {
|
||||
block->AddEvent(aEvent.AsMouseInput());
|
||||
}
|
||||
mQueuedInputs.AppendElement(MakeUnique<QueuedInput>(aEvent, *block));
|
||||
ProcessQueue();
|
||||
|
||||
if (DragTracker::EndsDrag(aEvent)) {
|
||||
block->MarkMouseUpReceived();
|
||||
|
@ -247,18 +222,14 @@ InputQueue::ReceiveScrollWheelInput(const RefPtr<AsyncPanZoomController>& aTarge
|
|||
bool aTargetConfirmed,
|
||||
const ScrollWheelInput& aEvent,
|
||||
uint64_t* aOutInputBlockId) {
|
||||
WheelBlockState* block = nullptr;
|
||||
if (!mInputBlockQueue.IsEmpty()) {
|
||||
block = mInputBlockQueue.LastElement()->AsWheelBlock();
|
||||
|
||||
// If the block is not accepting new events we'll create a new input block
|
||||
// (and therefore a new wheel transaction).
|
||||
if (block &&
|
||||
(!block->ShouldAcceptNewEvent() ||
|
||||
block->MaybeTimeout(aEvent)))
|
||||
{
|
||||
block = nullptr;
|
||||
}
|
||||
WheelBlockState* block = mActiveWheelBlock.get();
|
||||
// If the block is not accepting new events we'll create a new input block
|
||||
// (and therefore a new wheel transaction).
|
||||
if (block &&
|
||||
(!block->ShouldAcceptNewEvent() ||
|
||||
block->MaybeTimeout(aEvent)))
|
||||
{
|
||||
block = nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!block || block->InTransaction());
|
||||
|
@ -268,8 +239,7 @@ InputQueue::ReceiveScrollWheelInput(const RefPtr<AsyncPanZoomController>& aTarge
|
|||
INPQ_LOG("started new scroll wheel block %p id %" PRIu64 " for target %p\n",
|
||||
block, block->GetBlockId(), aTarget.get());
|
||||
|
||||
SweepDepletedBlocks();
|
||||
mInputBlockQueue.AppendElement(block);
|
||||
mActiveWheelBlock = block;
|
||||
|
||||
CancelAnimationsForNewBlock(block);
|
||||
MaybeRequestContentResponse(aTarget, block);
|
||||
|
@ -281,18 +251,19 @@ InputQueue::ReceiveScrollWheelInput(const RefPtr<AsyncPanZoomController>& aTarge
|
|||
*aOutInputBlockId = block->GetBlockId();
|
||||
}
|
||||
|
||||
// Copy the event, since WheelBlockState needs to affix a counter.
|
||||
ScrollWheelInput event(aEvent);
|
||||
block->Update(event);
|
||||
|
||||
// Note that the |aTarget| the APZCTM sent us may contradict the confirmed
|
||||
// target set on the block. In this case the confirmed target (which may be
|
||||
// null) should take priority. This is equivalent to just always using the
|
||||
// target (confirmed or not) from the block, which is what
|
||||
// MaybeHandleCurrentBlock() does.
|
||||
if (!MaybeHandleCurrentBlock(block, event)) {
|
||||
block->AddEvent(event);
|
||||
}
|
||||
// ProcessQueue() does.
|
||||
mQueuedInputs.AppendElement(MakeUnique<QueuedInput>(aEvent, *block));
|
||||
|
||||
// The WheelBlockState needs to affix a counter to the event before we process
|
||||
// it. Note that the counter is affixed to the copy in the queue rather than
|
||||
// |aEvent|.
|
||||
block->Update(mQueuedInputs.LastElement()->Input()->AsScrollWheelInput());
|
||||
|
||||
ProcessQueue();
|
||||
|
||||
return nsEventStatus_eConsumeDoDefault;
|
||||
}
|
||||
|
@ -320,9 +291,8 @@ InputQueue::ReceivePanGestureInput(const RefPtr<AsyncPanZoomController>& aTarget
|
|||
}
|
||||
|
||||
PanGestureBlockState* block = nullptr;
|
||||
if (!mInputBlockQueue.IsEmpty() &&
|
||||
aEvent.mType != PanGestureInput::PANGESTURE_START) {
|
||||
block = mInputBlockQueue.LastElement()->AsPanGestureBlock();
|
||||
if (aEvent.mType != PanGestureInput::PANGESTURE_START) {
|
||||
block = mActivePanGestureBlock.get();
|
||||
}
|
||||
|
||||
PanGestureInput event = aEvent;
|
||||
|
@ -355,8 +325,7 @@ InputQueue::ReceivePanGestureInput(const RefPtr<AsyncPanZoomController>& aTarget
|
|||
result = nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
SweepDepletedBlocks();
|
||||
mInputBlockQueue.AppendElement(block);
|
||||
mActivePanGestureBlock = block;
|
||||
|
||||
CancelAnimationsForNewBlock(block);
|
||||
MaybeRequestContentResponse(aTarget, block);
|
||||
|
@ -372,10 +341,9 @@ InputQueue::ReceivePanGestureInput(const RefPtr<AsyncPanZoomController>& aTarget
|
|||
// target set on the block. In this case the confirmed target (which may be
|
||||
// null) should take priority. This is equivalent to just always using the
|
||||
// target (confirmed or not) from the block, which is what
|
||||
// MaybeHandleCurrentBlock() does.
|
||||
if (!MaybeHandleCurrentBlock(block, event)) {
|
||||
block->AddEvent(event.AsPanGestureInput());
|
||||
}
|
||||
// ProcessQueue() does.
|
||||
mQueuedInputs.AppendElement(MakeUnique<QueuedInput>(event, *block));
|
||||
ProcessQueue();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -389,7 +357,7 @@ InputQueue::CancelAnimationsForNewBlock(CancelableBlockState* aBlock)
|
|||
// interfering with "past" animations (i.e. from a previous touch block that is still
|
||||
// being processed) we only do this animation-cancellation if there are no older
|
||||
// touch blocks still in the queue.
|
||||
if (aBlock == CurrentBlock()) {
|
||||
if (mQueuedInputs.IsEmpty()) {
|
||||
aBlock->GetOverscrollHandoffChain()->CancelAnimations(ExcludeOverscroll | ScrollSnap);
|
||||
}
|
||||
}
|
||||
|
@ -436,22 +404,6 @@ InputQueue::InjectNewTouchBlock(AsyncPanZoomController* aTarget)
|
|||
return block->GetBlockId();
|
||||
}
|
||||
|
||||
void
|
||||
InputQueue::SweepDepletedBlocks()
|
||||
{
|
||||
// We're going to start a new block, so clear out any depleted blocks at the head of the queue.
|
||||
// See corresponding comment in ProcessInputBlocks.
|
||||
while (!mInputBlockQueue.IsEmpty()) {
|
||||
CancelableBlockState* block = mInputBlockQueue[0].get();
|
||||
if (!block->IsReadyForHandling() || block->HasEvents()) {
|
||||
break;
|
||||
}
|
||||
|
||||
INPQ_LOG("discarding depleted %s block %p\n", block->Type(), block);
|
||||
mInputBlockQueue.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
TouchBlockState*
|
||||
InputQueue::StartNewTouchBlock(const RefPtr<AsyncPanZoomController>& aTarget,
|
||||
bool aTargetConfirmed,
|
||||
|
@ -460,64 +412,57 @@ InputQueue::StartNewTouchBlock(const RefPtr<AsyncPanZoomController>& aTarget,
|
|||
TouchBlockState* newBlock = new TouchBlockState(aTarget, aTargetConfirmed,
|
||||
mTouchCounter);
|
||||
if (aCopyPropertiesFromCurrent) {
|
||||
newBlock->CopyPropertiesFrom(*CurrentTouchBlock());
|
||||
// We should never enter here without a current touch block, because this
|
||||
// codepath is invoked from the OnLongPress handler in
|
||||
// AsyncPanZoomController, which should bail out if there is no current
|
||||
// touch block.
|
||||
MOZ_ASSERT(GetCurrentTouchBlock());
|
||||
newBlock->CopyPropertiesFrom(*GetCurrentTouchBlock());
|
||||
}
|
||||
|
||||
SweepDepletedBlocks();
|
||||
|
||||
// Add the new block to the queue.
|
||||
mInputBlockQueue.AppendElement(newBlock);
|
||||
mActiveTouchBlock = newBlock;
|
||||
return newBlock;
|
||||
}
|
||||
|
||||
CancelableBlockState*
|
||||
InputQueue::CurrentBlock() const
|
||||
InputQueue::GetCurrentBlock() const
|
||||
{
|
||||
APZThreadUtils::AssertOnControllerThread();
|
||||
|
||||
MOZ_ASSERT(!mInputBlockQueue.IsEmpty());
|
||||
return mInputBlockQueue[0].get();
|
||||
return mQueuedInputs.IsEmpty() ? nullptr : mQueuedInputs[0]->Block();
|
||||
}
|
||||
|
||||
TouchBlockState*
|
||||
InputQueue::CurrentTouchBlock() const
|
||||
InputQueue::GetCurrentTouchBlock() const
|
||||
{
|
||||
TouchBlockState* block = CurrentBlock()->AsTouchBlock();
|
||||
MOZ_ASSERT(block);
|
||||
return block;
|
||||
CancelableBlockState* block = GetCurrentBlock();
|
||||
return block ? block->AsTouchBlock() : mActiveTouchBlock.get();
|
||||
}
|
||||
|
||||
WheelBlockState*
|
||||
InputQueue::CurrentWheelBlock() const
|
||||
InputQueue::GetCurrentWheelBlock() const
|
||||
{
|
||||
WheelBlockState* block = CurrentBlock()->AsWheelBlock();
|
||||
MOZ_ASSERT(block);
|
||||
return block;
|
||||
CancelableBlockState* block = GetCurrentBlock();
|
||||
return block ? block->AsWheelBlock() : mActiveWheelBlock.get();
|
||||
}
|
||||
|
||||
DragBlockState*
|
||||
InputQueue::CurrentDragBlock() const
|
||||
InputQueue::GetCurrentDragBlock() const
|
||||
{
|
||||
DragBlockState* block = CurrentBlock()->AsDragBlock();
|
||||
MOZ_ASSERT(block);
|
||||
return block;
|
||||
CancelableBlockState* block = GetCurrentBlock();
|
||||
return block ? block->AsDragBlock() : mActiveDragBlock.get();
|
||||
}
|
||||
|
||||
PanGestureBlockState*
|
||||
InputQueue::CurrentPanGestureBlock() const
|
||||
InputQueue::GetCurrentPanGestureBlock() const
|
||||
{
|
||||
PanGestureBlockState* block = CurrentBlock()->AsPanGestureBlock();
|
||||
MOZ_ASSERT(block);
|
||||
return block;
|
||||
CancelableBlockState* block = GetCurrentBlock();
|
||||
return block ? block->AsPanGestureBlock() : mActivePanGestureBlock.get();
|
||||
}
|
||||
|
||||
WheelBlockState*
|
||||
InputQueue::GetCurrentWheelTransaction() const
|
||||
InputQueue::GetActiveWheelTransaction() const
|
||||
{
|
||||
if (mInputBlockQueue.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
WheelBlockState* block = CurrentBlock()->AsWheelBlock();
|
||||
WheelBlockState* block = mActiveWheelBlock.get();
|
||||
if (!block || !block->InTransaction()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -527,20 +472,19 @@ InputQueue::GetCurrentWheelTransaction() const
|
|||
bool
|
||||
InputQueue::HasReadyTouchBlock() const
|
||||
{
|
||||
return !mInputBlockQueue.IsEmpty() &&
|
||||
mInputBlockQueue[0]->AsTouchBlock() &&
|
||||
mInputBlockQueue[0]->IsReadyForHandling();
|
||||
return !mQueuedInputs.IsEmpty() &&
|
||||
mQueuedInputs[0]->Block()->AsTouchBlock() &&
|
||||
mQueuedInputs[0]->Block()->IsReadyForHandling();
|
||||
}
|
||||
|
||||
bool
|
||||
InputQueue::AllowScrollHandoff() const
|
||||
{
|
||||
MOZ_ASSERT(CurrentBlock());
|
||||
if (CurrentBlock()->AsWheelBlock()) {
|
||||
return CurrentBlock()->AsWheelBlock()->AllowScrollHandoff();
|
||||
if (GetCurrentWheelBlock()) {
|
||||
return GetCurrentWheelBlock()->AllowScrollHandoff();
|
||||
}
|
||||
if (CurrentBlock()->AsPanGestureBlock()) {
|
||||
return CurrentBlock()->AsPanGestureBlock()->AllowScrollHandoff();
|
||||
if (GetCurrentPanGestureBlock()) {
|
||||
return GetCurrentPanGestureBlock()->AllowScrollHandoff();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -569,26 +513,57 @@ InputQueue::ScheduleMainThreadTimeout(const RefPtr<AsyncPanZoomController>& aTar
|
|||
gfxPrefs::APZContentResponseTimeout());
|
||||
}
|
||||
|
||||
CancelableBlockState*
|
||||
InputQueue::FindBlockForId(uint64_t aInputBlockId,
|
||||
InputData** aOutFirstInput)
|
||||
{
|
||||
for (const auto& queuedInput : mQueuedInputs) {
|
||||
if (queuedInput->Block()->GetBlockId() == aInputBlockId) {
|
||||
if (aOutFirstInput) {
|
||||
*aOutFirstInput = queuedInput->Input();
|
||||
}
|
||||
return queuedInput->Block();
|
||||
}
|
||||
}
|
||||
|
||||
CancelableBlockState* block = nullptr;
|
||||
if (mActiveTouchBlock && mActiveTouchBlock->GetBlockId() == aInputBlockId) {
|
||||
block = mActiveTouchBlock.get();
|
||||
} else if (mActiveWheelBlock && mActiveWheelBlock->GetBlockId() == aInputBlockId) {
|
||||
block = mActiveWheelBlock.get();
|
||||
} else if (mActiveDragBlock && mActiveDragBlock->GetBlockId() == aInputBlockId) {
|
||||
block = mActiveDragBlock.get();
|
||||
} else if (mActivePanGestureBlock && mActivePanGestureBlock->GetBlockId() == aInputBlockId) {
|
||||
block = mActivePanGestureBlock.get();
|
||||
}
|
||||
// Since we didn't encounter this block while iterating through mQueuedInputs,
|
||||
// it must have no events associated with it at the moment.
|
||||
if (aOutFirstInput) {
|
||||
*aOutFirstInput = nullptr;
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
void
|
||||
InputQueue::MainThreadTimeout(const uint64_t& aInputBlockId) {
|
||||
InputQueue::MainThreadTimeout(uint64_t aInputBlockId) {
|
||||
APZThreadUtils::AssertOnControllerThread();
|
||||
|
||||
INPQ_LOG("got a main thread timeout; block=%" PRIu64 "\n", aInputBlockId);
|
||||
bool success = false;
|
||||
for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
|
||||
if (mInputBlockQueue[i]->GetBlockId() == aInputBlockId) {
|
||||
// time out the touch-listener response and also confirm the existing
|
||||
// target apzc in the case where the main thread doesn't get back to us
|
||||
// fast enough.
|
||||
success = mInputBlockQueue[i]->TimeoutContentResponse();
|
||||
success |= mInputBlockQueue[i]->SetConfirmedTargetApzc(
|
||||
mInputBlockQueue[i]->GetTargetApzc(),
|
||||
InputBlockState::TargetConfirmationState::eTimedOut);
|
||||
break;
|
||||
}
|
||||
InputData* firstInput = nullptr;
|
||||
CancelableBlockState* block = FindBlockForId(aInputBlockId, &firstInput);
|
||||
if (block) {
|
||||
// time out the touch-listener response and also confirm the existing
|
||||
// target apzc in the case where the main thread doesn't get back to us
|
||||
// fast enough.
|
||||
success = block->TimeoutContentResponse();
|
||||
success |= block->SetConfirmedTargetApzc(
|
||||
block->GetTargetApzc(),
|
||||
InputBlockState::TargetConfirmationState::eTimedOut,
|
||||
firstInput);
|
||||
}
|
||||
if (success) {
|
||||
ProcessInputBlocks();
|
||||
ProcessQueue();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -598,16 +573,13 @@ InputQueue::ContentReceivedInputBlock(uint64_t aInputBlockId, bool aPreventDefau
|
|||
|
||||
INPQ_LOG("got a content response; block=%" PRIu64 "\n", aInputBlockId);
|
||||
bool success = false;
|
||||
for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
|
||||
CancelableBlockState* block = mInputBlockQueue[i].get();
|
||||
if (block->GetBlockId() == aInputBlockId) {
|
||||
success = block->SetContentResponse(aPreventDefault);
|
||||
block->RecordContentResponseTime();
|
||||
break;
|
||||
}
|
||||
CancelableBlockState* block = FindBlockForId(aInputBlockId, nullptr);
|
||||
if (block) {
|
||||
success = block->SetContentResponse(aPreventDefault);
|
||||
block->RecordContentResponseTime();
|
||||
}
|
||||
if (success) {
|
||||
ProcessInputBlocks();
|
||||
ProcessQueue();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -618,17 +590,16 @@ InputQueue::SetConfirmedTargetApzc(uint64_t aInputBlockId, const RefPtr<AsyncPan
|
|||
INPQ_LOG("got a target apzc; block=%" PRIu64 " guid=%s\n",
|
||||
aInputBlockId, aTargetApzc ? Stringify(aTargetApzc->GetGuid()).c_str() : "");
|
||||
bool success = false;
|
||||
for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
|
||||
CancelableBlockState* block = mInputBlockQueue[i].get();
|
||||
if (block->GetBlockId() == aInputBlockId) {
|
||||
success = block->SetConfirmedTargetApzc(aTargetApzc,
|
||||
InputBlockState::TargetConfirmationState::eConfirmed);
|
||||
block->RecordContentResponseTime();
|
||||
break;
|
||||
}
|
||||
InputData* firstInput = nullptr;
|
||||
CancelableBlockState* block = FindBlockForId(aInputBlockId, &firstInput);
|
||||
if (block) {
|
||||
success = block->SetConfirmedTargetApzc(aTargetApzc,
|
||||
InputBlockState::TargetConfirmationState::eConfirmed,
|
||||
firstInput);
|
||||
block->RecordContentResponseTime();
|
||||
}
|
||||
if (success) {
|
||||
ProcessInputBlocks();
|
||||
ProcessQueue();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -641,18 +612,17 @@ InputQueue::ConfirmDragBlock(uint64_t aInputBlockId, const RefPtr<AsyncPanZoomCo
|
|||
INPQ_LOG("got a target apzc; block=%" PRIu64 " guid=%s\n",
|
||||
aInputBlockId, aTargetApzc ? Stringify(aTargetApzc->GetGuid()).c_str() : "");
|
||||
bool success = false;
|
||||
for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
|
||||
DragBlockState* block = mInputBlockQueue[i]->AsDragBlock();
|
||||
if (block && block->GetBlockId() == aInputBlockId) {
|
||||
block->SetDragMetrics(aDragMetrics);
|
||||
success = block->SetConfirmedTargetApzc(aTargetApzc,
|
||||
InputBlockState::TargetConfirmationState::eConfirmed);
|
||||
block->RecordContentResponseTime();
|
||||
break;
|
||||
}
|
||||
InputData* firstInput = nullptr;
|
||||
CancelableBlockState* block = FindBlockForId(aInputBlockId, &firstInput);
|
||||
if (block && block->AsDragBlock()) {
|
||||
block->AsDragBlock()->SetDragMetrics(aDragMetrics);
|
||||
success = block->SetConfirmedTargetApzc(aTargetApzc,
|
||||
InputBlockState::TargetConfirmationState::eConfirmed,
|
||||
firstInput);
|
||||
block->RecordContentResponseTime();
|
||||
}
|
||||
if (success) {
|
||||
ProcessInputBlocks();
|
||||
ProcessQueue();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -662,65 +632,77 @@ InputQueue::SetAllowedTouchBehavior(uint64_t aInputBlockId, const nsTArray<Touch
|
|||
|
||||
INPQ_LOG("got allowed touch behaviours; block=%" PRIu64 "\n", aInputBlockId);
|
||||
bool success = false;
|
||||
for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
|
||||
if (mInputBlockQueue[i]->GetBlockId() == aInputBlockId) {
|
||||
TouchBlockState *block = mInputBlockQueue[i]->AsTouchBlock();
|
||||
if (block) {
|
||||
success = block->SetAllowedTouchBehaviors(aBehaviors);
|
||||
block->RecordContentResponseTime();
|
||||
} else {
|
||||
NS_WARNING("input block is not a touch block");
|
||||
}
|
||||
break;
|
||||
}
|
||||
CancelableBlockState* block = FindBlockForId(aInputBlockId, nullptr);
|
||||
if (block && block->AsTouchBlock()) {
|
||||
success = block->AsTouchBlock()->SetAllowedTouchBehaviors(aBehaviors);
|
||||
block->RecordContentResponseTime();
|
||||
} else if (block) {
|
||||
NS_WARNING("input block is not a touch block");
|
||||
}
|
||||
if (success) {
|
||||
ProcessInputBlocks();
|
||||
ProcessQueue();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InputQueue::ProcessInputBlocks() {
|
||||
InputQueue::ProcessQueue() {
|
||||
APZThreadUtils::AssertOnControllerThread();
|
||||
|
||||
do {
|
||||
CancelableBlockState* curBlock = CurrentBlock();
|
||||
while (!mQueuedInputs.IsEmpty()) {
|
||||
CancelableBlockState* curBlock = mQueuedInputs[0]->Block();
|
||||
if (!curBlock->IsReadyForHandling()) {
|
||||
break;
|
||||
}
|
||||
|
||||
INPQ_LOG("processing input block %p; preventDefault %d target %p\n",
|
||||
INPQ_LOG("processing input from block %p; preventDefault %d target %p\n",
|
||||
curBlock, curBlock->IsDefaultPrevented(),
|
||||
curBlock->GetTargetApzc().get());
|
||||
RefPtr<AsyncPanZoomController> target = curBlock->GetTargetApzc();
|
||||
// target may be null here if the initial target was unconfirmed and then
|
||||
// we later got a confirmed null target. in that case drop the events.
|
||||
if (!target) {
|
||||
curBlock->DropEvents();
|
||||
} else if (curBlock->IsDefaultPrevented()) {
|
||||
curBlock->DropEvents();
|
||||
if (curBlock->AsTouchBlock()) {
|
||||
target->ResetTouchInputState();
|
||||
if (target) {
|
||||
if (curBlock->IsDefaultPrevented()) {
|
||||
if (curBlock->AsTouchBlock()) {
|
||||
target->ResetTouchInputState();
|
||||
}
|
||||
} else {
|
||||
UpdateActiveApzc(target);
|
||||
curBlock->DispatchEvent(*(mQueuedInputs[0]->Input()));
|
||||
}
|
||||
} else {
|
||||
UpdateActiveApzc(curBlock->GetTargetApzc());
|
||||
curBlock->HandleEvents();
|
||||
}
|
||||
MOZ_ASSERT(!curBlock->HasEvents());
|
||||
mQueuedInputs.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
if (mInputBlockQueue.Length() == 1 && curBlock->MustStayActive()) {
|
||||
// Some types of blocks (e.g. touch blocks) accumulate events until the
|
||||
// next input block is started. Therefore we cannot remove the block from
|
||||
// the queue until we have started another block. This block will be
|
||||
// removed by SweepDeletedBlocks() whenever a new block is added.
|
||||
break;
|
||||
}
|
||||
if (CanDiscardBlock(mActiveTouchBlock)) {
|
||||
mActiveTouchBlock = nullptr;
|
||||
}
|
||||
if (CanDiscardBlock(mActiveWheelBlock)) {
|
||||
mActiveWheelBlock = nullptr;
|
||||
}
|
||||
if (CanDiscardBlock(mActiveDragBlock)) {
|
||||
mActiveDragBlock = nullptr;
|
||||
}
|
||||
if (CanDiscardBlock(mActivePanGestureBlock)) {
|
||||
mActivePanGestureBlock = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, we know there are more touch blocks in the queue after
|
||||
// |curBlock|, so we can remove |curBlock| and try to process the next one.
|
||||
INPQ_LOG("discarding processed %s block %p\n", curBlock->Type(), curBlock);
|
||||
mInputBlockQueue.RemoveElementAt(0);
|
||||
} while (!mInputBlockQueue.IsEmpty());
|
||||
bool
|
||||
InputQueue::CanDiscardBlock(CancelableBlockState* aBlock)
|
||||
{
|
||||
if (!aBlock ||
|
||||
!aBlock->IsReadyForHandling() ||
|
||||
aBlock->MustStayActive()) {
|
||||
return false;
|
||||
}
|
||||
InputData* firstInput = nullptr;
|
||||
FindBlockForId(aBlock->GetBlockId(), &firstInput);
|
||||
if (firstInput) {
|
||||
// The block has at least one input event still in the queue, so it's
|
||||
// not depleted
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -737,7 +719,11 @@ InputQueue::Clear()
|
|||
{
|
||||
APZThreadUtils::AssertOnControllerThread();
|
||||
|
||||
mInputBlockQueue.Clear();
|
||||
mQueuedInputs.Clear();
|
||||
mActiveTouchBlock = nullptr;
|
||||
mActiveWheelBlock = nullptr;
|
||||
mActiveDragBlock = nullptr;
|
||||
mActivePanGestureBlock = nullptr;
|
||||
mLastActiveApzc = nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,11 +30,11 @@ class WheelBlockState;
|
|||
class DragBlockState;
|
||||
class PanGestureBlockState;
|
||||
class AsyncDragMetrics;
|
||||
class QueuedInput;
|
||||
|
||||
/**
|
||||
* This class stores incoming input events, separated into "input blocks", until
|
||||
* they are ready for handling. Currently input blocks are only created from
|
||||
* touch input.
|
||||
* This class stores incoming input events, associated with "input blocks", until
|
||||
* they are ready for handling.
|
||||
*/
|
||||
class InputQueue {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InputQueue)
|
||||
|
@ -90,28 +90,33 @@ public:
|
|||
*/
|
||||
uint64_t InjectNewTouchBlock(AsyncPanZoomController* aTarget);
|
||||
/**
|
||||
* Returns the pending input block at the head of the queue.
|
||||
* Returns the pending input block at the head of the queue, if there is one.
|
||||
* This may return null if there all input events have been processed.
|
||||
*/
|
||||
CancelableBlockState* CurrentBlock() const;
|
||||
/**
|
||||
* Returns the current pending input block as a specific kind of block.
|
||||
* These methods must only be called if the current pending block is of the
|
||||
* requested type.
|
||||
CancelableBlockState* GetCurrentBlock() const;
|
||||
/*
|
||||
* Returns the current pending input block as a specific kind of block. If
|
||||
* GetCurrentBlock() returns null, these functions additionally check the
|
||||
* mActiveXXXBlock field of the corresponding input type to see if there is
|
||||
* a depleted but still active input block, and returns that if found. These
|
||||
* functions may return null if no block is found.
|
||||
*/
|
||||
TouchBlockState* CurrentTouchBlock() const;
|
||||
WheelBlockState* CurrentWheelBlock() const;
|
||||
DragBlockState* CurrentDragBlock() const;
|
||||
PanGestureBlockState* CurrentPanGestureBlock() const;
|
||||
TouchBlockState* GetCurrentTouchBlock() const;
|
||||
WheelBlockState* GetCurrentWheelBlock() const;
|
||||
DragBlockState* GetCurrentDragBlock() const;
|
||||
PanGestureBlockState* GetCurrentPanGestureBlock() const;
|
||||
/**
|
||||
* Returns true iff the pending block at the head of the queue is ready for
|
||||
* handling.
|
||||
* Returns true iff the pending block at the head of the queue is a touch
|
||||
* block and is ready for handling.
|
||||
*/
|
||||
bool HasReadyTouchBlock() const;
|
||||
/**
|
||||
* If there is a wheel transaction, returns the WheelBlockState representing
|
||||
* the transaction. Otherwise, returns null.
|
||||
* If there is an active wheel transaction, returns the WheelBlockState
|
||||
* representing the transaction. Otherwise, returns null. "Active" in this
|
||||
* function name is the same kind of "active" as in mActiveWheelBlock - that
|
||||
* is, new incoming wheel events will go into the "active" block.
|
||||
*/
|
||||
WheelBlockState* GetCurrentWheelTransaction() const;
|
||||
WheelBlockState* GetActiveWheelTransaction() const;
|
||||
/**
|
||||
* Remove all input blocks from the input queue.
|
||||
*/
|
||||
|
@ -164,27 +169,37 @@ private:
|
|||
uint64_t* aOutInputBlockId);
|
||||
|
||||
/**
|
||||
* Remove any blocks that are inactive - not ready, and having no events.
|
||||
* Helper function that searches mQueuedInputs for the first block matching
|
||||
* the given id, and returns it. If |aOutFirstInput| is non-null, it is
|
||||
* populated with a pointer to the first input in mQueuedInputs that
|
||||
* corresponds to the block, or null if no such input was found. Note that
|
||||
* even if there are no inputs in mQueuedInputs, this function can return
|
||||
* non-null if the block id provided matches one of the depleted-but-still-
|
||||
* active blocks (mActiveTouchBlock, mActiveWheelBlock, etc.).
|
||||
*/
|
||||
void SweepDepletedBlocks();
|
||||
|
||||
/**
|
||||
* Processes the current block if it's ready for handling, using the block's
|
||||
* target APZC.
|
||||
*/
|
||||
bool MaybeHandleCurrentBlock(CancelableBlockState* block,
|
||||
const InputData& aEvent);
|
||||
|
||||
CancelableBlockState* FindBlockForId(uint64_t aInputBlockId,
|
||||
InputData** aOutFirstInput);
|
||||
void ScheduleMainThreadTimeout(const RefPtr<AsyncPanZoomController>& aTarget,
|
||||
CancelableBlockState* aBlock);
|
||||
void MainThreadTimeout(const uint64_t& aInputBlockId);
|
||||
void ProcessInputBlocks();
|
||||
void MainThreadTimeout(uint64_t aInputBlockId);
|
||||
void ProcessQueue();
|
||||
bool CanDiscardBlock(CancelableBlockState* aBlock);
|
||||
void UpdateActiveApzc(const RefPtr<AsyncPanZoomController>& aNewActive);
|
||||
|
||||
private:
|
||||
// The queue of input blocks that have not yet been fully processed.
|
||||
// The queue of input events that have not yet been fully processed.
|
||||
// This member must only be accessed on the controller/UI thread.
|
||||
nsTArray<UniquePtr<CancelableBlockState>> mInputBlockQueue;
|
||||
nsTArray<UniquePtr<QueuedInput>> mQueuedInputs;
|
||||
|
||||
// These are the most recently created blocks of each input type. They are
|
||||
// "active" in the sense that new inputs of that type are associated with
|
||||
// them. Note that these pointers may be null if no inputs of the type have
|
||||
// arrived, or if the inputs for the type formed a complete block that was
|
||||
// then discarded.
|
||||
RefPtr<TouchBlockState> mActiveTouchBlock;
|
||||
RefPtr<WheelBlockState> mActiveWheelBlock;
|
||||
RefPtr<DragBlockState> mActiveDragBlock;
|
||||
RefPtr<PanGestureBlockState> mActivePanGestureBlock;
|
||||
|
||||
// The APZC to which the last event was delivered
|
||||
RefPtr<AsyncPanZoomController> mLastActiveApzc;
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* 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 "QueuedInput.h"
|
||||
|
||||
#include "AsyncPanZoomController.h"
|
||||
#include "InputBlockState.h"
|
||||
#include "InputData.h"
|
||||
#include "OverscrollHandoffState.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
QueuedInput::QueuedInput(const MultiTouchInput& aInput, TouchBlockState& aBlock)
|
||||
: mInput(MakeUnique<MultiTouchInput>(aInput))
|
||||
, mBlock(&aBlock)
|
||||
{
|
||||
}
|
||||
|
||||
QueuedInput::QueuedInput(const ScrollWheelInput& aInput, WheelBlockState& aBlock)
|
||||
: mInput(MakeUnique<ScrollWheelInput>(aInput))
|
||||
, mBlock(&aBlock)
|
||||
{
|
||||
}
|
||||
|
||||
QueuedInput::QueuedInput(const MouseInput& aInput, DragBlockState& aBlock)
|
||||
: mInput(MakeUnique<MouseInput>(aInput))
|
||||
, mBlock(&aBlock)
|
||||
{
|
||||
}
|
||||
|
||||
QueuedInput::QueuedInput(const PanGestureInput& aInput, PanGestureBlockState& aBlock)
|
||||
: mInput(MakeUnique<PanGestureInput>(aInput))
|
||||
, mBlock(&aBlock)
|
||||
{
|
||||
}
|
||||
|
||||
InputData*
|
||||
QueuedInput::Input()
|
||||
{
|
||||
return mInput.get();
|
||||
}
|
||||
|
||||
CancelableBlockState*
|
||||
QueuedInput::Block()
|
||||
{
|
||||
return mBlock.get();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,58 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_layers_QueuedInput_h
|
||||
#define mozilla_layers_QueuedInput_h
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class InputData;
|
||||
class MultiTouchInput;
|
||||
class ScrollWheelInput;
|
||||
class MouseInput;
|
||||
class PanGestureInput;
|
||||
|
||||
namespace layers {
|
||||
|
||||
class CancelableBlockState;
|
||||
class TouchBlockState;
|
||||
class WheelBlockState;
|
||||
class DragBlockState;
|
||||
class PanGestureBlockState;
|
||||
|
||||
/**
|
||||
* This lightweight class holds a pointer to an input event that has not yet
|
||||
* been completely processed, along with the input block that the input event
|
||||
* is associated with.
|
||||
*/
|
||||
class QueuedInput
|
||||
{
|
||||
public:
|
||||
QueuedInput(const MultiTouchInput& aInput, TouchBlockState& aBlock);
|
||||
QueuedInput(const ScrollWheelInput& aInput, WheelBlockState& aBlock);
|
||||
QueuedInput(const MouseInput& aInput, DragBlockState& aBlock);
|
||||
QueuedInput(const PanGestureInput& aInput, PanGestureBlockState& aBlock);
|
||||
|
||||
InputData* Input();
|
||||
CancelableBlockState* Block();
|
||||
|
||||
private:
|
||||
// A copy of the input event that is provided to the constructor. This must
|
||||
// be non-null, and is owned by this QueuedInput instance (hence the
|
||||
// UniquePtr).
|
||||
UniquePtr<InputData> mInput;
|
||||
// A pointer to the block that the input event is associated with. This must
|
||||
// be non-null.
|
||||
RefPtr<CancelableBlockState> mBlock;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_layers_QueuedInput_h
|
|
@ -262,4 +262,35 @@ SmoothWheel(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
|
|||
return aTarget->ReceiveInputEvent(input, nullptr, aOutInputBlockId);
|
||||
}
|
||||
|
||||
template<class InputReceiver>
|
||||
nsEventStatus
|
||||
MouseDown(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
|
||||
TimeStamp aTime, uint64_t* aOutInputBlockId = nullptr)
|
||||
{
|
||||
MouseInput input(MouseInput::MOUSE_DOWN, MouseInput::ButtonType::LEFT_BUTTON,
|
||||
0, 0, aPoint, MillisecondsSinceStartup(aTime), aTime, 0);
|
||||
return aTarget->ReceiveInputEvent(input, nullptr, aOutInputBlockId);
|
||||
}
|
||||
|
||||
template<class InputReceiver>
|
||||
nsEventStatus
|
||||
MouseMove(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
|
||||
TimeStamp aTime, uint64_t* aOutInputBlockId = nullptr)
|
||||
{
|
||||
MouseInput input(MouseInput::MOUSE_MOVE, MouseInput::ButtonType::LEFT_BUTTON,
|
||||
0, 0, aPoint, MillisecondsSinceStartup(aTime), aTime, 0);
|
||||
return aTarget->ReceiveInputEvent(input, nullptr, aOutInputBlockId);
|
||||
}
|
||||
|
||||
template<class InputReceiver>
|
||||
nsEventStatus
|
||||
MouseUp(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
|
||||
TimeStamp aTime, uint64_t* aOutInputBlockId = nullptr)
|
||||
{
|
||||
MouseInput input(MouseInput::MOUSE_UP, MouseInput::ButtonType::LEFT_BUTTON,
|
||||
0, 0, aPoint, MillisecondsSinceStartup(aTime), aTime, 0);
|
||||
return aTarget->ReceiveInputEvent(input, nullptr, aOutInputBlockId);
|
||||
}
|
||||
|
||||
|
||||
#endif // mozilla_layers_InputUtils_h
|
||||
|
|
|
@ -597,10 +597,11 @@ TEST_F(APZCGestureDetectorTester, TapFollowedByMultipleTouches) {
|
|||
}
|
||||
|
||||
TEST_F(APZCGestureDetectorTester, LongPressInterruptedByWheel) {
|
||||
// Since the wheel block interrupted the long-press, we don't expect
|
||||
// any long-press notifications. However, this also shouldn't crash, which
|
||||
// is what it used to do.
|
||||
EXPECT_CALL(*mcc, HandleTap(TapType::eLongTap, _, _, _, _)).Times(0);
|
||||
// Since we try to allow concurrent input blocks of different types to
|
||||
// co-exist, the wheel block shouldn't interrupt the long-press detection.
|
||||
// But more importantly, this shouldn't crash, which is what it did at one
|
||||
// point in time.
|
||||
EXPECT_CALL(*mcc, HandleTap(TapType::eLongTap, _, _, _, _)).Times(1);
|
||||
|
||||
uint64_t touchBlockId = 0;
|
||||
uint64_t wheelBlockId = 0;
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* 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 "APZCTreeManagerTester.h"
|
||||
#include "APZTestCommon.h"
|
||||
#include "InputUtils.h"
|
||||
|
||||
// Test of scenario described in bug 1269067 - that a continuing mouse drag
|
||||
// doesn't interrupt a wheel scrolling animation
|
||||
TEST_F(APZCTreeManagerTester, WheelInterruptedByMouseDrag) {
|
||||
// Set up a scrollable layer
|
||||
CreateSimpleScrollingLayer();
|
||||
ScopedLayerTreeRegistration registration(manager, 0, root, mcc);
|
||||
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
||||
RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root);
|
||||
|
||||
uint64_t dragBlockId = 0;
|
||||
uint64_t wheelBlockId = 0;
|
||||
uint64_t tmpBlockId = 0;
|
||||
|
||||
// First start the mouse drag
|
||||
MouseDown(apzc, ScreenIntPoint(5, 5), mcc->Time(), &dragBlockId);
|
||||
MouseMove(apzc, ScreenIntPoint(6, 6), mcc->Time(), &tmpBlockId);
|
||||
EXPECT_EQ(dragBlockId, tmpBlockId);
|
||||
|
||||
// Insert the wheel event, check that it has a new block id
|
||||
SmoothWheel(apzc, ScreenIntPoint(6, 6), ScreenPoint(0, 1), mcc->Time(), &wheelBlockId);
|
||||
EXPECT_NE(dragBlockId, wheelBlockId);
|
||||
|
||||
// Continue the drag, check that the block id is the same as before
|
||||
MouseMove(apzc, ScreenIntPoint(7, 5), mcc->Time(), &tmpBlockId);
|
||||
EXPECT_EQ(dragBlockId, tmpBlockId);
|
||||
|
||||
// Finish the wheel animation
|
||||
apzc->AdvanceAnimationsUntilEnd();
|
||||
|
||||
// Check that it scrolled
|
||||
ParentLayerPoint scroll = apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::NORMAL);
|
||||
EXPECT_EQ(scroll.x, 0);
|
||||
EXPECT_EQ(scroll.y, 10); // We scrolled 1 "line" or 10 pixels
|
||||
}
|
|
@ -9,6 +9,7 @@ UNIFIED_SOURCES += [
|
|||
'TestEventRegions.cpp',
|
||||
'TestGestureDetector.cpp',
|
||||
'TestHitTesting.cpp',
|
||||
'TestInputQueue.cpp',
|
||||
'TestPanning.cpp',
|
||||
'TestPinching.cpp',
|
||||
'TestScrollHandoff.cpp',
|
||||
|
|
|
@ -281,6 +281,7 @@ UNIFIED_SOURCES += [
|
|||
'apz/src/InputQueue.cpp',
|
||||
'apz/src/OverscrollHandoffState.cpp',
|
||||
'apz/src/PotentialCheckerboardDurationTracker.cpp',
|
||||
'apz/src/QueuedInput.cpp',
|
||||
'apz/src/TouchCounter.cpp',
|
||||
'apz/src/WheelScrollAnimation.cpp',
|
||||
'apz/testutil/APZTestData.cpp',
|
||||
|
|
|
@ -320,11 +320,11 @@ VRDisplayOculus::VRDisplayOculus(ovrSession aSession)
|
|||
, mTextureSet(nullptr)
|
||||
, mQuadVS(nullptr)
|
||||
, mQuadPS(nullptr)
|
||||
, mLinearSamplerState(nullptr)
|
||||
, mVSConstantBuffer(nullptr)
|
||||
, mPSConstantBuffer(nullptr)
|
||||
, mVertexBuffer(nullptr)
|
||||
, mInputLayout(nullptr)
|
||||
, mLinearSamplerState(nullptr)
|
||||
, mIsPresenting(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR_INHERITED(VRDisplayOculus, VRDisplayHost);
|
||||
|
@ -352,9 +352,6 @@ VRDisplayOculus::VRDisplayOculus(ovrSession aSession)
|
|||
mDisplayInfo.mEyeFOV[VRDisplayInfo::Eye_Left] = FromFovPort(mFOVPort[VRDisplayInfo::Eye_Left]);
|
||||
mDisplayInfo.mEyeFOV[VRDisplayInfo::Eye_Right] = FromFovPort(mFOVPort[VRDisplayInfo::Eye_Right]);
|
||||
|
||||
uint32_t w = mDesc.Resolution.w;
|
||||
uint32_t h = mDesc.Resolution.h;
|
||||
|
||||
float pixelsPerDisplayPixel = 1.0;
|
||||
ovrSizei texSize[2];
|
||||
|
||||
|
|
|
@ -2146,8 +2146,8 @@ class BaseCompiler
|
|||
MOZ_ASSERT(sig.id.kind() == SigIdDesc::Kind::None);
|
||||
const TableDesc& table = mg_.tables[mg_.asmJSSigToTableIndex[sigIndex]];
|
||||
|
||||
MOZ_ASSERT(IsPowerOfTwo(table.initial));
|
||||
masm.andPtr(Imm32((table.initial - 1)), WasmTableCallIndexReg);
|
||||
MOZ_ASSERT(IsPowerOfTwo(table.limits.initial));
|
||||
masm.andPtr(Imm32((table.limits.initial - 1)), WasmTableCallIndexReg);
|
||||
|
||||
callee = CalleeDesc::asmJSTable(table);
|
||||
} else {
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
# include "vtune/VTuneWrapper.h"
|
||||
#endif
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
#include "vm/ArrayBufferObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
|
|
@ -633,14 +633,8 @@ DecodeName(Decoder& d)
|
|||
return name;
|
||||
}
|
||||
|
||||
struct Resizable
|
||||
{
|
||||
uint32_t initial;
|
||||
Maybe<uint32_t> maximum;
|
||||
};
|
||||
|
||||
static bool
|
||||
DecodeResizable(Decoder& d, Resizable* resizable)
|
||||
DecodeResizable(Decoder& d, ResizableLimits* limits)
|
||||
{
|
||||
uint32_t flags;
|
||||
if (!d.readVarU32(&flags))
|
||||
|
@ -652,7 +646,7 @@ DecodeResizable(Decoder& d, Resizable* resizable)
|
|||
if (!(flags & uint32_t(ResizableFlags::Default)))
|
||||
return Fail(d, "currently, every memory/table must be declared default");
|
||||
|
||||
if (!d.readVarU32(&resizable->initial))
|
||||
if (!d.readVarU32(&limits->initial))
|
||||
return Fail(d, "expected initial length");
|
||||
|
||||
if (flags & uint32_t(ResizableFlags::HasMaximum)) {
|
||||
|
@ -660,10 +654,10 @@ DecodeResizable(Decoder& d, Resizable* resizable)
|
|||
if (!d.readVarU32(&maximum))
|
||||
return Fail(d, "expected maximum length");
|
||||
|
||||
if (resizable->initial > maximum)
|
||||
if (limits->initial > maximum)
|
||||
return Fail(d, "maximum length less than initial length");
|
||||
|
||||
resizable->maximum.emplace(maximum);
|
||||
limits->maximum.emplace(maximum);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -675,21 +669,21 @@ DecodeResizableMemory(Decoder& d, ModuleGeneratorData* init)
|
|||
if (UsesMemory(init->memoryUsage))
|
||||
return Fail(d, "already have default memory");
|
||||
|
||||
Resizable resizable;
|
||||
if (!DecodeResizable(d, &resizable))
|
||||
ResizableLimits limits;
|
||||
if (!DecodeResizable(d, &limits))
|
||||
return false;
|
||||
|
||||
init->memoryUsage = MemoryUsage::Unshared;
|
||||
|
||||
CheckedInt<uint32_t> initialBytes = resizable.initial;
|
||||
CheckedInt<uint32_t> initialBytes = limits.initial;
|
||||
initialBytes *= PageSize;
|
||||
if (!initialBytes.isValid() || initialBytes.value() > uint32_t(INT32_MAX))
|
||||
return Fail(d, "initial memory size too big");
|
||||
|
||||
init->minMemoryLength = initialBytes.value();
|
||||
|
||||
if (resizable.maximum) {
|
||||
CheckedInt<uint32_t> maximumBytes = *resizable.maximum;
|
||||
if (limits.maximum) {
|
||||
CheckedInt<uint32_t> maximumBytes = *limits.maximum;
|
||||
maximumBytes *= PageSize;
|
||||
if (!maximumBytes.isValid())
|
||||
return Fail(d, "maximum memory size too big");
|
||||
|
@ -710,18 +704,14 @@ DecodeResizableTable(Decoder& d, ModuleGeneratorData* init)
|
|||
if (elementType != uint32_t(TypeConstructor::AnyFunc))
|
||||
return Fail(d, "expected 'anyfunc' element type");
|
||||
|
||||
Resizable resizable;
|
||||
if (!DecodeResizable(d, &resizable))
|
||||
ResizableLimits limits;
|
||||
if (!DecodeResizable(d, &limits))
|
||||
return false;
|
||||
|
||||
if (!init->tables.empty())
|
||||
return Fail(d, "already have default table");
|
||||
|
||||
TableDesc table;
|
||||
table.kind = TableKind::AnyFunction;
|
||||
table.initial = resizable.initial;
|
||||
table.maximum = resizable.maximum ? *resizable.maximum : UINT32_MAX;
|
||||
return init->tables.append(table);
|
||||
return init->tables.emplaceBack(TableKind::AnyFunction, limits);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -874,20 +864,19 @@ DecodeTableSection(Decoder& d, bool newFormat, ModuleGeneratorData* init, Uint32
|
|||
if (!DecodeResizableTable(d, init))
|
||||
return false;
|
||||
} else {
|
||||
TableDesc table;
|
||||
table.kind = TableKind::AnyFunction;
|
||||
table.maximum = UINT32_MAX;
|
||||
|
||||
if (!d.readVarU32(&table.initial))
|
||||
ResizableLimits limits;
|
||||
if (!d.readVarU32(&limits.initial))
|
||||
return Fail(d, "expected number of table elems");
|
||||
|
||||
if (table.initial > MaxTableElems)
|
||||
if (limits.initial > MaxTableElems)
|
||||
return Fail(d, "too many table elements");
|
||||
|
||||
if (!oldElems->resize(table.initial))
|
||||
limits.maximum = Some(limits.initial);
|
||||
|
||||
if (!oldElems->resize(limits.initial))
|
||||
return false;
|
||||
|
||||
for (uint32_t i = 0; i < table.initial; i++) {
|
||||
for (uint32_t i = 0; i < limits.initial; i++) {
|
||||
uint32_t funcDefIndex;
|
||||
if (!d.readVarU32(&funcDefIndex))
|
||||
return Fail(d, "expected table element");
|
||||
|
@ -899,7 +888,7 @@ DecodeTableSection(Decoder& d, bool newFormat, ModuleGeneratorData* init, Uint32
|
|||
}
|
||||
|
||||
MOZ_ASSERT(init->tables.empty());
|
||||
if (!init->tables.append(table))
|
||||
if (!init->tables.emplaceBack(TableKind::AnyFunction, limits))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1364,7 +1353,7 @@ DecodeElemSection(Decoder& d, bool newFormat, Uint32Vector&& oldElems, ModuleGen
|
|||
if (!d.readVarU32(&numElems))
|
||||
return Fail(d, "expected segment size");
|
||||
|
||||
uint32_t tableLength = mg.tables()[tableIndex].initial;
|
||||
uint32_t tableLength = mg.tables()[tableIndex].limits.initial;
|
||||
if (offset.isVal()) {
|
||||
uint32_t off = offset.val().i32();
|
||||
if (off > tableLength || tableLength - off < numElems)
|
||||
|
|
|
@ -157,7 +157,7 @@ ModuleGenerator::init(UniqueModuleGeneratorData shared, const CompileArgs& args,
|
|||
}
|
||||
|
||||
for (TableDesc& table : shared_->tables) {
|
||||
if (!allocateGlobalBytes(sizeof(void*), sizeof(void*), &table.globalDataOffset))
|
||||
if (!allocateGlobalBytes(sizeof(TableTls), sizeof(void*), &table.globalDataOffset))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1016,12 +1016,10 @@ ModuleGenerator::initSigTableLength(uint32_t sigIndex, uint32_t length)
|
|||
shared_->asmJSSigToTableIndex[sigIndex] = numTables_;
|
||||
|
||||
TableDesc& table = shared_->tables[numTables_++];
|
||||
MOZ_ASSERT(table.globalDataOffset == 0);
|
||||
MOZ_ASSERT(table.initial == 0);
|
||||
table.kind = TableKind::TypedFunction;
|
||||
table.initial = length;
|
||||
table.maximum = UINT32_MAX;
|
||||
return allocateGlobalBytes(sizeof(void*), sizeof(void*), &table.globalDataOffset);
|
||||
table.limits.initial = length;
|
||||
table.limits.maximum = Some(length);
|
||||
return allocateGlobalBytes(sizeof(TableTls), sizeof(void*), &table.globalDataOffset);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1031,7 +1029,7 @@ ModuleGenerator::initSigTableElems(uint32_t sigIndex, Uint32Vector&& elemFuncDef
|
|||
MOZ_ASSERT(finishedFuncDefs_);
|
||||
|
||||
uint32_t tableIndex = shared_->asmJSSigToTableIndex[sigIndex];
|
||||
MOZ_ASSERT(shared_->tables[tableIndex].initial == elemFuncDefIndices.length());
|
||||
MOZ_ASSERT(shared_->tables[tableIndex].limits.initial == elemFuncDefIndices.length());
|
||||
|
||||
Uint32Vector codeRangeIndices;
|
||||
if (!codeRangeIndices.resize(elemFuncDefIndices.length()))
|
||||
|
|
|
@ -88,13 +88,6 @@ class SigIdSet
|
|||
|
||||
ExclusiveData<SigIdSet> sigIdSet;
|
||||
|
||||
void**
|
||||
Instance::addressOfTableBase(size_t tableIndex) const
|
||||
{
|
||||
MOZ_ASSERT(metadata().tables[tableIndex].globalDataOffset >= InitialGlobalDataBytes);
|
||||
return (void**)(codeSegment().globalData() + metadata().tables[tableIndex].globalDataOffset);
|
||||
}
|
||||
|
||||
const void**
|
||||
Instance::addressOfSigId(const SigIdDesc& sigId) const
|
||||
{
|
||||
|
@ -109,6 +102,13 @@ Instance::funcImportTls(const FuncImport& fi)
|
|||
return *(FuncImportTls*)(codeSegment().globalData() + fi.tlsDataOffset());
|
||||
}
|
||||
|
||||
TableTls&
|
||||
Instance::tableTls(const TableDesc& td) const
|
||||
{
|
||||
MOZ_ASSERT(td.globalDataOffset >= InitialGlobalDataBytes);
|
||||
return *(TableTls*)(codeSegment().globalData() + td.globalDataOffset);
|
||||
}
|
||||
|
||||
bool
|
||||
Instance::callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, const uint64_t* argv,
|
||||
MutableHandleValue rval)
|
||||
|
@ -347,6 +347,13 @@ Instance::Instance(JSContext* cx,
|
|||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < tables_.length(); i++) {
|
||||
const TableDesc& td = metadata().tables[i];
|
||||
TableTls& table = tableTls(td);
|
||||
table.length = tables_[i]->length();
|
||||
table.base = tables_[i]->base();
|
||||
}
|
||||
|
||||
uint8_t* globalData = code_->segment().globalData();
|
||||
|
||||
for (size_t i = 0; i < metadata().globals.length(); i++) {
|
||||
|
@ -380,9 +387,6 @@ Instance::Instance(JSContext* cx,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < tables_.length(); i++)
|
||||
*addressOfTableBase(i) = tables_[i]->base();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -391,6 +395,11 @@ Instance::init(JSContext* cx)
|
|||
if (memory_ && memory_->movingGrowable() && !memory_->addMovingGrowObserver(cx, object_))
|
||||
return false;
|
||||
|
||||
for (const SharedTable& table : tables_) {
|
||||
if (table->movingGrowable() && !table->addMovingGrowObserver(cx, object_))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!metadata().sigIds.empty()) {
|
||||
ExclusiveData<SigIdSet>::Guard lockedSigIdSet = sigIdSet.lock();
|
||||
|
||||
|
@ -796,7 +805,7 @@ Instance::callExport(JSContext* cx, uint32_t funcDefIndex, CallArgs args)
|
|||
}
|
||||
|
||||
void
|
||||
Instance::onMovingGrow(uint8_t* prevMemoryBase)
|
||||
Instance::onMovingGrowMemory(uint8_t* prevMemoryBase)
|
||||
{
|
||||
MOZ_ASSERT(!isAsmJS());
|
||||
ArrayBufferObject& buffer = memory_->buffer().as<ArrayBufferObject>();
|
||||
|
@ -804,6 +813,16 @@ Instance::onMovingGrow(uint8_t* prevMemoryBase)
|
|||
code_->segment().onMovingGrow(prevMemoryBase, metadata(), buffer);
|
||||
}
|
||||
|
||||
void
|
||||
Instance::onMovingGrowTable()
|
||||
{
|
||||
MOZ_ASSERT(!isAsmJS());
|
||||
MOZ_ASSERT(tables_.length() == 1);
|
||||
TableTls& table = tableTls(metadata().tables[0]);
|
||||
table.length = tables_[0]->length();
|
||||
table.base = tables_[0]->base();
|
||||
}
|
||||
|
||||
void
|
||||
Instance::deoptimizeImportExit(uint32_t funcImportIndex)
|
||||
{
|
||||
|
|
|
@ -46,9 +46,9 @@ class Instance
|
|||
TlsData tlsData_;
|
||||
|
||||
// Internal helpers:
|
||||
void** addressOfTableBase(size_t tableIndex) const;
|
||||
const void** addressOfSigId(const SigIdDesc& sigId) const;
|
||||
FuncImportTls& funcImportTls(const FuncImport& fi);
|
||||
TableTls& tableTls(const TableDesc& td) const;
|
||||
|
||||
// Import call slow paths which are called directly from wasm code.
|
||||
friend void* AddressOf(SymbolicAddress, ExclusiveContext*);
|
||||
|
@ -65,14 +65,6 @@ class Instance
|
|||
friend class js::WasmInstanceObject;
|
||||
void tracePrivate(JSTracer* trc);
|
||||
|
||||
// Only WasmMemoryObject can call the private onMovingGrow notification.
|
||||
friend class js::WasmMemoryObject;
|
||||
void onMovingGrow(uint8_t* prevMemoryBase);
|
||||
|
||||
// Called by WasmTableObject to barrier table writes.
|
||||
friend class Table;
|
||||
WasmInstanceObject* objectUnbarriered() const;
|
||||
|
||||
public:
|
||||
Instance(JSContext* cx,
|
||||
HandleWasmInstanceObject object,
|
||||
|
@ -102,9 +94,11 @@ class Instance
|
|||
|
||||
// This method returns a pointer to the GC object that owns this Instance.
|
||||
// Instances may be reached via weak edges (e.g., Compartment::instances_)
|
||||
// so this perform a read-barrier on the returned object.
|
||||
// so this perform a read-barrier on the returned object unless the barrier
|
||||
// is explicitly waived.
|
||||
|
||||
WasmInstanceObject* object() const;
|
||||
WasmInstanceObject* objectUnbarriered() const;
|
||||
|
||||
// Execute the given export given the JS call arguments, storing the return
|
||||
// value in args.rval.
|
||||
|
@ -124,6 +118,11 @@ class Instance
|
|||
|
||||
bool memoryAccessWouldFault(uint8_t* addr, unsigned numBytes);
|
||||
|
||||
// Called by Wasm(Memory|Table)Object when a moving resize occurs:
|
||||
|
||||
void onMovingGrowMemory(uint8_t* prevMemoryBase);
|
||||
void onMovingGrowTable();
|
||||
|
||||
// See Code::ensureProfilingState comment.
|
||||
|
||||
MOZ_MUST_USE bool ensureProfilingState(JSContext* cx, bool enabled);
|
||||
|
|
|
@ -1010,11 +1010,11 @@ class FunctionCompiler
|
|||
if (mg_.isAsmJS()) {
|
||||
MOZ_ASSERT(sig.id.kind() == SigIdDesc::Kind::None);
|
||||
const TableDesc& table = mg_.tables[mg_.asmJSSigToTableIndex[sigIndex]];
|
||||
MOZ_ASSERT(IsPowerOfTwo(table.initial));
|
||||
MOZ_ASSERT(IsPowerOfTwo(table.limits.initial));
|
||||
MOZ_ASSERT(!table.external);
|
||||
MOZ_ASSERT(call.tlsStackOffset_ == MWasmCall::DontSaveTls);
|
||||
|
||||
MConstant* mask = MConstant::New(alloc(), Int32Value(table.initial - 1));
|
||||
MConstant* mask = MConstant::New(alloc(), Int32Value(table.limits.initial - 1));
|
||||
curBlock_->add(mask);
|
||||
MBitAnd* maskedIndex = MBitAnd::NewAsmJS(alloc(), index, mask, MIRType::Int32);
|
||||
curBlock_->add(maskedIndex);
|
||||
|
|
|
@ -326,6 +326,68 @@ js::InitWasmClass(JSContext* cx, HandleObject global)
|
|||
return Wasm;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Common functions
|
||||
|
||||
static bool
|
||||
ToNonWrappingUint32(JSContext* cx, HandleValue v, uint32_t max, const char* kind, const char* noun,
|
||||
uint32_t* u32)
|
||||
{
|
||||
double dbl;
|
||||
if (!ToInteger(cx, v, &dbl))
|
||||
return false;
|
||||
|
||||
if (dbl < 0 || dbl > max) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32, kind, noun);
|
||||
return false;
|
||||
}
|
||||
|
||||
*u32 = uint32_t(dbl);
|
||||
MOZ_ASSERT(double(*u32) == dbl);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
GetResizableLimits(JSContext* cx, HandleObject obj, uint32_t max, const char* kind,
|
||||
ResizableLimits* limits)
|
||||
{
|
||||
JSAtom* initialAtom = Atomize(cx, "initial", strlen("initial"));
|
||||
if (!initialAtom)
|
||||
return false;
|
||||
RootedId initialId(cx, AtomToId(initialAtom));
|
||||
|
||||
RootedValue initialVal(cx);
|
||||
if (!GetProperty(cx, obj, obj, initialId, &initialVal))
|
||||
return false;
|
||||
|
||||
if (!ToNonWrappingUint32(cx, initialVal, max, kind, "initial size", &limits->initial))
|
||||
return false;
|
||||
|
||||
JSAtom* maximumAtom = Atomize(cx, "maximum", strlen("maximum"));
|
||||
if (!maximumAtom)
|
||||
return false;
|
||||
RootedId maximumId(cx, AtomToId(maximumAtom));
|
||||
|
||||
bool found;
|
||||
if (HasProperty(cx, obj, maximumId, &found) && found) {
|
||||
RootedValue maxVal(cx);
|
||||
if (!GetProperty(cx, obj, obj, maximumId, &maxVal))
|
||||
return false;
|
||||
|
||||
limits->maximum.emplace();
|
||||
if (!ToNonWrappingUint32(cx, maxVal, max, kind, "maximum size", limits->maximum.ptr()))
|
||||
return false;
|
||||
|
||||
if (limits->initial > *limits->maximum) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32,
|
||||
kind, "maximum size");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// WebAssembly.Module class and methods
|
||||
|
||||
|
@ -773,53 +835,17 @@ WasmMemoryObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
|||
return false;
|
||||
}
|
||||
|
||||
JSAtom* initialAtom = Atomize(cx, "initial", strlen("initial"));
|
||||
if (!initialAtom)
|
||||
return false;
|
||||
RootedId initialId(cx, AtomToId(initialAtom));
|
||||
|
||||
JSAtom* maximumAtom = Atomize(cx, "maximum", strlen("maximum"));
|
||||
if (!maximumAtom)
|
||||
return false;
|
||||
RootedId maximumId(cx, AtomToId(maximumAtom));
|
||||
|
||||
RootedObject obj(cx, &args[0].toObject());
|
||||
RootedValue initialVal(cx);
|
||||
if (!GetProperty(cx, obj, obj, initialId, &initialVal))
|
||||
ResizableLimits limits;
|
||||
if (!GetResizableLimits(cx, obj, UINT32_MAX / PageSize, "Memory", &limits))
|
||||
return false;
|
||||
|
||||
double initialDbl;
|
||||
if (!ToInteger(cx, initialVal, &initialDbl))
|
||||
return false;
|
||||
limits.initial *= PageSize;
|
||||
if (limits.maximum)
|
||||
limits.maximum = Some(*limits.maximum * PageSize);
|
||||
|
||||
if (initialDbl < 0 || initialDbl > INT32_MAX / PageSize) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_SIZE, "Memory", "initial");
|
||||
return false;
|
||||
}
|
||||
|
||||
Maybe<uint32_t> maxSize;
|
||||
|
||||
bool found;
|
||||
if (HasProperty(cx, obj, maximumId, &found) && found) {
|
||||
RootedValue maxVal(cx);
|
||||
if (!GetProperty(cx, obj, obj, maximumId, &maxVal))
|
||||
return false;
|
||||
|
||||
double maxDbl;
|
||||
if (!ToInteger(cx, maxVal, &maxDbl))
|
||||
return false;
|
||||
|
||||
if (maxDbl < initialDbl || maxDbl > UINT32_MAX / PageSize) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_SIZE, "Memory",
|
||||
"maximum");
|
||||
return false;
|
||||
}
|
||||
|
||||
maxSize = Some<uint32_t>(uint32_t(maxDbl) * PageSize);
|
||||
}
|
||||
|
||||
uint32_t initialSize = uint32_t(initialDbl) * PageSize;
|
||||
RootedArrayBufferObject buffer(cx, ArrayBufferObject::createForWasm(cx, initialSize, maxSize));
|
||||
RootedArrayBufferObject buffer(cx,
|
||||
ArrayBufferObject::createForWasm(cx, limits.initial, limits.maximum));
|
||||
if (!buffer)
|
||||
return false;
|
||||
|
||||
|
@ -863,19 +889,14 @@ WasmMemoryObject::growImpl(JSContext* cx, const CallArgs& args)
|
|||
{
|
||||
RootedWasmMemoryObject memory(cx, &args.thisv().toObject().as<WasmMemoryObject>());
|
||||
|
||||
double deltaDbl;
|
||||
if (!ToInteger(cx, args.get(0), &deltaDbl))
|
||||
uint32_t delta;
|
||||
if (!ToNonWrappingUint32(cx, args.get(0), UINT32_MAX, "Memory", "grow delta", &delta))
|
||||
return false;
|
||||
|
||||
if (deltaDbl < 0 || deltaDbl > UINT32_MAX) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_GROW);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t ret = grow(memory, uint32_t(deltaDbl), cx);
|
||||
uint32_t ret = grow(memory, delta, cx);
|
||||
|
||||
if (ret == uint32_t(-1)) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_GROW);
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_GROW, "memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1000,7 +1021,7 @@ WasmMemoryObject::grow(HandleWasmMemoryObject memory, uint32_t delta, JSContext*
|
|||
if (memory->hasObservers()) {
|
||||
MOZ_ASSERT(prevMemoryBase);
|
||||
for (InstanceSet::Range r = memory->observers().all(); !r.empty(); r.popFront())
|
||||
r.front()->instance().onMovingGrow(prevMemoryBase);
|
||||
r.front()->instance().onMovingGrowMemory(prevMemoryBase);
|
||||
}
|
||||
|
||||
return oldNumPages;
|
||||
|
@ -1058,7 +1079,7 @@ WasmTableObject::trace(JSTracer* trc, JSObject* obj)
|
|||
}
|
||||
|
||||
/* static */ WasmTableObject*
|
||||
WasmTableObject::create(JSContext* cx, uint32_t length)
|
||||
WasmTableObject::create(JSContext* cx, ResizableLimits limits)
|
||||
{
|
||||
RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmTable).toObject());
|
||||
|
||||
|
@ -1069,13 +1090,10 @@ WasmTableObject::create(JSContext* cx, uint32_t length)
|
|||
|
||||
MOZ_ASSERT(obj->isNewborn());
|
||||
|
||||
TableDesc desc;
|
||||
desc.kind = TableKind::AnyFunction;
|
||||
desc.external = true;
|
||||
desc.initial = length;
|
||||
desc.maximum = length;
|
||||
TableDesc td(TableKind::AnyFunction, limits);
|
||||
td.external = true;
|
||||
|
||||
SharedTable table = Table::create(cx, desc, obj);
|
||||
SharedTable table = Table::create(cx, td, obj);
|
||||
if (!table)
|
||||
return nullptr;
|
||||
|
||||
|
@ -1102,55 +1120,35 @@ WasmTableObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
|
||||
RootedObject obj(cx, &args[0].toObject());
|
||||
RootedId id(cx);
|
||||
RootedValue val(cx);
|
||||
|
||||
JSAtom* elementAtom = Atomize(cx, "element", strlen("element"));
|
||||
if (!elementAtom)
|
||||
return false;
|
||||
id = AtomToId(elementAtom);
|
||||
if (!GetProperty(cx, obj, obj, id, &val))
|
||||
RootedId elementId(cx, AtomToId(elementAtom));
|
||||
|
||||
RootedValue elementVal(cx);
|
||||
if (!GetProperty(cx, obj, obj, elementId, &elementVal))
|
||||
return false;
|
||||
|
||||
if (!val.isString()) {
|
||||
if (!elementVal.isString()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_ELEMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSLinearString* str = val.toString()->ensureLinear(cx);
|
||||
if (!str)
|
||||
JSLinearString* elementStr = elementVal.toString()->ensureLinear(cx);
|
||||
if (!elementStr)
|
||||
return false;
|
||||
|
||||
if (!StringEqualsAscii(str, "anyfunc")) {
|
||||
if (!StringEqualsAscii(elementStr, "anyfunc")) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_ELEMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSAtom* initialAtom = Atomize(cx, "initial", strlen("initial"));
|
||||
if (!initialAtom)
|
||||
return false;
|
||||
id = AtomToId(initialAtom);
|
||||
if (!GetProperty(cx, obj, obj, id, &val))
|
||||
ResizableLimits limits;
|
||||
if (!GetResizableLimits(cx, obj, UINT32_MAX, "Table", &limits))
|
||||
return false;
|
||||
|
||||
double initialDbl;
|
||||
if (!ToInteger(cx, val, &initialDbl))
|
||||
return false;
|
||||
|
||||
if (initialDbl < 0 || initialDbl > INT32_MAX) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_SIZE, "Table", "initial");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t initial = uint32_t(initialDbl);
|
||||
MOZ_ASSERT(double(initial) == initialDbl);
|
||||
|
||||
if (initial > MaxTableElems) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_SIZE, "Table", "initial");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedWasmTableObject table(cx, WasmTableObject::create(cx, initial));
|
||||
RootedWasmTableObject table(cx, WasmTableObject::create(cx, limits));
|
||||
if (!table)
|
||||
return false;
|
||||
|
||||
|
@ -1190,18 +1188,10 @@ WasmTableObject::getImpl(JSContext* cx, const CallArgs& args)
|
|||
RootedWasmTableObject tableObj(cx, &args.thisv().toObject().as<WasmTableObject>());
|
||||
const Table& table = tableObj->table();
|
||||
|
||||
double indexDbl;
|
||||
if (!ToInteger(cx, args.get(0), &indexDbl))
|
||||
uint32_t index;
|
||||
if (!ToNonWrappingUint32(cx, args.get(0), table.length() - 1, "Table", "get index", &index))
|
||||
return false;
|
||||
|
||||
if (indexDbl < 0 || indexDbl >= table.length()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t index = uint32_t(indexDbl);
|
||||
MOZ_ASSERT(double(index) == indexDbl);
|
||||
|
||||
ExternalTableElem& elem = table.externalArray()[index];
|
||||
if (!elem.code) {
|
||||
args.rval().setNull();
|
||||
|
@ -1237,18 +1227,10 @@ WasmTableObject::setImpl(JSContext* cx, const CallArgs& args)
|
|||
if (!args.requireAtLeast(cx, "set", 2))
|
||||
return false;
|
||||
|
||||
double indexDbl;
|
||||
if (!ToInteger(cx, args[0], &indexDbl))
|
||||
uint32_t index;
|
||||
if (!ToNonWrappingUint32(cx, args.get(0), table.length() - 1, "Table", "set index", &index))
|
||||
return false;
|
||||
|
||||
if (indexDbl < 0 || indexDbl >= table.length()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t index = uint32_t(indexDbl);
|
||||
MOZ_ASSERT(double(index) == indexDbl);
|
||||
|
||||
RootedFunction value(cx);
|
||||
if (!IsExportedFunction(args[1], &value) && !args[1].isNull()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_TABLE_VALUE);
|
||||
|
@ -1285,10 +1267,38 @@ WasmTableObject::set(JSContext* cx, unsigned argc, Value* vp)
|
|||
return CallNonGenericMethod<IsTable, setImpl>(cx, args);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
WasmTableObject::growImpl(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
RootedWasmTableObject table(cx, &args.thisv().toObject().as<WasmTableObject>());
|
||||
|
||||
uint32_t delta;
|
||||
if (!ToNonWrappingUint32(cx, args.get(0), UINT32_MAX, "Table", "grow delta", &delta))
|
||||
return false;
|
||||
|
||||
uint32_t ret = table->table().grow(delta, cx);
|
||||
|
||||
if (ret == uint32_t(-1)) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_GROW, "table");
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setInt32(ret);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
WasmTableObject::grow(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod<IsTable, growImpl>(cx, args);
|
||||
}
|
||||
|
||||
const JSFunctionSpec WasmTableObject::methods[] =
|
||||
{
|
||||
JS_FN("get", WasmTableObject::get, 1, 0),
|
||||
JS_FN("set", WasmTableObject::set, 2, 0),
|
||||
JS_FN("grow", WasmTableObject::grow, 1, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
|
|
@ -210,6 +210,8 @@ class WasmTableObject : public NativeObject
|
|||
static bool get(JSContext* cx, unsigned argc, Value* vp);
|
||||
static bool setImpl(JSContext* cx, const CallArgs& args);
|
||||
static bool set(JSContext* cx, unsigned argc, Value* vp);
|
||||
static bool growImpl(JSContext* cx, const CallArgs& args);
|
||||
static bool grow(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
public:
|
||||
static const unsigned RESERVED_SLOTS = 1;
|
||||
|
@ -221,7 +223,7 @@ class WasmTableObject : public NativeObject
|
|||
// Note that, after creation, a WasmTableObject's table() is not initialized
|
||||
// and must be initialized before use.
|
||||
|
||||
static WasmTableObject* create(JSContext* cx, uint32_t length);
|
||||
static WasmTableObject* create(JSContext* cx, wasm::ResizableLimits limits);
|
||||
wasm::Table& table() const;
|
||||
};
|
||||
|
||||
|
|
|
@ -543,6 +543,31 @@ Module::instantiateFunctions(JSContext* cx, Handle<FunctionVector> funcImports)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckResizableLimits(JSContext* cx, uint32_t declaredMin, Maybe<uint32_t> declaredMax,
|
||||
uint32_t actualLength, Maybe<uint32_t> actualMax,
|
||||
bool isAsmJS, const char* kind)
|
||||
{
|
||||
if (isAsmJS) {
|
||||
MOZ_ASSERT(actualLength >= declaredMin);
|
||||
MOZ_ASSERT(!declaredMax);
|
||||
MOZ_ASSERT(actualLength == actualMax.value());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (actualLength < declaredMin || actualLength > declaredMax.valueOr(UINT32_MAX)) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMP_SIZE, kind);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((actualMax && (!declaredMax || *actualMax > *declaredMax)) || (!actualMax && declaredMax)) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMP_MAX, kind);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// asm.js module instantiation supplies its own buffer, but for wasm, create and
|
||||
// initialize the buffer if one is requested. Either way, the buffer is wrapped
|
||||
// in a WebAssembly.Memory object which is what the Instance stores.
|
||||
|
@ -563,22 +588,11 @@ Module::instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) c
|
|||
MOZ_ASSERT_IF(metadata_->isAsmJS(), buffer.isPreparedForAsmJS());
|
||||
MOZ_ASSERT_IF(!metadata_->isAsmJS(), buffer.as<ArrayBufferObject>().isWasm());
|
||||
|
||||
uint32_t actualLength = buffer.byteLength();
|
||||
if (actualLength < declaredMin || actualLength > declaredMax.valueOr(UINT32_MAX)) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMP_SIZE, "Memory");
|
||||
if (!CheckResizableLimits(cx, declaredMin, declaredMax,
|
||||
buffer.byteLength(), buffer.wasmMaxSize(),
|
||||
metadata_->isAsmJS(), "Memory")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (metadata_->isAsmJS()) {
|
||||
MOZ_ASSERT(IsValidAsmJSHeapLength(actualLength));
|
||||
MOZ_ASSERT(actualLength == buffer.wasmMaxSize().value());
|
||||
} else {
|
||||
Maybe<uint32_t> actualMax = buffer.as<ArrayBufferObject>().wasmMaxSize();
|
||||
if (declaredMax.isSome() != actualMax.isSome() || declaredMax < actualMax) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMP_SIZE, "Memory");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(!metadata_->isAsmJS());
|
||||
MOZ_ASSERT(metadata_->memoryUsage == MemoryUsage::Unshared);
|
||||
|
@ -608,12 +622,13 @@ Module::instantiateTable(JSContext* cx, MutableHandleWasmTableObject tableObj,
|
|||
MOZ_ASSERT(!metadata_->isAsmJS());
|
||||
|
||||
MOZ_ASSERT(metadata_->tables.length() == 1);
|
||||
const TableDesc& tableDesc = metadata_->tables[0];
|
||||
MOZ_ASSERT(tableDesc.external);
|
||||
const TableDesc& td = metadata_->tables[0];
|
||||
MOZ_ASSERT(td.external);
|
||||
|
||||
Table& table = tableObj->table();
|
||||
if (table.length() < tableDesc.initial || table.length() > tableDesc.maximum) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMP_SIZE, "Table");
|
||||
if (!CheckResizableLimits(cx, td.limits.initial, td.limits.maximum,
|
||||
table.length(), table.maximum(),
|
||||
metadata_->isAsmJS(), "Table")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -622,19 +637,19 @@ Module::instantiateTable(JSContext* cx, MutableHandleWasmTableObject tableObj,
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
for (const TableDesc& tableDesc : metadata_->tables) {
|
||||
for (const TableDesc& td : metadata_->tables) {
|
||||
SharedTable table;
|
||||
if (tableDesc.external) {
|
||||
if (td.external) {
|
||||
MOZ_ASSERT(!tableObj);
|
||||
MOZ_ASSERT(tableDesc.kind == TableKind::AnyFunction);
|
||||
MOZ_ASSERT(td.kind == TableKind::AnyFunction);
|
||||
|
||||
tableObj.set(WasmTableObject::create(cx, tableDesc.initial));
|
||||
tableObj.set(WasmTableObject::create(cx, td.limits));
|
||||
if (!tableObj)
|
||||
return false;
|
||||
|
||||
table = &tableObj->table();
|
||||
} else {
|
||||
table = Table::create(cx, tableDesc, /* HandleWasmTableObject = */ nullptr);
|
||||
table = Table::create(cx, td, /* HandleWasmTableObject = */ nullptr);
|
||||
if (!table)
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1111,11 +1111,6 @@ HandleFault(int signum, siginfo_t* info, void* ctx)
|
|||
else
|
||||
MOZ_RELEASE_ASSERT(signum == SIGBUS);
|
||||
|
||||
if (signal == Signal::SegFault && info->si_code != SEGV_ACCERR)
|
||||
return false;
|
||||
if (signal == Signal::BusError && info->si_code != BUS_ADRALN)
|
||||
return false;
|
||||
|
||||
CONTEXT* context = (CONTEXT*)ctx;
|
||||
uint8_t** ppc = ContextToPC(context);
|
||||
uint8_t* pc = *ppc;
|
||||
|
@ -1136,10 +1131,24 @@ HandleFault(int signum, siginfo_t* info, void* ctx)
|
|||
|
||||
uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(info->si_addr);
|
||||
|
||||
// This check isn't necessary, but, since we can, check anyway to make
|
||||
// sure we aren't covering up a real bug.
|
||||
if (!IsHeapAccessAddress(*instance, faultingAddress))
|
||||
// Although it's not strictly necessary, to make sure we're not covering up
|
||||
// any real bugs, check that the faulting address is indeed in the
|
||||
// instance's memory.
|
||||
if (!faultingAddress) {
|
||||
// On some Linux systems, the kernel apparently sometimes "gives up" and
|
||||
// passes a null faultingAddress with si_code set to SI_KERNEL.
|
||||
// This is observed on some automation machines for some out-of-bounds
|
||||
// atomic accesses on x86/64.
|
||||
#ifdef SI_KERNEL
|
||||
if (info->si_code != SI_KERNEL)
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
} else {
|
||||
if (!IsHeapAccessAddress(*instance, faultingAddress))
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef WASM_HUGE_MEMORY
|
||||
return HugeMemoryAccess(context, pc, faultingAddress, *instance, ppc);
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include "asmjs/WasmTable.h"
|
||||
|
||||
#include "mozilla/CheckedInt.h"
|
||||
|
||||
#include "jscntxt.h"
|
||||
|
||||
#include "asmjs/WasmInstance.h"
|
||||
|
@ -25,31 +27,34 @@
|
|||
|
||||
using namespace js;
|
||||
using namespace js::wasm;
|
||||
using mozilla::CheckedInt;
|
||||
|
||||
Table::Table(JSContext* cx, const TableDesc& desc, HandleWasmTableObject maybeObject,
|
||||
UniqueByteArray array)
|
||||
: maybeObject_(maybeObject),
|
||||
observers_(cx->zone(), InstanceSet()),
|
||||
array_(Move(array)),
|
||||
kind_(desc.kind),
|
||||
length_(desc.limits.initial),
|
||||
maximum_(desc.limits.maximum),
|
||||
external_(desc.external)
|
||||
{}
|
||||
|
||||
/* static */ SharedTable
|
||||
Table::create(JSContext* cx, const TableDesc& desc, HandleWasmTableObject maybeObject)
|
||||
{
|
||||
SharedTable table = cx->new_<Table>();
|
||||
if (!table)
|
||||
return nullptr;
|
||||
|
||||
// The raw element type of a Table depends on whether it is external: an
|
||||
// external table can contain functions from multiple instances and thus
|
||||
// must store an additional instance pointer in each element.
|
||||
void* array;
|
||||
UniqueByteArray array;
|
||||
if (desc.external)
|
||||
array = cx->pod_calloc<ExternalTableElem>(desc.initial);
|
||||
array.reset((uint8_t*)cx->pod_calloc<ExternalTableElem>(desc.limits.initial));
|
||||
else
|
||||
array = cx->pod_calloc<void*>(desc.initial);
|
||||
array.reset((uint8_t*)cx->pod_calloc<void*>(desc.limits.initial));
|
||||
if (!array)
|
||||
return nullptr;
|
||||
|
||||
table->maybeObject_.set(maybeObject);
|
||||
table->array_.reset((uint8_t*)array);
|
||||
table->kind_ = desc.kind;
|
||||
table->length_ = desc.initial;
|
||||
table->external_ = desc.external;
|
||||
return table;
|
||||
return SharedTable(cx->new_<Table>(cx, desc, maybeObject, Move(array)));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -133,6 +138,72 @@ Table::setNull(uint32_t index)
|
|||
elem.tls = nullptr;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Table::grow(uint32_t delta, JSContext* cx)
|
||||
{
|
||||
// This isn't just an optimization: movingGrowable() assumes that
|
||||
// onMovingGrowTable does not fire when length == maximum.
|
||||
if (!delta)
|
||||
return length_;
|
||||
|
||||
uint32_t oldLength = length_;
|
||||
|
||||
CheckedInt<uint32_t> newLength = oldLength;
|
||||
newLength += delta;
|
||||
if (!newLength.isValid())
|
||||
return -1;
|
||||
|
||||
if (maximum_ && newLength.value() > maximum_.value())
|
||||
return -1;
|
||||
|
||||
MOZ_ASSERT(movingGrowable());
|
||||
|
||||
JSRuntime* rt = cx; // Use JSRuntime's MallocProvider to avoid throwing.
|
||||
|
||||
// Note that realloc does not release array_'s pointee (which is returned by
|
||||
// externalArray()) on failure which is exactly what we need here.
|
||||
ExternalTableElem* newArray = rt->pod_realloc(externalArray(), length_, newLength.value());
|
||||
if (!newArray)
|
||||
return -1;
|
||||
Unused << array_.release();
|
||||
array_.reset((uint8_t*)newArray);
|
||||
|
||||
// Realloc does not zero the delta for us.
|
||||
PodZero(newArray + length_, delta);
|
||||
length_ = newLength.value();
|
||||
|
||||
if (observers_.initialized()) {
|
||||
for (InstanceSet::Range r = observers_.all(); !r.empty(); r.popFront())
|
||||
r.front()->instance().onMovingGrowTable();
|
||||
}
|
||||
|
||||
return oldLength;
|
||||
}
|
||||
|
||||
bool
|
||||
Table::movingGrowable() const
|
||||
{
|
||||
return !maximum_ || length_ < maximum_.value();
|
||||
}
|
||||
|
||||
bool
|
||||
Table::addMovingGrowObserver(JSContext* cx, WasmInstanceObject* instance)
|
||||
{
|
||||
MOZ_ASSERT(movingGrowable());
|
||||
|
||||
if (!observers_.initialized() && !observers_.init()) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!observers_.putNew(instance)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t
|
||||
Table::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
|
||||
{
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#define wasm_table_h
|
||||
|
||||
#include "asmjs/WasmCode.h"
|
||||
#include "gc/Policy.h"
|
||||
|
||||
namespace js {
|
||||
namespace wasm {
|
||||
|
@ -30,13 +31,22 @@ namespace wasm {
|
|||
|
||||
class Table : public ShareableBase<Table>
|
||||
{
|
||||
using InstanceSet = GCHashSet<ReadBarrieredWasmInstanceObject,
|
||||
MovableCellHasher<ReadBarrieredWasmInstanceObject>,
|
||||
SystemAllocPolicy>;
|
||||
typedef UniquePtr<uint8_t[], JS::FreePolicy> UniqueByteArray;
|
||||
|
||||
ReadBarrieredWasmTableObject maybeObject_;
|
||||
JS::WeakCache<InstanceSet> observers_;
|
||||
UniqueByteArray array_;
|
||||
TableKind kind_;
|
||||
const TableKind kind_;
|
||||
uint32_t length_;
|
||||
bool external_;
|
||||
const Maybe<uint32_t> maximum_;
|
||||
const bool external_;
|
||||
|
||||
template <class> friend struct js::MallocProvider;
|
||||
Table(JSContext* cx, const TableDesc& td, HandleWasmTableObject maybeObject,
|
||||
UniqueByteArray array);
|
||||
|
||||
void tracePrivate(JSTracer* trc);
|
||||
friend class js::WasmTableObject;
|
||||
|
@ -49,6 +59,7 @@ class Table : public ShareableBase<Table>
|
|||
bool external() const { return external_; }
|
||||
bool isTypedFunction() const { return kind_ == TableKind::TypedFunction; }
|
||||
uint32_t length() const { return length_; }
|
||||
Maybe<uint32_t> maximum() const { return maximum_; }
|
||||
uint8_t* base() const { return array_.get(); }
|
||||
|
||||
// All updates must go through a set() function with the exception of
|
||||
|
@ -60,6 +71,10 @@ class Table : public ShareableBase<Table>
|
|||
void set(uint32_t index, void* code, Instance& instance);
|
||||
void setNull(uint32_t index);
|
||||
|
||||
uint32_t grow(uint32_t delta, JSContext* cx);
|
||||
bool movingGrowable() const;
|
||||
bool addMovingGrowObserver(JSContext* cx, WasmInstanceObject* instance);
|
||||
|
||||
// about:memory reporting:
|
||||
|
||||
size_t sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const;
|
||||
|
|
|
@ -945,6 +945,14 @@ enum ModuleKind
|
|||
AsmJS
|
||||
};
|
||||
|
||||
// Represents the resizable limits of memories and tables.
|
||||
|
||||
struct ResizableLimits
|
||||
{
|
||||
uint32_t initial;
|
||||
Maybe<uint32_t> maximum;
|
||||
};
|
||||
|
||||
// TableDesc describes a table as well as the offset of the table's base pointer
|
||||
// in global memory. Currently, wasm only has "any function" and asm.js only
|
||||
// "typed function".
|
||||
|
@ -960,131 +968,18 @@ struct TableDesc
|
|||
TableKind kind;
|
||||
bool external;
|
||||
uint32_t globalDataOffset;
|
||||
uint32_t initial;
|
||||
uint32_t maximum;
|
||||
ResizableLimits limits;
|
||||
|
||||
TableDesc() { PodZero(this); }
|
||||
TableDesc() = default;
|
||||
TableDesc(TableKind kind, ResizableLimits limits)
|
||||
: kind(kind),
|
||||
external(false),
|
||||
globalDataOffset(UINT32_MAX),
|
||||
limits(limits)
|
||||
{}
|
||||
};
|
||||
|
||||
WASM_DECLARE_POD_VECTOR(TableDesc, TableDescVector)
|
||||
|
||||
// CalleeDesc describes how to compile one of the variety of asm.js/wasm calls.
|
||||
// This is hoisted into WasmTypes.h for sharing between Ion and Baseline.
|
||||
|
||||
class CalleeDesc
|
||||
{
|
||||
public:
|
||||
enum Which {
|
||||
// Calls a function defined in the same module by its index.
|
||||
Definition,
|
||||
|
||||
// Calls the import identified by the offset of its FuncImportTls in
|
||||
// thread-local data.
|
||||
Import,
|
||||
|
||||
// Calls a WebAssembly table (heterogeneous, index must be bounds
|
||||
// checked, callee instance depends on TableDesc).
|
||||
WasmTable,
|
||||
|
||||
// Calls an asm.js table (homogeneous, masked index, same-instance).
|
||||
AsmJSTable,
|
||||
|
||||
// Call a C++ function identified by SymbolicAddress.
|
||||
Builtin,
|
||||
|
||||
// Like Builtin, but automatically passes Instance* as first argument.
|
||||
BuiltinInstanceMethod
|
||||
};
|
||||
|
||||
private:
|
||||
Which which_;
|
||||
union U {
|
||||
U() {}
|
||||
uint32_t funcDefIndex_;
|
||||
struct {
|
||||
uint32_t globalDataOffset_;
|
||||
} import;
|
||||
struct {
|
||||
TableDesc desc_;
|
||||
SigIdDesc sigId_;
|
||||
} table;
|
||||
SymbolicAddress builtin_;
|
||||
} u;
|
||||
|
||||
public:
|
||||
CalleeDesc() {}
|
||||
static CalleeDesc definition(uint32_t funcDefIndex) {
|
||||
CalleeDesc c;
|
||||
c.which_ = Definition;
|
||||
c.u.funcDefIndex_ = funcDefIndex;
|
||||
return c;
|
||||
}
|
||||
static CalleeDesc import(uint32_t globalDataOffset) {
|
||||
CalleeDesc c;
|
||||
c.which_ = Import;
|
||||
c.u.import.globalDataOffset_ = globalDataOffset;
|
||||
return c;
|
||||
}
|
||||
static CalleeDesc wasmTable(const TableDesc& desc, SigIdDesc sigId) {
|
||||
CalleeDesc c;
|
||||
c.which_ = WasmTable;
|
||||
c.u.table.desc_ = desc;
|
||||
c.u.table.sigId_ = sigId;
|
||||
return c;
|
||||
}
|
||||
static CalleeDesc asmJSTable(const TableDesc& desc) {
|
||||
CalleeDesc c;
|
||||
c.which_ = AsmJSTable;
|
||||
c.u.table.desc_ = desc;
|
||||
return c;
|
||||
}
|
||||
static CalleeDesc builtin(SymbolicAddress callee) {
|
||||
CalleeDesc c;
|
||||
c.which_ = Builtin;
|
||||
c.u.builtin_ = callee;
|
||||
return c;
|
||||
}
|
||||
static CalleeDesc builtinInstanceMethod(SymbolicAddress callee) {
|
||||
CalleeDesc c;
|
||||
c.which_ = BuiltinInstanceMethod;
|
||||
c.u.builtin_ = callee;
|
||||
return c;
|
||||
}
|
||||
Which which() const {
|
||||
return which_;
|
||||
}
|
||||
uint32_t funcDefIndex() const {
|
||||
MOZ_ASSERT(which_ == Definition);
|
||||
return u.funcDefIndex_;
|
||||
}
|
||||
uint32_t importGlobalDataOffset() const {
|
||||
MOZ_ASSERT(which_ == Import);
|
||||
return u.import.globalDataOffset_;
|
||||
}
|
||||
bool isTable() const {
|
||||
return which_ == WasmTable || which_ == AsmJSTable;
|
||||
}
|
||||
uint32_t tableGlobalDataOffset() const {
|
||||
MOZ_ASSERT(isTable());
|
||||
return u.table.desc_.globalDataOffset;
|
||||
}
|
||||
uint32_t wasmTableLength() const {
|
||||
MOZ_ASSERT(which_ == WasmTable);
|
||||
return u.table.desc_.initial;
|
||||
}
|
||||
bool wasmTableIsExternal() const {
|
||||
MOZ_ASSERT(which_ == WasmTable);
|
||||
return u.table.desc_.external;
|
||||
}
|
||||
SigIdDesc wasmTableSigId() const {
|
||||
MOZ_ASSERT(which_ == WasmTable);
|
||||
return u.table.sigId_;
|
||||
}
|
||||
SymbolicAddress builtin() const {
|
||||
MOZ_ASSERT(which_ == Builtin || which_ == BuiltinInstanceMethod);
|
||||
return u.builtin_;
|
||||
}
|
||||
};
|
||||
typedef Vector<TableDesc, 0, SystemAllocPolicy> TableDescVector;
|
||||
|
||||
// ExportArg holds the unboxed operands to the wasm entry trampoline which can
|
||||
// be called through an ExportFuncPtr.
|
||||
|
@ -1155,9 +1050,23 @@ struct FuncImportTls
|
|||
static_assert(sizeof(GCPtrObject) == sizeof(void*), "for JIT access");
|
||||
};
|
||||
|
||||
// When a table can be shared between instances (it is "external"), the internal
|
||||
// representation is an array of ExternalTableElem instead of just an array of
|
||||
// code pointers.
|
||||
// TableTls describes the region of wasm global memory allocated in the
|
||||
// instance's thread-local storage which is accessed directly from JIT code
|
||||
// to bounds-check and index the table.
|
||||
|
||||
struct TableTls
|
||||
{
|
||||
// Length of the table in number of elements (not bytes).
|
||||
uint32_t length;
|
||||
|
||||
// Pointer to the array of elements (of type either ExternalTableElem or
|
||||
// void*).
|
||||
void* base;
|
||||
};
|
||||
|
||||
// When a table can contain functions from other instances (it is "external"),
|
||||
// the internal representation is an array of ExternalTableElem instead of just
|
||||
// an array of code pointers.
|
||||
|
||||
struct ExternalTableElem
|
||||
{
|
||||
|
@ -1173,6 +1082,126 @@ struct ExternalTableElem
|
|||
TlsData* tls;
|
||||
};
|
||||
|
||||
// CalleeDesc describes how to compile one of the variety of asm.js/wasm calls.
|
||||
// This is hoisted into WasmTypes.h for sharing between Ion and Baseline.
|
||||
|
||||
class CalleeDesc
|
||||
{
|
||||
public:
|
||||
enum Which {
|
||||
// Calls a function defined in the same module by its index.
|
||||
Definition,
|
||||
|
||||
// Calls the import identified by the offset of its FuncImportTls in
|
||||
// thread-local data.
|
||||
Import,
|
||||
|
||||
// Calls a WebAssembly table (heterogeneous, index must be bounds
|
||||
// checked, callee instance depends on TableDesc).
|
||||
WasmTable,
|
||||
|
||||
// Calls an asm.js table (homogeneous, masked index, same-instance).
|
||||
AsmJSTable,
|
||||
|
||||
// Call a C++ function identified by SymbolicAddress.
|
||||
Builtin,
|
||||
|
||||
// Like Builtin, but automatically passes Instance* as first argument.
|
||||
BuiltinInstanceMethod
|
||||
};
|
||||
|
||||
private:
|
||||
Which which_;
|
||||
union U {
|
||||
U() {}
|
||||
uint32_t funcDefIndex_;
|
||||
struct {
|
||||
uint32_t globalDataOffset_;
|
||||
} import;
|
||||
struct {
|
||||
uint32_t globalDataOffset_;
|
||||
bool external_;
|
||||
SigIdDesc sigId_;
|
||||
} table;
|
||||
SymbolicAddress builtin_;
|
||||
} u;
|
||||
|
||||
public:
|
||||
CalleeDesc() {}
|
||||
static CalleeDesc definition(uint32_t funcDefIndex) {
|
||||
CalleeDesc c;
|
||||
c.which_ = Definition;
|
||||
c.u.funcDefIndex_ = funcDefIndex;
|
||||
return c;
|
||||
}
|
||||
static CalleeDesc import(uint32_t globalDataOffset) {
|
||||
CalleeDesc c;
|
||||
c.which_ = Import;
|
||||
c.u.import.globalDataOffset_ = globalDataOffset;
|
||||
return c;
|
||||
}
|
||||
static CalleeDesc wasmTable(const TableDesc& desc, SigIdDesc sigId) {
|
||||
CalleeDesc c;
|
||||
c.which_ = WasmTable;
|
||||
c.u.table.globalDataOffset_ = desc.globalDataOffset;
|
||||
c.u.table.external_ = desc.external;
|
||||
c.u.table.sigId_ = sigId;
|
||||
return c;
|
||||
}
|
||||
static CalleeDesc asmJSTable(const TableDesc& desc) {
|
||||
CalleeDesc c;
|
||||
c.which_ = AsmJSTable;
|
||||
c.u.table.globalDataOffset_ = desc.globalDataOffset;
|
||||
return c;
|
||||
}
|
||||
static CalleeDesc builtin(SymbolicAddress callee) {
|
||||
CalleeDesc c;
|
||||
c.which_ = Builtin;
|
||||
c.u.builtin_ = callee;
|
||||
return c;
|
||||
}
|
||||
static CalleeDesc builtinInstanceMethod(SymbolicAddress callee) {
|
||||
CalleeDesc c;
|
||||
c.which_ = BuiltinInstanceMethod;
|
||||
c.u.builtin_ = callee;
|
||||
return c;
|
||||
}
|
||||
Which which() const {
|
||||
return which_;
|
||||
}
|
||||
uint32_t funcDefIndex() const {
|
||||
MOZ_ASSERT(which_ == Definition);
|
||||
return u.funcDefIndex_;
|
||||
}
|
||||
uint32_t importGlobalDataOffset() const {
|
||||
MOZ_ASSERT(which_ == Import);
|
||||
return u.import.globalDataOffset_;
|
||||
}
|
||||
bool isTable() const {
|
||||
return which_ == WasmTable || which_ == AsmJSTable;
|
||||
}
|
||||
uint32_t tableLengthGlobalDataOffset() const {
|
||||
MOZ_ASSERT(isTable());
|
||||
return u.table.globalDataOffset_ + offsetof(TableTls, length);
|
||||
}
|
||||
uint32_t tableBaseGlobalDataOffset() const {
|
||||
MOZ_ASSERT(isTable());
|
||||
return u.table.globalDataOffset_ + offsetof(TableTls, base);
|
||||
}
|
||||
bool wasmTableIsExternal() const {
|
||||
MOZ_ASSERT(which_ == WasmTable);
|
||||
return u.table.external_;
|
||||
}
|
||||
SigIdDesc wasmTableSigId() const {
|
||||
MOZ_ASSERT(which_ == WasmTable);
|
||||
return u.table.sigId_;
|
||||
}
|
||||
SymbolicAddress builtin() const {
|
||||
MOZ_ASSERT(which_ == Builtin || which_ == BuiltinInstanceMethod);
|
||||
return u.builtin_;
|
||||
}
|
||||
};
|
||||
|
||||
// Because ARM has a fixed-width instruction encoding, ARM can only express a
|
||||
// limited subset of immediates (in a single instruction).
|
||||
|
||||
|
|
|
@ -76,8 +76,8 @@ var ignoreCallees = {
|
|||
"js::ClassOps.finalize" : true,
|
||||
"JSRuntime.destroyPrincipals" : true,
|
||||
"icu_50::UObject.__deleting_dtor" : true, // destructors in ICU code can't cause GC
|
||||
"mozilla::CycleCollectedJSRuntime.DescribeCustomObjects" : true, // During tracing, cannot GC.
|
||||
"mozilla::CycleCollectedJSRuntime.NoteCustomGCThingXPCOMChildren" : true, // During tracing, cannot GC.
|
||||
"mozilla::CycleCollectedJSContext.DescribeCustomObjects" : true, // During tracing, cannot GC.
|
||||
"mozilla::CycleCollectedJSContext.NoteCustomGCThingXPCOMChildren" : true, // During tracing, cannot GC.
|
||||
"PLDHashTableOps.hashKey" : true,
|
||||
"z_stream_s.zfree" : true,
|
||||
"z_stream_s.zalloc" : true,
|
||||
|
|
|
@ -308,9 +308,13 @@ function test_int32(heap) {
|
|||
assertErrorMessage(() => i32m.xchg_i(oob), RangeError, /out-of-range index/);
|
||||
|
||||
// Edge cases
|
||||
assertErrorMessage(() => i32m.load_i(i32a.length*4), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i32m.store_i(i32a.length*4), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i32m.add_i(i32a.length*4), RangeError, /out-of-range index/);
|
||||
const INT32_MAX = Math.pow(2, 31);
|
||||
const UINT32_MAX = Math.pow(2, 32);
|
||||
for (var i of [i32a.length*4, INT32_MAX - 4, INT32_MAX, UINT32_MAX - 4]) {
|
||||
assertErrorMessage(() => i32m.load_i(i), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i32m.store_i(i), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i32m.add_i(i), RangeError, /out-of-range index/);
|
||||
}
|
||||
|
||||
i32a[i32a.length-1] = 88;
|
||||
assertEq(i32m.load_i((i32a.length-1)*4), 88);
|
||||
|
@ -588,9 +592,13 @@ function test_uint32(heap) {
|
|||
assertErrorMessage(() => i32m.xchg_i(oob), RangeError, /out-of-range index/);
|
||||
|
||||
// Edge cases
|
||||
assertErrorMessage(() => i32m.load_i(i32a.length*4), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i32m.store_i(i32a.length*4), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i32m.add_i(i32a.length*4), RangeError, /out-of-range index/);
|
||||
const INT32_MAX = Math.pow(2, 31);
|
||||
const UINT32_MAX = Math.pow(2, 32);
|
||||
for (var i of [i32a.length*4, INT32_MAX - 4, INT32_MAX, UINT32_MAX - 4]) {
|
||||
assertErrorMessage(() => i32m.load_i(i), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i32m.store_i(i), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i32m.add_i(i), RangeError, /out-of-range index/);
|
||||
}
|
||||
|
||||
i32a[i32a.length-1] = 88;
|
||||
assertEq(i32m.load_i((i32a.length-1)*4), 88);
|
||||
|
@ -876,9 +884,13 @@ function test_int16(heap) {
|
|||
assertErrorMessage(() => i16m.xchg_i(oob), RangeError, /out-of-range index/);
|
||||
|
||||
// Edge cases
|
||||
assertErrorMessage(() => i16m.load_i(i16a.length*2), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i16m.store_i(i16a.length*2), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i16m.add_i(i16a.length*2), RangeError, /out-of-range index/);
|
||||
const INT32_MAX = Math.pow(2, 31);
|
||||
const UINT32_MAX = Math.pow(2, 32);
|
||||
for (var i of [i16a.length*2, INT32_MAX - 2, INT32_MAX, UINT32_MAX - 2]) {
|
||||
assertErrorMessage(() => i16m.load_i(i), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i16m.store_i(i), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i16m.add_i(i), RangeError, /out-of-range index/);
|
||||
}
|
||||
|
||||
i16a[i16a.length-1] = 88;
|
||||
assertEq(i16m.load_i((i16a.length-1)*2), 88);
|
||||
|
@ -1164,9 +1176,13 @@ function test_uint16(heap) {
|
|||
assertErrorMessage(() => i16m.xchg_i(oob), RangeError, /out-of-range index/);
|
||||
|
||||
// Edge cases
|
||||
assertErrorMessage(() => i16m.load_i(i16a.length*2), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i16m.store_i(i16a.length*2), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i16m.add_i(i16a.length*2), RangeError, /out-of-range index/);
|
||||
const INT32_MAX = Math.pow(2, 31);
|
||||
const UINT32_MAX = Math.pow(2, 32);
|
||||
for (var i of [i16a.length*2, INT32_MAX - 2, INT32_MAX, UINT32_MAX - 2]) {
|
||||
assertErrorMessage(() => i16m.load_i(i), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i16m.store_i(i), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i16m.add_i(i), RangeError, /out-of-range index/);
|
||||
}
|
||||
|
||||
i16a[i16a.length-1] = 88;
|
||||
assertEq(i16m.load_i((i16a.length-1)*2), 88);
|
||||
|
@ -1445,9 +1461,13 @@ function test_int8(heap) {
|
|||
assertErrorMessage(() => i8m.xchg_i(oob), RangeError, /out-of-range index/);
|
||||
|
||||
// Edge cases
|
||||
assertErrorMessage(() => i8m.load_i(i8a.length), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i8m.store_i(i8a.length), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i8m.add_i(i8a.length), RangeError, /out-of-range index/);
|
||||
const INT32_MAX = Math.pow(2, 31);
|
||||
const UINT32_MAX = Math.pow(2, 32);
|
||||
for (var i of [i8a.length, INT32_MAX - 1, INT32_MAX, UINT32_MAX - 1]) {
|
||||
assertErrorMessage(() => i8m.load_i(i), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i8m.store_i(i), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i8m.add_i(i), RangeError, /out-of-range index/);
|
||||
}
|
||||
|
||||
i8a[i8a.length-1] = 88;
|
||||
assertEq(i8m.load_i(i8a.length-1), 88);
|
||||
|
@ -1736,9 +1756,13 @@ function test_uint8(heap) {
|
|||
assertErrorMessage(() => i8m.xchg_i(oob), RangeError, /out-of-range index/);
|
||||
|
||||
// Edge cases
|
||||
assertErrorMessage(() => i8m.load_i(i8a.length), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i8m.store_i(i8a.length), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i8m.add_i(i8a.length), RangeError, /out-of-range index/);
|
||||
const INT32_MAX = Math.pow(2, 31);
|
||||
const UINT32_MAX = Math.pow(2, 32);
|
||||
for (var i of [i8a.length, INT32_MAX - 1, INT32_MAX, UINT32_MAX - 1]) {
|
||||
assertErrorMessage(() => i8m.load_i(i), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i8m.store_i(i), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => i8m.add_i(i), RangeError, /out-of-range index/);
|
||||
}
|
||||
|
||||
i8a[i8a.length-1] = 88;
|
||||
assertEq(i8m.load_i(i8a.length-1), 88);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
if (!this['SharedArrayBuffer'])
|
||||
quit();
|
||||
|
||||
setJitCompilerOption('wasm.test-mode', 1);
|
||||
new SharedArrayBuffer(65536);
|
||||
setJitCompilerOption('wasm.test-mode', 0)
|
|
@ -22,7 +22,7 @@ const tab2Elem = new Table({initial:2, element:"anyfunc"});
|
|||
const tab3Elem = new Table({initial:3, element:"anyfunc"});
|
||||
const tab4Elem = new Table({initial:4, element:"anyfunc"});
|
||||
|
||||
assertErrorMessage(() => new Memory({initial:2, maximum:1}), TypeError, /bad Memory maximum size/);
|
||||
assertErrorMessage(() => new Memory({initial:2, maximum:1}), RangeError, /bad Memory maximum size/);
|
||||
|
||||
const m1 = new Module(textToBinary('(module (import "foo" "bar") (import "baz" "quux"))'));
|
||||
assertErrorMessage(() => new Instance(m1), TypeError, /no import object given/);
|
||||
|
@ -40,12 +40,12 @@ assertErrorMessage(() => new Instance(m2, {x:{y:mem1Page}}), TypeError, /importe
|
|||
assertErrorMessage(() => new Instance(m2, {x:{y:mem1PageMax1}}), TypeError, /imported Memory with incompatible size/);
|
||||
assertErrorMessage(() => new Instance(m2, {x:{y:mem4Page}}), TypeError, /imported Memory with incompatible size/);
|
||||
assertErrorMessage(() => new Instance(m2, {x:{y:mem4PageMax4}}), TypeError, /imported Memory with incompatible size/);
|
||||
assertErrorMessage(() => new Instance(m2, {x:{y:mem2Page}}), TypeError, /imported Memory with incompatible size/);
|
||||
assertErrorMessage(() => new Instance(m2, {x:{y:mem2Page}}), TypeError, /imported Memory with incompatible maximum size/);
|
||||
assertEq(new Instance(m2, {x:{y:mem2PageMax2}}) instanceof Instance, true);
|
||||
assertErrorMessage(() => new Instance(m2, {x:{y:mem3Page}}), TypeError, /imported Memory with incompatible size/);
|
||||
assertErrorMessage(() => new Instance(m2, {x:{y:mem3Page}}), TypeError, /imported Memory with incompatible maximum size/);
|
||||
assertEq(new Instance(m2, {x:{y:mem3PageMax3}}) instanceof Instance, true);
|
||||
assertEq(new Instance(m2, {x:{y:mem2PageMax3}}) instanceof Instance, true);
|
||||
assertErrorMessage(() => new Instance(m2, {x:{y:mem2PageMax4}}), TypeError, /imported Memory with incompatible size/);
|
||||
assertErrorMessage(() => new Instance(m2, {x:{y:mem2PageMax4}}), TypeError, /imported Memory with incompatible maximum size/);
|
||||
|
||||
const m3 = new Module(textToBinary('(module (import "foo" "bar" (memory 1 1)) (import "baz" "quux"))'));
|
||||
assertErrorMessage(() => new Instance(m3), TypeError, /no import object given/);
|
||||
|
@ -53,7 +53,7 @@ assertErrorMessage(() => new Instance(m3, {foo:null}), TypeError, /import object
|
|||
assertErrorMessage(() => new Instance(m3, {foo:{bar:{}}}), TypeError, /import object field is not a Memory/);
|
||||
assertErrorMessage(() => new Instance(m3, {foo:{bar:mem1Page}, baz:null}), TypeError, /import object field is not an Object/);
|
||||
assertErrorMessage(() => new Instance(m3, {foo:{bar:mem1Page}, baz:{quux:mem1Page}}), TypeError, /import object field is not a Function/);
|
||||
assertErrorMessage(() => new Instance(m3, {foo:{bar:mem1Page}, baz:{quux:()=>{}}}), TypeError, /imported Memory with incompatible size/);
|
||||
assertErrorMessage(() => new Instance(m3, {foo:{bar:mem1Page}, baz:{quux:()=>{}}}), TypeError, /imported Memory with incompatible maximum size/);
|
||||
assertEq(new Instance(m3, {foo:{bar:mem1PageMax1}, baz:{quux:()=>{}}}) instanceof Instance, true);
|
||||
|
||||
const m4 = new Module(textToBinary('(module (import "baz" "quux") (import "foo" "bar" (memory 1 1)))'));
|
||||
|
@ -62,7 +62,7 @@ assertErrorMessage(() => new Instance(m4, {baz:null}), TypeError, /import object
|
|||
assertErrorMessage(() => new Instance(m4, {baz:{quux:{}}}), TypeError, /import object field is not a Function/);
|
||||
assertErrorMessage(() => new Instance(m4, {baz:{quux:()=>{}}, foo:null}), TypeError, /import object field is not an Object/);
|
||||
assertErrorMessage(() => new Instance(m4, {baz:{quux:()=>{}}, foo:{bar:()=>{}}}), TypeError, /import object field is not a Memory/);
|
||||
assertErrorMessage(() => new Instance(m4, {baz:{quux:()=>{}}, foo:{bar:mem1Page}}), TypeError, /imported Memory with incompatible size/);
|
||||
assertErrorMessage(() => new Instance(m4, {baz:{quux:()=>{}}, foo:{bar:mem1Page}}), TypeError, /imported Memory with incompatible maximum size/);
|
||||
assertEq(new Instance(m3, {baz:{quux:()=>{}}, foo:{bar:mem1PageMax1}}) instanceof Instance, true);
|
||||
|
||||
const m5 = new Module(textToBinary('(module (import "a" "b" (memory 2)))'));
|
||||
|
@ -79,8 +79,8 @@ assertEq(new Instance(m6, {a:{b:tab4Elem}}) instanceof Instance, true);
|
|||
|
||||
const m7 = new Module(textToBinary('(module (import "a" "b" (table 2 3)))'));
|
||||
assertErrorMessage(() => new Instance(m7, {a:{b:tab1Elem}}), TypeError, /imported Table with incompatible size/);
|
||||
assertEq(new Instance(m7, {a:{b:tab2Elem}}) instanceof Instance, true);
|
||||
assertEq(new Instance(m7, {a:{b:tab3Elem}}) instanceof Instance, true);
|
||||
assertErrorMessage(() => new Instance(m7, {a:{b:tab2Elem}}), TypeError, /imported Table with incompatible maximum size/);
|
||||
assertErrorMessage(() => new Instance(m7, {a:{b:tab3Elem}}), TypeError, /imported Table with incompatible maximum size/);
|
||||
assertErrorMessage(() => new Instance(m7, {a:{b:tab4Elem}}), TypeError, /imported Table with incompatible size/);
|
||||
|
||||
assertErrorMessage(() => new Module(textToBinary('(module (memory 2 1))')), TypeError, /maximum length less than initial length/);
|
||||
|
@ -264,7 +264,7 @@ assertEq(e.tbl1.get(1), null);
|
|||
assertEq(e.tbl1.get(2), e.tbl1.get(2));
|
||||
assertEq(e.tbl1.get(2)(), 2);
|
||||
assertEq(e.tbl1.get(3), null);
|
||||
assertErrorMessage(() => e.tbl1.get(4), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => e.tbl1.get(4), RangeError, /bad Table get index/);
|
||||
assertEq(e.tbl1.get(1), null);
|
||||
e.tbl1.set(1, e.f3);
|
||||
assertEq(e.tbl1.get(1), e.f3);
|
||||
|
@ -282,13 +282,13 @@ assertEq(mem, e.foo);
|
|||
assertEq(mem, e.bar);
|
||||
|
||||
var code = textToBinary('(module (import "a" "b" (table 1 1)) (export "foo" table) (export "bar" table))');
|
||||
var tbl = new Table({initial:1, element:"anyfunc"});
|
||||
var tbl = new Table({initial:1, maximum:1, element:"anyfunc"});
|
||||
var e = new Instance(new Module(code), {a:{b:tbl}}).exports;
|
||||
assertEq(tbl, e.foo);
|
||||
assertEq(tbl, e.bar);
|
||||
|
||||
var code = textToBinary('(module (import "a" "b" (table 2 2)) (func $foo) (elem (i32.const 0) $foo) (export "foo" $foo))');
|
||||
var tbl = new Table({initial:2, element:"anyfunc"});
|
||||
var tbl = new Table({initial:2, maximum:2, element:"anyfunc"});
|
||||
var e1 = new Instance(new Module(code), {a:{b:tbl}}).exports;
|
||||
assertEq(e1.foo, tbl.get(0));
|
||||
tbl.set(1, e1.foo);
|
||||
|
|
|
@ -117,11 +117,11 @@ assertEq(Memory.name, "Memory");
|
|||
assertErrorMessage(() => Memory(), TypeError, /constructor without new is forbidden/);
|
||||
assertErrorMessage(() => new Memory(1), TypeError, "first argument must be a memory descriptor");
|
||||
assertErrorMessage(() => new Memory({initial:{valueOf() { throw new Error("here")}}}), Error, "here");
|
||||
assertErrorMessage(() => new Memory({initial:-1}), TypeError, /bad Memory initial size/);
|
||||
assertErrorMessage(() => new Memory({initial:Math.pow(2,32)}), TypeError, /bad Memory initial size/);
|
||||
assertErrorMessage(() => new Memory({initial:1, maximum: Math.pow(2,32)/Math.pow(2,14) }), TypeError, /bad Memory maximum size/);
|
||||
assertErrorMessage(() => new Memory({initial:2, maximum: 1 }), TypeError, /bad Memory maximum size/);
|
||||
assertErrorMessage(() => new Memory({maximum: -1 }), TypeError, /bad Memory maximum size/);
|
||||
assertErrorMessage(() => new Memory({initial:-1}), RangeError, /bad Memory initial size/);
|
||||
assertErrorMessage(() => new Memory({initial:Math.pow(2,32)}), RangeError, /bad Memory initial size/);
|
||||
assertErrorMessage(() => new Memory({initial:1, maximum: Math.pow(2,32)/Math.pow(2,14) }), RangeError, /bad Memory maximum size/);
|
||||
assertErrorMessage(() => new Memory({initial:2, maximum:1 }), RangeError, /bad Memory maximum size/);
|
||||
assertErrorMessage(() => new Memory({maximum: -1 }), RangeError, /bad Memory maximum size/);
|
||||
assertEq(new Memory({initial:1}) instanceof Memory, true);
|
||||
assertEq(new Memory({initial:1.5}).buffer.byteLength, WasmPage);
|
||||
|
||||
|
@ -159,18 +159,18 @@ assertEq(bufferGetter.call(mem1) instanceof ArrayBuffer, true);
|
|||
assertEq(bufferGetter.call(mem1).byteLength, WasmPage);
|
||||
|
||||
// 'WebAssembly.Memory.prototype.grow' data property
|
||||
const growDesc = Object.getOwnPropertyDescriptor(memoryProto, 'grow');
|
||||
assertEq(typeof growDesc.value, "function");
|
||||
assertEq(growDesc.enumerable, false);
|
||||
assertEq(growDesc.configurable, true);
|
||||
const memGrowDesc = Object.getOwnPropertyDescriptor(memoryProto, 'grow');
|
||||
assertEq(typeof memGrowDesc.value, "function");
|
||||
assertEq(memGrowDesc.enumerable, false);
|
||||
assertEq(memGrowDesc.configurable, true);
|
||||
|
||||
// 'WebAssembly.Memory.prototype.grow' method
|
||||
const grow = growDesc.value;
|
||||
assertEq(grow.length, 1);
|
||||
assertErrorMessage(() => grow.call(), TypeError, /called on incompatible undefined/);
|
||||
assertErrorMessage(() => grow.call({}), TypeError, /called on incompatible Object/);
|
||||
assertErrorMessage(() => grow.call(mem1, -1), Error, /failed to grow memory/);
|
||||
assertErrorMessage(() => grow.call(mem1, Math.pow(2,32)), Error, /failed to grow memory/);
|
||||
const memGrow = memGrowDesc.value;
|
||||
assertEq(memGrow.length, 1);
|
||||
assertErrorMessage(() => memGrow.call(), TypeError, /called on incompatible undefined/);
|
||||
assertErrorMessage(() => memGrow.call({}), TypeError, /called on incompatible Object/);
|
||||
assertErrorMessage(() => memGrow.call(mem1, -1), RangeError, /bad Memory grow delta/);
|
||||
assertErrorMessage(() => memGrow.call(mem1, Math.pow(2,32)), RangeError, /bad Memory grow delta/);
|
||||
var mem = new Memory({initial:1, maximum:2});
|
||||
var buf = mem.buffer;
|
||||
assertEq(buf.byteLength, WasmPage);
|
||||
|
@ -205,10 +205,14 @@ assertErrorMessage(() => new Table({initial:1, element:1}), TypeError, /must be
|
|||
assertErrorMessage(() => new Table({initial:1, element:"any"}), TypeError, /must be "anyfunc"/);
|
||||
assertErrorMessage(() => new Table({initial:1, element:{valueOf() { return "anyfunc" }}}), TypeError, /must be "anyfunc"/);
|
||||
assertErrorMessage(() => new Table({initial:{valueOf() { throw new Error("here")}}, element:"anyfunc"}), Error, "here");
|
||||
assertErrorMessage(() => new Table({initial:-1, element:"anyfunc"}), TypeError, /bad Table initial size/);
|
||||
assertErrorMessage(() => new Table({initial:Math.pow(2,32), element:"anyfunc"}), TypeError, /bad Table initial size/);
|
||||
assertErrorMessage(() => new Table({initial:-1, element:"anyfunc"}), RangeError, /bad Table initial size/);
|
||||
assertErrorMessage(() => new Table({initial:Math.pow(2,32), element:"anyfunc"}), RangeError, /bad Table initial size/);
|
||||
assertErrorMessage(() => new Table({initial:2, maximum:1, element:"anyfunc"}), RangeError, /bad Table maximum size/);
|
||||
assertErrorMessage(() => new Table({initial:2, maximum:Math.pow(2,32), element:"anyfunc"}), RangeError, /bad Table maximum size/);
|
||||
assertEq(new Table({initial:1, element:"anyfunc"}) instanceof Table, true);
|
||||
assertEq(new Table({initial:1.5, element:"anyfunc"}) instanceof Table, true);
|
||||
assertEq(new Table({initial:1, maximum:1.5, element:"anyfunc"}) instanceof Table, true);
|
||||
assertEq(new Table({initial:1, maximum:Math.pow(2,32)-1, element:"anyfunc"}) instanceof Table, true);
|
||||
|
||||
// 'WebAssembly.Table.prototype' data property
|
||||
const tableProtoDesc = Object.getOwnPropertyDescriptor(Table, 'prototype');
|
||||
|
@ -258,10 +262,10 @@ assertErrorMessage(() => get.call({}), TypeError, /called on incompatible Object
|
|||
assertEq(get.call(tbl1, 0), null);
|
||||
assertEq(get.call(tbl1, 1), null);
|
||||
assertEq(get.call(tbl1, 1.5), null);
|
||||
assertErrorMessage(() => get.call(tbl1, 2), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => get.call(tbl1, 2.5), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => get.call(tbl1, -1), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => get.call(tbl1, Math.pow(2,33)), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => get.call(tbl1, 2), RangeError, /bad Table get index/);
|
||||
assertErrorMessage(() => get.call(tbl1, 2.5), RangeError, /bad Table get index/);
|
||||
assertErrorMessage(() => get.call(tbl1, -1), RangeError, /bad Table get index/);
|
||||
assertErrorMessage(() => get.call(tbl1, Math.pow(2,33)), RangeError, /bad Table get index/);
|
||||
assertErrorMessage(() => get.call(tbl1, {valueOf() { throw new Error("hi") }}), Error, "hi");
|
||||
|
||||
// 'WebAssembly.Table.prototype.set' data property
|
||||
|
@ -276,9 +280,9 @@ assertEq(set.length, 2);
|
|||
assertErrorMessage(() => set.call(), TypeError, /called on incompatible undefined/);
|
||||
assertErrorMessage(() => set.call({}), TypeError, /called on incompatible Object/);
|
||||
assertErrorMessage(() => set.call(tbl1, 0), TypeError, /requires more than 1 argument/);
|
||||
assertErrorMessage(() => set.call(tbl1, 2, null), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => set.call(tbl1, -1, null), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => set.call(tbl1, Math.pow(2,33), null), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => set.call(tbl1, 2, null), RangeError, /bad Table set index/);
|
||||
assertErrorMessage(() => set.call(tbl1, -1, null), RangeError, /bad Table set index/);
|
||||
assertErrorMessage(() => set.call(tbl1, Math.pow(2,33), null), RangeError, /bad Table set index/);
|
||||
assertErrorMessage(() => set.call(tbl1, 0, undefined), TypeError, /can only assign WebAssembly exported functions to Table/);
|
||||
assertErrorMessage(() => set.call(tbl1, 0, {}), TypeError, /can only assign WebAssembly exported functions to Table/);
|
||||
assertErrorMessage(() => set.call(tbl1, 0, function() {}), TypeError, /can only assign WebAssembly exported functions to Table/);
|
||||
|
@ -287,6 +291,27 @@ assertErrorMessage(() => set.call(tbl1, {valueOf() { throw Error("hai") }}, null
|
|||
assertEq(set.call(tbl1, 0, null), undefined);
|
||||
assertEq(set.call(tbl1, 1, null), undefined);
|
||||
|
||||
// 'WebAssembly.Table.prototype.grow' data property
|
||||
const tblGrowDesc = Object.getOwnPropertyDescriptor(tableProto, 'grow');
|
||||
assertEq(typeof tblGrowDesc.value, "function");
|
||||
assertEq(tblGrowDesc.enumerable, false);
|
||||
assertEq(tblGrowDesc.configurable, true);
|
||||
|
||||
// 'WebAssembly.Table.prototype.grow' method
|
||||
const tblGrow = tblGrowDesc.value;
|
||||
assertEq(tblGrow.length, 1);
|
||||
assertErrorMessage(() => tblGrow.call(), TypeError, /called on incompatible undefined/);
|
||||
assertErrorMessage(() => tblGrow.call({}), TypeError, /called on incompatible Object/);
|
||||
assertErrorMessage(() => tblGrow.call(tbl1, -1), RangeError, /bad Table grow delta/);
|
||||
assertErrorMessage(() => tblGrow.call(tbl1, Math.pow(2,32)), RangeError, /bad Table grow delta/);
|
||||
var tbl = new Table({element:"anyfunc", initial:1, maximum:2});
|
||||
assertEq(tbl.length, 1);
|
||||
assertEq(tbl.grow(0), 1);
|
||||
assertEq(tbl.length, 1);
|
||||
assertEq(tbl.grow(1), 1);
|
||||
assertEq(tbl.length, 2);
|
||||
assertErrorMessage(() => tbl.grow(1), Error, /failed to grow table/);
|
||||
|
||||
// 'WebAssembly.compile' data property
|
||||
const compileDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'compile');
|
||||
assertEq(typeof compileDesc.value, "function");
|
||||
|
|
|
@ -6,6 +6,10 @@ const Instance = WebAssembly.Instance;
|
|||
const Table = WebAssembly.Table;
|
||||
const Memory = WebAssembly.Memory;
|
||||
|
||||
// ======
|
||||
// MEMORY
|
||||
// ======
|
||||
|
||||
// Test for stale heap pointers after resize
|
||||
|
||||
// Grow directly from builtin call:
|
||||
|
@ -26,7 +30,7 @@ assertEq(evalText(`(module
|
|||
|
||||
// Grow during call_import:
|
||||
var exports = evalText(`(module
|
||||
(import $imp "a" "imp")
|
||||
(import $imp "" "imp")
|
||||
(memory 1)
|
||||
(func $grow (grow_memory (i32.const 99)))
|
||||
(export "grow" $grow)
|
||||
|
@ -41,7 +45,7 @@ var exports = evalText(`(module
|
|||
(i32.load (i32.const 65532))
|
||||
(i32.load (i32.const 6553596)))))
|
||||
(export "test" $test)
|
||||
)`, {a:{imp() { exports.grow() }}}).exports;
|
||||
)`, {"":{imp() { exports.grow() }}}).exports;
|
||||
|
||||
setJitCompilerOption("baseline.warmup.trigger", 2);
|
||||
setJitCompilerOption("ion.warmup.trigger", 4);
|
||||
|
@ -52,16 +56,16 @@ for (var i = 0; i < 10; i++)
|
|||
var mem = new Memory({initial:1});
|
||||
var tbl = new Table({initial:1, element:"anyfunc"});
|
||||
var exports1 = evalText(`(module
|
||||
(import "a" "mem" (memory 1))
|
||||
(import "" "mem" (memory 1))
|
||||
(func $grow
|
||||
(i32.store (i32.const 65532) (i32.const 10))
|
||||
(grow_memory (i32.const 99))
|
||||
(i32.store (i32.const 6553596) (i32.const 100)))
|
||||
(export "grow" $grow)
|
||||
)`, {a:{mem}}).exports;
|
||||
)`, {"":{mem}}).exports;
|
||||
var exports2 = evalText(`(module
|
||||
(import "a" "tbl" (table 1))
|
||||
(import "a" "mem" (memory 1))
|
||||
(import "" "tbl" (table 1))
|
||||
(import "" "mem" (memory 1))
|
||||
(type $v2v (func))
|
||||
(func $test (result i32)
|
||||
(i32.store (i32.const 0) (i32.const 1))
|
||||
|
@ -72,7 +76,7 @@ var exports2 = evalText(`(module
|
|||
(i32.load (i32.const 65532))
|
||||
(i32.load (i32.const 6553596)))))
|
||||
(export "test" $test)
|
||||
)`, {a:{tbl, mem}}).exports;
|
||||
)`, {"":{tbl, mem}}).exports;
|
||||
tbl.set(0, exports1.grow);
|
||||
assertEq(exports2.test(), 111);
|
||||
|
||||
|
@ -113,3 +117,100 @@ assertEq(exp2.current_memory(), 4);
|
|||
assertEq(exp2.load(3*64*1024), 99);
|
||||
assertEq(mem.buffer.byteLength, 4*64*1024);
|
||||
assertEq(new Int32Array(mem.buffer)[3*64*1024/4], 99);
|
||||
|
||||
// ======
|
||||
// TABLE
|
||||
// ======
|
||||
|
||||
// Test for stale table base pointers after resize
|
||||
|
||||
// Grow during call_import:
|
||||
var exports = evalText(`(module
|
||||
(type $v2i (func (result i32)))
|
||||
(import $grow "" "grow")
|
||||
(table (resizable 1))
|
||||
(func $test (result i32)
|
||||
(i32.add
|
||||
(call_indirect $v2i (i32.const 0))
|
||||
(block
|
||||
(call $grow)
|
||||
(call_indirect $v2i (i32.const 1)))))
|
||||
(func $one (result i32) (i32.const 1))
|
||||
(elem (i32.const 0) $one)
|
||||
(func $two (result i32) (i32.const 2))
|
||||
(export "tbl" table)
|
||||
(export "test" $test)
|
||||
(export "two" $two)
|
||||
)`, {"":{grow() { exports.tbl.grow(1); exports.tbl.set(1, exports.two) }}}).exports;
|
||||
|
||||
setJitCompilerOption("baseline.warmup.trigger", 2);
|
||||
setJitCompilerOption("ion.warmup.trigger", 4);
|
||||
for (var i = 0; i < 10; i++)
|
||||
assertEq(exports.test(), 3);
|
||||
assertEq(exports.tbl.length, 11);
|
||||
|
||||
// Grow during call_indirect:
|
||||
var exports1 = evalText(`(module
|
||||
(import $grow "" "grow")
|
||||
(func $exp (call $grow))
|
||||
(export "exp" $exp)
|
||||
)`, {"":{grow() { exports2.tbl.grow(1); exports2.tbl.set(2, exports2.eleven) }}}).exports;
|
||||
var exports2 = evalText(`(module
|
||||
(type $v2v (func))
|
||||
(type $v2i (func (result i32)))
|
||||
(import $imp "" "imp")
|
||||
(elem (i32.const 0) $imp)
|
||||
(table (resizable 2))
|
||||
(func $test (result i32)
|
||||
(i32.add
|
||||
(call_indirect $v2i (i32.const 1))
|
||||
(block
|
||||
(call_indirect $v2v (i32.const 0))
|
||||
(call_indirect $v2i (i32.const 2)))))
|
||||
(func $ten (result i32) (i32.const 10))
|
||||
(elem (i32.const 1) $ten)
|
||||
(func $eleven (result i32) (i32.const 11))
|
||||
(export "tbl" table)
|
||||
(export "test" $test)
|
||||
(export "eleven" $eleven)
|
||||
)`, {"":{imp:exports1.exp}}).exports;
|
||||
assertEq(exports2.test(), 21);
|
||||
|
||||
// Test for coherent length/contents
|
||||
|
||||
var src = evalText(`(module
|
||||
(func $one (result i32) (i32.const 1))
|
||||
(export "one" $one)
|
||||
(func $two (result i32) (i32.const 2))
|
||||
(export "two" $two)
|
||||
(func $three (result i32) (i32.const 3))
|
||||
(export "three" $three)
|
||||
)`).exports;
|
||||
var tbl = new Table({element:"anyfunc", initial:1});
|
||||
tbl.set(0, src.one);
|
||||
|
||||
var mod = new Module(textToBinary(`(module
|
||||
(type $v2i (func (result i32)))
|
||||
(import "" "tbl" (table 1))
|
||||
(func $ci (param i32) (result i32) (call_indirect $v2i (get_local 0)))
|
||||
(export "call_indirect" $ci)
|
||||
)`));
|
||||
var exp1 = new Instance(mod, {"":{tbl}}).exports;
|
||||
var exp2 = new Instance(mod, {"":{tbl}}).exports;
|
||||
assertEq(exp1.call_indirect(0), 1);
|
||||
assertErrorMessage(() => exp1.call_indirect(1), Error, /out-of-range/);
|
||||
assertEq(exp2.call_indirect(0), 1);
|
||||
assertErrorMessage(() => exp2.call_indirect(1), Error, /out-of-range/);
|
||||
assertEq(tbl.grow(1), 1);
|
||||
assertEq(tbl.length, 2);
|
||||
assertEq(exp1.call_indirect(0), 1);
|
||||
assertErrorMessage(() => exp1.call_indirect(1), Error, /indirect call to null/);
|
||||
tbl.set(1, src.two);
|
||||
assertEq(exp1.call_indirect(1), 2);
|
||||
assertErrorMessage(() => exp1.call_indirect(2), Error, /out-of-range/);
|
||||
assertEq(tbl.grow(2), 2);
|
||||
assertEq(tbl.length, 4);
|
||||
assertEq(exp2.call_indirect(0), 1);
|
||||
assertEq(exp2.call_indirect(1), 2);
|
||||
assertErrorMessage(() => exp2.call_indirect(2), Error, /indirect call to null/);
|
||||
assertErrorMessage(() => exp2.call_indirect(3), Error, /indirect call to null/);
|
||||
|
|
|
@ -2777,7 +2777,7 @@ MacroAssembler::wasmCallIndirect(const wasm::CallSiteDesc& desc, const wasm::Cal
|
|||
if (callee.which() == wasm::CalleeDesc::AsmJSTable) {
|
||||
// asm.js tables require no signature check, have had their index masked
|
||||
// into range and thus need no bounds check and cannot be external.
|
||||
loadWasmGlobalPtr(callee.tableGlobalDataOffset(), scratch);
|
||||
loadWasmGlobalPtr(callee.tableBaseGlobalDataOffset(), scratch);
|
||||
loadPtr(BaseIndex(scratch, index, ScalePointer), scratch);
|
||||
call(desc, scratch);
|
||||
return;
|
||||
|
@ -2799,12 +2799,11 @@ MacroAssembler::wasmCallIndirect(const wasm::CallSiteDesc& desc, const wasm::Cal
|
|||
}
|
||||
|
||||
// WebAssembly throws if the index is out-of-bounds.
|
||||
branch32(Assembler::Condition::AboveOrEqual,
|
||||
index, Imm32(callee.wasmTableLength()),
|
||||
wasm::JumpTarget::OutOfBounds);
|
||||
loadWasmGlobalPtr(callee.tableLengthGlobalDataOffset(), scratch);
|
||||
branch32(Assembler::Condition::AboveOrEqual, index, scratch, wasm::JumpTarget::OutOfBounds);
|
||||
|
||||
// Load the base pointer of the table.
|
||||
loadWasmGlobalPtr(callee.tableGlobalDataOffset(), scratch);
|
||||
loadWasmGlobalPtr(callee.tableBaseGlobalDataOffset(), scratch);
|
||||
|
||||
// Load the callee from the table.
|
||||
if (callee.wasmTableIsExternal()) {
|
||||
|
|
|
@ -350,12 +350,13 @@ MSG_DEF(JSMSG_WASM_DECODE_FAIL, 2, JSEXN_TYPEERR, "wasm validation er
|
|||
MSG_DEF(JSMSG_WASM_TEXT_FAIL, 1, JSEXN_SYNTAXERR, "wasm text error: {0}")
|
||||
MSG_DEF(JSMSG_WASM_IND_CALL_TO_NULL, 0, JSEXN_ERR, "indirect call to null")
|
||||
MSG_DEF(JSMSG_WASM_IND_CALL_BAD_SIG, 0, JSEXN_ERR, "indirect call signature mismatch")
|
||||
MSG_DEF(JSMSG_WASM_BAD_GROW, 0, JSEXN_ERR, "failed to grow memory")
|
||||
MSG_DEF(JSMSG_WASM_BAD_GROW, 1, JSEXN_ERR, "failed to grow {0}")
|
||||
MSG_DEF(JSMSG_WASM_BAD_BUF_ARG, 0, JSEXN_TYPEERR, "first argument must be an ArrayBuffer or typed array object")
|
||||
MSG_DEF(JSMSG_WASM_BAD_MOD_ARG, 0, JSEXN_TYPEERR, "first argument must be a WebAssembly.Module")
|
||||
MSG_DEF(JSMSG_WASM_BAD_DESC_ARG, 1, JSEXN_TYPEERR, "first argument must be a {0} descriptor")
|
||||
MSG_DEF(JSMSG_WASM_BAD_IMP_SIZE, 1, JSEXN_TYPEERR, "imported {0} with incompatible size")
|
||||
MSG_DEF(JSMSG_WASM_BAD_SIZE, 2, JSEXN_TYPEERR, "bad {0} {1} size")
|
||||
MSG_DEF(JSMSG_WASM_BAD_UINT32, 2, JSEXN_RANGEERR, "bad {0} {1}")
|
||||
MSG_DEF(JSMSG_WASM_BAD_IMP_MAX, 1, JSEXN_TYPEERR, "imported {0} with incompatible maximum size")
|
||||
MSG_DEF(JSMSG_WASM_BAD_ELEMENT, 0, JSEXN_TYPEERR, "\"element\" property of table descriptor must be \"anyfunc\"")
|
||||
MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG, 0, JSEXN_TYPEERR, "second argument, if present, must be an object")
|
||||
MSG_DEF(JSMSG_WASM_BAD_IMPORT_FIELD, 1, JSEXN_TYPEERR, "import object field is not {0}")
|
||||
|
|
|
@ -92,6 +92,10 @@ case $cmd in
|
|||
# copy build and config directory.
|
||||
cp -pPR ${TOPSRCDIR}/build ${TOPSRCDIR}/config ${tgtpath}
|
||||
|
||||
# copy cargo config
|
||||
${MKDIR} -p ${tgtpath}/.cargo
|
||||
cp -pPR ${TOPSRCDIR}/.cargo/config.in ${tgtpath}/.cargo
|
||||
|
||||
# put in js itself
|
||||
cp -pPR ${TOPSRCDIR}/mfbt ${tgtpath}
|
||||
cp -p ${SRCDIR}/../moz.configure ${tgtpath}/js
|
||||
|
|
|
@ -127,7 +127,7 @@ static const size_t gStackChunkSize = 8192;
|
|||
|
||||
/*
|
||||
* Note: This limit should match the stack limit set by the browser in
|
||||
* js/xpconnect/src/XPCJSRuntime.cpp
|
||||
* js/xpconnect/src/XPCJSContext.cpp
|
||||
*/
|
||||
#if defined(MOZ_ASAN) || (defined(DEBUG) && !defined(XP_WIN))
|
||||
static const size_t gMaxStackSize = 2 * 128 * sizeof(size_t) * 1024;
|
||||
|
|
|
@ -43,26 +43,6 @@ AnyArrayBufferByteLength(const ArrayBufferObjectMaybeShared* buf)
|
|||
return buf->as<SharedArrayBufferObject>().byteLength();
|
||||
}
|
||||
|
||||
inline size_t
|
||||
WasmArrayBufferMappedSize(const ArrayBufferObjectMaybeShared* buf)
|
||||
{
|
||||
if (buf->is<ArrayBufferObject>())
|
||||
return buf->as<ArrayBufferObject>().wasmMappedSize();
|
||||
#ifdef WASM_HUGE_MEMORY
|
||||
return wasm::HugeMappedSize;
|
||||
#else
|
||||
return buf->as<SharedArrayBufferObject>().byteLength();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline mozilla::Maybe<uint32_t>
|
||||
WasmArrayBufferMaxSize(const ArrayBufferObjectMaybeShared* buf)
|
||||
{
|
||||
if (buf->is<ArrayBufferObject>())
|
||||
return buf->as<ArrayBufferObject>().wasmMaxSize();
|
||||
return mozilla::Some(buf->as<SharedArrayBufferObject>().byteLength());
|
||||
}
|
||||
|
||||
inline bool
|
||||
AnyArrayBufferIsPreparedForAsmJS(const ArrayBufferObjectMaybeShared* buf)
|
||||
{
|
||||
|
|
|
@ -843,6 +843,18 @@ ArrayBufferObject::wasmMappedSize() const
|
|||
return byteLength();
|
||||
}
|
||||
|
||||
size_t
|
||||
js::WasmArrayBufferMappedSize(const ArrayBufferObjectMaybeShared* buf)
|
||||
{
|
||||
if (buf->is<ArrayBufferObject>())
|
||||
return buf->as<ArrayBufferObject>().wasmMappedSize();
|
||||
#ifdef WASM_HUGE_MEMORY
|
||||
return wasm::HugeMappedSize;
|
||||
#else
|
||||
return buf->as<SharedArrayBufferObject>().byteLength();
|
||||
#endif
|
||||
}
|
||||
|
||||
Maybe<uint32_t>
|
||||
ArrayBufferObject::wasmMaxSize() const
|
||||
{
|
||||
|
@ -852,6 +864,15 @@ ArrayBufferObject::wasmMaxSize() const
|
|||
return Some<uint32_t>(byteLength());
|
||||
}
|
||||
|
||||
Maybe<uint32_t>
|
||||
js::WasmArrayBufferMaxSize(const ArrayBufferObjectMaybeShared* buf)
|
||||
{
|
||||
if (buf->is<ArrayBufferObject>())
|
||||
return buf->as<ArrayBufferObject>().wasmMaxSize();
|
||||
|
||||
return Some(buf->as<SharedArrayBufferObject>().byteLength());
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
ArrayBufferObject::wasmGrowToSizeInPlace(uint32_t newSize,
|
||||
HandleArrayBufferObject oldBuf,
|
||||
|
|
|
@ -838,7 +838,7 @@ Debugger::slowPathOnEnterFrame(JSContext* cx, AbstractFramePtr frame)
|
|||
return dbg->observesFrame(frame) && dbg->observesEnterFrame();
|
||||
},
|
||||
[&](Debugger* dbg) -> JSTrapStatus {
|
||||
return dbg->fireEnterFrame(cx, frame, &rval);
|
||||
return dbg->fireEnterFrame(cx, &rval);
|
||||
});
|
||||
|
||||
switch (status) {
|
||||
|
@ -1574,6 +1574,27 @@ CheckResumptionValue(JSContext* cx, AbstractFramePtr frame, const Maybe<HandleVa
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
GetThisValueForCheck(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc,
|
||||
MutableHandleValue thisv, Maybe<HandleValue>& maybeThisv)
|
||||
{
|
||||
if (frame.debuggerNeedsCheckPrimitiveReturn()) {
|
||||
{
|
||||
AutoCompartment ac(cx, frame.environmentChain());
|
||||
if (!GetThisValueForDebuggerMaybeOptimizedOut(cx, frame, pc, thisv))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!cx->compartment()->wrap(cx, thisv))
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT_IF(thisv.isMagic(), thisv.isMagic(JS_UNINITIALIZED_LEXICAL));
|
||||
maybeThisv.emplace(HandleValue(thisv));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Debugger::processResumptionValue(Maybe<AutoCompartment>& ac, AbstractFramePtr frame,
|
||||
const Maybe<HandleValue>& maybeThisv, HandleValue rval,
|
||||
|
@ -1598,57 +1619,68 @@ Debugger::processResumptionValue(Maybe<AutoCompartment>& ac, AbstractFramePtr fr
|
|||
}
|
||||
|
||||
JSTrapStatus
|
||||
Debugger::processHandlerResultHelper(Maybe<AutoCompartment>& ac, bool ok, const Value& rv,
|
||||
const Maybe<HandleValue>& thisVForCheck, AbstractFramePtr frame,
|
||||
MutableHandleValue vp)
|
||||
Debugger::processParsedHandlerResultHelper(Maybe<AutoCompartment>& ac, AbstractFramePtr frame,
|
||||
const Maybe<HandleValue>& maybeThisv, bool success,
|
||||
JSTrapStatus status, MutableHandleValue vp)
|
||||
{
|
||||
if (!ok)
|
||||
return handleUncaughtException(ac, vp, thisVForCheck, frame);
|
||||
if (!success)
|
||||
return handleUncaughtException(ac, vp, maybeThisv, frame);
|
||||
|
||||
JSContext* cx = ac->context()->asJSContext();
|
||||
RootedValue rvRoot(cx, rv);
|
||||
JSTrapStatus status = JSTRAP_CONTINUE;
|
||||
RootedValue v(cx);
|
||||
if (!processResumptionValue(ac, frame, thisVForCheck, rvRoot, status, &v))
|
||||
return handleUncaughtException(ac, vp, thisVForCheck, frame);
|
||||
vp.set(v);
|
||||
|
||||
if (!unwrapDebuggeeValue(cx, vp) ||
|
||||
!CheckResumptionValue(cx, frame, maybeThisv, status, vp))
|
||||
{
|
||||
return handleUncaughtException(ac, vp, maybeThisv, frame);
|
||||
}
|
||||
|
||||
ac.reset();
|
||||
if (!cx->compartment()->wrap(cx, vp)) {
|
||||
status = JSTRAP_ERROR;
|
||||
vp.setUndefined();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
JSTrapStatus
|
||||
Debugger::processHandlerResult(Maybe<AutoCompartment>& ac, bool ok, const Value& rv,
|
||||
AbstractFramePtr frame, jsbytecode* pc, MutableHandleValue vp)
|
||||
Debugger::processParsedHandlerResult(Maybe<AutoCompartment>& ac, AbstractFramePtr frame,
|
||||
jsbytecode* pc, bool success, JSTrapStatus status,
|
||||
MutableHandleValue vp)
|
||||
{
|
||||
JSContext* cx = ac->context()->asJSContext();
|
||||
RootedValue rootThis(cx);
|
||||
Maybe<HandleValue> thisArg;
|
||||
if (frame.debuggerNeedsCheckPrimitiveReturn()) {
|
||||
bool success;
|
||||
{
|
||||
AutoCompartment ac2(cx, frame.environmentChain());
|
||||
success = GetThisValueForDebuggerMaybeOptimizedOut(cx, frame, pc, &rootThis);
|
||||
}
|
||||
if (!success || !cx->compartment()->wrap(cx, &rootThis)) {
|
||||
ac.reset();
|
||||
return JSTRAP_ERROR;
|
||||
}
|
||||
MOZ_ASSERT_IF(rootThis.isMagic(), rootThis.isMagic(JS_UNINITIALIZED_LEXICAL));
|
||||
thisArg.emplace(HandleValue(rootThis));
|
||||
|
||||
RootedValue thisv(cx);
|
||||
Maybe<HandleValue> maybeThisv;
|
||||
if (!GetThisValueForCheck(cx, frame, pc, &thisv, maybeThisv)) {
|
||||
ac.reset();
|
||||
return JSTRAP_ERROR;
|
||||
}
|
||||
return processHandlerResultHelper(ac, ok, rv, thisArg, frame, vp);
|
||||
|
||||
return processParsedHandlerResultHelper(ac, frame, maybeThisv, success, status, vp);
|
||||
}
|
||||
|
||||
JSTrapStatus
|
||||
Debugger::processHandlerResult(Maybe<AutoCompartment>& ac, bool ok, const Value& rv,
|
||||
const Value& thisV, AbstractFramePtr frame, MutableHandleValue vp)
|
||||
Debugger::processHandlerResult(Maybe<AutoCompartment>& ac, bool success, const Value& rv,
|
||||
AbstractFramePtr frame, jsbytecode* pc, MutableHandleValue vp)
|
||||
{
|
||||
JSContext* cx = ac->context()->asJSContext();
|
||||
RootedValue rootThis(cx, thisV);
|
||||
Maybe<HandleValue> thisArg;
|
||||
if (frame.debuggerNeedsCheckPrimitiveReturn())
|
||||
thisArg.emplace(rootThis);
|
||||
|
||||
return processHandlerResultHelper(ac, ok, rv, thisArg, frame, vp);
|
||||
RootedValue thisv(cx);
|
||||
Maybe<HandleValue> maybeThisv;
|
||||
if (!GetThisValueForCheck(cx, frame, pc, &thisv, maybeThisv)) {
|
||||
ac.reset();
|
||||
return JSTRAP_ERROR;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
return handleUncaughtException(ac, vp, maybeThisv, frame);
|
||||
|
||||
RootedValue rootRv(cx, rv);
|
||||
JSTrapStatus status = JSTRAP_CONTINUE;
|
||||
success = ParseResumptionValue(cx, rootRv, status, vp);
|
||||
|
||||
return processParsedHandlerResultHelper(ac, frame, maybeThisv, success, status, vp);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -1732,7 +1764,7 @@ Debugger::fireExceptionUnwind(JSContext* cx, MutableHandleValue vp)
|
|||
}
|
||||
|
||||
JSTrapStatus
|
||||
Debugger::fireEnterFrame(JSContext* cx, AbstractFramePtr frame, MutableHandleValue vp)
|
||||
Debugger::fireEnterFrame(JSContext* cx, MutableHandleValue vp)
|
||||
{
|
||||
RootedObject hook(cx, getHook(OnEnterFrame));
|
||||
MOZ_ASSERT(hook);
|
||||
|
@ -1742,14 +1774,16 @@ Debugger::fireEnterFrame(JSContext* cx, AbstractFramePtr frame, MutableHandleVal
|
|||
ac.emplace(cx, object);
|
||||
|
||||
RootedValue scriptFrame(cx);
|
||||
if (!getScriptFrame(cx, frame, &scriptFrame))
|
||||
|
||||
ScriptFrameIter iter(cx);
|
||||
if (!getScriptFrame(cx, iter, &scriptFrame))
|
||||
return reportUncaughtException(ac);
|
||||
|
||||
RootedValue fval(cx, ObjectValue(*hook));
|
||||
RootedValue rv(cx);
|
||||
bool ok = js::Call(cx, fval, object, scriptFrame, &rv);
|
||||
|
||||
return processHandlerResult(ac, ok, rv, MagicValue(JS_UNINITIALIZED_LEXICAL), frame, vp);
|
||||
return processHandlerResult(ac, ok, rv, iter.abstractFramePtr(), iter.pc(), vp);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -559,21 +559,17 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
JSTrapStatus processHandlerResult(mozilla::Maybe<AutoCompartment>& ac, bool OK, const Value& rv,
|
||||
AbstractFramePtr frame, jsbytecode* pc, MutableHandleValue vp);
|
||||
|
||||
/*
|
||||
* When we run the onEnterFrame hook, the |this| slot hasn't been fully
|
||||
* initialized, because the initialzation happens in the function's
|
||||
* prologue. To combat this, we pass the this for the primitive return
|
||||
* check directly. When bug 1249193 is fixed, this overload should be
|
||||
* removed.
|
||||
*/
|
||||
JSTrapStatus processHandlerResult(mozilla::Maybe<AutoCompartment>& ac, bool OK, const Value& rv,
|
||||
const Value& thisVForCheck, AbstractFramePtr frame,
|
||||
MutableHandleValue vp);
|
||||
|
||||
JSTrapStatus processHandlerResultHelper(mozilla::Maybe<AutoCompartment>& ac, bool ok, const Value& rv,
|
||||
const mozilla::Maybe<HandleValue>& thisVForCheck, AbstractFramePtr frame,
|
||||
JSTrapStatus processParsedHandlerResult(mozilla::Maybe<AutoCompartment>& ac,
|
||||
AbstractFramePtr frame, jsbytecode* pc,
|
||||
bool success, JSTrapStatus status,
|
||||
MutableHandleValue vp);
|
||||
|
||||
JSTrapStatus processParsedHandlerResultHelper(mozilla::Maybe<AutoCompartment>& ac,
|
||||
AbstractFramePtr frame,
|
||||
const mozilla::Maybe<HandleValue>& maybeThisv,
|
||||
bool success, JSTrapStatus status,
|
||||
MutableHandleValue vp);
|
||||
|
||||
bool processResumptionValue(mozilla::Maybe<AutoCompartment>& ac, AbstractFramePtr frame,
|
||||
const mozilla::Maybe<HandleValue>& maybeThis, HandleValue rval,
|
||||
JSTrapStatus& statusp, MutableHandleValue vp);
|
||||
|
@ -717,7 +713,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
|
||||
JSTrapStatus fireDebuggerStatement(JSContext* cx, MutableHandleValue vp);
|
||||
JSTrapStatus fireExceptionUnwind(JSContext* cx, MutableHandleValue vp);
|
||||
JSTrapStatus fireEnterFrame(JSContext* cx, AbstractFramePtr frame, MutableHandleValue vp);
|
||||
JSTrapStatus fireEnterFrame(JSContext* cx, MutableHandleValue vp);
|
||||
JSTrapStatus fireNewGlobalObject(JSContext* cx, Handle<GlobalObject*> global, MutableHandleValue vp);
|
||||
JSTrapStatus firePromiseHook(JSContext* cx, Hook hook, HandleObject promise, MutableHandleValue vp);
|
||||
|
||||
|
|
|
@ -80,7 +80,6 @@ MarkValidRegion(void* addr, size_t len)
|
|||
static uint64_t
|
||||
SharedArrayMappedSize(uint32_t allocSize)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(jit::JitOptions.wasmTestMode);
|
||||
MOZ_RELEASE_ASSERT(sizeof(SharedArrayRawBuffer) < gc::SystemPageSize());
|
||||
#ifdef WASM_HUGE_MEMORY
|
||||
return wasm::HugeMappedSize + gc::SystemPageSize();
|
||||
|
|
|
@ -612,7 +612,7 @@ interface nsIXPCComponents_Utils : nsISupports
|
|||
* watchdog-related event occured.
|
||||
*
|
||||
* Valid categories:
|
||||
* "RuntimeStateChange" - Runtime switching between active and inactive states
|
||||
* "ContextStateChange" - Context switching between active and inactive states
|
||||
* "WatchdogWakeup" - Watchdog waking up from sleeping
|
||||
* "WatchdogHibernateStart" - Watchdog begins hibernating
|
||||
* "WatchdogHibernateStop" - Watchdog stops hibernating
|
||||
|
|
|
@ -776,7 +776,7 @@ NotifyPrecompilationCompleteRunnable::Run(void)
|
|||
AutoSendObserverNotification notifier(mPrecompiler);
|
||||
|
||||
if (mToken) {
|
||||
JSContext* cx = XPCJSRuntime::Get()->Context();
|
||||
JSContext* cx = XPCJSContext::Get()->Context();
|
||||
NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
|
||||
JS::CancelOffThreadScript(cx, mToken);
|
||||
}
|
||||
|
|
|
@ -365,7 +365,7 @@ NewFunctionForwarder(JSContext* cx, HandleId idArg, HandleObject callable,
|
|||
{
|
||||
RootedId id(cx, idArg);
|
||||
if (id == JSID_VOIDHANDLE)
|
||||
id = GetRTIdByIndex(cx, XPCJSRuntime::IDX_EMPTYSTRING);
|
||||
id = GetJSIDByIndex(cx, XPCJSContext::IDX_EMPTYSTRING);
|
||||
|
||||
// We have no way of knowing whether the underlying function wants to be a
|
||||
// constructor or not, so we just mark all forwarders as constructors, and
|
||||
|
|
|
@ -482,7 +482,7 @@ sandbox_addProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v)
|
|||
// Whenever JS_EnumerateStandardClasses is called, it defines the
|
||||
// "undefined" property, even if it's already defined. We don't want to do
|
||||
// anything in that case.
|
||||
if (id == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_UNDEFINED))
|
||||
if (id == XPCJSContext::Get()->GetStringID(XPCJSContext::IDX_UNDEFINED))
|
||||
return true;
|
||||
|
||||
// Avoid recursively triggering sandbox_addProperty in the
|
||||
|
|
|
@ -27,7 +27,7 @@ XPCCallContext::XPCCallContext(JSContext* cx,
|
|||
: mAr(cx),
|
||||
mState(INIT_FAILED),
|
||||
mXPC(nsXPConnect::XPConnect()),
|
||||
mXPCJSRuntime(nullptr),
|
||||
mXPCJSContext(nullptr),
|
||||
mJSContext(cx),
|
||||
mWrapper(nullptr),
|
||||
mTearOff(nullptr),
|
||||
|
@ -39,12 +39,12 @@ XPCCallContext::XPCCallContext(JSContext* cx,
|
|||
if (!mXPC)
|
||||
return;
|
||||
|
||||
mXPCJSRuntime = XPCJSRuntime::Get();
|
||||
mXPCJSContext = XPCJSContext::Get();
|
||||
|
||||
// hook into call context chain.
|
||||
mPrevCallContext = mXPCJSRuntime->SetCallContext(this);
|
||||
mPrevCallContext = mXPCJSContext->SetCallContext(this);
|
||||
|
||||
mState = HAVE_RUNTIME;
|
||||
mState = HAVE_CONTEXT;
|
||||
|
||||
if (!obj)
|
||||
return;
|
||||
|
@ -125,7 +125,7 @@ void
|
|||
XPCCallContext::SetCallInfo(XPCNativeInterface* iface, XPCNativeMember* member,
|
||||
bool isSetter)
|
||||
{
|
||||
CHECK_STATE(HAVE_RUNTIME);
|
||||
CHECK_STATE(HAVE_CONTEXT);
|
||||
|
||||
// We are going straight to the method info and need not do a lookup
|
||||
// by id.
|
||||
|
@ -197,7 +197,7 @@ XPCCallContext::SystemIsBeingShutDown()
|
|||
// can be making this call on one thread for call contexts on another
|
||||
// thread.
|
||||
NS_WARNING("Shutting Down XPConnect even through there is a live XPCCallContext");
|
||||
mXPCJSRuntime = nullptr;
|
||||
mXPCJSContext = nullptr;
|
||||
mState = SYSTEM_SHUTDOWN;
|
||||
mInterface = nullptr;
|
||||
|
||||
|
@ -207,8 +207,8 @@ XPCCallContext::SystemIsBeingShutDown()
|
|||
|
||||
XPCCallContext::~XPCCallContext()
|
||||
{
|
||||
if (mXPCJSRuntime) {
|
||||
DebugOnly<XPCCallContext*> old = mXPCJSRuntime->SetCallContext(mPrevCallContext);
|
||||
if (mXPCJSContext) {
|
||||
DebugOnly<XPCCallContext*> old = mXPCJSContext->SetCallContext(mPrevCallContext);
|
||||
MOZ_ASSERT(old == this, "bad pop from per thread data");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2569,7 +2569,7 @@ nsXPCComponents_Utils::GetWeakReference(HandleValue object, JSContext* cx,
|
|||
NS_IMETHODIMP
|
||||
nsXPCComponents_Utils::ForceGC()
|
||||
{
|
||||
JSContext* cx = nsXPConnect::GetRuntimeInstance()->Context();
|
||||
JSContext* cx = nsXPConnect::GetContextInstance()->Context();
|
||||
PrepareForFullGC(cx);
|
||||
GCForReason(cx, GC_NORMAL, gcreason::COMPONENT_UTILS);
|
||||
return NS_OK;
|
||||
|
@ -3187,8 +3187,8 @@ NS_IMETHODIMP
|
|||
nsXPCComponents_Utils::GetWatchdogTimestamp(const nsAString& aCategory, PRTime* aOut)
|
||||
{
|
||||
WatchdogTimestampCategory category;
|
||||
if (aCategory.EqualsLiteral("RuntimeStateChange"))
|
||||
category = TimestampRuntimeStateChange;
|
||||
if (aCategory.EqualsLiteral("ContextStateChange"))
|
||||
category = TimestampContextStateChange;
|
||||
else if (aCategory.EqualsLiteral("WatchdogWakeup"))
|
||||
category = TimestampWatchdogWakeup;
|
||||
else if (aCategory.EqualsLiteral("WatchdogHibernateStart"))
|
||||
|
@ -3197,7 +3197,7 @@ nsXPCComponents_Utils::GetWatchdogTimestamp(const nsAString& aCategory, PRTime*
|
|||
category = TimestampWatchdogHibernateStop;
|
||||
else
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
*aOut = XPCJSRuntime::Get()->GetWatchdogTimestamp(category);
|
||||
*aOut = XPCJSContext::Get()->GetWatchdogTimestamp(category);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3458,7 +3458,7 @@ nsXPCComponents::GetManager(nsIComponentManager * *aManager)
|
|||
NS_IMETHODIMP
|
||||
nsXPCComponents::GetReturnCode(JSContext* aCx, MutableHandleValue aOut)
|
||||
{
|
||||
nsresult res = XPCJSRuntime::Get()->GetPendingResult();
|
||||
nsresult res = XPCJSContext::Get()->GetPendingResult();
|
||||
aOut.setNumber(static_cast<uint32_t>(res));
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -3469,7 +3469,7 @@ nsXPCComponents::SetReturnCode(JSContext* aCx, HandleValue aCode)
|
|||
nsresult rv;
|
||||
if (!ToUint32(aCx, aCode, (uint32_t*)&rv))
|
||||
return NS_ERROR_FAILURE;
|
||||
XPCJSRuntime::Get()->SetPendingResult(rv);
|
||||
XPCJSContext::Get()->SetPendingResult(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// forward declarations of interally used classes...
|
||||
|
||||
class nsXPConnect;
|
||||
class XPCJSRuntime;
|
||||
class XPCJSContext;
|
||||
class XPCContext;
|
||||
class XPCCallContext;
|
||||
|
||||
|
|
|
@ -14,19 +14,19 @@
|
|||
/***************************************************************************/
|
||||
|
||||
inline void
|
||||
XPCJSRuntime::AddVariantRoot(XPCTraceableVariant* variant)
|
||||
XPCJSContext::AddVariantRoot(XPCTraceableVariant* variant)
|
||||
{
|
||||
variant->AddToRootSet(&mVariantRoots);
|
||||
}
|
||||
|
||||
inline void
|
||||
XPCJSRuntime::AddWrappedJSRoot(nsXPCWrappedJS* wrappedJS)
|
||||
XPCJSContext::AddWrappedJSRoot(nsXPCWrappedJS* wrappedJS)
|
||||
{
|
||||
wrappedJS->AddToRootSet(&mWrappedJSRoots);
|
||||
}
|
||||
|
||||
inline void
|
||||
XPCJSRuntime::AddObjectHolderRoot(XPCJSObjectHolder* holder)
|
||||
XPCJSContext::AddObjectHolderRoot(XPCJSObjectHolder* holder)
|
||||
{
|
||||
holder->AddToRootSet(&mObjectHolderRoots);
|
||||
}
|
||||
|
@ -39,24 +39,24 @@ XPCCallContext::IsValid() const
|
|||
return mState != INIT_FAILED;
|
||||
}
|
||||
|
||||
inline XPCJSRuntime*
|
||||
XPCCallContext::GetRuntime() const
|
||||
inline XPCJSContext*
|
||||
XPCCallContext::GetContext() const
|
||||
{
|
||||
CHECK_STATE(HAVE_RUNTIME);
|
||||
return mXPCJSRuntime;
|
||||
CHECK_STATE(HAVE_CONTEXT);
|
||||
return mXPCJSContext;
|
||||
}
|
||||
|
||||
inline JSContext*
|
||||
XPCCallContext::GetJSContext() const
|
||||
{
|
||||
CHECK_STATE(HAVE_RUNTIME);
|
||||
CHECK_STATE(HAVE_CONTEXT);
|
||||
return mJSContext;
|
||||
}
|
||||
|
||||
inline XPCCallContext*
|
||||
XPCCallContext::GetPrevCallContext() const
|
||||
{
|
||||
CHECK_STATE(HAVE_RUNTIME);
|
||||
CHECK_STATE(HAVE_CONTEXT);
|
||||
return mPrevCallContext;
|
||||
}
|
||||
|
||||
|
@ -185,29 +185,29 @@ XPCCallContext::SetRetVal(JS::Value val)
|
|||
inline jsid
|
||||
XPCCallContext::GetResolveName() const
|
||||
{
|
||||
CHECK_STATE(HAVE_RUNTIME);
|
||||
return XPCJSRuntime::Get()->GetResolveName();
|
||||
CHECK_STATE(HAVE_CONTEXT);
|
||||
return XPCJSContext::Get()->GetResolveName();
|
||||
}
|
||||
|
||||
inline jsid
|
||||
XPCCallContext::SetResolveName(JS::HandleId name)
|
||||
{
|
||||
CHECK_STATE(HAVE_RUNTIME);
|
||||
return XPCJSRuntime::Get()->SetResolveName(name);
|
||||
CHECK_STATE(HAVE_CONTEXT);
|
||||
return XPCJSContext::Get()->SetResolveName(name);
|
||||
}
|
||||
|
||||
inline XPCWrappedNative*
|
||||
XPCCallContext::GetResolvingWrapper() const
|
||||
{
|
||||
CHECK_STATE(HAVE_OBJECT);
|
||||
return XPCJSRuntime::Get()->GetResolvingWrapper();
|
||||
return XPCJSContext::Get()->GetResolvingWrapper();
|
||||
}
|
||||
|
||||
inline XPCWrappedNative*
|
||||
XPCCallContext::SetResolvingWrapper(XPCWrappedNative* w)
|
||||
{
|
||||
CHECK_STATE(HAVE_OBJECT);
|
||||
return XPCJSRuntime::Get()->SetResolvingWrapper(w);
|
||||
return XPCJSContext::Get()->SetResolvingWrapper(w);
|
||||
}
|
||||
|
||||
inline uint16_t
|
||||
|
@ -536,10 +536,10 @@ xpc_ForcePropertyResolve(JSContext* cx, JS::HandleObject obj, jsid idArg)
|
|||
}
|
||||
|
||||
inline jsid
|
||||
GetRTIdByIndex(JSContext* cx, unsigned index)
|
||||
GetJSIDByIndex(JSContext* cx, unsigned index)
|
||||
{
|
||||
XPCJSRuntime* rt = nsXPConnect::XPConnect()->GetRuntime();
|
||||
return rt->GetStringID(index);
|
||||
XPCJSContext* xpcx = nsXPConnect::XPConnect()->GetContext();
|
||||
return xpcx->GetStringID(index);
|
||||
}
|
||||
|
||||
inline
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* 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/. */
|
||||
|
||||
/* Per JSRuntime object */
|
||||
/* Per JSContext object */
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
@ -77,7 +77,7 @@ using mozilla::dom::AutoEntryScript;
|
|||
|
||||
/***************************************************************************/
|
||||
|
||||
const char* const XPCJSRuntime::mStrings[] = {
|
||||
const char* const XPCJSContext::mStrings[] = {
|
||||
"constructor", // IDX_CONSTRUCTOR
|
||||
"toString", // IDX_TO_STRING
|
||||
"toSource", // IDX_TO_SOURCE
|
||||
|
@ -501,19 +501,19 @@ EnableUniversalXPConnect(JSContext* cx)
|
|||
JSObject*
|
||||
UnprivilegedJunkScope()
|
||||
{
|
||||
return XPCJSRuntime::Get()->UnprivilegedJunkScope();
|
||||
return XPCJSContext::Get()->UnprivilegedJunkScope();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
PrivilegedJunkScope()
|
||||
{
|
||||
return XPCJSRuntime::Get()->PrivilegedJunkScope();
|
||||
return XPCJSContext::Get()->PrivilegedJunkScope();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
CompilationScope()
|
||||
{
|
||||
return XPCJSRuntime::Get()->CompilationScope();
|
||||
return XPCJSContext::Get()->CompilationScope();
|
||||
}
|
||||
|
||||
nsGlobalWindow*
|
||||
|
@ -568,8 +568,8 @@ CurrentWindowOrNull(JSContext* cx)
|
|||
static void
|
||||
CompartmentDestroyedCallback(JSFreeOp* fop, JSCompartment* compartment)
|
||||
{
|
||||
// NB - This callback may be called in JS_DestroyRuntime, which happens
|
||||
// after the XPCJSRuntime has been torn down.
|
||||
// NB - This callback may be called in JS_DestroyContext, which happens
|
||||
// after the XPCJSContext has been torn down.
|
||||
|
||||
// Get the current compartment private into an AutoPtr (which will do the
|
||||
// cleanup for us), and null out the private (which may already be null).
|
||||
|
@ -589,7 +589,7 @@ CompartmentSizeOfIncludingThisCallback(MallocSizeOf mallocSizeOf, JSCompartment*
|
|||
* inner window and whose reflector is gray. We don't merge system
|
||||
* compartments, so we don't use them to trigger merging CCs.
|
||||
*/
|
||||
bool XPCJSRuntime::UsefulToMergeZones() const
|
||||
bool XPCJSContext::UsefulToMergeZones() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -600,7 +600,7 @@ bool XPCJSRuntime::UsefulToMergeZones() const
|
|||
return false;
|
||||
}
|
||||
|
||||
void XPCJSRuntime::TraceNativeBlackRoots(JSTracer* trc)
|
||||
void XPCJSContext::TraceNativeBlackRoots(JSTracer* trc)
|
||||
{
|
||||
// Skip this part if XPConnect is shutting down. We get into
|
||||
// bad locking problems with the thread iteration otherwise.
|
||||
|
@ -620,7 +620,7 @@ void XPCJSRuntime::TraceNativeBlackRoots(JSTracer* trc)
|
|||
nsXPConnect::XPConnect()->IsShuttingDown());
|
||||
}
|
||||
|
||||
void XPCJSRuntime::TraceAdditionalNativeGrayRoots(JSTracer* trc)
|
||||
void XPCJSContext::TraceAdditionalNativeGrayRoots(JSTracer* trc)
|
||||
{
|
||||
XPCWrappedNativeScope::TraceWrappedNativesInAllScopes(trc, this);
|
||||
|
||||
|
@ -632,7 +632,7 @@ void XPCJSRuntime::TraceAdditionalNativeGrayRoots(JSTracer* trc)
|
|||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback& cb)
|
||||
XPCJSContext::TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback& cb)
|
||||
{
|
||||
XPCWrappedNativeScope::SuspectAllWrappers(this, cb);
|
||||
|
||||
|
@ -653,13 +653,13 @@ XPCJSRuntime::TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback& c
|
|||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::UnmarkSkippableJSHolders()
|
||||
XPCJSContext::UnmarkSkippableJSHolders()
|
||||
{
|
||||
CycleCollectedJSRuntime::UnmarkSkippableJSHolders();
|
||||
CycleCollectedJSContext::UnmarkSkippableJSHolders();
|
||||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::PrepareForForgetSkippable()
|
||||
XPCJSContext::PrepareForForgetSkippable()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
|
@ -668,7 +668,7 @@ XPCJSRuntime::PrepareForForgetSkippable()
|
|||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::BeginCycleCollectionCallback()
|
||||
XPCJSContext::BeginCycleCollectionCallback()
|
||||
{
|
||||
nsJSContext::BeginCycleCollectionCallback();
|
||||
|
||||
|
@ -679,7 +679,7 @@ XPCJSRuntime::BeginCycleCollectionCallback()
|
|||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::EndCycleCollectionCallback(CycleCollectorResults& aResults)
|
||||
XPCJSContext::EndCycleCollectionCallback(CycleCollectorResults& aResults)
|
||||
{
|
||||
nsJSContext::EndCycleCollectionCallback(aResults);
|
||||
|
||||
|
@ -690,7 +690,7 @@ XPCJSRuntime::EndCycleCollectionCallback(CycleCollectorResults& aResults)
|
|||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::DispatchDeferredDeletion(bool aContinuation, bool aPurge)
|
||||
XPCJSContext::DispatchDeferredDeletion(bool aContinuation, bool aPurge)
|
||||
{
|
||||
mAsyncSnowWhiteFreer->Dispatch(aContinuation, aPurge);
|
||||
}
|
||||
|
@ -698,17 +698,17 @@ XPCJSRuntime::DispatchDeferredDeletion(bool aContinuation, bool aPurge)
|
|||
void
|
||||
xpc_UnmarkSkippableJSHolders()
|
||||
{
|
||||
if (nsXPConnect::XPConnect()->GetRuntime()) {
|
||||
nsXPConnect::XPConnect()->GetRuntime()->UnmarkSkippableJSHolders();
|
||||
if (nsXPConnect::XPConnect()->GetContext()) {
|
||||
nsXPConnect::XPConnect()->GetContext()->UnmarkSkippableJSHolders();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
XPCJSRuntime::GCSliceCallback(JSContext* cx,
|
||||
XPCJSContext::GCSliceCallback(JSContext* cx,
|
||||
JS::GCProgress progress,
|
||||
const JS::GCDescription& desc)
|
||||
{
|
||||
XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
|
||||
XPCJSContext* self = nsXPConnect::GetContextInstance();
|
||||
if (!self)
|
||||
return;
|
||||
|
||||
|
@ -722,14 +722,14 @@ XPCJSRuntime::GCSliceCallback(JSContext* cx,
|
|||
}
|
||||
|
||||
/* static */ void
|
||||
XPCJSRuntime::DoCycleCollectionCallback(JSContext* cx)
|
||||
XPCJSContext::DoCycleCollectionCallback(JSContext* cx)
|
||||
{
|
||||
// The GC has detected that a CC at this point would collect a tremendous
|
||||
// amount of garbage that is being revivified unnecessarily.
|
||||
NS_DispatchToCurrentThread(
|
||||
NS_NewRunnableFunction([](){nsJSContext::CycleCollectNow(nullptr);}));
|
||||
|
||||
XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
|
||||
XPCJSContext* self = nsXPConnect::GetContextInstance();
|
||||
if (!self)
|
||||
return;
|
||||
|
||||
|
@ -738,7 +738,7 @@ XPCJSRuntime::DoCycleCollectionCallback(JSContext* cx)
|
|||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::CustomGCCallback(JSGCStatus status)
|
||||
XPCJSContext::CustomGCCallback(JSGCStatus status)
|
||||
{
|
||||
nsTArray<xpcGCCallback> callbacks(extraGCCallbacks);
|
||||
for (uint32_t i = 0; i < callbacks.Length(); ++i)
|
||||
|
@ -746,12 +746,12 @@ XPCJSRuntime::CustomGCCallback(JSGCStatus status)
|
|||
}
|
||||
|
||||
/* static */ void
|
||||
XPCJSRuntime::FinalizeCallback(JSFreeOp* fop,
|
||||
XPCJSContext::FinalizeCallback(JSFreeOp* fop,
|
||||
JSFinalizeStatus status,
|
||||
bool isZoneGC,
|
||||
void* data)
|
||||
{
|
||||
XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
|
||||
XPCJSContext* self = nsXPConnect::GetContextInstance();
|
||||
if (!self)
|
||||
return;
|
||||
|
||||
|
@ -810,7 +810,7 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp* fop,
|
|||
if (AutoMarkingPtr* roots = Get()->mAutoRoots)
|
||||
roots->MarkAfterJSFinalizeAll();
|
||||
|
||||
XPCCallContext* ccxp = XPCJSRuntime::Get()->GetCallContext();
|
||||
XPCCallContext* ccxp = XPCJSContext::Get()->GetCallContext();
|
||||
while (ccxp) {
|
||||
// Deal with the strictness of callcontext that
|
||||
// complains if you ask for a set when
|
||||
|
@ -877,7 +877,7 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp* fop,
|
|||
if (!nsXPConnect::XPConnect()->IsShuttingDown()) {
|
||||
// Do the marking...
|
||||
|
||||
XPCCallContext* ccxp = XPCJSRuntime::Get()->GetCallContext();
|
||||
XPCCallContext* ccxp = XPCJSContext::Get()->GetCallContext();
|
||||
while (ccxp) {
|
||||
// Deal with the strictness of callcontext that
|
||||
// complains if you ask for a tearoff when
|
||||
|
@ -925,12 +925,12 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp* fop,
|
|||
}
|
||||
|
||||
/* static */ void
|
||||
XPCJSRuntime::WeakPointerZoneGroupCallback(JSContext* cx, void* data)
|
||||
XPCJSContext::WeakPointerZoneGroupCallback(JSContext* cx, void* data)
|
||||
{
|
||||
// Called before each sweeping slice -- after processing any final marking
|
||||
// triggered by barriers -- to clear out any references to things that are
|
||||
// about to be finalized and update any pointers to moved GC things.
|
||||
XPCJSRuntime* self = static_cast<XPCJSRuntime*>(data);
|
||||
XPCJSContext* self = static_cast<XPCJSContext*>(data);
|
||||
|
||||
self->mWrappedJSMap->UpdateWeakPointersAfterGC(self);
|
||||
|
||||
|
@ -938,20 +938,20 @@ XPCJSRuntime::WeakPointerZoneGroupCallback(JSContext* cx, void* data)
|
|||
}
|
||||
|
||||
/* static */ void
|
||||
XPCJSRuntime::WeakPointerCompartmentCallback(JSContext* cx, JSCompartment* comp, void* data)
|
||||
XPCJSContext::WeakPointerCompartmentCallback(JSContext* cx, JSCompartment* comp, void* data)
|
||||
{
|
||||
// Called immediately after the ZoneGroup weak pointer callback, but only
|
||||
// once for each compartment that is being swept.
|
||||
XPCJSRuntime* self = static_cast<XPCJSRuntime*>(data);
|
||||
XPCJSContext* self = static_cast<XPCJSContext*>(data);
|
||||
CompartmentPrivate* xpcComp = CompartmentPrivate::Get(comp);
|
||||
if (xpcComp)
|
||||
xpcComp->UpdateWeakPointersAfterGC(self);
|
||||
}
|
||||
|
||||
void
|
||||
CompartmentPrivate::UpdateWeakPointersAfterGC(XPCJSRuntime* runtime)
|
||||
CompartmentPrivate::UpdateWeakPointersAfterGC(XPCJSContext* context)
|
||||
{
|
||||
mWrappedJSMap->UpdateWeakPointersAfterGC(runtime);
|
||||
mWrappedJSMap->UpdateWeakPointersAfterGC(context);
|
||||
}
|
||||
|
||||
static void WatchdogMain(void* arg);
|
||||
|
@ -1104,12 +1104,12 @@ class WatchdogManager : public nsIObserver
|
|||
public:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
explicit WatchdogManager(XPCJSRuntime* aRuntime) : mRuntime(aRuntime)
|
||||
, mRuntimeState(RUNTIME_INACTIVE)
|
||||
explicit WatchdogManager(XPCJSContext* aContext) : mContext(aContext)
|
||||
, mContextState(CONTEXT_INACTIVE)
|
||||
{
|
||||
// All the timestamps start at zero except for runtime state change.
|
||||
// All the timestamps start at zero except for context state change.
|
||||
PodArrayZero(mTimestamps);
|
||||
mTimestamps[TimestampRuntimeStateChange] = PR_Now();
|
||||
mTimestamps[TimestampContextStateChange] = PR_Now();
|
||||
|
||||
// Enable the watchdog, if appropriate.
|
||||
RefreshWatchdog();
|
||||
|
@ -1142,11 +1142,11 @@ class WatchdogManager : public nsIObserver
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Runtime statistics. These live on the watchdog manager, are written
|
||||
// Context statistics. These live on the watchdog manager, are written
|
||||
// from the main thread, and are read from the watchdog thread (holding
|
||||
// the lock in each case).
|
||||
void
|
||||
RecordRuntimeActivity(bool active)
|
||||
RecordContextActivity(bool active)
|
||||
{
|
||||
// The watchdog reads this state, so acquire the lock before writing it.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
@ -1155,21 +1155,21 @@ class WatchdogManager : public nsIObserver
|
|||
lock.emplace(mWatchdog);
|
||||
|
||||
// Write state.
|
||||
mTimestamps[TimestampRuntimeStateChange] = PR_Now();
|
||||
mRuntimeState = active ? RUNTIME_ACTIVE : RUNTIME_INACTIVE;
|
||||
mTimestamps[TimestampContextStateChange] = PR_Now();
|
||||
mContextState = active ? CONTEXT_ACTIVE : CONTEXT_INACTIVE;
|
||||
|
||||
// The watchdog may be hibernating, waiting for the runtime to go
|
||||
// The watchdog may be hibernating, waiting for the context to go
|
||||
// active. Wake it up if necessary.
|
||||
if (active && mWatchdog && mWatchdog->Hibernating())
|
||||
mWatchdog->WakeUp();
|
||||
}
|
||||
bool IsRuntimeActive() { return mRuntimeState == RUNTIME_ACTIVE; }
|
||||
PRTime TimeSinceLastRuntimeStateChange()
|
||||
bool IsContextActive() { return mContextState == CONTEXT_ACTIVE; }
|
||||
PRTime TimeSinceLastContextStateChange()
|
||||
{
|
||||
return PR_Now() - GetTimestamp(TimestampRuntimeStateChange);
|
||||
return PR_Now() - GetTimestamp(TimestampContextStateChange);
|
||||
}
|
||||
|
||||
// Note - Because of the runtime activity timestamp, these are read and
|
||||
// Note - Because of the context activity timestamp, these are read and
|
||||
// written from both threads.
|
||||
void RecordTimestamp(WatchdogTimestampCategory aCategory)
|
||||
{
|
||||
|
@ -1188,7 +1188,7 @@ class WatchdogManager : public nsIObserver
|
|||
return mTimestamps[aCategory];
|
||||
}
|
||||
|
||||
XPCJSRuntime* Runtime() { return mRuntime; }
|
||||
XPCJSContext* Context() { return mContext; }
|
||||
Watchdog* GetWatchdog() { return mWatchdog; }
|
||||
|
||||
void RefreshWatchdog()
|
||||
|
@ -1227,10 +1227,10 @@ class WatchdogManager : public nsIObserver
|
|||
}
|
||||
|
||||
private:
|
||||
XPCJSRuntime* mRuntime;
|
||||
XPCJSContext* mContext;
|
||||
nsAutoPtr<Watchdog> mWatchdog;
|
||||
|
||||
enum { RUNTIME_ACTIVE, RUNTIME_INACTIVE } mRuntimeState;
|
||||
enum { CONTEXT_ACTIVE, CONTEXT_INACTIVE } mContextState;
|
||||
PRTime mTimestamps[TimestampCount];
|
||||
};
|
||||
|
||||
|
@ -1261,8 +1261,8 @@ WatchdogMain(void* arg)
|
|||
MOZ_ASSERT(!self->ShuttingDown());
|
||||
while (!self->ShuttingDown()) {
|
||||
// Sleep only 1 second if recently (or currently) active; otherwise, hibernate
|
||||
if (manager->IsRuntimeActive() ||
|
||||
manager->TimeSinceLastRuntimeStateChange() <= PRTime(2*PR_USEC_PER_SEC))
|
||||
if (manager->IsContextActive() ||
|
||||
manager->TimeSinceLastContextStateChange() <= PRTime(2*PR_USEC_PER_SEC))
|
||||
{
|
||||
self->Sleep(PR_TicksPerSecond());
|
||||
} else {
|
||||
|
@ -1289,15 +1289,15 @@ WatchdogMain(void* arg)
|
|||
// periods, the script still has the other (timeout/2) seconds to
|
||||
// finish.
|
||||
PRTime usecs = self->MinScriptRunTimeSeconds() * PR_USEC_PER_SEC / 2;
|
||||
if (manager->IsRuntimeActive() &&
|
||||
manager->TimeSinceLastRuntimeStateChange() >= usecs)
|
||||
if (manager->IsContextActive() &&
|
||||
manager->TimeSinceLastContextStateChange() >= usecs)
|
||||
{
|
||||
bool debuggerAttached = false;
|
||||
nsCOMPtr<nsIDebug2> dbg = do_GetService("@mozilla.org/xpcom/debug;1");
|
||||
if (dbg)
|
||||
dbg->GetIsDebuggerAttached(&debuggerAttached);
|
||||
if (!debuggerAttached)
|
||||
JS_RequestInterruptCallback(manager->Runtime()->Context());
|
||||
JS_RequestInterruptCallback(manager->Context()->Context());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1306,7 +1306,7 @@ WatchdogMain(void* arg)
|
|||
}
|
||||
|
||||
PRTime
|
||||
XPCJSRuntime::GetWatchdogTimestamp(WatchdogTimestampCategory aCategory)
|
||||
XPCJSContext::GetWatchdogTimestamp(WatchdogTimestampCategory aCategory)
|
||||
{
|
||||
return mWatchdogManager->GetTimestamp(aCategory);
|
||||
}
|
||||
|
@ -1314,26 +1314,26 @@ XPCJSRuntime::GetWatchdogTimestamp(WatchdogTimestampCategory aCategory)
|
|||
void
|
||||
xpc::SimulateActivityCallback(bool aActive)
|
||||
{
|
||||
XPCJSRuntime::ActivityCallback(XPCJSRuntime::Get(), aActive);
|
||||
XPCJSContext::ActivityCallback(XPCJSContext::Get(), aActive);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
XPCJSRuntime::ActivityCallback(void* arg, bool active)
|
||||
XPCJSContext::ActivityCallback(void* arg, bool active)
|
||||
{
|
||||
if (!active) {
|
||||
ProcessHangMonitor::ClearHang();
|
||||
}
|
||||
|
||||
XPCJSRuntime* self = static_cast<XPCJSRuntime*>(arg);
|
||||
self->mWatchdogManager->RecordRuntimeActivity(active);
|
||||
XPCJSContext* self = static_cast<XPCJSContext*>(arg);
|
||||
self->mWatchdogManager->RecordContextActivity(active);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
XPCJSRuntime::InterruptCallback(JSContext* cx)
|
||||
XPCJSContext::InterruptCallback(JSContext* cx)
|
||||
{
|
||||
XPCJSRuntime* self = XPCJSRuntime::Get();
|
||||
XPCJSContext* self = XPCJSContext::Get();
|
||||
|
||||
// Normally we record mSlowScriptCheckpoint when we start to process an
|
||||
// event. However, we can run JS outside of event handlers. This code takes
|
||||
|
@ -1438,7 +1438,7 @@ XPCJSRuntime::InterruptCallback(JSContext* cx)
|
|||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::CustomOutOfMemoryCallback()
|
||||
XPCJSContext::CustomOutOfMemoryCallback()
|
||||
{
|
||||
if (!Preferences::GetBool("memory.dump_reports_on_oom")) {
|
||||
return;
|
||||
|
@ -1457,7 +1457,7 @@ XPCJSRuntime::CustomOutOfMemoryCallback()
|
|||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::CustomLargeAllocationFailureCallback()
|
||||
XPCJSContext::CustomLargeAllocationFailureCallback()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (os) {
|
||||
|
@ -1466,7 +1466,7 @@ XPCJSRuntime::CustomLargeAllocationFailureCallback()
|
|||
}
|
||||
|
||||
size_t
|
||||
XPCJSRuntime::SizeOfIncludingThis(MallocSizeOf mallocSizeOf)
|
||||
XPCJSContext::SizeOfIncludingThis(MallocSizeOf mallocSizeOf)
|
||||
{
|
||||
size_t n = 0;
|
||||
n += mallocSizeOf(this);
|
||||
|
@ -1475,9 +1475,9 @@ XPCJSRuntime::SizeOfIncludingThis(MallocSizeOf mallocSizeOf)
|
|||
n += mClassInfo2NativeSetMap->ShallowSizeOfIncludingThis(mallocSizeOf);
|
||||
n += mNativeSetMap->SizeOfIncludingThis(mallocSizeOf);
|
||||
|
||||
n += CycleCollectedJSRuntime::SizeOfExcludingThis(mallocSizeOf);
|
||||
n += CycleCollectedJSContext::SizeOfExcludingThis(mallocSizeOf);
|
||||
|
||||
// There are other XPCJSRuntime members that could be measured; the above
|
||||
// There are other XPCJSContext members that could be measured; the above
|
||||
// ones have been seen by DMD to be worth measuring. More stuff may be
|
||||
// added later.
|
||||
|
||||
|
@ -1495,7 +1495,7 @@ CompartmentPrivate::SizeOfIncludingThis(MallocSizeOf mallocSizeOf)
|
|||
|
||||
/***************************************************************************/
|
||||
|
||||
void XPCJSRuntime::SystemIsBeingShutDown()
|
||||
void XPCJSContext::SystemIsBeingShutDown()
|
||||
{
|
||||
for (auto i = mDetachedWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
|
||||
auto entry = static_cast<XPCWrappedNativeProtoMap::Entry*>(i.Get());
|
||||
|
@ -1509,8 +1509,8 @@ void XPCJSRuntime::SystemIsBeingShutDown()
|
|||
static void
|
||||
ReloadPrefsCallback(const char* pref, void* data)
|
||||
{
|
||||
XPCJSRuntime* runtime = reinterpret_cast<XPCJSRuntime*>(data);
|
||||
JSContext* cx = runtime->Context();
|
||||
XPCJSContext* xpccx = reinterpret_cast<XPCJSContext*>(data);
|
||||
JSContext* cx = xpccx->Context();
|
||||
|
||||
bool safeMode = false;
|
||||
nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
|
||||
|
@ -1585,16 +1585,16 @@ ReloadPrefsCallback(const char* pref, void* data)
|
|||
useIonEager ? 0 : -1);
|
||||
}
|
||||
|
||||
XPCJSRuntime::~XPCJSRuntime()
|
||||
XPCJSContext::~XPCJSContext()
|
||||
{
|
||||
// Elsewhere we abort immediately if XPCJSRuntime initialization fails.
|
||||
// Elsewhere we abort immediately if XPCJSContext initialization fails.
|
||||
// Therefore the context must be non-null.
|
||||
MOZ_ASSERT(MaybeContext());
|
||||
|
||||
// This destructor runs before ~CycleCollectedJSRuntime, which does the
|
||||
// actual JS_DestroyRuntime() call. But destroying the runtime triggers
|
||||
// one final GC, which can call back into the runtime with various
|
||||
// callback if we aren't careful. Null out the relevant callbacks.
|
||||
// This destructor runs before ~CycleCollectedJSContext, which does the
|
||||
// actual JS_DestroyContext() call. But destroying the context triggers
|
||||
// one final GC, which can call back into the context with various
|
||||
// callbacks if we aren't careful. Null out the relevant callbacks.
|
||||
js::SetActivityCallback(Context(), nullptr, nullptr);
|
||||
JS_RemoveFinalizeCallback(Context(), FinalizeCallback);
|
||||
JS_RemoveWeakPointerZoneGroupCallback(Context(), WeakPointerZoneGroupCallback);
|
||||
|
@ -1648,7 +1648,7 @@ XPCJSRuntime::~XPCJSRuntime()
|
|||
mDetachedWrappedNativeProtoMap = nullptr;
|
||||
|
||||
#ifdef MOZ_ENABLE_PROFILER_SPS
|
||||
// Tell the profiler that the runtime is gone
|
||||
// Tell the profiler that the context is gone
|
||||
if (PseudoStack* stack = mozilla_get_pseudo_stack())
|
||||
stack->sampleContext(nullptr);
|
||||
#endif
|
||||
|
@ -1756,13 +1756,13 @@ xpc::GetCurrentCompartmentName(JSContext* cx, nsCString& name)
|
|||
void
|
||||
xpc::AddGCCallback(xpcGCCallback cb)
|
||||
{
|
||||
XPCJSRuntime::Get()->AddGCCallback(cb);
|
||||
XPCJSContext::Get()->AddGCCallback(cb);
|
||||
}
|
||||
|
||||
void
|
||||
xpc::RemoveGCCallback(xpcGCCallback cb)
|
||||
{
|
||||
XPCJSRuntime::Get()->RemoveGCCallback(cb);
|
||||
XPCJSContext::Get()->RemoveGCCallback(cb);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
|
@ -1790,7 +1790,7 @@ JSMainRuntimeCompartmentsSystemDistinguishedAmount()
|
|||
static int64_t
|
||||
JSMainRuntimeCompartmentsUserDistinguishedAmount()
|
||||
{
|
||||
JSContext* cx = nsXPConnect::GetRuntimeInstance()->Context();
|
||||
JSContext* cx = nsXPConnect::GetContextInstance()->Context();
|
||||
return JS::UserCompartmentCount(cx);
|
||||
}
|
||||
|
||||
|
@ -2645,7 +2645,7 @@ class JSMainRuntimeCompartmentsReporter final : public nsIMemoryReporter
|
|||
|
||||
Data d;
|
||||
d.anonymizeID = anonymize ? 1 : 0;
|
||||
JS_IterateCompartments(nsXPConnect::GetRuntimeInstance()->Context(),
|
||||
JS_IterateCompartments(nsXPConnect::GetContextInstance()->Context(),
|
||||
&d, CompartmentCallback);
|
||||
|
||||
for (size_t i = 0; i < d.paths.length(); i++)
|
||||
|
@ -2718,7 +2718,7 @@ StartsWithExplicit(nsACString& s)
|
|||
}
|
||||
#endif
|
||||
|
||||
class XPCJSRuntimeStats : public JS::RuntimeStats
|
||||
class XPCJSContextStats : public JS::RuntimeStats
|
||||
{
|
||||
WindowPaths* mWindowPaths;
|
||||
WindowPaths* mTopWindowPaths;
|
||||
|
@ -2726,7 +2726,7 @@ class XPCJSRuntimeStats : public JS::RuntimeStats
|
|||
int mAnonymizeID;
|
||||
|
||||
public:
|
||||
XPCJSRuntimeStats(WindowPaths* windowPaths, WindowPaths* topWindowPaths,
|
||||
XPCJSContextStats(WindowPaths* windowPaths, WindowPaths* topWindowPaths,
|
||||
bool getLocations, bool anonymize)
|
||||
: JS::RuntimeStats(JSMallocSizeOf),
|
||||
mWindowPaths(windowPaths),
|
||||
|
@ -2735,7 +2735,7 @@ class XPCJSRuntimeStats : public JS::RuntimeStats
|
|||
mAnonymizeID(anonymize ? 1 : 0)
|
||||
{}
|
||||
|
||||
~XPCJSRuntimeStats() {
|
||||
~XPCJSContextStats() {
|
||||
for (size_t i = 0; i != compartmentStatsVector.length(); ++i)
|
||||
delete static_cast<xpc::CompartmentStatsExtras*>(compartmentStatsVector[i].extra);
|
||||
|
||||
|
@ -2853,7 +2853,7 @@ JSReporter::CollectReports(WindowPaths* windowPaths,
|
|||
nsISupports* data,
|
||||
bool anonymize)
|
||||
{
|
||||
XPCJSRuntime* xpcrt = nsXPConnect::GetRuntimeInstance();
|
||||
XPCJSContext* xpccx = nsXPConnect::GetContextInstance();
|
||||
|
||||
// In the first step we get all the stats and stash them in a local
|
||||
// data structure. In the second step we pass all the stashed stats to
|
||||
|
@ -2867,18 +2867,18 @@ JSReporter::CollectReports(WindowPaths* windowPaths,
|
|||
addonManager = do_GetService("@mozilla.org/addons/integration;1");
|
||||
}
|
||||
bool getLocations = !!addonManager;
|
||||
XPCJSRuntimeStats rtStats(windowPaths, topWindowPaths, getLocations,
|
||||
XPCJSContextStats rtStats(windowPaths, topWindowPaths, getLocations,
|
||||
anonymize);
|
||||
OrphanReporter orphanReporter(XPCConvert::GetISupportsFromJSObject);
|
||||
if (!JS::CollectRuntimeStats(xpcrt->Context(), &rtStats, &orphanReporter,
|
||||
if (!JS::CollectRuntimeStats(xpccx->Context(), &rtStats, &orphanReporter,
|
||||
anonymize))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
size_t xpcJSRuntimeSize = xpcrt->SizeOfIncludingThis(JSMallocSizeOf);
|
||||
size_t xpcJSRuntimeSize = xpccx->SizeOfIncludingThis(JSMallocSizeOf);
|
||||
|
||||
size_t wrappedJSSize = xpcrt->GetMultiCompartmentWrappedJSMap()->SizeOfWrappedJS(JSMallocSizeOf);
|
||||
size_t wrappedJSSize = xpccx->GetMultiCompartmentWrappedJSMap()->SizeOfWrappedJS(JSMallocSizeOf);
|
||||
|
||||
XPCWrappedNativeScope::ScopeSizeInfo sizeInfo(JSMallocSizeOf);
|
||||
XPCWrappedNativeScope::AddSizeOfAllScopesIncludingThis(&sizeInfo);
|
||||
|
@ -3056,7 +3056,7 @@ static nsresult
|
|||
JSSizeOfTab(JSObject* objArg, size_t* jsObjectsSize, size_t* jsStringsSize,
|
||||
size_t* jsPrivateSize, size_t* jsOtherSize)
|
||||
{
|
||||
JSContext* cx = nsXPConnect::GetRuntimeInstance()->Context();
|
||||
JSContext* cx = nsXPConnect::GetContextInstance()->Context();
|
||||
JS::RootedObject obj(cx, objArg);
|
||||
|
||||
TabSizes sizes;
|
||||
|
@ -3277,7 +3277,7 @@ ReadSourceFromFilename(JSContext* cx, const char* filename, char16_t** src, size
|
|||
}
|
||||
|
||||
// The JS engine calls this object's 'load' member function when it needs
|
||||
// the source for a chrome JS function. See the comment in the XPCJSRuntime
|
||||
// the source for a chrome JS function. See the comment in the XPCJSContext
|
||||
// constructor.
|
||||
class XPCJSSourceHook: public js::SourceHook {
|
||||
bool load(JSContext* cx, const char* filename, char16_t** src, size_t* length) {
|
||||
|
@ -3305,7 +3305,7 @@ static const JSWrapObjectCallbacks WrapObjectCallbacks = {
|
|||
xpc::WrapperFactory::PrepareForWrapping
|
||||
};
|
||||
|
||||
XPCJSRuntime::XPCJSRuntime()
|
||||
XPCJSContext::XPCJSContext()
|
||||
: mCallContext(nullptr),
|
||||
mAutoRoots(nullptr),
|
||||
mResolveName(JSID_VOID),
|
||||
|
@ -3369,9 +3369,9 @@ GetWindowsStackSize()
|
|||
#endif
|
||||
|
||||
nsresult
|
||||
XPCJSRuntime::Initialize()
|
||||
XPCJSContext::Initialize()
|
||||
{
|
||||
nsresult rv = CycleCollectedJSRuntime::Initialize(nullptr,
|
||||
nsresult rv = CycleCollectedJSContext::Initialize(nullptr,
|
||||
JS::DefaultHeapMaxBytes,
|
||||
JS::DefaultNurseryBytes);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -3539,13 +3539,13 @@ XPCJSRuntime::Initialize()
|
|||
}
|
||||
|
||||
// static
|
||||
XPCJSRuntime*
|
||||
XPCJSRuntime::newXPCJSRuntime()
|
||||
XPCJSContext*
|
||||
XPCJSContext::newXPCJSContext()
|
||||
{
|
||||
XPCJSRuntime* self = new XPCJSRuntime();
|
||||
XPCJSContext* self = new XPCJSContext();
|
||||
nsresult rv = self->Initialize();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RUNTIMEABORT("new XPCJSRuntime failed to initialize.");
|
||||
NS_RUNTIMEABORT("new XPCJSContext failed to initialize.");
|
||||
delete self;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -3563,14 +3563,14 @@ XPCJSRuntime::newXPCJSRuntime()
|
|||
return self;
|
||||
}
|
||||
|
||||
NS_RUNTIMEABORT("new XPCJSRuntime failed to initialize.");
|
||||
NS_RUNTIMEABORT("new XPCJSContext failed to initialize.");
|
||||
|
||||
delete self;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
XPCJSRuntime::JSContextInitialized(JSContext* cx)
|
||||
XPCJSContext::JSContextInitialized(JSContext* cx)
|
||||
{
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
|
@ -3596,7 +3596,7 @@ XPCJSRuntime::JSContextInitialized(JSContext* cx)
|
|||
}
|
||||
|
||||
bool
|
||||
XPCJSRuntime::DescribeCustomObjects(JSObject* obj, const js::Class* clasp,
|
||||
XPCJSContext::DescribeCustomObjects(JSObject* obj, const js::Class* clasp,
|
||||
char (&name)[72]) const
|
||||
{
|
||||
XPCNativeScriptableInfo* si = nullptr;
|
||||
|
@ -3618,7 +3618,7 @@ XPCJSRuntime::DescribeCustomObjects(JSObject* obj, const js::Class* clasp,
|
|||
}
|
||||
|
||||
bool
|
||||
XPCJSRuntime::NoteCustomGCThingXPCOMChildren(const js::Class* clasp, JSObject* obj,
|
||||
XPCJSContext::NoteCustomGCThingXPCOMChildren(const js::Class* clasp, JSObject* obj,
|
||||
nsCycleCollectionTraversalCallback& cb) const
|
||||
{
|
||||
if (clasp != &XPC_WN_Tearoff_JSClass) {
|
||||
|
@ -3636,7 +3636,7 @@ XPCJSRuntime::NoteCustomGCThingXPCOMChildren(const js::Class* clasp, JSObject* o
|
|||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::BeforeProcessTask(bool aMightBlock)
|
||||
XPCJSContext::BeforeProcessTask(bool aMightBlock)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -3665,11 +3665,11 @@ XPCJSRuntime::BeforeProcessTask(bool aMightBlock)
|
|||
// cancel any ongoing performance measurement.
|
||||
js::ResetPerformanceMonitoring(Get()->Context());
|
||||
|
||||
CycleCollectedJSRuntime::BeforeProcessTask(aMightBlock);
|
||||
CycleCollectedJSContext::BeforeProcessTask(aMightBlock);
|
||||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::AfterProcessTask(uint32_t aNewRecursionDepth)
|
||||
XPCJSContext::AfterProcessTask(uint32_t aNewRecursionDepth)
|
||||
{
|
||||
// Now that we're back to the event loop, reset the slow script checkpoint.
|
||||
mSlowScriptCheckpoint = mozilla::TimeStamp();
|
||||
|
@ -3679,7 +3679,7 @@ XPCJSRuntime::AfterProcessTask(uint32_t aNewRecursionDepth)
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsJSContext::MaybePokeCC();
|
||||
|
||||
CycleCollectedJSRuntime::AfterProcessTask(aNewRecursionDepth);
|
||||
CycleCollectedJSContext::AfterProcessTask(aNewRecursionDepth);
|
||||
|
||||
// Now that we are certain that the event is complete,
|
||||
// we can flush any ongoing performance measurement.
|
||||
|
@ -3689,11 +3689,11 @@ XPCJSRuntime::AfterProcessTask(uint32_t aNewRecursionDepth)
|
|||
/***************************************************************************/
|
||||
|
||||
void
|
||||
XPCJSRuntime::DebugDump(int16_t depth)
|
||||
XPCJSContext::DebugDump(int16_t depth)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
depth--;
|
||||
XPC_LOG_ALWAYS(("XPCJSRuntime @ %x", this));
|
||||
XPC_LOG_ALWAYS(("XPCJSContext @ %x", this));
|
||||
XPC_LOG_INDENT();
|
||||
XPC_LOG_ALWAYS(("mJSContext @ %x", Context()));
|
||||
|
||||
|
@ -3768,7 +3768,7 @@ void
|
|||
XPCRootSetElem::RemoveFromRootSet()
|
||||
{
|
||||
nsXPConnect* xpc = nsXPConnect::XPConnect();
|
||||
JS::PokeGC(xpc->GetRuntime()->Context());
|
||||
JS::PokeGC(xpc->GetContext()->Context());
|
||||
|
||||
MOZ_ASSERT(mSelfp, "Must be linked");
|
||||
|
||||
|
@ -3783,14 +3783,14 @@ XPCRootSetElem::RemoveFromRootSet()
|
|||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::AddGCCallback(xpcGCCallback cb)
|
||||
XPCJSContext::AddGCCallback(xpcGCCallback cb)
|
||||
{
|
||||
MOZ_ASSERT(cb, "null callback");
|
||||
extraGCCallbacks.AppendElement(cb);
|
||||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::RemoveGCCallback(xpcGCCallback cb)
|
||||
XPCJSContext::RemoveGCCallback(xpcGCCallback cb)
|
||||
{
|
||||
MOZ_ASSERT(cb, "null callback");
|
||||
bool found = extraGCCallbacks.RemoveElement(cb);
|
||||
|
@ -3800,7 +3800,7 @@ XPCJSRuntime::RemoveGCCallback(xpcGCCallback cb)
|
|||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::InitSingletonScopes()
|
||||
XPCJSContext::InitSingletonScopes()
|
||||
{
|
||||
// This all happens very early, so we don't bother with cx pushing.
|
||||
JSContext* cx = Context();
|
||||
|
@ -3836,7 +3836,7 @@ XPCJSRuntime::InitSingletonScopes()
|
|||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::DeleteSingletonScopes()
|
||||
XPCJSContext::DeleteSingletonScopes()
|
||||
{
|
||||
mUnprivilegedJunkScope = nullptr;
|
||||
mPrivilegedJunkScope = nullptr;
|
|
@ -710,12 +710,12 @@ nsJSCID::Construct(nsIXPConnectWrappedNative* wrapper,
|
|||
const CallArgs& args, bool* _retval)
|
||||
{
|
||||
RootedObject obj(cx, objArg);
|
||||
XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
|
||||
if (!rt)
|
||||
XPCJSContext* xpccx = nsXPConnect::GetContextInstance();
|
||||
if (!xpccx)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// 'push' a call context and call on it
|
||||
RootedId name(cx, rt->GetStringID(XPCJSRuntime::IDX_CREATE_INSTANCE));
|
||||
RootedId name(cx, xpccx->GetStringID(XPCJSContext::IDX_CREATE_INSTANCE));
|
||||
XPCCallContext ccx(cx, obj, nullptr, name, args.length(), args.array(),
|
||||
args.rval().address());
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ HashNativeKey(const void* data)
|
|||
// implement JSObject2WrappedJSMap...
|
||||
|
||||
void
|
||||
JSObject2WrappedJSMap::UpdateWeakPointersAfterGC(XPCJSRuntime* runtime)
|
||||
JSObject2WrappedJSMap::UpdateWeakPointersAfterGC(XPCJSContext* context)
|
||||
{
|
||||
// Check all wrappers and update their JSObject pointer if it has been
|
||||
// moved. Release any wrappers whose weakly held JSObject has died.
|
||||
|
|
|
@ -83,7 +83,7 @@ public:
|
|||
r.front().value()->DebugDump(depth);
|
||||
}
|
||||
|
||||
void UpdateWeakPointersAfterGC(XPCJSRuntime* runtime);
|
||||
void UpdateWeakPointersAfterGC(XPCJSContext* context);
|
||||
|
||||
void ShutdownMarker();
|
||||
|
||||
|
@ -314,7 +314,7 @@ public:
|
|||
|
||||
// ClassInfo2NativeSetMap holds pointers to *some* XPCNativeSets.
|
||||
// So we don't want to count those XPCNativeSets, because they are better
|
||||
// counted elsewhere (i.e. in XPCJSRuntime::mNativeSetMap, which holds
|
||||
// counted elsewhere (i.e. in XPCJSContext::mNativeSetMap, which holds
|
||||
// pointers to *all* XPCNativeSets). Hence the "Shallow".
|
||||
size_t ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
|
||||
|
||||
|
|
|
@ -50,10 +50,10 @@ Throw(JSContext* cx, nsresult rv)
|
|||
bool
|
||||
XPCThrower::CheckForPendingException(nsresult result, JSContext* cx)
|
||||
{
|
||||
nsCOMPtr<nsIException> e = XPCJSRuntime::Get()->GetPendingException();
|
||||
nsCOMPtr<nsIException> e = XPCJSContext::Get()->GetPendingException();
|
||||
if (!e)
|
||||
return false;
|
||||
XPCJSRuntime::Get()->SetPendingException(nullptr);
|
||||
XPCJSContext::Get()->SetPendingException(nullptr);
|
||||
|
||||
nsresult e_result;
|
||||
if (NS_FAILED(e->GetResult(&e_result)) || e_result != result)
|
||||
|
|
|
@ -41,7 +41,7 @@ using namespace mozilla;
|
|||
// now owned exclusively by its JS object. Either a weak reference will be turned into
|
||||
// a strong ref which will bring its refcount up to 2 and change the wrapper back to
|
||||
// the rooting state, or it will stay alive until the JS object dies. If the JS object
|
||||
// dies, then when XPCJSRuntime::FinalizeCallback calls FindDyingJSObjects
|
||||
// dies, then when XPCJSContext::FinalizeCallback calls FindDyingJSObjects
|
||||
// it will find the wrapper and call Release() in it, destroying the wrapper.
|
||||
// Otherwise, the wrapper will stay alive, even if it no longer has a weak reference
|
||||
// to it.
|
||||
|
@ -143,7 +143,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXPCWrappedJS)
|
|||
tmp->Unlink();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
// XPCJSRuntime keeps a table of WJS, so we can remove them from
|
||||
// XPCJSContext keeps a table of WJS, so we can remove them from
|
||||
// the purple buffer in between CCs.
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsXPCWrappedJS)
|
||||
return true;
|
||||
|
@ -249,7 +249,7 @@ nsXPCWrappedJS::AddRef(void)
|
|||
|
||||
if (2 == cnt && IsValid()) {
|
||||
GetJSObject(); // Unmark gray JSObject.
|
||||
mClass->GetRuntime()->AddWrappedJSRoot(this);
|
||||
mClass->GetContext()->AddWrappedJSRoot(this);
|
||||
}
|
||||
|
||||
return cnt;
|
||||
|
@ -350,10 +350,10 @@ nsXPCWrappedJS::GetNewOrUsed(JS::HandleObject jsObj,
|
|||
|
||||
// Find any existing wrapper.
|
||||
RefPtr<nsXPCWrappedJS> root = rootComp->GetWrappedJSMap()->Find(rootJSObj);
|
||||
MOZ_ASSERT_IF(root, !nsXPConnect::GetRuntimeInstance()->GetMultiCompartmentWrappedJSMap()->
|
||||
MOZ_ASSERT_IF(root, !nsXPConnect::GetContextInstance()->GetMultiCompartmentWrappedJSMap()->
|
||||
Find(rootJSObj));
|
||||
if (!root) {
|
||||
root = nsXPConnect::GetRuntimeInstance()->GetMultiCompartmentWrappedJSMap()->
|
||||
root = nsXPConnect::GetContextInstance()->GetMultiCompartmentWrappedJSMap()->
|
||||
Find(rootJSObj);
|
||||
}
|
||||
|
||||
|
@ -417,10 +417,10 @@ nsXPCWrappedJS::nsXPCWrappedJS(JSContext* cx,
|
|||
|
||||
// We always start wrappers in the per-compartment table. If adding
|
||||
// this wrapper to the chain causes it to cross compartments, we need
|
||||
// to migrate the chain to the global table on the XPCJSRuntime.
|
||||
// to migrate the chain to the global table on the XPCJSContext.
|
||||
if (mRoot->IsMultiCompartment()) {
|
||||
xpc::CompartmentPrivate::Get(mRoot->mJSObj)->GetWrappedJSMap()->Remove(mRoot);
|
||||
MOZ_RELEASE_ASSERT(nsXPConnect::GetRuntimeInstance()->
|
||||
MOZ_RELEASE_ASSERT(nsXPConnect::GetContextInstance()->
|
||||
GetMultiCompartmentWrappedJSMap()->Add(cx, mRoot));
|
||||
}
|
||||
}
|
||||
|
@ -432,7 +432,7 @@ nsXPCWrappedJS::~nsXPCWrappedJS()
|
|||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::RemoveWrappedJS(nsXPCWrappedJS* wrapper)
|
||||
XPCJSContext::RemoveWrappedJS(nsXPCWrappedJS* wrapper)
|
||||
{
|
||||
AssertInvalidWrappedJSNotInTable(wrapper);
|
||||
if (!wrapper->IsValid())
|
||||
|
@ -465,7 +465,7 @@ NotHasWrapperAssertionCallback(JSContext* cx, void* data, JSCompartment* comp)
|
|||
#endif
|
||||
|
||||
void
|
||||
XPCJSRuntime::AssertInvalidWrappedJSNotInTable(nsXPCWrappedJS* wrapper) const
|
||||
XPCJSContext::AssertInvalidWrappedJSNotInTable(nsXPCWrappedJS* wrapper) const
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (!wrapper->IsValid()) {
|
||||
|
@ -482,20 +482,20 @@ nsXPCWrappedJS::Destroy()
|
|||
MOZ_ASSERT(1 == int32_t(mRefCnt), "should be stabilized for deletion");
|
||||
|
||||
if (IsRootWrapper())
|
||||
nsXPConnect::GetRuntimeInstance()->RemoveWrappedJS(this);
|
||||
nsXPConnect::GetContextInstance()->RemoveWrappedJS(this);
|
||||
Unlink();
|
||||
}
|
||||
|
||||
void
|
||||
nsXPCWrappedJS::Unlink()
|
||||
{
|
||||
nsXPConnect::GetRuntimeInstance()->AssertInvalidWrappedJSNotInTable(this);
|
||||
nsXPConnect::GetContextInstance()->AssertInvalidWrappedJSNotInTable(this);
|
||||
|
||||
if (IsValid()) {
|
||||
XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
|
||||
if (rt) {
|
||||
XPCJSContext* cx = nsXPConnect::GetContextInstance();
|
||||
if (cx) {
|
||||
if (IsRootWrapper())
|
||||
rt->RemoveWrappedJS(this);
|
||||
cx->RemoveWrappedJS(this);
|
||||
|
||||
if (mRefCnt > 1)
|
||||
RemoveFromRootSet();
|
||||
|
@ -530,8 +530,8 @@ nsXPCWrappedJS::Unlink()
|
|||
|
||||
mClass = nullptr;
|
||||
if (mOuter) {
|
||||
XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
|
||||
if (rt->GCIsRunning()) {
|
||||
XPCJSContext* cx = nsXPConnect::GetContextInstance();
|
||||
if (cx->GCIsRunning()) {
|
||||
DeferredFinalize(mOuter.forget().take());
|
||||
} else {
|
||||
mOuter = nullptr;
|
||||
|
|
|
@ -82,22 +82,22 @@ bool xpc_IsReportableErrorCode(nsresult code)
|
|||
}
|
||||
}
|
||||
|
||||
// A little stack-based RAII class to help management of the XPCJSRuntime
|
||||
// A little stack-based RAII class to help management of the XPCJSContext
|
||||
// PendingResult.
|
||||
class MOZ_STACK_CLASS AutoSavePendingResult {
|
||||
public:
|
||||
explicit AutoSavePendingResult(XPCJSRuntime* xpcrt) :
|
||||
mXPCRuntime(xpcrt)
|
||||
explicit AutoSavePendingResult(XPCJSContext* xpccx) :
|
||||
mXPCContext(xpccx)
|
||||
{
|
||||
// Save any existing pending result and reset to NS_OK for this invocation.
|
||||
mSavedResult = xpcrt->GetPendingResult();
|
||||
xpcrt->SetPendingResult(NS_OK);
|
||||
mSavedResult = xpccx->GetPendingResult();
|
||||
xpccx->SetPendingResult(NS_OK);
|
||||
}
|
||||
~AutoSavePendingResult() {
|
||||
mXPCRuntime->SetPendingResult(mSavedResult);
|
||||
mXPCContext->SetPendingResult(mSavedResult);
|
||||
}
|
||||
private:
|
||||
XPCJSRuntime* mXPCRuntime;
|
||||
XPCJSContext* mXPCContext;
|
||||
nsresult mSavedResult;
|
||||
};
|
||||
|
||||
|
@ -105,8 +105,8 @@ private:
|
|||
already_AddRefed<nsXPCWrappedJSClass>
|
||||
nsXPCWrappedJSClass::GetNewOrUsed(JSContext* cx, REFNSIID aIID, bool allowNonScriptable)
|
||||
{
|
||||
XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
|
||||
IID2WrappedJSClassMap* map = rt->GetWrappedJSClassMap();
|
||||
XPCJSContext* xpccx = nsXPConnect::GetContextInstance();
|
||||
IID2WrappedJSClassMap* map = xpccx->GetWrappedJSClassMap();
|
||||
RefPtr<nsXPCWrappedJSClass> clasp = map->Find(aIID);
|
||||
|
||||
if (!clasp) {
|
||||
|
@ -129,13 +129,13 @@ nsXPCWrappedJSClass::GetNewOrUsed(JSContext* cx, REFNSIID aIID, bool allowNonScr
|
|||
|
||||
nsXPCWrappedJSClass::nsXPCWrappedJSClass(JSContext* cx, REFNSIID aIID,
|
||||
nsIInterfaceInfo* aInfo)
|
||||
: mRuntime(nsXPConnect::GetRuntimeInstance()),
|
||||
: mContext(nsXPConnect::GetContextInstance()),
|
||||
mInfo(aInfo),
|
||||
mName(nullptr),
|
||||
mIID(aIID),
|
||||
mDescriptors(nullptr)
|
||||
{
|
||||
mRuntime->GetWrappedJSClassMap()->Add(this);
|
||||
mContext->GetWrappedJSClassMap()->Add(this);
|
||||
|
||||
uint16_t methodCount;
|
||||
if (NS_SUCCEEDED(mInfo->GetMethodCount(&methodCount))) {
|
||||
|
@ -168,8 +168,8 @@ nsXPCWrappedJSClass::~nsXPCWrappedJSClass()
|
|||
{
|
||||
if (mDescriptors && mDescriptors != &zero_methods_descriptor)
|
||||
delete [] mDescriptors;
|
||||
if (mRuntime)
|
||||
mRuntime->GetWrappedJSClassMap()->Remove(this);
|
||||
if (mContext)
|
||||
mContext->GetWrappedJSClassMap()->Remove(this);
|
||||
|
||||
if (mName)
|
||||
free(mName);
|
||||
|
@ -209,7 +209,7 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(JSContext* cx,
|
|||
return nullptr;
|
||||
|
||||
// check upfront for the existence of the function property
|
||||
HandleId funid = mRuntime->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE);
|
||||
HandleId funid = mContext->GetStringID(XPCJSContext::IDX_QUERY_INTERFACE);
|
||||
if (!JS_GetPropertyById(cx, jsobj, funid, &fun) || fun.isPrimitive())
|
||||
return nullptr;
|
||||
|
||||
|
@ -778,11 +778,11 @@ nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
|
|||
nsCOMPtr<nsIException> xpc_exception = aSyntheticException;
|
||||
/* this one would be set by our error reporter */
|
||||
|
||||
XPCJSRuntime* xpcrt = XPCJSRuntime::Get();
|
||||
XPCJSContext* xpccx = XPCJSContext::Get();
|
||||
|
||||
// Get this right away in case we do something below to cause JS code
|
||||
// to run.
|
||||
nsresult pending_result = xpcrt->GetPendingResult();
|
||||
nsresult pending_result = xpccx->GetPendingResult();
|
||||
|
||||
RootedValue js_exception(cx);
|
||||
bool is_js_exception = JS_GetPendingException(cx, &js_exception);
|
||||
|
@ -796,7 +796,7 @@ nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
|
|||
|
||||
/* cleanup and set failed even if we can't build an exception */
|
||||
if (!xpc_exception) {
|
||||
xpcrt->SetPendingException(nullptr); // XXX necessary?
|
||||
xpccx->SetPendingException(nullptr); // XXX necessary?
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -915,7 +915,7 @@ nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
|
|||
// Whether or not it passes the 'reportable' test, it might
|
||||
// still be an error and we have to do the right thing here...
|
||||
if (NS_FAILED(e_result)) {
|
||||
xpcrt->SetPendingException(xpc_exception);
|
||||
xpccx->SetPendingException(xpc_exception);
|
||||
return e_result;
|
||||
}
|
||||
}
|
||||
|
@ -985,8 +985,8 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
|
|||
AutoValueVector args(cx);
|
||||
AutoScriptEvaluate scriptEval(cx);
|
||||
|
||||
XPCJSRuntime* xpcrt = XPCJSRuntime::Get();
|
||||
AutoSavePendingResult apr(xpcrt);
|
||||
XPCJSContext* xpccx = XPCJSContext::Get();
|
||||
AutoSavePendingResult apr(xpccx);
|
||||
|
||||
// XXX ASSUMES that retval is last arg. The xpidl compiler ensures this.
|
||||
uint8_t paramCount = info->num_args;
|
||||
|
@ -996,7 +996,7 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
|
|||
if (!scriptEval.StartEvaluating(obj))
|
||||
goto pre_call_clean_up;
|
||||
|
||||
xpcrt->SetPendingException(nullptr);
|
||||
xpccx->SetPendingException(nullptr);
|
||||
|
||||
// We use js_Invoke so that the gcthings we use as args will be rooted by
|
||||
// the engine as we do conversions and prepare to do the function call.
|
||||
|
@ -1042,7 +1042,7 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
|
|||
nsIXPCFunctionThisTranslator* translator;
|
||||
|
||||
IID2ThisTranslatorMap* map =
|
||||
mRuntime->GetThisTranslatorMap();
|
||||
mContext->GetThisTranslatorMap();
|
||||
|
||||
translator = map->Find(mIID);
|
||||
|
||||
|
@ -1173,7 +1173,7 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
|
|||
|
||||
if (param.IsIn()) {
|
||||
if (!JS_SetPropertyById(cx, out_obj,
|
||||
mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
|
||||
mContext->GetStringID(XPCJSContext::IDX_VALUE),
|
||||
val)) {
|
||||
goto pre_call_clean_up;
|
||||
}
|
||||
|
@ -1235,7 +1235,7 @@ pre_call_clean_up:
|
|||
return CheckForException(ccx, aes, name, GetInterfaceName(),
|
||||
syntheticException);
|
||||
|
||||
XPCJSRuntime::Get()->SetPendingException(nullptr); // XXX necessary?
|
||||
XPCJSContext::Get()->SetPendingException(nullptr); // XXX necessary?
|
||||
|
||||
// convert out args and result
|
||||
// NOTE: this is the total number of native params, not just the args
|
||||
|
@ -1273,7 +1273,7 @@ pre_call_clean_up:
|
|||
else {
|
||||
RootedObject obj(cx, &argv[i].toObject());
|
||||
if (!JS_GetPropertyById(cx, obj,
|
||||
mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
|
||||
mContext->GetStringID(XPCJSContext::IDX_VALUE),
|
||||
&val))
|
||||
break;
|
||||
}
|
||||
|
@ -1320,7 +1320,7 @@ pre_call_clean_up:
|
|||
else {
|
||||
RootedObject obj(cx, &argv[i].toObject());
|
||||
if (!JS_GetPropertyById(cx, obj,
|
||||
mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
|
||||
mContext->GetStringID(XPCJSContext::IDX_VALUE),
|
||||
&val))
|
||||
break;
|
||||
}
|
||||
|
@ -1373,7 +1373,7 @@ pre_call_clean_up:
|
|||
CleanupOutparams(cx, methodIndex, info, nativeParams, /* inOutOnly = */ false, i);
|
||||
} else {
|
||||
// set to whatever the JS code might have set as the result
|
||||
retval = xpcrt->GetPendingResult();
|
||||
retval = xpccx->GetPendingResult();
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
@ -1436,7 +1436,7 @@ nsXPCWrappedJSClass::DebugDump(int16_t depth)
|
|||
XPC_LOG_ALWAYS(("ConstantCount = %d", i));
|
||||
XPC_LOG_OUTDENT();
|
||||
}
|
||||
XPC_LOG_ALWAYS(("mRuntime @ %x", mRuntime));
|
||||
XPC_LOG_ALWAYS(("mContext @ %x", mContext));
|
||||
XPC_LOG_ALWAYS(("mDescriptors @ %x count = %d", mDescriptors, methodCount));
|
||||
if (depth && mDescriptors && methodCount) {
|
||||
depth--;
|
||||
|
|
|
@ -300,7 +300,7 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper,
|
|||
|
||||
nsresult rv;
|
||||
|
||||
MOZ_ASSERT(!Scope->GetRuntime()->GCIsRunning(),
|
||||
MOZ_ASSERT(!Scope->GetContext()->GCIsRunning(),
|
||||
"XPCWrappedNative::GetNewOrUsed called during GC");
|
||||
|
||||
nsISupports* identity = helper.GetCanonical();
|
||||
|
@ -608,8 +608,8 @@ XPCWrappedNative::Destroy()
|
|||
}
|
||||
|
||||
if (mIdentity) {
|
||||
XPCJSRuntime* rt = GetRuntime();
|
||||
if (rt && rt->GetDoingFinalization()) {
|
||||
XPCJSContext* cx = GetContext();
|
||||
if (cx && cx->GetDoingFinalization()) {
|
||||
DeferredFinalize(mIdentity.forget().take());
|
||||
} else {
|
||||
mIdentity = nullptr;
|
||||
|
@ -634,7 +634,7 @@ XPCWrappedNative::SetProto(XPCWrappedNativeProto* p)
|
|||
MOZ_ASSERT(HasProto());
|
||||
|
||||
// Write barrier for incremental GC.
|
||||
JSContext* cx = GetRuntime()->Context();
|
||||
JSContext* cx = GetContext()->Context();
|
||||
GetProto()->WriteBarrierPre(cx);
|
||||
|
||||
mMaybeProto = p;
|
||||
|
@ -903,7 +903,7 @@ XPCWrappedNative::FlatJSObjectFinalized()
|
|||
|
||||
// We also need to release any native pointers held...
|
||||
RefPtr<nsISupports> native = to->TakeNative();
|
||||
if (native && GetRuntime()) {
|
||||
if (native && GetContext()) {
|
||||
DeferredFinalize(native.forget().take());
|
||||
}
|
||||
|
||||
|
@ -1321,7 +1321,7 @@ public:
|
|||
, mMethodInfo(nullptr)
|
||||
, mCallee(ccx.GetTearOff()->GetNative())
|
||||
, mVTableIndex(ccx.GetMethodIndex())
|
||||
, mIdxValueId(ccx.GetRuntime()->GetStringID(XPCJSRuntime::IDX_VALUE))
|
||||
, mIdxValueId(ccx.GetContext()->GetStringID(XPCJSContext::IDX_VALUE))
|
||||
, mJSContextIndex(UINT8_MAX)
|
||||
, mOptArgcIndex(UINT8_MAX)
|
||||
, mArgv(ccx.GetArgv())
|
||||
|
@ -1356,7 +1356,7 @@ CallMethodHelper::Call()
|
|||
{
|
||||
mCallContext.SetRetVal(JS::UndefinedValue());
|
||||
|
||||
XPCJSRuntime::Get()->SetPendingException(nullptr);
|
||||
XPCJSContext::Get()->SetPendingException(nullptr);
|
||||
|
||||
if (mVTableIndex == 0) {
|
||||
return QueryInterfaceFastPath();
|
||||
|
@ -2010,11 +2010,11 @@ CallMethodHelper::CleanupParam(nsXPTCMiniVariant& param, nsXPTType& type)
|
|||
break;
|
||||
case nsXPTType::T_ASTRING:
|
||||
case nsXPTType::T_DOMSTRING:
|
||||
nsXPConnect::GetRuntimeInstance()->mScratchStrings.Destroy((nsString*)param.val.p);
|
||||
nsXPConnect::GetContextInstance()->mScratchStrings.Destroy((nsString*)param.val.p);
|
||||
break;
|
||||
case nsXPTType::T_UTF8STRING:
|
||||
case nsXPTType::T_CSTRING:
|
||||
nsXPConnect::GetRuntimeInstance()->mScratchCStrings.Destroy((nsCString*)param.val.p);
|
||||
nsXPConnect::GetContextInstance()->mScratchCStrings.Destroy((nsCString*)param.val.p);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(!type.IsArithmetic(), "Cleanup requested on unexpected type.");
|
||||
|
@ -2040,9 +2040,9 @@ CallMethodHelper::AllocateStringClass(nsXPTCVariant* dp,
|
|||
// ASTRING and DOMSTRING are very similar, and both use nsString.
|
||||
// UTF8_STRING and CSTRING are also quite similar, and both use nsCString.
|
||||
if (type_tag == nsXPTType::T_ASTRING || type_tag == nsXPTType::T_DOMSTRING)
|
||||
dp->val.p = nsXPConnect::GetRuntimeInstance()->mScratchStrings.Create();
|
||||
dp->val.p = nsXPConnect::GetContextInstance()->mScratchStrings.Create();
|
||||
else
|
||||
dp->val.p = nsXPConnect::GetRuntimeInstance()->mScratchCStrings.Create();
|
||||
dp->val.p = nsXPConnect::GetContextInstance()->mScratchCStrings.Create();
|
||||
|
||||
// Check for OOM, in either case.
|
||||
if (!dp->val.p) {
|
||||
|
@ -2317,7 +2317,7 @@ XPCJSObjectHolder::XPCJSObjectHolder(JSObject* obj)
|
|||
: mJSObj(obj)
|
||||
{
|
||||
MOZ_ASSERT(obj);
|
||||
XPCJSRuntime::Get()->AddObjectHolderRoot(this);
|
||||
XPCJSContext::Get()->AddObjectHolderRoot(this);
|
||||
}
|
||||
|
||||
XPCJSObjectHolder::~XPCJSObjectHolder()
|
||||
|
|
|
@ -109,7 +109,7 @@ XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface,
|
|||
|
||||
XPCNativeInterface::~XPCNativeInterface()
|
||||
{
|
||||
XPCJSRuntime::Get()->GetIID2NativeInterfaceMap()->Remove(this);
|
||||
XPCJSContext::Get()->GetIID2NativeInterfaceMap()->Remove(this);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -117,9 +117,9 @@ already_AddRefed<XPCNativeInterface>
|
|||
XPCNativeInterface::GetNewOrUsed(const nsIID* iid)
|
||||
{
|
||||
RefPtr<XPCNativeInterface> iface;
|
||||
XPCJSRuntime* rt = XPCJSRuntime::Get();
|
||||
XPCJSContext* cx = XPCJSContext::Get();
|
||||
|
||||
IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap();
|
||||
IID2NativeInterfaceMap* map = cx->GetIID2NativeInterfaceMap();
|
||||
if (!map)
|
||||
return nullptr;
|
||||
|
||||
|
@ -158,9 +158,9 @@ XPCNativeInterface::GetNewOrUsed(nsIInterfaceInfo* info)
|
|||
if (NS_FAILED(info->GetIIDShared(&iid)) || !iid)
|
||||
return nullptr;
|
||||
|
||||
XPCJSRuntime* rt = XPCJSRuntime::Get();
|
||||
XPCJSContext* cx = XPCJSContext::Get();
|
||||
|
||||
IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap();
|
||||
IID2NativeInterfaceMap* map = cx->GetIID2NativeInterfaceMap();
|
||||
if (!map)
|
||||
return nullptr;
|
||||
|
||||
|
@ -476,8 +476,8 @@ XPCNativeSet::GetNewOrUsed(const nsIID* iid)
|
|||
|
||||
XPCNativeSetKey key(iface);
|
||||
|
||||
XPCJSRuntime* rt = XPCJSRuntime::Get();
|
||||
NativeSetMap* map = rt->GetNativeSetMap();
|
||||
XPCJSContext* xpccx = XPCJSContext::Get();
|
||||
NativeSetMap* map = xpccx->GetNativeSetMap();
|
||||
if (!map)
|
||||
return nullptr;
|
||||
|
||||
|
@ -505,9 +505,9 @@ XPCNativeSet::GetNewOrUsed(nsIClassInfo* classInfo)
|
|||
{
|
||||
AutoJSContext cx;
|
||||
AutoMarkingNativeSetPtr set(cx);
|
||||
XPCJSRuntime* rt = XPCJSRuntime::Get();
|
||||
XPCJSContext* xpccx = XPCJSContext::Get();
|
||||
|
||||
ClassInfo2NativeSetMap* map = rt->GetClassInfo2NativeSetMap();
|
||||
ClassInfo2NativeSetMap* map = xpccx->GetClassInfo2NativeSetMap();
|
||||
if (!map)
|
||||
return nullptr;
|
||||
|
||||
|
@ -558,7 +558,7 @@ XPCNativeSet::GetNewOrUsed(nsIClassInfo* classInfo)
|
|||
if (interfaceArray.Length() > 0) {
|
||||
set = NewInstance(Move(interfaceArray));
|
||||
if (set) {
|
||||
NativeSetMap* map2 = rt->GetNativeSetMap();
|
||||
NativeSetMap* map2 = xpccx->GetNativeSetMap();
|
||||
if (!map2)
|
||||
goto out;
|
||||
|
||||
|
@ -603,8 +603,8 @@ out:
|
|||
void
|
||||
XPCNativeSet::ClearCacheEntryForClassInfo(nsIClassInfo* classInfo)
|
||||
{
|
||||
XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
|
||||
ClassInfo2NativeSetMap* map = rt->GetClassInfo2NativeSetMap();
|
||||
XPCJSContext* xpccx = nsXPConnect::GetContextInstance();
|
||||
ClassInfo2NativeSetMap* map = xpccx->GetClassInfo2NativeSetMap();
|
||||
if (map)
|
||||
map->Remove(classInfo);
|
||||
}
|
||||
|
@ -615,8 +615,8 @@ XPCNativeSet::GetNewOrUsed(XPCNativeSetKey* key)
|
|||
{
|
||||
AutoJSContext cx;
|
||||
AutoMarkingNativeSetPtr set(cx);
|
||||
XPCJSRuntime* rt = XPCJSRuntime::Get();
|
||||
NativeSetMap* map = rt->GetNativeSetMap();
|
||||
XPCJSContext* xpccx = XPCJSContext::Get();
|
||||
NativeSetMap* map = xpccx->GetNativeSetMap();
|
||||
if (!map)
|
||||
return nullptr;
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ XPC_WN_Shared_ToString(JSContext* cx, unsigned argc, Value* vp)
|
|||
XPCCallContext ccx(cx, obj);
|
||||
if (!ccx.IsValid())
|
||||
return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
|
||||
ccx.SetName(ccx.GetRuntime()->GetStringID(XPCJSRuntime::IDX_TO_STRING));
|
||||
ccx.SetName(ccx.GetContext()->GetStringID(XPCJSContext::IDX_TO_STRING));
|
||||
ccx.SetArgsAndResultPtr(args.length(), args.array(), vp);
|
||||
return ToStringGuts(ccx);
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ XPC_WN_Shared_toPrimitive(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
|
||||
MOZ_ASSERT(hint == JSTYPE_STRING || hint == JSTYPE_VOID);
|
||||
ccx.SetName(ccx.GetRuntime()->GetStringID(XPCJSRuntime::IDX_TO_STRING));
|
||||
ccx.SetName(ccx.GetContext()->GetStringID(XPCJSContext::IDX_TO_STRING));
|
||||
ccx.SetArgsAndResultPtr(0, nullptr, args.rval().address());
|
||||
|
||||
XPCNativeMember* member = ccx.GetMember();
|
||||
|
@ -155,8 +155,8 @@ GetDoubleWrappedJSObject(XPCCallContext& ccx, XPCWrappedNative* wrapper)
|
|||
if (underware) {
|
||||
RootedObject mainObj(ccx, underware->GetJSObject());
|
||||
if (mainObj) {
|
||||
RootedId id(ccx, ccx.GetRuntime()->
|
||||
GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT));
|
||||
RootedId id(ccx, ccx.GetContext()->
|
||||
GetStringID(XPCJSContext::IDX_WRAPPED_JSOBJECT));
|
||||
|
||||
JSAutoCompartment ac(ccx, mainObj);
|
||||
|
||||
|
@ -234,7 +234,7 @@ DefinePropertyIfFound(XPCCallContext& ccx,
|
|||
{
|
||||
RootedId id(ccx, idArg);
|
||||
RefPtr<XPCNativeInterface> iface = ifaceArg;
|
||||
XPCJSRuntime* rt = ccx.GetRuntime();
|
||||
XPCJSContext* xpccx = ccx.GetContext();
|
||||
bool found;
|
||||
const char* name;
|
||||
|
||||
|
@ -267,14 +267,14 @@ DefinePropertyIfFound(XPCCallContext& ccx,
|
|||
bool overwriteToString = !(flags & nsIClassInfo::DOM_OBJECT)
|
||||
|| Preferences::GetBool("dom.XPCToStringForDOMClasses", false);
|
||||
|
||||
if(id == rt->GetStringID(XPCJSRuntime::IDX_TO_STRING)
|
||||
if(id == xpccx->GetStringID(XPCJSContext::IDX_TO_STRING)
|
||||
&& overwriteToString)
|
||||
{
|
||||
call = XPC_WN_Shared_ToString;
|
||||
name = rt->GetStringName(XPCJSRuntime::IDX_TO_STRING);
|
||||
} else if (id == rt->GetStringID(XPCJSRuntime::IDX_TO_SOURCE)) {
|
||||
name = xpccx->GetStringName(XPCJSContext::IDX_TO_STRING);
|
||||
} else if (id == xpccx->GetStringID(XPCJSContext::IDX_TO_SOURCE)) {
|
||||
call = XPC_WN_Shared_ToSource;
|
||||
name = rt->GetStringName(XPCJSRuntime::IDX_TO_SOURCE);
|
||||
name = xpccx->GetStringName(XPCJSContext::IDX_TO_SOURCE);
|
||||
} else if (id == SYMBOL_TO_JSID(
|
||||
JS::GetWellKnownSymbol(ccx, JS::SymbolCode::toPrimitive)))
|
||||
{
|
||||
|
@ -331,15 +331,15 @@ DefinePropertyIfFound(XPCCallContext& ccx,
|
|||
|
||||
// This *might* be a double wrapped JSObject
|
||||
if (wrapperToReflectDoubleWrap &&
|
||||
id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT) &&
|
||||
id == xpccx->GetStringID(XPCJSContext::IDX_WRAPPED_JSOBJECT) &&
|
||||
GetDoubleWrappedJSObject(ccx, wrapperToReflectDoubleWrap)) {
|
||||
// We build and add a getter function.
|
||||
// A security check is done on a per-get basis.
|
||||
|
||||
JSFunction* fun;
|
||||
|
||||
id = rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT);
|
||||
name = rt->GetStringName(XPCJSRuntime::IDX_WRAPPED_JSOBJECT);
|
||||
id = xpccx->GetStringID(XPCJSContext::IDX_WRAPPED_JSOBJECT);
|
||||
name = xpccx->GetStringName(XPCJSContext::IDX_WRAPPED_JSOBJECT);
|
||||
|
||||
fun = JS_NewFunction(ccx, XPC_WN_DoubleWrappedGetter,
|
||||
0, 0, name);
|
||||
|
@ -412,11 +412,11 @@ DefinePropertyIfFound(XPCCallContext& ccx,
|
|||
}
|
||||
}
|
||||
|
||||
if (id == rt->GetStringID(XPCJSRuntime::IDX_TO_STRING) ||
|
||||
id == rt->GetStringID(XPCJSRuntime::IDX_TO_SOURCE) ||
|
||||
if (id == xpccx->GetStringID(XPCJSContext::IDX_TO_STRING) ||
|
||||
id == xpccx->GetStringID(XPCJSContext::IDX_TO_SOURCE) ||
|
||||
(scriptableInfo &&
|
||||
scriptableInfo->GetFlags().DontEnumQueryInterface() &&
|
||||
id == rt->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE)))
|
||||
id == xpccx->GetStringID(XPCJSContext::IDX_QUERY_INTERFACE)))
|
||||
propFlags &= ~JSPROP_ENUMERATE;
|
||||
|
||||
RootedValue funval(ccx);
|
||||
|
@ -932,8 +932,8 @@ XPCNativeScriptableInfo::Construct(const XPCNativeScriptableCreateInfo* sci)
|
|||
|
||||
bool success;
|
||||
|
||||
XPCJSRuntime* rt = XPCJSRuntime::Get();
|
||||
XPCNativeScriptableSharedMap* map = rt->GetNativeScriptableSharedMap();
|
||||
XPCJSContext* cx = XPCJSContext::Get();
|
||||
XPCNativeScriptableSharedMap* map = cx->GetNativeScriptableSharedMap();
|
||||
success = map->GetNewOrUsed(sci->GetFlags(), name, newObj);
|
||||
|
||||
if (!success) {
|
||||
|
@ -1067,7 +1067,7 @@ XPCNativeScriptableShared::~XPCNativeScriptableShared()
|
|||
// removed.
|
||||
|
||||
if (mJSClass.cOps) {
|
||||
XPCJSRuntime::Get()->GetNativeScriptableSharedMap()->Remove(this);
|
||||
XPCJSContext::Get()->GetNativeScriptableSharedMap()->Remove(this);
|
||||
free((void*)mJSClass.cOps);
|
||||
}
|
||||
|
||||
|
|
|
@ -122,8 +122,8 @@ XPCWrappedNativeProto::JSProtoObjectFinalized(js::FreeOp* fop, JSObject* obj)
|
|||
if (map->Find(mClassInfo) == this)
|
||||
map->Remove(mClassInfo);
|
||||
|
||||
GetRuntime()->GetDetachedWrappedNativeProtoMap()->Remove(this);
|
||||
GetRuntime()->GetDyingWrappedNativeProtoMap()->Add(this);
|
||||
GetContext()->GetDetachedWrappedNativeProtoMap()->Remove(this);
|
||||
GetContext()->GetDyingWrappedNativeProtoMap()->Add(this);
|
||||
|
||||
mJSProtoObject.finalize(js::CastToJSFreeOp(fop)->runtime());
|
||||
}
|
||||
|
|
|
@ -237,7 +237,7 @@ XPCWrappedNativeScope::AttachComponentsObject(JSContext* aCx)
|
|||
if (c)
|
||||
attrs |= JSPROP_PERMANENT;
|
||||
|
||||
RootedId id(aCx, XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_COMPONENTS));
|
||||
RootedId id(aCx, XPCJSContext::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS));
|
||||
return JS_DefinePropertyById(aCx, global, id, components, attrs);
|
||||
}
|
||||
|
||||
|
@ -483,7 +483,7 @@ XPCWrappedNativeScope::~XPCWrappedNativeScope()
|
|||
|
||||
// static
|
||||
void
|
||||
XPCWrappedNativeScope::TraceWrappedNativesInAllScopes(JSTracer* trc, XPCJSRuntime* rt)
|
||||
XPCWrappedNativeScope::TraceWrappedNativesInAllScopes(JSTracer* trc, XPCJSContext* cx)
|
||||
{
|
||||
// Do JS::TraceEdge for all wrapped natives with external references, as
|
||||
// well as any DOM expando objects.
|
||||
|
@ -512,7 +512,7 @@ SuspectDOMExpandos(JSObject* obj, nsCycleCollectionNoteRootCallback& cb)
|
|||
|
||||
// static
|
||||
void
|
||||
XPCWrappedNativeScope::SuspectAllWrappers(XPCJSRuntime* rt,
|
||||
XPCWrappedNativeScope::SuspectAllWrappers(XPCJSContext* cx,
|
||||
nsCycleCollectionNoteRootCallback& cb)
|
||||
{
|
||||
for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
|
||||
|
@ -529,7 +529,7 @@ XPCWrappedNativeScope::SuspectAllWrappers(XPCJSRuntime* rt,
|
|||
|
||||
// static
|
||||
void
|
||||
XPCWrappedNativeScope::UpdateWeakPointersAfterGC(XPCJSRuntime* rt)
|
||||
XPCWrappedNativeScope::UpdateWeakPointersAfterGC(XPCJSContext* cx)
|
||||
{
|
||||
// If this is called from the finalization callback in JSGC_MARK_END then
|
||||
// JSGC_FINALIZE_END must always follow it calling
|
||||
|
|
|
@ -22,8 +22,8 @@ UNIFIED_SOURCES += [
|
|||
'XPCConvert.cpp',
|
||||
'XPCDebug.cpp',
|
||||
'XPCException.cpp',
|
||||
'XPCJSContext.cpp',
|
||||
'XPCJSID.cpp',
|
||||
'XPCJSRuntime.cpp',
|
||||
'XPCJSWeakReference.cpp',
|
||||
'XPCLocale.cpp',
|
||||
'XPCLog.cpp',
|
||||
|
|
|
@ -60,18 +60,18 @@ const char XPC_XPCONNECT_CONTRACTID[] = "@mozilla.org/js/xpc/XPConnect;1";
|
|||
/***************************************************************************/
|
||||
|
||||
nsXPConnect::nsXPConnect()
|
||||
: mRuntime(nullptr),
|
||||
: mContext(nullptr),
|
||||
mShuttingDown(false)
|
||||
{
|
||||
mRuntime = XPCJSRuntime::newXPCJSRuntime();
|
||||
if (!mRuntime) {
|
||||
NS_RUNTIMEABORT("Couldn't create XPCJSRuntime.");
|
||||
mContext = XPCJSContext::newXPCJSContext();
|
||||
if (!mContext) {
|
||||
NS_RUNTIMEABORT("Couldn't create XPCJSContext.");
|
||||
}
|
||||
}
|
||||
|
||||
nsXPConnect::~nsXPConnect()
|
||||
{
|
||||
mRuntime->DeleteSingletonScopes();
|
||||
mContext->DeleteSingletonScopes();
|
||||
|
||||
// In order to clean up everything properly, we need to GC twice: once now,
|
||||
// to clean anything that can go away on its own (like the Junk Scope, which
|
||||
|
@ -79,17 +79,17 @@ nsXPConnect::~nsXPConnect()
|
|||
// XPConnect, to clean the stuff we forcibly disconnected. The forced
|
||||
// shutdown code defaults to leaking in a number of situations, so we can't
|
||||
// get by with only the second GC. :-(
|
||||
mRuntime->GarbageCollect(JS::gcreason::XPCONNECT_SHUTDOWN);
|
||||
mContext->GarbageCollect(JS::gcreason::XPCONNECT_SHUTDOWN);
|
||||
|
||||
mShuttingDown = true;
|
||||
XPCWrappedNativeScope::SystemIsBeingShutDown();
|
||||
mRuntime->SystemIsBeingShutDown();
|
||||
mContext->SystemIsBeingShutDown();
|
||||
|
||||
// The above causes us to clean up a bunch of XPConnect data structures,
|
||||
// after which point we need to GC to clean everything up. We need to do
|
||||
// this before deleting the XPCJSRuntime, because doing so destroys the
|
||||
// this before deleting the XPCJSContext, because doing so destroys the
|
||||
// maps that our finalize callback depends on.
|
||||
mRuntime->GarbageCollect(JS::gcreason::XPCONNECT_SHUTDOWN);
|
||||
mContext->GarbageCollect(JS::gcreason::XPCONNECT_SHUTDOWN);
|
||||
|
||||
NS_RELEASE(gSystemPrincipal);
|
||||
gScriptSecurityManager = nullptr;
|
||||
|
@ -97,7 +97,7 @@ nsXPConnect::~nsXPConnect()
|
|||
// shutdown the logging system
|
||||
XPC_LOG_FINISH();
|
||||
|
||||
delete mRuntime;
|
||||
delete mContext;
|
||||
|
||||
gSelf = nullptr;
|
||||
gOnceAliveNowDead = true;
|
||||
|
@ -109,8 +109,8 @@ nsXPConnect::InitStatics()
|
|||
{
|
||||
gSelf = new nsXPConnect();
|
||||
gOnceAliveNowDead = false;
|
||||
if (!gSelf->mRuntime) {
|
||||
NS_RUNTIMEABORT("Couldn't create XPCJSRuntime.");
|
||||
if (!gSelf->mContext) {
|
||||
NS_RUNTIMEABORT("Couldn't create XPCJSContext.");
|
||||
}
|
||||
|
||||
// Initial extra ref to keep the singleton alive
|
||||
|
@ -123,13 +123,13 @@ nsXPConnect::InitStatics()
|
|||
gScriptSecurityManager->GetSystemPrincipal(&gSystemPrincipal);
|
||||
MOZ_RELEASE_ASSERT(gSystemPrincipal);
|
||||
|
||||
if (!JS::InitSelfHostedCode(gSelf->mRuntime->Context()))
|
||||
if (!JS::InitSelfHostedCode(gSelf->mContext->Context()))
|
||||
MOZ_CRASH("InitSelfHostedCode failed");
|
||||
if (!gSelf->mRuntime->JSContextInitialized(gSelf->mRuntime->Context()))
|
||||
if (!gSelf->mContext->JSContextInitialized(gSelf->mContext->Context()))
|
||||
MOZ_CRASH("JSContextInitialized failed");
|
||||
|
||||
// Initialize our singleton scopes.
|
||||
gSelf->mRuntime->InitSingletonScopes();
|
||||
gSelf->mContext->InitSingletonScopes();
|
||||
}
|
||||
|
||||
nsXPConnect*
|
||||
|
@ -152,11 +152,11 @@ nsXPConnect::ReleaseXPConnectSingleton()
|
|||
}
|
||||
|
||||
// static
|
||||
XPCJSRuntime*
|
||||
nsXPConnect::GetRuntimeInstance()
|
||||
XPCJSContext*
|
||||
nsXPConnect::GetContextInstance()
|
||||
{
|
||||
nsXPConnect* xpc = XPConnect();
|
||||
return xpc->GetRuntime();
|
||||
return xpc->GetContext();
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -293,7 +293,7 @@ xpc::ErrorReport::ErrorReportToMessageString(JSErrorReport* aReport,
|
|||
aString.Truncate();
|
||||
const char16_t* m = aReport->ucmessage;
|
||||
if (m) {
|
||||
JSFlatString* name = js::GetErrorTypeName(CycleCollectedJSRuntime::Get()->Context(), aReport->exnType);
|
||||
JSFlatString* name = js::GetErrorTypeName(CycleCollectedJSContext::Get()->Context(), aReport->exnType);
|
||||
if (name) {
|
||||
AssignJSFlatString(aString, name);
|
||||
aString.AppendLiteral(": ");
|
||||
|
@ -321,7 +321,7 @@ nsXPConnect::GetInfoForName(const char * name, nsIInterfaceInfo** info)
|
|||
NS_IMETHODIMP
|
||||
nsXPConnect::GarbageCollect(uint32_t reason)
|
||||
{
|
||||
GetRuntime()->GarbageCollect(reason);
|
||||
GetContext()->GarbageCollect(reason);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -762,7 +762,7 @@ nsXPConnect::GetCurrentNativeCallContext(nsAXPCNativeCallContext * *aCurrentNati
|
|||
{
|
||||
MOZ_ASSERT(aCurrentNativeCallContext, "bad param");
|
||||
|
||||
*aCurrentNativeCallContext = XPCJSRuntime::Get()->GetCallContext();
|
||||
*aCurrentNativeCallContext = XPCJSContext::Get()->GetCallContext();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -770,8 +770,8 @@ NS_IMETHODIMP
|
|||
nsXPConnect::SetFunctionThisTranslator(const nsIID & aIID,
|
||||
nsIXPCFunctionThisTranslator* aTranslator)
|
||||
{
|
||||
XPCJSRuntime* rt = GetRuntime();
|
||||
IID2ThisTranslatorMap* map = rt->GetThisTranslatorMap();
|
||||
XPCJSContext* cx = GetContext();
|
||||
IID2ThisTranslatorMap* map = cx->GetThisTranslatorMap();
|
||||
map->Add(aIID, aTranslator);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -860,13 +860,13 @@ nsXPConnect::DebugDump(int16_t depth)
|
|||
XPC_LOG_INDENT();
|
||||
XPC_LOG_ALWAYS(("gSelf @ %x", gSelf));
|
||||
XPC_LOG_ALWAYS(("gOnceAliveNowDead is %d", (int)gOnceAliveNowDead));
|
||||
if (mRuntime) {
|
||||
if (mContext) {
|
||||
if (depth)
|
||||
mRuntime->DebugDump(depth);
|
||||
mContext->DebugDump(depth);
|
||||
else
|
||||
XPC_LOG_ALWAYS(("XPCJSRuntime @ %x", mRuntime));
|
||||
XPC_LOG_ALWAYS(("XPCJSContext @ %x", mContext));
|
||||
} else
|
||||
XPC_LOG_ALWAYS(("mRuntime is null"));
|
||||
XPC_LOG_ALWAYS(("mContext is null"));
|
||||
XPCWrappedNativeScope::DebugDumpAllScopes(depth);
|
||||
XPC_LOG_OUTDENT();
|
||||
#endif
|
||||
|
@ -1068,7 +1068,7 @@ SetLocationForGlobal(JSObject* global, nsIURI* locationURI)
|
|||
NS_IMETHODIMP
|
||||
nsXPConnect::NotifyDidPaint()
|
||||
{
|
||||
JS::NotifyDidPaint(GetRuntime()->Context());
|
||||
JS::NotifyDidPaint(GetContext()->Context());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче