This commit is contained in:
Wes Kocher 2014-06-30 18:53:15 -07:00
Родитель ec33540af0 deb94787d6
Коммит 160fc3eb2e
452 изменённых файлов: 2059 добавлений и 1108 удалений

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

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bc3bbf42d2a606f6b7038881cff5ec3795fdf953"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="90bb898e8401f5fb98edcf38293073c5c26ab7bd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

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

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="bc3bbf42d2a606f6b7038881cff5ec3795fdf953"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="90bb898e8401f5fb98edcf38293073c5c26ab7bd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="276ce45e78b09c4a4ee643646f691d22804754c1">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="bc3bbf42d2a606f6b7038881cff5ec3795fdf953"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="90bb898e8401f5fb98edcf38293073c5c26ab7bd"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

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

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bc3bbf42d2a606f6b7038881cff5ec3795fdf953"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="90bb898e8401f5fb98edcf38293073c5c26ab7bd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

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

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="bc3bbf42d2a606f6b7038881cff5ec3795fdf953"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="90bb898e8401f5fb98edcf38293073c5c26ab7bd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>

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

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "2c2f2fa0a101f07cbb206cca2e69ef3a7b18244c",
"revision": "944559e6e60f9c97bc3b9daf00d73549e0eb80a6",
"repo_path": "/integration/gaia-central"
}

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

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bc3bbf42d2a606f6b7038881cff5ec3795fdf953"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="90bb898e8401f5fb98edcf38293073c5c26ab7bd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

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

@ -15,7 +15,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bc3bbf42d2a606f6b7038881cff5ec3795fdf953"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="90bb898e8401f5fb98edcf38293073c5c26ab7bd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

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

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="bc3bbf42d2a606f6b7038881cff5ec3795fdf953"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="90bb898e8401f5fb98edcf38293073c5c26ab7bd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>

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

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bc3bbf42d2a606f6b7038881cff5ec3795fdf953"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="90bb898e8401f5fb98edcf38293073c5c26ab7bd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

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

@ -24,15 +24,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "PanelFrame", "resource:///modules/Panel
iframe.addEventListener("DOMContentLoaded", function documentDOMLoaded() {
iframe.removeEventListener("DOMContentLoaded", documentDOMLoaded, true);
injectLoopAPI(iframe.contentWindow);
// We use loopPanelInitialized so that we know we've finished localising before
// sizing the panel.
iframe.contentWindow.addEventListener("loopPanelInitialized",
function documentLoaded() {
iframe.contentWindow.removeEventListener("loopPanelInitialized",
documentLoaded, true);
}, true);
}, true);
};

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

@ -212,7 +212,6 @@
let panel = this.panel;
let frameId = this.getAttribute("notificationFrameId");
let wasAlive = SharedFrame.isGroupAlive(frameId);
SharedFrame.setOwner(frameId, this.content);
// Clear dimensions on all browsers so the panel size will

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

@ -29,7 +29,10 @@ function handleRequest(request, response) {
cachedCount++;
}
Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer).initWithCallback(() => {
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.initWithCallback(() => {
// to avoid garbage collection
timer = null;
switch (format) {
case "txt": {
response.setStatusLine(request.httpVersion, status, "DA DA DA");

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

@ -9,7 +9,10 @@ function handleRequest(request, response) {
let params = request.queryString.split("&");
let index = params.filter((s) => s.contains("index="))[0].split("=")[1];
Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer).initWithCallback(() => {
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.initWithCallback(() => {
// to avoid garbage collection
timer = null;
response.setStatusLine(request.httpVersion, index == 1 ? 101 : index * 100, "Meh");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");

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

@ -9,7 +9,10 @@ function handleRequest(request, response) {
let params = request.queryString.split("&");
let status = params.filter((s) => s.contains("sts="))[0].split("=")[1];
Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer).initWithCallback(() => {
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.initWithCallback(() => {
// to avoid garbage collection
timer = null;
switch (status) {
case "100":
response.setStatusLine(request.httpVersion, 101, "Switching Protocols");

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

@ -135,7 +135,6 @@ let PanelFrame = {
let notificationFrameId = aToolbarButton.getAttribute("notificationFrameId");
let notificationFrame = aWindow.document.getElementById(notificationFrameId);
let wasAlive = SharedFrame.isGroupAlive(notificationFrameId);
SharedFrame.setOwner(notificationFrameId, notificationFrame);
// Clear dimensions on all browsers so the panel size will
@ -184,7 +183,7 @@ let PanelFrame = {
if (!inMenuPanel)
anchorBtn.setAttribute("open", "true");
if (notificationFrame.contentDocument &&
notificationFrame.contentDocument.readyState == "complete" && wasAlive) {
notificationFrame.contentDocument.readyState == "complete") {
initFrameShow();
} else {
// first time load, wait for load and dispatch after load

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

@ -2474,17 +2474,14 @@ nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed)
// If we have no parent then we're the root docshell; no ancestor of the
// original docshell doesn't have a allowfullscreen attribute, so
// report fullscreen as allowed.
nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
GetParent(getter_AddRefs(parentTreeItem));
if (!parentTreeItem) {
nsRefPtr<nsDocShell> parent = GetParentDocshell();
if (!parent) {
*aFullscreenAllowed = true;
return NS_OK;
}
// Otherwise, we have a parent, continue the checking for
// mozFullscreenAllowed in the parent docshell's ancestors.
nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentTreeItem);
NS_ENSURE_TRUE(parent, NS_OK);
return parent->GetFullscreenAllowed(aFullscreenAllowed);
}
@ -3132,16 +3129,15 @@ NS_IMETHODIMP
nsDocShell::GetRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem)
{
NS_ENSURE_ARG_POINTER(aRootTreeItem);
*aRootTreeItem = static_cast<nsIDocShellTreeItem *>(this);
nsCOMPtr<nsIDocShellTreeItem> parent;
NS_ENSURE_SUCCESS(GetParent(getter_AddRefs(parent)), NS_ERROR_FAILURE);
nsRefPtr<nsDocShell> root = this;
nsRefPtr<nsDocShell> parent = root->GetParentDocshell();
while (parent) {
*aRootTreeItem = parent;
NS_ENSURE_SUCCESS((*aRootTreeItem)->GetParent(getter_AddRefs(parent)),
NS_ERROR_FAILURE);
root = parent;
parent = root->GetParentDocshell();
}
NS_ADDREF(*aRootTreeItem);
root.forget(aRootTreeItem);
return NS_OK;
}
@ -5556,15 +5552,12 @@ nsDocShell::GetVisibility(bool * aVisibility)
// for a hidden view, unless we're an off screen browser, which
// would make this test meaningless.
nsCOMPtr<nsIDocShellTreeItem> treeItem = this;
nsCOMPtr<nsIDocShellTreeItem> parentItem;
treeItem->GetParent(getter_AddRefs(parentItem));
nsRefPtr<nsDocShell> docShell = this;
nsRefPtr<nsDocShell> parentItem = docShell->GetParentDocshell();
while (parentItem) {
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(treeItem));
presShell = docShell->GetPresShell();
nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentItem);
nsCOMPtr<nsIPresShell> pPresShell = parentDS->GetPresShell();
nsCOMPtr<nsIPresShell> pPresShell = parentItem->GetPresShell();
// Null-check for crash in bug 267804
if (!pPresShell) {
@ -5593,8 +5586,8 @@ nsDocShell::GetVisibility(bool * aVisibility)
return NS_OK;
}
treeItem = parentItem;
treeItem->GetParent(getter_AddRefs(parentItem));
docShell = parentItem;
parentItem = docShell->GetParentDocshell();
}
nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
@ -8019,8 +8012,7 @@ nsDocShell::RestoreFromHistory()
nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
uint32_t parentSuspendCount = 0;
if (document) {
nsCOMPtr<nsIDocShellTreeItem> parent;
GetParent(getter_AddRefs(parent));
nsRefPtr<nsDocShell> parent = GetParentDocshell();
if (parent) {
nsCOMPtr<nsIDocument> d = parent->GetDocument();
if (d) {
@ -9225,8 +9217,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
// If this docshell is owned by a frameloader, make sure to cancel
// possible frameloader initialization before loading a new page.
nsCOMPtr<nsIDocShellTreeItem> parent;
GetParent(getter_AddRefs(parent));
nsCOMPtr<nsIDocShellTreeItem> parent = GetParentDocshell();
if (parent) {
nsCOMPtr<nsIDocument> doc = do_GetInterface(parent);
if (doc) {
@ -12302,7 +12293,7 @@ nsDocShell::GetNestedFrameId(uint64_t* aId)
NS_IMETHODIMP
nsDocShell::IsAppOfType(uint32_t aAppType, bool *aIsOfType)
{
nsCOMPtr<nsIDocShell> shell = this;
nsRefPtr<nsDocShell> shell = this;
while (shell) {
uint32_t type;
shell->GetAppType(&type);
@ -12310,10 +12301,7 @@ nsDocShell::IsAppOfType(uint32_t aAppType, bool *aIsOfType)
*aIsOfType = true;
return NS_OK;
}
nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(shell);
nsCOMPtr<nsIDocShellTreeItem> parent;
item->GetParent(getter_AddRefs(parent));
shell = do_QueryInterface(parent);
shell = shell->GetParentDocshell();
}
*aIsOfType = false;
@ -13076,19 +13064,14 @@ nsDocShell::GetAsyncPanZoomEnabled(bool* aOut)
bool
nsDocShell::HasUnloadedParent()
{
nsCOMPtr<nsIDocShellTreeItem> currentTreeItem = this;
while (currentTreeItem) {
nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
currentTreeItem->GetParent(getter_AddRefs(parentTreeItem));
nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentTreeItem);
if (parent) {
bool inUnload = false;
parent->GetIsInUnload(&inUnload);
if (inUnload) {
return true;
}
nsRefPtr<nsDocShell> parent = GetParentDocshell();
while (parent) {
bool inUnload = false;
parent->GetIsInUnload(&inUnload);
if (inUnload) {
return true;
}
currentTreeItem.swap(parentTreeItem);
parent = parent->GetParentDocshell();
}
return false;
}

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

@ -11,6 +11,7 @@
#include "nsWeakReference.h"
#include "nsIObserver.h"
#include "nsWrapperCache.h"
#include "nsMimeTypeArray.h"
#include "nsPluginTags.h"
#include "nsPIDOMWindow.h"

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

@ -32,6 +32,8 @@ public:
virtual nsresult Get(uint32_t aKey, int32_t& aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Set(uint32_t aKey, int64_t aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Get(uint32_t aKey, int64_t& aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Set(uint32_t aKey, bool aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Get(uint32_t aKey, bool& aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Set(uint32_t aKey, const Size& aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Get(uint32_t aKey, Size& aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult Set(uint32_t aKey, const nsTArray<Region>& aRegions) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }

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

@ -474,6 +474,19 @@ nsGonkCameraControl::Get(uint32_t aKey, int64_t& aRet)
return mParams.Get(aKey, aRet);
}
// Boolean parameter accessors.
nsresult
nsGonkCameraControl::Set(uint32_t aKey, bool aValue)
{
return SetAndPush(aKey, aValue);
}
nsresult
nsGonkCameraControl::Get(uint32_t aKey, bool& aRet)
{
return mParams.Get(aKey, aRet);
}
// Weighted-region parameter accessors.
nsresult
nsGonkCameraControl::Set(uint32_t aKey, const nsTArray<Region>& aRegions)

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

@ -65,6 +65,8 @@ public:
virtual nsresult Get(uint32_t aKey, int32_t& aValue) MOZ_OVERRIDE;
virtual nsresult Set(uint32_t aKey, int64_t aValue) MOZ_OVERRIDE;
virtual nsresult Get(uint32_t aKey, int64_t& aValue) MOZ_OVERRIDE;
virtual nsresult Set(uint32_t aKey, bool aValue) MOZ_OVERRIDE;
virtual nsresult Get(uint32_t aKey, bool& aValue) MOZ_OVERRIDE;
virtual nsresult Set(uint32_t aKey, const Size& aValue) MOZ_OVERRIDE;
virtual nsresult Get(uint32_t aKey, Size& aValue) MOZ_OVERRIDE;
virtual nsresult Set(uint32_t aKey, const nsTArray<Region>& aRegions) MOZ_OVERRIDE;

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

@ -206,6 +206,8 @@ public:
virtual nsresult Get(uint32_t aKey, int32_t& aValue) = 0;
virtual nsresult Set(uint32_t aKey, int64_t aValue) = 0;
virtual nsresult Get(uint32_t aKey, int64_t& aValue) = 0;
virtual nsresult Set(uint32_t aKey, bool aValue) = 0;
virtual nsresult Get(uint32_t aKey, bool& aValue) = 0;
virtual nsresult Set(uint32_t aKey, const Size& aValue) = 0;
virtual nsresult Get(uint32_t aKey, Size& aValue) = 0;
virtual nsresult Set(uint32_t aKey, const nsTArray<Region>& aRegions) = 0;

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

@ -66,6 +66,7 @@ struct FontListEntry {
int16_t stretch;
uint8_t italic;
uint8_t index;
bool isHidden;
};
struct DeviceStorageFreeSpaceParams

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

@ -16,6 +16,7 @@ qemu = true
[test_mobile_data_state.js]
[test_mobile_mmi.js]
[test_mobile_mmi_change_pin.js]
[test_mobile_mmi_call_forwarding.js]
[test_mobile_roaming_preference.js]
[test_call_barring_get_option.js]
[test_call_barring_set_error.js]

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

@ -0,0 +1,145 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = "head.js";
const TEST_DATA = [
{
reason: MozMobileConnection.CALL_FORWARD_REASON_UNCONDITIONAL,
number: "+886912345678",
serviceClass: MozMobileConnection.ICC_SERVICE_CLASS_VOICE,
timeSeconds: 5
}, {
reason: MozMobileConnection.CALL_FORWARD_REASON_MOBILE_BUSY,
number: "0912345678",
serviceClass: MozMobileConnection.ICC_SERVICE_CLASS_VOICE,
timeSeconds: 10
}, {
reason: MozMobileConnection.CALL_FORWARD_REASON_NO_REPLY,
number: "+886987654321",
serviceClass: MozMobileConnection.ICC_SERVICE_CLASS_VOICE,
timeSeconds: 15
}, {
reason: MozMobileConnection.CALL_FORWARD_REASON_NOT_REACHABLE,
number: "+0987654321",
serviceClass: MozMobileConnection.ICC_SERVICE_CLASS_VOICE,
timeSeconds: 20
}
];
// Please see TS 22.030 Annex B
const CF_REASON_TO_MMI = {
/* CALL_FORWARD_REASON_UNCONDITIONAL */
0: "21",
/* CALL_FORWARD_REASON_MOBILE_BUSY */
1: "67",
/* CALL_FORWARD_REASON_NO_REPLY */
2: "61",
/* CALL_FORWARD_REASON_NOT_REACHABLE */
3: "62",
/* CALL_FORWARD_REASON_ALL_CALL_FORWARDING */
4: "002",
/* CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING */
5: "004"
};
// Please see TS 22.030 Annex C
const SERVICE_CLASS_TO_MMI = {
/* ICC_SERVICE_CLASS_VOICE */
1: "11"
};
function testSetCallForwarding(aData) {
// Registration: **SC*SIA*SIB*SIC#
let MMI_CODE = "**" + CF_REASON_TO_MMI[aData.reason] + "*" + aData.number +
"*" + SERVICE_CLASS_TO_MMI[aData.serviceClass] +
"*" + aData.timeSeconds + "#";
log("Test " + MMI_CODE);
let promises = [];
// Check cfstatechange event.
promises.push(waitForManagerEvent("cfstatechange").then(function(aEvent) {
is(aEvent.success, true, "check success");
is(aEvent.action, MozMobileConnection.CALL_FORWARD_ACTION_REGISTRATION,
"check action");
is(aEvent.reason, aData.reason, "check reason");
is(aEvent.number, aData.number, "check number");
is(aEvent.timeSeconds, aData.timeSeconds, "check timeSeconds");
is(aEvent.serviceClass, aData.serviceClass, "check serviceClass");
}));
// Check DOMRequest's result.
promises.push(sendMMI(MMI_CODE)
.then(function resolve(aResult) {
is(aResult.serviceCode, "scCallForwarding", "Check service code");
is(aResult.statusMessage, "smServiceRegistered", "Check status message");
is(aResult.additionalInformation, undefined, "Check additional information");
}, function reject(aError) {
ok(false, "got '" + aError.name + "' error");
}));
return Promise.all(promises);
}
function testGetCallForwarding(aExpectedData) {
// Interrogation: *#SC#
let MMI_CODE = "*#" + CF_REASON_TO_MMI[aExpectedData.reason] + "#";
log("Test " + MMI_CODE);
return sendMMI(MMI_CODE)
.then(function resolve(aResult) {
is(aResult.serviceCode, "scCallForwarding", "Check service code");
is(aResult.statusMessage, "smServiceInterrogated", "Check status message");
is(Array.isArray(aResult.additionalInformation), true,
"additionalInformation should be an array");
for (let i = 0; i < aResult.additionalInformation.length; i++) {
let result = aResult.additionalInformation[i];
// Only need to check the result containing the serviceClass that we are
// interested in.
if (!(result.serviceClass & aExpectedData.serviceClass)) {
continue;
}
is(result.active, true, "check active");
is(result.reason, aExpectedData.reason, "check reason");
is(result.number, aExpectedData.number, "check number");
is(result.timeSeconds, aExpectedData.timeSeconds, "check timeSeconds");
}
}, function reject(aError) {
ok(false, MMI_CODE + " got error: " + aError.name);
});
}
function clearAllCallForwardingSettings() {
log("Clear all call forwarding settings");
let promise = Promise.resolve();
for (let reason = MozMobileConnection.CALL_FORWARD_REASON_UNCONDITIONAL;
reason <= MozMobileConnection.CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING;
reason++) {
let options = {
reason: reason,
action: MozMobileConnection.CALL_FORWARD_ACTION_ERASURE
};
// Emulator doesn't support CALL_FORWARD_REASON_ALL_* yet, we catch the
// reject here in order to avoid impact the test result.
promise =
promise.then(() => setCallForwardingOption(options).then(null, () => {}));
}
return promise;
}
// Start tests
startTestCommon(function() {
let promise = Promise.resolve();
for (let i = 0; i < TEST_DATA.length; i++) {
let data = TEST_DATA[i];
promise = promise.then(() => testSetCallForwarding(data))
.then(() => testGetCallForwarding(data));
}
// reset call forwarding settings.
return promise.then(null, () => { ok(false, "promise reject during test"); })
.then(() => clearAllCallForwardingSettings());
});

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

@ -7,7 +7,7 @@ skip-if = toolkit == "gonk"
[test_tcpsocket_enabled_with_perm.html]
skip-if = toolkit == "gonk" || e10s
[test_networkstats_alarms.html]
skip-if = toolkit != "gonk" || true # Intermittent failures (bug 1023341)
skip-if = toolkit != "gonk"
[test_networkstats_basics.html]
skip-if = toolkit != "gonk" || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(Will be fixed in bug 858005) b2g-desktop(Will be fixed in bug 858005)
[test_networkstats_disabled.html]

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

@ -92,7 +92,7 @@ var steps = [
ok(true, "Calling addAlarm()");
req = navigator.mozNetworkStats
.addAlarm(new window.MozNetworkStatsInterface(wifi), 1000000);
.addAlarm(new window.MozNetworkStatsInterface(wifi), 100000000);
req.onsuccess = function () {
ok(true, "Succeeded to add alarm. AlarmId: " + req.result);

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

@ -243,10 +243,15 @@ WifiGeoPositionProvider.prototype = {
let radio = radioService.getRadioInterface(i);
let iccInfo = radio.rilContext.iccInfo;
let cell = radio.rilContext.voice.cell;
let type = radio.rilContext.voice.type;
if (iccInfo && cell) {
// TODO type and signal strength
result.push({ radio: "gsm",
if (iccInfo && cell && type) {
if (type === "gsm" || type === "gprs" || type === "edge") {
type = "gsm";
} else {
type = "wcdma";
}
result.push({ radio: type,
mobileCountryCode: iccInfo.mcc,
mobileNetworkCode: iccInfo.mnc,
locationAreaCode: cell.gsmLocationAreaCode,

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

@ -246,7 +246,7 @@ GLContextEGL::GLContextEGL(
mHwc = HwcComposer2D::GetInstance();
MOZ_ASSERT(!mHwc->Initialized());
if (mHwc->Init(EGL_DISPLAY(), mSurface)) {
if (mHwc->Init(EGL_DISPLAY(), mSurface, this)) {
NS_WARNING("HWComposer initialization failed!");
mHwc = nullptr;
}

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

@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/ArrayUtils.h"
#include "mozilla/Base64.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/ContentChild.h"
@ -43,6 +44,8 @@
#include "mozilla/Preferences.h"
#include "mozilla/scache/StartupCache.h"
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
using namespace mozilla;
@ -582,7 +585,8 @@ FT2FontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
*/
void
FT2FontFamily::AddFacesToFontList(InfallibleTArray<FontListEntry>* aFontList)
FT2FontFamily::AddFacesToFontList(InfallibleTArray<FontListEntry>* aFontList,
Visibility aVisibility)
{
for (int i = 0, n = mAvailableFonts.Length(); i < n; ++i) {
const FT2FontEntry *fe =
@ -595,7 +599,8 @@ FT2FontFamily::AddFacesToFontList(InfallibleTArray<FontListEntry>* aFontList)
fe->mFilename,
fe->Weight(), fe->Stretch(),
fe->IsItalic(),
fe->mFTFontIndex));
fe->mFTFontIndex,
aVisibility == kHidden));
}
}
@ -827,9 +832,11 @@ gfxFT2FontList::gfxFT2FontList()
}
void
gfxFT2FontList::AppendFacesFromCachedFaceList(const nsCString& aFileName,
bool aStdFile,
const nsCString& aFaceList)
gfxFT2FontList::AppendFacesFromCachedFaceList(
const nsCString& aFileName,
const nsCString& aFaceList,
StandardFile aStdFile,
FT2FontFamily::Visibility aVisibility)
{
const char *beginning = aFaceList.get();
const char *end = strchr(beginning, ',');
@ -865,7 +872,8 @@ gfxFT2FontList::AppendFacesFromCachedFaceList(const nsCString& aFileName,
int32_t stretch = strtol(beginning, nullptr, 10);
FontListEntry fle(familyName, faceName, aFileName,
weight, stretch, italic, index);
weight, stretch, italic, index,
aVisibility == FT2FontFamily::kHidden);
AppendFaceFromFontListEntry(fle, aStdFile);
beginning = end + 1;
@ -923,8 +931,9 @@ FT2FontEntry::CheckForBrokenFont(gfxFontFamily *aFamily)
void
gfxFT2FontList::AppendFacesFromFontFile(const nsCString& aFileName,
bool aStdFile,
FontNameCache *aCache)
FontNameCache *aCache,
StandardFile aStdFile,
FT2FontFamily::Visibility aVisibility)
{
nsCString faceList;
uint32_t filesize = 0, timestamp = 0;
@ -938,7 +947,8 @@ gfxFT2FontList::AppendFacesFromFontFile(const nsCString& aFileName,
s.st_mtime == timestamp && s.st_size == filesize)
{
LOG(("using cached font info for %s", aFileName.get()));
AppendFacesFromCachedFaceList(aFileName, aStdFile, faceList);
AppendFacesFromCachedFaceList(aFileName, faceList, aStdFile,
aVisibility);
return;
}
@ -954,7 +964,7 @@ gfxFT2FontList::AppendFacesFromFontFile(const nsCString& aFileName,
if (FT_Err_Ok != FT_New_Face(ftLibrary, aFileName.get(), i, &face)) {
continue;
}
AddFaceToList(aFileName, i, aStdFile, face, faceList);
AddFaceToList(aFileName, i, aStdFile, aVisibility, face, faceList);
FT_Done_Face(face);
}
FT_Done_Face(dummy);
@ -1017,7 +1027,9 @@ gfxFT2FontList::FindFontsInOmnijar(FontNameCache *aCache)
// add the face to the available font list and to the faceList string
void
gfxFT2FontList::AddFaceToList(const nsCString& aEntryName, uint32_t aIndex,
bool aStdFile, FT_Face aFace,
StandardFile aStdFile,
FT2FontFamily::Visibility aVisibility,
FT_Face aFace,
nsCString& aFaceList)
{
if (FT_Err_Ok != FT_Select_Charmap(aFace, FT_ENCODING_UNICODE)) {
@ -1030,13 +1042,17 @@ gfxFT2FontList::AddFaceToList(const nsCString& aEntryName, uint32_t aIndex,
FT2FontEntry* fe =
CreateNamedFontEntry(aFace, aEntryName.get(), aIndex);
auto& fontFamilies =
(aVisibility == FT2FontFamily::kHidden) ? mHiddenFontFamilies :
mFontFamilies;
if (fe) {
NS_ConvertUTF8toUTF16 name(aFace->family_name);
BuildKeyNameFromFontName(name);
gfxFontFamily *family = mFontFamilies.GetWeak(name);
gfxFontFamily *family = fontFamilies.GetWeak(name);
if (!family) {
family = new FT2FontFamily(name);
mFontFamilies.Put(name, family);
fontFamilies.Put(name, family);
if (mSkipSpaceLookupCheckFamilies.Contains(name)) {
family->SetSkipSpaceFeatureCheck(true);
}
@ -1044,7 +1060,7 @@ gfxFT2FontList::AddFaceToList(const nsCString& aEntryName, uint32_t aIndex,
family->SetBadUnderlineFamily();
}
}
fe->mStandardFace = aStdFile;
fe->mStandardFace = (aStdFile == kStandard);
family->AddFontEntry(fe);
fe->CheckForBrokenFont(family);
@ -1074,7 +1090,7 @@ gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
uint32_t filesize, timestamp;
aCache->GetInfoForFile(aEntryName, faceList, &timestamp, &filesize);
if (faceList.Length() > 0) {
AppendFacesFromCachedFaceList(aEntryName, true, faceList);
AppendFacesFromCachedFaceList(aEntryName, faceList);
return;
}
}
@ -1111,7 +1127,8 @@ gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
if (FT_Err_Ok != FT_New_Memory_Face(ftLibrary, buf, bufSize, i, &face)) {
continue;
}
AddFaceToList(aEntryName, i, true, face, faceList);
AddFaceToList(aEntryName, i, kStandard, FT2FontFamily::kVisible,
face, faceList);
FT_Done_Face(face);
}
@ -1160,14 +1177,19 @@ gfxFT2FontList::FindFonts()
InfallibleTArray<FontListEntry> fonts;
mozilla::dom::ContentChild::GetSingleton()->SendReadFontList(&fonts);
for (uint32_t i = 0, n = fonts.Length(); i < n; ++i) {
AppendFaceFromFontListEntry(fonts[i], false);
// We don't need to identify "standard" font files here,
// as the faces are already sorted.
AppendFaceFromFontListEntry(fonts[i], kUnknown);
}
// Passing null for userdata tells Finalize that it does not need
// to sort faces (because they were already sorted by chrome,
// so we just maintain the existing order)
mFontFamilies.Enumerate(FinalizeFamilyMemberList, nullptr);
LOG(("got font list from chrome process: %d faces in %d families",
fonts.Length(), mFontFamilies.Count()));
mHiddenFontFamilies.Enumerate(FinalizeFamilyMemberList, nullptr);
LOG(("got font list from chrome process: %d faces in %d families "
"and %d in hidden families",
fonts.Length(), mFontFamilies.Count(),
mHiddenFontFamilies.Count()));
return;
}
@ -1185,13 +1207,20 @@ gfxFT2FontList::FindFonts()
}
root.AppendLiteral("/fonts");
FindFontsInDir(root, &fnc);
FindFontsInDir(root, &fnc, FT2FontFamily::kVisible);
if (mFontFamilies.Count() == 0) {
// if we can't find/read the font directory, we are doomed!
NS_RUNTIMEABORT("Could not read the system fonts directory");
}
#ifdef MOZ_WIDGET_GONK
// Look for fonts in /system/fonts/hidden and preload them to the
// user-font cache as data: URIs
root.AppendLiteral("/hidden");
FindFontsInDir(root, &fnc, FT2FontFamily::kHidden);
#endif
// Look for fonts stored in omnijar, unless we're on a low-memory
// device where we don't want to spend the RAM to decompress them.
// (Prefs may disable this, or force-enable it even with low memory.)
@ -1212,7 +1241,7 @@ gfxFT2FontList::FindFonts()
nsCString localPath;
rv = localDir->GetNativePath(localPath);
if (NS_SUCCEEDED(rv)) {
FindFontsInDir(localPath, &fnc);
FindFontsInDir(localPath, &fnc, FT2FontFamily::kVisible);
}
}
@ -1220,10 +1249,13 @@ gfxFT2FontList::FindFonts()
// and marking "simple" families.
// Passing non-null userData here says that we want faces to be sorted.
mFontFamilies.Enumerate(FinalizeFamilyMemberList, this);
mHiddenFontFamilies.Enumerate(FinalizeFamilyMemberList, this);
}
void
gfxFT2FontList::FindFontsInDir(const nsCString& aDir, FontNameCache *aFNC)
gfxFT2FontList::FindFontsInDir(const nsCString& aDir,
FontNameCache *aFNC,
FT2FontFamily::Visibility aVisibility)
{
static const char* sStandardFonts[] = {
"DroidSans.ttf",
@ -1272,7 +1304,8 @@ gfxFT2FontList::FindFontsInDir(const nsCString& aDir, FontNameCache *aFNC)
// note that if we have cached info for this file in fnc,
// and the file is unchanged, we won't actually need to read it.
// If the file is new/changed, this will update the FontNameCache.
AppendFacesFromFontFile(s, isStdFont, aFNC);
AppendFacesFromFontFile(s, aFNC, isStdFont ? kStandard : kUnknown,
aVisibility);
}
}
@ -1281,16 +1314,18 @@ gfxFT2FontList::FindFontsInDir(const nsCString& aDir, FontNameCache *aFNC)
void
gfxFT2FontList::AppendFaceFromFontListEntry(const FontListEntry& aFLE,
bool aStdFile)
StandardFile aStdFile)
{
FT2FontEntry* fe = FT2FontEntry::CreateFontEntry(aFLE);
if (fe) {
fe->mStandardFace = aStdFile;
auto& fontFamilies =
aFLE.isHidden() ? mHiddenFontFamilies : mFontFamilies;
fe->mStandardFace = (aStdFile == kStandard);
nsAutoString name(aFLE.familyName());
gfxFontFamily *family = mFontFamilies.GetWeak(name);
gfxFontFamily *family = fontFamilies.GetWeak(name);
if (!family) {
family = new FT2FontFamily(name);
mFontFamilies.Put(name, family);
fontFamilies.Put(name, family);
if (mSkipSpaceLookupCheckFamilies.Contains(name)) {
family->SetSkipSpaceFeatureCheck(true);
}
@ -1313,7 +1348,21 @@ AddFamilyToFontList(nsStringHashKey::KeyType aKey,
reinterpret_cast<InfallibleTArray<FontListEntry>*>(aUserArg);
FT2FontFamily *family = static_cast<FT2FontFamily*>(aFamily.get());
family->AddFacesToFontList(fontlist);
family->AddFacesToFontList(fontlist, FT2FontFamily::kVisible);
return PL_DHASH_NEXT;
}
static PLDHashOperator
AddHiddenFamilyToFontList(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamily,
void* aUserArg)
{
InfallibleTArray<FontListEntry>* fontlist =
reinterpret_cast<InfallibleTArray<FontListEntry>*>(aUserArg);
FT2FontFamily *family = static_cast<FT2FontFamily*>(aFamily.get());
family->AddFacesToFontList(fontlist, FT2FontFamily::kHidden);
return PL_DHASH_NEXT;
}
@ -1322,6 +1371,7 @@ void
gfxFT2FontList::GetFontList(InfallibleTArray<FontListEntry>* retValue)
{
mFontFamilies.Enumerate(AddFamilyToFontList, retValue);
mHiddenFontFamilies.Enumerate(AddHiddenFamilyToFontList, retValue);
}
static void
@ -1338,16 +1388,93 @@ LoadSkipSpaceLookupCheck(nsTHashtable<nsStringHashKey>& aSkipSpaceLookupCheck)
}
}
static PLDHashOperator
PreloadAsUserFontFaces(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamily,
void* aUserArg)
{
gfxFontFamily *family = aFamily.get();
auto& faces = family->GetFontList();
size_t count = faces.Length();
for (size_t i = 0; i < count; ++i) {
FT2FontEntry* fe = static_cast<FT2FontEntry*>(faces[i].get());
if (fe->mFTFontIndex != 0) {
NS_NOTREACHED("don't try to preload a multi-face font");
continue;
}
// XXX Should we move the i/o here off the main thread?
// Map the font data in fe->mFilename, so we can generate a data: URI.
int fd = open(fe->mFilename.get(), O_RDONLY);
if (fd < 0) {
continue;
}
struct stat buf;
if (fstat(fd, &buf) != 0 || buf.st_size < 12) {
close(fd);
continue;
}
char* data = static_cast<char*>(
mmap(0, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0));
close(fd);
if (data == MAP_FAILED) {
continue;
}
// First byte is sufficient to distinguish WOFF from uncompressed
// OpenType (either TrueType or CFF).
bool isWoff = (data[0] == 'w');
// Generate a corresponding data: URI that apps could use.
nsCString encodedData;
nsresult rv = Base64Encode(Substring(data, buf.st_size), encodedData);
munmap(data, buf.st_size);
if (NS_FAILED(rv)) {
continue;
}
nsCString spec("data:font/");
spec.Append(isWoff ? "woff" : "opentype");
spec.Append(";base64,");
spec.Append(encodedData);
#if 0
ALOG("\n**** Preloading family [%s] face [%s]:\n%s\n\n",
NS_ConvertUTF16toUTF8(family->Name()).get(),
fe->mFilename.get(),
spec.get());
#endif
// Record the URI in gfxUserFontData on the entry.
nsCOMPtr<nsIURI> uri;
if (NS_FAILED(NS_NewURI(getter_AddRefs(uri), spec))) {
continue;
}
fe->mUserFontData = new gfxUserFontData;
fe->mUserFontData->mURI = uri;
fe->mUserFontData->mRealName = fe->Name();
// Stash it persistently in the user-font cache.
gfxUserFontSet::UserFontCache::CacheFont(
fe, gfxUserFontSet::UserFontCache::kPersistent);
}
return PL_DHASH_NEXT;
}
nsresult
gfxFT2FontList::InitFontList()
{
// reset font lists
gfxPlatformFontList::InitFontList();
mHiddenFontFamilies.Clear();
LoadSkipSpaceLookupCheck(mSkipSpaceLookupCheckFamilies);
FindFonts();
mHiddenFontFamilies.Enumerate(PreloadAsUserFontFaces, this);
return NS_OK;
}
@ -1402,6 +1529,8 @@ gfxFT2FontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
// walk over list of names
FullFontNameSearch data(aFontName);
// Note that we only check mFontFamilies here, not mHiddenFontFamilies;
// hence @font-face { src:local(...) } will not find hidden fonts.
mFontFamilies.Enumerate(FindFullName, &data);
if (!data.mFontEntry) {
@ -1459,3 +1588,21 @@ gfxFT2FontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
return FT2FontEntry::CreateFontEntry(*aProxyEntry, aFontData, aLength);
}
static PLDHashOperator
AppendFamily(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamily,
void* aUserArg)
{
nsTArray<nsRefPtr<gfxFontFamily> > * familyArray =
reinterpret_cast<nsTArray<nsRefPtr<gfxFontFamily>>*>(aUserArg);
familyArray->AppendElement(aFamily);
return PL_DHASH_NEXT;
}
void
gfxFT2FontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
{
mFontFamilies.Enumerate(AppendFamily, &aFamilyArray);
mHiddenFontFamilies.Enumerate(AppendFamily, &aFamilyArray);
}

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

@ -95,11 +95,20 @@ public:
class FT2FontFamily : public gfxFontFamily
{
public:
// Flags to indicate whether a font should be "visible" in the global
// font list (available for use in font-family), or "hidden" (available
// only to support a matching data: URI used in @font-face).
typedef enum {
kVisible,
kHidden
} Visibility;
FT2FontFamily(const nsAString& aName) :
gfxFontFamily(aName) { }
// Append this family's faces to the IPC fontlist
void AddFacesToFontList(InfallibleTArray<FontListEntry>* aFontList);
void AddFacesToFontList(InfallibleTArray<FontListEntry>* aFontList,
Visibility aVisibility);
};
class gfxFT2FontList : public gfxPlatformFontList
@ -122,35 +131,52 @@ public:
return static_cast<gfxFT2FontList*>(gfxPlatformFontList::PlatformFontList());
}
virtual void GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray);
protected:
typedef enum {
kUnknown,
kStandard
} StandardFile;
virtual nsresult InitFontList();
void AppendFaceFromFontListEntry(const FontListEntry& aFLE,
bool isStdFile);
StandardFile aStdFile);
void AppendFacesFromFontFile(const nsCString& aFileName,
bool isStdFile = false,
FontNameCache *aCache = nullptr);
FontNameCache *aCache,
StandardFile aStdFile,
FT2FontFamily::Visibility aVisibility);
void AppendFacesFromOmnijarEntry(nsZipArchive *aReader,
const nsCString& aEntryName,
FontNameCache *aCache,
bool aJarChanged);
// the defaults here are suitable for reading bundled fonts from omnijar
void AppendFacesFromCachedFaceList(const nsCString& aFileName,
bool isStdFile,
const nsCString& aFaceList);
const nsCString& aFaceList,
StandardFile aStdFile = kStandard,
FT2FontFamily::Visibility aVisibility =
FT2FontFamily::kVisible);
void AddFaceToList(const nsCString& aEntryName, uint32_t aIndex,
bool aStdFile, FT_Face aFace, nsCString& aFaceList);
StandardFile aStdFile,
FT2FontFamily::Visibility aVisibility,
FT_Face aFace, nsCString& aFaceList);
void FindFonts();
void FindFontsInOmnijar(FontNameCache *aCache);
void FindFontsInDir(const nsCString& aDir, FontNameCache* aFNC);
void FindFontsInDir(const nsCString& aDir, FontNameCache* aFNC,
FT2FontFamily::Visibility aVisibility);
nsTHashtable<nsStringHashKey> mSkipSpaceLookupCheckFamilies;
private:
nsRefPtrHashtable<nsStringHashKey, gfxFontFamily> mHiddenFontFamilies;
};
#endif /* GFX_FT2FONTLIST_H */

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

@ -828,6 +828,14 @@ nsTHashtable<gfxUserFontSet::UserFontCache::Entry>*
NS_IMPL_ISUPPORTS(gfxUserFontSet::UserFontCache::Flusher, nsIObserver)
PLDHashOperator
gfxUserFontSet::UserFontCache::Entry::RemoveUnlessPersistent(Entry* aEntry,
void* aUserData)
{
return aEntry->mPersistence == kPersistent ? PL_DHASH_NEXT :
PL_DHASH_REMOVE;
}
PLDHashOperator
gfxUserFontSet::UserFontCache::Entry::RemoveIfPrivate(Entry* aEntry,
void* aUserData)
@ -861,7 +869,7 @@ gfxUserFontSet::UserFontCache::Flusher::Observe(nsISupports* aSubject,
}
if (!strcmp(aTopic, "cacheservice:empty-cache")) {
sUserFonts->Clear();
sUserFonts->EnumerateEntries(Entry::RemoveUnlessPersistent, nullptr);
} else if (!strcmp(aTopic, "last-pb-context-exited")) {
sUserFonts->EnumerateEntries(Entry::RemoveIfPrivate, nullptr);
} else if (!strcmp(aTopic, "xpcom-shutdown")) {
@ -919,7 +927,8 @@ gfxUserFontSet::UserFontCache::Entry::KeyEquals(const KeyTypePointer aKey) const
}
void
gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry *aFontEntry)
gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry *aFontEntry,
EntryPersistence aPersistence)
{
NS_ASSERTION(aFontEntry->mFamilyName.Length() != 0,
"caching a font associated with no family yet");
@ -948,7 +957,7 @@ gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry *aFontEntry)
principal = data->mPrincipal;
}
sUserFonts->PutEntry(Key(data->mURI, principal, aFontEntry,
data->mPrivate));
data->mPrivate, aPersistence));
#ifdef DEBUG_USERFONT_CACHE
printf("userfontcache added fontentry: %p\n", aFontEntry);

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

@ -61,7 +61,7 @@ operator==(const gfxFontFaceSrc& a, const gfxFontFaceSrc& b)
class gfxUserFontData {
public:
gfxUserFontData()
: mSrcIndex(0), mFormat(0), mMetaOrigLen(0)
: mSrcIndex(0), mFormat(0), mMetaOrigLen(0), mPrivate(false)
{ }
virtual ~gfxUserFontData() { }
@ -248,10 +248,21 @@ public:
class UserFontCache {
public:
// Flag passed when caching a font entry, to specify whether the entry
// should persist in the cache or be discardable.
typedef enum {
kDiscardable,
kPersistent
} EntryPersistence;
// Record a loaded user-font in the cache. This requires that the
// font-entry's userFontData has been set up already, as it relies
// on the URI and Principal recorded there.
static void CacheFont(gfxFontEntry *aFontEntry);
// If aPersistence is Persistent, the entry will remain in the cache
// across cacheservice:empty-cache notifications. This is used for
// "preloaded hidden fonts" on FxOS.
static void CacheFont(gfxFontEntry *aFontEntry,
EntryPersistence aPersistence = kDiscardable);
// The given gfxFontEntry is being destroyed, so remove any record that
// refers to it.
@ -298,13 +309,16 @@ public:
nsCOMPtr<nsIPrincipal> mPrincipal; // use nullptr with data: URLs
gfxFontEntry *mFontEntry;
bool mPrivate;
EntryPersistence mPersistence;
Key(nsIURI* aURI, nsIPrincipal* aPrincipal,
gfxFontEntry* aFontEntry, bool aPrivate)
gfxFontEntry* aFontEntry, bool aPrivate,
EntryPersistence aPersistence = kDiscardable)
: mURI(aURI),
mPrincipal(aPrincipal),
mFontEntry(aFontEntry),
mPrivate(aPrivate)
mPrivate(aPrivate),
mPersistence(aPersistence)
{ }
};
@ -317,14 +331,16 @@ public:
: mURI(aKey->mURI),
mPrincipal(aKey->mPrincipal),
mFontEntry(aKey->mFontEntry),
mPrivate(aKey->mPrivate)
mPrivate(aKey->mPrivate),
mPersistence(aKey->mPersistence)
{ }
Entry(const Entry& aOther)
: mURI(aOther.mURI),
mPrincipal(aOther.mPrincipal),
mFontEntry(aOther.mFontEntry),
mPrivate(aOther.mPrivate)
mPrivate(aOther.mPrivate),
mPersistence(aOther.mPersistence)
{ }
~Entry() { }
@ -352,9 +368,14 @@ public:
gfxFontEntry* GetFontEntry() const { return mFontEntry; }
static PLDHashOperator RemoveIfPrivate(Entry* aEntry, void* aUserData);
static PLDHashOperator RemoveIfMatches(Entry* aEntry, void* aUserData);
static PLDHashOperator DisconnectSVG(Entry* aEntry, void* aUserData);
static PLDHashOperator
RemoveUnlessPersistent(Entry* aEntry, void* aUserData);
static PLDHashOperator
RemoveIfPrivate(Entry* aEntry, void* aUserData);
static PLDHashOperator
RemoveIfMatches(Entry* aEntry, void* aUserData);
static PLDHashOperator
DisconnectSVG(Entry* aEntry, void* aUserData);
#ifdef DEBUG_USERFONT_CACHE
static PLDHashOperator DumpEntry(Entry* aEntry, void* aUserData);
@ -377,6 +398,9 @@ public:
// Whether this font was loaded from a private window.
bool mPrivate;
// Whether this entry should survive cache-flushing.
EntryPersistence mPersistence;
};
static nsTHashtable<Entry> *sUserFonts;

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

@ -23,14 +23,14 @@
#define FLOAT32X4_UNARY_FUNCTION_LIST(V) \
V(abs, (Func<Float32x4, Abs<float, Float32x4>, Float32x4>), 1, 0, Abs) \
V(bitsToInt32x4, (FuncConvertBits<Float32x4, Int32x4>), 1, 0, BitsToInt32x4) \
V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Float32x4>), 1, 0, FromInt32x4Bits) \
V(neg, (Func<Float32x4, Neg<float, Float32x4>, Float32x4>), 1, 0, Neg) \
V(not, (CoercedFunc<Float32x4, Int32x4, Not<int32_t, Int32x4>, Float32x4>), 1, 0, Not) \
V(reciprocal, (Func<Float32x4, Rec<float, Float32x4>, Float32x4>), 1, 0, Reciprocal) \
V(reciprocalSqrt, (Func<Float32x4, RecSqrt<float, Float32x4>, Float32x4>), 1, 0, ReciprocalSqrt) \
V(splat, (FuncSplat<Float32x4>), 1, 0, Splat) \
V(sqrt, (Func<Float32x4, Sqrt<float, Float32x4>, Float32x4>), 1, 0, Sqrt) \
V(toInt32x4, (FuncConvert<Float32x4, Int32x4>), 1, 0, ToInt32x4)
V(fromInt32x4, (FuncConvert<Int32x4, Float32x4> ), 1, 0, FromInt32x4)
#define FLOAT32X4_BINARY_FUNCTION_LIST(V) \
V(add, (Func<Float32x4, Add<float, Float32x4>, Float32x4>), 2, 0, Add) \
@ -69,11 +69,11 @@
V(zero, (FuncZero<Int32x4>), 0, 0, Zero)
#define INT32X4_UNARY_FUNCTION_LIST(V) \
V(bitsToFloat32x4, (FuncConvertBits<Int32x4, Float32x4>), 1, 0, BitsToFloat32x4) \
V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int32x4>), 1, 0, FromFloat32x4Bits) \
V(neg, (Func<Int32x4, Neg<int32_t, Int32x4>, Int32x4>), 1, 0, Neg) \
V(not, (Func<Int32x4, Not<int32_t, Int32x4>, Int32x4>), 1, 0, Not) \
V(splat, (FuncSplat<Int32x4>), 0, 0, Splat) \
V(toFloat32x4, (FuncConvert<Int32x4, Float32x4>), 1, 0, ToFloat32x4)
V(fromFloat32x4, (FuncConvert<Float32x4, Int32x4>), 1, 0, FromFloat32x4)
#define INT32X4_BINARY_FUNCTION_LIST(V) \
V(add, (Func<Int32x4, Add<int32_t, Int32x4>, Int32x4>), 2, 0, Add) \

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

@ -143,22 +143,6 @@ function CheckObjectCoercible(v) {
ThrowError(JSMSG_CANT_CONVERT_TO, ToString(v), "object");
}
/********** Various utility functions **********/
/** Returns true iff Type(v) is Object; see ES5 8.6. */
function IsObject(v) {
// Watch out for |typeof null === "object"| as the most obvious pitfall.
// But also be careful of SpiderMonkey's objects that emulate undefined
// (i.e. |document.all|), which have bogus |typeof| behavior. Detect
// these objects using strict equality, which said bogosity doesn't affect.
return (typeof v === "object" && v !== null) ||
typeof v === "function" ||
(typeof v === "undefined" && v !== undefined);
}
/********** Testing code **********/
#ifdef ENABLE_PARALLEL_JS

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

@ -0,0 +1,96 @@
setJitCompilerOption("baseline.usecount.trigger", 10);
setJitCompilerOption("ion.usecount.trigger", 20);
function myCeil(x) {
if(x >= 0) {
var r = Math.abs(x % 1);
if(r != 0)
return (x + 1) - r;
else
return x;
}
else
return x + Math.abs(x % 1);
}
function ceilRangeTest(x) {
if(10 < x) {
if(x < 100) {
assertEq(Math.ceil(x), myCeil(x));
}
}
if(-100 < x) {
if(x < -10) {
assertEq(Math.ceil(x), myCeil(x));
}
}
if (-(4294967296 - 1) < x) {
if(x < 10) {
assertEq(Math.ceil(x), myCeil(x));
}
}
if (-10 < x) {
if(x < 4294967296) {
assertEq(Math.ceil(x), myCeil(x));
}
}
if (-2147483648 < x) {
if(x < 10) {
assertEq(Math.ceil(x), myCeil(x));
}
}
if ((-2147483648 -1) < x) {
if(x < 10) {
assertEq(Math.ceil(x), myCeil(x));
}
}
if (10 < x) {
if(x < 2147483648) {
assertEq(Math.ceil(x), myCeil(x));
}
}
if (10 < x) {
if(x < 2147483649) {
assertEq(Math.ceil(x), myCeil(x));
}
}
if (Math.pow(2,31) < x) {
if(x < Math.pow(2,33)) {
assertEq(Math.ceil(x), myCeil(x));
}
}
}
var a = [Math.pow(2,31), Math.pow(2,33), -4294967296.4, 214748364.2, -50.4, 50.4];
for(var i = 0; i < 10; i++) {
for (var j = 0; j < a.length; j++) {
ceilRangeTest(a[j]);
}
}
for (var j = 0; j < 30; j++) {
(function() {
Math.ceil(1.5);
})()
}
for (var j = 0; j < 30; j++) {
(function() {
Math.ceil(-1.5);
})()
}
for (var j = 0; j < 30; j++) {
(function() {
Math.ceil(-127.5);
})()
}

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

@ -296,6 +296,14 @@ function rconcat_number(i) {
return i;
}
var uceFault_string_length = eval(uneval(uceFault).replace('uceFault', 'uceFault_string_length'));
function rstring_length(i) {
var x = i.toString().length;
if (uceFault_string_length(i) || uceFault_string_length(i))
assertEq(x, 2);
return i;
}
var uceFault_floor_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_floor_number'));
function rfloor_number(i) {
var x = Math.floor(i + 0.1111);
@ -425,6 +433,7 @@ for (i = 0; i < 100; i++) {
rmod_object(i);
rconcat_string(i);
rconcat_number(i);
rstring_length(i);
rfloor_number(i);
rfloor_object(i);
rround_number(i);

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

@ -8484,6 +8484,15 @@ CodeGenerator::visitIsCallable(LIsCallable *ins)
return true;
}
bool
CodeGenerator::visitIsObject(LIsObject *ins)
{
Register output = ToRegister(ins->output());
ValueOperand value = ToValue(ins, LIsObject::Input);
masm.testObjectSet(Assembler::Equal, value, output);
return true;
}
void
CodeGenerator::loadOutermostJSScript(Register reg)
{

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

@ -290,6 +290,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitCallDOMNative(LCallDOMNative *lir);
bool visitCallGetIntrinsicValue(LCallGetIntrinsicValue *lir);
bool visitIsCallable(LIsCallable *lir);
bool visitIsObject(LIsObject *lir);
bool visitHaveSameClass(LHaveSameClass *lir);
bool visitHasClass(LHasClass *lir);
bool visitAsmJSCall(LAsmJSCall *lir);

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

@ -730,6 +730,7 @@ class IonBuilder : public MIRGenerator
// Utility intrinsics.
InliningStatus inlineIsCallable(CallInfo &callInfo);
InliningStatus inlineIsObject(CallInfo &callInfo);
InliningStatus inlineHaveSameClass(CallInfo &callInfo);
InliningStatus inlineToObject(CallInfo &callInfo);
InliningStatus inlineToInteger(CallInfo &callInfo);

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

@ -5789,6 +5789,16 @@ class LIsCallable : public LInstructionHelper<1, 1, 0>
}
};
class LIsObject : public LInstructionHelper<1, BOX_PIECES, 0>
{
public:
LIR_HEADER(IsObject);
static const size_t Input = 0;
MIsObject *mir() const {
return mir_->toIsObject();
}
};
class LHaveSameClass : public LInstructionHelper<1, 2, 1>
{
public:

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

@ -282,6 +282,7 @@
_(SetDOMProperty) \
_(CallDOMNative) \
_(IsCallable) \
_(IsObject) \
_(HaveSameClass) \
_(HasClass) \
_(AsmJSLoadHeap) \

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

@ -7,6 +7,8 @@
#ifndef jit_Label_h
#define jit_Label_h
#include "jit/Ion.h"
namespace js {
namespace jit {
@ -25,10 +27,6 @@ struct LabelBase
LabelBase() : offset_(INVALID_OFFSET), bound_(false)
{ }
LabelBase(const LabelBase &label)
: offset_(label.offset_),
bound_(label.bound_)
{ }
// If the label is bound, all incoming edges have been patched and any
// future incoming edges will be immediately patched.
@ -79,10 +77,20 @@ struct LabelBase
class Label : public LabelBase
{
public:
Label()
{ }
Label(const Label &label) : LabelBase(label)
{ }
~Label()
{
#ifdef DEBUG
// The assertion below doesn't hold if an error occurred.
if (OOM_counter > OOM_maxAllocations)
return;
if (IonContext *context = MaybeGetIonContext()) {
if (context->runtime->hadOutOfMemory())
return;
}
MOZ_ASSERT(!used());
#endif
}
};
// Label's destructor asserts that if it has been used it has also been bound.
@ -90,6 +98,14 @@ class Label : public LabelBase
// trigger this failure innocuously. This Label silences the assertion.
class NonAssertingLabel : public Label
{
public:
~NonAssertingLabel()
{
#ifdef DEBUG
if (used())
bind(0);
#endif
}
};
} } // namespace js::jit

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

@ -622,27 +622,58 @@ ReorderComparison(JSOp op, MDefinition **lhsp, MDefinition **rhsp)
return op;
}
static bool
ShouldReorderCommutative(MDefinition *lhs, MDefinition *rhs, MInstruction *ins)
{
// lhs and rhs are used by the commutative operator.
JS_ASSERT(lhs->hasDefUses());
JS_ASSERT(rhs->hasDefUses());
// Ensure that if there is a constant, then it is in rhs.
if (rhs->isConstant())
return false;
if (lhs->isConstant())
return true;
// Since clobbering binary operations clobber the left operand, prefer a
// non-constant lhs operand with no further uses. To be fully precise, we
// should check whether this is the *last* use, but checking hasOneDefUse()
// is a decent approximation which doesn't require any extra analysis.
bool rhsSingleUse = rhs->hasOneDefUse();
bool lhsSingleUse = lhs->hasOneDefUse();
if (rhsSingleUse) {
if (!lhsSingleUse)
return true;
} else {
if (lhsSingleUse)
return false;
}
// If this is a reduction-style computation, such as
//
// sum = 0;
// for (...)
// sum += ...;
//
// put the phi on the left to promote coalescing. This is fairly specific.
if (rhsSingleUse &&
rhs->isPhi() &&
rhs->block()->isLoopHeader() &&
ins == rhs->toPhi()->getLoopBackedgeOperand())
{
return true;
}
return false;
}
static void
ReorderCommutative(MDefinition **lhsp, MDefinition **rhsp)
ReorderCommutative(MDefinition **lhsp, MDefinition **rhsp, MInstruction *ins)
{
MDefinition *lhs = *lhsp;
MDefinition *rhs = *rhsp;
// Ensure that if there is a constant, then it is in rhs.
// In addition, since clobbering binary operations clobber the left
// operand, prefer a non-constant lhs operand with no further uses.
if (rhs->isConstant())
return;
// lhs and rhs are used by the commutative operator. If they have any
// *other* uses besides, try to reorder to avoid clobbering them. To
// be fully precise, we should check whether this is the *last* use,
// but checking hasOneDefUse() is a decent approximation which doesn't
// require any extra analysis.
JS_ASSERT(lhs->hasDefUses());
JS_ASSERT(rhs->hasDefUses());
if (lhs->isConstant() || (rhs->hasOneDefUse() && !lhs->hasOneDefUse())) {
if (ShouldReorderCommutative(lhs, rhs, ins)) {
*rhsp = lhs;
*lhsp = rhs;
}
@ -828,7 +859,7 @@ LIRGenerator::visitTest(MTest *test)
MDefinition *lhs = opd->getOperand(0);
MDefinition *rhs = opd->getOperand(1);
if (lhs->type() == MIRType_Int32 && rhs->type() == MIRType_Int32) {
ReorderCommutative(&lhs, &rhs);
ReorderCommutative(&lhs, &rhs, test);
return lowerForBitAndAndBranch(new(alloc()) LBitAndAndBranch(ifTrue, ifFalse), test, lhs, rhs);
}
}
@ -1011,7 +1042,7 @@ LIRGenerator::lowerBitOp(JSOp op, MInstruction *ins)
MDefinition *rhs = ins->getOperand(1);
if (lhs->type() == MIRType_Int32 && rhs->type() == MIRType_Int32) {
ReorderCommutative(&lhs, &rhs);
ReorderCommutative(&lhs, &rhs, ins);
return lowerForALU(new(alloc()) LBitOpI(op), ins, lhs, rhs);
}
@ -1228,7 +1259,7 @@ LIRGenerator::visitMinMax(MMinMax *ins)
MDefinition *first = ins->getOperand(0);
MDefinition *second = ins->getOperand(1);
ReorderCommutative(&first, &second);
ReorderCommutative(&first, &second, ins);
if (ins->specialization() == MIRType_Int32) {
LMinMaxI *lir = new(alloc()) LMinMaxI(useRegisterAtStart(first), useRegisterOrConstant(second));
@ -1390,7 +1421,7 @@ LIRGenerator::visitAdd(MAdd *ins)
if (ins->specialization() == MIRType_Int32) {
JS_ASSERT(lhs->type() == MIRType_Int32);
ReorderCommutative(&lhs, &rhs);
ReorderCommutative(&lhs, &rhs, ins);
LAddI *lir = new(alloc()) LAddI;
if (ins->fallible() && !assignSnapshot(lir, Bailout_OverflowInvalidate))
@ -1405,13 +1436,13 @@ LIRGenerator::visitAdd(MAdd *ins)
if (ins->specialization() == MIRType_Double) {
JS_ASSERT(lhs->type() == MIRType_Double);
ReorderCommutative(&lhs, &rhs);
ReorderCommutative(&lhs, &rhs, ins);
return lowerForFPU(new(alloc()) LMathD(JSOP_ADD), ins, lhs, rhs);
}
if (ins->specialization() == MIRType_Float32) {
JS_ASSERT(lhs->type() == MIRType_Float32);
ReorderCommutative(&lhs, &rhs);
ReorderCommutative(&lhs, &rhs, ins);
return lowerForFPU(new(alloc()) LMathF(JSOP_ADD), ins, lhs, rhs);
}
@ -1460,7 +1491,7 @@ LIRGenerator::visitMul(MMul *ins)
if (ins->specialization() == MIRType_Int32) {
JS_ASSERT(lhs->type() == MIRType_Int32);
ReorderCommutative(&lhs, &rhs);
ReorderCommutative(&lhs, &rhs, ins);
// If our RHS is a constant -1 and we don't have to worry about
// overflow, we can optimize to an LNegI.
@ -1471,7 +1502,7 @@ LIRGenerator::visitMul(MMul *ins)
}
if (ins->specialization() == MIRType_Double) {
JS_ASSERT(lhs->type() == MIRType_Double);
ReorderCommutative(&lhs, &rhs);
ReorderCommutative(&lhs, &rhs, ins);
// If our RHS is a constant -1.0, we can optimize to an LNegD.
if (rhs->isConstant() && rhs->toConstant()->value() == DoubleValue(-1.0))
@ -1481,7 +1512,7 @@ LIRGenerator::visitMul(MMul *ins)
}
if (ins->specialization() == MIRType_Float32) {
JS_ASSERT(lhs->type() == MIRType_Float32);
ReorderCommutative(&lhs, &rhs);
ReorderCommutative(&lhs, &rhs, ins);
// We apply the same optimizations as for doubles
if (rhs->isConstant() && rhs->toConstant()->value() == Float32Value(-1.0f))
@ -3429,6 +3460,17 @@ LIRGenerator::visitIsCallable(MIsCallable *ins)
return define(new(alloc()) LIsCallable(useRegister(ins->object())), ins);
}
bool
LIRGenerator::visitIsObject(MIsObject *ins)
{
MDefinition *opd = ins->input();
JS_ASSERT(opd->type() == MIRType_Value);
LIsObject *lir = new(alloc()) LIsObject();
if (!useBoxAtStart(lir, LIsObject::Input, opd))
return false;
return define(lir, ins);
}
bool
LIRGenerator::visitHaveSameClass(MHaveSameClass *ins)
{

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

@ -245,6 +245,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitCallInstanceOf(MCallInstanceOf *ins);
bool visitProfilerStackOp(MProfilerStackOp *ins);
bool visitIsCallable(MIsCallable *ins);
bool visitIsObject(MIsObject *ins);
bool visitHaveSameClass(MHaveSameClass *ins);
bool visitHasClass(MHasClass *ins);
bool visitAsmJSLoadGlobalVar(MAsmJSLoadGlobalVar *ins);

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

@ -163,6 +163,8 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSFunction *target)
return inlineHaveSameClass(callInfo);
if (native == intrinsic_ToObject)
return inlineToObject(callInfo);
if (native == intrinsic_IsObject)
return inlineIsObject(callInfo);
if (native == intrinsic_ToInteger)
return inlineToInteger(callInfo);
if (native == intrinsic_ToString)
@ -1902,6 +1904,21 @@ IonBuilder::inlineIsCallable(CallInfo &callInfo)
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineIsObject(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
return InliningStatus_NotInlined;
if (getInlineReturnType() != MIRType_Boolean)
return InliningStatus_NotInlined;
callInfo.setImplicitlyUsedUnchecked();
MIsObject *isObject = MIsObject::New(alloc(), callInfo.getArg(0));
current->add(isObject);
current->push(isObject);
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineToObject(CallInfo &callInfo)
{

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

@ -909,6 +909,23 @@ MTypeBarrier::printOpcode(FILE *fp) const
getOperand(0)->printName(fp);
}
#ifdef DEBUG
void
MPhi::assertLoopPhi() const
{
// getLoopPredecessorOperand and getLoopBackedgeOperand rely on these
// predecessors being at indices 0 and 1.
MBasicBlock *pred = block()->getPredecessor(0);
MBasicBlock *back = block()->getPredecessor(1);
JS_ASSERT(pred == block()->loopPredecessor());
JS_ASSERT(pred->successorWithPhis() == block());
JS_ASSERT(pred->positionInPhiSuccessor() == 0);
JS_ASSERT(back == block()->backedge());
JS_ASSERT(back->successorWithPhis() == block());
JS_ASSERT(back->positionInPhiSuccessor() == 1);
}
#endif
void
MPhi::removeOperand(size_t index)
{
@ -3065,6 +3082,19 @@ MSqrt::trySpecializeFloat32(TempAllocator &alloc) {
setPolicyType(MIRType_Float32);
}
MDefinition *
MBoundsCheck::foldsTo(TempAllocator &alloc)
{
if (index()->isConstant() && length()->isConstant()) {
uint32_t len = length()->toConstant()->value().toInt32();
uint32_t idx = index()->toConstant()->value().toInt32();
if (idx + uint32_t(minimum()) < len && idx + uint32_t(maximum()) < len)
return index();
}
return this;
}
bool
jit::ElementAccessIsDenseNative(MDefinition *obj, MDefinition *id)
{

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

@ -5026,6 +5026,28 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineListNode<MPhi>
}
bool specializeType();
#ifdef DEBUG
// Assert that this is a phi in a loop header with a unique predecessor and
// a unique backedge.
void assertLoopPhi() const;
#else
void assertLoopPhi() const {}
#endif
// Assuming this phi is in a loop header with a unique loop entry, return
// the phi operand along the loop entry.
MDefinition *getLoopPredecessorOperand() const {
assertLoopPhi();
return getOperand(0);
}
// Assuming this phi is in a loop header with a unique loop entry, return
// the phi operand along the loop backedge.
MDefinition *getLoopBackedgeOperand() const {
assertLoopPhi();
return getOperand(1);
}
// Whether this phi's type already includes information for def.
bool typeIncludes(MDefinition *def);
@ -6270,6 +6292,7 @@ class MBoundsCheck
void setMaximum(int32_t n) {
maximum_ = n;
}
MDefinition *foldsTo(TempAllocator &alloc);
bool congruentTo(const MDefinition *ins) const {
if (!ins->isBoundsCheck())
return false;
@ -8897,6 +8920,11 @@ class MStringLength
}
void computeRange(TempAllocator &alloc);
bool writeRecoverData(CompactBufferWriter &writer) const;
bool canRecoverOnBailout() const {
return true;
}
};
// Inlined version of Math.floor().
@ -8988,6 +9016,7 @@ class MCeil
bool congruentTo(const MDefinition *ins) const {
return congruentIfOperandsEqual(ins);
}
void computeRange(TempAllocator &alloc);
};
// Inlined version of Math.round().
@ -10093,7 +10122,32 @@ class MIsCallable
static MIsCallable *New(TempAllocator &alloc, MDefinition *obj) {
return new(alloc) MIsCallable(obj);
}
TypePolicy *typePolicy() {
return this;
}
MDefinition *object() const {
return getOperand(0);
}
AliasSet getAliasSet() const {
return AliasSet::None();
}
};
class MIsObject
: public MUnaryInstruction,
public BoxInputsPolicy
{
explicit MIsObject(MDefinition *object)
: MUnaryInstruction(object)
{
setResultType(MIRType_Boolean);
setMovable();
}
public:
INSTRUCTION_HEADER(IsObject);
static MIsObject *New(TempAllocator &alloc, MDefinition *obj) {
return new(alloc) MIsObject(obj);
}
TypePolicy *typePolicy() {
return this;
}

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

@ -197,6 +197,7 @@ namespace jit {
_(GetDOMMember) \
_(SetDOMProperty) \
_(IsCallable) \
_(IsObject) \
_(HaveSameClass) \
_(HasClass) \
_(AsmJSNeg) \

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

@ -306,6 +306,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
SAFE_OP(FunctionDispatch)
SAFE_OP(TypeObjectDispatch)
SAFE_OP(IsCallable)
SAFE_OP(IsObject)
SAFE_OP(HaveSameClass)
SAFE_OP(HasClass)
UNSAFE_OP(EffectiveAddress)

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

@ -563,7 +563,7 @@ Range::setDouble(double l, double h)
hasInt32LowerBound_ = false;
}
if (h >= INT32_MIN && h <= INT32_MAX) {
upper_ = int32_t(ceil(h));
upper_ = int32_t(::ceil(h));
hasInt32UpperBound_ = true;
} else {
upper_ = INT32_MAX;
@ -979,6 +979,25 @@ Range::floor(TempAllocator &alloc, const Range *op)
return copy;
}
Range *
Range::ceil(TempAllocator &alloc, const Range *op)
{
Range *copy = new(alloc) Range(*op);
// We need to refine max_exponent_ because ceil may have incremented the int value.
// If we have got int32 bounds defined, just deduce it using the defined bounds.
// Else we can just increment its value,
// as we are looking to maintain an over estimation.
if (copy->hasInt32Bounds())
copy->max_exponent_ = copy->exponentImpliedByInt32Bounds();
else if (copy->max_exponent_ < MaxFiniteExponent)
copy->max_exponent_++;
copy->canHaveFractionalPart_ = false;
copy->assertInvariants();
return copy;
}
bool
Range::negativeZeroMul(const Range *lhs, const Range *rhs)
{
@ -1207,6 +1226,13 @@ MFloor::computeRange(TempAllocator &alloc)
setRange(Range::floor(alloc, &other));
}
void
MCeil::computeRange(TempAllocator &alloc)
{
Range other(getOperand(0));
setRange(Range::ceil(alloc, &other));
}
void
MMinMax::computeRange(TempAllocator &alloc)
{
@ -1697,13 +1723,13 @@ RangeAnalysis::analyzeLoopIterationCount(MBasicBlock *header,
// The first operand of the phi should be the lhs' value at the start of
// the first executed iteration, and not a value written which could
// replace the second operand below during the middle of execution.
MDefinition *lhsInitial = lhs.term->toPhi()->getOperand(0);
MDefinition *lhsInitial = lhs.term->toPhi()->getLoopPredecessorOperand();
if (lhsInitial->block()->isMarked())
return nullptr;
// The second operand of the phi should be a value written by an add/sub
// in every loop iteration, i.e. in a block which dominates the backedge.
MDefinition *lhsWrite = lhs.term->toPhi()->getOperand(1);
MDefinition *lhsWrite = lhs.term->toPhi()->getLoopBackedgeOperand();
if (lhsWrite->isBeta())
lhsWrite = lhsWrite->getOperand(0);
if (!lhsWrite->isAdd() && !lhsWrite->isSub())
@ -1783,17 +1809,11 @@ RangeAnalysis::analyzeLoopPhi(MBasicBlock *header, LoopIterationBound *loopBound
JS_ASSERT(phi->numOperands() == 2);
MBasicBlock *preLoop = header->loopPredecessor();
JS_ASSERT(!preLoop->isMarked() && preLoop->successorWithPhis() == header);
MBasicBlock *backedge = header->backedge();
JS_ASSERT(backedge->isMarked() && backedge->successorWithPhis() == header);
MDefinition *initial = phi->getOperand(preLoop->positionInPhiSuccessor());
MDefinition *initial = phi->getLoopPredecessorOperand();
if (initial->block()->isMarked())
return;
SimpleLinearSum modified = ExtractLinearSum(phi->getOperand(backedge->positionInPhiSuccessor()));
SimpleLinearSum modified = ExtractLinearSum(phi->getLoopBackedgeOperand());
if (modified.term != phi || modified.constant == 0)
return;

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

@ -415,6 +415,7 @@ class Range : public TempObject {
static Range *min(TempAllocator &alloc, const Range *lhs, const Range *rhs);
static Range *max(TempAllocator &alloc, const Range *lhs, const Range *rhs);
static Range *floor(TempAllocator &alloc, const Range *op);
static Range *ceil(TempAllocator &alloc, const Range *op);
static bool negativeZeroMul(const Range *lhs, const Range *rhs);

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

@ -510,6 +510,31 @@ RConcat::recover(JSContext *cx, SnapshotIterator &iter) const
return true;
}
RStringLength::RStringLength(CompactBufferReader &reader)
{}
bool
RStringLength::recover(JSContext *cx, SnapshotIterator &iter) const
{
RootedValue operand(cx, iter.read());
RootedValue result(cx);
MOZ_ASSERT(!operand.isObject());
if (!js::GetLengthProperty(operand, &result))
return false;
iter.storeInstructionResult(result);
return true;
}
bool
MStringLength::writeRecoverData(CompactBufferWriter &writer) const
{
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_StringLength));
return true;
}
bool
MFloor::writeRecoverData(CompactBufferWriter &writer) const
{

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

@ -31,6 +31,7 @@ namespace jit {
_(Div) \
_(Mod) \
_(Concat) \
_(StringLength) \
_(Floor) \
_(Round) \
_(CharCodeAt) \
@ -274,6 +275,18 @@ class RConcat MOZ_FINAL : public RInstruction
bool recover(JSContext *cx, SnapshotIterator &iter) const;
};
class RStringLength MOZ_FINAL : public RInstruction
{
public:
RINSTRUCTION_HEADER_(StringLength)
virtual uint32_t numOperands() const {
return 1;
}
bool recover(JSContext *cx, SnapshotIterator &iter) const;
};
class RFloor MOZ_FINAL : public RInstruction
{
public:

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

@ -1508,6 +1508,12 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
cond = testNull(cond, value);
emitSet(cond, dest);
}
void testObjectSet(Condition cond, const ValueOperand &value, Register dest) {
cond = testObject(cond, value);
emitSet(cond, dest);
}
void testUndefinedSet(Condition cond, const ValueOperand &value, Register dest) {
cond = testUndefined(cond, value);
emitSet(cond, dest);

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

@ -2298,6 +2298,12 @@ MacroAssemblerMIPSCompat::branchTestObject(Condition cond, const BaseIndex &src,
ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_OBJECT), label, cond);
}
void
MacroAssemblerMIPSCompat::testObjectSet(Condition cond, const ValueOperand &value, Register dest)
{
MOZ_ASSERT(cond == Equal || cond == NotEqual);
ma_cmp_set(dest, value.typeReg(), ImmType(JSVAL_TYPE_OBJECT), cond);
}
void
MacroAssemblerMIPSCompat::branchTestString(Condition cond, const ValueOperand &value, Label *label)

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

@ -686,6 +686,7 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
void branchTestObject(Condition cond, const ValueOperand &value, Label *label);
void branchTestObject(Condition cond, Register tag, Label *label);
void branchTestObject(Condition cond, const BaseIndex &src, Label *label);
void testObjectSet(Condition cond, const ValueOperand &value, Register dest);
void branchTestString(Condition cond, const ValueOperand &value, Label *label);
void branchTestString(Condition cond, Register tag, Label *label);

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

@ -1029,6 +1029,12 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
cond = testNull(cond, value);
emitSet(cond, dest);
}
void testObjectSet(Condition cond, const ValueOperand &value, Register dest) {
cond = testObject(cond, value);
emitSet(cond, dest);
}
void testUndefinedSet(Condition cond, const ValueOperand &value, Register dest) {
cond = testUndefined(cond, value);
emitSet(cond, dest);

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

@ -486,6 +486,12 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
cond = testNull(cond, value);
emitSet(cond, dest);
}
void testObjectSet(Condition cond, const ValueOperand &value, Register dest) {
cond = testObject(cond, value);
emitSet(cond, dest);
}
void testUndefinedSet(Condition cond, const ValueOperand &value, Register dest) {
cond = testUndefined(cond, value);
emitSet(cond, dest);

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

@ -480,6 +480,11 @@ js::Atomize(ExclusiveContext *cx, const char *bytes, size_t length, InternBehavi
if (!JSString::validateLength(cx, length))
return nullptr;
if (EnableLatin1Strings) {
const Latin1Char *chars = reinterpret_cast<const Latin1Char*>(bytes);
return AtomizeAndCopyChars(cx, chars, length, ib);
}
static const unsigned ATOMIZE_BUF_MAX = 32;
if (length < ATOMIZE_BUF_MAX) {
/*

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

@ -1007,6 +1007,7 @@ class ContextAllocPolicy
/* Exposed intrinsics so that Ion may inline them. */
bool intrinsic_ToObject(JSContext *cx, unsigned argc, Value *vp);
bool intrinsic_IsObject(JSContext *cx, unsigned argc, Value *vp);
bool intrinsic_ToInteger(JSContext *cx, unsigned argc, Value *vp);
bool intrinsic_ToString(JSContext *cx, unsigned argc, Value *vp);
bool intrinsic_IsCallable(JSContext *cx, unsigned argc, Value *vp);

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

@ -308,7 +308,7 @@ CopyStringPure(JSContext *cx, JSString *str)
if (!str->asRope().copyTwoByteCharsZ(cx, copiedChars))
return nullptr;
return NewString<CanGC>(cx, copiedChars.forget(), len);
return NewStringDontDeflate<CanGC>(cx, copiedChars.forget(), len);
}
bool

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

@ -1540,7 +1540,6 @@ ScriptedDirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject
}
// step 22
// FIXME: This is incorrect with respect to [[Origin]]. See bug 999156.
resultDesc.populatePropertyDescriptor(proxy, desc);
return true;
}
@ -1567,8 +1566,7 @@ ScriptedDirectProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, Ha
if (trap.isUndefined())
return DirectProxyHandler::defineProperty(cx, proxy, id, desc);
// step 8-9, with 9 blatantly defied.
// FIXME: This is incorrect with respect to [[Origin]]. See bug 601379.
// step 8-9
RootedValue descObj(cx);
if (!NewPropertyDescriptorObject(cx, desc, &descObj))
return false;

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

@ -719,7 +719,7 @@ ToLowerCase(JSContext *cx, JSLinearString *str)
newChars[length] = 0;
}
JSString *res = NewString<CanGC>(cx, newChars.get(), length);
JSString *res = NewStringDontDeflate<CanGC>(cx, newChars.get(), length);
if (!res)
return nullptr;
@ -4205,16 +4205,10 @@ js::str_fromCharCode_one_arg(JSContext *cx, HandleValue code, MutableHandleValue
return true;
}
jschar *chars = cx->pod_malloc<jschar>(2);
if (!chars)
jschar c = jschar(ucode);
JSString *str = NewStringCopyN<CanGC>(cx, &c, 1);
if (!str)
return false;
chars[0] = jschar(ucode);
chars[1] = 0;
JSString *str = NewString<CanGC>(cx, chars, 1);
if (!str) {
js_free(chars);
return false;
}
rval.setString(str);
return true;
@ -4281,35 +4275,6 @@ js_InitStringClass(JSContext *cx, HandleObject obj)
return proto;
}
template <AllowGC allowGC, typename CharT>
JSFlatString *
js::NewString(ThreadSafeContext *cx, CharT *chars, size_t length)
{
if (length == 1) {
jschar c = chars[0];
if (StaticStrings::hasUnit(c)) {
// Free |chars| because we're taking possession of it, but it's no
// longer needed because we use the static string instead.
js_free(chars);
return cx->staticStrings().getUnit(c);
}
}
return JSFlatString::new_<allowGC>(cx, chars, length);
}
template JSFlatString *
js::NewString<CanGC>(ThreadSafeContext *cx, jschar *chars, size_t length);
template JSFlatString *
js::NewString<NoGC>(ThreadSafeContext *cx, jschar *chars, size_t length);
template JSFlatString *
js::NewString<CanGC>(ThreadSafeContext *cx, Latin1Char *chars, size_t length);
template JSFlatString *
js::NewString<NoGC>(ThreadSafeContext *cx, Latin1Char *chars, size_t length);
JSLinearString *
js::NewDependentString(JSContext *cx, JSString *baseArg, size_t start, size_t length)
{
@ -4415,7 +4380,7 @@ NewStringDeflated(ThreadSafeContext *cx, const jschar *s, size_t n)
}
news[n] = '\0';
JSFlatString *str = NewString<allowGC>(cx, news.get(), n);
JSFlatString *str = JSFlatString::new_<allowGC>(cx, news.get(), n);
if (!str)
return nullptr;
@ -4430,6 +4395,72 @@ NewStringDeflated(ThreadSafeContext *cx, const Latin1Char *s, size_t n)
MOZ_CRASH("Shouldn't be called for Latin1 chars");
}
template <AllowGC allowGC, typename CharT>
JSFlatString *
js::NewStringDontDeflate(ThreadSafeContext *cx, CharT *chars, size_t length)
{
if (length == 1) {
jschar c = chars[0];
if (StaticStrings::hasUnit(c)) {
// Free |chars| because we're taking possession of it, but it's no
// longer needed because we use the static string instead.
js_free(chars);
return cx->staticStrings().getUnit(c);
}
}
return JSFlatString::new_<allowGC>(cx, chars, length);
}
template JSFlatString *
js::NewStringDontDeflate<CanGC>(ThreadSafeContext *cx, jschar *chars, size_t length);
template JSFlatString *
js::NewStringDontDeflate<NoGC>(ThreadSafeContext *cx, jschar *chars, size_t length);
template JSFlatString *
js::NewStringDontDeflate<CanGC>(ThreadSafeContext *cx, Latin1Char *chars, size_t length);
template JSFlatString *
js::NewStringDontDeflate<NoGC>(ThreadSafeContext *cx, Latin1Char *chars, size_t length);
template <AllowGC allowGC, typename CharT>
JSFlatString *
js::NewString(ThreadSafeContext *cx, CharT *chars, size_t length)
{
if (IsSame<CharT, jschar>::value && CanStoreCharsAsLatin1(chars, length)) {
if (length == 1) {
jschar c = chars[0];
if (StaticStrings::hasUnit(c)) {
js_free(chars);
return cx->staticStrings().getUnit(c);
}
}
JSFlatString *s = NewStringDeflated<allowGC>(cx, chars, length);
if (!s)
return nullptr;
// Free |chars| because we're taking possession of it but not using it.
js_free(chars);
return s;
}
return NewStringDontDeflate<allowGC>(cx, chars, length);
}
template JSFlatString *
js::NewString<CanGC>(ThreadSafeContext *cx, jschar *chars, size_t length);
template JSFlatString *
js::NewString<NoGC>(ThreadSafeContext *cx, jschar *chars, size_t length);
template JSFlatString *
js::NewString<CanGC>(ThreadSafeContext *cx, Latin1Char *chars, size_t length);
template JSFlatString *
js::NewString<NoGC>(ThreadSafeContext *cx, Latin1Char *chars, size_t length);
namespace js {
template <AllowGC allowGC, typename CharT>
@ -4447,7 +4478,7 @@ NewStringCopyNDontDeflate(ThreadSafeContext *cx, const CharT *s, size_t n)
PodCopy(news.get(), s, n);
news[n] = 0;
JSFlatString *str = NewString<allowGC>(cx, news.get(), n);
JSFlatString *str = JSFlatString::new_<allowGC>(cx, news.get(), n);
if (!str)
return nullptr;
@ -4465,7 +4496,7 @@ NewStringCopyNDontDeflate(ThreadSafeContext *cx, const CharT *s, size_t n)
CopyCharsMaybeInflate(news.get(), s, n);
news[n] = 0;
JSFlatString *str = NewString<allowGC>(cx, news.get(), n);
JSFlatString *str = JSFlatString::new_<allowGC>(cx, news.get(), n);
if (!str)
return nullptr;

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

@ -131,6 +131,11 @@ template <js::AllowGC allowGC, typename CharT>
extern JSFlatString *
NewString(js::ThreadSafeContext *cx, CharT *chars, size_t length);
/* Like NewString, but doesn't try to deflate to Latin1. */
template <js::AllowGC allowGC, typename CharT>
extern JSFlatString *
NewStringDontDeflate(js::ThreadSafeContext *cx, CharT *chars, size_t length);
extern JSLinearString *
NewDependentString(JSContext *cx, JSString *base, size_t start, size_t length);

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

@ -13,14 +13,14 @@ var summary = 'Handles';
var int32x4 = SIMD.int32x4;
var a = int32x4((4294967295), 200, 300, 400);
var c = SIMD.int32x4.bitsToFloat32x4(a);
var c = SIMD.float32x4.fromInt32x4Bits(a);
// NaN canonicalization occurs when extracting out x lane:
assertEq(c.x, NaN);
// but underlying bits are faithfully transmitted
// (though reinterpreted as a signed integer):
var d = SIMD.float32x4.bitsToInt32x4(c);
var d = SIMD.int32x4.fromFloat32x4Bits(c);
assertEq(d.x, -1);
reportCompare(true, true);

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

@ -3,7 +3,7 @@ var BUGNUMBER = 946042;
var float32x4 = SIMD.float32x4;
var int32x4 = SIMD.int32x4;
var summary = 'int32x4 toFloat32x4';
var summary = 'float32x4 fromInt32x4';
function test() {
print(BUGNUMBER + ": " + summary);
@ -11,7 +11,7 @@ function test() {
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(1, 2, 3, 4);
var c = SIMD.int32x4.toFloat32x4(a);
var c = SIMD.float32x4.fromInt32x4(a);
assertEq(c.x, 1);
assertEq(c.y, 2);
assertEq(c.z, 3);

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

@ -3,7 +3,7 @@ var BUGNUMBER = 946042;
var float32x4 = SIMD.float32x4;
var int32x4 = SIMD.int32x4;
var summary = 'int32x4 bitsToFloat32x4';
var summary = 'float32x4 fromInt32x4Bits';
function test() {
print(BUGNUMBER + ": " + summary);
@ -11,7 +11,7 @@ function test() {
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = int32x4(100, 200, 300, 400);
var c = SIMD.int32x4.bitsToFloat32x4(a);
var c = SIMD.float32x4.fromInt32x4Bits(a);
assertEq(c.x, 1.401298464324817e-43);
assertEq(c.y, 2.802596928649634e-43);
assertEq(c.z, 4.203895392974451e-43);

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

@ -3,7 +3,7 @@ var BUGNUMBER = 946042;
var float32x4 = SIMD.float32x4;
var int32x4 = SIMD.int32x4;
var summary = 'float32x4 toInt32x4';
var summary = 'int32x4 fromFloat32x4';
function test() {
print(BUGNUMBER + ": " + summary);
@ -11,7 +11,7 @@ function test() {
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1.1, 2.2, 3.3, 4.6);
var c = SIMD.float32x4.toInt32x4(a);
var c = SIMD.int32x4.fromFloat32x4(a);
assertEq(c.x, 1);
assertEq(c.y, 2);
assertEq(c.z, 3);

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

@ -3,7 +3,7 @@ var BUGNUMBER = 946042;
var float32x4 = SIMD.float32x4;
var int32x4 = SIMD.int32x4;
var summary = 'float32x4 bitsToInt32x4';
var summary = 'int32x4 fromFloat32x4Bits';
function test() {
print(BUGNUMBER + ": " + summary);
@ -11,7 +11,7 @@ function test() {
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1, 2, 3, 4);
var c = SIMD.float32x4.bitsToInt32x4(a);
var c = SIMD.int32x4.fromFloat32x4Bits(a);
assertEq(c.x, 1065353216);
assertEq(c.y, 1073741824);
assertEq(c.z, 1077936128);

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

@ -63,6 +63,16 @@ js::intrinsic_ToObject(JSContext *cx, unsigned argc, Value *vp)
return true;
}
bool
js::intrinsic_IsObject(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
Value val = args[0];
bool isObject = val.isObject();
args.rval().setBoolean(isObject);
return true;
}
bool
js::intrinsic_ToInteger(JSContext *cx, unsigned argc, Value *vp)
{
@ -766,6 +776,7 @@ intrinsic_RuntimeDefaultLocale(JSContext *cx, unsigned argc, Value *vp)
static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("ToObject", intrinsic_ToObject, 1,0),
JS_FN("IsObject", intrinsic_IsObject, 1,0),
JS_FN("ToInteger", intrinsic_ToInteger, 1,0),
JS_FN("ToString", intrinsic_ToString, 1,0),
JS_FN("IsCallable", intrinsic_IsCallable, 1,0),

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

@ -77,7 +77,7 @@ FinishStringFlat(ExclusiveContext *cx, StringBuffer &sb, Buffer &cb)
if (!buf)
return nullptr;
JSFlatString *str = NewString<CanGC>(cx, buf.get(), len);
JSFlatString *str = NewStringDontDeflate<CanGC>(cx, buf.get(), len);
if (!str)
return nullptr;

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

@ -90,7 +90,7 @@ LOCAL_INCLUDES += [
'/js/ipc',
'/layout/base',
'/layout/style',
'/xpcom/reflect/xptinfo/src',
'/xpcom/reflect/xptinfo',
]
if CONFIG['MOZ_B2G_BT']:

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

@ -4137,6 +4137,8 @@ PresShell::FlushPendingNotifications(mozilla::ChangesToFlush aFlush)
NS_ASSERTION(!isSafeToFlush || mViewManager, "Must have view manager");
// Make sure the view manager stays alive.
nsRefPtr<nsViewManager> viewManagerDeathGrip = mViewManager;
bool didStyleFlush = false;
bool didLayoutFlush = false;
if (isSafeToFlush && mViewManager) {
// Processing pending notifications can kill us, and some callers only
// hold weak refs when calling FlushPendingNotifications(). :(
@ -4226,6 +4228,8 @@ PresShell::FlushPendingNotifications(mozilla::ChangesToFlush aFlush)
mPresContext->RestyleManager()->ProcessPendingRestyles();
}
didStyleFlush = true;
// There might be more pending constructors now, but we're not going to
// worry about them. They can't be triggered during reflow, so we should
@ -4233,6 +4237,7 @@ PresShell::FlushPendingNotifications(mozilla::ChangesToFlush aFlush)
if (flushType >= (mSuppressInterruptibleReflows ? Flush_Layout : Flush_InterruptibleLayout) &&
!mIsDestroying) {
didLayoutFlush = true;
mFrameConstructor->RecalcQuotesAndCounters();
mViewManager->FlushDelayedResize(true);
if (ProcessReflowCommands(flushType < Flush_Layout) && mContentToScrollTo) {
@ -4243,11 +4248,6 @@ PresShell::FlushPendingNotifications(mozilla::ChangesToFlush aFlush)
mContentToScrollTo = nullptr;
}
}
} else if (!mIsDestroying && mSuppressInterruptibleReflows &&
flushType == Flush_InterruptibleLayout) {
// We suppressed this flush, but the document thinks it doesn't
// need to flush anymore. Let it know what's really going on.
mDocument->SetNeedLayoutFlush();
}
if (flushType >= Flush_Layout) {
@ -4256,6 +4256,19 @@ PresShell::FlushPendingNotifications(mozilla::ChangesToFlush aFlush)
}
}
}
if (!didStyleFlush && flushType >= Flush_Style && !mIsDestroying) {
mDocument->SetNeedStyleFlush();
}
if (!didLayoutFlush && !mIsDestroying &&
(flushType >=
(mSuppressInterruptibleReflows ? Flush_Layout : Flush_InterruptibleLayout))) {
// We suppressed this flush due to mSuppressInterruptibleReflows or
// !isSafeToFlush, but the document thinks it doesn't
// need to flush anymore. Let it know what's really going on.
mDocument->SetNeedLayoutFlush();
}
}
void

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

@ -180,22 +180,22 @@ public:
// mContentArea.BSize is not NS_UNCONSTRAINEDSIZE; otherwise
// coordinate overflow may occur.
mozilla::LogicalRect mContentArea;
nscoord ContentIStart() {
nscoord ContentIStart() const {
return mContentArea.IStart(mReflowState.GetWritingMode());
}
nscoord ContentISize() {
nscoord ContentISize() const {
return mContentArea.ISize(mReflowState.GetWritingMode());
}
nscoord ContentIEnd() {
nscoord ContentIEnd() const {
return mContentArea.IEnd(mReflowState.GetWritingMode());
}
nscoord ContentBStart() {
nscoord ContentBStart() const {
return mContentArea.BStart(mReflowState.GetWritingMode());
}
nscoord ContentBSize() {
nscoord ContentBSize() const {
return mContentArea.BSize(mReflowState.GetWritingMode());
}
nscoord ContentBEnd() {
nscoord ContentBEnd() const {
return mContentArea.BEnd(mReflowState.GetWritingMode());
}
nscoord mContainerWidth;

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

@ -8,7 +8,7 @@ $6 = (nsIContent * const) 0x0
(gdb) bt 3
#0 0xb6457185 in nsIContent::SetAttr (this=0x0, aNameSpaceID=0, aName=0xb0cb064c, aValue=..., aNotify=1) at ../../dist/include/nsIContent.h:285
#1 0xb6b72072 in nsTreeColumns::RestoreNaturalOrder (this=0xaaf83cc0) at layout/xul/base/src/tree/src/nsTreeColumns.cpp:605
#2 0xb736c76f in NS_InvokeByIndex_P () at xpcom/reflect/xptcall/src/md/unix/xptcinvoke_gcc_x86_unix.cpp:69
#2 0xb736c76f in NS_InvokeByIndex_P () at xpcom/reflect/xptcall/md/unix/xptcinvoke_gcc_x86_unix.cpp:69
(More stack frames follow...)
(gdb) frame 1
#1 0xb6b72072 in nsTreeColumns::RestoreNaturalOrder (this=0xaaf83cc0) at layout/xul/base/src/tree/src/nsTreeColumns.cpp:605

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

@ -5,7 +5,7 @@ Program received signal SIGSEGV, Segmentation fault.
610 mTree->Invalidate();
(gdb) bt 3
#0 0xb6b720a6 in nsTreeColumns::RestoreNaturalOrder (this=0xa947a580) at layout/xul/base/src/tree/src/nsTreeColumns.cpp:610
#1 0xb736c76f in NS_InvokeByIndex_P () at xpcom/reflect/xptcall/src/md/unix/xptcinvoke_gcc_x86_unix.cpp:69
#1 0xb736c76f in NS_InvokeByIndex_P () at xpcom/reflect/xptcall/md/unix/xptcinvoke_gcc_x86_unix.cpp:69
#2 0xb6171901 in XPCWrappedNative::CallMethod (ccx=..., mode=XPCWrappedNative::CALL_METHOD)
at js/src/xpconnect/src/xpcwrappednative.cpp:2722
(More stack frames follow...)

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

@ -7,7 +7,7 @@ Program received signal SIGSEGV, Segmentation fault.
571 boxObject->GetElement(getter_AddRefs(element));
(gdb) bt 3
#0 0xb6b7463a in nsTreeContentView::SetTree (this=0xb0ba2510, aTree=0xaaecece0) at layout/xul/base/src/tree/src/nsTreeContentView.cpp:571
#1 0xb736c76f in NS_InvokeByIndex_P () at xpcom/reflect/xptcall/src/md/unix/xptcinvoke_gcc_x86_unix.cpp:69
#1 0xb736c76f in NS_InvokeByIndex_P () at xpcom/reflect/xptcall/md/unix/xptcinvoke_gcc_x86_unix.cpp:69
#2 0xb6171901 in XPCWrappedNative::CallMethod (ccx=..., mode=XPCWrappedNative::CALL_METHOD)
at js/src/xpconnect/src/xpcwrappednative.cpp:2722
(More stack frames follow...)

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

@ -14,21 +14,21 @@ Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, int buffer_size, unsigne
/* buffer_size:
* 1 - int8_t;
* 2 - int16_t;
* 3 - int32_t;
* 4 - int64_t;
* 4 - int32_t;
* 8 - int64_t;
*/
long i;
for(i = len-1; i >= 0; i--) {
unsigned char x;
if (buffer_size == 1) {
x = (char)(*(const int8_t *)buffer_in >> (i * 8));
} else if (buffer_size == 2) {
} else if (buffer_size == 2) {
x = (char)(*(const int16_t *)buffer_in >> (i * 8));
} else if (buffer_size == 4) {
} else if (buffer_size == 4) {
x = (char)(*(const int32_t *)buffer_in >> (i * 8));
} else if (buffer_size == 8) {
} else if (buffer_size == 8) {
x = (char)(*(const int64_t *)buffer_in >> (i * 8));
}
}
Ebml_Write(glob, &x, 1);
}
}
@ -65,7 +65,7 @@ void Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, unsigned long clas
Ebml_WriteID(glob, class_id);
ebmlLoc->offset = glob->offset;
// todo this is always taking 8 bytes, this may need later optimization
Ebml_Serialize(glob, (void *)&unknownLen,sizeof(unknownLen), 8); // this is a key that says lenght unknown
Ebml_Serialize(glob, (void *)&unknownLen,sizeof(unknownLen), 8); // this is a key that says length unknown
}
void Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc) {

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

@ -0,0 +1,41 @@
diff --git a/media/libmkv/EbmlBufferWriter.c b/media/libmkv/EbmlBufferWriter.c
index 8c26e80..5925504 100644
--- a/media/libmkv/EbmlBufferWriter.c
+++ b/media/libmkv/EbmlBufferWriter.c
@@ -14,21 +14,21 @@ Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, int buffer_size, unsigne
/* buffer_size:
* 1 - int8_t;
* 2 - int16_t;
- * 3 - int32_t;
- * 4 - int64_t;
+ * 4 - int32_t;
+ * 8 - int64_t;
*/
long i;
for(i = len-1; i >= 0; i--) {
unsigned char x;
if (buffer_size == 1) {
x = (char)(*(const int8_t *)buffer_in >> (i * 8));
- } else if (buffer_size == 2) {
+ } else if (buffer_size == 2) {
x = (char)(*(const int16_t *)buffer_in >> (i * 8));
- } else if (buffer_size == 4) {
+ } else if (buffer_size == 4) {
x = (char)(*(const int32_t *)buffer_in >> (i * 8));
- } else if (buffer_size == 8) {
+ } else if (buffer_size == 8) {
x = (char)(*(const int64_t *)buffer_in >> (i * 8));
- }
+ }
Ebml_Write(glob, &x, 1);
}
}
@@ -65,7 +65,7 @@ void Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, unsigned long clas
Ebml_WriteID(glob, class_id);
ebmlLoc->offset = glob->offset;
// todo this is always taking 8 bytes, this may need later optimization
- Ebml_Serialize(glob, (void *)&unknownLen,sizeof(unknownLen), 8); // this is a key that says lenght unknown
+ Ebml_Serialize(glob, (void *)&unknownLen,sizeof(unknownLen), 8); // this is a key that says length unknown
}
void Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc) {

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

@ -36,3 +36,4 @@ patch -p1 < gecko_fix.patch
patch -p1 < const_fix.patch
patch -p3 < bock_fix.patch
patch -p3 < bug970774.patch
patch -p3 < cleanup.patch

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

@ -102,8 +102,6 @@ add_test(function test_safebrowsing_update() {
var streamUpdater = Cc["@mozilla.org/url-classifier/streamupdater;1"]
.getService(Ci.nsIUrlClassifierStreamUpdater);
streamUpdater.updateUrl = URL + safebrowsingUpdatePath;
function onSuccess() {
run_next_test();
}
@ -115,7 +113,7 @@ add_test(function test_safebrowsing_update() {
}
streamUpdater.downloadUpdates("test-phish-simple,test-malware-simple", "",
onSuccess, onUpdateError, onDownloadError);
URL + safebrowsingUpdatePath, onSuccess, onUpdateError, onDownloadError);
});
add_test(function test_non_safebrowsing_cookie() {

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

@ -7,6 +7,7 @@ import datetime
import os
import shutil
import subprocess
import sys
import tempfile
import time
@ -17,7 +18,7 @@ from .emulator_battery import EmulatorBattery
from .emulator_geo import EmulatorGeo
from .emulator_screen import EmulatorScreen
from ..utils import uses_marionette
from ..errors import TimeoutException, ScriptTimeoutException
from ..errors import TimeoutException
class ArchContext(object):
def __init__(self, arch, context, binary=None):
@ -207,7 +208,13 @@ waitFor(
function() { return isSystemMessageListenerReady(); }
);
""")
except ScriptTimeoutException:
except:
# Look for ScriptTimeoutException this way to avoid a
# dependency on the marionette python client.
exc_name = sys.exc_info()[0].__name__
if exc_name != 'ScriptTimeoutException':
raise
print 'timed out'
# We silently ignore the timeout if it occurs, since
# isSystemMessageListenerReady() isn't available on

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

@ -11,6 +11,3 @@ class RunnerNotStartedError(RunnerException):
class TimeoutException(RunnerException):
"""Raised on timeout waiting for targets to start."""
class ScriptTimeoutException(RunnerException):
"""Raised on timeout waiting for execute_script to finish."""

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

@ -121,7 +121,8 @@ def main():
# Update config file
config_in_path = os.path.join(here, 'config', 'config.json.in')
replacements = {'__TESTDIR__': testdir, '__EXTENSIONDIR__': extdir}
replacements = {'__TESTDIR__': testdir.replace('\\','/'),
'__EXTENSIONDIR__': extdir.replace('\\','/')}
if options.username and options.password:
replacements.update({
'__FX_ACCOUNT_USERNAME__': options.username,

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

@ -150,9 +150,9 @@
#define NS_URLCLASSIFIERDBSERVICE_CID \
{ 0x8a389f21, 0xf821, 0x4e29, { 0x9c, 0x6b, 0x3d, 0xe6, 0xf3, 0x3c, 0xd7, 0xcf} }
// {79e6b710-ce68-4639-ac6b-7d293af424a1}
// e1797597-f4d6-4dd3-a1e1-745ad352cd80
#define NS_URLCLASSIFIERSTREAMUPDATER_CID \
{ 0x79e6b710, 0xce68, 0x4639, { 0xac, 0x6b, 0x7d, 0x29, 0x3a, 0xf4, 0x24, 0xa1} }
{ 0xe1797597, 0xf4d6, 0x4dd3, { 0xa1, 0xe1, 0x74, 0x5a, 0xd3, 0x52, 0xcd, 0x80 }}
// {b7b2ccec-7912-4ea6-a548-b038447004bd}
#define NS_URLCLASSIFIERUTILS_CID \

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

@ -205,7 +205,6 @@ add_test(function test_local_list() {
let streamUpdater = Cc["@mozilla.org/url-classifier/streamupdater;1"]
.getService(Ci.nsIUrlClassifierStreamUpdater);
streamUpdater.updateUrl = "http://localhost:4444/downloads";
// Load up some update chunks for the safebrowsing server to serve.
// This chunk contains the hash of blocklisted.com/.
@ -228,6 +227,7 @@ add_test(function test_local_list() {
streamUpdater.downloadUpdates(
"goog-downloadwhite-digest256,goog-badbinurl-shavar",
"goog-downloadwhite-digest256,goog-badbinurl-shavar;\n",
"http://localhost:4444/downloads",
updateSuccess, handleError, handleError);
});

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

@ -257,7 +257,6 @@ function waitForUpdates() {
let streamUpdater = Cc["@mozilla.org/url-classifier/streamupdater;1"]
.getService(Ci.nsIUrlClassifierStreamUpdater);
streamUpdater.updateUrl = "http://localhost:4444/downloads";
// Load up some update chunks for the safebrowsing server to serve. This
// particular chunk contains the hash of whitelisted.com/ and
@ -280,6 +279,7 @@ function waitForUpdates() {
streamUpdater.downloadUpdates(
"goog-downloadwhite-digest256",
"goog-downloadwhite-digest256;\n",
"http://localhost:4444/downloads",
updateSuccess, handleError, handleError);
return deferred.promise;
}

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

@ -318,7 +318,7 @@ Classifier::ApplyUpdates(nsTArray<TableUpdate*>* aUpdates)
nsresult rv = BackupTables();
NS_ENSURE_SUCCESS(rv, rv);
LOG(("Applying table updates."));
LOG(("Applying %d table updates.", aUpdates->Length()));
for (uint32_t i = 0; i < aUpdates->Length(); i++) {
// Previous ApplyTableUpdates() may have consumed this update..
@ -576,8 +576,9 @@ Classifier::ApplyTableUpdates(nsTArray<TableUpdate*>* aUpdates,
nsAutoPtr<HashStore> store(new HashStore(aTable, mStoreDirectory));
if (!store)
if (!store) {
return NS_ERROR_FAILURE;
}
// take the quick exit if there is no valid update for us
// (common case)

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

@ -54,16 +54,16 @@ this.SafeBrowsing = {
let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
getService(Ci.nsIUrlListManager);
for (let i = 0; i < phishingLists.length; ++i) {
listManager.registerTable(phishingLists[i], false);
listManager.registerTable(phishingLists[i], this.updateURL, this.gethashURL);
}
for (let i = 0; i < malwareLists.length; ++i) {
listManager.registerTable(malwareLists[i], false);
listManager.registerTable(malwareLists[i], this.updateURL, this.gethashURL);
}
for (let i = 0; i < downloadBlockLists.length; ++i) {
listManager.registerTable(downloadBlockLists[i], false);
listManager.registerTable(downloadBlockLists[i], this.updateURL, this.gethashURL);
}
for (let i = 0; i < downloadAllowLists.length; ++i) {
listManager.registerTable(downloadAllowLists[i], false);
listManager.registerTable(downloadAllowLists[i], this.updateURL, this.gethashURL);
}
this.addMozEntries();
@ -134,15 +134,8 @@ this.SafeBrowsing = {
this.updateURL = this.updateURL.replace("SAFEBROWSING_ID", clientID);
this.gethashURL = this.gethashURL.replace("SAFEBROWSING_ID", clientID);
let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
getService(Ci.nsIUrlListManager);
listManager.setUpdateUrl(this.updateURL);
listManager.setGethashUrl(this.gethashURL);
},
controlUpdateChecking: function() {
log("phishingEnabled:", this.phishingEnabled, "malwareEnabled:", this.malwareEnabled);

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

@ -2,7 +2,6 @@
# 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/.
// This is the only implementation of nsIUrlListManager.
// A class that manages lists, namely white and black lists for
// phishing or malware protection. The ListManager knows how to fetch,
@ -13,6 +12,17 @@
// TODO more comprehensive update tests, for example add unittest check
// that the listmanagers tables are properly written on updates
// Log only if browser.safebrowsing.debug is true
var debug = false;
function log(...stuff) {
if (!debug) {
return;
}
let msg = "listmanager: " + stuff.join(" ");
dump(msg + "\n");
}
function QueryAdapter(callback) {
this.callback_ = callback;
};
@ -28,46 +38,31 @@ QueryAdapter.prototype.handleResponse = function(value) {
* @constructor
*/
function PROT_ListManager() {
this.debugZone = "listmanager";
G_debugService.enableZone(this.debugZone);
this.currentUpdateChecker_ = null; // set when we toggle updates
this.prefs_ = new G_Preferences();
this.updateInterval = this.prefs_.getPref("urlclassifier.updateinterval", 30 * 60) * 1000;
this.updateserverURL_ = null;
this.gethashURL_ = null;
this.isTesting_ = false;
// A map of tableNames to objects of type
// { updateUrl: <updateUrl>, gethashUrl: <gethashUrl> }
this.tablesData = {};
// A map of updateUrls to maps of tables requiring updates, e.g.
// { safebrowsing-update-url: { goog-phish-shavar: true,
// goog-malware-shavar: true }
this.needsUpdate_ = {};
this.observerServiceObserver_ = new G_ObserverServiceObserver(
'quit-application',
BindToObject(this.shutdown_, this),
true /*only once*/);
this.cookieObserver_ = new G_ObserverServiceObserver(
'cookie-changed',
BindToObject(this.cookieChanged_, this),
false);
/* Backoff interval should be between 30 and 60 minutes. */
var backoffInterval = 30 * 60 * 1000;
backoffInterval += Math.floor(Math.random() * (30 * 60 * 1000));
this.requestBackoff_ = new RequestBackoff(2 /* max errors */,
60*1000 /* retry interval, 1 min */,
4 /* num requests */,
60*60*1000 /* request time, 60 min */,
backoffInterval /* backoff interval, 60 min */,
8*60*60*1000 /* max backoff, 8hr */);
this.updateCheckers_ = {};
this.requestBackoffs_ = {};
this.dbService_ = Cc["@mozilla.org/url-classifier/dbservice;1"]
.getService(Ci.nsIUrlClassifierDBService);
this.hashCompleter_ = Cc["@mozilla.org/url-classifier/hashcompleter;1"]
.getService(Ci.nsIUrlClassifierHashCompleter);
debug = this.prefs_.getPref("browser.safebrowsing.debug");
}
/**
@ -80,53 +75,53 @@ PROT_ListManager.prototype.shutdown_ = function() {
}
}
/**
* Set the url we check for updates. If the new url is valid and different,
* update our table list.
*
* After setting the update url, the caller is responsible for registering
* tables and then toggling update checking. All the code for this logic is
* currently in browser/components/safebrowsing. Maybe it should be part of
* the listmanger?
*/
PROT_ListManager.prototype.setUpdateUrl = function(url) {
G_Debug(this, "Set update url: " + url);
if (url != this.updateserverURL_) {
this.updateserverURL_ = url;
this.requestBackoff_.reset();
// Remove old tables which probably aren't valid for the new provider.
for (var name in this.tablesData) {
delete this.tablesData[name];
}
}
}
/**
* Set the gethash url.
*/
PROT_ListManager.prototype.setGethashUrl = function(url) {
G_Debug(this, "Set gethash url: " + url);
if (url != this.gethashURL_) {
this.gethashURL_ = url;
this.hashCompleter_.gethashUrl = url;
}
}
/**
* Register a new table table
* @param tableName - the name of the table
* @param opt_requireMac true if a mac is required on update, false otherwise
* @param updateUrl - the url for updating the table
* @param gethashUrl - the url for fetching hash completions
* @returns true if the table could be created; false otherwise
*/
PROT_ListManager.prototype.registerTable = function(tableName,
opt_requireMac) {
PROT_ListManager.prototype.registerTable = function(tableName,
updateUrl,
gethashUrl) {
log("registering " + tableName + " with " + updateUrl);
if (!updateUrl) {
log("Can't register table " + tableName + " without updateUrl");
return false;
}
this.tablesData[tableName] = {};
this.tablesData[tableName].needsUpdate = false;
this.tablesData[tableName].updateUrl = updateUrl;
this.tablesData[tableName].gethashUrl = gethashUrl;
// Keep track of all of our update URLs.
if (!this.needsUpdate_[updateUrl]) {
this.needsUpdate_[updateUrl] = {};
/* Backoff interval should be between 30 and 60 minutes. */
var backoffInterval = 30 * 60 * 1000;
backoffInterval += Math.floor(Math.random() * (30 * 60 * 1000));
log("Creating request backoff for " + updateUrl);
this.requestBackoffs_[updateUrl] = new RequestBackoff(2 /* max errors */,
60*1000 /* retry interval, 1 min */,
4 /* num requests */,
60*60*1000 /* request time, 60 min */,
backoffInterval /* backoff interval, 60 min */,
8*60*60*1000 /* max backoff, 8hr */);
}
this.needsUpdate_[updateUrl][tableName] = false;
return true;
}
PROT_ListManager.prototype.getGethashUrl = function(tableName) {
if (this.tablesData[tableName] && this.tablesData[tableName].gethashUrl) {
return this.tablesData[tableName].gethashUrl;
}
return "";
}
/**
* Enable updates for some tables
* @param tables - an array of table names that need updating
@ -135,13 +130,14 @@ PROT_ListManager.prototype.enableUpdate = function(tableName) {
var changed = false;
var table = this.tablesData[tableName];
if (table) {
G_Debug(this, "Enabling table updates for " + tableName);
table.needsUpdate = true;
log("Enabling table updates for " + tableName);
this.needsUpdate_[table.updateUrl][tableName] = true;
changed = true;
}
if (changed === true)
if (changed) {
this.maybeToggleUpdateChecking();
}
}
/**
@ -152,42 +148,30 @@ PROT_ListManager.prototype.disableUpdate = function(tableName) {
var changed = false;
var table = this.tablesData[tableName];
if (table) {
G_Debug(this, "Disabling table updates for " + tableName);
table.needsUpdate = false;
log("Disabling table updates for " + tableName);
this.needsUpdate_[table.updateUrl][tableName] = false;
changed = true;
}
if (changed === true)
if (changed) {
this.maybeToggleUpdateChecking();
}
}
/**
* Determine if we have some tables that need updating.
*/
PROT_ListManager.prototype.requireTableUpdates = function() {
for (var type in this.tablesData) {
// Tables that need updating even if other tables dont require it
if (this.tablesData[type].needsUpdate)
for (var name in this.tablesData) {
// Tables that need updating even if other tables don't require it
if (this.needsUpdate_[this.tablesData[name].updateUrl][name]) {
return true;
}
}
return false;
}
/**
* Start managing the lists we know about. We don't do this automatically
* when the listmanager is instantiated because their profile directory
* (where we store the lists) might not be available.
*/
PROT_ListManager.prototype.maybeStartManagingUpdates = function() {
if (this.isTesting_)
return;
// We might have been told about tables already, so see if we should be
// actually updating.
this.maybeToggleUpdateChecking();
}
/**
* Acts as a nsIUrlClassifierCallback for getTables.
*/
@ -197,25 +181,40 @@ PROT_ListManager.prototype.kickoffUpdate_ = function (onDiskTableData)
var initialUpdateDelay = 3000;
// Check if any table registered for updates has ever been downloaded.
var diskTablesAreUpdating = false;
var updatingExisting = false;
for (var tableName in this.tablesData) {
if (this.tablesData[tableName].needsUpdate) {
if (this.needsUpdate_[this.tablesData[tableName].updateUrl][tableName]) {
if (onDiskTableData.indexOf(tableName) != -1) {
diskTablesAreUpdating = true;
updatingExisting = true;
}
}
}
// If the user has never downloaded tables, do the check now.
// If the user has tables, add a fuzz of a few minutes.
if (diskTablesAreUpdating) {
// Add a fuzz of 0-5 minutes.
initialUpdateDelay += Math.floor(Math.random() * (5 * 60 * 1000));
log("needsUpdate: " + JSON.stringify(this.needsUpdate_, undefined, 2));
for (var url in this.needsUpdate_) {
// If the user has tables, add a fuzz of a few minutes.
if (updatingExisting) {
// Add a fuzz of 0-5 minutes.
initialUpdateDelay += Math.floor(Math.random() * (5 * 60 * 1000));
}
// If we haven't already kicked off updates for this updateUrl, set a
// repeating timer for it. The delay will be reset either on updateSuccess
// to this.updateinterval, or backed off on downloadError.
if (!this.updateCheckers_[url]) {
this.updateCheckers_[url] =
new G_Alarm(BindToObject(this.checkForUpdates, this, url),
initialUpdateDelay, true /* repeating */);
}
}
}
this.currentUpdateChecker_ =
new G_Alarm(BindToObject(this.checkForUpdates, this),
initialUpdateDelay);
PROT_ListManager.prototype.stopUpdateCheckers = function() {
log("Stopping updates");
for (var updateUrl in this.updateCheckers_) {
this.updateCheckers_[updateUrl].cancel();
this.updateCheckers_[updateUrl] = null;
}
}
/**
@ -223,70 +222,21 @@ PROT_ListManager.prototype.kickoffUpdate_ = function (onDiskTableData)
* Wardens may call us with new tables that need to be updated.
*/
PROT_ListManager.prototype.maybeToggleUpdateChecking = function() {
// If we are testing or dont have an application directory yet, we should
// not start reading tables from disk or schedule remote updates
if (this.isTesting_)
return;
// We update tables if we have some tables that want updates. If there
// are no tables that want to be updated - we dont need to check anything.
if (this.requireTableUpdates() === true) {
G_Debug(this, "Starting managing lists");
this.startUpdateChecker();
if (this.requireTableUpdates()) {
log("Starting managing lists");
// Multiple warden can ask us to reenable updates at the same time, but we
// really just need to schedule a single update.
if (!this.currentUpdateChecker && !this.startingUpdate_) {
// Get the list of existing tables from the DBService before making any
// update requests.
if (!this.startingUpdate_) {
this.startingUpdate_ = true;
// check the current state of tables in the database
this.dbService_.getTables(BindToObject(this.kickoffUpdate_, this));
}
} else {
G_Debug(this, "Stopping managing lists (if currently active)");
this.stopUpdateChecker(); // Cancel pending updates
}
}
/**
* Start periodic checks for updates. Idempotent.
* We want to distribute update checks evenly across the update period (an
* hour). The first update is scheduled for a random time between 0.5 and 1.5
* times the update interval.
*/
PROT_ListManager.prototype.startUpdateChecker = function() {
this.stopUpdateChecker();
// Schedule the first check for between 15 and 45 minutes.
var repeatingUpdateDelay = this.updateInterval / 2;
repeatingUpdateDelay += Math.floor(Math.random() * this.updateInterval);
this.updateChecker_ = new G_Alarm(BindToObject(this.initialUpdateCheck_,
this),
repeatingUpdateDelay);
}
/**
* Callback for the first update check.
* We go ahead and check for table updates, then start a regular timer (once
* every update interval).
*/
PROT_ListManager.prototype.initialUpdateCheck_ = function() {
this.checkForUpdates();
this.updateChecker_ = new G_Alarm(BindToObject(this.checkForUpdates, this),
this.updateInterval, true /* repeat */);
}
/**
* Stop checking for updates. Idempotent.
*/
PROT_ListManager.prototype.stopUpdateChecker = function() {
if (this.updateChecker_) {
this.updateChecker_.cancel();
this.updateChecker_ = null;
}
// Cancel the oneoff check from maybeToggleUpdateChecking.
if (this.currentUpdateChecker_) {
this.currentUpdateChecker_.cancel();
this.currentUpdateChecker_ = null;
log("Stopping managing lists (if currently active)");
this.stopUpdateCheckers(); // Cancel pending updates
}
}
@ -303,13 +253,13 @@ PROT_ListManager.prototype.stopUpdateChecker = function() {
*/
PROT_ListManager.prototype.safeLookup = function(key, callback) {
try {
G_Debug(this, "safeLookup: " + key);
log("safeLookup: " + key);
var cb = new QueryAdapter(callback);
this.dbService_.lookup(key,
BindToObject(cb.handleResponse, cb),
true);
} catch(e) {
G_Debug(this, "safeLookup masked failure for key " + key + ": " + e);
log("safeLookup masked failure for key " + key + ": " + e);
callback.handleEvent("");
}
}
@ -317,24 +267,22 @@ PROT_ListManager.prototype.safeLookup = function(key, callback) {
/**
* Updates our internal tables from the update server
*
* @returns true when a new request was scheduled, false if an old request
* was still pending.
* @param updateUrl: request updates for tables associated with that url, or
* for all tables if the url is empty.
*/
PROT_ListManager.prototype.checkForUpdates = function() {
// Allow new updates to be scheduled from maybeToggleUpdateChecking()
this.currentUpdateChecker_ = null;
if (!this.updateserverURL_) {
G_Debug(this, 'checkForUpdates: no update server url');
PROT_ListManager.prototype.checkForUpdates = function(updateUrl) {
log("checkForUpdates with " + updateUrl);
// See if we've triggered the request backoff logic.
if (!updateUrl) {
return false;
}
// See if we've triggered the request backoff logic.
if (!this.requestBackoff_.canMakeRequest())
if (!this.requestBackoffs_[updateUrl] ||
!this.requestBackoffs_[updateUrl].canMakeRequest()) {
return false;
}
// Grab the current state of the tables from the database
this.dbService_.getTables(BindToObject(this.makeUpdateRequest_, this));
this.dbService_.getTables(BindToObject(this.makeUpdateRequest_, this,
updateUrl));
return true;
}
@ -344,56 +292,76 @@ PROT_ListManager.prototype.checkForUpdates = function() {
* @param tableData List of table data already in the database, in the form
* tablename;<chunk ranges>\n
*/
PROT_ListManager.prototype.makeUpdateRequest_ = function(tableData) {
var tableList;
var tableNames = {};
PROT_ListManager.prototype.makeUpdateRequest_ = function(updateUrl, tableData) {
log("this.tablesData: " + JSON.stringify(this.tablesData, undefined, 2));
log("existing chunks: " + tableData + "\n");
// Disallow blank updateUrls
if (!updateUrl) {
return;
}
// An object of the form
// { tableList: comma-separated list of tables to request,
// tableNames: map of tables that need updating,
// request: list of tables and existing chunk ranges from tableData
// }
var streamerMap = { tableList: null, tableNames: {}, request: "" };
for (var tableName in this.tablesData) {
if (this.tablesData[tableName].needsUpdate)
tableNames[tableName] = true;
if (!tableList) {
tableList = tableName;
// Skip tables not matching this update url
if (this.tablesData[tableName].updateUrl != updateUrl) {
continue;
}
if (this.needsUpdate_[this.tablesData[tableName].updateUrl][tableName]) {
streamerMap.tableNames[tableName] = true;
}
if (!streamerMap.tableList) {
streamerMap.tableList = tableName;
} else {
tableList += "," + tableName;
streamerMap.tableList += "," + tableName;
}
}
var request = "";
// For each table already in the database, include the chunk data from
// the database
// Build the request. For each table already in the database, include the
// chunk data from the database
var lines = tableData.split("\n");
for (var i = 0; i < lines.length; i++) {
var fields = lines[i].split(";");
if (tableNames[fields[0]]) {
request += lines[i] + "\n";
delete tableNames[fields[0]];
var name = fields[0];
if (streamerMap.tableNames[name]) {
streamerMap.request += lines[i] + "\n";
delete streamerMap.tableNames[name];
}
}
// For each requested table that didn't have chunk data in the database,
// request it fresh
for (var tableName in tableNames) {
request += tableName + ";\n";
for (let tableName in streamerMap.tableNames) {
streamerMap.request += tableName + ";\n";
}
G_Debug(this, 'checkForUpdates: scheduling request..');
log("update request: " + JSON.stringify(streamerMap, undefined, 2) + "\n");
if (Object.keys(streamerMap.tableNames).length > 0) {
this.makeUpdateRequestForEntry_(updateUrl, streamerMap.tableList,
streamerMap.request);
}
}
PROT_ListManager.prototype.makeUpdateRequestForEntry_ = function(updateUrl,
tableList,
request) {
log("makeUpdateRequestForEntry_: request " + request + " update: " +
updateUrl + " tablelist: " + tableList + "\n");
var streamer = Cc["@mozilla.org/url-classifier/streamupdater;1"]
.getService(Ci.nsIUrlClassifierStreamUpdater);
try {
streamer.updateUrl = this.updateserverURL_;
} catch (e) {
G_Debug(this, 'invalid url');
return;
}
this.requestBackoff_.noteRequest();
this.requestBackoffs_[updateUrl].noteRequest();
if (!streamer.downloadUpdates(tableList,
request,
BindToObject(this.updateSuccess_, this),
BindToObject(this.updateError_, this),
BindToObject(this.downloadError_, this))) {
G_Debug(this, "pending update, wait until later");
if (!streamer.downloadUpdates(
tableList,
request,
updateUrl,
BindToObject(this.updateSuccess_, this, tableList, updateUrl),
BindToObject(this.updateError_, this, tableList, updateUrl),
BindToObject(this.downloadError_, this, tableList, updateUrl))) {
log("pending update, wait until later");
}
}
@ -402,26 +370,34 @@ PROT_ListManager.prototype.makeUpdateRequest_ = function(tableData) {
* @param waitForUpdate String The number of seconds that the client should
* wait before requesting again.
*/
PROT_ListManager.prototype.updateSuccess_ = function(waitForUpdate) {
G_Debug(this, "update success: " + waitForUpdate);
PROT_ListManager.prototype.updateSuccess_ = function(tableList, updateUrl,
waitForUpdate) {
log("update success for " + tableList + " from " + updateUrl + ": " +
waitForUpdate + "\n");
if (waitForUpdate) {
var delay = parseInt(waitForUpdate, 10);
// As long as the delay is something sane (5 minutes or more), update
// our delay time for requesting updates
if (delay >= (5 * 60) && this.updateChecker_)
this.updateChecker_.setDelay(delay * 1000);
// our delay time for requesting updates. Setting the delay requires a
// repeating timer, so always use one.
if (delay >= (5 * 60) && this.updateCheckers_[updateUrl]) {
log("Waiting " + delay);
this.updateCheckers_[updateUrl].setDelay(delay * 1000);
} else {
log("Ignoring delay from server, waiting " + this.updateInterval);
this.updateCheckers_[updateUrl].setDelay(this.updateInterval);
}
}
// Let the backoff object know that we completed successfully.
this.requestBackoff_.noteServerResponse(200);
this.requestBackoffs_[updateUrl].noteServerResponse(200);
}
/**
* Callback function if the update request succeeded.
* @param result String The error code of the failure
*/
PROT_ListManager.prototype.updateError_ = function(result) {
G_Debug(this, "update error: " + result);
PROT_ListManager.prototype.updateError_ = function(table, updateUrl, result) {
log("update error for " + table + " from " + updateUrl + ": " + result + "\n");
// XXX: there was some trouble applying the updates.
}
@ -429,34 +405,22 @@ PROT_ListManager.prototype.updateError_ = function(result) {
* Callback function when the download failed
* @param status String http status or an empty string if connection refused.
*/
PROT_ListManager.prototype.downloadError_ = function(status) {
G_Debug(this, "download error: " + status);
PROT_ListManager.prototype.downloadError_ = function(table, updateUrl, status) {
log("download error for " + table + ": " + status + "\n");
// If status is empty, then we assume that we got an NS_CONNECTION_REFUSED
// error. In this case, we treat this is a http 500 error.
if (!status) {
status = 500;
}
status = parseInt(status, 10);
this.requestBackoff_.noteServerResponse(status);
if (this.requestBackoff_.isErrorStatus(status)) {
this.requestBackoffs_[updateUrl].noteServerResponse(status);
if (this.requestBackoffs_[updateUrl].isErrorStatus(status)) {
// Schedule an update for when our backoff is complete
this.currentUpdateChecker_ =
new G_Alarm(BindToObject(this.checkForUpdates, this),
this.requestBackoff_.nextRequestDelay());
this.updateCheckers_[updateUrl].setDelay(
this.requestBackoffs_[updateUrl].nextRequestDelay());
}
}
/**
* Called when cookies are cleared
*/
PROT_ListManager.prototype.cookieChanged_ = function(subject, topic, data) {
if (data != "cleared")
return;
G_Debug(this, "cookies cleared");
}
PROT_ListManager.prototype.QueryInterface = function(iid) {
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIUrlListManager) ||

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

@ -21,7 +21,7 @@ const HTTP_TEMPORARY_REDIRECT = 307;
* @param retryIncrement Time (ms) for each retry before backing off.
* @param maxRequests Number the number of requests needed to trigger backoff
* @param requestPeriod Number time (ms) in which maxRequests have to occur to
* trigger the backoff behavior
* trigger the backoff behavior (0 to disable maxRequests)
* @param timeoutIncrement Number time (ms) the starting timeout period
* we double this time for consecutive errors
* @param maxTimeout Number time (ms) maximum timeout period
@ -45,7 +45,7 @@ function RequestBackoff(maxErrors, retryIncrement,
}
/**
* Reset the object for reuse.
* Reset the object for reuse. This deliberately doesn't clear requestTimes_.
*/
RequestBackoff.prototype.reset = function() {
this.numErrors_ = 0;

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

@ -46,21 +46,20 @@ interface nsIUrlClassifierHashCompleterCallback : nsISupports
* This is only ever used for testing and should absolutely be deleted (I
* think).
*/
[scriptable, uuid(ade9b72b-3562-44f5-aba6-e63246be53ae)]
[scriptable, uuid(231fb2ad-ea8a-4e63-a331-eafc3b434811)]
interface nsIUrlClassifierHashCompleter : nsISupports
{
/**
* Request a completed hash.
* Request a completed hash from the given gethash url.
*
* @param partialHash
* The 32-bit hash encountered by the url-classifier.
* @param gethashUrl
* The gethash url to use.
* @param callback
* An nsIUrlClassifierCompleterCallback instance.
*/
void complete(in ACString partialHash,
in ACString gethashUrl,
in nsIUrlClassifierHashCompleterCallback callback);
/**
* The URL for the gethash request
*/
attribute ACString gethashUrl;
};

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

@ -11,22 +11,17 @@
* downloading the whole update and then updating the sqlite database, we
* update tables as the data is streaming in.
*/
[scriptable, uuid(79e6b710-ce68-4639-ac6b-7d293af424a1)]
[scriptable, uuid(e1797597-f4d6-4dd3-a1e1-745ad352cd80)]
interface nsIUrlClassifierStreamUpdater : nsISupports
{
/**
* The Url to download from. Should be plain ascii text.
*/
attribute ACString updateUrl;
/**
* Try to download updates from updateUrl. Only one instance of this
* runs at a time, so we return false if another instance is already
* running.
* This is used in nsIUrlListManager as well as in testing.
* Try to download updates from updateUrl. If an update is already in
* progress, queues the requested update. This is used in nsIUrlListManager
* as well as in testing.
* @param aRequestTables Comma-separated list of tables included in this
* update.
* @param aRequestBody The body for the request.
* @param aUpdateUrl The plaintext url from which to request updates.
* @param aSuccessCallback Called after a successful update.
* @param aUpdateErrorCallback Called for problems applying the update
* @param aDownloadErrorCallback Called if we get an http error or a
@ -34,6 +29,7 @@ interface nsIUrlClassifierStreamUpdater : nsISupports
*/
boolean downloadUpdates(in ACString aRequestTables,
in ACString aRequestBody,
in ACString aUpdateUrl,
in nsIUrlClassifierCallback aSuccessCallback,
in nsIUrlClassifierCallback aUpdateErrorCallback,
in nsIUrlClassifierCallback aDownloadErrorCallback);

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

@ -18,29 +18,29 @@ interface nsIUrlListManagerCallback : nsISupports {
};
[scriptable, uuid(62484bb5-bf7e-4988-9055-8803b16b48a1)]
[scriptable, uuid(653afdc4-ad4e-4ee0-8375-c576e85ebc40)]
interface nsIUrlListManager : nsISupports
{
/**
* Set the URL we check for updates.
* Get the gethash url for this table
*/
void setUpdateUrl(in ACString url);
ACString getGethashUrl(in ACString tableName);
/**
* Set the URL that we will query for complete hashes after a partial
* hash match.
*/
void setGethashUrl(in ACString url);
/**
* Add a table to the list of tables we are managing. The name is a
* Add a table to the list of tables we are managing. The name is a
* string of the format provider_name-semantic_type-table_type. For
* example, goog-white-enchash or goog-black-url.
* @param tableName A string of the format
* provider_name-semantic_type-table_type. For example,
* goog-white-enchash or goog-black-url.
* @param updateUrl The URL from which to fetch updates.
* @param gethashUrl The URL from which to fetch hash completions.
*/
boolean registerTable(in ACString tableName);
boolean registerTable(in ACString tableName,
in ACString updateUrl,
in ACString gethashUrl);
/**
* Turn on update checking for a table. I.e., during the next server
* Turn on update checking for a table. I.e., during the next server
* check, download updates for this table.
*/
void enableUpdate(in ACString tableName);
@ -57,6 +57,4 @@ interface nsIUrlListManager : nsISupports
*/
void safeLookup(in nsIPrincipal key,
in nsIUrlListManagerCallback cb);
void checkForUpdates();
};

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

@ -94,7 +94,7 @@ static bool gShuttingDownThread = false;
static mozilla::Atomic<int32_t> gFreshnessGuarantee(CONFIRM_AGE_DEFAULT_SEC);
// -------------------------------------------------------------------------
// Actual worker implemenatation
// Actual worker implementation
class nsUrlClassifierDBServiceWorker MOZ_FINAL :
public nsIUrlClassifierDBServiceWorker
{
@ -428,8 +428,9 @@ nsUrlClassifierDBServiceWorker::BeginUpdate(nsIUrlClassifierUpdateObserver *obse
{
LOG(("nsUrlClassifierDBServiceWorker::BeginUpdate [%s]", PromiseFlatCString(tables).get()));
if (gShuttingDownThread)
if (gShuttingDownThread) {
return NS_ERROR_NOT_INITIALIZED;
}
NS_ENSURE_STATE(!mUpdateObserver);
@ -523,8 +524,10 @@ nsUrlClassifierDBServiceWorker::UpdateStream(const nsACString& chunk)
NS_IMETHODIMP
nsUrlClassifierDBServiceWorker::FinishStream()
{
if (gShuttingDownThread)
if (gShuttingDownThread) {
LOG(("shutting down"));
return NS_ERROR_NOT_INITIALIZED;
}
NS_ENSURE_STATE(mInStream);
NS_ENSURE_STATE(mUpdateObserver);
@ -822,13 +825,26 @@ nsUrlClassifierLookupCallback::LookupComplete(nsTArray<LookupResult>* results)
// We will complete partial matches and matches that are stale.
if (!result.Confirmed()) {
nsCOMPtr<nsIUrlClassifierHashCompleter> completer;
nsCString gethashUrl;
nsresult rv;
nsCOMPtr<nsIUrlListManager> listManager = do_GetService(
"@mozilla.org/url-classifier/listmanager;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = listManager->GetGethashUrl(result.mTableName, gethashUrl);
NS_ENSURE_SUCCESS(rv, rv);
// We only allow empty gethashUrls for test- tables
if (gethashUrl.IsEmpty()) {
MOZ_ASSERT(
StringBeginsWith(result.mTableName, NS_LITERAL_CSTRING("test-")),
"Only test tables may have empty gethash urls");
}
if (mDBService->GetCompleter(result.mTableName,
getter_AddRefs(completer))) {
nsAutoCString partialHash;
partialHash.Assign(reinterpret_cast<char*>(&result.hash.prefix),
PREFIX_SIZE);
nsresult rv = completer->Complete(partialHash, this);
nsresult rv = completer->Complete(partialHash, gethashUrl, this);
if (NS_SUCCEEDED(rv)) {
mPendingCompletions++;
}
@ -1342,8 +1358,10 @@ nsUrlClassifierDBService::BeginUpdate(nsIUrlClassifierUpdateObserver *observer,
{
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
if (mInUpdate)
if (mInUpdate) {
LOG(("Already updating, not available"));
return NS_ERROR_NOT_AVAILABLE;
}
mInUpdate = true;

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

@ -13,6 +13,7 @@
#include "nsIObserver.h"
#include "nsUrlClassifierPrefixSet.h"
#include "nsIUrlClassifierHashCompleter.h"
#include "nsIUrlListManager.h"
#include "nsIUrlClassifierDBService.h"
#include "nsIURIClassifier.h"
#include "nsToolkitCompsCID.h"

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

@ -14,51 +14,37 @@ const COMPLETE_LENGTH = 32;
const PARTIAL_LENGTH = 4;
// These backoff related constants are taken from v2 of the Google Safe Browsing
// API.
// API. All times are in milliseconds.
// BACKOFF_ERRORS: the number of errors incurred until we start to back off.
// BACKOFF_INTERVAL: the initial time, in seconds, to wait once we start backing
// BACKOFF_INTERVAL: the initial time to wait once we start backing
// off.
// BACKOFF_MAX: as the backoff time doubles after each failure, this is a
// ceiling on the time to wait, in seconds.
// BACKOFF_TIME: length of the interval of time, in seconds, during which errors
// are taken into account.
// ceiling on the time to wait.
const BACKOFF_ERRORS = 2;
const BACKOFF_INTERVAL = 30 * 60;
const BACKOFF_MAX = 8 * 60 * 60;
const BACKOFF_TIME = 5 * 60;
const BACKOFF_INTERVAL = 30 * 60 * 1000;
const BACKOFF_MAX = 8 * 60 * 60 * 1000;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
function HashCompleter() {
// This is a HashCompleterRequest and is used by multiple calls to |complete|
// in succession to avoid unnecessarily creating requests. Once it has been
// started, this is set to null again.
// The current HashCompleterRequest in flight. Once it is started, it is set
// to null. It may be used by multiple calls to |complete| in succession to
// avoid creating multiple requests to the same gethash URL.
this._currentRequest = null;
// A map of gethashUrls to HashCompleterRequests that haven't yet begun.
this._pendingRequests = {};
// A map of gethash URLs to RequestBackoff objects.
this._backoffs = {};
// Whether we have been informed of a shutdown by the xpcom-shutdown event.
this._shuttingDown = false;
// All of these backoff properties are different per completer as the DB
// service keeps one completer per table.
//
// _backoff tells us whether we are "backing off" from making requests.
// It is set in |noteServerResponse| and set after a number of failures.
this._backoff = false;
// _backoffTime tells us how long we should wait (in seconds) before making
// another request.
this._backoffTime = 0;
// _nextRequestTime is the earliest time at which we are allowed to make
// another request by the backoff policy. It is measured in milliseconds.
this._nextRequestTime = 0;
// A list of the times at which a failed request was made, recorded in
// |noteServerResponse|. Sorted by oldest to newest and its length is clamped
// by BACKOFF_ERRORS.
this._errorTimes = [];
Services.obs.addObserver(this, "xpcom-shutdown", true);
}
HashCompleter.prototype = {
classID: Components.ID("{9111de73-9322-4bfc-8b65-2b727f3e6ec8}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIUrlClassifierHashCompleter,
@ -70,108 +56,91 @@ HashCompleter.prototype = {
// This is mainly how the HashCompleter interacts with other components.
// Even though it only takes one partial hash and callback, subsequent
// calls are made into the same HTTP request by using a thread dispatch.
complete: function HC_complete(aPartialHash, aCallback) {
if (!this._currentRequest) {
this._currentRequest = new HashCompleterRequest(this);
// It's possible for getHashUrl to not be set, usually at start-up.
if (this._getHashUrl) {
Services.tm.currentThread.dispatch(this, Ci.nsIThread.DISPATCH_NORMAL);
}
complete: function HC_complete(aPartialHash, aGethashUrl, aCallback) {
if (!aGethashUrl) {
throw Cr.NS_ERROR_NOT_INITIALIZED;
}
this._currentRequest.add(aPartialHash, aCallback);
if (!this._currentRequest) {
this._currentRequest = new HashCompleterRequest(this, aGethashUrl);
}
if (this._currentRequest.gethashUrl == aGethashUrl) {
this._currentRequest.add(aPartialHash, aCallback);
} else {
if (!this._pendingRequests[aGethashUrl]) {
this._pendingRequests[aGethashUrl] =
new HashCompleterRequest(this, aGethashUrl);
}
this._pendingRequests[aGethashUrl].add(aPartialHash, aCallback);
}
if (!this._backoffs[aGethashUrl]) {
// Initialize request backoffs separately, since requests are deleted
// after they are dispatched.
var jslib = Cc["@mozilla.org/url-classifier/jslib;1"]
.getService().wrappedJSObject;
this._backoffs[aGethashUrl] = new jslib.RequestBackoff(
BACKOFF_ERRORS /* max errors */,
60*1000 /* retry interval, 1 min */,
10 /* keep track of max requests */,
0 /* don't throttle on successful requests per time period */,
BACKOFF_INTERVAL /* backoff interval, 60 min */,
BACKOFF_MAX /* max backoff, 8hr */);
}
// Start off this request. Without dispatching to a thread, every call to
// complete makes an individual HTTP request.
Services.tm.currentThread.dispatch(this, Ci.nsIThread.DISPATCH_NORMAL);
},
// This is called when either the getHashUrl has been set or after a few calls
// to |complete|. It starts off the HTTP request by making a |begin| call
// to the HashCompleterRequest.
run: function HC_run() {
// This is called after several calls to |complete|, or after the
// currentRequest has finished. It starts off the HTTP request by making a
// |begin| call to the HashCompleterRequest.
run: function() {
// Clear everything on shutdown
if (this._shuttingDown) {
this._currentRequest = null;
this._pendingRequests = null;
for (var url in this._backoffs) {
this._backoffs[url] = null;
}
throw Cr.NS_ERROR_NOT_INITIALIZED;
}
if (!this._currentRequest) {
return;
// If we don't have an in-flight request, make one
let pendingUrls = Object.keys(this._pendingRequests);
if (!this._currentRequest && (pendingUrls.length > 0)) {
let nextUrl = pendingUrls[0];
this._currentRequest = this._pendingRequests[nextUrl];
delete this._pendingRequests[nextUrl];
}
if (!this._getHashUrl) {
throw Cr.NS_ERROR_NOT_INITIALIZED;
}
let url = this._getHashUrl;
let uri = Services.io.newURI(url, null, null);
this._currentRequest.setURI(uri);
// If |begin| fails, we should get rid of our request.
try {
this._currentRequest.begin();
}
finally {
this._currentRequest = null;
}
},
get gethashUrl() {
return this._getHashUrl;
},
// Because we hold off on making a request until we have a valid getHashUrl,
// we kick off the process here.
set gethashUrl(aNewUrl) {
this._getHashUrl = aNewUrl;
if (this._currentRequest) {
Services.tm.currentThread.dispatch(this, Ci.nsIThread.DISPATCH_NORMAL);
try {
this._currentRequest.begin();
} finally {
// If |begin| fails, we should get rid of our request.
this._currentRequest = null;
}
}
},
// This handles all the logic about setting a back off time based on
// server responses. It should only be called once in the life time of a
// request.
// The logic behind backoffs is documented in the Google Safe Browsing API,
// the general idea is that a completer should go into backoff mode after
// BACKOFF_ERRORS errors in the last BACKOFF_TIME seconds. From there,
// we do not make a request for BACKOFF_INTERVAL seconds and for every failed
// request after that we double how long to wait, to a maximum of BACKOFF_MAX.
// Note that even in the case of a successful response we still keep a history
// of past errors.
noteServerResponse: function HC_noteServerResponse(aSuccess) {
if (aSuccess) {
this._backoff = false;
this._nextRequestTime = 0;
this._backoffTime = 0;
return;
}
let now = Date.now();
// We only alter the size of |_errorTimes| here, so we can guarantee that
// its length is at most BACKOFF_ERRORS.
this._errorTimes.push(now);
if (this._errorTimes.length > BACKOFF_ERRORS) {
this._errorTimes.shift();
}
if (this._backoff) {
this._backoffTime *= 2;
} else if (this._errorTimes.length == BACKOFF_ERRORS &&
((now - this._errorTimes[0]) / 1000) <= BACKOFF_TIME) {
this._backoff = true;
this._backoffTime = BACKOFF_INTERVAL;
}
if (this._backoff) {
this._backoffTime = Math.min(this._backoffTime, BACKOFF_MAX);
this._nextRequestTime = now + (this._backoffTime * 1000);
}
// Pass the server response status to the RequestBackoff for the given
// gethashUrl and fetch the next pending request, if there is one.
finishRequest: function(url, aStatus) {
this._backoffs[url].noteServerResponse(aStatus);
Services.tm.currentThread.dispatch(this, Ci.nsIThread.DISPATCH_NORMAL);
},
// This is not included on the interface but is used to communicate to the
// HashCompleterRequest. It returns a time in milliseconds.
get nextRequestTime() {
return this._nextRequestTime;
// Returns true if we can make a request from the given url, false otherwise.
canMakeRequest: function(aGethashUrl) {
return this._backoffs[aGethashUrl].canMakeRequest();
},
// Notifies the RequestBackoff of a new request so we can throttle based on
// max requests/time period. This must be called before a channel is opened,
// and finishRequest must be called once the response is received.
noteRequest: function(aGethashUrl) {
return this._backoffs[aGethashUrl].noteRequest();
},
observe: function HC_observe(aSubject, aTopic, aData) {
@ -181,20 +150,18 @@ HashCompleter.prototype = {
},
};
function HashCompleterRequest(aCompleter) {
function HashCompleterRequest(aCompleter, aGethashUrl) {
// HashCompleter object that created this HashCompleterRequest.
this._completer = aCompleter;
// The internal set of hashes and callbacks that this request corresponds to.
this._requests = [];
// URI to query for hash completions. Largely comes from the
// browser.safebrowsing.gethashURL pref.
this._uri = null;
// nsIChannel that the hash completion query is transmitted over.
this._channel = null;
// Response body of hash completion. Created in onDataAvailable.
this._response = "";
// Whether we have been informed of a shutdown by the xpcom-shutdown event.
this._shuttingDown = false;
this.gethashUrl = aGethashUrl;
}
HashCompleterRequest.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver,
@ -213,9 +180,11 @@ HashCompleterRequest.prototype = {
},
// This initiates the HTTP request. It can fail due to backoff timings and
// will notify all callbacks as necessary.
// will notify all callbacks as necessary. We notify the backoff object on
// begin.
begin: function HCR_begin() {
if (Date.now() < this._completer.nextRequestTime) {
if (!this._completer.canMakeRequest(this.gethashUrl)) {
dump("hashcompleter: Can't make request to " + this.gethashUrl + "\n");
this.notifyFailure(Cr.NS_ERROR_ABORT);
return;
}
@ -224,6 +193,9 @@ HashCompleterRequest.prototype = {
try {
this.openChannel();
// Notify the RequestBackoff if opening the channel succeeded. At this
// point, finishRequest must be called.
this._completer.noteRequest(this.gethashUrl);
}
catch (err) {
this.notifyFailure(err);
@ -231,16 +203,13 @@ HashCompleterRequest.prototype = {
}
},
setURI: function HCR_setURI(aURI) {
this._uri = aURI;
},
// Creates an nsIChannel for the request and fills the body.
openChannel: function HCR_openChannel() {
let loadFlags = Ci.nsIChannel.INHIBIT_CACHING |
Ci.nsIChannel.LOAD_BYPASS_CACHE;
let channel = Services.io.newChannelFromURI(this._uri);
let uri = Services.io.newURI(this.gethashUrl, null, null);
let channel = Services.io.newChannelFromURI(uri);
channel.loadFlags = loadFlags;
this._channel = channel;
@ -306,12 +275,13 @@ HashCompleterRequest.prototype = {
let start = 0;
let length = this._response.length;
while (start != length)
while (start != length) {
start = this.handleTable(start);
}
},
// This parses a table entry in the response body and calls |handleItem|
// for complete hash in the table entry.
// for complete hash in the table entry.
handleTable: function HCR_handleTable(aStart) {
let body = this._response.substring(aStart);
@ -404,16 +374,21 @@ HashCompleterRequest.prototype = {
throw Cr.NS_ERROR_ABORT;
}
// Default HTTP status to service unavailable, in case we can't retrieve
// the true status from the channel.
let httpStatus = 503;
if (Components.isSuccessCode(aStatusCode)) {
let channel = aRequest.QueryInterface(Ci.nsIHttpChannel);
let success = channel.requestSucceeded;
httpStatus = channel.responseStatus;
if (!success) {
aStatusCode = Cr.NS_ERROR_ABORT;
}
}
let success = Components.isSuccessCode(aStatusCode);
this._completer.noteServerResponse(success);
// Notify the RequestBackoff once a response is received.
this._completer.finishRequest(this.gethashUrl, httpStatus);
if (success) {
try {

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

@ -39,13 +39,13 @@ static const PRLogModuleInfo *gUrlClassifierStreamUpdaterLog = nullptr;
nsUrlClassifierStreamUpdater::nsUrlClassifierStreamUpdater()
: mIsUpdating(false), mInitialized(false), mDownloadError(false),
mBeganStream(false), mUpdateUrl(nullptr), mChannel(nullptr)
mBeganStream(false), mChannel(nullptr)
{
#if defined(PR_LOGGING)
if (!gUrlClassifierStreamUpdaterLog)
gUrlClassifierStreamUpdaterLog = PR_NewLogModule("UrlClassifierStreamUpdater");
#endif
LOG(("nsUrlClassifierStreamUpdater init [this=%p]", this));
}
NS_IMPL_ISUPPORTS(nsUrlClassifierStreamUpdater,
@ -76,33 +76,20 @@ nsUrlClassifierStreamUpdater::DownloadDone()
///////////////////////////////////////////////////////////////////////////////
// nsIUrlClassifierStreamUpdater implementation
NS_IMETHODIMP
nsUrlClassifierStreamUpdater::GetUpdateUrl(nsACString & aUpdateUrl)
{
if (mUpdateUrl) {
mUpdateUrl->GetSpec(aUpdateUrl);
} else {
aUpdateUrl.Truncate();
}
return NS_OK;
}
NS_IMETHODIMP
nsUrlClassifierStreamUpdater::SetUpdateUrl(const nsACString & aUpdateUrl)
{
LOG(("Update URL is %s\n", PromiseFlatCString(aUpdateUrl).get()));
nsresult rv = NS_NewURI(getter_AddRefs(mUpdateUrl), aUpdateUrl);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
nsUrlClassifierStreamUpdater::FetchUpdate(nsIURI *aUpdateUrl,
const nsACString & aRequestBody,
const nsACString & aStreamTable)
{
#ifdef DEBUG
{
nsCString spec;
aUpdateUrl->GetSpec(spec);
LOG(("Fetching update %s from %s", aRequestBody.Data(), spec.get()));
}
#endif
nsresult rv;
uint32_t loadFlags = nsIChannel::INHIBIT_CACHING |
nsIChannel::LOAD_BYPASS_CACHE;
@ -165,24 +152,33 @@ nsUrlClassifierStreamUpdater::FetchUpdate(const nsACString & aUpdateUrl,
NS_IMETHODIMP
nsUrlClassifierStreamUpdater::DownloadUpdates(
const nsACString &aRequestTables,
const nsACString &aRequestBody,
nsIUrlClassifierCallback *aSuccessCallback,
nsIUrlClassifierCallback *aUpdateErrorCallback,
nsIUrlClassifierCallback *aDownloadErrorCallback,
bool *_retval)
const nsACString &aRequestTables,
const nsACString &aRequestBody,
const nsACString &aUpdateUrl,
nsIUrlClassifierCallback *aSuccessCallback,
nsIUrlClassifierCallback *aUpdateErrorCallback,
nsIUrlClassifierCallback *aDownloadErrorCallback,
bool *_retval)
{
NS_ENSURE_ARG(aSuccessCallback);
NS_ENSURE_ARG(aUpdateErrorCallback);
NS_ENSURE_ARG(aDownloadErrorCallback);
if (mIsUpdating) {
LOG(("already updating, skipping update"));
LOG(("Already updating, queueing update %s from %s", aRequestBody.Data(),
aUpdateUrl.Data()));
*_retval = false;
PendingRequest *request = mPendingRequests.AppendElement();
request->mTables = aRequestTables;
request->mRequest = aRequestBody;
request->mUrl = aUpdateUrl;
request->mSuccessCallback = aSuccessCallback;
request->mUpdateErrorCallback = aUpdateErrorCallback;
request->mDownloadErrorCallback = aDownloadErrorCallback;
return NS_OK;
}
if (!mUpdateUrl) {
if (aUpdateUrl.IsEmpty()) {
NS_ERROR("updateUrl not set");
return NS_ERROR_NOT_INITIALIZED;
}
@ -208,10 +204,20 @@ nsUrlClassifierStreamUpdater::DownloadUpdates(
rv = mDBService->BeginUpdate(this, aRequestTables);
if (rv == NS_ERROR_NOT_AVAILABLE) {
LOG(("already updating, skipping update"));
LOG(("Service busy, already updating, queuing update %s from %s",
aRequestBody.Data(), aUpdateUrl.Data()));
*_retval = false;
PendingRequest *request = mPendingRequests.AppendElement();
request->mTables = aRequestTables;
request->mRequest = aRequestBody;
request->mUrl = aUpdateUrl;
request->mSuccessCallback = aSuccessCallback;
request->mUpdateErrorCallback = aUpdateErrorCallback;
request->mDownloadErrorCallback = aDownloadErrorCallback;
return NS_OK;
} else if (NS_FAILED(rv)) {
}
if (NS_FAILED(rv)) {
return rv;
}
@ -222,14 +228,10 @@ nsUrlClassifierStreamUpdater::DownloadUpdates(
mIsUpdating = true;
*_retval = true;
nsAutoCString urlSpec;
mUpdateUrl->GetAsciiSpec(urlSpec);
LOG(("FetchUpdate: %s", urlSpec.get()));
LOG(("FetchUpdate: %s", aUpdateUrl.Data()));
//LOG(("requestBody: %s", aRequestBody.Data()));
LOG(("Calling into FetchUpdate"));
return FetchUpdate(mUpdateUrl, aRequestBody, EmptyCString());
return FetchUpdate(aUpdateUrl, aRequestBody, EmptyCString());
}
///////////////////////////////////////////////////////////////////////////////
@ -290,6 +292,34 @@ nsUrlClassifierStreamUpdater::FetchNext()
return NS_OK;
}
nsresult
nsUrlClassifierStreamUpdater::FetchNextRequest()
{
if (mPendingRequests.Length() == 0) {
LOG(("No more requests, returning"));
return NS_OK;
}
PendingRequest &request = mPendingRequests[0];
LOG(("Stream updater: fetching next request: %s, %s",
request.mTables.get(), request.mUrl.get()));
bool dummy;
DownloadUpdates(
request.mTables,
request.mRequest,
request.mUrl,
request.mSuccessCallback,
request.mUpdateErrorCallback,
request.mDownloadErrorCallback,
&dummy);
request.mSuccessCallback = nullptr;
request.mUpdateErrorCallback = nullptr;
request.mDownloadErrorCallback = nullptr;
mPendingRequests.RemoveElementAt(0);
return NS_OK;
}
NS_IMETHODIMP
nsUrlClassifierStreamUpdater::StreamFinished(nsresult status,
uint32_t requestedDelay)
@ -334,6 +364,9 @@ nsUrlClassifierStreamUpdater::UpdateSuccess(uint32_t requestedTimeout)
if (successCallback) {
successCallback->HandleEvent(strTimeout);
}
// Now fetch the next request
LOG(("stream updater: calling into fetch next request"));
FetchNextRequest();
return NS_OK;
}

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

@ -63,17 +63,29 @@ private:
// Fetches the next table, from mPendingUpdates.
nsresult FetchNext();
// Fetches the next request, from mPendingRequests
nsresult FetchNextRequest();
bool mIsUpdating;
bool mInitialized;
bool mDownloadError;
bool mBeganStream;
nsCOMPtr<nsIURI> mUpdateUrl;
nsCString mStreamTable;
nsCOMPtr<nsIChannel> mChannel;
nsCOMPtr<nsIUrlClassifierDBService> mDBService;
nsCOMPtr<nsITimer> mTimer;
struct PendingRequest {
nsCString mTables;
nsCString mRequest;
nsCString mUrl;
nsCOMPtr<nsIUrlClassifierCallback> mSuccessCallback;
nsCOMPtr<nsIUrlClassifierCallback> mUpdateErrorCallback;
nsCOMPtr<nsIUrlClassifierCallback> mDownloadErrorCallback;
};
nsTArray<PendingRequest> mPendingRequests;
struct PendingUpdate {
nsCString mUrl;
nsCString mTable;

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