Merge inbound to m-c a=merge

This commit is contained in:
Wes Kocher 2015-02-23 16:05:13 -08:00
commit 530c4a09f9
102 changed files with 1632 additions and 629 deletions

View File

@ -157,7 +157,7 @@ struct EventNameMapping
{
// This holds pointers to nsGkAtoms members, and is therefore safe as a
// non-owning reference.
nsIAtom* MOZ_OWNING_REF mAtom;
nsIAtom* MOZ_NON_OWNING_REF mAtom;
uint32_t mId;
int32_t mType;
mozilla::EventClassID mEventClassID;

View File

@ -120,27 +120,19 @@ nsStyleLinkElement::SetLineNumber(uint32_t aLineNumber)
}
/* static */ bool
nsStyleLinkElement::IsImportEnabled(nsIPrincipal* aPrincipal)
nsStyleLinkElement::IsImportEnabled()
{
static bool sAdded = false;
static bool sWebComponentsEnabled;
static bool sImportsEnabled;
if (!sAdded) {
// This part runs only once because of the static flag.
Preferences::AddBoolVarCache(&sWebComponentsEnabled,
"dom.webcomponents.enabled",
Preferences::AddBoolVarCache(&sImportsEnabled,
"dom.htmlimports.enabled",
false);
sAdded = true;
}
if (sWebComponentsEnabled) {
return true;
}
// If the web components pref is not enabled, check
// if we are in a certified app because imports is enabled
// for certified apps.
return aPrincipal &&
aPrincipal->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED;
return sImportsEnabled;
}
static uint32_t ToLinkMask(const nsAString& aLink, nsIPrincipal* aPrincipal)
@ -155,8 +147,8 @@ static uint32_t ToLinkMask(const nsAString& aLink, nsIPrincipal* aPrincipal)
return nsStyleLinkElement::eNEXT;
else if (aLink.EqualsLiteral("alternate"))
return nsStyleLinkElement::eALTERNATE;
else if (aLink.EqualsLiteral("import") && aPrincipal &&
nsStyleLinkElement::IsImportEnabled(aPrincipal))
else if (aLink.EqualsLiteral("import") &&
nsStyleLinkElement::IsImportEnabled())
return nsStyleLinkElement::eHTMLIMPORT;
else
return 0;

View File

@ -68,7 +68,7 @@ public:
static uint32_t ParseLinkTypes(const nsAString& aTypes,
nsIPrincipal* aPrincipal);
static bool IsImportEnabled(nsIPrincipal* aPrincipal);
static bool IsImportEnabled();
void UpdateStyleSheetInternal()
{

View File

@ -28,6 +28,7 @@
#include "mozilla/MemoryReporting.h"
#include "mozilla/CycleCollectedJSRuntime.h"
#include "nsCycleCollector.h"
#include "nsIGlobalObject.h"
#include "nsIXPConnect.h"
#include "nsJSUtils.h"
#include "nsISupportsImpl.h"
@ -1577,6 +1578,15 @@ WrapNativeParent(JSContext* cx, const T& p)
return WrapNativeParent(cx, GetParentPointer(p), GetWrapperCache(p), GetUseXBLScope(p));
}
// Specialization for the case of nsIGlobalObject, since in that case
// we can just get the JSObject* directly.
template<>
inline JSObject*
WrapNativeParent(JSContext* cx, nsIGlobalObject* const& p)
{
return p ? p->GetGlobalJSObject() : JS::CurrentGlobalOrNull(cx);
}
template<typename T, bool WrapperCached=NativeHasMember<T>::GetParentObject>
struct GetParentObject
{

View File

@ -16,8 +16,9 @@ DataContainerEvent::DataContainerEvent(EventTarget* aOwner,
WidgetEvent* aEvent)
: Event(aOwner, aPresContext, aEvent)
{
if (mOwner) {
if (nsIDocument* doc = mOwner->GetExtantDoc()) {
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mOwner);
if (win) {
if (nsIDocument* doc = win->GetExtantDoc()) {
doc->WarnOnceAbout(nsIDocument::eDataContainerEvent);
}
}

View File

@ -1026,7 +1026,11 @@ Event::TimeStamp() const
return 0.0;
}
nsPerformance* perf = mOwner->GetPerformance();
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mOwner);
if (NS_WARN_IF(!win)) {
return 0.0;
}
nsPerformance* perf = win->GetPerformance();
if (NS_WARN_IF(!perf)) {
return 0.0;
}
@ -1049,8 +1053,9 @@ Event::TimeStamp() const
bool
Event::GetPreventDefault() const
{
if (mOwner) {
if (nsIDocument* doc = mOwner->GetExtantDoc()) {
nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mOwner));
if (win) {
if (nsIDocument* doc = win->GetExtantDoc()) {
doc->WarnOnceAbout(nsIDocument::eGetPreventDefault);
}
}
@ -1130,23 +1135,23 @@ Event::SetOwner(mozilla::dom::EventTarget* aOwner)
nsCOMPtr<nsINode> n = do_QueryInterface(aOwner);
if (n) {
mOwner = do_QueryInterface(n->OwnerDoc()->GetScopeObject());
mOwner = n->OwnerDoc()->GetScopeObject();
return;
}
nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aOwner);
if (w) {
if (w->IsOuterWindow()) {
mOwner = w->GetCurrentInnerWindow();
mOwner = do_QueryInterface(w->GetCurrentInnerWindow());
} else {
mOwner.swap(w);
mOwner = do_QueryInterface(w);
}
return;
}
nsCOMPtr<DOMEventTargetHelper> eth = do_QueryInterface(aOwner);
if (eth) {
mOwner = eth->GetOwner();
mOwner = eth->GetParentObject();
return;
}

View File

@ -19,6 +19,7 @@
#include "nsIScriptGlobalObject.h"
#include "Units.h"
#include "js/TypeDecls.h"
#include "nsIGlobalObject.h"
class nsIContent;
class nsIDOMEventTarget;
@ -63,15 +64,6 @@ private:
WidgetEvent* aEvent);
public:
void GetParentObject(nsIScriptGlobalObject** aParentObject)
{
if (mOwner) {
CallQueryInterface(mOwner, aParentObject);
} else {
*aParentObject = nullptr;
}
}
static Event* FromSupports(nsISupports* aSupports)
{
nsIDOMEvent* event =
@ -93,7 +85,7 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Event)
nsISupports* GetParentObject()
nsIGlobalObject* GetParentObject()
{
return mOwner;
}
@ -274,7 +266,7 @@ protected:
mozilla::WidgetEvent* mEvent;
nsRefPtr<nsPresContext> mPresContext;
nsCOMPtr<EventTarget> mExplicitOriginalTarget;
nsCOMPtr<nsPIDOMWindow> mOwner; // nsPIDOMWindow for now.
nsCOMPtr<nsIGlobalObject> mOwner;
bool mEventIsInternal;
bool mPrivateDataDuplicated;
bool mIsMainThreadEvent;

View File

@ -275,7 +275,7 @@ HTMLLinkElement::UpdateImport()
return;
}
if (!nsStyleLinkElement::IsImportEnabled(NodePrincipal())) {
if (!nsStyleLinkElement::IsImportEnabled()) {
// For now imports are hidden behind a pref...
return;
}

View File

@ -28,7 +28,6 @@
#include "nsIEffectiveTLDService.h"
#include "nsIIDNService.h"
#include "nsCRT.h"
#include "mozilla/plugins/PluginTypes.h"
#ifdef XP_WIN
#include "nsIWindowsRegKey.h"
@ -37,6 +36,7 @@
namespace mozilla {
namespace plugins {
class PluginAsyncSurrogate;
class PluginTag;
} // namespace mozilla
} // namespace plugins

View File

@ -2228,6 +2228,7 @@ XMLHttpRequest::Abort(ErrorResult& aRv)
if (mCanceled) {
aRv.ThrowUncatchableException();
return;
}
if (!mProxy) {

View File

@ -1,10 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
# Due to bug 796023, we can't have -DUNICODE and -D_UNICODE; defining those
# macros changes the type of LOGFONT to LOGFONTW instead of LOGFONTA. This
# changes the symbol names of exported C++ functions that use LOGFONT.
DEFINES := $(filter-out -DUNICODE -D_UNICODE,$(DEFINES))

View File

@ -170,3 +170,10 @@ CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gtk3', 'gonk', 'qt'):
CXXFLAGS += CONFIG['CAIRO_FT_CFLAGS']
if CONFIG['OS_ARCH'] == 'WINNT':
# Due to bug 796023, we can't have -DUNICODE and -D_UNICODE; defining those
# macros changes the type of LOGFONT to LOGFONTW instead of LOGFONTA. This
# changes the symbol names of exported C++ functions that use LOGFONT.
del DEFINES['UNICODE']
del DEFINES['_UNICODE']

View File

@ -1,7 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
DEFINES := $(filter-out -DUNICODE,$(DEFINES))

View File

@ -157,3 +157,6 @@ CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
CXXFLAGS += CONFIG['TK_CFLAGS']
CFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
CFLAGS += CONFIG['TK_CFLAGS']
if CONFIG['OS_ARCH'] == 'WINNT':
del DEFINES['UNICODE']

View File

@ -244,7 +244,7 @@ already_AddRefed<nsIDOMWindowUtils>
APZCCallbackHelper::GetDOMWindowUtils(const nsIContent* aContent)
{
nsCOMPtr<nsIDOMWindowUtils> utils;
nsIDocument* doc = aContent->GetCurrentDoc();
nsIDocument* doc = aContent->GetComposedDoc();
if (doc) {
utils = GetDOMWindowUtils(doc);
}

View File

@ -4,7 +4,5 @@
include $(topsrcdir)/config/rules.mk
DEFINES := $(filter-out -DUNICODE,$(DEFINES))
DeprecatedPremultiplyTables.h: $(srcdir)/genTables.py
$(PYTHON) $(srcdir)/genTables.py

View File

@ -1067,6 +1067,11 @@ gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry* aFontEntry,
NS_ASSERTION(aFontEntry->mFamilyName.Length() != 0,
"caching a font associated with no family yet");
// if caching is disabled, simply return
if (Preferences::GetBool("gfx.downloadable_fonts.disable_cache")) {
return;
}
gfxUserFontData* data = aFontEntry->mUserFontData;
if (data->mIsBuffer) {
#ifdef DEBUG_USERFONT_CACHE
@ -1143,7 +1148,8 @@ gfxUserFontSet::UserFontCache::GetFont(nsIURI* aSrcURI,
gfxUserFontEntry* aUserFontEntry,
bool aPrivate)
{
if (!sUserFonts) {
if (!sUserFonts ||
Preferences::GetBool("gfx.downloadable_fonts.disable_cache")) {
return nullptr;
}

View File

@ -1973,13 +1973,6 @@ public:
mSoftwareVsyncRate = TimeDuration::FromMilliseconds(rate);
}
virtual ~D3DVsyncDisplay()
{
MOZ_ASSERT(NS_IsMainThread());
DisableVsync();
delete mVsyncThread;
}
virtual void EnableVsync() MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
@ -2082,6 +2075,13 @@ public:
}
private:
virtual ~D3DVsyncDisplay()
{
MOZ_ASSERT(NS_IsMainThread());
DisableVsync();
delete mVsyncThread;
}
bool IsInVsyncThread()
{
return mVsyncThread->thread_id() == PlatformThread::CurrentId();

View File

@ -302,3 +302,6 @@ DEFINES['GRAPHITE2_STATIC'] = True
if CONFIG['GKMEDIAS_SHARED_LIBRARY']:
DEFINES['OTS_DLL'] = True
if CONFIG['OS_ARCH'] == 'WINNT':
del DEFINES['UNICODE']

View File

@ -22,6 +22,8 @@ ${INCLUDES}
using namespace std;
using base::Thread;
namespace mozilla {
namespace _ipdltest {

View File

@ -20,6 +20,9 @@ struct RunnableMethodTraits<mozilla::_ipdltest2::TestOpensOpenedChild>
using namespace mozilla::ipc;
using base::ProcessHandle;
using base::Thread;
namespace mozilla {
// NB: this is generally bad style, but I am lazy.
using namespace _ipdltest;

View File

@ -311,6 +311,7 @@ selfhosting_srcs := \
$(srcdir)/builtin/Map.js \
$(srcdir)/builtin/Number.js \
$(srcdir)/builtin/Object.js \
$(srcdir)/builtin/RegExp.js \
$(srcdir)/builtin/String.js \
$(srcdir)/builtin/Set.js \
$(srcdir)/builtin/TypedArray.js \

View File

@ -689,7 +689,10 @@ js::obj_create(JSContext *cx, unsigned argc, Value *vp)
/* 15.2.3.5 step 4. */
if (args.hasDefined(1)) {
if (args[1].isPrimitive()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args[1], NullPtr());
if (!bytes)
return false;
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes);
return false;
}

View File

@ -328,67 +328,6 @@ regexp_toString(JSContext *cx, unsigned argc, Value *vp)
return CallNonGenericMethod<IsRegExp, regexp_toString_impl>(cx, args);
}
/* ES6 draft rev29 21.2.5.3 RegExp.prototype.flags */
bool
regexp_flags(JSContext *cx, unsigned argc, JS::Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
/* Steps 1-2. */
if (!args.thisv().isObject()) {
char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.thisv(), NullPtr());
if (!bytes)
return false;
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
bytes, "not an object");
js_free(bytes);
return false;
}
RootedObject thisObj(cx, &args.thisv().toObject());
/* Step 3. */
StringBuffer sb(cx);
/* Steps 4-6. */
RootedValue global(cx);
if (!GetProperty(cx, thisObj, thisObj, cx->names().global, &global))
return false;
if (ToBoolean(global) && !sb.append('g'))
return false;
/* Steps 7-9. */
RootedValue ignoreCase(cx);
if (!GetProperty(cx, thisObj, thisObj, cx->names().ignoreCase, &ignoreCase))
return false;
if (ToBoolean(ignoreCase) && !sb.append('i'))
return false;
/* Steps 10-12. */
RootedValue multiline(cx);
if (!GetProperty(cx, thisObj, thisObj, cx->names().multiline, &multiline))
return false;
if (ToBoolean(multiline) && !sb.append('m'))
return false;
/* Steps 13-15. */
RootedValue unicode(cx);
if (!GetProperty(cx, thisObj, thisObj, cx->names().unicode, &unicode))
return false;
if (ToBoolean(unicode) && !sb.append('u'))
return false;
/* Steps 16-18. */
RootedValue sticky(cx);
if (!GetProperty(cx, thisObj, thisObj, cx->names().sticky, &sticky))
return false;
if (ToBoolean(sticky) && !sb.append('y'))
return false;
/* Step 19. */
args.rval().setString(sb.finishString());
return true;
}
/* ES6 draft rev32 21.2.5.4. */
MOZ_ALWAYS_INLINE bool
regexp_global_impl(JSContext *cx, CallArgs args)
@ -499,7 +438,7 @@ regexp_sticky(JSContext *cx, unsigned argc, JS::Value *vp)
}
static const JSPropertySpec regexp_properties[] = {
JS_PSG("flags", regexp_flags, 0),
JS_SELF_HOSTED_GET("flags", "RegExpFlagsGetter", 0),
JS_PSG("global", regexp_global, 0),
JS_PSG("ignoreCase", regexp_ignoreCase, 0),
JS_PSG("multiline", regexp_multiline, 0),

38
js/src/builtin/RegExp.js Normal file
View File

@ -0,0 +1,38 @@
/* 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/. */
// ES6 draft rev34 (2015/02/20) 21.2.5.3 get RegExp.prototype.flags
function RegExpFlagsGetter() {
// Steps 1-2.
var R = this;
if (!IsObject(R))
ThrowError(JSMSG_NOT_NONNULL_OBJECT, R === null ? "null" : typeof R);
// Step 3.
var result = "";
// Steps 4-6.
if (R.global)
result += "g";
// Steps 7-9.
if (R.ignoreCase)
result += "i";
// Steps 10-12.
if (R.multiline)
result += "m";
// Steps 13-15.
// TODO: Uncomment these steps when bug 1135377 is fixed.
// if (R.unicode)
// result += "u";
// Steps 16-18.
if (R.sticky)
result += "y";
// Step 19.
return result;
}

View File

@ -16,7 +16,7 @@ function WeakSet_add(value) {
// Step 5.
if (!IsObject(value))
ThrowError(JSMSG_NOT_NONNULL_OBJECT);
ThrowError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(0, value));
// Steps 7-8.
callFunction(std_WeakMap_set, entries, value, true);

View File

@ -123,7 +123,10 @@ WeakSetObject::construct(JSContext *cx, unsigned argc, Value *vp)
if (isOriginalAdder) {
if (keyVal.isPrimitive()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, keyVal, NullPtr());
if (!bytes)
return false;
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes);
return false;
}

View File

@ -748,6 +748,7 @@ class JitCode;
typedef PreBarriered<JSObject*> PreBarrieredObject;
typedef PreBarriered<JSScript*> PreBarrieredScript;
typedef PreBarriered<jit::JitCode*> PreBarrieredJitCode;
typedef PreBarriered<JSString*> PreBarrieredString;
typedef PreBarriered<JSAtom*> PreBarrieredAtom;
typedef RelocatablePtr<JSObject*> RelocatablePtrObject;

View File

@ -908,10 +908,10 @@ class GCRuntime
void sweepBackgroundThings(ZoneList &zones, LifoAlloc &freeBlocks, ThreadType threadType);
void assertBackgroundSweepingFinished();
bool shouldCompact();
IncrementalProgress compactPhase(bool lastGC);
IncrementalProgress compactPhase(bool lastGC, JS::gcreason::Reason reason);
void sweepTypesAfterCompacting(Zone *zone);
void sweepZoneAfterCompacting(Zone *zone);
ArenaHeader *relocateArenas();
ArenaHeader *relocateArenas(JS::gcreason::Reason reason);
void updateAllCellPointersParallel(MovingTracer *trc);
void updateAllCellPointersSerial(MovingTracer *trc);
void updatePointersToRelocatedCells();

View File

@ -422,7 +422,7 @@ GetObjectAllocKindForCopy(const Nursery &nursery, JSObject *obj)
// Unboxed plain objects are sized according to the data they store.
if (obj->is<UnboxedPlainObject>()) {
size_t nbytes = obj->as<UnboxedPlainObject>().layout().size();
size_t nbytes = obj->as<UnboxedPlainObject>().layoutDontCheckGeneration().size();
return GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + nbytes);
}

View File

@ -0,0 +1,19 @@
function binaryX4(op, v, w) {
var arr = [];
var [varr, warr] = [simdToArray(v), simdToArray(w)];
[varr, warr] = [varr.map(Math.fround), warr.map(Math.fround)];
for (var i = 0; i < 4; i++)
arr[i] = op(varr[i], warr[i]);
return arr.map(Math.fround);
}
function assertEqX4(vec, arr) {
assertEq(vec.x, arr[0]);
assertEq(vec.y, arr[1]);
assertEq(vec.z, arr[2]);
assertEq(vec.w, arr[3]);
}
function simdToArray(vec) {
return [vec.x, vec.y, vec.z, vec.w];
}

View File

@ -0,0 +1,33 @@
load(libdir + 'simd.js');
setJitCompilerOption("ion.warmup.trigger", 50);
function maxNum(x, y) {
if (x != x)
return y;
if (y != y)
return x;
return Math.max(x, y);
}
function minNum(x, y) {
if (x != x)
return y;
if (y != y)
return x;
return Math.min(x, y);
}
function f() {
var f1 = SIMD.float32x4(1, 2, 3, 4);
var f2 = SIMD.float32x4(4, 3, 2, 1);
for (var i = 0; i < 150; i++) {
assertEqX4(SIMD.float32x4.div(f1, f2), binaryX4((x, y) => x / y, f1, f2));
assertEqX4(SIMD.float32x4.min(f1, f2), binaryX4(Math.min, f1, f2));
assertEqX4(SIMD.float32x4.max(f1, f2), binaryX4(Math.max, f1, f2));
assertEqX4(SIMD.float32x4.minNum(f1, f2), binaryX4(minNum, f1, f2));
assertEqX4(SIMD.float32x4.maxNum(f1, f2), binaryX4(maxNum, f1, f2));
}
}
f();

View File

@ -0,0 +1,40 @@
load(libdir + "simd.js");
setJitCompilerOption("ion.warmup.trigger", 50);
var helpers = (function() {
var i32 = new Int32Array(2);
var f32 = new Float32Array(i32.buffer);
return {
and: function(x, y) {
f32[0] = x;
f32[1] = y;
i32[0] = i32[0] & i32[1];
return f32[0];
},
or: function(x, y) {
f32[0] = x;
f32[1] = y;
i32[0] = i32[0] | i32[1];
return f32[0];
},
xor: function(x, y) {
f32[0] = x;
f32[1] = y;
i32[0] = i32[0] ^ i32[1];
return f32[0];
},
}
})();
function f() {
var f1 = SIMD.float32x4(1, 2, 3, 4);
var f2 = SIMD.float32x4(4, 3, 2, 1);
for (var i = 0; i < 150; i++) {
assertEqX4(SIMD.float32x4.and(f1, f2), binaryX4(helpers.and, f1, f2));
assertEqX4(SIMD.float32x4.or(f1, f2), binaryX4(helpers.or, f1, f2));
assertEqX4(SIMD.float32x4.xor(f1, f2), binaryX4(helpers.xor, f1, f2));
}
}
f();

View File

@ -0,0 +1,18 @@
function f(obj) {
return typeof obj[15];
}
function test() {
var a = [1, 2];
a.__proto__ = {15: 1337};
var b = [1, 2, 3, 4];
for (var i = 0; i < 1000; i++) {
var r = f(i % 2 ? a : b);
assertEq(r, i % 2 ? "number" : "undefined");
}
}
test();
test();
test();

View File

@ -0,0 +1,10 @@
function Foo(a, b) {
b = {};
this.b = b;
};
var a = [];
for (var i = 0; i < 50; i++)
a.push(new Foo(i, i + 1));
i = 0;
a[i].c = i;

View File

@ -0,0 +1,28 @@
function f() {
var x = [1, 2, 3];
var y = {};
x.__proto__ = y;
for (var i = 0; i < 200; i++) {
if (i == 100)
y[100000] = 15;
else
assertEq(typeof x[100000], i > 100 ? "number" : "undefined");
}
}
function g() {
var x = [1, 2, 3];
var y = {};
x.__proto__ = y;
for (var i = 0; i < 200; i++) {
if (i == 100)
y[4] = 15;
else
assertEq(typeof x[4], i > 100 ? "number" : "undefined");
}
}
f();
g();

View File

@ -107,6 +107,7 @@ check("o[~(o)]");
check("o[+ (o)]");
check("o[- (o)]");
// A few one off tests
check_one("6", (function () { 6() }), " is not a function");
check_one("Array.prototype.reverse.call(...)", (function () { Array.prototype.reverse.call('123'); }), " is read-only");
@ -114,6 +115,8 @@ check_one(`(intermediate value)[Symbol.iterator](...).next(...).value`,
function () { var [{ x }] = [null, {}]; }, " is null");
check_one(`(intermediate value)[Symbol.iterator](...).next(...).value`,
function () { ieval("let (x) { var [a, b, [c0, c1]] = [x, x, x]; }") }, " is undefined");
check_one("void 1", function() { (void 1)(); }, " is not a function");
check_one("void o[1]", function() { var o = []; (void o[1])() }, " is not a function");
// Check fallback behavior
assertThrowsInstanceOf(function () { for (let x of undefined) {} }, TypeError);

View File

@ -9167,6 +9167,16 @@ GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc,
return !!res;
}
#undef ADD_INT32X4_SIMD_OP_NAME_
#define ADD_FLOAT32X4_SIMD_OP_NAME_(OP) || native == js::simd_float32x4_##OP
if (false
ARITH_FLOAT32X4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_)
BITWISE_COMMONX4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_))
{
Rooted<SimdTypeDescr *> descr(cx, &cx->global()->float32x4TypeDescr().as<SimdTypeDescr>());
res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
return !!res;
}
#undef ADD_FLOAT32X4_SIMD_OP_NAME_
}
return true;

View File

@ -805,10 +805,10 @@ class IonBuilder
// SIMD intrinsics and natives.
InliningStatus inlineConstructSimdObject(CallInfo &callInfo, SimdTypeDescr *target);
InliningStatus inlineSimdInt32x4BinaryArith(CallInfo &callInfo, JSNative native,
MSimdBinaryArith::Operation op);
InliningStatus inlineSimdInt32x4BinaryBitwise(CallInfo &callInfo, JSNative native,
MSimdBinaryBitwise::Operation op);
template <typename T>
InliningStatus inlineBinarySimd(CallInfo &callInfo, JSNative native,
typename T::Operation op, SimdTypeDescr::Type type);
// Utility intrinsics.
InliningStatus inlineIsCallable(CallInfo &callInfo);

View File

@ -3258,6 +3258,160 @@ GetElementIC::attachDenseElement(JSContext *cx, HandleScript outerScript, IonScr
return linkAndAttachStub(cx, masm, attacher, ion, "dense array");
}
/* static */ bool
GetElementIC::canAttachDenseElementHole(JSObject *obj, const Value &idval, TypedOrValueRegister output)
{
if (!idval.isInt32())
return false;
if (!output.hasValue())
return false;
if (!obj->isNative())
return false;
if (obj->as<NativeObject>().getDenseInitializedLength() == 0)
return false;
while (obj) {
if (obj->isIndexed())
return false;
if (ClassCanHaveExtraProperties(obj->getClass()))
return false;
JSObject *proto = obj->getProto();
if (!proto)
break;
if (!proto->isNative())
return false;
// Make sure objects on the prototype don't have dense elements.
if (proto->as<NativeObject>().getDenseInitializedLength() != 0)
return false;
obj = proto;
}
return true;
}
static bool
GenerateDenseElementHole(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
IonScript *ion, JSObject *obj, const Value &idval,
Register object, ConstantOrRegister index, TypedOrValueRegister output)
{
MOZ_ASSERT(GetElementIC::canAttachDenseElementHole(obj, idval, output));
MOZ_ASSERT(obj->lastProperty());
Register scratchReg = output.valueReg().scratchReg();
// Guard on the shape and group, to prevent non-dense elements from appearing.
Label failures;
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
Address(object, JSObject::offsetOfShape()),
ImmGCPtr(obj->lastProperty()), &failures);
if (obj->hasUncacheableProto()) {
masm.loadPtr(Address(object, JSObject::offsetOfGroup()), scratchReg);
Address proto(scratchReg, ObjectGroup::offsetOfProto());
masm.branchPtr(Assembler::NotEqual, proto,
ImmMaybeNurseryPtr(obj->getProto()), &failures);
}
JSObject *pobj = obj->getProto();
while (pobj) {
MOZ_ASSERT(pobj->lastProperty());
masm.movePtr(ImmMaybeNurseryPtr(pobj), scratchReg);
if (pobj->hasUncacheableProto()) {
MOZ_ASSERT(!pobj->isSingleton());
Address groupAddr(scratchReg, JSObject::offsetOfGroup());
masm.branchPtr(Assembler::NotEqual, groupAddr, ImmGCPtr(pobj->group()), &failures);
}
// Make sure the shape matches, to avoid non-dense elements.
masm.branchPtr(Assembler::NotEqual, Address(scratchReg, JSObject::offsetOfShape()),
ImmGCPtr(pobj->lastProperty()), &failures);
// Load elements vector.
masm.loadPtr(Address(scratchReg, NativeObject::offsetOfElements()), scratchReg);
// Also make sure there are no dense elements.
Label hole;
Address initLength(scratchReg, ObjectElements::offsetOfInitializedLength());
masm.branch32(Assembler::NotEqual, initLength, Imm32(0), &failures);
pobj = pobj->getProto();
}
// Ensure the index is an int32 value.
Register indexReg = InvalidReg;
Register elementsReg = InvalidReg;
if (index.reg().hasValue()) {
indexReg = scratchReg;
MOZ_ASSERT(indexReg != InvalidReg);
ValueOperand val = index.reg().valueReg();
masm.branchTestInt32(Assembler::NotEqual, val, &failures);
// Unbox the index.
masm.unboxInt32(val, indexReg);
// Save the object register.
masm.push(object);
elementsReg = object;
} else {
MOZ_ASSERT(!index.reg().typedReg().isFloat());
indexReg = index.reg().typedReg().gpr();
elementsReg = scratchReg;
}
// Load elements vector.
masm.loadPtr(Address(object, NativeObject::offsetOfElements()), elementsReg);
// Guard on the initialized length.
Label hole;
Address initLength(elementsReg, ObjectElements::offsetOfInitializedLength());
masm.branch32(Assembler::BelowOrEqual, initLength, indexReg, &hole);
// Load the value.
Label done;
masm.loadValue(BaseObjectElementIndex(elementsReg, indexReg), output.valueReg());
masm.branchTestMagic(Assembler::NotEqual, output.valueReg(), &done);
// Load undefined for the hole.
masm.bind(&hole);
masm.moveValue(UndefinedValue(), output.valueReg());
masm.bind(&done);
// Restore the object register.
if (elementsReg == object)
masm.pop(object);
attacher.jumpRejoin(masm);
// All failure flows through here.
masm.bind(&failures);
attacher.jumpNextStub(masm);
return true;
}
bool
GetElementIC::attachDenseElementHole(JSContext *cx, HandleScript outerScript, IonScript *ion,
HandleObject obj, const Value &idval)
{
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
RepatchStubAppender attacher(*this);
GenerateDenseElementHole(cx, masm, attacher, ion, obj, idval, object(), index(), output());
return linkAndAttachStub(cx, masm, attacher, ion, "dense hole");
}
/* static */ bool
GetElementIC::canAttachTypedArrayElement(JSObject *obj, const Value &idval,
TypedOrValueRegister output)
@ -3568,6 +3722,13 @@ GetElementIC::update(JSContext *cx, HandleScript outerScript, size_t cacheIndex,
return false;
attachedStub = true;
}
if (!attachedStub && cache.monitoredResult() &&
canAttachDenseElementHole(obj, idval, cache.output()))
{
if (!cache.attachDenseElementHole(cx, outerScript, ion, obj, idval))
return false;
attachedStub = true;
}
if (!attachedStub && canAttachTypedArrayElement(obj, idval, cache.output())) {
if (!cache.attachTypedArrayElement(cx, outerScript, ion, obj, idval))
return false;

View File

@ -842,6 +842,8 @@ class GetElementIC : public RepatchIonCache
static bool canAttachGetProp(JSObject *obj, const Value &idval, jsid id);
static bool canAttachDenseElement(JSObject *obj, const Value &idval);
static bool canAttachDenseElementHole(JSObject *obj, const Value &idval,
TypedOrValueRegister output);
static bool canAttachTypedArrayElement(JSObject *obj, const Value &idval,
TypedOrValueRegister output);
@ -851,6 +853,9 @@ class GetElementIC : public RepatchIonCache
bool attachDenseElement(JSContext *cx, HandleScript outerScript, IonScript *ion,
HandleObject obj, const Value &idval);
bool attachDenseElementHole(JSContext *cx, HandleScript outerScript, IonScript *ion,
HandleObject obj, const Value &idval);
bool attachTypedArrayElement(JSContext *cx, HandleScript outerScript, IonScript *ion,
HandleObject tarr, const Value &idval);

View File

@ -520,6 +520,9 @@ class LSimdBinaryBitwiseX4 : public LInstructionHelper<1, 2, 0>
MSimdBinaryBitwise::Operation operation() const {
return mir_->toSimdBinaryBitwise()->operation();
}
const char *extraName() const {
return MSimdBinaryBitwise::OperationName(operation());
}
MIRType type() const {
return mir_->type();
}

View File

@ -257,17 +257,29 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSFunction *target)
return inlineBoundFunction(callInfo, target);
// Simd functions
#define INLINE_INT32X4_SIMD_ARITH_(OP) \
if (native == js::simd_int32x4_##OP) \
return inlineSimdInt32x4BinaryArith(callInfo, native, MSimdBinaryArith::Op_##OP);
#define INLINE_INT32X4_SIMD_ARITH_(OP) \
if (native == js::simd_int32x4_##OP) \
return inlineBinarySimd<MSimdBinaryArith>(callInfo, native, MSimdBinaryArith::Op_##OP, \
SimdTypeDescr::TYPE_INT32);
ARITH_COMMONX4_SIMD_OP(INLINE_INT32X4_SIMD_ARITH_)
#undef INLINE_INT32X4_SIMD_ARITH_
#define INLINE_INT32X4_SIMD_BITWISE_(OP) \
if (native == js::simd_int32x4_##OP) \
return inlineSimdInt32x4BinaryBitwise(callInfo, native, MSimdBinaryBitwise::OP##_);
BITWISE_COMMONX4_SIMD_OP(INLINE_INT32X4_SIMD_BITWISE_)
#undef INLINE_INT32X4_SIMD_BITWISE_
#define INLINE_FLOAT32X4_SIMD_ARITH_(OP) \
if (native == js::simd_float32x4_##OP) \
return inlineBinarySimd<MSimdBinaryArith>(callInfo, native, MSimdBinaryArith::Op_##OP, \
SimdTypeDescr::TYPE_FLOAT32);
ARITH_FLOAT32X4_SIMD_OP(INLINE_FLOAT32X4_SIMD_ARITH_)
#undef INLINE_FLOAT32X4_SIMD_ARITH_
#define INLINE_SIMD_BITWISE_(OP) \
if (native == js::simd_int32x4_##OP) \
return inlineBinarySimd<MSimdBinaryBitwise>(callInfo, native, MSimdBinaryBitwise::OP##_, \
SimdTypeDescr::TYPE_INT32); \
if (native == js::simd_float32x4_##OP) \
return inlineBinarySimd<MSimdBinaryBitwise>(callInfo, native, MSimdBinaryBitwise::OP##_, \
SimdTypeDescr::TYPE_FLOAT32);
BITWISE_COMMONX4_SIMD_OP(INLINE_SIMD_BITWISE_)
#undef INLINE_SIMD_BITWISE_
return InliningStatus_NotInlined;
}
@ -2860,41 +2872,21 @@ IonBuilder::inlineConstructSimdObject(CallInfo &callInfo, SimdTypeDescr *descr)
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineSimdInt32x4BinaryArith(CallInfo &callInfo, JSNative native,
MSimdBinaryArith::Operation op)
static MIRType
SimdTypeDescrToMIRType(SimdTypeDescr::Type type)
{
if (callInfo.argc() != 2)
return InliningStatus_NotInlined;
JSObject *templateObject = inspector->getTemplateObjectForNative(pc, native);
if (!templateObject)
return InliningStatus_NotInlined;
InlineTypedObject *inlineTypedObject = &templateObject->as<InlineTypedObject>();
MOZ_ASSERT(inlineTypedObject->typeDescr().as<SimdTypeDescr>().type() == js::Int32x4::type);
// If the type of any of the arguments is neither a SIMD type, an Object
// type, or a Value, then the applyTypes phase will add a fallible box &
// unbox sequence. This does not matter much as the binary arithmetic
// instruction is supposed to produce a TypeError once it is called.
MSimdBinaryArith *ins = MSimdBinaryArith::New(alloc(), callInfo.getArg(0), callInfo.getArg(1),
op, MIRType_Int32x4);
MSimdBox *obj = MSimdBox::New(alloc(), constraints(), ins, inlineTypedObject,
inlineTypedObject->group()->initialHeap(constraints()));
current->add(ins);
current->add(obj);
current->push(obj);
callInfo.setImplicitlyUsedUnchecked();
return InliningStatus_Inlined;
switch (type) {
case SimdTypeDescr::TYPE_FLOAT32: return MIRType_Float32x4;
case SimdTypeDescr::TYPE_INT32: return MIRType_Int32x4;
case SimdTypeDescr::TYPE_FLOAT64: break;
}
MOZ_CRASH("unexpected SimdTypeDescr");
}
template<typename T>
IonBuilder::InliningStatus
IonBuilder::inlineSimdInt32x4BinaryBitwise(CallInfo &callInfo, JSNative native,
MSimdBinaryBitwise::Operation op)
IonBuilder::inlineBinarySimd(CallInfo &callInfo, JSNative native, typename T::Operation op,
SimdTypeDescr::Type type)
{
if (callInfo.argc() != 2)
return InliningStatus_NotInlined;
@ -2904,14 +2896,14 @@ IonBuilder::inlineSimdInt32x4BinaryBitwise(CallInfo &callInfo, JSNative native,
return InliningStatus_NotInlined;
InlineTypedObject *inlineTypedObject = &templateObject->as<InlineTypedObject>();
MOZ_ASSERT(inlineTypedObject->typeDescr().as<SimdTypeDescr>().type() == js::Int32x4::type);
MOZ_ASSERT(inlineTypedObject->typeDescr().as<SimdTypeDescr>().type() == type);
// If the type of any of the arguments is neither a SIMD type, an Object
// type, or a Value, then the applyTypes phase will add a fallible box &
// unbox sequence. This does not matter much as the binary bitwise
// instruction is supposed to produce a TypeError once it is called.
MSimdBinaryBitwise *ins = MSimdBinaryBitwise::New(alloc(), callInfo.getArg(0), callInfo.getArg(1),
op, MIRType_Int32x4);
T *ins = T::New(alloc(), callInfo.getArg(0), callInfo.getArg(1), op,
SimdTypeDescrToMIRType(type));
MSimdBox *obj = MSimdBox::New(alloc(), constraints(), ins, inlineTypedObject,
inlineTypedObject->group()->initialHeap(constraints()));

View File

@ -2036,6 +2036,15 @@ class MSimdBinaryBitwise
xor_
};
static const char* OperationName(Operation op) {
switch (op) {
case and_: return "and";
case or_: return "or";
case xor_: return "xor";
}
MOZ_CRASH("unexpected operation");
}
private:
Operation operation_;

View File

@ -80,7 +80,7 @@ MSG_DEF(JSMSG_BAD_GENERATOR_YIELD, 1, JSEXN_TYPEERR, "yield from closing gen
MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value")
MSG_DEF(JSMSG_UNEXPECTED_TYPE, 2, JSEXN_TYPEERR, "{0} is {1}")
MSG_DEF(JSMSG_MISSING_FUN_ARG, 2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}")
MSG_DEF(JSMSG_NOT_NONNULL_OBJECT, 0, JSEXN_TYPEERR, "value is not a non-null object")
MSG_DEF(JSMSG_NOT_NONNULL_OBJECT, 1, JSEXN_TYPEERR, "{0} is not a non-null object")
MSG_DEF(JSMSG_INVALID_DESCRIPTOR, 0, JSEXN_TYPEERR, "property descriptors must not specify a value or be writable when a getter or setter has been specified")
MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE, 1, JSEXN_TYPEERR, "{0} is not extensible")
MSG_DEF(JSMSG_CANT_REDEFINE_PROP, 1, JSEXN_TYPEERR, "can't redefine non-configurable property '{0}'")

View File

@ -2145,7 +2145,7 @@ inline int CheckIsStrictPropertyOp(JSStrictPropertyOp op);
#define JS_SELF_HOSTED_GET(name, getterName, flags) \
{name, \
uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_GETTER), \
{ nullptr, JS_CAST_STRING_TO(getterName, const JSJitInfo *) }, \
{ { nullptr, JS_CAST_STRING_TO(getterName, const JSJitInfo *) } }, \
JSNATIVE_WRAPPER(nullptr) }
#define JS_SELF_HOSTED_GETSET(name, getterName, setterName, flags) \
{name, \

View File

@ -495,14 +495,14 @@ JSCompartment::wrap(JSContext *cx, MutableHandle<PropDesc> desc)
}
/*
* This method marks pointers that cross compartment boundaries. It should be
* called only for per-compartment GCs, since full GCs naturally follow pointers
* across compartments.
* This method marks pointers that cross compartment boundaries. It is called in
* per-zone GCs (since full GCs naturally follow pointers across compartments)
* and when compacting to update cross-compartment pointers.
*/
void
JSCompartment::markCrossCompartmentWrappers(JSTracer *trc)
{
MOZ_ASSERT(!zone()->isCollecting());
MOZ_ASSERT(!zone()->isCollecting() || trc->runtime()->isHeapCompacting());
for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
Value v = e.front().value();

View File

@ -1952,7 +1952,7 @@ size_t ArenaHeader::countUsedCells()
}
ArenaHeader *
ArenaList::removeRemainingArenas(ArenaHeader **arenap, const AutoLockGC &lock)
ArenaList::removeRemainingArenas(ArenaHeader **arenap)
{
// This is only ever called to remove arenas that are after the cursor, so
// we don't need to update it.
@ -1966,53 +1966,52 @@ ArenaList::removeRemainingArenas(ArenaHeader **arenap, const AutoLockGC &lock)
return remainingArenas;
}
/*
* Choose which arenas to relocate all cells out of and remove them from the
* arena list. Return the head of a list of arenas to relocate.
*/
ArenaHeader *
ArenaList::pickArenasToRelocate(JSRuntime *runtime)
static bool
ShouldRelocateAllArenas(JSRuntime *runtime)
{
AutoLockGC lock(runtime);
check();
if (isEmpty())
return nullptr;
// In zeal mode and in debug builds on 64 bit architectures, we relocate all
// arenas. The purpose of this is to balance test coverage of object moving
// with test coverage of the arena selection routine below.
bool relocateAll = runtime->gc.zeal() == ZealCompactValue;
// In compacting zeal mode and in debug builds on 64 bit architectures, we
// relocate all arenas. The purpose of this is to balance test coverage of
// object moving with test coverage of the arena selection routine in
// pickArenasToRelocate().
#if defined(DEBUG) && defined(JS_PUNBOX64)
relocateAll = true;
return true;
#else
return runtime->gc.zeal() == ZealCompactValue;
#endif
if (relocateAll) {
ArenaHeader *allArenas = head();
clear();
return allArenas;
}
}
// Otherwise we relocate the greatest number of arenas such that the number
// of used cells in relocated arenas is less than or equal to the number of
// free cells in unrelocated arenas. In other words we only relocate cells
// we can move into existing arenas, and we choose the least full areans to
// relocate.
/*
* Choose which arenas to relocate all cells from. Return an arena cursor that
* can be passed to removeRemainingArenas().
*/
ArenaHeader **
ArenaList::pickArenasToRelocate(size_t &arenaTotalOut, size_t &relocTotalOut)
{
// Relocate the greatest number of arenas such that the number of used cells
// in relocated arenas is less than or equal to the number of free cells in
// unrelocated arenas. In other words we only relocate cells we can move
// into existing arenas, and we choose the least full areans to relocate.
//
// This is made easier by the fact that the arena list has been sorted in
// descending order of number of used cells, so we will always relocate a
// tail of the arena list. All we need to do is find the point at which to
// start relocating.
check();
if (isCursorAtEnd())
return nullptr;
ArenaHeader **arenap = cursorp_; // Next arena to consider
size_t previousFreeCells = 0; // Count of free cells before
size_t followingUsedCells = 0; // Count of used cells after arenap.
size_t arenaCount = 0; // Total number of arenas.
size_t arenaIndex = 0; // Index of the next arena to consider.
// Count of used cells after arenap.
size_t followingUsedCells = 0;
for (ArenaHeader *arena = *arenap; arena; arena = arena->next)
for (ArenaHeader *arena = *cursorp_; arena; arena = arena->next) {
followingUsedCells += arena->countUsedCells();
arenaCount++;
}
mozilla::DebugOnly<size_t> lastFreeCells(0);
size_t cellsPerArena = Arena::thingsPerArena((*arenap)->getThingSize());
@ -2020,7 +2019,8 @@ ArenaList::pickArenasToRelocate(JSRuntime *runtime)
while (*arenap) {
ArenaHeader *arena = *arenap;
if (followingUsedCells <= previousFreeCells)
return removeRemainingArenas(arenap, lock);
break;
size_t freeCells = arena->countFreeCells();
size_t usedCells = cellsPerArena - freeCells;
followingUsedCells -= usedCells;
@ -2030,10 +2030,16 @@ ArenaList::pickArenasToRelocate(JSRuntime *runtime)
#endif
previousFreeCells += freeCells;
arenap = &arena->next;
arenaIndex++;
}
check();
return nullptr;
size_t relocCount = arenaCount - arenaIndex;
MOZ_ASSERT(relocCount < arenaCount);
MOZ_ASSERT((relocCount == 0) == (!*arenap));
arenaTotalOut += arenaCount;
relocTotalOut += relocCount;
return arenap;
}
#ifdef DEBUG
@ -2148,36 +2154,79 @@ ArenaList::relocateArenas(ArenaHeader *toRelocate, ArenaHeader *relocated,
return relocated;
}
ArenaHeader *
ArenaLists::relocateArenas(ArenaHeader *relocatedList, gcstats::Statistics& stats)
// Skip compacting zones unless we can free a certain proportion of their GC
// heap memory.
static const double MIN_ZONE_RECLAIM_PERCENT = 2.0;
static bool ShouldRelocateZone(size_t arenaCount, size_t relocCount, JS::gcreason::Reason reason)
{
if (relocCount == 0)
return false;
if (reason == JS::gcreason::MEM_PRESSURE || reason == JS::gcreason::LAST_DITCH)
return true;
return (relocCount * 100.0) / arenaCount >= MIN_ZONE_RECLAIM_PERCENT;
}
bool
ArenaLists::relocateArenas(ArenaHeader *&relocatedListOut, JS::gcreason::Reason reason,
gcstats::Statistics& stats)
{
// This is only called from the main thread while we are doing a GC, so
// there is no need to lock.
MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
MOZ_ASSERT(runtime_->isHeapCompacting());
MOZ_ASSERT(!runtime_->gc.isBackgroundSweeping());
// Flush all the freeLists back into the arena headers
purge();
checkEmptyFreeLists();
for (size_t i = 0; i < FINALIZE_LIMIT; i++) {
if (CanRelocateAllocKind(AllocKind(i))) {
ArenaList &al = arenaLists[i];
ArenaHeader *toRelocate = al.pickArenasToRelocate(runtime_);
if (toRelocate)
relocatedList = al.relocateArenas(toRelocate, relocatedList, stats);
if (ShouldRelocateAllArenas(runtime_)) {
for (size_t i = 0; i < FINALIZE_LIMIT; i++) {
if (CanRelocateAllocKind(AllocKind(i))) {
ArenaList &al = arenaLists[i];
ArenaHeader *allArenas = al.head();
al.clear();
relocatedListOut = al.relocateArenas(allArenas, relocatedListOut, stats);
}
}
} else {
size_t arenaCount = 0;
size_t relocCount = 0;
ArenaHeader **toRelocate[FINALIZE_LIMIT] = {nullptr};
for (size_t i = 0; i < FINALIZE_LIMIT; i++) {
if (CanRelocateAllocKind(AllocKind(i)))
toRelocate[i] = arenaLists[i].pickArenasToRelocate(arenaCount, relocCount);
}
if (!ShouldRelocateZone(arenaCount, relocCount, reason))
return false;
for (size_t i = 0; i < FINALIZE_LIMIT; i++) {
if (toRelocate[i]) {
ArenaList &al = arenaLists[i];
ArenaHeader *arenas = al.removeRemainingArenas(toRelocate[i]);
relocatedListOut = al.relocateArenas(arenas, relocatedListOut, stats);
}
}
}
/*
* When we allocate new locations for cells, we use
* allocateFromFreeList(). Reset the free list again so that
* AutoCopyFreeListToArenasForGC doesn't complain that the free lists
* are different now.
*/
// When we allocate new locations for cells, we use
// allocateFromFreeList(). Reset the free list again so that
// AutoCopyFreeListToArenasForGC doesn't complain that the free lists are
// different now.
purge();
checkEmptyFreeLists();
return relocatedList;
return true;
}
ArenaHeader *
GCRuntime::relocateArenas()
GCRuntime::relocateArenas(JS::gcreason::Reason reason)
{
gcstats::AutoPhase ap(stats, gcstats::PHASE_COMPACT_MOVE);
@ -2187,9 +2236,9 @@ GCRuntime::relocateArenas()
MOZ_ASSERT(!zone->isPreservingCode());
if (CanRelocateZone(rt, zone)) {
zone->setGCState(Zone::Compact);
jit::StopAllOffThreadCompilations(zone);
relocatedList = zone->arenas.relocateArenas(relocatedList, stats);
if (zone->arenas.relocateArenas(relocatedList, reason, stats))
zone->setGCState(Zone::Compact);
}
}
@ -2244,7 +2293,6 @@ GCRuntime::sweepZoneAfterCompacting(Zone *zone)
for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
c->sweepInnerViews();
c->sweepCrossCompartmentWrappers();
c->sweepBaseShapeTable();
c->sweepInitialShapeTable();
c->objectGroups.sweep(fop);
@ -2389,14 +2437,16 @@ ArenasToUpdate::next(AutoLockHelperThreadState& lock)
initialized = true;
for (; !zone.done(); zone.next()) {
for (kind = 0; kind < FINALIZE_LIMIT; ++kind) {
if (shouldProcessKind(kind)) {
for (arena = zone.get()->arenas.getFirstArena(AllocKind(kind));
arena;
arena = arena->next)
{
return arena;
resumePoint:;
if (zone->isGCCompacting()) {
for (kind = 0; kind < FINALIZE_LIMIT; ++kind) {
if (shouldProcessKind(kind)) {
for (arena = zone.get()->arenas.getFirstArena(AllocKind(kind));
arena;
arena = arena->next)
{
return arena;
resumePoint:;
}
}
}
}
@ -2560,8 +2610,10 @@ GCRuntime::updatePointersToRelocatedCells()
comp->fixupAfterMovingGC();
// Fixup cross compartment wrappers as we assert the existence of wrappers in the map.
for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next())
for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) {
comp->sweepCrossCompartmentWrappers();
comp->markCrossCompartmentWrappers(&trc);
}
// Iterate through all cells that can contain JSObject pointers to update
// them. Since updating each cell is independent we try to parallelize this
@ -2595,7 +2647,7 @@ GCRuntime::updatePointersToRelocatedCells()
WatchpointMap::sweepAll(rt);
Debugger::sweepAll(rt->defaultFreeOp());
for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
if (CanRelocateZone(rt, zone))
if (zone->isGCCompacting())
rt->gc.sweepZoneAfterCompacting(zone);
}
@ -5419,7 +5471,7 @@ GCRuntime::endSweepPhase(bool lastGC)
}
GCRuntime::IncrementalProgress
GCRuntime::compactPhase(bool lastGC)
GCRuntime::compactPhase(bool lastGC, JS::gcreason::Reason reason)
{
gcstats::AutoPhase ap(stats, gcstats::PHASE_COMPACT);
@ -5435,8 +5487,9 @@ GCRuntime::compactPhase(bool lastGC)
MOZ_ASSERT(rt->gc.nursery.isEmpty());
assertBackgroundSweepingFinished();
ArenaHeader *relocatedList = relocateArenas();
updatePointersToRelocatedCells();
ArenaHeader *relocatedList = relocateArenas(reason);
if (relocatedList)
updatePointersToRelocatedCells();
#ifdef DEBUG
for (ArenaHeader *arena = relocatedList; arena; arena = arena->next) {
@ -5470,7 +5523,7 @@ GCRuntime::compactPhase(bool lastGC)
#ifdef DEBUG
CheckHashTablesAfterMovingGC(rt);
for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
if (CanRelocateZone(rt, zone)) {
if (zone->isGCCompacting()) {
MOZ_ASSERT(!zone->isPreservingCode());
zone->arenas.checkEmptyFreeLists();
@ -5877,9 +5930,11 @@ GCRuntime::incrementalCollectSlice(SliceBudget &budget, JS::gcreason::Reason rea
break;
case COMPACT:
if (isCompacting && compactPhase(lastGC) == NotFinished)
if (isCompacting && compactPhase(lastGC, reason) == NotFinished)
break;
finishCollection();
incrementalState = NO_INCREMENTAL;
break;

View File

@ -474,8 +474,8 @@ class ArenaList {
return *this;
}
ArenaHeader *removeRemainingArenas(ArenaHeader **arenap, const AutoLockGC &lock);
ArenaHeader *pickArenasToRelocate(JSRuntime *runtime);
ArenaHeader *removeRemainingArenas(ArenaHeader **arenap);
ArenaHeader **pickArenasToRelocate(size_t &arenaTotalOut, size_t &relocTotalOut);
ArenaHeader *relocateArenas(ArenaHeader *toRelocate, ArenaHeader *relocated,
gcstats::Statistics& stats);
};
@ -804,7 +804,8 @@ class ArenaLists
MOZ_ASSERT(freeLists[kind].isEmpty());
}
ArenaHeader *relocateArenas(ArenaHeader *relocatedList, gcstats::Statistics& stats);
bool relocateArenas(ArenaHeader *&relocatedListOut, JS::gcreason::Reason reason,
gcstats::Statistics& stats);
void queueForegroundObjectsForSweep(FreeOp *fop);
void queueForegroundThingsForSweep(FreeOp *fop);

View File

@ -92,7 +92,11 @@ JSObject *
js::NonNullObject(JSContext *cx, const Value &v)
{
if (v.isPrimitive()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
RootedValue value(cx, v);
char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, value, NullPtr());
if (!bytes)
return nullptr;
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes);
return nullptr;
}
return &v.toObject();
@ -280,7 +284,10 @@ PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors)
/* 8.10.5 step 1 */
if (v.isPrimitive()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NullPtr());
if (!bytes)
return false;
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes);
return false;
}
RootedObject desc(cx, &v.toObject());

View File

@ -1620,6 +1620,8 @@ ExpressionDecompiler::decompilePC(jsbytecode *pc)
return false;
return write(str);
}
case JSOP_VOID:
return write("void ") && decompilePCForStackOperand(pc, -1);
default:
break;
}

View File

@ -384,7 +384,10 @@ WeakMap_set_impl(JSContext *cx, CallArgs args)
MOZ_ASSERT(IsWeakMap(args.thisv()));
if (!args.get(0).isObject()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), NullPtr());
if (!bytes)
return false;
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes);
return false;
}
@ -565,7 +568,10 @@ WeakMap_construct(JSContext *cx, unsigned argc, Value *vp)
// Steps 12k-l.
if (isOriginalAdder) {
if (keyVal.isPrimitive()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, keyVal, NullPtr());
if (!bytes)
return false;
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes);
return false;
}

View File

@ -210,7 +210,10 @@ static PerfMeasurement*
GetPM(JSContext* cx, JS::HandleValue value, const char* fname)
{
if (!value.isObject()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, 0, JSMSG_NOT_NONNULL_OBJECT);
char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, value, NullPtr());
if (!bytes)
return nullptr;
JS_ReportErrorNumber(cx, js_GetErrorMessage, 0, JSMSG_NOT_NONNULL_OBJECT, bytes);
return nullptr;
}
RootedObject obj(cx, &value.toObject());

View File

@ -46,16 +46,19 @@ function expectSyntaxError(code)
expectSyntaxError("function f1() {} 'use strict'; function f2() {}");
expectSyntaxError("function f3() { var x; 'use strict'; }");
expectSyntaxError("function f4() {} 'use asm'; function f5() {}");
if (isAsmJSCompilationAvailable())
expectSyntaxError("function f4() {} 'use asm'; function f5() {}");
expectSyntaxError("function f6() { var x; 'use strict'; }");
expectSyntaxError("'use asm'; function f7() {}");
if (isAsmJSCompilationAvailable())
expectSyntaxError("'use asm'; function f7() {}");
// No errors expected -- useless non-directives, but not contrary to used
// semantics.
evaluateNoRval("'use strict'; function f8() {} 'use strict'; function f9() {}");
evaluateNoRval("'use strict'; function f10() { var z; 'use strict' }");
evaluateNoRval("function f11() { 'use asm'; return {}; }");
if (isAsmJSCompilationAvailable())
evaluateNoRval("function f11() { 'use asm'; return {}; }");
/******************************************************************************/

View File

@ -7,14 +7,16 @@ assertEq(RegExp.prototype.flags, "");
assertEq(/foo/iymg.flags, "gimy");
assertEq(RegExp("").flags, "");
assertEq(RegExp("", "mygi").flags, "gimy");
// TODO: Uncomment lines 12, 16, 19 and remove lines 11, 15, 18 when bug 1135377 is fixed.
assertThrowsInstanceOf(() => RegExp("", "mygui").flags, SyntaxError);
// When the /u flag is supported, uncomment the line below and remove the line above
// assertEq(RegExp("", "mygui").flags, "gimuy");
assertEq(genericFlags({}), "");
assertEq(genericFlags({ignoreCase: true}), "i");
assertEq(genericFlags({sticky:1, unicode:1, global: 0}), "uy");
assertEq(genericFlags({sticky:1, unicode:1, global: 0}), "y");
// assertEq(genericFlags({sticky:1, unicode:1, global: 0}), "uy");
assertEq(genericFlags({__proto__: {multiline: true}}), "m");
assertEq(genericFlags(new Proxy({}, {get(){return true}})), "gimuy");
assertEq(genericFlags(new Proxy({}, {get(){return true}})), "gimy");
// assertEq(genericFlags(new Proxy({}, {get(){return true}})), "gimuy");
assertThrowsInstanceOf(() => genericFlags(), TypeError);
assertThrowsInstanceOf(() => genericFlags(1), TypeError);

View File

@ -123,7 +123,7 @@ GetOrCreateFunctionScript(JSContext *cx, HandleFunction fun)
bool
js::ReportObjectRequired(JSContext *cx)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, "value");
return false;
}

View File

@ -79,7 +79,7 @@ DebuggerMemory::checkThis(JSContext *cx, CallArgs &args, const char *fnName)
const Value &thisValue = args.thisv();
if (!thisValue.isObject()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, InformalValueTypeName(thisValue));
return nullptr;
}

View File

@ -34,19 +34,6 @@ class ErrorObject : public NativeObject
friend JSObject *
::js_InitExceptionClasses(JSContext *cx, JS::HandleObject global);
/* For access to assignInitialShape. */
friend bool
EmptyShape::ensureInitialCustomShape<ErrorObject>(ExclusiveContext *cx,
Handle<ErrorObject*> obj);
/*
* Assign the initial error shape to the empty object. (This shape does
* *not* include .message, which must be added separately if needed; see
* ErrorObject::init.)
*/
static Shape *
assignInitialShape(ExclusiveContext *cx, Handle<ErrorObject*> obj);
static bool
init(JSContext *cx, Handle<ErrorObject*> obj, JSExnType type,
ScopedJSFreePtr<JSErrorReport> *errorReport, HandleString fileName, HandleString stack,
@ -85,6 +72,14 @@ class ErrorObject : public NativeObject
uint32_t lineNumber, uint32_t columnNumber, ScopedJSFreePtr<JSErrorReport> *report,
HandleString message);
/*
* Assign the initial error shape to the empty object. (This shape does
* *not* include .message, which must be added separately if needed; see
* ErrorObject::init.)
*/
static Shape *
assignInitialShape(ExclusiveContext *cx, Handle<ErrorObject*> obj);
JSExnType type() const {
return JSExnType(getReservedSlot(EXNTYPE_SLOT).toInt32());
}

View File

@ -289,9 +289,14 @@ class ObjectGroup : public gc::TenuredCell
return maybeUnboxedLayoutDontCheckGeneration();
}
UnboxedLayout &unboxedLayout() {
UnboxedLayout &unboxedLayoutDontCheckGeneration() const {
MOZ_ASSERT(addendumKind() == Addendum_UnboxedLayout);
return *maybeUnboxedLayout();
return *maybeUnboxedLayoutDontCheckGeneration();
}
UnboxedLayout &unboxedLayout() {
maybeSweep(nullptr);
return unboxedLayoutDontCheckGeneration();
}
void setUnboxedLayout(UnboxedLayout *layout) {

View File

@ -376,6 +376,14 @@ class RegExpObject : public NativeObject
createNoStatics(ExclusiveContext *cx, HandleAtom atom, RegExpFlag flags,
frontend::TokenStream *ts, LifoAlloc &alloc);
/*
* Compute the initial shape to associate with fresh RegExp objects,
* encoding their initial properties. Return the shape after
* changing |obj|'s last property to it.
*/
static Shape *
assignInitialShape(ExclusiveContext *cx, Handle<RegExpObject*> obj);
/* Accessors. */
static unsigned lastIndexSlot() { return LAST_INDEX_SLOT; }
@ -446,19 +454,6 @@ class RegExpObject : public NativeObject
private:
friend class RegExpObjectBuilder;
/* For access to assignInitialShape. */
friend bool
EmptyShape::ensureInitialCustomShape<RegExpObject>(ExclusiveContext *cx,
Handle<RegExpObject*> obj);
/*
* Compute the initial shape to associate with fresh RegExp objects,
* encoding their initial properties. Return the shape after
* changing |obj|'s last property to it.
*/
static Shape *
assignInitialShape(ExclusiveContext *cx, Handle<RegExpObject*> obj);
bool init(ExclusiveContext *cx, HandleAtom source, RegExpFlag flags);
/*

View File

@ -341,7 +341,7 @@ SavedFrame::checkThis(JSContext *cx, CallArgs &args, const char *fnName,
const Value &thisValue = args.thisv();
if (!thisValue.isObject()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, InformalValueTypeName(thisValue));
return false;
}

View File

@ -31,6 +31,14 @@ class StringObject : public NativeObject
static inline StringObject *create(JSContext *cx, HandleString str,
NewObjectKind newKind = GenericObject);
/*
* Compute the initial shape to associate with fresh String objects, which
* encodes the initial length property. Return the shape after changing
* |obj|'s last property to it.
*/
static Shape *
assignInitialShape(ExclusiveContext *cx, Handle<StringObject*> obj);
JSString *unbox() const {
return getFixedSlot(PRIMITIVE_VALUE_SLOT).toString();
}
@ -58,19 +66,6 @@ class StringObject : public NativeObject
/* For access to init, as String.prototype is special. */
friend JSObject *
::js_InitStringClass(JSContext *cx, js::HandleObject global);
/* For access to assignInitialShape. */
friend bool
EmptyShape::ensureInitialCustomShape<StringObject>(ExclusiveContext *cx,
Handle<StringObject*> obj);
/*
* Compute the initial shape to associate with fresh String objects, which
* encodes the initial length property. Return the shape after changing
* |obj|'s last property to it.
*/
static Shape *
assignInitialShape(ExclusiveContext *cx, Handle<StringObject*> obj);
};
} // namespace js

View File

@ -2268,8 +2268,8 @@ TemporaryTypeSet::propertyNeedsBarrier(CompilerConstraintList *constraints, jsid
return false;
}
static inline bool
ClassCanHaveExtraProperties(const Class *clasp)
bool
js::ClassCanHaveExtraProperties(const Class *clasp)
{
return clasp->resolve
|| clasp->ops.lookupProperty

View File

@ -909,6 +909,9 @@ class TypeNewScript
/* Is this a reasonable PC to be doing inlining on? */
inline bool isInlinableCall(jsbytecode *pc);
bool
ClassCanHaveExtraProperties(const Class *clasp);
/*
* Whether Array.prototype, or an object on its proto chain, has an
* indexed property.

View File

@ -87,7 +87,8 @@ UnboxedPlainObject::setValue(JSContext *cx, const UnboxedLayout::Property &prope
case JSVAL_TYPE_STRING:
if (v.isString()) {
*reinterpret_cast<HeapPtrString*>(p) = v.toString();
MOZ_ASSERT(!IsInsideNursery(v.toString()));
*reinterpret_cast<PreBarrieredString*>(p) = v.toString();
return true;
}
return false;
@ -99,7 +100,14 @@ UnboxedPlainObject::setValue(JSContext *cx, const UnboxedLayout::Property &prope
// created.
AddTypePropertyId(cx, this, NameToId(property.name), v);
*reinterpret_cast<HeapPtrObject*>(p) = v.toObjectOrNull();
// Manually trigger post barriers on the whole object. If we treat
// the pointer as a HeapPtrObject we will get confused later if the
// object is converted to its native representation.
JSObject *obj = v.toObjectOrNull();
if (IsInsideNursery(v.toObjectOrNull()) && !IsInsideNursery(this))
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(this);
*reinterpret_cast<PreBarrieredObject*>(p) = obj;
return true;
}
return false;
@ -138,7 +146,7 @@ UnboxedPlainObject::getValue(const UnboxedLayout::Property &property)
void
UnboxedPlainObject::trace(JSTracer *trc, JSObject *obj)
{
const UnboxedLayout &layout = obj->as<UnboxedPlainObject>().layout();
const UnboxedLayout &layout = obj->as<UnboxedPlainObject>().layoutDontCheckGeneration();
const int32_t *list = layout.traceList();
if (!list)
return;

View File

@ -176,6 +176,10 @@ class UnboxedPlainObject : public JSObject
return group()->unboxedLayout();
}
const UnboxedLayout &layoutDontCheckGeneration() const {
return group()->unboxedLayoutDontCheckGeneration();
}
uint8_t *data() {
return &data_[0];
}

View File

@ -396,6 +396,23 @@ bool OpenSlesInput::EnqueueAllBuffers() {
return true;
}
void OpenSlesInput::SetupVoiceMode() {
SLAndroidConfigurationItf configItf;
SLresult res = (*sles_recorder_)->GetInterface(sles_recorder_, SL_IID_ANDROIDCONFIGURATION_,
(void*)&configItf);
WEBRTC_TRACE(kTraceError, kTraceAudioDevice, id_, "OpenSL GetInterface: %d", res);
if (res == SL_RESULT_SUCCESS) {
SLuint32 voiceMode = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
SLuint32 voiceSize = sizeof(voiceMode);
res = (*configItf)->SetConfiguration(configItf,
SL_ANDROID_KEY_RECORDING_PRESET,
&voiceMode, voiceSize);
WEBRTC_TRACE(kTraceError, kTraceAudioDevice, id_, "OpenSL Set Voice mode res: %d", res);
}
}
#if defined(WEBRTC_GONK) && defined(WEBRTC_HARDWARE_AEC_NS)
bool OpenSlesInput::CheckPlatformAEC() {
effect_descriptor_t fxDesc;
@ -519,16 +536,7 @@ bool OpenSlesInput::CreateAudioRecorder() {
&recorder_config),
false);
// Set audio recorder configuration to
// SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION which ensures that we
// use the main microphone tuned for audio communications.
SLuint32 stream_type = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
OPENSL_RETURN_ON_FAILURE(
(*recorder_config)->SetConfiguration(recorder_config,
SL_ANDROID_KEY_RECORDING_PRESET,
&stream_type,
sizeof(SLint32)),
false);
SetupVoiceMode();
// Realize the recorder in synchronous mode.
OPENSL_RETURN_ON_FAILURE((*sles_recorder_)->Realize(sles_recorder_,

View File

@ -147,9 +147,9 @@ class OpenSlesInput {
// etc, so it should be called when starting recording.
bool CreateAudioRecorder();
void DestroyAudioRecorder();
void SetupVoiceMode();
#if defined(WEBRTC_GONK) && defined(WEBRTC_HARDWARE_AEC_NS)
void SetupAECAndNS();
void SetupVoiceMode();
bool CheckPlatformAEC();
#endif

View File

@ -607,6 +607,11 @@ pref("gfx.color_management.enablev4", false);
pref("gfx.downloadable_fonts.enabled", true);
pref("gfx.downloadable_fonts.fallback_delay", 3000);
// disable downloadable font cache so that behavior is consistently
// the uncached load behavior across pages (useful for testing reflow problems)
pref("gfx.downloadable_fonts.disable_cache", false);
#ifdef RELEASE_BUILD
pref("gfx.downloadable_fonts.woff2.enabled", false);
#else

View File

@ -412,14 +412,11 @@ NS_IMETHODIMP CacheEntry::OnFileReady(nsresult aResult, bool aIsNew)
if (NS_SUCCEEDED(aResult)) {
if (aIsNew) {
mozilla::Telemetry::AccumulateTimeDelta(
mozilla::Telemetry::NETWORK_CACHE_V2_MISS_TIME_MS,
mLoadStart);
}
else {
mozilla::Telemetry::AccumulateTimeDelta(
mozilla::Telemetry::NETWORK_CACHE_V2_HIT_TIME_MS,
mLoadStart);
CacheFileUtils::DetailedCacheHitTelemetry::AddRecord(
CacheFileUtils::DetailedCacheHitTelemetry::MISS, mLoadStart);
} else {
CacheFileUtils::DetailedCacheHitTelemetry::AddRecord(
CacheFileUtils::DetailedCacheHitTelemetry::HIT, mLoadStart);
}
}

View File

@ -3576,6 +3576,45 @@ CacheFileIOManager::CreateCacheTree()
StartRemovingTrash();
if (!CacheObserver::CacheFSReported()) {
uint32_t fsType = 4; // Other OS
#ifdef XP_WIN
nsAutoString target;
nsresult rv = mCacheDirectory->GetTarget(target);
if (NS_FAILED(rv)) {
return NS_OK;
}
wchar_t volume_path[MAX_PATH + 1] = { 0 };
if (!::GetVolumePathNameW(target.get(),
volume_path,
mozilla::ArrayLength(volume_path))) {
return NS_OK;
}
wchar_t fsName[6] = { 0 };
if (!::GetVolumeInformationW(volume_path, nullptr, 0, nullptr, nullptr,
nullptr, fsName,
mozilla::ArrayLength(fsName))) {
return NS_OK;
}
if (wcscmp(fsName, L"NTFS") == 0) {
fsType = 0;
} else if (wcscmp(fsName, L"FAT32") == 0) {
fsType = 1;
} else if (wcscmp(fsName, L"FAT") == 0) {
fsType = 2;
} else {
fsType = 3;
}
#endif
Telemetry::Accumulate(Telemetry::NETWORK_CACHE_FS_TYPE, fsType);
CacheObserver::SetCacheFSReported();
}
return NS_OK;
}
@ -3619,6 +3658,18 @@ CacheFileIOManager::OpenNSPRHandle(CacheFileHandle *aHandle, bool aCreate)
LOG(("CacheFileIOManager::OpenNSPRHandle() - Successfully evicted entry"
" with hash %08x%08x%08x%08x%08x. %s to create the new file.",
LOGSHA1(&hash), NS_SUCCEEDED(rv) ? "Succeeded" : "Failed"));
// Report the full size only once per session
static bool sSizeReported = false;
if (!sSizeReported) {
uint32_t cacheUsage;
if (NS_SUCCEEDED(CacheIndex::GetCacheSize(&cacheUsage))) {
cacheUsage >>= 10;
Telemetry::Accumulate(Telemetry::NETWORK_CACHE_SIZE_FULL_FAT,
cacheUsage);
sSizeReported = true;
}
}
} else {
LOG(("CacheFileIOManager::OpenNSPRHandle() - Couldn't evict an existing"
" entry."));

View File

@ -64,6 +64,7 @@ CacheFileMetadata::CacheFileMetadata(CacheFileHandle *aHandle, const nsACString
CacheFileMetadata::CacheFileMetadata(bool aMemoryOnly, const nsACString &aKey)
: CacheMemoryConsumer(aMemoryOnly ? MEMORY_ONLY : NORMAL)
, mHandle(nullptr)
, mFirstRead(true)
, mHashArray(nullptr)
, mHashArraySize(0)
, mHashCount(0)
@ -95,6 +96,7 @@ CacheFileMetadata::CacheFileMetadata(bool aMemoryOnly, const nsACString &aKey)
CacheFileMetadata::CacheFileMetadata()
: CacheMemoryConsumer(DONT_REPORT /* This is a helper class */)
, mHandle(nullptr)
, mFirstRead(true)
, mHashArray(nullptr)
, mHashArraySize(0)
, mHashCount(0)
@ -206,6 +208,7 @@ CacheFileMetadata::ReadMetadata(CacheFileMetadataListener *aListener)
LOG(("CacheFileMetadata::ReadMetadata() - Reading metadata from disk, trying "
"offset=%lld, filesize=%lld [this=%p]", offset, size, this));
mReadStart = mozilla::TimeStamp::Now();
mListener = aListener;
rv = CacheFileIOManager::Read(mHandle, offset, mBuf, mBufSize, this);
if (NS_FAILED(rv)) {
@ -629,6 +632,16 @@ CacheFileMetadata::OnDataRead(CacheFileHandle *aHandle, char *aBuf,
return NS_OK;
}
if (mFirstRead) {
Telemetry::AccumulateTimeDelta(
Telemetry::NETWORK_CACHE_METADATA_FIRST_READ_TIME_MS, mReadStart);
Telemetry::Accumulate(
Telemetry::NETWORK_CACHE_METADATA_FIRST_READ_SIZE, mBufSize);
} else {
Telemetry::AccumulateTimeDelta(
Telemetry::NETWORK_CACHE_METADATA_SECOND_READ_TIME_MS, mReadStart);
}
// check whether we have read all necessary data
uint32_t realOffset = NetworkEndian::readUint32(mBuf + mBufSize -
sizeof(uint32_t));
@ -663,6 +676,8 @@ CacheFileMetadata::OnDataRead(CacheFileHandle *aHandle, char *aBuf,
LOG(("CacheFileMetadata::OnDataRead() - We need to read %d more bytes to "
"have full metadata. [this=%p]", missing, this));
mFirstRead = false;
mReadStart = mozilla::TimeStamp::Now();
rv = CacheFileIOManager::Read(mHandle, realOffset, mBuf, missing, this);
if (NS_FAILED(rv)) {
LOG(("CacheFileMetadata::OnDataRead() - CacheFileIOManager::Read() "
@ -680,6 +695,9 @@ CacheFileMetadata::OnDataRead(CacheFileHandle *aHandle, char *aBuf,
return NS_OK;
}
Telemetry::Accumulate(Telemetry::NETWORK_CACHE_METADATA_SIZE,
size - realOffset);
// We have all data according to offset information at the end of the entry.
// Try to parse it.
rv = ParseMetadata(realOffset, realOffset - usedOffset, true);

View File

@ -176,6 +176,8 @@ private:
nsRefPtr<CacheFileHandle> mHandle;
nsCString mKey;
bool mFirstRead;
mozilla::TimeStamp mReadStart;
CacheHash::Hash16_t *mHashArray;
uint32_t mHashArraySize;
uint32_t mHashCount;

View File

@ -424,6 +424,116 @@ ValidityMap::operator[](uint32_t aIdx)
return mMap.ElementAt(aIdx);
}
StaticMutex DetailedCacheHitTelemetry::sLock;
uint32_t DetailedCacheHitTelemetry::sRecordCnt = 0;
DetailedCacheHitTelemetry::HitRate DetailedCacheHitTelemetry::sHRStats[kNumOfRanges];
DetailedCacheHitTelemetry::HitRate::HitRate()
{
Reset();
}
void
DetailedCacheHitTelemetry::HitRate::AddRecord(ERecType aType)
{
if (aType == HIT) {
++mHitCnt;
} else {
++mMissCnt;
}
}
uint32_t
DetailedCacheHitTelemetry::HitRate::GetHitRateBucket(uint32_t aNumOfBuckets) const
{
uint32_t bucketIdx = (aNumOfBuckets * mHitCnt) / (mHitCnt + mMissCnt);
if (bucketIdx == aNumOfBuckets) { // make sure 100% falls into the last bucket
--bucketIdx;
}
return bucketIdx;
}
uint32_t
DetailedCacheHitTelemetry::HitRate::Count()
{
return mHitCnt + mMissCnt;
}
void
DetailedCacheHitTelemetry::HitRate::Reset()
{
mHitCnt = 0;
mMissCnt = 0;
}
// static
void
DetailedCacheHitTelemetry::AddRecord(ERecType aType, TimeStamp aLoadStart)
{
bool isUpToDate = false;
CacheIndex::IsUpToDate(&isUpToDate);
if (!isUpToDate) {
// Ignore the record when the entry file count might be incorrect
return;
}
uint32_t entryCount;
nsresult rv = CacheIndex::GetEntryFileCount(&entryCount);
if (NS_FAILED(rv)) {
return;
}
uint32_t rangeIdx = entryCount / kRangeSize;
if (rangeIdx >= kNumOfRanges) { // The last range has no upper limit.
rangeIdx = kNumOfRanges - 1;
}
uint32_t hitMissValue = 2 * rangeIdx; // 2 values per range
if (aType == MISS) { // The order is HIT, MISS
++hitMissValue;
}
StaticMutexAutoLock lock(sLock);
if (aType == MISS) {
mozilla::Telemetry::AccumulateTimeDelta(
mozilla::Telemetry::NETWORK_CACHE_V2_MISS_TIME_MS,
aLoadStart);
} else {
mozilla::Telemetry::AccumulateTimeDelta(
mozilla::Telemetry::NETWORK_CACHE_V2_HIT_TIME_MS,
aLoadStart);
}
Telemetry::Accumulate(Telemetry::NETWORK_CACHE_HIT_MISS_STAT_PER_CACHE_SIZE,
hitMissValue);
sHRStats[rangeIdx].AddRecord(aType);
++sRecordCnt;
if (sRecordCnt < kTotalSamplesReportLimit) {
return;
}
sRecordCnt = 0;
for (uint32_t i = 0; i < kNumOfRanges; ++i) {
if (sHRStats[i].Count() >= kHitRateSamplesReportLimit) {
// The telemetry enums are grouped by buckets as follows:
// Telemetry value : 0,1,2,3, ... ,19,20,21,22, ... ,398,399
// Hit rate bucket : 0,0,0,0, ... , 0, 1, 1, 1, ... , 19, 19
// Cache size range: 0,1,2,3, ... ,19, 0, 1, 2, ... , 18, 19
uint32_t bucketOffset = sHRStats[i].GetHitRateBucket(kHitRateBuckets) *
kNumOfRanges;
Telemetry::Accumulate(Telemetry::NETWORK_CACHE_HIT_RATE_PER_CACHE_SIZE,
bucketOffset + i);
sHRStats[i].Reset();
}
}
}
} // CacheFileUtils
} // net
} // mozilla

View File

@ -9,6 +9,8 @@
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsTArray.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/TimeStamp.h"
class nsILoadContextInfo;
class nsACString;
@ -86,6 +88,64 @@ private:
nsTArray<ValidityPair> mMap;
};
class DetailedCacheHitTelemetry {
public:
enum ERecType {
HIT = 0,
MISS = 1
};
static void AddRecord(ERecType aType, TimeStamp aLoadStart);
private:
class HitRate {
public:
HitRate();
void AddRecord(ERecType aType);
// Returns the bucket index that the current hit rate falls into according
// to the given aNumOfBuckets.
uint32_t GetHitRateBucket(uint32_t aNumOfBuckets) const;
uint32_t Count();
void Reset();
private:
uint32_t mHitCnt;
uint32_t mMissCnt;
};
// Group the hits and misses statistics by cache files count ranges (0-5000,
// 5001-10000, ... , 95001- )
static const uint32_t kRangeSize = 5000;
static const uint32_t kNumOfRanges = 20;
// Use the same ranges to report an average hit rate. Report the hit rates
// (and reset the counters) every kTotalSamplesReportLimit samples.
static const uint32_t kTotalSamplesReportLimit = 1000;
// Report hit rate for a given cache size range only if it contains
// kHitRateSamplesReportLimit or more samples. This limit should avoid
// reporting a biased statistics.
static const uint32_t kHitRateSamplesReportLimit = 500;
// All hit rates are accumulated in a single telemetry probe, so to use
// a sane number of enumerated values the hit rate is divided into buckets
// instead of using a percent value. This constant defines number of buckets
// that we divide the hit rates into. I.e. we'll report ranges 0%-5%, 5%-10%,
// 10-%15%, ...
static const uint32_t kHitRateBuckets = 20;
// Protects sRecordCnt, sHitStats and Telemetry::Accumulated() calls.
static StaticMutex sLock;
// Counter of samples that is compared against kTotalSamplesReportLimit.
static uint32_t sRecordCnt;
// Hit rate statistics for every cache size range.
static HitRate sHRStats[kNumOfRanges];
};
} // CacheFileUtils
} // net
} // mozilla

View File

@ -1309,6 +1309,29 @@ CacheIndex::GetCacheSize(uint32_t *_retval)
return NS_OK;
}
// static
nsresult
CacheIndex::GetEntryFileCount(uint32_t *_retval)
{
LOG(("CacheIndex::GetEntryFileCount()"));
nsRefPtr<CacheIndex> index = gInstance;
if (!index) {
return NS_ERROR_NOT_INITIALIZED;
}
CacheIndexAutoLock lock(index);
if (!index->IsIndexUsable()) {
return NS_ERROR_NOT_AVAILABLE;
}
*_retval = index->mIndexStats.ActiveEntriesCount();
LOG(("CacheIndex::GetEntryFileCount() - returning %u", *_retval));
return NS_OK;
}
// static
nsresult
CacheIndex::GetCacheStats(nsILoadContextInfo *aInfo, uint32_t *aSize, uint32_t *aCount)

View File

@ -651,6 +651,9 @@ public:
// Returns cache size in kB.
static nsresult GetCacheSize(uint32_t *_retval);
// Returns number of entry files in the cache
static nsresult GetEntryFileCount(uint32_t *_retval);
// Synchronously returns the disk occupation and number of entries per-context.
// Callable on any thread.
static nsresult GetCacheStats(nsILoadContextInfo *aInfo, uint32_t *aSize, uint32_t *aCount);

View File

@ -86,6 +86,9 @@ bool CacheObserver::sSanitizeOnShutdown = kDefaultSanitizeOnShutdown;
static bool kDefaultClearCacheOnShutdown = false;
bool CacheObserver::sClearCacheOnShutdown = kDefaultClearCacheOnShutdown;
static bool kDefaultCacheFSReported = false;
bool CacheObserver::sCacheFSReported = kDefaultCacheFSReported;
NS_IMPL_ISUPPORTS(CacheObserver,
nsIObserver,
nsISupportsWeakReference)
@ -317,6 +320,32 @@ CacheObserver::StoreDiskCacheCapacity()
sDiskCacheCapacity);
}
// static
void
CacheObserver::SetCacheFSReported()
{
sCacheFSReported = true;
if (!sSelf) {
return;
}
if (NS_IsMainThread()) {
sSelf->StoreCacheFSReported();
} else {
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(sSelf, &CacheObserver::StoreCacheFSReported);
NS_DispatchToMainThread(event);
}
}
void
CacheObserver::StoreCacheFSReported()
{
mozilla::Preferences::SetInt("browser.cache.disk.filesystem_reported",
sCacheFSReported);
}
// static
void CacheObserver::ParentDirOverride(nsIFile** aDir)
{

View File

@ -61,6 +61,9 @@ class CacheObserver : public nsIObserver
{ return sHalfLifeExperiment; }
static bool const ClearCacheOnShutdown()
{ return sSanitizeOnShutdown && sClearCacheOnShutdown; }
static bool const CacheFSReported()
{ return sCacheFSReported; }
static void SetCacheFSReported();
static void ParentDirOverride(nsIFile ** aDir);
static bool const EntryIsTooBig(int64_t aSize, bool aUsingDisk);
@ -69,6 +72,7 @@ private:
static CacheObserver* sSelf;
void StoreDiskCacheCapacity();
void StoreCacheFSReported();
void AttachToPreferences();
static uint32_t sUseNewCache;
@ -91,6 +95,7 @@ private:
static int32_t sHalfLifeExperiment;
static bool sSanitizeOnShutdown;
static bool sClearCacheOnShutdown;
static bool sCacheFSReported;
// Non static properties, accessible via sSelf
nsCOMPtr<nsIFile> mCacheParentDirectoryOverride;

View File

@ -492,7 +492,7 @@ class CCacheStats(object):
DIRECTORY_DESCRIPTION = "cache directory"
PRIMARY_CONFIG_DESCRIPTION = "primary config"
SECONDARY_CONFIG_DESCRIPTION = "secondary config (readonly)"
ABSOLUTE_KEYS = {'cache_max_size'}
ABSOLUTE_KEYS = {'cache_files', 'cache_size', 'cache_max_size'}
FORMAT_KEYS = {'cache_size', 'cache_max_size'}
GiB = 1024 ** 3

View File

@ -80,6 +80,50 @@ class TestCcacheStats(unittest.TestCase):
max cache size 8.6 GB
"""
STAT4 = """
cache directory /Users/tlin/.ccache
primary config /Users/tlin/.ccache/ccache.conf
secondary config (readonly) /usr/local/Cellar/ccache/3.2.1/etc/ccache.conf
cache hit (direct) 21039
cache hit (preprocessed) 2315
cache miss 39370
called for link 3651
called for preprocessing 6693
compile failed 723
ccache internal error 1
preprocessor error 588
bad compiler arguments 128
unsupported source language 99
autoconf compile/link 3669
unsupported compiler option 187
no input file 1711
files in cache 18313
cache size 6.3 GB
max cache size 6.0 GB
"""
STAT5 = """
cache directory /Users/tlin/.ccache
primary config /Users/tlin/.ccache/ccache.conf
secondary config (readonly) /usr/local/Cellar/ccache/3.2.1/etc/ccache.conf
cache hit (direct) 21039
cache hit (preprocessed) 2315
cache miss 39372
called for link 3653
called for preprocessing 6693
compile failed 723
ccache internal error 1
preprocessor error 588
bad compiler arguments 128
unsupported source language 99
autoconf compile/link 3669
unsupported compiler option 187
no input file 1711
files in cache 17411
cache size 6.0 GB
max cache size 6.0 GB
"""
def test_parse_garbage_stats_message(self):
self.assertRaises(ValueError, CCacheStats, self.STAT_GARBAGE)
@ -116,6 +160,13 @@ class TestCcacheStats(unittest.TestCase):
self.assertTrue(stat3)
self.assertTrue(stats_diff)
def test_cache_size_shrinking(self):
stat4 = CCacheStats(self.STAT4)
stat5 = CCacheStats(self.STAT5)
stats_diff = stat5 - stat4
self.assertTrue(stat4)
self.assertTrue(stat5)
self.assertTrue(stats_diff)
if __name__ == '__main__':
main()

View File

@ -9,6 +9,7 @@ if CONFIG['CLANG_CXX']:
'-Wno-missing-prototypes',
'-Wno-missing-variable-declarations',
'-Wno-padded',
'-Wno-reserved-id-macro', # NSPR and NSS use reserved IDs in their include guards.
'-Wno-shadow', # XXX: Clang's rules are too strict for constructors.
'-Wno-weak-vtables', # We rely on the linker to merge the duplicate vtables.
]

View File

@ -50,6 +50,7 @@ user_pref("browser.panorama.experienced_first_run", true); // Assume experienced
user_pref("dom.w3c_touch_events.enabled", 1);
user_pref("dom.undo_manager.enabled", true);
user_pref("dom.webcomponents.enabled", true);
user_pref("dom.htmlimports.enabled", true);
user_pref("dom.animations-api.core.enabled", true);
// Set a future policy version to avoid the telemetry prompt.
user_pref("toolkit.telemetry.prompted", 999);

View File

@ -6589,6 +6589,61 @@
"n_values": "7",
"description": "Final status of the CacheFileInputStream (0=ok, 1=other error, 2=out of memory, 3=disk full, 4=file corrupted, 5=file not found, 6=binding aborted)"
},
"NETWORK_CACHE_FS_TYPE": {
"expires_in_version": "42",
"kind": "enumerated",
"n_values": "5",
"description": "Type of FS that the cache is stored on (0=NTFS (Win), 1=FAT32 (Win), 2=FAT (Win), 3=other FS (Win), 4=other OS)"
},
"NETWORK_CACHE_SIZE_FULL_FAT": {
"expires_in_version": "42",
"kind": "linear",
"high": "500",
"n_buckets": 50,
"description": "Size (in MB) of a cache that reached a file count limit"
},
"NETWORK_CACHE_HIT_MISS_STAT_PER_CACHE_SIZE": {
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 40,
"description": "Hit/Miss count split by cache size in file count (0=Hit 0-5000, 1=Miss 0-5000, 2=Hit 5001-10000, ...)"
},
"NETWORK_CACHE_HIT_RATE_PER_CACHE_SIZE": {
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 400,
"description": "Hit rate for a specific cache size in file count. The hit rate is split into 20 buckets, the lower limit of the range in percents is 5*n/20. The cache size is divided into 20 ranges of length 5000, the lower limit of the range is 5000*(n%20)"
},
"NETWORK_CACHE_METADATA_FIRST_READ_TIME_MS": {
"expires_in_version": "never",
"kind": "exponential",
"high": "10000",
"n_buckets": 50,
"extended_statistics_ok": true,
"description": "Time spent to read the first part of the metadata from the cache entry file."
},
"NETWORK_CACHE_METADATA_SECOND_READ_TIME_MS": {
"expires_in_version": "never",
"kind": "exponential",
"high": "10000",
"n_buckets": 50,
"extended_statistics_ok": true,
"description": "Time spent to read the missing part of the metadata from the cache entry file."
},
"NETWORK_CACHE_METADATA_FIRST_READ_SIZE": {
"expires_in_version": "never",
"kind": "linear",
"high": "5119",
"n_buckets": 256,
"description": "Guessed size of the metadata that we read from the cache file as the first part."
},
"NETWORK_CACHE_METADATA_SIZE": {
"expires_in_version": "never",
"kind": "linear",
"high": "5119",
"n_buckets": 256,
"description": "Actual size of the metadata parsed from the disk."
},
"DATABASE_LOCKED_EXCEPTION": {
"expires_in_version": "42",
"kind": "enumerated",

View File

@ -3,6 +3,8 @@
* 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/. */
'use strict';
Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
Components.utils.import("resource://gre/modules/AddonManager.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
@ -344,7 +346,7 @@ var gUpdates = {
onLoad: function() {
this.wiz = document.documentElement;
gLogEnabled = getPref("getBoolPref", PREF_APP_UPDATE_LOG, false)
gLogEnabled = getPref("getBoolPref", PREF_APP_UPDATE_LOG, false);
this.strings = document.getElementById("updateStrings");
var brandStrings = document.getElementById("brandStrings");
@ -427,13 +429,8 @@ var gUpdates = {
var p = this.update.selectedPatch;
if (p) {
var state = p.state;
var patchFailed;
try {
patchFailed = this.update.getProperty("patchingFailed");
}
catch (e) {
}
let state = p.state;
let patchFailed = this.update.getProperty("patchingFailed");
if (patchFailed) {
if (patchFailed == "partial" && this.update.patchCount == 2) {
// If the system failed to apply the partial patch, show the
@ -453,24 +450,24 @@ var gUpdates = {
// Now select the best page to start with, given the current state of
// the Update.
switch (state) {
case STATE_PENDING:
case STATE_PENDING_SVC:
case STATE_APPLIED:
case STATE_APPLIED_SVC:
this.sourceEvent = SRCEVT_BACKGROUND;
aCallback("finishedBackground");
return;
case STATE_DOWNLOADING:
aCallback("downloading");
return;
case STATE_FAILED:
window.getAttention();
aCallback("errorpatching");
return;
case STATE_DOWNLOAD_FAILED:
case STATE_APPLYING:
aCallback("errors");
return;
case STATE_PENDING:
case STATE_PENDING_SVC:
case STATE_APPLIED:
case STATE_APPLIED_SVC:
this.sourceEvent = SRCEVT_BACKGROUND;
aCallback("finishedBackground");
return;
case STATE_DOWNLOADING:
aCallback("downloading");
return;
case STATE_FAILED:
window.getAttention();
aCallback("errorpatching");
return;
case STATE_DOWNLOAD_FAILED:
case STATE_APPLYING:
aCallback("errors");
return;
}
}
if (this.update.licenseURL)
@ -1615,48 +1612,48 @@ var gDownloadingPage = {
var u = gUpdates.update;
switch (status) {
case CoR.NS_ERROR_CORRUPTED_CONTENT:
case CoR.NS_ERROR_UNEXPECTED:
if (u.selectedPatch.state == STATE_DOWNLOAD_FAILED &&
(u.isCompleteUpdate || u.patchCount != 2)) {
// Verification error of complete patch, informational text is held in
// the update object.
case CoR.NS_ERROR_CORRUPTED_CONTENT:
case CoR.NS_ERROR_UNEXPECTED:
if (u.selectedPatch.state == STATE_DOWNLOAD_FAILED &&
(u.isCompleteUpdate || u.patchCount != 2)) {
// Verification error of complete patch, informational text is held in
// the update object.
this.cleanUp();
gUpdates.wiz.goTo("errors");
break;
}
// Verification failed for a partial patch, complete patch is now
// downloading so return early and do NOT remove the download listener!
// Reset the progress meter to "undertermined" mode so that we don't
// show old progress for the new download of the "complete" patch.
this._downloadProgress.mode = "undetermined";
this._pauseButton.disabled = true;
document.getElementById("verificationFailed").hidden = false;
break;
case CoR.NS_BINDING_ABORTED:
LOG("gDownloadingPage", "onStopRequest - pausing download");
// Do not remove UI listener since the user may resume downloading again.
break;
case CoR.NS_OK:
LOG("gDownloadingPage", "onStopRequest - patch verification succeeded");
// If the background update pref is set, we should wait until the update
// is actually staged in the background.
let aus = CoC["@mozilla.org/updates/update-service;1"].
getService(CoI.nsIApplicationUpdateService);
if (aus.canStageUpdates) {
this._setUpdateApplying();
} else {
this.cleanUp();
gUpdates.wiz.goTo("finished");
}
break;
default:
LOG("gDownloadingPage", "onStopRequest - transfer failed");
// Some kind of transfer error, die.
this.cleanUp();
gUpdates.wiz.goTo("errors");
break;
}
// Verification failed for a partial patch, complete patch is now
// downloading so return early and do NOT remove the download listener!
// Reset the progress meter to "undertermined" mode so that we don't
// show old progress for the new download of the "complete" patch.
this._downloadProgress.mode = "undetermined";
this._pauseButton.disabled = true;
document.getElementById("verificationFailed").hidden = false;
break;
case CoR.NS_BINDING_ABORTED:
LOG("gDownloadingPage", "onStopRequest - pausing download");
// Do not remove UI listener since the user may resume downloading again.
break;
case CoR.NS_OK:
LOG("gDownloadingPage", "onStopRequest - patch verification succeeded");
// If the background update pref is set, we should wait until the update
// is actually staged in the background.
var aus = CoC["@mozilla.org/updates/update-service;1"].
getService(CoI.nsIApplicationUpdateService);
if (aus.canStageUpdates) {
this._setUpdateApplying();
} else {
this.cleanUp();
gUpdates.wiz.goTo("finished");
}
break;
default:
LOG("gDownloadingPage", "onStopRequest - transfer failed");
// Some kind of transfer error, die.
this.cleanUp();
gUpdates.wiz.goTo("errors");
break;
}
},
@ -1775,16 +1772,16 @@ var gErrorPatchingPage = {
onWizardNext: function() {
switch (gUpdates.update.selectedPatch.state) {
case STATE_PENDING:
case STATE_PENDING_SVC:
gUpdates.wiz.goTo("finished");
break;
case STATE_DOWNLOADING:
gUpdates.wiz.goTo("downloading");
break;
case STATE_DOWNLOAD_FAILED:
gUpdates.wiz.goTo("errors");
break;
case STATE_PENDING:
case STATE_PENDING_SVC:
gUpdates.wiz.goTo("finished");
break;
case STATE_DOWNLOADING:
gUpdates.wiz.goTo("downloading");
break;
case STATE_DOWNLOAD_FAILED:
gUpdates.wiz.goTo("errors");
break;
}
}
};

View File

@ -1598,19 +1598,19 @@ function UpdatePatch(patch) {
var attr = patch.attributes.item(i);
attr.QueryInterface(Ci.nsIDOMAttr);
switch (attr.name) {
case "selected":
this.selected = attr.value == "true";
break;
case "size":
if (0 == parseInt(attr.value)) {
LOG("UpdatePatch:init - 0-sized patch!");
throw Cr.NS_ERROR_ILLEGAL_VALUE;
}
// fall through
default:
this[attr.name] = attr.value;
break;
};
case "selected":
this.selected = attr.value == "true";
break;
case "size":
if (0 == parseInt(attr.value)) {
LOG("UpdatePatch:init - 0-sized patch!");
throw Cr.NS_ERROR_ILLEGAL_VALUE;
}
// fall through
default:
this[attr.name] = attr.value;
break;
}
}
}
UpdatePatch.prototype = {
@ -1622,17 +1622,21 @@ UpdatePatch.prototype = {
patch.setAttribute("type", this.type);
patch.setAttribute("URL", this.URL);
// finalURL is not available until after the download has started
if (this.finalURL)
if (this.finalURL) {
patch.setAttribute("finalURL", this.finalURL);
}
patch.setAttribute("hashFunction", this.hashFunction);
patch.setAttribute("hashValue", this.hashValue);
patch.setAttribute("size", this.size);
patch.setAttribute("selected", this.selected);
if (this.selected) {
patch.setAttribute("selected", this.selected);
}
patch.setAttribute("state", this.state);
for (var p in this._properties) {
if (this._properties[p].present)
if (this._properties[p].present) {
patch.setAttribute(p, this._properties[p].data);
}
}
return patch;
@ -1672,12 +1676,15 @@ UpdatePatch.prototype = {
/**
* See nsIPropertyBag.idl
* Note: returns null instead of throwing when the property doesn't exist to
* simplify code and to silence warnings in debug builds.
*/
getProperty: function UpdatePatch_getProperty(name) {
if (name in this._properties &&
this._properties[name].present)
this._properties[name].present) {
return this._properties[name].data;
throw Cr.NS_ERROR_FAILURE;
}
return null;
},
/**
@ -1728,15 +1735,17 @@ function Update(update) {
// Null <update>, assume this is a message container and do no
// further initialization
if (!update)
if (!update) {
return;
}
const ELEMENT_NODE = Ci.nsIDOMNode.ELEMENT_NODE;
for (var i = 0; i < update.childNodes.length; ++i) {
var patchElement = update.childNodes.item(i);
if (patchElement.nodeType != ELEMENT_NODE ||
patchElement.localName != "patch")
patchElement.localName != "patch") {
continue;
}
patchElement.QueryInterface(Ci.nsIDOMElement);
try {
@ -1747,8 +1756,9 @@ function Update(update) {
this._patches.push(patch);
}
if (this._patches.length == 0 && !update.hasAttribute("unsupported"))
if (this._patches.length == 0 && !update.hasAttribute("unsupported")) {
throw Cr.NS_ERROR_ILLEGAL_VALUE;
}
// Fallback to the behavior prior to bug 530872 if the update does not have an
// appVersion attribute.
@ -1762,82 +1772,84 @@ function Update(update) {
}
}
// Set the installDate value with the current time. If the update has an
// installDate attribute this will be replaced with that value if it doesn't
// equal 0.
this.installDate = (new Date()).getTime();
for (var i = 0; i < update.attributes.length; ++i) {
var attr = update.attributes.item(i);
attr.QueryInterface(Ci.nsIDOMAttr);
if (attr.value == "undefined")
if (attr.value == "undefined") {
continue;
else if (attr.name == "detailsURL")
} else if (attr.name == "detailsURL") {
this._detailsURL = attr.value;
else if (attr.name == "extensionVersion") {
} else if (attr.name == "extensionVersion") {
// Prevent extensionVersion from replacing appVersion if appVersion is
// present in the update xml.
if (!this.appVersion)
if (!this.appVersion) {
this.appVersion = attr.value;
}
else if (attr.name == "installDate" && attr.value)
this.installDate = parseInt(attr.value);
else if (attr.name == "isCompleteUpdate")
}
} else if (attr.name == "installDate" && attr.value) {
let val = parseInt(attr.value);
if (val) {
this.installDate = val;
}
} else if (attr.name == "isCompleteUpdate") {
this.isCompleteUpdate = attr.value == "true";
else if (attr.name == "isSecurityUpdate")
} else if (attr.name == "isSecurityUpdate") {
this.isSecurityUpdate = attr.value == "true";
else if (attr.name == "isOSUpdate")
} else if (attr.name == "isOSUpdate") {
this.isOSUpdate = attr.value == "true";
else if (attr.name == "showNeverForVersion")
} else if (attr.name == "showNeverForVersion") {
this.showNeverForVersion = attr.value == "true";
else if (attr.name == "showPrompt")
} else if (attr.name == "showPrompt") {
this.showPrompt = attr.value == "true";
else if (attr.name == "promptWaitTime")
{
if(!isNaN(attr.value))
} else if (attr.name == "promptWaitTime") {
if(!isNaN(attr.value)) {
this.promptWaitTime = parseInt(attr.value);
}
else if (attr.name == "unsupported")
}
} else if (attr.name == "unsupported") {
this.unsupported = attr.value == "true";
else if (attr.name == "version") {
} else if (attr.name == "version") {
// Prevent version from replacing displayVersion if displayVersion is
// present in the update xml.
if (!this.displayVersion)
if (!this.displayVersion) {
this.displayVersion = attr.value;
}
else {
}
} else {
this[attr.name] = attr.value;
switch (attr.name) {
case "appVersion":
case "billboardURL":
case "buildID":
case "channel":
case "displayVersion":
case "licenseURL":
case "name":
case "platformVersion":
case "previousAppVersion":
case "serviceURL":
case "statusText":
case "type":
break;
default:
// Save custom attributes when serializing to the local xml file but
// don't use this method for the expected attributes which are already
// handled in serialize.
this.setProperty(attr.name, attr.value);
break;
};
case "appVersion":
case "billboardURL":
case "buildID":
case "channel":
case "displayVersion":
case "licenseURL":
case "name":
case "platformVersion":
case "previousAppVersion":
case "serviceURL":
case "statusText":
case "type":
break;
default:
// Save custom attributes when serializing to the local xml file but
// don't use this method for the expected attributes which are already
// handled in serialize.
this.setProperty(attr.name, attr.value);
break;
}
}
}
// Set the initial value with the current time when it doesn't already have a
// value or the value is already set to 0 (bug 316328).
if (!this.installDate && this.installDate != 0)
this.installDate = (new Date()).getTime();
// The Update Name is either the string provided by the <update> element, or
// the string: "<App Name> <Update App Version>"
var name = "";
if (update.hasAttribute("name"))
if (update.hasAttribute("name")) {
name = update.getAttribute("name");
else {
} else {
var brandBundle = Services.strings.createBundle(URI_BRAND_PROPERTIES);
var appName = brandBundle.GetStringFromName("brandShortName");
name = gUpdateBundle.formatStringFromName("updateName",
@ -1917,6 +1929,12 @@ Update.prototype = {
* See nsIUpdateService.idl
*/
serialize: function Update_serialize(updates) {
// If appVersion isn't defined just return null. This happens when a
// temporary nsIUpdate is passed to the UI when the
// app.update.showInstalledUI prefence is set to true.
if (!this.appVersion) {
return null;
}
var update = updates.createElementNS(URI_UPDATE_NS, "update");
update.setAttribute("appVersion", this.appVersion);
update.setAttribute("buildID", this.buildID);
@ -1937,29 +1955,38 @@ Update.prototype = {
update.setAttribute("version", this.displayVersion);
// Optional attributes
if (this.billboardURL)
if (this.billboardURL) {
update.setAttribute("billboardURL", this.billboardURL);
if (this.detailsURL)
}
if (this.detailsURL) {
update.setAttribute("detailsURL", this.detailsURL);
if (this.licenseURL)
}
if (this.licenseURL) {
update.setAttribute("licenseURL", this.licenseURL);
if (this.platformVersion)
}
if (this.platformVersion) {
update.setAttribute("platformVersion", this.platformVersion);
if (this.previousAppVersion)
}
if (this.previousAppVersion) {
update.setAttribute("previousAppVersion", this.previousAppVersion);
if (this.statusText)
}
if (this.statusText) {
update.setAttribute("statusText", this.statusText);
if (this.unsupported)
}
if (this.unsupported) {
update.setAttribute("unsupported", this.unsupported);
}
updates.documentElement.appendChild(update);
for (var p in this._properties) {
if (this._properties[p].present)
if (this._properties[p].present) {
update.setAttribute(p, this._properties[p].data);
}
}
for (var i = 0; i < this.patchCount; ++i)
for (let i = 0; i < this.patchCount; ++i) {
update.appendChild(this.getPatchAt(i).serialize(updates));
}
return update;
},
@ -1998,11 +2025,14 @@ Update.prototype = {
/**
* See nsIPropertyBag.idl
* Note: returns null instead of throwing when the property doesn't exist to
* simplify code and to silence warnings in debug builds.
*/
getProperty: function Update_getProperty(name) {
if (name in this._properties && this._properties[name].present)
if (name in this._properties && this._properties[name].present) {
return this._properties[name].data;
throw Cr.NS_ERROR_FAILURE;
}
return null;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdate,
@ -2081,41 +2111,41 @@ UpdateService.prototype = {
*/
observe: function AUS_observe(subject, topic, data) {
switch (topic) {
case "post-update-processing":
// Clean up any extant updates
this._postUpdateProcessing();
break;
case "network:offline-status-changed":
this._offlineStatusChanged(data);
break;
case "nsPref:changed":
if (data == PREF_APP_UPDATE_LOG) {
gLogEnabled = getPref("getBoolPref", PREF_APP_UPDATE_LOG, false);
}
break;
case "post-update-processing":
// Clean up any extant updates
this._postUpdateProcessing();
break;
case "network:offline-status-changed":
this._offlineStatusChanged(data);
break;
case "nsPref:changed":
if (data == PREF_APP_UPDATE_LOG) {
gLogEnabled = getPref("getBoolPref", PREF_APP_UPDATE_LOG, false);
}
break;
#ifdef MOZ_WIDGET_GONK
case "profile-change-net-teardown": // fall thru
case "profile-change-net-teardown": // fall thru
#endif
case "xpcom-shutdown":
Services.obs.removeObserver(this, topic);
Services.prefs.removeObserver(PREF_APP_UPDATE_LOG, this);
case "xpcom-shutdown":
Services.obs.removeObserver(this, topic);
Services.prefs.removeObserver(PREF_APP_UPDATE_LOG, this);
#ifdef XP_WIN
// If we hold the update mutex, let it go!
// The OS would clean this up sometime after shutdown,
// but that would have no guarantee on timing.
if (gUpdateMutexHandle) {
closeHandle(gUpdateMutexHandle);
}
// If we hold the update mutex, let it go!
// The OS would clean this up sometime after shutdown,
// but that would have no guarantee on timing.
if (gUpdateMutexHandle) {
closeHandle(gUpdateMutexHandle);
}
#endif
if (this._retryTimer) {
this._retryTimer.cancel();
}
if (this._retryTimer) {
this._retryTimer.cancel();
}
this.pauseDownload();
// Prevent leaking the downloader (bug 454964)
this._downloader = null;
break;
this.pauseDownload();
// Prevent leaking the downloader (bug 454964)
this._downloader = null;
break;
}
},
@ -3217,11 +3247,8 @@ UpdateService.prototype = {
throw Cr.NS_ERROR_FAILURE;
}
let osApplyToDir;
try {
aUpdate.QueryInterface(Ci.nsIWritablePropertyBag);
osApplyToDir = aUpdate.getProperty("osApplyToDir");
} catch (e) {}
aUpdate.QueryInterface(Ci.nsIWritablePropertyBag);
let osApplyToDir = aUpdate.getProperty("osApplyToDir");
if (!osApplyToDir) {
LOG("UpdateService:applyOsUpdate - Error: osApplyToDir is not defined" +
@ -3478,8 +3505,9 @@ UpdateManager.prototype = {
createInstance(Ci.nsIFileOutputStream);
var modeFlags = FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE |
FileUtils.MODE_TRUNCATE;
if (!file.exists())
if (!file.exists()) {
file.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
}
fos.init(file, modeFlags, FileUtils.PERMS_FILE, 0);
try {
@ -3489,15 +3517,18 @@ UpdateManager.prototype = {
var doc = parser.parseFromString(EMPTY_UPDATES_DOCUMENT, "text/xml");
for (var i = 0; i < updates.length; ++i) {
if (updates[i])
// If appVersion isn't defined don't add the update. This happens when a
// temporary nsIUpdate is passed to the UI when the
// app.update.showInstalledUI prefence is set to true.
if (updates[i] && updates[i].appVersion) {
doc.documentElement.appendChild(updates[i].serialize(doc));
}
}
var serializer = Cc["@mozilla.org/xmlextras/xmlserializer;1"].
createInstance(Ci.nsIDOMSerializer);
serializer.serializeToStream(doc.documentElement, fos, null);
}
catch (e) {
} catch (e) {
}
FileUtils.closeSafeFileOutputStream(fos);
@ -3829,7 +3860,7 @@ Checker.prototype = {
if (this._isHttpStatusCode(status)) {
update.errorCode = HTTP_ERROR_OFFSET + status;
}
if (e.result == Cr.NS_ERROR_ILLEGAL_VALUE) {
if (e.result && e.result == Cr.NS_ERROR_ILLEGAL_VALUE) {
update.errorCode = updates[0] ? CERT_ATTR_CHECK_FAILED_HAS_UPDATE
: CERT_ATTR_CHECK_FAILED_NO_UPDATE;
}
@ -3896,13 +3927,13 @@ Checker.prototype = {
this._request.abort();
switch (duration) {
case Ci.nsIUpdateChecker.CURRENT_SESSION:
this._enabled = false;
break;
case Ci.nsIUpdateChecker.ANY_CHECKS:
this._enabled = false;
Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, this._enabled);
break;
case Ci.nsIUpdateChecker.CURRENT_SESSION:
this._enabled = false;
break;
case Ci.nsIUpdateChecker.ANY_CHECKS:
this._enabled = false;
Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, this._enabled);
break;
}
this._callback = null;
@ -3981,10 +4012,11 @@ Downloader.prototype = {
*/
_verifyDownload: function Downloader__verifyDownload() {
LOG("Downloader:_verifyDownload called");
if (!this._request)
if (!this._request) {
return false;
}
var destination = this._request.destination;
let destination = this._request.destination;
// Ensure that the file size matches the expected file size.
if (destination.fileSize != this._patch.size) {
@ -3993,16 +4025,18 @@ Downloader.prototype = {
}
LOG("Downloader:_verifyDownload downloaded size == expected size.");
var fileStream = Cc["@mozilla.org/network/file-input-stream;1"].
let fileStream = Cc["@mozilla.org/network/file-input-stream;1"].
createInstance(Ci.nsIFileInputStream);
fileStream.init(destination, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0);
let digest;
try {
var hash = Cc["@mozilla.org/security/hash;1"].
let hash = Cc["@mozilla.org/security/hash;1"].
createInstance(Ci.nsICryptoHash);
var hashFunction = Ci.nsICryptoHash[this._patch.hashFunction.toUpperCase()];
if (hashFunction == undefined)
if (hashFunction == undefined) {
throw Cr.NS_ERROR_UNEXPECTED;
}
hash.init(hashFunction);
hash.updateFromStream(fileStream, -1);
// NOTE: For now, we assume that the format of _patch.hashValue is hex
@ -4069,35 +4103,35 @@ Downloader.prototype = {
LOG("Downloader:_selectPatch - found existing patch with state: " +
state);
switch (state) {
case STATE_DOWNLOADING:
LOG("Downloader:_selectPatch - resuming download");
return selectedPatch;
case STATE_DOWNLOADING:
LOG("Downloader:_selectPatch - resuming download");
return selectedPatch;
#ifdef MOZ_WIDGET_GONK
case STATE_PENDING:
case STATE_APPLYING:
LOG("Downloader:_selectPatch - resuming interrupted apply");
return selectedPatch;
case STATE_APPLIED:
LOG("Downloader:_selectPatch - already downloaded and staged");
return null;
#else
case STATE_PENDING_SVC:
case STATE_PENDING:
LOG("Downloader:_selectPatch - already downloaded and staged");
return null;
#endif
default:
// Something went wrong when we tried to apply the previous patch.
// Try the complete patch next time.
if (update && selectedPatch.type == "partial") {
useComplete = true;
} else {
// This is a pretty fatal error. Just bail.
LOG("Downloader:_selectPatch - failed to apply complete patch!");
writeStatusFile(updateDir, STATE_NONE);
writeVersionFile(getUpdatesDir(), null);
case STATE_PENDING:
case STATE_APPLYING:
LOG("Downloader:_selectPatch - resuming interrupted apply");
return selectedPatch;
case STATE_APPLIED:
LOG("Downloader:_selectPatch - already downloaded and staged");
return null;
}
#else
case STATE_PENDING_SVC:
case STATE_PENDING:
LOG("Downloader:_selectPatch - already downloaded and staged");
return null;
#endif
default:
// Something went wrong when we tried to apply the previous patch.
// Try the complete patch next time.
if (update && selectedPatch.type == "partial") {
useComplete = true;
} else {
// This is a pretty fatal error. Just bail.
LOG("Downloader:_selectPatch - failed to apply complete patch!");
writeStatusFile(updateDir, STATE_NONE);
writeVersionFile(getUpdatesDir(), null);
return null;
}
}
selectedPatch = null;
@ -4571,14 +4605,8 @@ Downloader.prototype = {
// notify the user about the error. If the update was a background
// update there is no notification since the user won't be expecting it.
if (!Services.wm.getMostRecentWindow(UPDATE_WINDOW_NAME)) {
try {
this._update.QueryInterface(Ci.nsIWritablePropertyBag);
var fgdl = this._update.getProperty("foregroundDownload");
}
catch (e) {
}
if (fgdl == "true") {
this._update.QueryInterface(Ci.nsIWritablePropertyBag);
if (this._update.getProperty("foregroundDownload") == "true") {
var prompter = Cc["@mozilla.org/updates/update-prompt;1"].
createInstance(Ci.nsIUpdatePrompt);
prompter.showUpdateError(this._update);

View File

@ -114,6 +114,8 @@
* install completes.
*/
'use strict';
Components.utils.import("resource://gre/modules/AddonManager.jsm");
// The tests have to use the pageid instead of the pageIndex due to the
@ -158,7 +160,6 @@ const PREF_APP_UPDATE_LASTUPDATETIME = "app.update.lastUpdateTime.background-upd
// from interefering with the tests.
const PREF_DISABLEDADDONS = "app.update.test.disabledAddons";
const PREF_EM_HOTFIX_ID = "extensions.hotfix.id";
const PREF_EM_SILENT = "app.update.silent";
const TEST_ADDONS = [ "appdisabled_1", "appdisabled_2",
"compatible_1", "compatible_2",
"noupdate_1", "noupdate_2",
@ -922,9 +923,9 @@ function setupPrefs() {
Services.prefs.setIntPref(PREF_APP_UPDATE_IDLETIME, 0);
Services.prefs.setIntPref(PREF_APP_UPDATE_PROMPTWAITTIME, 0);
Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, false);
Services.prefs.setBoolPref(PREF_EXTENSIONS_STRICT_COMPAT, true);
Services.prefs.setCharPref(PREF_EM_HOTFIX_ID, "hotfix" + ADDON_ID_SUFFIX);
Services.prefs.setBoolPref(PREF_EM_SILENT, false);
}
/**
@ -1078,6 +1079,10 @@ function resetPrefs() {
catch(e) {
}
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SILENT)) {
Services.prefs.clearUserPref(PREF_APP_UPDATE_SILENT);
}
if (Services.prefs.prefHasUserValue(PREF_EXTENSIONS_STRICT_COMPAT)) {
Services.prefs.clearUserPref(PREF_EXTENSIONS_STRICT_COMPAT);
}
@ -1085,10 +1090,6 @@ function resetPrefs() {
if (Services.prefs.prefHasUserValue(PREF_EM_HOTFIX_ID)) {
Services.prefs.clearUserPref(PREF_EM_HOTFIX_ID);
}
if (Services.prefs.prefHasUserValue(PREF_EM_SILENT)) {
Services.prefs.clearUserPref(PREF_EM_SILENT);
}
}
function setupTimer(aTestTimeout) {
@ -1187,7 +1188,7 @@ function setupAddons(aCallback) {
if (--xpiCount == 0) {
let installCount = installs.length;
function installCompleted(aInstall) {
let installCompleted = function(aInstall) {
aInstall.removeListener(listener);
if (getAddonTestType(aInstall.addon.name) == "userdisabled") {
@ -1196,7 +1197,7 @@ function setupAddons(aCallback) {
if (--installCount == 0) {
setNoUpdateAddonsDisabledState();
}
}
};
let listener = {
onDownloadFailed: installCompleted,

View File

@ -36,15 +36,6 @@ class AutoLocalJNIFrame;
void InitAndroidJavaWrappers(JNIEnv *jEnv);
/*
* Note: do not store global refs to any WrappedJavaObject;
* these are live only during a particular JNI method, as
* NewGlobalRef is -not- called on the jobject.
*
* If this is needed, WrappedJavaObject can be extended to
* handle it.
*/
class RefCountedJavaObject {
public:
RefCountedJavaObject(JNIEnv* env, jobject obj) : mRefCnt(0), mObject(env->NewGlobalRef(obj)) {}
@ -66,6 +57,14 @@ private:
jobject mObject;
};
/*
* Note: do not store global refs to any WrappedJavaObject;
* these are live only during a particular JNI method, as
* NewGlobalRef is -not- called on the jobject.
*
* If this is needed, WrappedJavaObject can be extended to
* handle it.
*/
class WrappedJavaObject {
public:
WrappedJavaObject() :

View File

@ -234,10 +234,14 @@ WindowsOSVersion()
if (winVersion == UNINITIALIZED_VALUE) {
vinfo.dwOSVersionInfoSize = sizeof (vinfo);
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4996)
#endif
if (!GetVersionEx(&vinfo)) {
#ifdef _MSC_VER
#pragma warning(pop)
#endif
winVersion = kWindowsUnknown;
} else {
winVersion = int32_t(vinfo.dwMajorVersion << 16) + vinfo.dwMinorVersion;

View File

@ -237,7 +237,6 @@ nsresult JumpListBuilder::RemoveIconCacheForAllItems()
if (NS_FAILED(currFile->GetPath(path)))
continue;
int32_t len = path.Length();
if (StringTail(path, 4).LowerCaseEqualsASCII(".ico")) {
// Check if the cached ICO file exists
bool exists;

View File

@ -1625,7 +1625,6 @@ NativeKey::HandleCharMessage(const MSG& aCharMsg,
// Bug 50255 and Bug 351310: Keep the characters unshifted for shortcuts and
// accesskeys and make sure that numbers are always passed as such.
if (uniChar && (mModKeyState.IsControl() || mModKeyState.IsAlt())) {
KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
char16_t unshiftedCharCode =
(mVirtualKeyCode >= '0' && mVirtualKeyCode <= '9') ?
mVirtualKeyCode : mModKeyState.IsShift() ?
@ -2126,7 +2125,6 @@ NativeKey::DispatchKeyPressEventsWithKeyboardLayout() const
uint32_t skipUniChars = longestLength - inputtingChars.mLength;
uint32_t skipShiftedChars = longestLength - shiftedChars.mLength;
uint32_t skipUnshiftedChars = longestLength - unshiftedChars.mLength;
UINT keyCode = !inputtingChars.mLength ? mDOMKeyCode : 0;
bool defaultPrevented = false;
for (uint32_t cnt = 0; cnt < longestLength; cnt++) {
uint16_t uniChar, shiftedChar, unshiftedChar;

View File

@ -295,8 +295,8 @@ private:
private:
bool mInitialized;
int32_t mScrollLines;
int32_t mScrollChars;
uint32_t mScrollLines;
uint32_t mScrollChars;
};
SystemSettings mSystemSettings;

View File

@ -481,12 +481,11 @@ WinUtils::LogW(const wchar_t *fmt, ...)
OutputDebugStringW(buffer);
OutputDebugStringW(L"\n");
int len = wcslen(buffer);
int len = WideCharToMultiByte(CP_ACP, 0, buffer, -1, nullptr, 0, nullptr, nullptr);
if (len) {
char* utf8 = new char[len+1];
memset(utf8, 0, sizeof(utf8));
char* utf8 = new char[len];
if (WideCharToMultiByte(CP_ACP, 0, buffer,
-1, utf8, len+1, nullptr,
-1, utf8, len, nullptr,
nullptr) > 0) {
// desktop console
printf("%s\n", utf8);
@ -1077,11 +1076,11 @@ WinUtils::InvalidatePluginAsWorkaround(nsIWidget *aWidget, const nsIntRect &aRec
}
#ifdef MOZ_PLACES
/************************************************************************/
/* Constructs as AsyncFaviconDataReady Object
/* @param aIOThread : the thread which performs the action
/* @param aURLShortcut : Differentiates between (false)Jumplistcache and (true)Shortcutcache
/************************************************************************/
/************************************************************************
* Constructs as AsyncFaviconDataReady Object
* @param aIOThread : the thread which performs the action
* @param aURLShortcut : Differentiates between (false)Jumplistcache and (true)Shortcutcache
************************************************************************/
AsyncFaviconDataReady::AsyncFaviconDataReady(nsIURI *aNewURI,
nsCOMPtr<nsIThread> &aIOThread,

View File

@ -29,7 +29,7 @@ using namespace mozilla::widget;
// A wake lock listener that disables screen saver when requested by
// Gecko. For example when we're playing video in a foreground tab we
// don't want the screen saver to turn on.
class WinWakeLockListener : public nsIDOMMozWakeLockListener {
class WinWakeLockListener MOZ_FINAL : public nsIDOMMozWakeLockListener {
public:
NS_DECL_ISUPPORTS;

View File

@ -51,6 +51,10 @@ class nsDataObjCollection MOZ_FINAL : public nsIDataObjCollection, public nsData
virtual HRESULT GetFileContents(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
virtual HRESULT GetFirstSupporting(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
using nsDataObj::GetFile;
using nsDataObj::GetFileContents;
using nsDataObj::GetText;
// support for clipboard
void AddDataFlavor(const char * aDataFlavor, LPFORMATETC aFE);

View File

@ -573,6 +573,8 @@ GetSysFontInfo(HDC aHDC, LookAndFeel::FontID anID,
case LookAndFeel::eFont_Tooltips:
ptrLogFont = &ncm.lfStatusFont;
break;
default:
MOZ_CRASH();
}
break;

View File

@ -1025,7 +1025,6 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, uint8_t aWidgetType,
case NS_THEME_PROGRESSBAR_CHUNK:
case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: {
nsIFrame* parentFrame = aFrame->GetParent();
EventStates eventStates = GetContentState(parentFrame, aWidgetType);
if (aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL ||
IsVerticalProgress(parentFrame)) {
aPart = IsVistaOrLater() ?
@ -1463,12 +1462,8 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, uint8_t aWidgetType,
case NS_THEME_MENUCHECKBOX:
case NS_THEME_MENURADIO:
{
bool isChecked;
EventStates eventState = GetContentState(aFrame, aWidgetType);
// NOTE: we can probably use NS_EVENT_STATE_CHECKED
isChecked = CheckBooleanAttr(aFrame, nsGkAtoms::checked);
aPart = MENU_POPUPCHECK;
aState = MC_CHECKMARKNORMAL;
@ -3178,7 +3173,6 @@ nsresult nsNativeThemeWin::ClassicGetThemePartAndState(nsIFrame* aFrame, uint8_t
case NS_THEME_RADIOMENUITEM: {
bool isTopLevel = false;
bool isOpen = false;
bool isContainer = false;
nsMenuFrame *menuFrame = do_QueryFrame(aFrame);
EventStates eventState = GetContentState(aFrame, aWidgetType);
@ -3194,7 +3188,6 @@ nsresult nsNativeThemeWin::ClassicGetThemePartAndState(nsIFrame* aFrame, uint8_t
// rendering.
isTopLevel = menuFrame->IsOnMenuBar();
isOpen = menuFrame->IsOpen();
isContainer = menuFrame->IsMenu();
}
if (IsDisabled(aFrame, eventState))
@ -3477,6 +3470,8 @@ static void DrawTab(HDC hdc, const RECT& R, int32_t aPosition, bool aSelected,
::SetRect(&lightRect, R.left, R.bottom-3, R.left+2, R.bottom-1);
::SetRect(&shadeRect, R.right-2, R.bottom-3, R.right, R.bottom-1);
break;
default:
MOZ_CRASH();
}
// Background
@ -3812,7 +3807,6 @@ RENDER_AGAIN:
bool indeterminate = IsIndeterminateProgress(stateFrame, eventStates);
bool vertical = IsVerticalProgress(stateFrame) ||
aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL;
int32_t overlayPart = GetProgressOverlayStyle(vertical);
nsIContent* content = aFrame->GetContent();
if (!indeterminate || !content) {

View File

@ -1173,11 +1173,11 @@ bool nsTextStore::sDoNotReturnNoLayoutErrorToEasyChangjei = false;
#define TEXTSTORE_DEFAULT_VIEW (1)
nsTextStore::nsTextStore()
: mLockedContent(mComposition, mSelection)
, mEditCookie(0)
: mEditCookie(0)
, mSinkMask(0)
, mLock(0)
, mLockQueued(0)
, mLockedContent(mComposition, mSelection)
, mRequestedAttrValues(false)
, mIsRecordingActionsWithoutLock(false)
, mPendingOnSelectionChange(false)

View File

@ -1701,8 +1701,6 @@ NS_METHOD nsWindow::ConstrainPosition(bool aAllowSlop,
int32_t logWidth = std::max<int32_t>(NSToIntRound(mBounds.width / dpiScale), 1);
int32_t logHeight = std::max<int32_t>(NSToIntRound(mBounds.height / dpiScale), 1);
bool doConstrain = false; // whether we have enough info to do anything
/* get our playing field. use the current screen, or failing that
for any reason, use device caps for the default screen. */
RECT screenRect;
@ -1726,7 +1724,6 @@ NS_METHOD nsWindow::ConstrainPosition(bool aAllowSlop,
screenRect.right = left + width;
screenRect.top = top;
screenRect.bottom = top + height;
doConstrain = true;
}
} else {
if (mWnd) {
@ -1740,7 +1737,6 @@ NS_METHOD nsWindow::ConstrainPosition(bool aAllowSlop,
screenRect.right = GetSystemMetrics(SM_CXFULLSCREEN);
screenRect.bottom = GetSystemMetrics(SM_CYFULLSCREEN);
}
doConstrain = true;
}
::ReleaseDC(mWnd, dc);
}
@ -2701,6 +2697,8 @@ void nsWindow::UpdateGlass()
case eTransparencyGlass:
policy = DWMNCRP_ENABLED;
break;
default:
break;
}
PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
@ -5179,7 +5177,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
*aRetValue = 0;
// Do explicit casting to make it working on 64bit systems (see bug 649236
// for details).
DWORD objId = static_cast<DWORD>(lParam);
int32_t objId = static_cast<DWORD>(lParam);
if (objId == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically
a11y::Accessible* rootAccessible = GetAccessible(); // Held by a11y cache
if (rootAccessible) {
@ -6568,8 +6566,6 @@ nsWindow::GetPreferredCompositorBackends(nsTArray<LayersBackend>& aHints)
aHints.AppendElement(LayersBackend::LAYERS_OPENGL);
}
ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11Device();
if (!prefs.mPreferD3D9) {
aHints.AppendElement(LayersBackend::LAYERS_D3D11);
}

View File

@ -90,6 +90,8 @@ public:
virtual nsWindowBase* GetParentWindowBase(bool aIncludeOwner) MOZ_OVERRIDE;
virtual bool IsTopLevelWidget() MOZ_OVERRIDE { return mIsTopWidgetWindow; }
using nsWindowBase::DispatchPluginEvent;
// nsIWidget interface
NS_IMETHOD Create(nsIWidget *aParent,
nsNativeWidget aNativeParent,

Some files were not shown because too many files have changed in this diff Show More