Merge m-c to fx-team

This commit is contained in:
Wes Kocher 2014-07-02 19:10:42 -07:00
commit 46f0e233a5
106 changed files with 1749 additions and 1062 deletions

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "616fb21109ca9af6e0371a6d109dc4e3032ae4be",
"revision": "4e3596b10de8df9202d9c0a7f64b7913bdfaaead",
"repo_path": "/integration/gaia-central"
}

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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="*">

View File

@ -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")) {

View File

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

View File

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

View File

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

View File

@ -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"

View File

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

View File

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

View File

@ -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,

View File

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

View File

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

View File

@ -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) {

View File

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

View File

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

View File

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

View File

@ -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)
{

View File

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

View File

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

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

View File

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

View File

@ -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 {

View File

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

View File

@ -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()
{

View File

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

View File

@ -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)
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)) {

View File

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

View File

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

View File

@ -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)

View File

@ -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++)

View File

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

View 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();

View 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];
});
}

View File

@ -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 {

View File

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

View File

@ -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
{

View File

@ -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:

View File

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

View File

@ -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 {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)
{

View File

@ -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)

View File

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

View File

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

View File

@ -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
/*

View File

@ -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);
/*

View File

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

View File

@ -39,7 +39,7 @@ function boom_391747() {
SimpleTest.finish();
}
setTimeout(boom_391747,400)
addLoadEvent(boom_391747);
SimpleTest.waitForExplicitFinish()
</script>

View File

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

View File

@ -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",

View File

@ -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());

View File

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

View File

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

View File

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

View File

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

View File

@ -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,

View File

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

View File

@ -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,

View File

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

View File

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

View File

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

View File

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

View File

@ -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");

View File

@ -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,

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@
/*****************************************************************************/
#include <stdint.h>
const PRTime gPreloadListExpirationTime = INT64_C(1414837778473000);
const PRTime gPreloadListExpirationTime = INT64_C(1415206745808000);
class nsSTSPreload
{

View File

@ -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) {

View File

@ -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()

View File

@ -33,6 +33,7 @@ PARALLEL_DIRS += [
'passwordmgr',
'perf',
'places',
'promiseworker',
'prompts',
'protobuf',
'reflect',

View File

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

View File

@ -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',

View File

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

View File

@ -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.
*

View File

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

View File

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

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

View 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',
]

View 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;

View 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