mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-03 02:25:34 +00:00
Merge m-c to fx-team
This commit is contained in:
commit
46f0e233a5
@ -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="b0ddb2122771e25cdd880359406a53b10cdc0507"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6848631d1fe8baf973e3d1257f7b50427295477b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<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="b0ddb2122771e25cdd880359406a53b10cdc0507"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="6848631d1fe8baf973e3d1257f7b50427295477b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="96cdde4b5b5d8d3785b36c3c68cd746aff3005cc"/>
|
||||
<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="b0ddb2122771e25cdd880359406a53b10cdc0507"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="6848631d1fe8baf973e3d1257f7b50427295477b"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<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="b0ddb2122771e25cdd880359406a53b10cdc0507"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6848631d1fe8baf973e3d1257f7b50427295477b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<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="b0ddb2122771e25cdd880359406a53b10cdc0507"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="6848631d1fe8baf973e3d1257f7b50427295477b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="96cdde4b5b5d8d3785b36c3c68cd746aff3005cc"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "616fb21109ca9af6e0371a6d109dc4e3032ae4be",
|
||||
"revision": "4e3596b10de8df9202d9c0a7f64b7913bdfaaead",
|
||||
"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="b0ddb2122771e25cdd880359406a53b10cdc0507"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6848631d1fe8baf973e3d1257f7b50427295477b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<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="b0ddb2122771e25cdd880359406a53b10cdc0507"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6848631d1fe8baf973e3d1257f7b50427295477b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<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="b0ddb2122771e25cdd880359406a53b10cdc0507"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="6848631d1fe8baf973e3d1257f7b50427295477b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="96cdde4b5b5d8d3785b36c3c68cd746aff3005cc"/>
|
||||
<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="b0ddb2122771e25cdd880359406a53b10cdc0507"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6848631d1fe8baf973e3d1257f7b50427295477b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1403823002000">
|
||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1404245815000">
|
||||
<emItems>
|
||||
<emItem blockID="i454" id="sqlmoz@facebook.com">
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3">
|
||||
@ -554,6 +554,12 @@
|
||||
</versionRange>
|
||||
<prefs>
|
||||
</prefs>
|
||||
</emItem>
|
||||
<emItem blockID="i632" id="jid1-4vUehhSALFNqCw@jetpack">
|
||||
<versionRange minVersion="100.7" maxVersion="100.7" severity="3">
|
||||
</versionRange>
|
||||
<prefs>
|
||||
</prefs>
|
||||
</emItem>
|
||||
<emItem blockID="i63" id="youtube@youtuber.com">
|
||||
<versionRange minVersion="0" maxVersion="*">
|
||||
|
@ -2329,11 +2329,18 @@ let BrowserOnClick = {
|
||||
onAboutCertError: function (browser, elementId, isTopFrame, location) {
|
||||
let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
|
||||
switch (elementId) {
|
||||
let docshell = aOwnerDoc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
let securityInfo = docshell.failedChannel.securityInfo;
|
||||
let sslStatus = securityInfo.QueryInterface(Ci.nsISSLStatusProvider).SSLStatus;
|
||||
|
||||
case "exceptionDialogButton":
|
||||
if (isTopFrame) {
|
||||
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_CLICK_ADD_EXCEPTION);
|
||||
}
|
||||
let params = { exceptionAdded : false };
|
||||
let params = { exceptionAdded : false,
|
||||
sslStatus : sslStatus };
|
||||
|
||||
try {
|
||||
switch (Services.prefs.getIntPref("browser.ssl_override_behavior")) {
|
||||
|
@ -33,7 +33,6 @@ const Cr = Components.results;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
Cu.import("resource://gre/modules/osfile/_PromiseWorker.jsm", this);
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/AsyncShutdown.jsm");
|
||||
|
||||
@ -193,13 +192,6 @@ let SessionFileInternal = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The promise returned by the latest call to |write|.
|
||||
* We use it to ensure that AsyncShutdown.profileBeforeChange cannot
|
||||
* interrupt a call to |write|.
|
||||
*/
|
||||
_latestWrite: null,
|
||||
|
||||
/**
|
||||
* |true| once we have decided to stop receiving write instructiosn
|
||||
*/
|
||||
@ -278,9 +270,17 @@ let SessionFileInternal = {
|
||||
isFinalWrite = this._isClosed = true;
|
||||
}
|
||||
|
||||
return this._latestWrite = Task.spawn(function* task() {
|
||||
let deferredWritten = Promise.defer();
|
||||
return Task.spawn(function* task() {
|
||||
TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj);
|
||||
|
||||
// Ensure that we can write sessionstore.js cleanly before the profile
|
||||
// becomes unaccessible.
|
||||
AsyncShutdown.profileBeforeChange.addBlocker(
|
||||
"SessionFile: Finish writing Session Restore data",
|
||||
deferredWritten.promise
|
||||
);
|
||||
|
||||
try {
|
||||
let performShutdownCleanup = isFinalWrite &&
|
||||
!sessionStartup.isAutomaticRestoreEnabled();
|
||||
@ -296,14 +296,18 @@ let SessionFileInternal = {
|
||||
let msg = yield promise;
|
||||
this._recordTelemetry(msg.telemetry);
|
||||
|
||||
if (msg.ok && msg.ok.upgradeBackup) {
|
||||
if (msg.result.upgradeBackup) {
|
||||
// We have just completed a backup-on-upgrade, store the information
|
||||
// in preferences.
|
||||
Services.prefs.setCharPref(PREF_UPGRADE_BACKUP, Services.appinfo.platformBuildID);
|
||||
}
|
||||
deferredWritten.resolve();
|
||||
} catch (ex) {
|
||||
TelemetryStopwatch.cancel("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj);
|
||||
console.error("Could not write session state file ", ex, ex.stack);
|
||||
deferredWritten.reject(ex);
|
||||
} finally {
|
||||
AsyncShutdown.profileBeforeChange.removeBlocker(deferredWritten.promise);
|
||||
}
|
||||
|
||||
if (isFinalWrite) {
|
||||
@ -332,11 +336,3 @@ let SessionFileInternal = {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Ensure that we can write sessionstore.js cleanly before the profile
|
||||
// becomes unaccessible.
|
||||
AsyncShutdown.profileBeforeChange.addBlocker(
|
||||
"SessionFile: Finish writing the latest sessionstore.js",
|
||||
function() {
|
||||
return SessionFileInternal._latestWrite;
|
||||
});
|
||||
|
@ -10,48 +10,24 @@
|
||||
|
||||
importScripts("resource://gre/modules/osfile.jsm");
|
||||
|
||||
let PromiseWorker = require("resource://gre/modules/workers/PromiseWorker.js");
|
||||
|
||||
let File = OS.File;
|
||||
let Encoder = new TextEncoder();
|
||||
let Decoder = new TextDecoder();
|
||||
|
||||
/**
|
||||
* Communications with the controller.
|
||||
*
|
||||
* Accepts messages:
|
||||
* {fun:function_name, args:array_of_arguments_or_null, id: custom_id}
|
||||
*
|
||||
* Sends messages:
|
||||
* {ok: result, id: custom_id, telemetry: {}} /
|
||||
* {fail: serialized_form_of_OS.File.Error, id: custom_id}
|
||||
*/
|
||||
self.onmessage = function (msg) {
|
||||
let data = msg.data;
|
||||
if (!(data.fun in Agent)) {
|
||||
throw new Error("Cannot find method " + data.fun);
|
||||
}
|
||||
|
||||
let result;
|
||||
let id = data.id;
|
||||
|
||||
try {
|
||||
result = Agent[data.fun].apply(Agent, data.args) || {};
|
||||
} catch (ex if ex instanceof OS.File.Error) {
|
||||
// Instances of OS.File.Error know how to serialize themselves
|
||||
// (deserialization ensures that we end up with OS-specific
|
||||
// instances of |OS.File.Error|)
|
||||
self.postMessage({fail: OS.File.Error.toMsg(ex), id: id});
|
||||
return;
|
||||
}
|
||||
|
||||
// Other exceptions do not, and should be propagated through DOM's
|
||||
// built-in mechanism for uncaught errors, although this mechanism
|
||||
// may lose interesting information.
|
||||
self.postMessage({
|
||||
ok: result.result,
|
||||
id: id,
|
||||
telemetry: result.telemetry || {}
|
||||
});
|
||||
let worker = new PromiseWorker.AbstractWorker();
|
||||
worker.dispatch = function(method, args = []) {
|
||||
return Agent[method](...args);
|
||||
};
|
||||
worker.postMessage = function(result, ...transfers) {
|
||||
self.postMessage(result, ...transfers);
|
||||
};
|
||||
worker.close = function() {
|
||||
self.close();
|
||||
};
|
||||
|
||||
self.addEventListener("message", msg => worker.handleMessage(msg));
|
||||
|
||||
// The various possible states
|
||||
|
||||
|
@ -13,31 +13,13 @@ const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/osfile/_PromiseWorker.jsm", this);
|
||||
Cu.import("resource://gre/modules/PromiseWorker.jsm", this);
|
||||
Cu.import("resource://gre/modules/osfile.jsm", this);
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["SessionWorker"];
|
||||
|
||||
this.SessionWorker = (function () {
|
||||
let worker = new PromiseWorker("resource:///modules/sessionstore/SessionWorker.js",
|
||||
OS.Shared.LOG.bind("SessionWorker"));
|
||||
return {
|
||||
post: function post(...args) {
|
||||
let promise = worker.post.apply(worker, args);
|
||||
return promise.then(
|
||||
null,
|
||||
function onError(error) {
|
||||
// Decode any serialized error
|
||||
if (error instanceof PromiseWorker.WorkerError) {
|
||||
throw OS.File.Error.fromMsg(error.data);
|
||||
}
|
||||
// Extract something meaningful from ErrorEvent
|
||||
if (error instanceof ErrorEvent) {
|
||||
throw new Error(error.message, error.filename, error.lineno);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
})();
|
||||
this.SessionWorker = new BasePromiseWorker("resource:///modules/sessionstore/SessionWorker.js");
|
||||
// As the Session Worker performs I/O, we can receive instances of
|
||||
// OS.File.Error, so we need to install a decoder.
|
||||
this.SessionWorker.ExceptionHandlers["OS.File.Error"] = OS.File.Error.fromMsg;
|
||||
|
||||
|
@ -2153,9 +2153,9 @@ ia64*-hpux*)
|
||||
# autoconf insists on passing $LDFLAGS to the compiler.
|
||||
if test -z "$CLANG_CL"; then
|
||||
LDFLAGS="$LDFLAGS -LARGEADDRESSAWARE -NXCOMPAT"
|
||||
fi
|
||||
if test -z "$DEVELOPER_OPTIONS"; then
|
||||
LDFLAGS="$LDFLAGS -RELEASE"
|
||||
if test -z "$DEVELOPER_OPTIONS"; then
|
||||
LDFLAGS="$LDFLAGS -RELEASE"
|
||||
fi
|
||||
fi
|
||||
dnl For profile-guided optimization
|
||||
PROFILE_GEN_CFLAGS="-GL"
|
||||
|
@ -15,8 +15,6 @@ class nsIURI;
|
||||
{ 0xd753c84a, 0x17fd, 0x4d5f, \
|
||||
{ 0xb2, 0xe9, 0x63, 0x52, 0x8c, 0x87, 0x99, 0x7a } }
|
||||
|
||||
class nsIStyleSheet;
|
||||
|
||||
namespace mozilla {
|
||||
class CSSStyleSheet;
|
||||
} // namespace mozilla
|
||||
@ -37,10 +35,9 @@ public:
|
||||
/**
|
||||
* Used to obtain the style sheet linked in by this element.
|
||||
*
|
||||
* @param aStyleSheet out parameter that returns the style
|
||||
* sheet associated with this element.
|
||||
* @return the style sheet associated with this element.
|
||||
*/
|
||||
NS_IMETHOD GetStyleSheet(nsIStyleSheet*& aStyleSheet) = 0;
|
||||
NS_IMETHOD_(mozilla::CSSStyleSheet*) GetStyleSheet() = 0;
|
||||
|
||||
/**
|
||||
* Initialize the stylesheet linking element. If aDontLoadStyle is
|
||||
|
@ -77,13 +77,10 @@ nsStyleLinkElement::SetStyleSheet(CSSStyleSheet* aStyleSheet)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStyleLinkElement::GetStyleSheet(nsIStyleSheet*& aStyleSheet)
|
||||
NS_IMETHODIMP_(CSSStyleSheet*)
|
||||
nsStyleLinkElement::GetStyleSheet()
|
||||
{
|
||||
aStyleSheet = mStyleSheet;
|
||||
NS_IF_ADDREF(aStyleSheet);
|
||||
|
||||
return NS_OK;
|
||||
return mStyleSheet;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
|
||||
// nsIStyleSheetLinkingElement
|
||||
NS_IMETHOD SetStyleSheet(mozilla::CSSStyleSheet* aStyleSheet) MOZ_OVERRIDE;
|
||||
NS_IMETHOD GetStyleSheet(nsIStyleSheet*& aStyleSheet) MOZ_OVERRIDE;
|
||||
NS_IMETHOD_(mozilla::CSSStyleSheet*) GetStyleSheet() MOZ_OVERRIDE;
|
||||
NS_IMETHOD InitStyleLinkElement(bool aDontLoadStyle) MOZ_OVERRIDE;
|
||||
NS_IMETHOD UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
|
||||
bool* aWillNotify,
|
||||
|
@ -3100,7 +3100,7 @@ nsGenericHTMLElement::SetItemValue(JSContext* aCx, JS::Value aValue,
|
||||
return;
|
||||
}
|
||||
|
||||
binding_detail::FakeDependentString string;
|
||||
nsDependentString string;
|
||||
JS::Rooted<JS::Value> value(aCx, aValue);
|
||||
if (!ConvertJSValueToString(aCx, value, &value, eStringify, eStringify, string)) {
|
||||
aError.Throw(NS_ERROR_UNEXPECTED);
|
||||
|
@ -2628,9 +2628,12 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
||||
}
|
||||
|
||||
#ifdef USE_CONTROLLERS_SHIM
|
||||
// Note: We use |obj| rather than |aWin| to get the principal here, because
|
||||
// this is called during Window setup when the Document isn't necessarily
|
||||
// hooked up yet.
|
||||
if (id == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_CONTROLLERS) &&
|
||||
!xpc::IsXrayWrapper(obj) &&
|
||||
!nsContentUtils::IsSystemPrincipal(aWin->GetPrincipal()))
|
||||
!nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(obj)))
|
||||
{
|
||||
if (aWin->GetDoc()) {
|
||||
aWin->GetDoc()->WarnOnceAbout(nsIDocument::eWindow_Controllers);
|
||||
|
@ -2124,30 +2124,51 @@ ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
|
||||
pval.set(JS::StringValue(s)); // Root the new string.
|
||||
}
|
||||
|
||||
size_t length;
|
||||
const jschar *chars = JS_GetStringCharsZAndLength(cx, s, &length);
|
||||
if (!chars) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Conversion from Javascript string to ByteString is only valid if all
|
||||
// characters < 256.
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
if (chars[i] > 255) {
|
||||
// characters < 256. This is always the case for Latin1 strings.
|
||||
size_t length;
|
||||
if (!JS_StringHasLatin1Chars(s)) {
|
||||
// ThrowErrorMessage can GC, so we first scan the string for bad chars
|
||||
// and report the error outside the AutoCheckCannotGC scope.
|
||||
bool foundBadChar = false;
|
||||
size_t badCharIndex;
|
||||
jschar badChar;
|
||||
{
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
const jschar* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, s, &length);
|
||||
if (!chars) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
if (chars[i] > 255) {
|
||||
badCharIndex = i;
|
||||
badChar = chars[i];
|
||||
foundBadChar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundBadChar) {
|
||||
MOZ_ASSERT(badCharIndex < length);
|
||||
MOZ_ASSERT(badChar > 255);
|
||||
// The largest unsigned 64 bit number (18,446,744,073,709,551,615) has
|
||||
// 20 digits, plus one more for the null terminator.
|
||||
char index[21];
|
||||
static_assert(sizeof(size_t) <= 8, "index array too small");
|
||||
PR_snprintf(index, sizeof(index), "%d", i);
|
||||
PR_snprintf(index, sizeof(index), "%d", badCharIndex);
|
||||
// A jschar is 16 bits long. The biggest unsigned 16 bit
|
||||
// number (65,535) has 5 digits, plus one more for the null
|
||||
// terminator.
|
||||
char badChar[6];
|
||||
static_assert(sizeof(jschar) <= 2, "badChar array too small");
|
||||
PR_snprintf(badChar, sizeof(badChar), "%d", chars[i]);
|
||||
ThrowErrorMessage(cx, MSG_INVALID_BYTESTRING, index, badChar);
|
||||
char badCharArray[6];
|
||||
static_assert(sizeof(jschar) <= 2, "badCharArray too small");
|
||||
PR_snprintf(badCharArray, sizeof(badCharArray), "%d", badChar);
|
||||
ThrowErrorMessage(cx, MSG_INVALID_BYTESTRING, index, badCharArray);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
length = JS_GetStringLength(s);
|
||||
}
|
||||
|
||||
if (length >= UINT32_MAX) {
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Alignment.h"
|
||||
#include "mozilla/Array.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/CallbackObject.h"
|
||||
#include "mozilla/dom/DOMJSClass.h"
|
||||
@ -1055,16 +1056,16 @@ HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
|
||||
|
||||
template<bool Fatal>
|
||||
inline bool
|
||||
EnumValueNotFound(JSContext* cx, const jschar* chars, size_t length,
|
||||
const char* type, const char* sourceDescription)
|
||||
EnumValueNotFound(JSContext* cx, JSString* str, const char* type,
|
||||
const char* sourceDescription)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool
|
||||
EnumValueNotFound<false>(JSContext* cx, const jschar* chars, size_t length,
|
||||
const char* type, const char* sourceDescription)
|
||||
EnumValueNotFound<false>(JSContext* cx, JSString* str, const char* type,
|
||||
const char* sourceDescription)
|
||||
{
|
||||
// TODO: Log a warning to the console.
|
||||
return true;
|
||||
@ -1072,34 +1073,21 @@ EnumValueNotFound<false>(JSContext* cx, const jschar* chars, size_t length,
|
||||
|
||||
template<>
|
||||
inline bool
|
||||
EnumValueNotFound<true>(JSContext* cx, const jschar* chars, size_t length,
|
||||
const char* type, const char* sourceDescription)
|
||||
EnumValueNotFound<true>(JSContext* cx, JSString* str, const char* type,
|
||||
const char* sourceDescription)
|
||||
{
|
||||
NS_LossyConvertUTF16toASCII deflated(static_cast<const char16_t*>(chars),
|
||||
length);
|
||||
JSAutoByteString deflated(cx, str);
|
||||
if (!deflated) {
|
||||
return false;
|
||||
}
|
||||
return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, sourceDescription,
|
||||
deflated.get(), type);
|
||||
deflated.ptr(), type);
|
||||
}
|
||||
|
||||
|
||||
template<bool InvalidValueFatal>
|
||||
template<typename CharT>
|
||||
inline int
|
||||
FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* values,
|
||||
const char* type, const char* sourceDescription, bool* ok)
|
||||
FindEnumStringIndexImpl(const CharT* chars, size_t length, const EnumEntry* values)
|
||||
{
|
||||
// JS_StringEqualsAscii is slow as molasses, so don't use it here.
|
||||
JSString* str = JS::ToString(cx, v);
|
||||
if (!str) {
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
JS::Anchor<JSString*> anchor(str);
|
||||
size_t length;
|
||||
const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
|
||||
if (!chars) {
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
int i = 0;
|
||||
for (const EnumEntry* value = values; value->value; ++value, ++i) {
|
||||
if (length != value->length) {
|
||||
@ -1116,13 +1104,54 @@ FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* val
|
||||
}
|
||||
|
||||
if (equal) {
|
||||
*ok = true;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
*ok = EnumValueNotFound<InvalidValueFatal>(cx, chars, length, type,
|
||||
sourceDescription);
|
||||
return -1;
|
||||
}
|
||||
|
||||
template<bool InvalidValueFatal>
|
||||
inline int
|
||||
FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* values,
|
||||
const char* type, const char* sourceDescription, bool* ok)
|
||||
{
|
||||
// JS_StringEqualsAscii is slow as molasses, so don't use it here.
|
||||
JSString* str = JS::ToString(cx, v);
|
||||
if (!str) {
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
JS::Anchor<JSString*> anchor(str);
|
||||
|
||||
{
|
||||
int index;
|
||||
size_t length;
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
if (JS_StringHasLatin1Chars(str)) {
|
||||
const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str,
|
||||
&length);
|
||||
if (!chars) {
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
index = FindEnumStringIndexImpl(chars, length, values);
|
||||
} else {
|
||||
const jschar* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, str,
|
||||
&length);
|
||||
if (!chars) {
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
index = FindEnumStringIndexImpl(chars, length, values);
|
||||
}
|
||||
if (index >= 0) {
|
||||
*ok = true;
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
*ok = EnumValueNotFound<InvalidValueFatal>(cx, str, type, sourceDescription);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1700,8 +1729,8 @@ struct FakeDependentString {
|
||||
{
|
||||
}
|
||||
|
||||
void SetData(const nsDependentString::char_type* aData,
|
||||
nsDependentString::size_type aLength) {
|
||||
void Rebind(const nsDependentString::char_type* aData,
|
||||
nsDependentString::size_type aLength) {
|
||||
MOZ_ASSERT(mFlags == nsDependentString::F_TERMINATED);
|
||||
mData = aData;
|
||||
mLength = aLength;
|
||||
@ -1712,7 +1741,9 @@ struct FakeDependentString {
|
||||
mLength = 0;
|
||||
}
|
||||
|
||||
void SetNull() {
|
||||
void SetIsVoid(bool aValue) {
|
||||
MOZ_ASSERT(aValue,
|
||||
"We don't support SetIsVoid(false) on FakeDependentString!");
|
||||
Truncate();
|
||||
mFlags |= nsDependentString::F_VOIDED;
|
||||
}
|
||||
@ -1778,12 +1809,13 @@ enum StringificationBehavior {
|
||||
};
|
||||
|
||||
// pval must not be null and must point to a rooted JS::Value
|
||||
template<typename T>
|
||||
static inline bool
|
||||
ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
|
||||
JS::MutableHandle<JS::Value> pval,
|
||||
StringificationBehavior nullBehavior,
|
||||
StringificationBehavior undefinedBehavior,
|
||||
binding_detail::FakeDependentString& result)
|
||||
T& result)
|
||||
{
|
||||
JSString *s;
|
||||
if (v.isString()) {
|
||||
@ -1802,7 +1834,7 @@ ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
|
||||
if (behavior == eEmpty) {
|
||||
result.Truncate();
|
||||
} else {
|
||||
result.SetNull();
|
||||
result.SetIsVoid(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1820,7 +1852,7 @@ ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
|
||||
return false;
|
||||
}
|
||||
|
||||
result.SetData(chars, len);
|
||||
result.Rebind(chars, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4435,10 +4435,10 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
|
||||
if isinstance(defaultValue, IDLNullValue):
|
||||
assert(type.nullable())
|
||||
defaultCode = "%s.SetNull()" % varName
|
||||
defaultCode = "%s.SetIsVoid(true)" % varName
|
||||
else:
|
||||
defaultCode = handleDefaultStringValue(defaultValue,
|
||||
"%s.SetData" % varName)
|
||||
"%s.Rebind" % varName)
|
||||
return handleDefault(conversionCode, defaultCode + ";\n")
|
||||
|
||||
if isMember:
|
||||
@ -8508,7 +8508,7 @@ class CGUnionConversionStruct(CGThing):
|
||||
[Argument("const nsDependentString::char_type*", "aData"),
|
||||
Argument("nsDependentString::size_type", "aLength")],
|
||||
inline=True, bodyInHeader=True,
|
||||
body="RawSetAs%s().SetData(aData, aLength);\n" % t.name))
|
||||
body="RawSetAs%s().Rebind(aData, aLength);\n" % t.name))
|
||||
|
||||
if vars["holderType"] is not None:
|
||||
holderType = CGTemplatedType("Maybe",
|
||||
@ -9375,7 +9375,9 @@ class CGProxyNamedOperation(CGProxySpecialOperation):
|
||||
unwrapString = fill(
|
||||
"""
|
||||
if (MOZ_LIKELY(JSID_IS_ATOM(${idName}))) {
|
||||
${argName}.SetData(js::GetAtomChars(JSID_TO_ATOM(${idName})), js::GetAtomLength(JSID_TO_ATOM(${idName})));
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
JSAtom* atom = JSID_TO_ATOM(${idName});
|
||||
${argName}.Rebind(js::GetTwoByteAtomChars(nogc, atom), js::GetAtomLength(atom));
|
||||
} else {
|
||||
nameVal = js::IdToValue(${idName});
|
||||
$*{unwrapString}
|
||||
|
@ -155,7 +155,15 @@ GetArrayIndexFromId(JSContext* cx, JS::Handle<jsid> id)
|
||||
}
|
||||
if (MOZ_LIKELY(JSID_IS_ATOM(id))) {
|
||||
JSAtom* atom = JSID_TO_ATOM(id);
|
||||
jschar s = *js::GetAtomChars(atom);
|
||||
jschar s;
|
||||
{
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
if (js::AtomHasLatin1Chars(atom)) {
|
||||
s = *js::GetLatin1AtomChars(nogc, atom);
|
||||
} else {
|
||||
s = *js::GetTwoByteAtomChars(nogc, atom);
|
||||
}
|
||||
}
|
||||
if (MOZ_LIKELY((unsigned)s >= 'a' && (unsigned)s <= 'z'))
|
||||
return -1;
|
||||
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "XPCWrapper.h"
|
||||
@ -123,6 +125,18 @@ Throw(JSContext* aCx, nsresult aRv, const char* aMessage)
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ThrowAndReport(nsPIDOMWindow* aWindow, nsresult aRv, const char* aMessage)
|
||||
{
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(aWindow))) {
|
||||
return;
|
||||
}
|
||||
|
||||
Throw(jsapi.cx(), aRv, aMessage);
|
||||
(void) JS_ReportPendingException(jsapi.cx());
|
||||
}
|
||||
|
||||
already_AddRefed<Exception>
|
||||
CreateException(JSContext* aCx, nsresult aRv, const char* aMessage)
|
||||
{
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "nsIException.h"
|
||||
|
||||
class nsIStackFrame;
|
||||
class nsPIDOMWindow;
|
||||
template <class T>
|
||||
struct already_AddRefed;
|
||||
|
||||
@ -24,6 +25,11 @@ class Exception;
|
||||
bool
|
||||
Throw(JSContext* cx, nsresult rv, const char* sz = nullptr);
|
||||
|
||||
// Create, throw and report an exception to a given window.
|
||||
void
|
||||
ThrowAndReport(nsPIDOMWindow* aWindow, nsresult aRv,
|
||||
const char* aMessage = nullptr);
|
||||
|
||||
bool
|
||||
ThrowExceptionObject(JSContext* aCx, Exception* aException);
|
||||
|
||||
|
@ -143,7 +143,7 @@ JSEventHandler::HandleEvent(nsIDOMEvent* aEvent)
|
||||
ErrorEvent* scriptEvent = aEvent->InternalDOMEvent()->AsErrorEvent();
|
||||
if (scriptEvent) {
|
||||
scriptEvent->GetMessage(errorMsg);
|
||||
msgOrEvent.SetAsString().SetData(errorMsg.Data(), errorMsg.Length());
|
||||
msgOrEvent.SetAsString().Rebind(errorMsg.Data(), errorMsg.Length());
|
||||
|
||||
scriptEvent->GetFilename(file);
|
||||
fileName = &file;
|
||||
|
@ -9,7 +9,7 @@ interface nsIDOMWindow;
|
||||
|
||||
// Interface to allow the content process socket to reach the IPC bridge.
|
||||
// Implemented in C++ as TCPSocketChild, referenced as _socketBridge in TCPSocket.js
|
||||
[scriptable, uuid(292ebb3a-beac-4e06-88b0-b5b4e88ebd1c)]
|
||||
[scriptable, uuid(4277aff0-4c33-11e3-8f96-0800200c9a66)]
|
||||
interface nsITCPSocketChild : nsISupports
|
||||
{
|
||||
// Tell the chrome process to open a corresponding connection with the given parameters
|
||||
@ -44,4 +44,7 @@ interface nsITCPSocketChild : nsISupports
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
void setSocketAndWindow(in nsITCPSocketInternal socket, in jsval windowVal);
|
||||
|
||||
readonly attribute DOMString host;
|
||||
readonly attribute unsigned short port;
|
||||
};
|
||||
|
@ -12,7 +12,7 @@ interface nsITCPSocketIntermediary;
|
||||
// Interface required to allow the TCP socket object (TCPSocket.js) in the
|
||||
// parent process to talk to the parent IPC actor, TCPSocketParent, which
|
||||
// is written in C++.
|
||||
[scriptable, uuid(868662a4-681c-4b89-9f02-6fe5b7ace265)]
|
||||
[scriptable, uuid(6f040bf0-6852-11e3-949a-0800200c9a66)]
|
||||
interface nsITCPSocketParent : nsISupports
|
||||
{
|
||||
[implicit_jscontext] void initJS(in jsval intermediary);
|
||||
@ -55,6 +55,9 @@ interface nsITCPSocketParent : nsISupports
|
||||
// to make sure the bufferedAmount updated on the child will correspond
|
||||
// to the latest call of send().
|
||||
void sendUpdateBufferedAmount(in uint32_t bufferedAmount, in uint32_t trackingNumber);
|
||||
|
||||
readonly attribute DOMString host;
|
||||
readonly attribute unsigned short port;
|
||||
};
|
||||
|
||||
// Intermediate class to handle sending multiple possible data types
|
||||
|
@ -74,8 +74,24 @@ TCPServerSocketParent::SendCallbackAccept(nsITCPSocketParent *socket)
|
||||
|
||||
_socket->AddIPDLReference();
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsString host;
|
||||
rv = socket->GetHost(host);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Failed to get host from nsITCPSocketParent");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
uint16_t port;
|
||||
rv = socket->GetPort(&port);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Failed to get port from nsITCPSocketParent");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (mNeckoParent) {
|
||||
if (mNeckoParent->SendPTCPSocketConstructor(_psocket)) {
|
||||
if (mNeckoParent->SendPTCPSocketConstructor(_psocket, host, port)) {
|
||||
mozilla::unused << PTCPServerSocketParent::SendCallbackAccept(_psocket);
|
||||
}
|
||||
else {
|
||||
|
@ -437,6 +437,10 @@ TCPSocket.prototype = {
|
||||
that._inputStreamPump = new InputStreamPump(that._socketInputStream, -1, -1, 0, 0, false);
|
||||
that._inputStreamPump.asyncRead(that, null);
|
||||
|
||||
// Grab host/port from SocketTransport.
|
||||
that._host = transport.host;
|
||||
that._port = transport.port;
|
||||
|
||||
return that;
|
||||
},
|
||||
|
||||
@ -448,6 +452,8 @@ TCPSocket.prototype = {
|
||||
that._readyState = kOPEN;
|
||||
socketChild.setSocketAndWindow(that, windowObject);
|
||||
that._socketBridge = socketChild;
|
||||
that._host = socketChild.host;
|
||||
that._port = socketChild.port;
|
||||
|
||||
return that;
|
||||
},
|
||||
|
@ -73,9 +73,16 @@ NS_IMETHODIMP_(MozExternalRefCountType) TCPSocketChild::Release(void)
|
||||
|
||||
TCPSocketChild::TCPSocketChild()
|
||||
: mWindowObj(nullptr)
|
||||
, mHost()
|
||||
, mPort(0)
|
||||
{
|
||||
}
|
||||
|
||||
void TCPSocketChild::Init(const nsString& aHost, const uint16_t& aPort) {
|
||||
mHost = aHost;
|
||||
mPort = aPort;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TCPSocketChild::SendOpen(nsITCPSocketInternal* aSocket,
|
||||
const nsAString& aHost, uint16_t aPort,
|
||||
@ -91,7 +98,7 @@ TCPSocketChild::SendOpen(nsITCPSocketInternal* aSocket,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
AddIPDLReference();
|
||||
gNeckoChild->SendPTCPSocketConstructor(this);
|
||||
gNeckoChild->SendPTCPSocketConstructor(this, nsString(aHost), aPort);
|
||||
PTCPSocketChild::SendOpen(nsString(aHost), aPort,
|
||||
aUseSSL, nsString(aBinaryType));
|
||||
return NS_OK;
|
||||
@ -246,6 +253,20 @@ TCPSocketChild::SetSocketAndWindow(nsITCPSocketInternal *aSocket,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TCPSocketChild::GetHost(nsAString& aHost)
|
||||
{
|
||||
aHost = mHost;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TCPSocketChild::GetPort(uint16_t* aPort)
|
||||
{
|
||||
*aPort = mPort;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
TCPSocketChild::RecvRequestDelete()
|
||||
{
|
||||
|
@ -45,6 +45,8 @@ public:
|
||||
TCPSocketChild();
|
||||
~TCPSocketChild();
|
||||
|
||||
void Init(const nsString& aHost, const uint16_t& aPort);
|
||||
|
||||
virtual bool RecvCallback(const nsString& aType,
|
||||
const CallbackData& aData,
|
||||
const nsString& aReadyState) MOZ_OVERRIDE;
|
||||
@ -53,6 +55,8 @@ public:
|
||||
const uint32_t& aTrackingNumber) MOZ_OVERRIDE;
|
||||
private:
|
||||
JSObject* mWindowObj;
|
||||
nsString mHost;
|
||||
uint16_t mPort;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -278,6 +278,26 @@ TCPSocketParent::SendUpdateBufferedAmount(uint32_t aBufferedAmount,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TCPSocketParent::GetHost(nsAString& aHost)
|
||||
{
|
||||
if (!mSocket) {
|
||||
NS_ERROR("No internal socket instance mSocket!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return mSocket->GetHost(aHost);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TCPSocketParent::GetPort(uint16_t* aPort)
|
||||
{
|
||||
if (!mSocket) {
|
||||
NS_ERROR("No internal socket instance mSocket!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return mSocket->GetPort(aPort);
|
||||
}
|
||||
|
||||
void
|
||||
TCPSocketParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
|
@ -174,6 +174,14 @@ function connectSock() {
|
||||
|
||||
server = TCPSocket.listen(PORT, options, BACKLOG);
|
||||
server.onconnect = function(socket) {
|
||||
// Bug 937528 - Accepted client tcp socket (mozTcpSocket) has
|
||||
// uninitialized host and port.
|
||||
if (socket.host !== '127.0.0.1') {
|
||||
do_throw('got unexpected: connected socket host should be 127.0.0.1 but not ' + socket.host);
|
||||
} else {
|
||||
do_print('Got expected connected socket host: ' + socket.host);
|
||||
}
|
||||
|
||||
connectedsock = socket;
|
||||
connectedsock.ondata = makeFailureCase('serverdata');
|
||||
connectedsock.onerror = makeFailureCase('servererror');
|
||||
@ -187,7 +195,7 @@ function connectSock() {
|
||||
sock.ondrain = null;
|
||||
sock.ondata = makeFailureCase('data');
|
||||
sock.onerror = makeFailureCase('error');
|
||||
sock.onclose = makeFailureCase('close');
|
||||
sock.onclose = makeFailureCase('close');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -197,7 +205,7 @@ function connectSock() {
|
||||
function openSockInClosingServer() {
|
||||
var success = makeSuccessCase('clientnotopen');
|
||||
var options = { binaryType: 'arraybuffer' };
|
||||
|
||||
|
||||
sock = TCPSocket.open(
|
||||
'127.0.0.1', PORT, options);
|
||||
|
||||
|
@ -61,34 +61,11 @@ NS_IMPL_ISUPPORTS(GonkGPSGeolocationProvider,
|
||||
nsISettingsServiceCallback)
|
||||
|
||||
/* static */ GonkGPSGeolocationProvider* GonkGPSGeolocationProvider::sSingleton = nullptr;
|
||||
GpsCallbacks GonkGPSGeolocationProvider::mCallbacks = {
|
||||
sizeof(GpsCallbacks),
|
||||
LocationCallback,
|
||||
StatusCallback,
|
||||
SvStatusCallback,
|
||||
NmeaCallback,
|
||||
SetCapabilitiesCallback,
|
||||
AcquireWakelockCallback,
|
||||
ReleaseWakelockCallback,
|
||||
CreateThreadCallback,
|
||||
#ifdef GPS_CAPABILITY_ON_DEMAND_TIME
|
||||
RequestUtcTimeCallback,
|
||||
#endif
|
||||
};
|
||||
GpsCallbacks GonkGPSGeolocationProvider::mCallbacks;
|
||||
|
||||
#ifdef MOZ_B2G_RIL
|
||||
AGpsCallbacks
|
||||
GonkGPSGeolocationProvider::mAGPSCallbacks = {
|
||||
AGPSStatusCallback,
|
||||
CreateThreadCallback,
|
||||
};
|
||||
|
||||
AGpsRilCallbacks
|
||||
GonkGPSGeolocationProvider::mAGPSRILCallbacks = {
|
||||
AGPSRILSetIDCallback,
|
||||
AGPSRILRefLocCallback,
|
||||
CreateThreadCallback,
|
||||
};
|
||||
AGpsCallbacks GonkGPSGeolocationProvider::mAGPSCallbacks;
|
||||
AGpsRilCallbacks GonkGPSGeolocationProvider::mAGPSRILCallbacks;
|
||||
#endif // MOZ_B2G_RIL
|
||||
|
||||
void
|
||||
@ -564,6 +541,31 @@ GonkGPSGeolocationProvider::Init()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mCallbacks.size) {
|
||||
mCallbacks.size = sizeof(GpsCallbacks);
|
||||
mCallbacks.location_cb = LocationCallback;
|
||||
mCallbacks.status_cb = StatusCallback;
|
||||
mCallbacks.sv_status_cb = SvStatusCallback;
|
||||
mCallbacks.nmea_cb = NmeaCallback;
|
||||
mCallbacks.set_capabilities_cb = SetCapabilitiesCallback;
|
||||
mCallbacks.acquire_wakelock_cb = AcquireWakelockCallback;
|
||||
mCallbacks.release_wakelock_cb = ReleaseWakelockCallback;
|
||||
mCallbacks.create_thread_cb = CreateThreadCallback;
|
||||
|
||||
#ifdef GPS_CAPABILITY_ON_DEMAND_TIME
|
||||
mCallbacks.request_utc_time_cb = RequestUtcTimeCallback;
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_RIL
|
||||
mAGPSCallbacks.status_cb = AGPSStatusCallback;
|
||||
mAGPSCallbacks.create_thread_cb = CreateThreadCallback;
|
||||
|
||||
mAGPSRILCallbacks.request_setid = AGPSRILSetIDCallback;
|
||||
mAGPSRILCallbacks.request_refloc = AGPSRILRefLocCallback;
|
||||
mAGPSRILCallbacks.create_thread_cb = CreateThreadCallback;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (mGpsInterface->init(&mCallbacks) != 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -1576,6 +1576,15 @@ RadioInterfaceLayer.prototype = {
|
||||
return this.radioInterfaces[clientId];
|
||||
},
|
||||
|
||||
getClientIdForEmergencyCall: function() {
|
||||
for (let cid = 0; cid < this.numRadioInterfaces; ++cid) {
|
||||
if (gRadioEnabledController._isRadioAbleToEnableAtClient(cid)) {
|
||||
return cid;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
|
||||
setMicrophoneMuted: function(muted) {
|
||||
for (let clientId = 0; clientId < this.numRadioInterfaces; clientId++) {
|
||||
let radioInterface = this.radioInterfaces[clientId];
|
||||
|
@ -93,12 +93,19 @@ interface nsIRadioInterface : nsISupports
|
||||
void getNeighboringCellIds(in nsINeighboringCellIdsCallback callback);
|
||||
};
|
||||
|
||||
[scriptable, uuid(d035c32e-b491-11e3-9f9d-c716fab88bd6)]
|
||||
[scriptable, uuid(78b65e8c-68e7-4510-9a05-65bba12b283e)]
|
||||
interface nsIRadioInterfaceLayer : nsISupports
|
||||
{
|
||||
readonly attribute unsigned long numRadioInterfaces;
|
||||
|
||||
nsIRadioInterface getRadioInterface(in unsigned long clientId);
|
||||
|
||||
/**
|
||||
* Select a proper client for dialing emergency call.
|
||||
*
|
||||
* @return clientId or -1 if none of the clients are avaialble.
|
||||
*/
|
||||
unsigned long getClientIdForEmergencyCall();
|
||||
|
||||
void setMicrophoneMuted(in boolean muted);
|
||||
};
|
||||
|
@ -374,60 +374,71 @@ TelephonyService.prototype = {
|
||||
aListener.enumerateCallStateComplete();
|
||||
},
|
||||
|
||||
_hasCallsOnOtherClient: function(aClientId) {
|
||||
for (let cid = 0; cid < this._numClients; ++cid) {
|
||||
if (cid === aClientId) {
|
||||
continue;
|
||||
}
|
||||
if (Object.keys(this._currentCalls[cid]).length !== 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
// All calls in the conference is regarded as one conference call.
|
||||
_numCallsOnLine: function(aClientId) {
|
||||
let numCalls = 0;
|
||||
let hasConference = false;
|
||||
|
||||
for (let cid in this._currentCalls[aClientId]) {
|
||||
let call = this._currentCalls[aClientId][cid];
|
||||
if (call.isConference) {
|
||||
hasConference = true;
|
||||
} else {
|
||||
numCalls++;
|
||||
}
|
||||
}
|
||||
|
||||
return hasConference ? numCalls + 1 : numCalls;
|
||||
},
|
||||
|
||||
isDialing: false,
|
||||
dial: function(aClientId, aNumber, aIsEmergency, aTelephonyCallback) {
|
||||
if (DEBUG) debug("Dialing " + (aIsEmergency ? "emergency " : "") + aNumber);
|
||||
|
||||
if (this.isDialing) {
|
||||
if (DEBUG) debug("Already has a dialing call. Drop.");
|
||||
if (DEBUG) debug("Error: Already has a dialing call.");
|
||||
aTelephonyCallback.notifyDialError(DIAL_ERROR_INVALID_STATE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
function hasCallsOnOtherClient(aClientId) {
|
||||
for (let cid = 0; cid < this._numClients; ++cid) {
|
||||
if (cid === aClientId) {
|
||||
continue;
|
||||
}
|
||||
if (Object.keys(this._currentCalls[cid]).length !== 0) {
|
||||
return true;
|
||||
}
|
||||
// Select a proper clientId for dialEmergency.
|
||||
if (aIsEmergency) {
|
||||
aClientId = gRadioInterfaceLayer.getClientIdForEmergencyCall() ;
|
||||
if (aClientId === -1) {
|
||||
if (DEBUG) debug("Error: No client is avaialble for emergency call.");
|
||||
aTelephonyCallback.notifyDialError(DIAL_ERROR_INVALID_STATE_ERROR);
|
||||
return;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// For DSDS, if there is aleady a call on SIM 'aClientId', we cannot place
|
||||
// any new call on other SIM.
|
||||
if (hasCallsOnOtherClient.call(this, aClientId)) {
|
||||
if (DEBUG) debug("Already has a call on other sim. Drop.");
|
||||
if (this._hasCallsOnOtherClient(aClientId)) {
|
||||
if (DEBUG) debug("Error: Already has a call on other sim.");
|
||||
aTelephonyCallback.notifyDialError(DIAL_ERROR_OTHER_CONNECTION_IN_USE);
|
||||
return;
|
||||
}
|
||||
|
||||
// All calls in the conference is regarded as one conference call.
|
||||
function numCallsOnLine(aClientId) {
|
||||
let numCalls = 0;
|
||||
let hasConference = false;
|
||||
|
||||
for (let cid in this._currentCalls[aClientId]) {
|
||||
let call = this._currentCalls[aClientId][cid];
|
||||
if (call.isConference) {
|
||||
hasConference = true;
|
||||
} else {
|
||||
numCalls++;
|
||||
}
|
||||
}
|
||||
|
||||
return hasConference ? numCalls + 1 : numCalls;
|
||||
}
|
||||
|
||||
if (numCallsOnLine.call(this, aClientId) >= 2) {
|
||||
if (DEBUG) debug("Has more than 2 calls on line. Drop.");
|
||||
// We can only have at most two calls on the same line (client).
|
||||
if (this._numCallsOnLine(aClientId) >= 2) {
|
||||
if (DEBUG) debug("Error: Has more than 2 calls on line.");
|
||||
aTelephonyCallback.notifyDialError(DIAL_ERROR_INVALID_STATE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// we don't try to be too clever here, as the phone is probably in the
|
||||
// We don't try to be too clever here, as the phone is probably in the
|
||||
// locked state. Let's just check if it's a number without normalizing
|
||||
if (!aIsEmergency) {
|
||||
aNumber = gPhoneNumberUtils.normalize(aNumber);
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseWorkerProxy.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
#include "WorkerPrivate.h"
|
||||
@ -217,16 +218,13 @@ protected:
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
// Get the JSContext for the target window
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo =
|
||||
do_QueryInterface(static_cast<DOMEventTargetHelper*>
|
||||
(mBackingStore.get())->GetOwner());
|
||||
MOZ_ASSERT(sgo);
|
||||
|
||||
nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
|
||||
AutoPushJSContext cx(scriptContext ? scriptContext->GetNativeContext()
|
||||
: nsContentUtils::GetSafeJSContext());
|
||||
MOZ_ASSERT(cx);
|
||||
// Initialise an AutoJSAPI with the target window.
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(mBackingStore->GetParentObject()))) {
|
||||
mRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return true;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
JS::Rooted<JS::Value> value(cx);
|
||||
if (!mObjBuffer.read(cx, &value)) {
|
||||
@ -287,16 +285,13 @@ protected:
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
// Get the JSContext for the target window
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo =
|
||||
do_QueryInterface(static_cast<DOMEventTargetHelper*>
|
||||
(mBackingStore.get())->GetOwner());
|
||||
MOZ_ASSERT(sgo);
|
||||
|
||||
nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
|
||||
AutoPushJSContext cx(scriptContext ? scriptContext->GetNativeContext()
|
||||
: nsContentUtils::GetSafeJSContext());
|
||||
MOZ_ASSERT(cx);
|
||||
// Initialise an AutoJSAPI with the target window.
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(mBackingStore->GetParentObject()))) {
|
||||
mRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return true;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
JS::Rooted<JS::Value> value(cx);
|
||||
if (!mObjBuffer.read(cx, &value)) {
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "mozilla/dom/EventTargetBinding.h"
|
||||
#include "mozilla/dom/MessageEventBinding.h"
|
||||
#include "mozilla/dom/WorkerBinding.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/Navigator.h"
|
||||
@ -2070,14 +2071,11 @@ RuntimeService::CancelWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
GetWorkersForWindow(aWindow, workers);
|
||||
|
||||
if (!workers.IsEmpty()) {
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aWindow);
|
||||
MOZ_ASSERT(sgo);
|
||||
|
||||
nsIScriptContext* scx = sgo->GetContext();
|
||||
|
||||
AutoPushJSContext cx(scx ?
|
||||
scx->GetNativeContext() :
|
||||
nsContentUtils::GetSafeJSContext());
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(aWindow))) {
|
||||
return;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
for (uint32_t index = 0; index < workers.Length(); index++) {
|
||||
WorkerPrivate*& worker = workers[index];
|
||||
@ -2101,14 +2099,11 @@ RuntimeService::SuspendWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
GetWorkersForWindow(aWindow, workers);
|
||||
|
||||
if (!workers.IsEmpty()) {
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aWindow);
|
||||
MOZ_ASSERT(sgo);
|
||||
|
||||
nsIScriptContext* scx = sgo->GetContext();
|
||||
|
||||
AutoPushJSContext cx(scx ?
|
||||
scx->GetNativeContext() :
|
||||
nsContentUtils::GetSafeJSContext());
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(aWindow))) {
|
||||
return;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
for (uint32_t index = 0; index < workers.Length(); index++) {
|
||||
if (!workers[index]->Suspend(cx, aWindow)) {
|
||||
@ -2128,17 +2123,14 @@ RuntimeService::ResumeWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||
GetWorkersForWindow(aWindow, workers);
|
||||
|
||||
if (!workers.IsEmpty()) {
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aWindow);
|
||||
MOZ_ASSERT(sgo);
|
||||
|
||||
nsIScriptContext* scx = sgo->GetContext();
|
||||
|
||||
AutoPushJSContext cx(scx ?
|
||||
scx->GetNativeContext() :
|
||||
nsContentUtils::GetSafeJSContext());
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(aWindow))) {
|
||||
return;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
for (uint32_t index = 0; index < workers.Length(); index++) {
|
||||
if (!workers[index]->SynchronizeAndResume(cx, aWindow, scx)) {
|
||||
if (!workers[index]->SynchronizeAndResume(cx, aWindow)) {
|
||||
JS_ReportPendingException(cx);
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "mozilla/dom/MessageEvent.h"
|
||||
#include "mozilla/dom/MessageEventBinding.h"
|
||||
#include "mozilla/dom/MessagePortList.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/WorkerBinding.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsAlgorithm.h"
|
||||
@ -218,17 +219,10 @@ private:
|
||||
struct WindowAction
|
||||
{
|
||||
nsPIDOMWindow* mWindow;
|
||||
JSContext* mJSContext;
|
||||
bool mDefaultAction;
|
||||
|
||||
WindowAction(nsPIDOMWindow* aWindow, JSContext* aJSContext)
|
||||
: mWindow(aWindow), mJSContext(aJSContext), mDefaultAction(true)
|
||||
{
|
||||
MOZ_ASSERT(aJSContext);
|
||||
}
|
||||
|
||||
WindowAction(nsPIDOMWindow* aWindow)
|
||||
: mWindow(aWindow), mJSContext(nullptr), mDefaultAction(true)
|
||||
: mWindow(aWindow), mDefaultAction(true)
|
||||
{ }
|
||||
|
||||
bool
|
||||
@ -1843,14 +1837,11 @@ class WorkerPrivateParent<Derived>::SynchronizeAndResumeRunnable MOZ_FINAL
|
||||
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
nsCOMPtr<nsIScriptContext> mScriptContext;
|
||||
|
||||
public:
|
||||
SynchronizeAndResumeRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
nsPIDOMWindow* aWindow,
|
||||
nsIScriptContext* aScriptContext)
|
||||
: mWorkerPrivate(aWorkerPrivate), mWindow(aWindow),
|
||||
mScriptContext(aScriptContext)
|
||||
nsPIDOMWindow* aWindow)
|
||||
: mWorkerPrivate(aWorkerPrivate), mWindow(aWindow)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
@ -1868,9 +1859,11 @@ private:
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (mWorkerPrivate) {
|
||||
AutoPushJSContext cx(mScriptContext ?
|
||||
mScriptContext->GetNativeContext() :
|
||||
nsContentUtils::GetSafeJSContext());
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(mWindow))) {
|
||||
return NS_OK;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
if (!mWorkerPrivate->Resume(cx, mWindow)) {
|
||||
JS_ReportPendingException(cx);
|
||||
@ -1889,7 +1882,6 @@ private:
|
||||
|
||||
mWorkerPrivate = nullptr;
|
||||
mWindow = nullptr;
|
||||
mScriptContext = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
@ -2609,8 +2601,7 @@ template <class Derived>
|
||||
bool
|
||||
WorkerPrivateParent<Derived>::SynchronizeAndResume(
|
||||
JSContext* aCx,
|
||||
nsPIDOMWindow* aWindow,
|
||||
nsIScriptContext* aScriptContext)
|
||||
nsPIDOMWindow* aWindow)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(!GetParent());
|
||||
@ -2623,8 +2614,7 @@ WorkerPrivateParent<Derived>::SynchronizeAndResume(
|
||||
// the messages.
|
||||
|
||||
nsRefPtr<SynchronizeAndResumeRunnable> runnable =
|
||||
new SynchronizeAndResumeRunnable(ParentAsWorkerPrivate(), aWindow,
|
||||
aScriptContext);
|
||||
new SynchronizeAndResumeRunnable(ParentAsWorkerPrivate(), aWindow);
|
||||
if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
|
||||
JS_ReportError(aCx, "Failed to dispatch to current thread!");
|
||||
return false;
|
||||
@ -2824,16 +2814,11 @@ WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo;
|
||||
port->GetParentObject(getter_AddRefs(sgo));
|
||||
MOZ_ASSERT(sgo, "Should never happen if IsClosed() returned false!");
|
||||
MOZ_ASSERT(sgo->GetGlobalJSObject());
|
||||
|
||||
nsCOMPtr<nsIScriptContext> scx = sgo->GetContext();
|
||||
MOZ_ASSERT_IF(scx, scx->GetNativeContext());
|
||||
|
||||
AutoPushJSContext cx(scx ? scx->GetNativeContext() : aCx);
|
||||
JSAutoCompartment(cx, sgo->GetGlobalJSObject());
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(port->GetParentObject()))) {
|
||||
return false;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
JS::Rooted<JS::Value> data(cx);
|
||||
if (!buffer.read(cx, &data, WorkerStructuredCloneCallbacks(true))) {
|
||||
@ -3149,14 +3134,6 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
|
||||
// May be null.
|
||||
nsPIDOMWindow* window = sharedWorker->GetOwner();
|
||||
|
||||
size_t actionsIndex = windowActions.LastIndexOf(WindowAction(window));
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(sharedWorker->GetOwner()))) {
|
||||
continue;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
RootedDictionary<ErrorEventInit> errorInit(aCx);
|
||||
errorInit.mBubbles = false;
|
||||
errorInit.mCancelable = true;
|
||||
@ -3169,8 +3146,7 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
|
||||
ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"),
|
||||
errorInit);
|
||||
if (!errorEvent) {
|
||||
Throw(cx, NS_ERROR_UNEXPECTED);
|
||||
JS_ReportPendingException(cx);
|
||||
ThrowAndReport(window, NS_ERROR_UNEXPECTED);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -3179,8 +3155,7 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
|
||||
bool defaultActionEnabled;
|
||||
nsresult rv = sharedWorker->DispatchEvent(errorEvent, &defaultActionEnabled);
|
||||
if (NS_FAILED(rv)) {
|
||||
Throw(cx, rv);
|
||||
JS_ReportPendingException(cx);
|
||||
ThrowAndReport(window, rv);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -3188,12 +3163,15 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
|
||||
// Add the owning window to our list so that we will fire an error event
|
||||
// at it later.
|
||||
if (!windowActions.Contains(window)) {
|
||||
windowActions.AppendElement(WindowAction(window, cx));
|
||||
windowActions.AppendElement(WindowAction(window));
|
||||
}
|
||||
} else {
|
||||
size_t actionsIndex = windowActions.LastIndexOf(WindowAction(window));
|
||||
if (actionsIndex != windowActions.NoIndex) {
|
||||
// Any listener that calls preventDefault() will prevent the window from
|
||||
// receiving the error event.
|
||||
windowActions[actionsIndex].mDefaultAction = false;
|
||||
}
|
||||
} else if (actionsIndex != windowActions.NoIndex) {
|
||||
// Any listener that calls preventDefault() will prevent the window from
|
||||
// receiving the error event.
|
||||
windowActions[actionsIndex].mDefaultAction = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3214,10 +3192,6 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
|
||||
continue;
|
||||
}
|
||||
|
||||
JSContext* cx = windowAction.mJSContext;
|
||||
|
||||
AutoCxPusher autoPush(cx);
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo =
|
||||
do_QueryInterface(windowAction.mWindow);
|
||||
MOZ_ASSERT(sgo);
|
||||
@ -3233,8 +3207,7 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
rv = sgo->HandleScriptError(init, &status);
|
||||
if (NS_FAILED(rv)) {
|
||||
Throw(cx, rv);
|
||||
JS_ReportPendingException(cx);
|
||||
ThrowAndReport(windowAction.mWindow, rv);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -339,6 +339,9 @@ public:
|
||||
return Notify(aCx, Killing);
|
||||
}
|
||||
|
||||
// We can assume that an nsPIDOMWindow will be available for Suspend, Resume
|
||||
// and SynchronizeAndResume as these are only used for globals going in and
|
||||
// out of the bfcache.
|
||||
bool
|
||||
Suspend(JSContext* aCx, nsPIDOMWindow* aWindow);
|
||||
|
||||
@ -346,8 +349,7 @@ public:
|
||||
Resume(JSContext* aCx, nsPIDOMWindow* aWindow);
|
||||
|
||||
bool
|
||||
SynchronizeAndResume(JSContext* aCx, nsPIDOMWindow* aWindow,
|
||||
nsIScriptContext* aScriptContext);
|
||||
SynchronizeAndResume(JSContext* aCx, nsPIDOMWindow* aWindow);
|
||||
|
||||
bool
|
||||
Terminate(JSContext* aCx)
|
||||
|
@ -817,7 +817,7 @@ function ArrayReducePar(func, mode) {
|
||||
var numSlices = slicesInfo.count;
|
||||
var subreductions = NewDenseArray(numSlices);
|
||||
|
||||
ForkJoin(reduceThread, 0, numSlices, ForkJoinMode(mode), null);
|
||||
ForkJoin(reduceThread, 0, numSlices, ForkJoinMode(mode), subreductions);
|
||||
|
||||
var accumulator = subreductions[0];
|
||||
for (var i = 1; i < numSlices; i++)
|
||||
|
@ -419,6 +419,45 @@ function rpowhalf_object(i) {
|
||||
return i;
|
||||
}
|
||||
|
||||
var uceFault_min_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_min_number'));
|
||||
function rmin_number(i) {
|
||||
var x = Math.min(i, i-1, i-2.1);
|
||||
if (uceFault_min_number(i) || uceFault_min_number(i))
|
||||
assertEq(x, i-2.1);
|
||||
return i;
|
||||
}
|
||||
|
||||
var uceFault_min_object = eval(uneval(uceFault).replace('uceFault', 'uceFault_min_object'));
|
||||
function rmin_object(i) {
|
||||
var t = i;
|
||||
var o = { valueOf: function () { return t; } };
|
||||
var x = Math.min(o, o-1, o-2.1)
|
||||
t = 1000;
|
||||
if (uceFault_min_object(i) || uceFault_min_object(i))
|
||||
assertEq(x, i-2.1);
|
||||
return i;
|
||||
}
|
||||
|
||||
var uceFault_max_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_max_number'));
|
||||
function rmax_number(i) {
|
||||
var x = Math.max(i, i-1, i-2.1);
|
||||
if (uceFault_max_number(i) || uceFault_max_number(i))
|
||||
assertEq(x, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
var uceFault_max_object = eval(uneval(uceFault).replace('uceFault', 'uceFault_max_object'));
|
||||
function rmax_object(i) {
|
||||
var t = i;
|
||||
var o = { valueOf: function () { return t; } };
|
||||
var x = Math.max(o, o-1, o-2.1)
|
||||
t = 1000;
|
||||
if (uceFault_max_object(i) || uceFault_max_object(i))
|
||||
assertEq(x, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
rbitnot_number(i);
|
||||
rbitnot_object(i);
|
||||
@ -464,6 +503,10 @@ for (i = 0; i < 100; i++) {
|
||||
rpow_object(i);
|
||||
rpowhalf_number(i);
|
||||
rpowhalf_object(i);
|
||||
rmin_number(i);
|
||||
rmin_object(i);
|
||||
rmax_number(i);
|
||||
rmax_object(i);
|
||||
}
|
||||
|
||||
// Test that we can refer multiple time to the same recover instruction, as well
|
||||
|
21
js/src/jit-test/tests/parallel/bug1033115-2.js
Normal file
21
js/src/jit-test/tests/parallel/bug1033115-2.js
Normal file
@ -0,0 +1,21 @@
|
||||
// Failed to pass the subreductions as an assignment root to Array.prototype.reducePar,
|
||||
// fuzzing test case discovered separately.
|
||||
|
||||
if (!getBuildConfiguration().parallelJS)
|
||||
quit(0);
|
||||
|
||||
x = [];
|
||||
y = x.mapPar(function() {});
|
||||
Object.defineProperty(y, 3, {
|
||||
get: (function( ... $8) {
|
||||
try {
|
||||
Int8Array(y);
|
||||
x.reducePar(function() function q() 1);
|
||||
} catch (e) {}
|
||||
})
|
||||
});
|
||||
var x = [1,2,3];
|
||||
function rsh() {
|
||||
return y.toSource() >> 2.0;
|
||||
}
|
||||
rsh();
|
13
js/src/jit-test/tests/parallel/bug1033115.js
Normal file
13
js/src/jit-test/tests/parallel/bug1033115.js
Normal file
@ -0,0 +1,13 @@
|
||||
// Failed to pass the subreductions as an assignment root to Array.prototype.reducePar,
|
||||
// fuzzing test case.
|
||||
|
||||
if (!getBuildConfiguration().parallelJS)
|
||||
quit(0);
|
||||
|
||||
x = []
|
||||
x[8] = ((function() {})());
|
||||
for each(let a in [0, 0]) {
|
||||
x.reducePar(function() {
|
||||
return [0];
|
||||
});
|
||||
}
|
@ -7769,8 +7769,9 @@ CodeGenerator::emitLoadElementT(LLoadElementT *lir, const T &source)
|
||||
{
|
||||
if (LIRGenerator::allowTypedElementHoleCheck()) {
|
||||
if (lir->mir()->needsHoleCheck()) {
|
||||
Assembler::Condition cond = masm.testMagic(Assembler::Equal, source);
|
||||
if (!bailoutIf(cond, lir->snapshot()))
|
||||
Label bail;
|
||||
masm.branchTestMagic(Assembler::Equal, source, &bail);
|
||||
if (!bailoutFrom(&bail, lir->snapshot()))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -3936,6 +3936,10 @@ class MMinMax
|
||||
return AliasSet::None();
|
||||
}
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool writeRecoverData(CompactBufferWriter &writer) const;
|
||||
bool canRecoverOnBailout() const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class MAbs
|
||||
|
@ -710,6 +710,34 @@ RPowHalf::recover(JSContext *cx, SnapshotIterator &iter) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MMinMax::writeRecoverData(CompactBufferWriter &writer) const
|
||||
{
|
||||
MOZ_ASSERT(canRecoverOnBailout());
|
||||
writer.writeUnsigned(uint32_t(RInstruction::Recover_MinMax));
|
||||
writer.writeByte(isMax_);
|
||||
return true;
|
||||
}
|
||||
|
||||
RMinMax::RMinMax(CompactBufferReader &reader)
|
||||
{
|
||||
isMax_ = reader.readByte();
|
||||
}
|
||||
|
||||
bool
|
||||
RMinMax::recover(JSContext *cx, SnapshotIterator &iter) const
|
||||
{
|
||||
RootedValue a(cx, iter.read());
|
||||
RootedValue b(cx, iter.read());
|
||||
RootedValue result(cx);
|
||||
|
||||
if (!js_minmax_impl(cx, isMax_, a, b, &result))
|
||||
return false;
|
||||
|
||||
iter.storeInstructionResult(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MMathFunction::writeRecoverData(CompactBufferWriter &writer) const
|
||||
{
|
||||
|
@ -39,6 +39,7 @@ namespace jit {
|
||||
_(FromCharCode) \
|
||||
_(Pow) \
|
||||
_(PowHalf) \
|
||||
_(MinMax) \
|
||||
_(NewObject) \
|
||||
_(NewDerivedTypedObject)
|
||||
|
||||
@ -372,6 +373,21 @@ class RPowHalf MOZ_FINAL : public RInstruction
|
||||
bool recover(JSContext *cx, SnapshotIterator &iter) const;
|
||||
};
|
||||
|
||||
class RMinMax MOZ_FINAL : public RInstruction
|
||||
{
|
||||
private:
|
||||
bool isMax_;
|
||||
|
||||
public:
|
||||
RINSTRUCTION_HEADER_(MinMax)
|
||||
|
||||
virtual uint32_t numOperands() const {
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool recover(JSContext *cx, SnapshotIterator &iter) const;
|
||||
};
|
||||
|
||||
class RNewObject MOZ_FINAL : public RInstruction
|
||||
{
|
||||
private:
|
||||
|
@ -793,18 +793,19 @@ CodeGeneratorMIPS::visitModMaskI(LModMaskI *ins)
|
||||
{
|
||||
Register src = ToRegister(ins->getOperand(0));
|
||||
Register dest = ToRegister(ins->getDef(0));
|
||||
Register tmp = ToRegister(ins->getTemp(0));
|
||||
Register tmp0 = ToRegister(ins->getTemp(0));
|
||||
Register tmp1 = ToRegister(ins->getTemp(1));
|
||||
MMod *mir = ins->mir();
|
||||
|
||||
if (!mir->isTruncated() && mir->canBeNegativeDividend()) {
|
||||
MOZ_ASSERT(mir->fallible());
|
||||
|
||||
Label bail;
|
||||
masm.ma_mod_mask(src, dest, tmp, ins->shift(), &bail);
|
||||
masm.ma_mod_mask(src, dest, tmp0, tmp1, ins->shift(), &bail);
|
||||
if (!bailoutFrom(&bail, ins->snapshot()))
|
||||
return false;
|
||||
} else {
|
||||
masm.ma_mod_mask(src, dest, tmp, ins->shift(), nullptr);
|
||||
masm.ma_mod_mask(src, dest, tmp0, tmp1, ins->shift(), nullptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -208,18 +208,20 @@ class LModPowTwoI : public LInstructionHelper<1, 1, 0>
|
||||
}
|
||||
};
|
||||
|
||||
class LModMaskI : public LInstructionHelper<1, 1, 1>
|
||||
class LModMaskI : public LInstructionHelper<1, 1, 2>
|
||||
{
|
||||
const int32_t shift_;
|
||||
|
||||
public:
|
||||
LIR_HEADER(ModMaskI);
|
||||
|
||||
LModMaskI(const LAllocation &lhs, const LDefinition &temp1, int32_t shift)
|
||||
LModMaskI(const LAllocation &lhs, const LDefinition &temp0, const LDefinition &temp1,
|
||||
int32_t shift)
|
||||
: shift_(shift)
|
||||
{
|
||||
setOperand(0, lhs);
|
||||
setTemp(0, temp1);
|
||||
setTemp(0, temp0);
|
||||
setTemp(1, temp1);
|
||||
}
|
||||
|
||||
int32_t shift() const {
|
||||
|
@ -322,7 +322,9 @@ LIRGeneratorMIPS::lowerModI(MMod *mod)
|
||||
return define(lir, mod);
|
||||
} else if (shift < 31 && (1 << (shift + 1)) - 1 == rhs) {
|
||||
LModMaskI *lir = new(alloc()) LModMaskI(useRegister(mod->lhs()),
|
||||
temp(LDefinition::GENERAL), shift + 1);
|
||||
temp(LDefinition::GENERAL),
|
||||
temp(LDefinition::GENERAL),
|
||||
shift + 1);
|
||||
if (mod->fallible() && !assignSnapshot(lir, Bailout_DoubleOutput))
|
||||
return false;
|
||||
return define(lir, mod);
|
||||
|
@ -620,8 +620,8 @@ MacroAssemblerMIPS::ma_div_branch_overflow(Register rd, Register rs, Imm32 imm,
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPS::ma_mod_mask(Register src, Register dest, Register hold, int32_t shift,
|
||||
Label *negZero)
|
||||
MacroAssemblerMIPS::ma_mod_mask(Register src, Register dest, Register hold, Register remain,
|
||||
int32_t shift, Label *negZero)
|
||||
{
|
||||
// MATH:
|
||||
// We wish to compute x % (1<<y) - 1 for a known constant, y.
|
||||
@ -641,34 +641,32 @@ MacroAssemblerMIPS::ma_mod_mask(Register src, Register dest, Register hold, int3
|
||||
Label head, negative, sumSigned, done;
|
||||
|
||||
// hold holds -1 if the value was negative, 1 otherwise.
|
||||
// ScratchRegister holds the remaining bits that have not been processed
|
||||
// lr serves as a temporary location to store extracted bits into as well
|
||||
// as holding the trial subtraction as a temp value dest is the
|
||||
// accumulator (and holds the final result)
|
||||
// remain holds the remaining bits that have not been processed
|
||||
// SecondScratchReg serves as a temporary location to store extracted bits
|
||||
// into as well as holding the trial subtraction as a temp value dest is
|
||||
// the accumulator (and holds the final result)
|
||||
|
||||
// move the whole value into the scratch register, setting the codition
|
||||
// codes so we can muck with them later.
|
||||
ma_move(ScratchRegister, src);
|
||||
// move the whole value into the remain.
|
||||
ma_move(remain, src);
|
||||
// Zero out the dest.
|
||||
ma_subu(dest, dest, dest);
|
||||
ma_li(dest, Imm32(0));
|
||||
// Set the hold appropriately.
|
||||
ma_b(ScratchRegister, ScratchRegister, &negative, Signed, ShortJump);
|
||||
ma_b(remain, remain, &negative, Signed, ShortJump);
|
||||
ma_li(hold, Imm32(1));
|
||||
ma_b(&head, ShortJump);
|
||||
|
||||
bind(&negative);
|
||||
ma_li(hold, Imm32(-1));
|
||||
ma_negu(ScratchRegister, ScratchRegister);
|
||||
ma_negu(remain, remain);
|
||||
|
||||
// Begin the main loop.
|
||||
bind(&head);
|
||||
|
||||
// Extract the bottom bits into lr.
|
||||
ma_and(SecondScratchReg, ScratchRegister, Imm32(mask));
|
||||
// Extract the bottom bits into SecondScratchReg.
|
||||
ma_and(SecondScratchReg, remain, Imm32(mask));
|
||||
// Add those bits to the accumulator.
|
||||
as_addu(dest, dest, SecondScratchReg);
|
||||
// Do a trial subtraction, this is the same operation as cmp, but we
|
||||
// store the dest
|
||||
// Do a trial subtraction
|
||||
ma_subu(SecondScratchReg, dest, Imm32(mask));
|
||||
// If (sum - C) > 0, store sum - C back into sum, thus performing a
|
||||
// modulus.
|
||||
@ -676,9 +674,9 @@ MacroAssemblerMIPS::ma_mod_mask(Register src, Register dest, Register hold, int3
|
||||
ma_move(dest, SecondScratchReg);
|
||||
bind(&sumSigned);
|
||||
// Get rid of the bits that we extracted before.
|
||||
as_srl(ScratchRegister, ScratchRegister, shift);
|
||||
as_srl(remain, remain, shift);
|
||||
// If the shift produced zero, finish, otherwise, continue in the loop.
|
||||
ma_b(ScratchRegister, ScratchRegister, &head, NonZero, ShortJump);
|
||||
ma_b(remain, remain, &head, NonZero, ShortJump);
|
||||
// Check the hold to see if we need to negate the result.
|
||||
ma_b(hold, hold, &done, NotSigned, ShortJump);
|
||||
|
||||
@ -1674,6 +1672,12 @@ MacroAssemblerMIPSCompat::not32(Register reg)
|
||||
}
|
||||
|
||||
// Logical operations
|
||||
void
|
||||
MacroAssemblerMIPSCompat::and32(Register src, Register dest)
|
||||
{
|
||||
ma_and(dest, dest, src);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::and32(Imm32 imm, Register dest)
|
||||
{
|
||||
@ -1688,6 +1692,13 @@ MacroAssemblerMIPSCompat::and32(Imm32 imm, const Address &dest)
|
||||
store32(SecondScratchReg, dest);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::and32(const Address &src, Register dest)
|
||||
{
|
||||
load32(src, SecondScratchReg);
|
||||
ma_and(dest, SecondScratchReg);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::or32(Imm32 imm, const Address &dest)
|
||||
{
|
||||
@ -2024,6 +2035,12 @@ MacroAssemblerMIPSCompat::storePtr(Register src, const Address &address)
|
||||
ma_sw(src, address);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::storePtr(Register src, const BaseIndex &address)
|
||||
{
|
||||
ma_store(src, address, SizeWord);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::storePtr(Register src, AbsoluteAddress dest)
|
||||
{
|
||||
@ -2082,6 +2099,13 @@ MacroAssemblerMIPSCompat::subPtr(Imm32 imm, const Register dest)
|
||||
ma_subu(dest, dest, imm);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::subPtr(const Address &addr, const Register dest)
|
||||
{
|
||||
loadPtr(addr, SecondScratchReg);
|
||||
subPtr(SecondScratchReg, dest);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::subPtr(Register src, const Address &dest)
|
||||
{
|
||||
@ -2713,6 +2737,35 @@ MacroAssemblerMIPSCompat::getType(const Value &val)
|
||||
return jv.s.tag;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
MacroAssemblerMIPSCompat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T &dest,
|
||||
MIRType slotType)
|
||||
{
|
||||
if (valueType == MIRType_Double) {
|
||||
storeDouble(value.reg().typedReg().fpu(), dest);
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the type tag if needed.
|
||||
if (valueType != slotType)
|
||||
storeTypeTag(ImmType(ValueTypeFromMIRType(valueType)), dest);
|
||||
|
||||
// Store the payload.
|
||||
if (value.constant())
|
||||
storePayload(value.value(), dest);
|
||||
else
|
||||
storePayload(value.reg().typedReg().gpr(), dest);
|
||||
}
|
||||
|
||||
template void
|
||||
MacroAssemblerMIPSCompat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const Address &dest,
|
||||
MIRType slotType);
|
||||
|
||||
template void
|
||||
MacroAssemblerMIPSCompat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex &dest,
|
||||
MIRType slotType);
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::moveData(const Value &val, Register data)
|
||||
{
|
||||
@ -2904,10 +2957,11 @@ MacroAssemblerMIPSCompat::storePayload(Register src, Address dest)
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::storePayload(const Value &val, Register base, Register index,
|
||||
int32_t shift)
|
||||
MacroAssemblerMIPSCompat::storePayload(const Value &val, const BaseIndex &dest)
|
||||
{
|
||||
computeScaledAddress(BaseIndex(base, index, ShiftToScale(shift)), SecondScratchReg);
|
||||
MOZ_ASSERT(dest.offset == 0);
|
||||
|
||||
computeScaledAddress(dest, SecondScratchReg);
|
||||
|
||||
moveData(val, ScratchRegister);
|
||||
|
||||
@ -2915,9 +2969,11 @@ MacroAssemblerMIPSCompat::storePayload(const Value &val, Register base, Register
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::storePayload(Register src, Register base, Register index, int32_t shift)
|
||||
MacroAssemblerMIPSCompat::storePayload(Register src, const BaseIndex &dest)
|
||||
{
|
||||
computeScaledAddress(BaseIndex(base, index, ShiftToScale(shift)), SecondScratchReg);
|
||||
MOZ_ASSERT(dest.offset == 0);
|
||||
|
||||
computeScaledAddress(dest, SecondScratchReg);
|
||||
as_sw(src, SecondScratchReg, NUNBOX32_PAYLOAD_OFFSET);
|
||||
}
|
||||
|
||||
@ -2929,9 +2985,11 @@ MacroAssemblerMIPSCompat::storeTypeTag(ImmTag tag, Address dest)
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::storeTypeTag(ImmTag tag, Register base, Register index, int32_t shift)
|
||||
MacroAssemblerMIPSCompat::storeTypeTag(ImmTag tag, const BaseIndex &dest)
|
||||
{
|
||||
computeScaledAddress(BaseIndex(base, index, ShiftToScale(shift)), SecondScratchReg);
|
||||
MOZ_ASSERT(dest.offset == 0);
|
||||
|
||||
computeScaledAddress(dest, SecondScratchReg);
|
||||
ma_li(ScratchRegister, tag);
|
||||
as_sw(ScratchRegister, SecondScratchReg, TAG_OFFSET);
|
||||
}
|
||||
|
@ -200,8 +200,8 @@ class MacroAssemblerMIPS : public Assembler
|
||||
|
||||
// fast mod, uses scratch registers, and thus needs to be in the assembler
|
||||
// implicitly assumes that we can overwrite dest at the beginning of the sequence
|
||||
void ma_mod_mask(Register src, Register dest, Register hold, int32_t shift,
|
||||
Label *negZero = nullptr);
|
||||
void ma_mod_mask(Register src, Register dest, Register hold, Register remain,
|
||||
int32_t shift, Label *negZero = nullptr);
|
||||
|
||||
// memory
|
||||
// shortcut for when we know we're transferring 32 bits of data
|
||||
@ -741,6 +741,10 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
|
||||
ma_lw(SecondScratchReg, address);
|
||||
branchTest32(cond, SecondScratchReg, imm, label);
|
||||
}
|
||||
void branchTest32(Condition cond, AbsoluteAddress address, Imm32 imm, Label *label) {
|
||||
loadPtr(address, ScratchRegister);
|
||||
branchTest32(cond, ScratchRegister, imm, label);
|
||||
}
|
||||
void branchTestPtr(Condition cond, Register lhs, Register rhs, Label *label) {
|
||||
branchTest32(cond, lhs, rhs, label);
|
||||
}
|
||||
@ -847,6 +851,10 @@ public:
|
||||
load32(address, dest.gpr());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T &dest,
|
||||
MIRType slotType);
|
||||
|
||||
void moveValue(const Value &val, const ValueOperand &dest);
|
||||
|
||||
void moveValue(const ValueOperand &src, const ValueOperand &dest) {
|
||||
@ -916,10 +924,10 @@ public:
|
||||
}
|
||||
void storePayload(const Value &val, Address dest);
|
||||
void storePayload(Register src, Address dest);
|
||||
void storePayload(const Value &val, Register base, Register index, int32_t shift = defaultShift);
|
||||
void storePayload(Register src, Register base, Register index, int32_t shift = defaultShift);
|
||||
void storePayload(const Value &val, const BaseIndex &dest);
|
||||
void storePayload(Register src, const BaseIndex &dest);
|
||||
void storeTypeTag(ImmTag tag, Address dest);
|
||||
void storeTypeTag(ImmTag tag, Register base, Register index, int32_t shift = defaultShift);
|
||||
void storeTypeTag(ImmTag tag, const BaseIndex &dest);
|
||||
|
||||
void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
|
||||
ma_sll(frameSizeReg, frameSizeReg, Imm32(FRAMESIZE_SHIFT));
|
||||
@ -1035,8 +1043,10 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void and32(Register src, Register dest);
|
||||
void and32(Imm32 imm, Register dest);
|
||||
void and32(Imm32 imm, const Address &dest);
|
||||
void and32(const Address &src, Register dest);
|
||||
void or32(Imm32 imm, const Address &dest);
|
||||
void xor32(Imm32 imm, Register dest);
|
||||
void xorPtr(Imm32 imm, Register dest);
|
||||
@ -1112,6 +1122,7 @@ public:
|
||||
void storePtr(ImmPtr imm, const Address &address);
|
||||
void storePtr(ImmGCPtr imm, const Address &address);
|
||||
void storePtr(Register src, const Address &address);
|
||||
void storePtr(Register src, const BaseIndex &address);
|
||||
void storePtr(Register src, AbsoluteAddress dest);
|
||||
void storeDouble(FloatRegister src, Address addr) {
|
||||
ma_sd(src, addr);
|
||||
@ -1161,6 +1172,7 @@ public:
|
||||
}
|
||||
|
||||
void subPtr(Imm32 imm, const Register dest);
|
||||
void subPtr(const Address &addr, const Register dest);
|
||||
void subPtr(Register src, const Address &dest);
|
||||
void addPtr(Imm32 imm, const Register dest);
|
||||
void addPtr(Imm32 imm, const Address &dest);
|
||||
@ -1190,6 +1202,9 @@ public:
|
||||
void rshiftPtr(Imm32 imm, Register dest) {
|
||||
ma_srl(dest, dest, imm);
|
||||
}
|
||||
void rshiftPtrArithmetic(Imm32 imm, Register dest) {
|
||||
ma_sra(dest, dest, imm);
|
||||
}
|
||||
void lshiftPtr(Imm32 imm, Register dest) {
|
||||
ma_sll(dest, dest, imm);
|
||||
}
|
||||
|
@ -5321,6 +5321,12 @@ JS_GetStringLength(JSString *str)
|
||||
return str->length();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StringHasLatin1Chars(JSString *str)
|
||||
{
|
||||
return str->hasLatin1Chars();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(const jschar *)
|
||||
JS_GetStringCharsZ(JSContext *cx, JSString *str)
|
||||
{
|
||||
@ -5359,6 +5365,36 @@ JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength)
|
||||
return linear->chars();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(const JS::Latin1Char *)
|
||||
JS_GetLatin1StringCharsAndLength(JSContext *cx, const JS::AutoCheckCannotGC &nogc, JSString *str,
|
||||
size_t *plength)
|
||||
{
|
||||
JS_ASSERT(plength);
|
||||
AssertHeapIsIdleOrStringIsFlat(cx, str);
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, str);
|
||||
JSLinearString *linear = str->ensureLinear(cx);
|
||||
if (!linear)
|
||||
return nullptr;
|
||||
*plength = linear->length();
|
||||
return linear->latin1Chars(nogc);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(const jschar *)
|
||||
JS_GetTwoByteStringCharsAndLength(JSContext *cx, const JS::AutoCheckCannotGC &nogc, JSString *str,
|
||||
size_t *plength)
|
||||
{
|
||||
JS_ASSERT(plength);
|
||||
AssertHeapIsIdleOrStringIsFlat(cx, str);
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, str);
|
||||
JSLinearString *linear = str->ensureLinear(cx);
|
||||
if (!linear)
|
||||
return nullptr;
|
||||
*plength = linear->length();
|
||||
return linear->twoByteChars(nogc);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(const jschar *)
|
||||
JS_GetInternedStringChars(JSString *str)
|
||||
{
|
||||
@ -5544,8 +5580,7 @@ JS_GetStringEncodingLength(JSContext *cx, JSString *str)
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
const jschar *chars = str->getChars(cx);
|
||||
if (!chars)
|
||||
if (!str->ensureLinear(cx))
|
||||
return size_t(-1);
|
||||
return str->length();
|
||||
}
|
||||
@ -5562,10 +5597,21 @@ JS_EncodeStringToBuffer(JSContext *cx, JSString *str, char *buffer, size_t lengt
|
||||
* error.
|
||||
*/
|
||||
size_t writtenLength = length;
|
||||
const jschar *chars = str->getChars(nullptr);
|
||||
if (!chars)
|
||||
return size_t(-1);
|
||||
if (DeflateStringToBuffer(nullptr, chars, str->length(), buffer, &writtenLength)) {
|
||||
JSLinearString *linear = str->ensureLinear(cx);
|
||||
if (!linear)
|
||||
return size_t(-1);
|
||||
|
||||
bool res;
|
||||
if (linear->hasLatin1Chars()) {
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
res = DeflateStringToBuffer(nullptr, linear->latin1Chars(nogc), linear->length(), buffer,
|
||||
&writtenLength);
|
||||
} else {
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
res = DeflateStringToBuffer(nullptr, linear->twoByteChars(nogc), linear->length(), buffer,
|
||||
&writtenLength);
|
||||
}
|
||||
if (res) {
|
||||
JS_ASSERT(writtenLength <= length);
|
||||
return writtenLength;
|
||||
}
|
||||
@ -5624,12 +5670,12 @@ JS_Stringify(JSContext *cx, MutableHandleValue vp, HandleObject replacer,
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, replacer, space);
|
||||
StringBuffer sb(cx);
|
||||
if (!sb.ensureTwoByteChars())
|
||||
return false;
|
||||
if (!js_Stringify(cx, vp, replacer, space, sb))
|
||||
return false;
|
||||
if (sb.empty()) {
|
||||
HandlePropertyName null = cx->names().null;
|
||||
return callback(null->chars(), null->length(), data);
|
||||
}
|
||||
if (sb.empty() && !sb.append(cx->names().null))
|
||||
return false;
|
||||
return callback(sb.rawTwoByteBegin(), sb.length(), data);
|
||||
}
|
||||
|
||||
|
@ -4166,9 +4166,21 @@ JS_FileEscapedString(FILE *fp, JSString *str, char quote);
|
||||
extern JS_PUBLIC_API(size_t)
|
||||
JS_GetStringLength(JSString *str);
|
||||
|
||||
/* Returns true iff the string's characters are stored as Latin1. */
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_StringHasLatin1Chars(JSString *str);
|
||||
|
||||
extern JS_PUBLIC_API(const jschar *)
|
||||
JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *length);
|
||||
|
||||
extern JS_PUBLIC_API(const JS::Latin1Char *)
|
||||
JS_GetLatin1StringCharsAndLength(JSContext *cx, const JS::AutoCheckCannotGC &nogc, JSString *str,
|
||||
size_t *length);
|
||||
|
||||
extern JS_PUBLIC_API(const jschar *)
|
||||
JS_GetTwoByteStringCharsAndLength(JSContext *cx, const JS::AutoCheckCannotGC &nogc, JSString *str,
|
||||
size_t *length);
|
||||
|
||||
extern JS_PUBLIC_API(const jschar *)
|
||||
JS_GetInternedStringChars(JSString *str);
|
||||
|
||||
|
@ -761,25 +761,42 @@ GetObjectSlot(JSObject *obj, size_t slot)
|
||||
return reinterpret_cast<const shadow::Object *>(obj)->slotRef(slot);
|
||||
}
|
||||
|
||||
inline const jschar *
|
||||
GetAtomChars(JSAtom *atom)
|
||||
{
|
||||
using shadow::Atom;
|
||||
Atom *atom_ = reinterpret_cast<Atom *>(atom);
|
||||
JS_ASSERT(!(atom_->flags & Atom::LATIN1_CHARS_BIT));
|
||||
if (atom_->flags & Atom::INLINE_CHARS_BIT) {
|
||||
char *p = reinterpret_cast<char *>(atom);
|
||||
return reinterpret_cast<const jschar *>(p + offsetof(Atom, inlineStorageTwoByte));
|
||||
}
|
||||
return atom_->nonInlineCharsTwoByte;
|
||||
}
|
||||
|
||||
inline size_t
|
||||
GetAtomLength(JSAtom *atom)
|
||||
{
|
||||
return reinterpret_cast<shadow::Atom*>(atom)->length;
|
||||
}
|
||||
|
||||
inline bool
|
||||
AtomHasLatin1Chars(JSAtom *atom)
|
||||
{
|
||||
return reinterpret_cast<shadow::Atom *>(atom)->flags & shadow::Atom::LATIN1_CHARS_BIT;
|
||||
}
|
||||
|
||||
inline const JS::Latin1Char *
|
||||
GetLatin1AtomChars(const JS::AutoCheckCannotGC &nogc, JSAtom *atom)
|
||||
{
|
||||
MOZ_ASSERT(AtomHasLatin1Chars(atom));
|
||||
|
||||
using shadow::Atom;
|
||||
Atom *atom_ = reinterpret_cast<Atom *>(atom);
|
||||
if (atom_->flags & Atom::INLINE_CHARS_BIT)
|
||||
return atom_->inlineStorageLatin1;
|
||||
return atom_->nonInlineCharsLatin1;
|
||||
}
|
||||
|
||||
inline const jschar *
|
||||
GetTwoByteAtomChars(const JS::AutoCheckCannotGC &nogc, JSAtom *atom)
|
||||
{
|
||||
MOZ_ASSERT(!AtomHasLatin1Chars(atom));
|
||||
|
||||
using shadow::Atom;
|
||||
Atom *atom_ = reinterpret_cast<Atom *>(atom);
|
||||
if (atom_->flags & Atom::INLINE_CHARS_BIT)
|
||||
return atom_->inlineStorageTwoByte;
|
||||
return atom_->nonInlineCharsTwoByte;
|
||||
}
|
||||
|
||||
inline JSLinearString *
|
||||
AtomToLinearString(JSAtom *atom)
|
||||
{
|
||||
|
@ -552,6 +552,15 @@ js::math_log(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static double
|
||||
max_double(double x, double y)
|
||||
{
|
||||
// Math.max(num, NaN) => NaN, Math.max(-0, +0) => +0
|
||||
if (x > y || IsNaN(x) || (x == y && IsNegative(y)))
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
bool
|
||||
js_math_max(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
@ -562,14 +571,21 @@ js_math_max(JSContext *cx, unsigned argc, Value *vp)
|
||||
double x;
|
||||
if (!ToNumber(cx, args[i], &x))
|
||||
return false;
|
||||
// Math.max(num, NaN) => NaN, Math.max(-0, +0) => +0
|
||||
if (x > maxval || IsNaN(x) || (x == maxval && IsNegative(maxval)))
|
||||
maxval = x;
|
||||
maxval = max_double(x, maxval);
|
||||
}
|
||||
args.rval().setNumber(maxval);
|
||||
return true;
|
||||
}
|
||||
|
||||
static double
|
||||
min_double(double x, double y)
|
||||
{
|
||||
// Math.min(num, NaN) => NaN, Math.min(-0, +0) => -0
|
||||
if (x < y || IsNaN(x) || (x == y && IsNegativeZero(x)))
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
bool
|
||||
js_math_min(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
@ -580,14 +596,30 @@ js_math_min(JSContext *cx, unsigned argc, Value *vp)
|
||||
double x;
|
||||
if (!ToNumber(cx, args[i], &x))
|
||||
return false;
|
||||
// Math.min(num, NaN) => NaN, Math.min(-0, +0) => -0
|
||||
if (x < minval || IsNaN(x) || (x == minval && IsNegativeZero(x)))
|
||||
minval = x;
|
||||
minval = min_double(x, minval);
|
||||
}
|
||||
args.rval().setNumber(minval);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js_minmax_impl(JSContext *cx, bool max, HandleValue a, HandleValue b, MutableHandleValue res)
|
||||
{
|
||||
double x, y;
|
||||
|
||||
if (!ToNumber(cx, a, &x))
|
||||
return false;
|
||||
if (!ToNumber(cx, b, &y))
|
||||
return false;
|
||||
|
||||
if (max)
|
||||
res.setNumber(max_double(x, y));
|
||||
else
|
||||
res.setNumber(min_double(x, y));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disable PGO for Math.pow() and related functions (see bug 791214).
|
||||
#if defined(_MSC_VER)
|
||||
# pragma optimize("g", off)
|
||||
|
@ -111,11 +111,16 @@ extern bool
|
||||
js_math_sqrt(JSContext *cx, unsigned argc, js::Value *vp);
|
||||
|
||||
extern bool
|
||||
js_math_pow_handle(JSContext *cx, js::HandleValue base, js::HandleValue power, js::MutableHandleValue result);
|
||||
js_math_pow_handle(JSContext *cx, js::HandleValue base, js::HandleValue power,
|
||||
js::MutableHandleValue result);
|
||||
|
||||
extern bool
|
||||
js_math_pow(JSContext *cx, unsigned argc, js::Value *vp);
|
||||
|
||||
extern bool
|
||||
js_minmax_impl(JSContext *cx, bool max, js::HandleValue a, js::HandleValue b,
|
||||
js::MutableHandleValue res);
|
||||
|
||||
namespace js {
|
||||
|
||||
extern bool
|
||||
|
@ -38,9 +38,13 @@ js::AutoEnterPolicy::reportErrorIfExceptionIsNotPending(JSContext *cx, jsid id)
|
||||
JSMSG_OBJECT_ACCESS_DENIED);
|
||||
} else {
|
||||
JSString *str = IdToString(cx, id);
|
||||
const jschar *prop = str ? str->getCharsZ(cx) : nullptr;
|
||||
JS_ReportErrorNumberUC(cx, js_GetErrorMessage, nullptr,
|
||||
JSMSG_PROPERTY_ACCESS_DENIED, prop);
|
||||
AutoStableStringChars chars(cx);
|
||||
const jschar *prop = nullptr;
|
||||
if (str->ensureFlat(cx) && chars.initTwoByte(cx, str))
|
||||
prop = chars.twoByteChars();
|
||||
|
||||
JS_ReportErrorNumberUC(cx, js_GetErrorMessage, nullptr, JSMSG_PROPERTY_ACCESS_DENIED,
|
||||
prop);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4888,14 +4888,15 @@ js::InflateString(ThreadSafeContext *cx, const char *bytes, size_t *lengthp)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
bool
|
||||
js::DeflateStringToBuffer(JSContext *maybecx, const jschar *src, size_t srclen,
|
||||
js::DeflateStringToBuffer(JSContext *maybecx, const CharT *src, size_t srclen,
|
||||
char *dst, size_t *dstlenp)
|
||||
{
|
||||
size_t dstlen = *dstlenp;
|
||||
if (srclen > dstlen) {
|
||||
for (size_t i = 0; i < dstlen; i++)
|
||||
dst[i] = (char) src[i];
|
||||
dst[i] = char(src[i]);
|
||||
if (maybecx) {
|
||||
AutoSuppressGC suppress(maybecx);
|
||||
JS_ReportErrorNumber(maybecx, js_GetErrorMessage, nullptr,
|
||||
@ -4904,11 +4905,19 @@ js::DeflateStringToBuffer(JSContext *maybecx, const jschar *src, size_t srclen,
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < srclen; i++)
|
||||
dst[i] = (char) src[i];
|
||||
dst[i] = char(src[i]);
|
||||
*dstlenp = srclen;
|
||||
return true;
|
||||
}
|
||||
|
||||
template bool
|
||||
js::DeflateStringToBuffer(JSContext *maybecx, const Latin1Char *src, size_t srclen,
|
||||
char *dst, size_t *dstlenp);
|
||||
|
||||
template bool
|
||||
js::DeflateStringToBuffer(JSContext *maybecx, const jschar *src, size_t srclen,
|
||||
char *dst, size_t *dstlenp);
|
||||
|
||||
#define ____ false
|
||||
|
||||
/*
|
||||
|
@ -319,8 +319,9 @@ CopyAndInflateChars(jschar *dst, const JS::Latin1Char *src, size_t srclen)
|
||||
* must to be initialized with the buffer size and will contain on return the
|
||||
* number of copied bytes.
|
||||
*/
|
||||
template <typename CharT>
|
||||
extern bool
|
||||
DeflateStringToBuffer(JSContext *maybecx, const jschar *chars,
|
||||
DeflateStringToBuffer(JSContext *maybecx, const CharT *chars,
|
||||
size_t charsLength, char *bytes, size_t *length);
|
||||
|
||||
/*
|
||||
|
@ -44,7 +44,9 @@ JSString::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
||||
// JSExtensibleString: count the full capacity, not just the used space.
|
||||
if (isExtensible()) {
|
||||
JSExtensibleString &extensible = asExtensible();
|
||||
return mallocSizeOf(extensible.nonInlineChars());
|
||||
return extensible.hasLatin1Chars()
|
||||
? mallocSizeOf(extensible.rawLatin1Chars())
|
||||
: mallocSizeOf(extensible.rawTwoByteChars());
|
||||
}
|
||||
|
||||
// JSExternalString: don't count, the chars could be stored anywhere.
|
||||
@ -59,7 +61,9 @@ JSString::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
||||
// JSUndependedString, there is no need to count the base string, for the
|
||||
// same reason as JSDependentString above.
|
||||
JSFlatString &flat = asFlat();
|
||||
return mallocSizeOf(flat.chars());
|
||||
return flat.hasLatin1Chars()
|
||||
? mallocSizeOf(flat.rawLatin1Chars())
|
||||
: mallocSizeOf(flat.rawTwoByteChars());
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -39,7 +39,7 @@ function boom_391747() {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
setTimeout(boom_391747,400)
|
||||
addLoadEvent(boom_391747);
|
||||
SimpleTest.waitForExplicitFinish()
|
||||
|
||||
</script>
|
||||
|
@ -543,13 +543,12 @@ nsMediaList::Matches(nsPresContext* aPresContext,
|
||||
return mArray.IsEmpty();
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsMediaList::SetStyleSheet(CSSStyleSheet* aSheet)
|
||||
{
|
||||
NS_ASSERTION(aSheet == mStyleSheet || !aSheet || !mStyleSheet,
|
||||
"multiple style sheets competing for one media list");
|
||||
mStyleSheet = aSheet;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsMediaList>
|
||||
|
@ -560,9 +560,7 @@ RuleHash::~RuleHash()
|
||||
RuleValue* value = &(mUniversalRules[i]);
|
||||
nsAutoString selectorText;
|
||||
uint32_t lineNumber = value->mRule->GetLineNumber();
|
||||
nsCOMPtr<nsIStyleSheet> sheet;
|
||||
value->mRule->GetStyleSheet(*getter_AddRefs(sheet));
|
||||
nsRefPtr<CSSStyleSheet> cssSheet = do_QueryObject(sheet);
|
||||
nsRefPtr<CSSStyleSheet> cssSheet = value->mRule->GetStyleSheet();
|
||||
value->mSelector->ToString(selectorText, cssSheet);
|
||||
|
||||
printf(" line %d, %s\n",
|
||||
|
@ -176,7 +176,7 @@ public:
|
||||
bool Matches(nsPresContext* aPresContext,
|
||||
nsMediaQueryResultCacheKey* aKey);
|
||||
|
||||
nsresult SetStyleSheet(mozilla::CSSStyleSheet* aSheet);
|
||||
void SetStyleSheet(mozilla::CSSStyleSheet* aSheet);
|
||||
void AppendQuery(nsAutoPtr<nsMediaQuery>& aQuery) {
|
||||
// Takes ownership of aQuery
|
||||
mArray.AppendElement(aQuery.forget());
|
||||
|
@ -34,6 +34,7 @@
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -257,16 +258,22 @@ int VcmSIPCCBinding::getVideoCodecsHw()
|
||||
// Note that currently, OMXCodecReservation needs to be held by an sp<> because it puts
|
||||
// 'this' into an sp<EventListener> to talk to the resource reservation code
|
||||
#ifdef MOZ_WEBRTC_OMX
|
||||
android::sp<android::OMXCodecReservation> encode = new android::OMXCodecReservation(true);
|
||||
android::sp<android::OMXCodecReservation> decode = new android::OMXCodecReservation(false);
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
if (Preferences::GetBool("media.peerconnection.video.h264_enabled")) {
|
||||
#endif
|
||||
android::sp<android::OMXCodecReservation> encode = new android::OMXCodecReservation(true);
|
||||
android::sp<android::OMXCodecReservation> decode = new android::OMXCodecReservation(false);
|
||||
|
||||
// Currently we just check if they're available right now, which will fail if we're
|
||||
// trying to call ourself, for example. It will work for most real-world cases, like
|
||||
// if we try to add a person to a 2-way call to make a 3-way mesh call
|
||||
if (encode->ReserveOMXCodec() && decode->ReserveOMXCodec()) {
|
||||
CSFLogDebug( logTag, "%s: H264 hardware codec available", __FUNCTION__);
|
||||
return VCM_CODEC_RESOURCE_H264;
|
||||
}
|
||||
// Currently we just check if they're available right now, which will fail if we're
|
||||
// trying to call ourself, for example. It will work for most real-world cases, like
|
||||
// if we try to add a person to a 2-way call to make a 3-way mesh call
|
||||
if (encode->ReserveOMXCodec() && decode->ReserveOMXCodec()) {
|
||||
CSFLogDebug( logTag, "%s: H264 hardware codec available", __FUNCTION__);
|
||||
return VCM_CODEC_RESOURCE_H264;
|
||||
}
|
||||
#if defined( MOZILLA_INTERNAL_API)
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
@ -274,17 +274,35 @@ void CacheEntry::AsyncOpen(nsICacheEntryOpenCallback* aCallback, uint32_t aFlags
|
||||
|
||||
Callback callback(this, aCallback, readonly, multithread);
|
||||
|
||||
if (!Open(callback, truncate, priority, bypassIfBusy)) {
|
||||
// We get here when the callback wants to bypass cache when it's busy.
|
||||
LOG((" writing or revalidating, callback wants to bypass cache"));
|
||||
callback.mNotWanted = true;
|
||||
InvokeAvailableCallback(callback);
|
||||
}
|
||||
}
|
||||
|
||||
bool CacheEntry::Open(Callback & aCallback, bool aTruncate,
|
||||
bool aPriority, bool aBypassIfBusy)
|
||||
{
|
||||
mozilla::MutexAutoLock lock(mLock);
|
||||
|
||||
RememberCallback(callback, bypassIfBusy);
|
||||
// Check state under the lock
|
||||
if (aBypassIfBusy && (mState == WRITING || mState == REVALIDATING)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RememberCallback(aCallback);
|
||||
|
||||
// Load() opens the lock
|
||||
if (Load(truncate, priority)) {
|
||||
if (Load(aTruncate, aPriority)) {
|
||||
// Loading is in progress...
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
InvokeCallbacks();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CacheEntry::Load(bool aTruncate, bool aPriority)
|
||||
@ -508,20 +526,13 @@ void CacheEntry::TransferCallbacks(CacheEntry & aFromEntry)
|
||||
}
|
||||
}
|
||||
|
||||
void CacheEntry::RememberCallback(Callback & aCallback, bool aBypassIfBusy)
|
||||
void CacheEntry::RememberCallback(Callback & aCallback)
|
||||
{
|
||||
mLock.AssertCurrentThreadOwns();
|
||||
|
||||
LOG(("CacheEntry::RememberCallback [this=%p, cb=%p, state=%s]",
|
||||
this, aCallback.mCallback.get(), StateString(mState)));
|
||||
|
||||
if (aBypassIfBusy && (mState == WRITING || mState == REVALIDATING)) {
|
||||
LOG((" writing or revalidating, callback wants to bypass cache"));
|
||||
aCallback.mNotWanted = true;
|
||||
InvokeAvailableCallback(aCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
mCallbacks.AppendElement(aCallback);
|
||||
}
|
||||
|
||||
|
@ -204,11 +204,14 @@ private:
|
||||
nsresult mRv;
|
||||
};
|
||||
|
||||
// Starts the load or just invokes the callback, bypasses (when required)
|
||||
// if busy. Returns true on job done, false on bypass.
|
||||
bool Open(Callback & aCallback, bool aTruncate, bool aPriority, bool aBypassIfBusy);
|
||||
// Loads from disk asynchronously
|
||||
bool Load(bool aTruncate, bool aPriority);
|
||||
void OnLoaded();
|
||||
|
||||
void RememberCallback(Callback & aCallback, bool aBypassIfBusy);
|
||||
void RememberCallback(Callback & aCallback);
|
||||
void InvokeCallbacksLock();
|
||||
void InvokeCallbacks();
|
||||
bool InvokeCallbacks(bool aReadOnly);
|
||||
|
@ -201,9 +201,11 @@ NeckoChild::DeallocPRtspChannelChild(PRtspChannelChild* child)
|
||||
}
|
||||
|
||||
PTCPSocketChild*
|
||||
NeckoChild::AllocPTCPSocketChild()
|
||||
NeckoChild::AllocPTCPSocketChild(const nsString& host,
|
||||
const uint16_t& port)
|
||||
{
|
||||
TCPSocketChild* p = new TCPSocketChild();
|
||||
p->Init(host, port);
|
||||
p->AddIPDLReference();
|
||||
return p;
|
||||
}
|
||||
|
@ -43,7 +43,8 @@ protected:
|
||||
AllocPWebSocketChild(const PBrowserOrId&,
|
||||
const SerializedLoadContext&) MOZ_OVERRIDE;
|
||||
virtual bool DeallocPWebSocketChild(PWebSocketChild*) MOZ_OVERRIDE;
|
||||
virtual PTCPSocketChild* AllocPTCPSocketChild() MOZ_OVERRIDE;
|
||||
virtual PTCPSocketChild* AllocPTCPSocketChild(const nsString& host,
|
||||
const uint16_t& port) MOZ_OVERRIDE;
|
||||
virtual bool DeallocPTCPSocketChild(PTCPSocketChild*) MOZ_OVERRIDE;
|
||||
virtual PTCPServerSocketChild*
|
||||
AllocPTCPServerSocketChild(const uint16_t& aLocalPort,
|
||||
|
@ -397,8 +397,12 @@ NeckoParent::DeallocPRtspChannelParent(PRtspChannelParent* actor)
|
||||
}
|
||||
|
||||
PTCPSocketParent*
|
||||
NeckoParent::AllocPTCPSocketParent()
|
||||
NeckoParent::AllocPTCPSocketParent(const nsString& /* host */,
|
||||
const uint16_t& /* port */)
|
||||
{
|
||||
// We actually don't need host/port to construct a TCPSocketParent since
|
||||
// TCPSocketParent will maintain an internal nsIDOMTCPSocket instance which
|
||||
// can be delegated to get the host/port.
|
||||
TCPSocketParent* p = new TCPSocketParent();
|
||||
p->AddIPDLReference();
|
||||
return p;
|
||||
|
@ -127,7 +127,8 @@ protected:
|
||||
AllocPWebSocketParent(const PBrowserOrId& browser,
|
||||
const SerializedLoadContext& aSerialized) MOZ_OVERRIDE;
|
||||
virtual bool DeallocPWebSocketParent(PWebSocketParent*) MOZ_OVERRIDE;
|
||||
virtual PTCPSocketParent* AllocPTCPSocketParent() MOZ_OVERRIDE;
|
||||
virtual PTCPSocketParent* AllocPTCPSocketParent(const nsString& host,
|
||||
const uint16_t& port) MOZ_OVERRIDE;
|
||||
|
||||
virtual PRemoteOpenFileParent*
|
||||
AllocPRemoteOpenFileParent(const SerializedLoadContext& aSerialized,
|
||||
|
@ -102,7 +102,10 @@ child:
|
||||
nsString realm, uint64_t callbackId);
|
||||
|
||||
both:
|
||||
PTCPSocket();
|
||||
// Actually we need PTCPSocket() for parent. But ipdl disallows us having different
|
||||
// signatures on parent and child. So when constructing the parent side object, we just
|
||||
// leave host/port unused.
|
||||
PTCPSocket(nsString host, uint16_t port);
|
||||
};
|
||||
|
||||
|
||||
|
@ -2163,56 +2163,39 @@ nsHttpChannel::ProcessPartialContent()
|
||||
rv = InstallOfflineCacheListener(mLogicalOffset);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// merge any new headers with the cached response headers
|
||||
rv = mCachedResponseHead->UpdateHeaders(mResponseHead->Headers());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// update the cached response head
|
||||
nsAutoCString head;
|
||||
mCachedResponseHead->Flatten(head, true);
|
||||
rv = mCacheEntry->SetMetaDataElement("response-head", head.get());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
UpdateInhibitPersistentCachingFlag();
|
||||
|
||||
rv = UpdateExpirationTime();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mCachedContentIsPartial = false;
|
||||
mConcurentCacheAccess = 0;
|
||||
|
||||
// notify observers interested in looking at a response that has been
|
||||
// merged with any cached headers (http-on-examine-merged-response).
|
||||
gHttpHandler->OnExamineMergedResponse(this);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// suspend the current transaction
|
||||
rv = mTransactionPump->Suspend();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// merge any new headers with the cached response headers
|
||||
rv = mCachedResponseHead->UpdateHeaders(mResponseHead->Headers());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
// merge any new headers with the cached response headers
|
||||
rv = mCachedResponseHead->UpdateHeaders(mResponseHead->Headers());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// update the cached response head
|
||||
nsAutoCString head;
|
||||
mCachedResponseHead->Flatten(head, true);
|
||||
rv = mCacheEntry->SetMetaDataElement("response-head", head.get());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
// update the cached response head
|
||||
nsAutoCString head;
|
||||
mCachedResponseHead->Flatten(head, true);
|
||||
rv = mCacheEntry->SetMetaDataElement("response-head", head.get());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// make the cached response be the current response
|
||||
mResponseHead = Move(mCachedResponseHead);
|
||||
// make the cached response be the current response
|
||||
mResponseHead = Move(mCachedResponseHead);
|
||||
|
||||
UpdateInhibitPersistentCachingFlag();
|
||||
UpdateInhibitPersistentCachingFlag();
|
||||
|
||||
rv = UpdateExpirationTime();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = UpdateExpirationTime();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// notify observers interested in looking at a response that has been
|
||||
// merged with any cached headers (http-on-examine-merged-response).
|
||||
gHttpHandler->OnExamineMergedResponse(this);
|
||||
// notify observers interested in looking at a response that has been
|
||||
// merged with any cached headers (http-on-examine-merged-response).
|
||||
gHttpHandler->OnExamineMergedResponse(this);
|
||||
|
||||
if (mConcurentCacheAccess) {
|
||||
mCachedContentIsPartial = false;
|
||||
mConcurentCacheAccess = 0;
|
||||
// Now we continue reading the network response.
|
||||
} else {
|
||||
// the cached content is valid, although incomplete.
|
||||
mCachedContentIsValid = true;
|
||||
rv = ReadFromCache(false);
|
||||
|
@ -217,11 +217,6 @@ typedef HANDLE userland_thread_t;
|
||||
|
||||
typedef char* caddr_t;
|
||||
|
||||
int Win_getifaddrs(struct ifaddrs**);
|
||||
#define getifaddrs(interfaces) (int)Win_getifaddrs(interfaces)
|
||||
int win_if_nametoindex(const char *);
|
||||
#define if_nametoindex(x) win_if_nametoindex(x)
|
||||
|
||||
#define bzero(buf, len) memset(buf, 0, len)
|
||||
#define bcopy(srcKey, dstKey, len) memcpy(dstKey, srcKey, len)
|
||||
#define snprintf(data, size, format, name) _snprintf_s(data, size, _TRUNCATE, format, name)
|
||||
@ -399,6 +394,11 @@ struct udphdr {
|
||||
unsigned __int16 uh_sum;
|
||||
};
|
||||
|
||||
int Win_getifaddrs(struct ifaddrs**);
|
||||
#define getifaddrs(interfaces) (int)Win_getifaddrs(interfaces)
|
||||
int win_if_nametoindex(const char *);
|
||||
#define if_nametoindex(x) win_if_nametoindex(x)
|
||||
|
||||
#else /* !defined(Userspace_os_Windows) */
|
||||
#include <sys/cdefs.h> /* needed? added from old __FreeBSD__ */
|
||||
#include <sys/socket.h>
|
||||
|
@ -41,7 +41,15 @@
|
||||
#include <strings.h>
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#include "netinet/sctp_os_userspace.h"
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600
|
||||
#include <stdint.h>
|
||||
#elif defined(SCTP_STDINT_INCLUDE)
|
||||
#include SCTP_STDINT_INCLUDE
|
||||
#else
|
||||
#define uint32_t unsigned __int32
|
||||
#define uint64_t unsigned __int64
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#define MINALLOCSIZE UMA_SMALLEST_UNIT
|
||||
|
@ -4,6 +4,11 @@ function run_test()
|
||||
{
|
||||
do_get_profile();
|
||||
|
||||
if (!newCacheBackEndUsed()) {
|
||||
do_check_true(true, "This test checks only cache2 specific behavior.");
|
||||
return;
|
||||
}
|
||||
|
||||
var mc = new MultipleCallbacks(2, function() {
|
||||
var mem = getCacheStorage("memory");
|
||||
var disk = getCacheStorage("disk");
|
||||
|
@ -730,7 +730,9 @@ class RunProgram(MachCommandBase):
|
||||
help='Do not pass the -no-remote argument by default.')
|
||||
@CommandArgument('+background', '+b', action='store_true',
|
||||
help='Do not pass the -foreground argument by default on Mac')
|
||||
def run(self, params, remote, background):
|
||||
@CommandArgument('+profile', '+P', action='store_true',
|
||||
help='Specifiy thr profile to use')
|
||||
def run(self, params, remote, background, profile):
|
||||
try:
|
||||
args = [self.get_binary_path('app')]
|
||||
except Exception as e:
|
||||
@ -742,6 +744,12 @@ class RunProgram(MachCommandBase):
|
||||
args.append('-no-remote')
|
||||
if not background and sys.platform == 'darwin':
|
||||
args.append('-foreground')
|
||||
if '-profile' not in params and '-P' not in params:
|
||||
path = os.path.join(self.topobjdir, 'tmp', 'scratch_user')
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path)
|
||||
args.append('-profile')
|
||||
args.append(path)
|
||||
if params:
|
||||
args.extend(params)
|
||||
return self.run_process(args=args, ensure_exit_code=False,
|
||||
@ -763,6 +771,8 @@ class DebugProgram(MachCommandBase):
|
||||
help='Name of debugger to launch')
|
||||
@CommandArgument('+debugparams', default=None, metavar='params', type=str,
|
||||
help='Command-line arguments to pass to GDB or LLDB itself; split as the Bourne shell would.')
|
||||
@CommandArgument('+profile', '+P', action='store_true',
|
||||
help='Specifiy thr profile to use')
|
||||
# Bug 933807 introduced JS_DISABLE_SLOW_SCRIPT_SIGNALS to avoid clever
|
||||
# segfaults induced by the slow-script-detecting logic for Ion/Odin JITted
|
||||
# code. If we don't pass this, the user will need to periodically type
|
||||
@ -770,7 +780,7 @@ class DebugProgram(MachCommandBase):
|
||||
# automatic resuming; see the bug.
|
||||
@CommandArgument('+slowscript', action='store_true',
|
||||
help='Do not set the JS_DISABLE_SLOW_SCRIPT_SIGNALS env variable; when not set, recoverable but misleading SIGSEGV instances may occur in Ion/Odin JIT code')
|
||||
def debug(self, params, remote, background, debugger, debugparams, slowscript):
|
||||
def debug(self, params, remote, background, profile, debugger, debugparams, slowscript):
|
||||
import which
|
||||
if debugger:
|
||||
try:
|
||||
@ -829,6 +839,12 @@ class DebugProgram(MachCommandBase):
|
||||
args.append('-foreground')
|
||||
if params:
|
||||
args.extend(params)
|
||||
if '-profile' not in params and '-P' not in params:
|
||||
path = os.path.join(self.topobjdir, 'tmp', 'scratch_user')
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path)
|
||||
args.append('-profile')
|
||||
args.append(path)
|
||||
if not slowscript:
|
||||
extra_env['JS_DISABLE_SLOW_SCRIPT_SIGNALS'] = '1'
|
||||
return self.run_process(args=args, append_env=extra_env,
|
||||
|
@ -1,30 +1,6 @@
|
||||
+ set -e
|
||||
+ OBJ=obj-x86_64-unknown-linux-gnu
|
||||
+ obj-x86_64-unknown-linux-gnu/dist/bin/run-mozilla.sh obj-x86_64-unknown-linux-gnu/dist/bin/xpcshell /home/mchew/mozilla-central/security/manager/tools/genHPKPStaticPins.js /home/mchew/mozilla-central/security/manager/tools/PreloadedHPKPins.json /home/mchew/mozilla-central/security/manager/ssl/tests/unit/tlsserver/default-ee.der /home/mchew/mozilla-central/security/manager/boot/src/StaticHPKPins.h
|
||||
[32405] WARNING: NS_ENSURE_SUCCESS(rv, nsresult::NS_ERROR_UNEXPECTED) failed with result 0x80004005: file /home/mchew/mozilla-central/extensions/cookie/nsPermissionManager.cpp, line 444
|
||||
[32405] WARNING: Forcing memory-only entry since CacheFileIOManager doesn't have mCacheDirectory.: file /home/mchew/mozilla-central/netwerk/cache2/CacheFile.cpp, line 474
|
||||
[32405] WARNING: Forcing memory-only entry since CacheFileIOManager doesn't have mCacheDirectory.: file /home/mchew/mozilla-central/netwerk/cache2/CacheFile.cpp, line 474
|
||||
Can't find hash in builtin certs for Chrome nickname RapidSSL, inserting GOOGLE_PIN_RapidSSL
|
||||
Can't find hash in builtin certs for Chrome nickname Entrust_G2, inserting GOOGLE_PIN_Entrust_G2
|
||||
Can't find hash in builtin certs for Chrome nickname Tor2web, inserting GOOGLE_PIN_Tor2web
|
||||
Can't find hash in builtin certs for Chrome nickname AlphaSSL_G2, inserting GOOGLE_PIN_AlphaSSL_G2
|
||||
Can't find hash in builtin certs for Chrome nickname CryptoCat1, inserting GOOGLE_PIN_CryptoCat1
|
||||
Can't find hash in builtin certs for Chrome nickname Libertylavabitcom, inserting GOOGLE_PIN_Libertylavabitcom
|
||||
[32405] WARNING: Forcing memory-only entry since CacheFileIOManager doesn't have mCacheDirectory.: file /home/mchew/mozilla-central/netwerk/cache2/CacheFile.cpp, line 474
|
||||
[32405] WARNING: '!mMainThread', file /home/mchew/mozilla-central/xpcom/threads/nsThreadManager.cpp, line 279
|
||||
[32405] WARNING: '!thread', file /home/mchew/mozilla-central/xpcom/glue/nsThreadUtils.cpp, line 194
|
||||
[32405] WARNING: '!thread', file /home/mchew/mozilla-central/xpcom/glue/nsThreadUtils.cpp, line 194
|
||||
[32405] WARNING: '!mMainThread', file /home/mchew/mozilla-central/xpcom/threads/nsThreadManager.cpp, line 269
|
||||
[32405] WARNING: 'NS_FAILED(rv)', file /home/mchew/mozilla-central/xpcom/glue/nsThreadUtils.cpp, line 180
|
||||
[32405] WARNING: Leaking the RDF Service.: file /home/mchew/mozilla-central/rdf/build/nsRDFModule.cpp, line 165
|
||||
[32405] WARNING: '!compMgr', file /home/mchew/mozilla-central/xpcom/glue/nsComponentManagerUtils.cpp, line 59
|
||||
[32405] WARNING: XPCOM objects created/destroyed from static ctor/dtor: file /home/mchew/mozilla-central/xpcom/base/nsTraceRefcnt.cpp, line 148
|
||||
[32405] WARNING: XPCOM objects created/destroyed from static ctor/dtor: file /home/mchew/mozilla-central/xpcom/base/nsTraceRefcnt.cpp, line 148
|
||||
nsStringStats
|
||||
=> mAllocCount: 3577
|
||||
=> mReallocCount: 444
|
||||
=> mFreeCount: 3577
|
||||
=> mShareCount: 8797
|
||||
=> mAdoptCount: 177
|
||||
=> mAdoptFreeCount: 177
|
||||
=> Process ID: 32405, Thread ID: 140248381782592
|
||||
|
@ -998,4 +998,4 @@ static const int kPublicKeyPinningPreloadListLength = 322;
|
||||
|
||||
static const int32_t kUnknownId = -1;
|
||||
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1414009276397000);
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1415206756678000);
|
||||
|
@ -17,7 +17,7 @@ braintreegateway.com: did not receive HSTS header
|
||||
braintreepayments.com: did not receive HSTS header
|
||||
browserid.org: did not receive HSTS header
|
||||
business.medbank.com.mt: did not receive HSTS header
|
||||
calyxinstitute.org: could not connect to host
|
||||
calyxinstitute.org: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no]
|
||||
carlolly.co.uk: did not receive HSTS header
|
||||
cert.se: max-age too low: 2628001
|
||||
checkout.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
@ -54,10 +54,10 @@ googleplex.com: could not connect to host (error ignored - included regardless)
|
||||
goto.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
greplin.com: did not receive HSTS header
|
||||
groups.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
harvestapp.com: could not connect to host
|
||||
haste.ch: could not connect to host
|
||||
history.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
hostedtalkgadget.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
id.atlassian.com: did not receive HSTS header
|
||||
id.atlassian.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no]
|
||||
in.xero.com: max-age too low: 3600
|
||||
intercom.io: did not receive HSTS header
|
||||
iop.intuit.com: max-age too low: 86400
|
||||
@ -66,12 +66,11 @@ jitsi.org: did not receive HSTS header
|
||||
jottit.com: did not receive HSTS header
|
||||
keymaster.lookout.com: did not receive HSTS header
|
||||
kiwiirc.com: max-age too low: 5256000
|
||||
lastpass.com: could not connect to host
|
||||
ledgerscope.net: did not receive HSTS header
|
||||
liberty.lavabit.com: could not connect to host
|
||||
lifeguard.aecom.com: did not receive HSTS header
|
||||
lists.mayfirst.org: did not receive HSTS header
|
||||
lumi.do: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-hsts-000000000000000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no]
|
||||
lumi.do: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no]
|
||||
mail.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
market.android.com: did not receive HSTS header (error ignored - included regardless)
|
||||
mobilethreat.net: could not connect to host
|
||||
@ -84,17 +83,15 @@ nexth.de: could not connect to host
|
||||
nexth.net: did not receive HSTS header
|
||||
nexth.us: could not connect to host
|
||||
noexpect.org: could not connect to host
|
||||
onedrive.live.com: could not connect to host
|
||||
openshift.redhat.com: did not receive HSTS header
|
||||
ottospora.nl: could not connect to host
|
||||
paypal.com: max-age too low: 14400
|
||||
payroll.xero.com: max-age too low: 3600
|
||||
pixi.me: could not connect to host
|
||||
platform.lookout.com: could not connect to host
|
||||
play.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
prodpad.com: did not receive HSTS header
|
||||
profiles.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
rapidresearch.me: could not connect to host
|
||||
rapidresearch.me: did not receive HSTS header
|
||||
riseup.net: did not receive HSTS header
|
||||
sah3.net: could not connect to host
|
||||
saturngames.co.uk: did not receive HSTS header
|
||||
@ -104,10 +101,8 @@ semenkovich.com: did not receive HSTS header
|
||||
serverdensity.io: did not receive HSTS header
|
||||
shops.neonisi.com: could not connect to host
|
||||
silentcircle.org: could not connect to host
|
||||
simbolo.co.uk: could not connect to host
|
||||
simon.butcher.name: max-age too low: 2629743
|
||||
sites.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
skydrive.live.com: could not connect to host
|
||||
sol.io: could not connect to host
|
||||
souyar.de: could not connect to host
|
||||
souyar.net: could not connect to host
|
||||
@ -126,13 +121,13 @@ uprotect.it: could not connect to host
|
||||
wallet.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
webmail.mayfirst.org: did not receive HSTS header
|
||||
whonix.org: did not receive HSTS header
|
||||
www.calyxinstitute.org: could not connect to host
|
||||
www.calyxinstitute.org: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no]
|
||||
www.cueup.com: did not receive HSTS header
|
||||
www.developer.mydigipass.com: could not connect to host
|
||||
www.elanex.biz: did not receive HSTS header
|
||||
www.gmail.com: did not receive HSTS header (error ignored - included regardless)
|
||||
www.googlemail.com: did not receive HSTS header (error ignored - included regardless)
|
||||
www.gov.uk: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-hsts-000000000000000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no]
|
||||
www.gov.uk: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no]
|
||||
www.greplin.com: could not connect to host
|
||||
www.intercom.io: did not receive HSTS header
|
||||
www.jitsi.org: did not receive HSTS header
|
||||
@ -142,9 +137,8 @@ www.logentries.com: did not receive HSTS header
|
||||
www.moneybookers.com: did not receive HSTS header
|
||||
www.neonisi.com: could not connect to host
|
||||
www.paycheckrecords.com: max-age too low: 86400
|
||||
www.paypal.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-hsts-000000000000000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no]
|
||||
www.paypal.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no]
|
||||
www.roddis.net: did not receive HSTS header
|
||||
www.sandbox.mydigipass.com: could not connect to host
|
||||
www.simbolo.co.uk: could not connect to host
|
||||
www.surfeasy.com: did not receive HSTS header
|
||||
zoo24.de: max-age too low: 2592000
|
||||
|
@ -8,7 +8,7 @@
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
const PRTime gPreloadListExpirationTime = INT64_C(1414837778473000);
|
||||
const PRTime gPreloadListExpirationTime = INT64_C(1415206745808000);
|
||||
|
||||
class nsSTSPreload
|
||||
{
|
||||
|
@ -62,14 +62,18 @@ function initExceptionDialog() {
|
||||
document.getElementById("locationTextBox").value = args[0].location;
|
||||
document.getElementById('checkCertButton').disabled = false;
|
||||
|
||||
// We can optionally pre-fetch the certificate too. Don't do this
|
||||
// synchronously, since it would prevent the window from appearing
|
||||
// until the fetch is completed, which could be multiple seconds.
|
||||
// Instead, let's use a timer to spawn the actual fetch, but update
|
||||
// the dialog to "checking..." state right away, so that the UI
|
||||
// is appropriately responsive. Bug 453855
|
||||
if (args[0].prefetchCert) {
|
||||
|
||||
if (args[0].sslStatus) {
|
||||
gSSLStatus = args[0].sslStatus;
|
||||
gCert = gSSLStatus.serverCert;
|
||||
gBroken = true;
|
||||
updateCertStatus();
|
||||
} else if (args[0].prefetchCert) {
|
||||
// We can optionally pre-fetch the certificate too. Don't do this
|
||||
// synchronously, since it would prevent the window from appearing
|
||||
// until the fetch is completed, which could be multiple seconds.
|
||||
// Instead, let's use a timer to spawn the actual fetch, but update
|
||||
// the dialog to "checking..." state right away, so that the UI
|
||||
// is appropriately responsive. Bug 453855
|
||||
document.getElementById("checkCertButton").disabled = true;
|
||||
gChecking = true;
|
||||
updateCertStatus();
|
||||
@ -83,35 +87,6 @@ function initExceptionDialog() {
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if found and global status could be set
|
||||
function findRecentBadCert(uri) {
|
||||
try {
|
||||
var certDB = Components.classes["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Components.interfaces.nsIX509CertDB);
|
||||
if (!certDB)
|
||||
return false;
|
||||
var recentCertsSvc = certDB.getRecentBadCerts(inPrivateBrowsingMode());
|
||||
if (!recentCertsSvc)
|
||||
return false;
|
||||
|
||||
var hostWithPort = uri.host + ":" + uri.port;
|
||||
gSSLStatus = recentCertsSvc.getRecentBadCert(hostWithPort);
|
||||
if (!gSSLStatus)
|
||||
return false;
|
||||
|
||||
gCert = gSSLStatus.QueryInterface(Components.interfaces.nsISSLStatus).serverCert;
|
||||
if (!gCert)
|
||||
return false;
|
||||
|
||||
gBroken = true;
|
||||
}
|
||||
catch (e) {
|
||||
return false;
|
||||
}
|
||||
updateCertStatus();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to download the certificate for the location specified, and populate
|
||||
* the Certificate Status section with the result.
|
||||
@ -126,10 +101,6 @@ function checkCert() {
|
||||
|
||||
var uri = getURI();
|
||||
|
||||
// Is the cert already known in the list of recently seen bad certs?
|
||||
if (findRecentBadCert(uri) == true)
|
||||
return;
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
try {
|
||||
if(uri) {
|
||||
|
@ -25,7 +25,6 @@ class TPSFirefoxRunner(object):
|
||||
self.url = None
|
||||
self.binary = binary
|
||||
|
||||
self.runner = None
|
||||
self.installdir = None
|
||||
|
||||
def __del__(self):
|
||||
@ -78,8 +77,8 @@ class TPSFirefoxRunner(object):
|
||||
if self.binary is None and self.url:
|
||||
self.binary = self.download_build()
|
||||
|
||||
if self.runner is None:
|
||||
self.runner = FirefoxRunner(profile=self.profile, binary=self.binary, env=env, cmdargs=args)
|
||||
runner = FirefoxRunner(profile=self.profile, binary=self.binary,
|
||||
env=env, cmdargs=args)
|
||||
|
||||
self.runner.start(timeout=timeout)
|
||||
return self.runner.wait()
|
||||
runner.start(timeout=timeout)
|
||||
return runner.wait()
|
||||
|
@ -33,6 +33,7 @@ PARALLEL_DIRS += [
|
||||
'passwordmgr',
|
||||
'perf',
|
||||
'places',
|
||||
'promiseworker',
|
||||
'prompts',
|
||||
'protobuf',
|
||||
'reflect',
|
||||
|
@ -1,205 +0,0 @@
|
||||
/**
|
||||
* Thin wrapper around a ChromeWorker that wraps postMessage/onmessage/onerror
|
||||
* as promises.
|
||||
*
|
||||
* Not for public use yet.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["PromiseWorker"];
|
||||
|
||||
// The library of promises.
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
/**
|
||||
* An implementation of queues (FIFO).
|
||||
*
|
||||
* The current implementation uses one array, runs in O(n ^ 2), and is optimized
|
||||
* for the case in which queues are generally short.
|
||||
*/
|
||||
let Queue = function Queue() {
|
||||
this._array = [];
|
||||
};
|
||||
Queue.prototype = {
|
||||
pop: function pop() {
|
||||
return this._array.shift();
|
||||
},
|
||||
push: function push(x) {
|
||||
return this._array.push(x);
|
||||
},
|
||||
isEmpty: function isEmpty() {
|
||||
return this._array.length == 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An object responsible for dispatching messages to
|
||||
* a chrome worker and routing the responses.
|
||||
*
|
||||
* @param {string} url The url containing the source code for this worker,
|
||||
* as in constructor ChromeWorker.
|
||||
* @param {Function} log A logging function.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function PromiseWorker(url, log) {
|
||||
if (typeof url != "string") {
|
||||
throw new TypeError("Expecting a string");
|
||||
}
|
||||
if (typeof log !== "function") {
|
||||
throw new TypeError("log is expected to be a function");
|
||||
}
|
||||
this._log = log;
|
||||
this._url = url;
|
||||
|
||||
/**
|
||||
* The queue of deferred, waiting for the completion of their
|
||||
* respective job by the worker.
|
||||
*
|
||||
* Each item in the list may contain an additional field |closure|,
|
||||
* used to store strong references to value that must not be
|
||||
* garbage-collected before the reply has been received (e.g.
|
||||
* arrays).
|
||||
*
|
||||
* @type {Queue<{deferred:deferred, closure:*=}>}
|
||||
*/
|
||||
this._queue = new Queue();
|
||||
|
||||
/**
|
||||
* The number of the current message.
|
||||
*
|
||||
* Used for debugging purposes.
|
||||
*/
|
||||
this._id = 0;
|
||||
|
||||
/**
|
||||
* The instant at which the worker was launched.
|
||||
*/
|
||||
this.launchTimeStamp = null;
|
||||
|
||||
/**
|
||||
* Timestamps provided by the worker for statistics purposes.
|
||||
*/
|
||||
this.workerTimeStamps = null;
|
||||
}
|
||||
PromiseWorker.prototype = {
|
||||
/**
|
||||
* Instantiate the worker lazily.
|
||||
*/
|
||||
get _worker() {
|
||||
delete this._worker;
|
||||
let worker = new ChromeWorker(this._url);
|
||||
let self = this;
|
||||
Object.defineProperty(this, "_worker", {value:
|
||||
worker
|
||||
});
|
||||
|
||||
// We assume that we call to _worker for the purpose of calling
|
||||
// postMessage().
|
||||
this.launchTimeStamp = Date.now();
|
||||
|
||||
/**
|
||||
* Receive errors that are not instances of OS.File.Error, propagate
|
||||
* them to the listeners.
|
||||
*
|
||||
* The worker knows how to serialize errors that are instances
|
||||
* of |OS.File.Error|. These are treated by |worker.onmessage|.
|
||||
* However, for other errors, we rely on DOM's mechanism for
|
||||
* serializing errors, which transmits these errors through
|
||||
* |worker.onerror|.
|
||||
*
|
||||
* @param {Error} error Some JS error.
|
||||
*/
|
||||
worker.onerror = function onerror(error) {
|
||||
self._log("Received uncaught error from worker", error.message, error.filename, error.lineno);
|
||||
error.preventDefault();
|
||||
let {deferred} = self._queue.pop();
|
||||
deferred.reject(error);
|
||||
};
|
||||
|
||||
/**
|
||||
* Receive messages from the worker, propagate them to the listeners.
|
||||
*
|
||||
* Messages must have one of the following shapes:
|
||||
* - {ok: some_value} in case of success
|
||||
* - {fail: some_error} in case of error, where
|
||||
* some_error is an instance of |PromiseWorker.WorkerError|
|
||||
*
|
||||
* Messages may also contain a field |id| to help
|
||||
* with debugging.
|
||||
*
|
||||
* Messages may also optionally contain a field |durationMs|, holding
|
||||
* the duration of the function call in milliseconds.
|
||||
*
|
||||
* @param {*} msg The message received from the worker.
|
||||
*/
|
||||
worker.onmessage = function onmessage(msg) {
|
||||
self._log("Received message from worker", msg.data);
|
||||
let handler = self._queue.pop();
|
||||
let deferred = handler.deferred;
|
||||
let data = msg.data;
|
||||
if (data.id != handler.id) {
|
||||
throw new Error("Internal error: expecting msg " + handler.id + ", " +
|
||||
" got " + data.id + ": " + JSON.stringify(msg.data));
|
||||
}
|
||||
if ("timeStamps" in data) {
|
||||
self.workerTimeStamps = data.timeStamps;
|
||||
}
|
||||
if ("ok" in data) {
|
||||
// Pass the data to the listeners.
|
||||
deferred.resolve(data);
|
||||
} else if ("StopIteration" in data) {
|
||||
// We have received a StopIteration error
|
||||
deferred.reject(StopIteration);
|
||||
} if ("fail" in data) {
|
||||
// We have received an error that was serialized by the
|
||||
// worker.
|
||||
deferred.reject(new PromiseWorker.WorkerError(data.fail));
|
||||
}
|
||||
};
|
||||
return worker;
|
||||
},
|
||||
|
||||
/**
|
||||
* Post a message to a worker.
|
||||
*
|
||||
* @param {string} fun The name of the function to call.
|
||||
* @param {Array} array The contents of the message.
|
||||
* @param {*=} closure An object holding references that should not be
|
||||
* garbage-collected before the message treatment is complete.
|
||||
*
|
||||
* @return {promise}
|
||||
*/
|
||||
post: function post(fun, array, closure) {
|
||||
let deferred = Promise.defer();
|
||||
let id = ++this._id;
|
||||
let message = {fun: fun, args: array, id: id};
|
||||
this._log("Posting message", message);
|
||||
try {
|
||||
this._worker.postMessage(message);
|
||||
} catch (ex if typeof ex == "number") {
|
||||
this._log("Could not post message", message, "due to xpcom error", ex);
|
||||
// handle raw xpcom errors (see eg bug 961317)
|
||||
return Promise.reject(new Components.Exception("Error in postMessage", ex));
|
||||
} catch (ex) {
|
||||
this._log("Could not post message", message, "due to error", ex);
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
|
||||
this._queue.push({deferred:deferred, closure: closure, id: id});
|
||||
this._log("Message posted");
|
||||
return deferred.promise;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An error that has been serialized by the worker.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
PromiseWorker.WorkerError = function WorkerError(data) {
|
||||
this.data = data;
|
||||
};
|
||||
|
||||
this.PromiseWorker = PromiseWorker;
|
@ -7,7 +7,6 @@
|
||||
JS_MODULES_PATH = 'modules/osfile'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'_PromiseWorker.jsm',
|
||||
'osfile_async_front.jsm',
|
||||
'osfile_async_worker.js',
|
||||
'osfile_native.jsm',
|
||||
|
@ -54,43 +54,12 @@ Cu.import("resource://gre/modules/Promise.jsm", this);
|
||||
Cu.import("resource://gre/modules/Task.jsm", this);
|
||||
|
||||
// The implementation of communications
|
||||
Cu.import("resource://gre/modules/osfile/_PromiseWorker.jsm", this);
|
||||
|
||||
Cu.import("resource://gre/modules/PromiseWorker.jsm", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://gre/modules/TelemetryStopwatch.jsm", this);
|
||||
Cu.import("resource://gre/modules/AsyncShutdown.jsm", this);
|
||||
let Native = Cu.import("resource://gre/modules/osfile/osfile_native.jsm", {});
|
||||
|
||||
/**
|
||||
* Constructors for decoding standard exceptions
|
||||
* received from the worker.
|
||||
*/
|
||||
const EXCEPTION_CONSTRUCTORS = {
|
||||
EvalError: function(error) {
|
||||
return new EvalError(error.message, error.fileName, error.lineNumber);
|
||||
},
|
||||
InternalError: function(error) {
|
||||
return new InternalError(error.message, error.fileName, error.lineNumber);
|
||||
},
|
||||
RangeError: function(error) {
|
||||
return new RangeError(error.message, error.fileName, error.lineNumber);
|
||||
},
|
||||
ReferenceError: function(error) {
|
||||
return new ReferenceError(error.message, error.fileName, error.lineNumber);
|
||||
},
|
||||
SyntaxError: function(error) {
|
||||
return new SyntaxError(error.message, error.fileName, error.lineNumber);
|
||||
},
|
||||
TypeError: function(error) {
|
||||
return new TypeError(error.message, error.fileName, error.lineNumber);
|
||||
},
|
||||
URIError: function(error) {
|
||||
return new URIError(error.message, error.fileName, error.lineNumber);
|
||||
},
|
||||
OSError: function(error) {
|
||||
return OS.File.Error.fromMsg(error);
|
||||
}
|
||||
};
|
||||
|
||||
// It's possible for osfile.jsm to get imported before the profile is
|
||||
// set up. In this case, some path constants aren't yet available.
|
||||
@ -253,9 +222,11 @@ let Scheduler = {
|
||||
*/
|
||||
get worker() {
|
||||
if (!this._worker) {
|
||||
// Either the worker has never been created or it has been reset
|
||||
this._worker = new PromiseWorker(
|
||||
"resource://gre/modules/osfile/osfile_async_worker.js", LOG);
|
||||
// Either the worker has never been created or it has been
|
||||
// reset. In either case, it is time to instantiate the worker.
|
||||
this._worker = new BasePromiseWorker("resource://gre/modules/osfile/osfile_async_worker.js");
|
||||
this._worker.log = LOG;
|
||||
this._worker.ExceptionHandlers["OS.File.Error"] = OSError.fromMsg;
|
||||
}
|
||||
return this._worker;
|
||||
},
|
||||
@ -329,12 +300,11 @@ let Scheduler = {
|
||||
try {
|
||||
Scheduler.latestReceived = [];
|
||||
Scheduler.latestSent = [Date.now(), ...message];
|
||||
let promise = this._worker.post(...message);
|
||||
|
||||
// Wait for result
|
||||
let resources;
|
||||
try {
|
||||
resources = (yield promise).ok;
|
||||
resources = yield this._worker.post(...message);
|
||||
|
||||
Scheduler.latestReceived = [Date.now(), message];
|
||||
} catch (ex) {
|
||||
@ -411,7 +381,7 @@ let Scheduler = {
|
||||
* @return {Promise} A promise conveying the result/error caused by
|
||||
* calling |method| with arguments |args|.
|
||||
*/
|
||||
post: function post(method, ...args) {
|
||||
post: function post(method, args = undefined, closure = undefined) {
|
||||
if (this.shutdown) {
|
||||
LOG("OS.File is not available anymore. The following request has been rejected.",
|
||||
method, args);
|
||||
@ -426,12 +396,6 @@ let Scheduler = {
|
||||
Scheduler.Debugging.messagesSent++;
|
||||
}
|
||||
|
||||
// By convention, the last argument of any message may be an |options| object.
|
||||
let options;
|
||||
let methodArgs = args[0];
|
||||
if (methodArgs) {
|
||||
options = methodArgs[methodArgs.length - 1];
|
||||
}
|
||||
Scheduler.Debugging.messagesQueued++;
|
||||
return this.push(Task.async(function*() {
|
||||
if (this.shutdown) {
|
||||
@ -443,78 +407,32 @@ let Scheduler = {
|
||||
// Update debugging information. As |args| may be quite
|
||||
// expensive, we only keep a shortened version of it.
|
||||
Scheduler.Debugging.latestReceived = null;
|
||||
Scheduler.Debugging.latestSent = [Date.now(), method, summarizeObject(methodArgs)];
|
||||
Scheduler.Debugging.latestSent = [Date.now(), method, summarizeObject(args)];
|
||||
|
||||
// Don't kill the worker just yet
|
||||
Scheduler.restartTimer();
|
||||
|
||||
|
||||
let data;
|
||||
let reply;
|
||||
let isError = false;
|
||||
try {
|
||||
try {
|
||||
Scheduler.Debugging.messagesSent++;
|
||||
data = yield this.worker.post(method, ...args);
|
||||
Scheduler.Debugging.latestSent = Scheduler.Debugging.latestSent.slice(0, 2);
|
||||
reply = yield this.worker.post(method, args, closure);
|
||||
Scheduler.Debugging.latestReceived = [Date.now(), summarizeObject(reply)];
|
||||
return reply;
|
||||
} finally {
|
||||
Scheduler.Debugging.messagesReceived++;
|
||||
}
|
||||
reply = data;
|
||||
} catch (error) {
|
||||
reply = error;
|
||||
isError = true;
|
||||
if (error instanceof PromiseWorker.WorkerError) {
|
||||
throw EXCEPTION_CONSTRUCTORS[error.data.exn || "OSError"](error.data);
|
||||
}
|
||||
if (error instanceof ErrorEvent) {
|
||||
let message = error.message;
|
||||
if (message == "uncaught exception: [object StopIteration]") {
|
||||
isError = false;
|
||||
throw StopIteration;
|
||||
}
|
||||
throw new Error(message, error.filename, error.lineno);
|
||||
}
|
||||
Scheduler.Debugging.latestReceived = [Date.now(), error.message, error.fileName, error.lineNumber];
|
||||
throw error;
|
||||
} finally {
|
||||
Scheduler.Debugging.latestSent = Scheduler.Debugging.latestSent.slice(0, 2);
|
||||
if (isError) {
|
||||
Scheduler.Debugging.latestReceived = [Date.now(), reply.message, reply.fileName, reply.lineNumber];
|
||||
} else {
|
||||
Scheduler.Debugging.latestReceived = [Date.now(), summarizeObject(reply)];
|
||||
}
|
||||
if (firstLaunch) {
|
||||
Scheduler._updateTelemetry();
|
||||
}
|
||||
|
||||
Scheduler.restartTimer();
|
||||
}
|
||||
|
||||
// Check for duration and return result.
|
||||
if (!options) {
|
||||
return data.ok;
|
||||
}
|
||||
// Check for options.outExecutionDuration.
|
||||
if (typeof options !== "object" ||
|
||||
!("outExecutionDuration" in options)) {
|
||||
return data.ok;
|
||||
}
|
||||
// If data.durationMs is not present, return data.ok (there was an
|
||||
// exception applying the method).
|
||||
if (!("durationMs" in data)) {
|
||||
return data.ok;
|
||||
}
|
||||
// Bug 874425 demonstrates that two successive calls to Date.now()
|
||||
// can actually produce an interval with negative duration.
|
||||
// We assume that this is due to an operation that is so short
|
||||
// that Date.now() is not monotonic, so we round this up to 0.
|
||||
let durationMs = Math.max(0, data.durationMs);
|
||||
// Accumulate (or initialize) outExecutionDuration
|
||||
if (typeof options.outExecutionDuration == "number") {
|
||||
options.outExecutionDuration += durationMs;
|
||||
} else {
|
||||
options.outExecutionDuration = durationMs;
|
||||
}
|
||||
return data.ok;
|
||||
}.bind(this)));
|
||||
},
|
||||
|
||||
|
@ -1,24 +1,13 @@
|
||||
if (this.Components) {
|
||||
throw new Error("This worker can only be loaded from a worker thread");
|
||||
}
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
// Worker thread for osfile asynchronous front-end
|
||||
if (this.Components) {
|
||||
throw new Error("This worker can only be loaded from a worker thread");
|
||||
}
|
||||
|
||||
// Exception names to be posted from the worker thread to main thread
|
||||
const EXCEPTION_NAMES = {
|
||||
EvalError: "EvalError",
|
||||
InternalError: "InternalError",
|
||||
RangeError: "RangeError",
|
||||
ReferenceError: "ReferenceError",
|
||||
SyntaxError: "SyntaxError",
|
||||
TypeError: "TypeError",
|
||||
URIError: "URIError"
|
||||
};
|
||||
// Worker thread for osfile asynchronous front-end
|
||||
|
||||
(function(exports) {
|
||||
"use strict";
|
||||
@ -33,108 +22,28 @@ const EXCEPTION_NAMES = {
|
||||
|
||||
importScripts("resource://gre/modules/osfile.jsm");
|
||||
|
||||
let PromiseWorker = require("resource://gre/modules/workers/PromiseWorker.js");
|
||||
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
|
||||
let LOG = SharedAll.LOG.bind(SharedAll, "Agent");
|
||||
|
||||
// Post a message to the parent, decorate it with statistics if
|
||||
// necessary. Use this instead of self.postMessage.
|
||||
function post(message, ...transfers) {
|
||||
let worker = new PromiseWorker.AbstractWorker();
|
||||
worker.dispatch = function(method, args = []) {
|
||||
return Agent[method](...args);
|
||||
},
|
||||
worker.log = LOG;
|
||||
worker.postMessage = function(message, ...transfers) {
|
||||
if (timeStamps) {
|
||||
message.timeStamps = timeStamps;
|
||||
timeStamps = null;
|
||||
}
|
||||
self.postMessage(message, ...transfers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Communications with the controller.
|
||||
*
|
||||
* Accepts messages:
|
||||
* {fun:function_name, args:array_of_arguments_or_null, id:id}
|
||||
*
|
||||
* Sends messages:
|
||||
* {ok: result, id:id} / {fail: serialized_form_of_OS.File.Error, id:id}
|
||||
*/
|
||||
self.onmessage = function onmessage(msg) {
|
||||
let data = msg.data;
|
||||
LOG("Received message", data);
|
||||
let id = data.id;
|
||||
|
||||
let start;
|
||||
let options;
|
||||
if (data.args) {
|
||||
options = data.args[data.args.length - 1];
|
||||
}
|
||||
// If |outExecutionDuration| option was supplied, start measuring the
|
||||
// duration of the operation.
|
||||
if (options && typeof options === "object" && "outExecutionDuration" in options) {
|
||||
start = Date.now();
|
||||
}
|
||||
|
||||
let result;
|
||||
let exn;
|
||||
let durationMs;
|
||||
try {
|
||||
let method = data.fun;
|
||||
LOG("Calling method", method);
|
||||
result = Agent[method].apply(Agent, data.args);
|
||||
LOG("Method", method, "succeeded");
|
||||
} catch (ex) {
|
||||
exn = ex;
|
||||
LOG("Error while calling agent method", exn, exn.moduleStack || exn.stack || "");
|
||||
}
|
||||
|
||||
if (start) {
|
||||
// Record duration
|
||||
durationMs = Date.now() - start;
|
||||
LOG("Method took", durationMs, "ms");
|
||||
}
|
||||
|
||||
// Now, post a reply, possibly as an uncaught error.
|
||||
// We post this message from outside the |try ... catch| block
|
||||
// to avoid capturing errors that take place during |postMessage| and
|
||||
// built-in serialization.
|
||||
if (!exn) {
|
||||
LOG("Sending positive reply", result, "id is", id);
|
||||
if (result instanceof Meta) {
|
||||
if ("transfers" in result.meta) {
|
||||
// Take advantage of zero-copy transfers
|
||||
post({ok: result.data, id: id, durationMs: durationMs},
|
||||
result.meta.transfers);
|
||||
} else {
|
||||
post({ok: result.data, id:id, durationMs: durationMs});
|
||||
}
|
||||
if (result.meta.shutdown || false) {
|
||||
// Time to close the worker
|
||||
self.close();
|
||||
}
|
||||
} else {
|
||||
post({ok: result, id:id, durationMs: durationMs});
|
||||
}
|
||||
} else if (exn == StopIteration) {
|
||||
// StopIteration cannot be serialized automatically
|
||||
LOG("Sending back StopIteration");
|
||||
post({StopIteration: true, id: id, durationMs: durationMs});
|
||||
} else if (exn instanceof exports.OS.File.Error) {
|
||||
LOG("Sending back OS.File error", exn, "id is", id);
|
||||
// Instances of OS.File.Error know how to serialize themselves
|
||||
// (deserialization ensures that we end up with OS-specific
|
||||
// instances of |OS.File.Error|)
|
||||
post({fail: exports.OS.File.Error.toMsg(exn), id:id, durationMs: durationMs});
|
||||
} else if (exn.constructor.name in EXCEPTION_NAMES) {
|
||||
LOG("Sending back exception", exn.constructor.name);
|
||||
post({fail: {exn: exn.constructor.name, message: exn.message,
|
||||
fileName: exn.moduleName || exn.fileName, lineNumber: exn.lineNumber},
|
||||
id: id, durationMs: durationMs});
|
||||
} else {
|
||||
// Other exceptions do not, and should be propagated through DOM's
|
||||
// built-in mechanism for uncaught errors, although this mechanism
|
||||
// may lose interesting information.
|
||||
LOG("Sending back regular error", exn, exn.moduleStack || exn.stack, "id is", id);
|
||||
|
||||
throw exn;
|
||||
}
|
||||
};
|
||||
worker.close = function() {
|
||||
self.close();
|
||||
};
|
||||
let Meta = PromiseWorker.Meta;
|
||||
|
||||
self.addEventListener("message", msg => worker.handleMessage(msg));
|
||||
|
||||
/**
|
||||
* A data structure used to track opened resources
|
||||
@ -235,26 +144,6 @@ const EXCEPTION_NAMES = {
|
||||
|
||||
let File = exports.OS.File;
|
||||
|
||||
/**
|
||||
* A constructor used to return data to the caller thread while
|
||||
* also executing some specific treatment (e.g. shutting down
|
||||
* the current thread, transmitting data instead of copying it).
|
||||
*
|
||||
* @param {object=} data The data to return to the caller thread.
|
||||
* @param {object=} meta Additional instructions, as an object
|
||||
* that may contain the following fields:
|
||||
* - {bool} shutdown If |true|, shut down the current thread after
|
||||
* having sent the result.
|
||||
* - {Array} transfers An array of objects that should be transferred
|
||||
* instead of being copied.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
let Meta = function Meta(data, meta) {
|
||||
this.data = data;
|
||||
this.meta = meta;
|
||||
};
|
||||
|
||||
/**
|
||||
* The agent.
|
||||
*
|
||||
|
@ -91,6 +91,9 @@ OSError.prototype.toString = function toString() {
|
||||
(this.path? " on file " + this.path : "") +
|
||||
" (" + LazyBindings.strerror(this.unixErrno).readString() + ")";
|
||||
};
|
||||
OSError.prototype.toMsg = function toMsg() {
|
||||
return OSError.toMsg(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
@ -154,6 +157,10 @@ Object.defineProperty(OSError.prototype, "becauseInvalidArgument", {
|
||||
*/
|
||||
OSError.toMsg = function toMsg(error) {
|
||||
return {
|
||||
exn: "OS.File.Error",
|
||||
fileName: error.moduleName,
|
||||
lineNumber: error.lineNumber,
|
||||
stack: error.moduleStack,
|
||||
operation: error.operation,
|
||||
unixErrno: error.unixErrno,
|
||||
path: error.path
|
||||
@ -164,7 +171,11 @@ OSError.toMsg = function toMsg(error) {
|
||||
* Deserialize a message back to an instance of OSError
|
||||
*/
|
||||
OSError.fromMsg = function fromMsg(msg) {
|
||||
return new OSError(msg.operation, msg.unixErrno, msg.path);
|
||||
let error = new OSError(msg.operation, msg.unixErrno, msg.path);
|
||||
error.stack = msg.stack;
|
||||
error.fileName = msg.fileName;
|
||||
error.lineNumber = msg.lineNumber;
|
||||
return error;
|
||||
};
|
||||
exports.Error = OSError;
|
||||
|
||||
|
@ -113,6 +113,9 @@ OSError.prototype.toString = function toString() {
|
||||
+ this.operation + (this.path? " on file " + this.path : "") +
|
||||
" (" + buf.readString() + ")";
|
||||
};
|
||||
OSError.prototype.toMsg = function toMsg() {
|
||||
return OSError.toMsg(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
@ -178,6 +181,10 @@ Object.defineProperty(OSError.prototype, "becauseInvalidArgument", {
|
||||
*/
|
||||
OSError.toMsg = function toMsg(error) {
|
||||
return {
|
||||
exn: "OS.File.Error",
|
||||
fileName: error.moduleName,
|
||||
lineNumber: error.lineNumber,
|
||||
stack: error.moduleStack,
|
||||
operation: error.operation,
|
||||
winLastError: error.winLastError,
|
||||
path: error.path
|
||||
@ -188,7 +195,11 @@ OSError.toMsg = function toMsg(error) {
|
||||
* Deserialize a message back to an instance of OSError
|
||||
*/
|
||||
OSError.fromMsg = function fromMsg(msg) {
|
||||
return new OSError(msg.operation, msg.winLastError, msg.path);
|
||||
let error = new OSError(msg.operation, msg.winLastError, msg.path);
|
||||
error.stack = msg.stack;
|
||||
error.fileName = msg.fileName;
|
||||
error.lineNumber = msg.lineNumber;
|
||||
return error;
|
||||
};
|
||||
exports.Error = OSError;
|
||||
|
||||
|
342
toolkit/components/promiseworker/PromiseWorker.jsm
Normal file
342
toolkit/components/promiseworker/PromiseWorker.jsm
Normal file
@ -0,0 +1,342 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* A wrapper around ChromeWorker with extended capabilities designed
|
||||
* to simplify main thread-to-worker thread asynchronous function calls.
|
||||
*
|
||||
* This wrapper:
|
||||
* - groups requests and responses as a method `post` that returns a `Promise`;
|
||||
* - ensures that exceptions thrown on the worker thread are correctly deserialized;
|
||||
* - provides some utilities for benchmarking various operations.
|
||||
*
|
||||
* Generally, you should use PromiseWorker.jsm along with its worker-side
|
||||
* counterpart PromiseWorker.js.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["BasePromiseWorker"];
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
/**
|
||||
* An implementation of queues (FIFO).
|
||||
*
|
||||
* The current implementation uses one array, runs in O(n ^ 2), and is optimized
|
||||
* for the case in which queues are generally short.
|
||||
*/
|
||||
function Queue() {
|
||||
this._array = [];
|
||||
};
|
||||
Queue.prototype = {
|
||||
pop: function pop() {
|
||||
return this._array.shift();
|
||||
},
|
||||
push: function push(x) {
|
||||
return this._array.push(x);
|
||||
},
|
||||
isEmpty: function isEmpty() {
|
||||
return this._array.length == 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructors for decoding standard exceptions received from the
|
||||
* worker.
|
||||
*/
|
||||
const EXCEPTION_CONSTRUCTORS = {
|
||||
EvalError: function(error) {
|
||||
let result = new EvalError(error.message, error.fileName, error.lineNumber);
|
||||
result.stack = error.stack;
|
||||
return result;
|
||||
},
|
||||
InternalError: function(error) {
|
||||
let result = new InternalError(error.message, error.fileName, error.lineNumber);
|
||||
result.stack = error.stack;
|
||||
return result;
|
||||
},
|
||||
RangeError: function(error) {
|
||||
let result = new RangeError(error.message, error.fileName, error.lineNumber);
|
||||
result.stack = error.stack;
|
||||
return result;
|
||||
},
|
||||
ReferenceError: function(error) {
|
||||
let result = new ReferenceError(error.message, error.fileName, error.lineNumber);
|
||||
result.stack = error.stack;
|
||||
return result;
|
||||
},
|
||||
SyntaxError: function(error) {
|
||||
let result = new SyntaxError(error.message, error.fileName, error.lineNumber);
|
||||
result.stack = error.stack;
|
||||
return result;
|
||||
},
|
||||
TypeError: function(error) {
|
||||
let result = new TypeError(error.message, error.fileName, error.lineNumber);
|
||||
result.stack = error.stack;
|
||||
return result;
|
||||
},
|
||||
URIError: function(error) {
|
||||
let result = new URIError(error.message, error.fileName, error.lineNumber);
|
||||
result.stack = error.stack;
|
||||
return result;
|
||||
},
|
||||
StopIteration: function() {
|
||||
return StopIteration;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An object responsible for dispatching messages to a chrome worker
|
||||
* and routing the responses.
|
||||
*
|
||||
* Instances of this constructor who need logging may provide a method
|
||||
* `log: function(...args) { ... }` in charge of printing out (or
|
||||
* discarding) logs.
|
||||
*
|
||||
* Instances of this constructor may add exception handlers to
|
||||
* `this.ExceptionHandlers`, if they need to handle custom exceptions.
|
||||
*
|
||||
* @param {string} url The url containing the source code for this worker,
|
||||
* as in constructor ChromeWorker.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
this.BasePromiseWorker = function(url) {
|
||||
if (typeof url != "string") {
|
||||
throw new TypeError("Expecting a string");
|
||||
}
|
||||
this._url = url;
|
||||
|
||||
/**
|
||||
* A set of methods, with the following
|
||||
*
|
||||
* ConstructorName: function({message, fileName, lineNumber}) {
|
||||
* // Construct a new instance of ConstructorName based on
|
||||
* // `message`, `fileName`, `lineNumber`
|
||||
* }
|
||||
*
|
||||
* By default, this covers EvalError, InternalError, RangeError,
|
||||
* ReferenceError, SyntaxError, TypeError, URIError, StopIteration.
|
||||
*/
|
||||
this.ExceptionHandlers = Object.create(EXCEPTION_CONSTRUCTORS);
|
||||
|
||||
/**
|
||||
* The queue of deferred, waiting for the completion of their
|
||||
* respective job by the worker.
|
||||
*
|
||||
* Each item in the list may contain an additional field |closure|,
|
||||
* used to store strong references to value that must not be
|
||||
* garbage-collected before the reply has been received (e.g.
|
||||
* arrays).
|
||||
*
|
||||
* @type {Queue<{deferred:deferred, closure:*=}>}
|
||||
*/
|
||||
this._queue = new Queue();
|
||||
|
||||
/**
|
||||
* The number of the current message.
|
||||
*
|
||||
* Used for debugging purposes.
|
||||
*/
|
||||
this._id = 0;
|
||||
|
||||
/**
|
||||
* The instant at which the worker was launched.
|
||||
*/
|
||||
this.launchTimeStamp = null;
|
||||
|
||||
/**
|
||||
* Timestamps provided by the worker for statistics purposes.
|
||||
*/
|
||||
this.workerTimeStamps = null;
|
||||
};
|
||||
this.BasePromiseWorker.prototype = {
|
||||
log: function() {
|
||||
// By Default, ignore all logs.
|
||||
},
|
||||
|
||||
/**
|
||||
* Instantiate the worker lazily.
|
||||
*/
|
||||
get _worker() {
|
||||
delete this._worker;
|
||||
let worker = new ChromeWorker(this._url);
|
||||
Object.defineProperty(this, "_worker", {value:
|
||||
worker
|
||||
});
|
||||
|
||||
// We assume that we call to _worker for the purpose of calling
|
||||
// postMessage().
|
||||
this.launchTimeStamp = Date.now();
|
||||
|
||||
/**
|
||||
* Receive errors that have been serialized by the built-in mechanism
|
||||
* of DOM/Chrome Workers.
|
||||
*
|
||||
* PromiseWorker.js knows how to serialize a number of errors
|
||||
* without losing information. These are treated by
|
||||
* |worker.onmessage|. However, for other errors, we rely on
|
||||
* DOM's mechanism for serializing errors, which transmits these
|
||||
* errors through |worker.onerror|.
|
||||
*
|
||||
* @param {Error} error Some JS error.
|
||||
*/
|
||||
worker.onerror = error => {
|
||||
this.log("Received uncaught error from worker", error.message, error.filename, error.lineno);
|
||||
error.preventDefault();
|
||||
let {deferred} = this._queue.pop();
|
||||
deferred.reject(error);
|
||||
};
|
||||
|
||||
/**
|
||||
* Receive messages from the worker, propagate them to the listeners.
|
||||
*
|
||||
* Messages must have one of the following shapes:
|
||||
* - {ok: some_value} in case of success
|
||||
* - {fail: some_error} in case of error, where
|
||||
* some_error is an instance of |PromiseWorker.WorkerError|
|
||||
*
|
||||
* Messages may also contain a field |id| to help
|
||||
* with debugging.
|
||||
*
|
||||
* Messages may also optionally contain a field |durationMs|, holding
|
||||
* the duration of the function call in milliseconds.
|
||||
*
|
||||
* @param {*} msg The message received from the worker.
|
||||
*/
|
||||
worker.onmessage = msg => {
|
||||
this.log("Received message from worker", msg.data);
|
||||
let handler = this._queue.pop();
|
||||
let deferred = handler.deferred;
|
||||
let data = msg.data;
|
||||
if (data.id != handler.id) {
|
||||
throw new Error("Internal error: expecting msg " + handler.id + ", " +
|
||||
" got " + data.id + ": " + JSON.stringify(msg.data));
|
||||
}
|
||||
if ("timeStamps" in data) {
|
||||
this.workerTimeStamps = data.timeStamps;
|
||||
}
|
||||
if ("ok" in data) {
|
||||
// Pass the data to the listeners.
|
||||
deferred.resolve(data);
|
||||
} else if ("fail" in data) {
|
||||
// We have received an error that was serialized by the
|
||||
// worker.
|
||||
deferred.reject(new WorkerError(data.fail));
|
||||
}
|
||||
};
|
||||
return worker;
|
||||
},
|
||||
|
||||
/**
|
||||
* Post a message to a worker.
|
||||
*
|
||||
* @param {string} fun The name of the function to call.
|
||||
* @param {Array} args The arguments to pass to `fun`. By convention,
|
||||
* the last argument may be an object `options` with some of the following
|
||||
* fields:
|
||||
* - {number|null} outExecutionDuration A parameter to be filled with the
|
||||
* duration of the off main thread execution for this call.
|
||||
* @param {*=} closure An object holding references that should not be
|
||||
* garbage-collected before the message treatment is complete.
|
||||
*
|
||||
* @return {promise}
|
||||
*/
|
||||
post: function(fun, args, closure) {
|
||||
return Task.spawn(function* postMessage() {
|
||||
let id = ++this._id;
|
||||
let message = {fun: fun, args: args, id: id};
|
||||
this.log("Posting message", message);
|
||||
try {
|
||||
this._worker.postMessage(message);
|
||||
} catch (ex if typeof ex == "number") {
|
||||
this.log("Could not post message", message, "due to xpcom error", ex);
|
||||
// handle raw xpcom errors (see eg bug 961317)
|
||||
throw new Components.Exception("Error in postMessage", ex);
|
||||
} catch (ex) {
|
||||
this.log("Could not post message", message, "due to error", ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
let deferred = Promise.defer();
|
||||
this._queue.push({deferred:deferred, closure: closure, id: id});
|
||||
this.log("Message posted");
|
||||
|
||||
let reply;
|
||||
let isError = false;
|
||||
try {
|
||||
this.log("Expecting reply");
|
||||
reply = yield deferred.promise;
|
||||
} catch (error) {
|
||||
this.log("Got error", error);
|
||||
reply = error;
|
||||
isError = true;
|
||||
|
||||
if (error instanceof WorkerError) {
|
||||
// We know how to deserialize most well-known errors
|
||||
throw this.ExceptionHandlers[error.data.exn](error.data);
|
||||
}
|
||||
|
||||
if (error instanceof ErrorEvent) {
|
||||
// Other errors get propagated as instances of ErrorEvent
|
||||
this.log("Error serialized by DOM", error.message, error.filename, error.lineno);
|
||||
throw new Error(error.message, error.filename, error.lineno);
|
||||
}
|
||||
|
||||
// We don't know about this kind of error
|
||||
throw error;
|
||||
}
|
||||
|
||||
// By convention, the last argument may be an object `options`.
|
||||
let options = null;
|
||||
if (args) {
|
||||
options = args[args.length - 1];
|
||||
}
|
||||
|
||||
// Check for duration and return result.
|
||||
if (!options ||
|
||||
typeof options !== "object" ||
|
||||
!("outExecutionDuration" in options)) {
|
||||
return reply.ok;
|
||||
}
|
||||
// If reply.durationMs is not present, just return the result,
|
||||
// without updating durations (there was an error in the method
|
||||
// dispatch).
|
||||
if (!("durationMs" in reply)) {
|
||||
return reply.ok;
|
||||
}
|
||||
// Bug 874425 demonstrates that two successive calls to Date.now()
|
||||
// can actually produce an interval with negative duration.
|
||||
// We assume that this is due to an operation that is so short
|
||||
// that Date.now() is not monotonic, so we round this up to 0.
|
||||
let durationMs = Math.max(0, reply.durationMs);
|
||||
// Accumulate (or initialize) outExecutionDuration
|
||||
if (typeof options.outExecutionDuration == "number") {
|
||||
options.outExecutionDuration += durationMs;
|
||||
} else {
|
||||
options.outExecutionDuration = durationMs;
|
||||
}
|
||||
return reply.ok;
|
||||
|
||||
}.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An error that has been serialized by the worker.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function WorkerError(data) {
|
||||
this.data = data;
|
||||
};
|
13
toolkit/components/promiseworker/moz.build
Normal file
13
toolkit/components/promiseworker/moz.build
Normal file
@ -0,0 +1,13 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
PARALLEL_DIRS += [
|
||||
'worker'
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES = [
|
||||
'PromiseWorker.jsm',
|
||||
]
|
206
toolkit/components/promiseworker/worker/PromiseWorker.js
Normal file
206
toolkit/components/promiseworker/worker/PromiseWorker.js
Normal file
@ -0,0 +1,206 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* A wrapper around `self` with extended capabilities designed
|
||||
* to simplify main thread-to-worker thread asynchronous function calls.
|
||||
*
|
||||
* This wrapper:
|
||||
* - groups requests and responses as a method `post` that returns a `Promise`;
|
||||
* - ensures that exceptions thrown on the worker thread are correctly serialized;
|
||||
* - provides some utilities for benchmarking various operations.
|
||||
*
|
||||
* Generally, you should use PromiseWorker.js along with its main thread-side
|
||||
* counterpart PromiseWorker.jsm.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
if (typeof Components != "undefined") {
|
||||
throw new Error("This module is meant to be used from the worker thread");
|
||||
}
|
||||
if (typeof require == "undefined" || typeof module == "undefined") {
|
||||
throw new Error("this module is meant to be imported using the implementation of require() at resource://gre/modules/workers/require.js");
|
||||
}
|
||||
|
||||
importScripts("resource://gre/modules/workers/require.js");
|
||||
|
||||
/**
|
||||
* Built-in JavaScript exceptions that may be serialized without
|
||||
* loss of information.
|
||||
*/
|
||||
const EXCEPTION_NAMES = {
|
||||
EvalError: "EvalError",
|
||||
InternalError: "InternalError",
|
||||
RangeError: "RangeError",
|
||||
ReferenceError: "ReferenceError",
|
||||
SyntaxError: "SyntaxError",
|
||||
TypeError: "TypeError",
|
||||
URIError: "URIError",
|
||||
};
|
||||
|
||||
/**
|
||||
* A constructor used to return data to the caller thread while
|
||||
* also executing some specific treatment (e.g. shutting down
|
||||
* the current thread, transmitting data instead of copying it).
|
||||
*
|
||||
* @param {object=} data The data to return to the caller thread.
|
||||
* @param {object=} meta Additional instructions, as an object
|
||||
* that may contain the following fields:
|
||||
* - {bool} shutdown If |true|, shut down the current thread after
|
||||
* having sent the result.
|
||||
* - {Array} transfers An array of objects that should be transferred
|
||||
* instead of being copied.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function Meta(data, meta) {
|
||||
this.data = data;
|
||||
this.meta = meta;
|
||||
};
|
||||
exports.Meta = Meta;
|
||||
|
||||
/**
|
||||
* Base class for a worker.
|
||||
*
|
||||
* Derived classes are expected to provide the following methods:
|
||||
* {
|
||||
* dispatch: function(method, args) {
|
||||
* // Dispatch a call to method `method` with args `args`
|
||||
* },
|
||||
* log: function(...msg) {
|
||||
* // Log (or discard) messages (optional)
|
||||
* },
|
||||
* postMessage: function(message, ...transfers) {
|
||||
* // Post a message to the main thread
|
||||
* },
|
||||
* close: function() {
|
||||
* // Close the worker
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* By default, the AbstractWorker is not connected to a message port,
|
||||
* hence will not receive anything.
|
||||
*
|
||||
* To connect it, use `onmessage`, as follows:
|
||||
* self.addEventListener("message", msg => myWorkerInstance.handleMessage(msg));
|
||||
*/
|
||||
function AbstractWorker(agent) {
|
||||
this._agent = agent;
|
||||
};
|
||||
AbstractWorker.prototype = {
|
||||
// Default logger: discard all messages
|
||||
log: function() {
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle a message.
|
||||
*/
|
||||
handleMessage: function(msg) {
|
||||
let data = msg.data;
|
||||
this.log("Received message", data);
|
||||
let id = data.id;
|
||||
|
||||
let start;
|
||||
let options;
|
||||
if (data.args) {
|
||||
options = data.args[data.args.length - 1];
|
||||
}
|
||||
// If |outExecutionDuration| option was supplied, start measuring the
|
||||
// duration of the operation.
|
||||
if (options && typeof options === "object" && "outExecutionDuration" in options) {
|
||||
start = Date.now();
|
||||
}
|
||||
|
||||
let result;
|
||||
let exn;
|
||||
let durationMs;
|
||||
let method = data.fun;
|
||||
try {
|
||||
this.log("Calling method", method);
|
||||
result = this.dispatch(method, data.args);
|
||||
this.log("Method", method, "succeeded");
|
||||
} catch (ex) {
|
||||
exn = ex;
|
||||
this.log("Error while calling agent method", method, exn, exn.moduleStack || exn.stack || "");
|
||||
}
|
||||
|
||||
if (start) {
|
||||
// Record duration
|
||||
durationMs = Date.now() - start;
|
||||
this.log("Method took", durationMs, "ms");
|
||||
}
|
||||
|
||||
// Now, post a reply, possibly as an uncaught error.
|
||||
// We post this message from outside the |try ... catch| block
|
||||
// to avoid capturing errors that take place during |postMessage| and
|
||||
// built-in serialization.
|
||||
if (!exn) {
|
||||
this.log("Sending positive reply", result, "id is", id);
|
||||
if (result instanceof Meta) {
|
||||
if ("transfers" in result.meta) {
|
||||
// Take advantage of zero-copy transfers
|
||||
this.postMessage({ok: result.data, id: id, durationMs: durationMs},
|
||||
result.meta.transfers);
|
||||
} else {
|
||||
this.postMessage({ok: result.data, id:id, durationMs: durationMs});
|
||||
}
|
||||
if (result.meta.shutdown || false) {
|
||||
// Time to close the worker
|
||||
this.close();
|
||||
}
|
||||
} else {
|
||||
this.postMessage({ok: result, id:id, durationMs: durationMs});
|
||||
}
|
||||
} else if (exn.constructor.name in EXCEPTION_NAMES) {
|
||||
// Rather than letting the DOM mechanism [de]serialize built-in
|
||||
// JS errors, which loses lots of information (in particular,
|
||||
// the constructor name, the moduleName and the moduleStack),
|
||||
// we [de]serialize them manually with a little more care.
|
||||
this.log("Sending back exception", exn.constructor.name, "id is", id);
|
||||
let error = {
|
||||
exn: exn.constructor.name,
|
||||
message: exn.message,
|
||||
fileName: exn.moduleName || exn.fileName,
|
||||
lineNumber: exn.lineNumber,
|
||||
stack: exn.moduleStack
|
||||
};
|
||||
this.postMessage({fail: error, id: id, durationMs: durationMs});
|
||||
} else if (exn == StopIteration) {
|
||||
// StopIteration is a well-known singleton, and requires a
|
||||
// slightly different treatment.
|
||||
this.log("Sending back StopIteration, id is", id);
|
||||
let error = {
|
||||
exn: "StopIteration"
|
||||
};
|
||||
this.postMessage({fail: error, id: id, durationMs: durationMs});
|
||||
} else if ("toMsg" in exn) {
|
||||
// Extension mechanism for exception [de]serialization. We
|
||||
// assume that any exception with a method `toMsg()` knows how
|
||||
// to serialize itself. The other side is expected to have
|
||||
// registered a deserializer using the `ExceptionHandlers`
|
||||
// object.
|
||||
this.log("Sending back an error that knows how to serialize itself", exn, "id is", id);
|
||||
let msg = exn.toMsg();
|
||||
this.postMessage({fail: msg, id:id, durationMs: durationMs});
|
||||
} else {
|
||||
// If we encounter an exception for which we have no
|
||||
// serialization mechanism in place, we have no choice but to
|
||||
// let the DOM handle said [de]serialization. We can just
|
||||
// attempt to mitigate the data loss by injecting `moduleName` and
|
||||
// `moduleStack`.
|
||||
this.log("Sending back regular error", exn, exn.moduleStack || exn.stack, "id is", id);
|
||||
|
||||
try {
|
||||
// Attempt to introduce human-readable filename and stack
|
||||
exn.filename = exn.moduleName;
|
||||
exn.stack = exn.moduleStack;
|
||||
} catch (_) {
|
||||
// Nothing we can do
|
||||
}
|
||||
throw exn;
|
||||
}
|
||||
}
|
||||
};
|
||||
exports.AbstractWorker = AbstractWorker;
|
11
toolkit/components/promiseworker/worker/moz.build
Normal file
11
toolkit/components/promiseworker/worker/moz.build
Normal file
@ -0,0 +1,11 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
JS_MODULES_PATH = 'modules/workers'
|
||||
|
||||
EXTRA_JS_MODULES = [
|
||||
'PromiseWorker.js',
|
||||
]
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user