merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2016-09-15 11:59:50 +02:00
Родитель 6acc7fef72 1560ed91a0
Коммит 25a074d342
258 изменённых файлов: 2887 добавлений и 3466 удалений

6
.cargo/config.in Normal file
Просмотреть файл

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

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