From 14b7123a72f6fd97cc315b4aeb1cdb8756335691 Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Tue, 6 Feb 2018 14:32:06 -0800 Subject: [PATCH 01/11] #463: add IdleRequestCallback to nsTimeout --- dom/base/nsGlobalWindow.cpp | 22 +++++++++++++++++++++- dom/base/nsGlobalWindow.h | 9 +++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index f8bf14a4f..1032c4b33 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -11537,10 +11537,20 @@ nsGlobalWindow::SetInterval(JSContext* aCx, const nsAString& aHandler, return SetTimeoutOrInterval(aCx, aHandler, timeout, isInterval, aError); } +// TenFourFox issue 463 nsresult nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler, int32_t interval, bool aIsInterval, int32_t *aReturn) +{ + return SetTimeoutOrIntervalOrIdleCallback(aHandler, interval, aIsInterval, aReturn, nullptr); +} + +nsresult +nsGlobalWindow::SetTimeoutOrIntervalOrIdleCallback(nsIScriptTimeoutHandler *aHandler, + int32_t interval, + bool aIsInterval, int32_t *aReturn, + mozilla::dom::IdleRequestCallback *aCallback) { MOZ_ASSERT(IsInnerWindow()); @@ -11565,7 +11575,10 @@ nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler, RefPtr timeout = new nsTimeout(); timeout->mIsInterval = aIsInterval; timeout->mInterval = interval; - timeout->mScriptHandler = aHandler; + if (aCallback) + timeout->mCallback = aCallback; + else + timeout->mScriptHandler = aHandler; // Now clamp the actual interval we will use for the timer based on uint32_t nestingLevel = sNestingLevel + 1; @@ -11754,6 +11767,13 @@ nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout, reason = "setTimeout handler"; } + if (!timeout->mScriptHandler) { + // Time to assess the conditions for requestIdleCallback (issue 463). + MOZ_ASSERT(timeout->mCallback); + MOZ_CRASH("RunTimeoutHandler triggered on requestIdleCallback"); + return false; + } + nsCOMPtr handler(timeout->mScriptHandler); RefPtr callback = handler->GetCallback(); if (!callback) { diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 41d1b65e4..025b261fa 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -211,7 +211,10 @@ public: PopupControlState mPopupState; // The language-specific information about the callback. + // If there is an nsIScriptTimeoutHandler, this is a regular setTimeout. + // If there is an IdleRequestCallback, this is requestIdleCallback (issue 463). nsCOMPtr mScriptHandler; + RefPtr mCallback; }; struct IdleObserverHolder @@ -1411,6 +1414,12 @@ public: nsresult SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler, int32_t interval, bool aIsInterval, int32_t* aReturn) override; + // TenFourFox issue 463 + nsresult SetTimeoutOrIntervalOrIdleCallback(nsIScriptTimeoutHandler *aHandler, + int32_t interval, + bool aIsInterval, int32_t *aReturn, + mozilla::dom::IdleRequestCallback *aCallback); + int32_t SetTimeoutOrInterval(JSContext* aCx, mozilla::dom::Function& aFunction, int32_t aTimeout, From 2b033c64734cf196e512765e3b0ae7e6a6e6443f Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Tue, 6 Feb 2018 20:03:38 -0800 Subject: [PATCH 02/11] #469: more hosts for adblock --- caps/nsScriptSecurityManager.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index ae3bda203..8ab91af6f 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -748,8 +748,9 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal, BLOK("at.atwola.com") || - BLOK("pixel.advertising.com") || BLOK("dtm.advertising.com") || + BLOK("pixel.advertising.com") || + BLOK("adserver-us.adtech.advertising.com") || BLOK("sp.analytics.yahoo.com") || BLOK("ads.yap.yahoo.com") || @@ -904,6 +905,12 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal, BLOK("yads.yjtag.yahoo.co.jp") || BLOK("px-ya.ladsp.com") || + + BLOK("stats.cloudwp.io") || + + BLOK("ap.lijit.com") || + + BLOK("tlx.3lift.com") || 0) { #undef BLOK // Yup. From b1e7495de6aecd02646b5e32f1bd708f9ca360b1 Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Thu, 8 Feb 2018 23:49:40 -0800 Subject: [PATCH 03/11] #469: even more hosts for adblock --- caps/nsScriptSecurityManager.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 8ab91af6f..74f59fa54 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -815,6 +815,7 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal, BLOK("rscdn.cxense.com") || BLOK("z.moatads.com") || + BLOK("js.moatads.com") || BLOK("s-jsonp.moatads.com") || BLOK("static.yieldmo.com") || @@ -911,6 +912,16 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal, BLOK("ap.lijit.com") || BLOK("tlx.3lift.com") || + + BLOK("v.lkqd.net") || + BLOK("ad.lkqd.net") || + + BLOK("vpaid.springserve.com") || + + BLOK("vd.ads.memevideoad.com") || + BLOK("sp.ads.memevideoad.com") || + + BLOK("static.adsnative.com") || 0) { #undef BLOK // Yup. From 341aeed992b65265df50c307312f6d08f16e97ec Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Sat, 10 Feb 2018 13:04:00 -0800 Subject: [PATCH 04/11] #469: even more even more hosts for adblock --- caps/nsScriptSecurityManager.cpp | 50 ++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 74f59fa54..d2fa3dab4 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -727,9 +727,11 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal, BLOK("ipv6.adrta.com") || BLOK("ib.adnxs.com") || + BLOK("cdn.adnxs.com") || BLOK("acdn.adnxs.com") || BLOK("secure.adnxs.com") || BLOK("yj-a.p.adnxs.com") || + BLOK("nym1-ib.adnxs.com") || BLOK("sharethrough.adnxs.com") || BLOK("c2.taboola.com") || @@ -845,6 +847,8 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal, BLOK("www.npttech.com") || BLOK("cdn.adsafeprotected.com") || + BLOK("pixel.adsafeprotected.com") || + BLOK("static.adsafeprotected.com") || BLOK("aka-cdn.adtechus.com") || BLOK("adserver.adtechus.com") || @@ -922,6 +926,52 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal, BLOK("sp.ads.memevideoad.com") || BLOK("static.adsnative.com") || + + BLOK("cm.mgid.com") || + BLOK("jsc.mgid.com") || + BLOK("servicer.mgid.com") || + + BLOK("cdn.engine.addroplet.com") || + + BLOK("de.tynt.com") || + BLOK("sc.tynt.com") || + BLOK("cdn.tynt.com") || + + BLOK("bid.underdog.media") || + + BLOK("cdn.fastclick.net") || + BLOK("media.fastclick.net") || + + BLOK("udmserve.net") || + + BLOK("sic.33across.com") || + BLOK("cdn-sic.33across.com") || + + BLOK("d.adroll.com") || + BLOK("s.adroll.com") || + + BLOK("c.betrad.com") || + + BLOK("fqtag.com") || + BLOK("c.fqtag.com") || + BLOK("new.fqtag.com") || + + BLOK("a-nj.1rx.io") || + BLOK("rxcdn.1rx.io") || + + BLOK("c.evidon.com") || + + BLOK("api.content-ad.net") || + + BLOK("cdn.distiltag.com") || + + BLOK("my.hellobar.com") || + + BLOK("static.hotjar.com") || + BLOK("script.hotjar.com") || + + BLOK("tags.mathtag.com") || + BLOK("pixel.mathtag.com") || 0) { #undef BLOK // Yup. From f9f066fc153ac7e505d3f79721452bf2d589fd85 Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Sat, 10 Feb 2018 13:33:19 -0800 Subject: [PATCH 05/11] more fonts for blacklist --- gfx/thebes/gfxPlatformMac.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gfx/thebes/gfxPlatformMac.cpp b/gfx/thebes/gfxPlatformMac.cpp index dcbe312a2..19a804faf 100644 --- a/gfx/thebes/gfxPlatformMac.cpp +++ b/gfx/thebes/gfxPlatformMac.cpp @@ -263,6 +263,10 @@ gfxPlatformMac::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) spec.Equals("http://www.latimes.com/pb/resources/dist/la/latest/4dcd1b9d7833fcec708a/fonts/KisFBDisplay-Bold.woff2") || spec.Equals("http://www.latimes.com/pb/resources/dist/la/latest/4dcd1b9d7833fcec708a/fonts/KisFBDisplay-Roman.woff") || spec.Equals("http://www.latimes.com/pb/resources/dist/la/latest/4dcd1b9d7833fcec708a/fonts/KisFBDisplay-Roman.woff2") || + spec.Equals("http://www.latimes.com/pb/resources/dist/la/latest/4b58868f482c8c9570aa/fonts/KisFBDisplay-Bold.woff") || + spec.Equals("http://www.latimes.com/pb/resources/dist/la/latest/4b58868f482c8c9570aa/fonts/KisFBDisplay-Bold.woff2") || + spec.Equals("http://www.latimes.com/pb/resources/dist/la/latest/4b58868f482c8c9570aa/fonts/KisFBDisplay-Roman.woff") || + spec.Equals("http://www.latimes.com/pb/resources/dist/la/latest/4b58868f482c8c9570aa/fonts/KisFBDisplay-Roman.woff2") || spec.Equals("https://cdn-static-1.medium.com/_/fp/fonts/charter-nonlatin.b-nw7PXlIqmGHGmHvkDiTw.woff") || spec.Equals("http://typeface.nytimes.com/fonts/nyt-cheltenham-200-normal.woff") || spec.Equals("https://typeface.nyt.com/fonts/nyt-cheltenham-200-normal.woff") || From b62716ce587f64b38c478f68e801d579f2468b1e Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Sat, 10 Feb 2018 15:38:28 -0800 Subject: [PATCH 06/11] #465: jsstr.cpp (less aggressively) --- js/src/jsstr.cpp | 264 +++++++++++++++++++++++------------------------ 1 file changed, 132 insertions(+), 132 deletions(-) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index b508c9fda..549c6b608 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -145,7 +145,7 @@ Escape(JSContext* cx, const CharT* chars, uint32_t length, uint32_t* newLengthOu } Latin1Char* newChars = cx->pod_malloc(newLength + 1); - if (!newChars) + if (MOZ_UNLIKELY(!newChars)) return nullptr; static const char digits[] = "0123456789ABCDEF"; @@ -194,11 +194,11 @@ str_escape(JSContext* cx, unsigned argc, Value* vp) newChars = Escape(cx, str->twoByteChars(nogc), str->length(), &newLength); } - if (!newChars) + if (MOZ_UNLIKELY(!newChars)) return false; JSString* res = NewString(cx, newChars.get(), newLength); - if (!res) + if (MOZ_UNLIKELY(!res)) return false; newChars.forget(); @@ -277,7 +277,7 @@ Unescape(StringBuffer& sb, const mozilla::Range chars) do { \ if (!building) { \ building = true; \ - if (!sb.reserve(length)) \ + if (MOZ_UNLIKELY(!sb.reserve(length))) \ return false; \ sb.infallibleAppend(chars.start().get(), k); \ } \ @@ -302,7 +302,7 @@ Unescape(StringBuffer& sb, const mozilla::Range chars) } step_18: - if (building && !sb.append(c)) + if (building && MOZ_UNLIKELY(!sb.append(c))) return false; /* Step 19. */ @@ -326,23 +326,23 @@ str_unescape(JSContext* cx, unsigned argc, Value* vp) /* Step 3. */ StringBuffer sb(cx); - if (str->hasTwoByteChars() && !sb.ensureTwoByteChars()) + if (str->hasTwoByteChars() && MOZ_UNLIKELY(!sb.ensureTwoByteChars())) return false; if (str->hasLatin1Chars()) { AutoCheckCannotGC nogc; - if (!Unescape(sb, str->latin1Range(nogc))) + if (MOZ_UNLIKELY(!Unescape(sb, str->latin1Range(nogc)))) return false; } else { AutoCheckCannotGC nogc; - if (!Unescape(sb, str->twoByteRange(nogc))) + if (MOZ_UNLIKELY(!Unescape(sb, str->twoByteRange(nogc)))) return false; } JSLinearString* result; if (!sb.empty()) { result = sb.finishString(); - if (!result) + if (MOZ_UNLIKELY(!result)) return false; } else { result = str; @@ -389,7 +389,7 @@ str_enumerate(JSContext* cx, HandleObject obj) RootedValue value(cx); for (size_t i = 0, length = str->length(); i < length; i++) { JSString* str1 = NewDependentString(cx, str, i, 1); - if (!str1) + if (MOZ_UNLIKELY(!str1)) return false; value.setString(str1); if (!DefineElement(cx, obj, i, value, nullptr, nullptr, @@ -593,11 +593,11 @@ js::SubstringKernel(JSContext* cx, HandleString str, int32_t beginInt, int32_t l Rooted ropeRoot(cx, rope); RootedString lhs(cx, NewDependentString(cx, ropeRoot->leftChild(), begin, lhsLength)); - if (!lhs) + if (MOZ_UNLIKELY(!lhs)) return nullptr; RootedString rhs(cx, NewDependentString(cx, ropeRoot->rightChild(), 0, rhsLength)); - if (!rhs) + if (MOZ_UNLIKELY(!rhs)) return nullptr; return JSRope::new_(cx, lhs, rhs, len); @@ -715,7 +715,7 @@ static inline bool ToLowerCaseHelper(JSContext* cx, CallReceiver call) { RootedString str(cx, ThisToStringForStringProto(cx, call)); - if (MOZ_UNLIKELY(!str)) + if (!str) return false; JSLinearString* linear = str->ensureLinear(cx); @@ -829,14 +829,14 @@ ToUpperCase(JSContext* cx, JSLinearString* str) if (resultIsLatin1) { Latin1CharPtr buf = cx->make_pod_array(length + 1); - if (!buf) + if (MOZ_UNLIKELY(!buf)) return nullptr; ToUpperCaseImpl(buf.get(), chars, i, length); newChars.construct(Move(buf)); } else { TwoByteCharPtr buf = cx->make_pod_array(length + 1); - if (!buf) + if (MOZ_UNLIKELY(!buf)) return nullptr; ToUpperCaseImpl(buf.get(), chars, i, length); @@ -847,13 +847,13 @@ ToUpperCase(JSContext* cx, JSLinearString* str) JSString* res; if (newChars.constructed()) { res = NewStringDontDeflate(cx, newChars.ref().get(), length); - if (!res) + if (MOZ_UNLIKELY(!res)) return nullptr; newChars.ref().release(); } else { res = NewStringDontDeflate(cx, newChars.ref().get(), length); - if (!res) + if (MOZ_UNLIKELY(!res)) return nullptr; newChars.ref().release(); @@ -870,14 +870,14 @@ ToUpperCaseHelper(JSContext* cx, CallReceiver call) return false; JSLinearString* linear = str->ensureLinear(cx); - if (!linear) + if (MOZ_UNLIKELY(!linear)) return false; if (linear->hasLatin1Chars()) str = ToUpperCase(cx, linear); else str = ToUpperCase(cx, linear); - if (!str) + if (MOZ_UNLIKELY(!str)) return false; call.rval().setString(str); @@ -986,7 +986,7 @@ str_normalize(JSContext* cx, unsigned argc, Value* vp) // Step 8. AutoStableStringChars stableChars(cx); - if (!str->ensureFlat(cx) || !stableChars.initTwoByte(cx, str)) + if (MOZ_UNLIKELY(!str->ensureFlat(cx) || !stableChars.initTwoByte(cx, str))) return false; static const size_t INLINE_CAPACITY = 32; @@ -994,7 +994,7 @@ str_normalize(JSContext* cx, unsigned argc, Value* vp) const UChar* srcChars = Char16ToUChar(stableChars.twoByteRange().start().get()); int32_t srcLen = AssertedCast(str->length()); Vector chars(cx); - if (!chars.resize(INLINE_CAPACITY)) + if (MOZ_UNLIKELY(!chars.resize(INLINE_CAPACITY))) return false; UErrorCode status = U_ZERO_ERROR; @@ -1002,7 +1002,7 @@ str_normalize(JSContext* cx, unsigned argc, Value* vp) Char16ToUChar(chars.begin()), INLINE_CAPACITY, &status); if (status == U_BUFFER_OVERFLOW_ERROR) { - if (!chars.resize(size)) + if (MOZ_UNLIKELY(!chars.resize(size))) return false; status = U_ZERO_ERROR; #ifdef DEBUG @@ -1017,7 +1017,7 @@ str_normalize(JSContext* cx, unsigned argc, Value* vp) return false; JSString* ns = NewStringCopyN(cx, chars.begin(), size); - if (!ns) + if (MOZ_UNLIKELY(!ns)) return false; // Step 9. @@ -1053,7 +1053,7 @@ js::str_charAt(JSContext* cx, unsigned argc, Value* vp) } str = cx->staticStrings().getUnitStringForElement(cx, str, i); - if (!str) + if (MOZ_UNLIKELY(!str)) return false; args.rval().setString(str); return true; @@ -1082,7 +1082,7 @@ js::str_charCodeAt_impl(JSContext* cx, HandleString string, HandleValue index, M i = size_t(d); } char16_t c; - if (!string->getChar(cx, i , &c)) + if (MOZ_UNLIKELY(!string->getChar(cx, i , &c))) return false; res.setInt32(c); return true; @@ -1378,7 +1378,7 @@ class StringSegmentRange bool settle(JSString* str) { while (str->isRope()) { JSRope& rope = str->asRope(); - if (!stack.append(rope.rightChild())) + if (MOZ_UNLIKELY(!stack.append(rope.rightChild()))) return false; str = rope.leftChild(); } @@ -1521,7 +1521,7 @@ RopeMatch(JSContext* cx, JSRope* text, JSLinearString* pat, int* match) !strings.append(r.front())) { JSLinearString* linear = text->ensureLinear(cx); - if (!linear) + if (MOZ_UNLIKELY(!linear)) return false; *match = StringMatch(linear, pat); @@ -1598,7 +1598,7 @@ str_includes(JSContext* cx, unsigned argc, Value* vp) // Steps 13 and 14 JSLinearString* text = str->ensureLinear(cx); - if (!text) + if (MOZ_UNLIKELY(!text)) return false; args.rval().setBoolean(StringMatch(text, searchStr, start) != -1); @@ -1663,7 +1663,7 @@ js::str_indexOf(JSContext* cx, unsigned argc, Value* vp) // Steps 10 and 11 JSLinearString* text = str->ensureLinear(cx); - if (!text) + if (MOZ_UNLIKELY(!text)) return false; args.rval().setInt32(StringMatch(text, searchStr, start)); @@ -1751,7 +1751,7 @@ js::str_lastIndexOf(JSContext* cx, unsigned argc, Value* vp) } JSLinearString* text = textstr->ensureLinear(cx); - if (!text) + if (MOZ_UNLIKELY(!text)) return false; int32_t res; @@ -1856,7 +1856,7 @@ js::str_startsWith(JSContext* cx, unsigned argc, Value* vp) // Steps 15 and 16 JSLinearString* text = str->ensureLinear(cx); - if (!text) + if (MOZ_UNLIKELY(!text)) return false; args.rval().setBoolean(HasSubstringAt(text, searchStr, start)); @@ -1925,7 +1925,7 @@ str_endsWith(JSContext* cx, unsigned argc, Value* vp) // Steps 16 and 17 JSLinearString* text = str->ensureLinear(cx); - if (!text) + if (MOZ_UNLIKELY(!text)) return false; args.rval().setBoolean(HasSubstringAt(text, searchStr, start)); @@ -1962,7 +1962,7 @@ TrimString(JSContext* cx, Value* vp, bool trimLeft, bool trimRight) return false; JSLinearString* linear = str->ensureLinear(cx); - if (!linear) + if (MOZ_UNLIKELY(!linear)) return false; size_t length = linear->length(); @@ -1976,7 +1976,7 @@ TrimString(JSContext* cx, Value* vp, bool trimLeft, bool trimRight) } str = NewDependentString(cx, str, begin, end - begin); - if (!str) + if (MOZ_UNLIKELY(!str)) return false; call.rval().setString(str); @@ -2097,10 +2097,10 @@ class MOZ_STACK_CLASS StringRegExpGuard static const char ESCAPE_CHAR = '\\'; for (const CharT* it = chars; it < chars + len; ++it) { if (IsRegExpMetaChar(*it)) { - if (!sb.append(ESCAPE_CHAR) || !sb.append(*it)) + if (MOZ_UNLIKELY(!sb.append(ESCAPE_CHAR) || !sb.append(*it))) return false; } else { - if (!sb.append(*it)) + if (MOZ_UNLIKELY(!sb.append(*it))) return false; } } @@ -2111,7 +2111,7 @@ class MOZ_STACK_CLASS StringRegExpGuard flattenPattern(JSContext* cx, JSAtom* pat) { StringBuffer sb(cx); - if (!sb.reserve(pat->length())) + if (MOZ_UNLIKELY(!sb.reserve(pat->length()))) return nullptr; if (pat->hasLatin1Chars()) { @@ -2425,7 +2425,7 @@ DoMatchGlobal(JSContext* cx, const CallArgs& args, RegExpStatics* res, HandleLin // Step 8f(iii)(4-5). JSLinearString* str = NewDependentString(cx, input, match.start, match.length()); - if (!str) + if (MOZ_UNLIKELY(!str)) return false; if (!elements.append(StringValue(str))) return false; @@ -2444,7 +2444,7 @@ DoMatchGlobal(JSContext* cx, const CallArgs& args, RegExpStatics* res, HandleLin // Steps 8b, 8f(iii)(5-6), 8h. JSObject* array = NewDenseCopiedArray(cx, elements.length(), elements.begin()); - if (!array) + if (MOZ_UNLIKELY(!array)) return false; args.rval().setObject(*array); @@ -2465,7 +2465,7 @@ BuildFlatMatchArray(JSContext* cx, HandleString textstr, const FlatMatch& fm, Ca return false; RootedArrayObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, 1, templateObject)); - if (!arr) + if (MOZ_UNLIKELY(!arr)) return false; /* Store a Value for each pair. */ @@ -2523,11 +2523,11 @@ js::str_match(JSContext* cx, unsigned argc, Value* vp) return false; RegExpStatics* res = cx->global()->getRegExpStatics(cx); - if (!res) + if (MOZ_UNLIKELY(!res)) return false; RootedLinearString linearStr(cx, str->ensureLinear(cx)); - if (!linearStr) + if (MOZ_UNLIKELY(!linearStr)) return false; /* Steps 5-6, 7. */ @@ -2561,11 +2561,11 @@ js::str_search(JSContext* cx, unsigned argc, Value* vp) return false; RootedLinearString linearStr(cx, str->ensureLinear(cx)); - if (!linearStr) + if (MOZ_UNLIKELY(!linearStr)) return false; RegExpStatics* res = cx->global()->getRegExpStatics(cx); - if (!res) + if (MOZ_UNLIKELY(!res)) return false; /* Per ECMAv5 15.5.4.12 (5) The last index property is ignored and left unchanged. */ @@ -2810,7 +2810,7 @@ FindReplaceLengthString(JSContext* cx, RegExpStatics* res, ReplaceData& rdata, s } while (dp); } - if (!replen.isValid()) { + if (MOZ_UNLIKELY(!replen.isValid())) { ReportAllocationOverflow(cx); return false; } @@ -2843,7 +2843,7 @@ FindReplaceLength(JSContext* cx, RegExpStatics* res, ReplaceData& rdata, size_t* RootedValue v(cx); if (HasDataProperty(cx, rdata.elembase, AtomToId(atom), v.address()) && v.isString()) { rdata.repstr = v.toString()->ensureLinear(cx); - if (!rdata.repstr) + if (MOZ_UNLIKELY(!rdata.repstr)) return false; *sizep = rdata.repstr->length(); return true; @@ -2899,7 +2899,7 @@ FindReplaceLength(JSContext* cx, RegExpStatics* res, ReplaceData& rdata, size_t* if (!repstr) return false; rdata.repstr = repstr->ensureLinear(cx); - if (!rdata.repstr) + if (MOZ_UNLIKELY(!rdata.repstr)) return false; *sizep = rdata.repstr->length(); return true; @@ -2970,7 +2970,7 @@ ReplaceRegExp(JSContext* cx, RegExpStatics* res, ReplaceData& rdata) CheckedInt newlen(rdata.sb.length()); newlen += leftlen; newlen += replen; - if (!newlen.isValid()) { + if (MOZ_UNLIKELY(!newlen.isValid())) { ReportAllocationOverflow(cx); return false; } @@ -2981,11 +2981,11 @@ ReplaceRegExp(JSContext* cx, RegExpStatics* res, ReplaceData& rdata) */ JSLinearString& str = rdata.str->asLinear(); /* flattened for regexp */ if (str.hasTwoByteChars() || rdata.repstr->hasTwoByteChars()) { - if (!rdata.sb.ensureTwoByteChars()) + if (MOZ_UNLIKELY(!rdata.sb.ensureTwoByteChars())) return false; } - if (!rdata.sb.reserve(newlen.value())) + if (MOZ_UNLIKELY(!rdata.sb.reserve(newlen.value()))) return false; /* Append skipped-over portion of the search value. */ @@ -3033,9 +3033,9 @@ BuildFlatReplacement(JSContext* cx, HandleString textstr, HandleString repstr, * replacement string here. */ RootedString leftSide(cx, NewDependentString(cx, str, 0, match - pos)); - if (!leftSide || + if (MOZ_UNLIKELY(!leftSide || !builder.append(leftSide) || - !builder.append(repstr)) + !builder.append(repstr))) { return nullptr; } @@ -3048,11 +3048,11 @@ BuildFlatReplacement(JSContext* cx, HandleString textstr, HandleString repstr, if (strEnd > matchEnd) { RootedString rightSide(cx, NewDependentString(cx, str, matchEnd - pos, strEnd - matchEnd)); - if (!rightSide || !builder.append(rightSide)) + if (MOZ_UNLIKELY(!rightSide || !builder.append(rightSide))) return nullptr; } } else { - if (!builder.append(str)) + if (MOZ_UNLIKELY(!builder.append(str))) return nullptr; } pos += str->length(); @@ -3061,15 +3061,15 @@ BuildFlatReplacement(JSContext* cx, HandleString textstr, HandleString repstr, } } else { RootedString leftSide(cx, NewDependentString(cx, textstr, 0, match)); - if (!leftSide) + if (MOZ_UNLIKELY(!leftSide)) return nullptr; RootedString rightSide(cx); rightSide = NewDependentString(cx, textstr, match + fm.patternLength(), textstr->length() - match - fm.patternLength()); - if (!rightSide || + if (MOZ_UNLIKELY(!rightSide || !builder.append(leftSide) || !builder.append(repstr) || - !builder.append(rightSide)) + !builder.append(rightSide))) { return nullptr; } @@ -3096,30 +3096,30 @@ AppendDollarReplacement(StringBuffer& newReplaceChars, size_t firstDollarIndex, const CharT* repLimit = repChars + repLength; for (const CharT* it = repChars + firstDollarIndex; it < repLimit; ++it) { if (*it != '$' || it == repLimit - 1) { - if (!newReplaceChars.append(*it)) + if (MOZ_UNLIKELY(!newReplaceChars.append(*it))) return false; continue; } switch (*(it + 1)) { case '$': /* Eat one of the dollars. */ - if (!newReplaceChars.append(*it)) + if (MOZ_UNLIKELY(!newReplaceChars.append(*it))) return false; break; case '&': - if (!newReplaceChars.appendSubstring(text, matchStart, matchLimit - matchStart)) + if (MOZ_UNLIKELY(!newReplaceChars.appendSubstring(text, matchStart, matchLimit - matchStart))) return false; break; case '`': - if (!newReplaceChars.appendSubstring(text, 0, matchStart)) + if (MOZ_UNLIKELY(!newReplaceChars.appendSubstring(text, 0, matchStart))) return false; break; case '\'': - if (!newReplaceChars.appendSubstring(text, matchLimit, text->length() - matchLimit)) + if (MOZ_UNLIKELY(!newReplaceChars.appendSubstring(text, matchLimit, text->length() - matchLimit))) return false; break; default: /* The dollar we saw was not special (no matter what its mother told it). */ - if (!newReplaceChars.append(*it)) + if (MOZ_UNLIKELY(!newReplaceChars.append(*it))) return false; continue; } @@ -3140,7 +3140,7 @@ BuildDollarReplacement(JSContext* cx, JSString* textstrArg, JSLinearString* reps uint32_t firstDollarIndex, const FlatMatch& fm) { RootedLinearString textstr(cx, textstrArg->ensureLinear(cx)); - if (!textstr) + if (MOZ_UNLIKELY(!textstr)) return nullptr; size_t matchStart = fm.match(); @@ -3154,10 +3154,10 @@ BuildDollarReplacement(JSContext* cx, JSString* textstrArg, JSLinearString* reps * Note that dollar vars _could_ make the resulting text smaller than this. */ StringBuffer newReplaceChars(cx); - if (repstr->hasTwoByteChars() && !newReplaceChars.ensureTwoByteChars()) + if (repstr->hasTwoByteChars() && MOZ_UNLIKELY(!newReplaceChars.ensureTwoByteChars())) return nullptr; - if (!newReplaceChars.reserve(textstr->length() - fm.patternLength() + repstr->length())) + if (MOZ_UNLIKELY(!newReplaceChars.reserve(textstr->length() - fm.patternLength() + repstr->length()))) return nullptr; bool res; @@ -3174,21 +3174,21 @@ BuildDollarReplacement(JSContext* cx, JSString* textstrArg, JSLinearString* reps return nullptr; RootedString leftSide(cx, NewDependentString(cx, textstr, 0, matchStart)); - if (!leftSide) + if (MOZ_UNLIKELY(!leftSide)) return nullptr; RootedString newReplace(cx, newReplaceChars.finishString()); - if (!newReplace) + if (MOZ_UNLIKELY(!newReplace)) return nullptr; MOZ_ASSERT(textstr->length() >= matchLimit); RootedString rightSide(cx, NewDependentString(cx, textstr, matchLimit, textstr->length() - matchLimit)); - if (!rightSide) + if (MOZ_UNLIKELY(!rightSide)) return nullptr; RopeBuilder builder(cx); - if (!builder.append(leftSide) || !builder.append(newReplace) || !builder.append(rightSide)) + if (MOZ_UNLIKELY(!builder.append(leftSide) || !builder.append(newReplace) || !builder.append(rightSide))) return nullptr; return builder.result(); @@ -3225,7 +3225,7 @@ FlattenSubstrings(JSContext* cx, HandleLinearString str, const StringRange* rang size_t rangesLen, size_t outputLen) { JSFatInlineString* result = Allocate(cx); - if (!result) + if (MOZ_UNLIKELY(!result)) return nullptr; AutoCheckCannotGC nogc; @@ -3276,11 +3276,11 @@ AppendSubstrings(JSContext* cx, HandleLinearString str, const StringRange* range i = end; } - if (!part) + if (MOZ_UNLIKELY(!part)) return nullptr; /* Appending to the rope permanently roots the substring. */ - if (!rope.append(part)) + if (MOZ_UNLIKELY(!rope.append(part))) return nullptr; } @@ -3291,7 +3291,7 @@ static JSString* StrReplaceRegexpRemove(JSContext* cx, HandleString str, RegExpShared& re) { RootedLinearString linearStr(cx, str->ensureLinear(cx)); - if (!linearStr) + if (MOZ_UNLIKELY(!linearStr)) return nullptr; Vector ranges; @@ -3318,7 +3318,7 @@ StrReplaceRegexpRemove(JSContext* cx, HandleString str, RegExpShared& re) /* Include the latest unmatched substring. */ if (size_t(match.start) > lastIndex) { - if (!ranges.append(StringRange(lastIndex, match.start - lastIndex))) + if (MOZ_UNLIKELY(!ranges.append(StringRange(lastIndex, match.start - lastIndex)))) return nullptr; } @@ -3340,7 +3340,7 @@ StrReplaceRegexpRemove(JSContext* cx, HandleString str, RegExpShared& re) if (!lastIndex) { if (startIndex > 0) { res = cx->global()->getRegExpStatics(cx); - if (!res) + if (MOZ_UNLIKELY(!res)) return nullptr; res->updateLazily(cx, linearStr, &re, lazyIndex); } @@ -3350,14 +3350,14 @@ StrReplaceRegexpRemove(JSContext* cx, HandleString str, RegExpShared& re) /* The last successful match updates the RegExpStatics. */ res = cx->global()->getRegExpStatics(cx); - if (!res) + if (MOZ_UNLIKELY(!res)) return nullptr; res->updateLazily(cx, linearStr, &re, lazyIndex); /* Include any remaining part of the string. */ if (lastIndex < charsLen) { - if (!ranges.append(StringRange(lastIndex, charsLen - lastIndex))) + if (MOZ_UNLIKELY(!ranges.append(StringRange(lastIndex, charsLen - lastIndex)))) return nullptr; } @@ -3375,7 +3375,7 @@ StrReplaceRegExp(JSContext* cx, ReplaceData& rdata) rdata.calledBack = false; RegExpStatics* res = cx->global()->getRegExpStatics(cx); - if (!res) + if (MOZ_UNLIKELY(!res)) return nullptr; RegExpShared& re = rdata.g.regExp(); @@ -3396,7 +3396,7 @@ StrReplaceRegExp(JSContext* cx, ReplaceData& rdata) } RootedLinearString linearStr(cx, rdata.str->ensureLinear(cx)); - if (!linearStr) + if (MOZ_UNLIKELY(!linearStr)) return nullptr; size_t rightContextOffset = 0; @@ -3415,7 +3415,7 @@ StrReplaceRegExp(JSContext* cx, ReplaceData& rdata) MOZ_ASSERT(rightContextOffset <= rdata.str->length()); size_t length = rdata.str->length() - rightContextOffset; - if (!rdata.sb.appendSubstring(rdata.str, rightContextOffset, length)) + if (MOZ_UNLIKELY(!rdata.sb.appendSubstring(rdata.str, rightContextOffset, length))) return nullptr; return rdata.sb.finishString(); @@ -3442,7 +3442,7 @@ js::str_replace_regexp_raw(JSContext* cx, HandleString string, Handlelength() == 0) { StringRegExpGuard guard(cx); - if (!guard.initRegExp(cx, regexp)) + if (MOZ_UNLIKELY(!guard.initRegExp(cx, regexp))) return nullptr; RegExpShared& re = guard.regExp(); @@ -3453,12 +3453,12 @@ js::str_replace_regexp_raw(JSContext* cx, HandleString string, HandleensureLinear(cx); - if (!repl) + if (MOZ_UNLIKELY(!repl)) return nullptr; rdata.setReplacementString(repl); - if (!rdata.g.initRegExp(cx, regexp)) + if (MOZ_UNLIKELY(!rdata.g.initRegExp(cx, regexp))) return nullptr; return StrReplaceRegExp(cx, rdata); @@ -3493,12 +3493,12 @@ StrFlatReplaceGlobal(JSContext *cx, JSLinearString *str, JSLinearString *pat, JS CheckedInt strLength(str->length()); CheckedInt repLength(rep->length()); CheckedInt length = repLength * (strLength - 1) + strLength; - if (!length.isValid()) { + if (MOZ_UNLIKELY(!length.isValid())) { ReportAllocationOverflow(cx); return false; } - if (!sb.reserve(length.value())) + if (MOZ_UNLIKELY(!sb.reserve(length.value()))) return false; for (unsigned i = 0; i < str->length() - 1; ++i, ++strChars) { @@ -3512,7 +3512,7 @@ StrFlatReplaceGlobal(JSContext *cx, JSLinearString *str, JSLinearString *pat, JS // If it's true, we are sure that the result's length is, at least, the same // length as |str->length()|. if (rep->length() >= pat->length()) { - if (!sb.reserve(str->length())) + if (MOZ_UNLIKELY(!sb.reserve(str->length()))) return false; } @@ -3521,14 +3521,14 @@ StrFlatReplaceGlobal(JSContext *cx, JSLinearString *str, JSLinearString *pat, JS int match = StringMatch(str, pat, start); if (match < 0) break; - if (!sb.append(strChars + start, match - start)) + if (MOZ_UNLIKELY(!sb.append(strChars + start, match - start))) return false; - if (!sb.append(repChars, rep->length())) + if (MOZ_UNLIKELY(!sb.append(repChars, rep->length()))) return false; start = match + pat->length(); } - if (!sb.append(strChars + start, str->length() - start)) + if (MOZ_UNLIKELY(!sb.append(strChars + start, str->length() - start))) return false; return true; @@ -3548,20 +3548,20 @@ js::str_flat_replace_string(JSContext *cx, HandleString string, HandleString pat return string; RootedLinearString linearRepl(cx, replacement->ensureLinear(cx)); - if (!linearRepl) + if (MOZ_UNLIKELY(!linearRepl)) return nullptr; RootedLinearString linearPat(cx, pattern->ensureLinear(cx)); - if (!linearPat) + if (MOZ_UNLIKELY(!linearPat)) return nullptr; RootedLinearString linearStr(cx, string->ensureLinear(cx)); - if (!linearStr) + if (MOZ_UNLIKELY(!linearStr)) return nullptr; StringBuffer sb(cx); if (linearStr->hasTwoByteChars()) { - if (!sb.ensureTwoByteChars()) + if (MOZ_UNLIKELY(!sb.ensureTwoByteChars())) return nullptr; if (linearRepl->hasTwoByteChars()) { if (!StrFlatReplaceGlobal(cx, linearStr, linearPat, linearRepl, sb)) @@ -3572,7 +3572,7 @@ js::str_flat_replace_string(JSContext *cx, HandleString string, HandleString pat } } else { if (linearRepl->hasTwoByteChars()) { - if (!sb.ensureTwoByteChars()) + if (MOZ_UNLIKELY(!sb.ensureTwoByteChars())) return nullptr; if (!StrFlatReplaceGlobal(cx, linearStr, linearPat, linearRepl, sb)) return nullptr; @@ -3583,7 +3583,7 @@ js::str_flat_replace_string(JSContext *cx, HandleString string, HandleString pat } JSString *str = sb.finishString(); - if (!str) + if (MOZ_UNLIKELY(!str)) return nullptr; return str; @@ -3599,11 +3599,11 @@ js::str_replace_string_raw(JSContext* cx, HandleString string, HandleString patt rdata.str = string; JSLinearString* repl = replacement->ensureLinear(cx); - if (!repl) + if (MOZ_UNLIKELY(!repl)) return nullptr; rdata.setReplacementString(repl); - if (!rdata.g.init(cx, pattern)) + if (MOZ_UNLIKELY(!rdata.g.init(cx, pattern))) return nullptr; const FlatMatch* fm = rdata.g.tryFlatMatch(cx, rdata.str, ReplaceOptArg, ReplaceOptArg, false); @@ -3618,7 +3618,7 @@ str_replace_flat_lambda(JSContext* cx, const CallArgs& outerArgs, ReplaceData& r const FlatMatch& fm) { RootedString matchStr(cx, NewDependentString(cx, rdata.str, fm.match(), fm.patternLength())); - if (!matchStr) + if (MOZ_UNLIKELY(!matchStr)) return false; /* lambda(matchStr, matchStart, textstr) */ @@ -3643,19 +3643,19 @@ str_replace_flat_lambda(JSContext* cx, const CallArgs& outerArgs, ReplaceData& r return false; RootedString leftSide(cx, NewDependentString(cx, rdata.str, 0, fm.match())); - if (!leftSide) + if (MOZ_UNLIKELY(!leftSide)) return false; size_t matchLimit = fm.match() + fm.patternLength(); RootedString rightSide(cx, NewDependentString(cx, rdata.str, matchLimit, rdata.str->length() - matchLimit)); - if (!rightSide) + if (MOZ_UNLIKELY(!rightSide)) return false; RopeBuilder builder(cx); - if (!(builder.append(leftSide) && + if (MOZ_UNLIKELY(!(builder.append(leftSide) && builder.append(repstr) && - builder.append(rightSide))) { + builder.append(rightSide)))) { return false; } @@ -3900,7 +3900,7 @@ SplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, const Matcher /* Steps 13(c)(iii)(1-3). */ size_t subLength = size_t(endIndex - sepLength - lastEndIndex); JSString* sub = NewDependentString(cx, str, lastEndIndex, subLength); - if (!sub || !splits.append(StringValue(sub))) + if (MOZ_UNLIKELY(!sub || !splits.append(StringValue(sub)))) return nullptr; /* Step 13(c)(iii)(4). */ @@ -3913,7 +3913,7 @@ SplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, const Matcher /* Step 13(c)(iii)(6-7). */ if (Matcher::returnsCaptures) { RegExpStatics* res = cx->global()->getRegExpStatics(cx); - if (!res) + if (MOZ_UNLIKELY(!res)) return nullptr; const MatchPairs& matches = res->getMatches(); @@ -3923,10 +3923,10 @@ SplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, const Matcher JSSubString parsub; res->getParen(i + 1, &parsub); sub = NewDependentString(cx, parsub.base, parsub.offset, parsub.length); - if (!sub || !splits.append(StringValue(sub))) + if (MOZ_UNLIKELY(!sub || !splits.append(StringValue(sub)))) return nullptr; } else { - if (!splits.append(UndefinedValue())) + if (MOZ_UNLIKELY(!splits.append(UndefinedValue()))) return nullptr; } @@ -3942,7 +3942,7 @@ SplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, const Matcher /* Steps 14-15. */ JSString* sub = NewDependentString(cx, str, lastEndIndex, strLength - lastEndIndex); - if (!sub || !splits.append(StringValue(sub))) + if (MOZ_UNLIKELY(!sub || !splits.append(StringValue(sub)))) return nullptr; /* Step 16. */ @@ -3961,12 +3961,12 @@ CharSplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, HandleObj uint32_t resultlen = (limit < strLength ? limit : strLength); AutoValueVector splits(cx); - if (!splits.reserve(resultlen)) + if (MOZ_UNLIKELY(!splits.reserve(resultlen))) return nullptr; for (size_t i = 0; i < resultlen; ++i) { JSString* sub = staticStrings.getUnitStringForElement(cx, str, i); - if (!sub) + if (MOZ_UNLIKELY(!sub)) return nullptr; splits.infallibleAppend(StringValue(sub)); } @@ -4107,7 +4107,7 @@ js::str_split(JSContext* cx, unsigned argc, Value* vp) return true; } RootedLinearString linearStr(cx, str->ensureLinear(cx)); - if (!linearStr) + if (MOZ_UNLIKELY(!linearStr)) return false; /* Steps 11-15. */ @@ -4121,7 +4121,7 @@ js::str_split(JSContext* cx, unsigned argc, Value* vp) } } else { RegExpStatics* res = cx->global()->getRegExpStatics(cx); - if (!res) + if (MOZ_UNLIKELY(!res)) return false; SplitRegExpMatcher matcher(*re, res); aobj = SplitHelper(cx, linearStr, limit, matcher, group, re->unicode()); @@ -4139,11 +4139,11 @@ JSObject* js::str_split_string(JSContext* cx, HandleObjectGroup group, HandleString str, HandleString sep) { RootedLinearString linearStr(cx, str->ensureLinear(cx)); - if (!linearStr) + if (MOZ_UNLIKELY(!linearStr)) return nullptr; RootedLinearString linearSep(cx, sep->ensureLinear(cx)); - if (!linearSep) + if (MOZ_UNLIKELY(!linearSep)) return nullptr; uint32_t limit = UINT32_MAX; @@ -4304,7 +4304,7 @@ str_fromCharCode_few_args(JSContext* cx, const CallArgs& args) chars[i] = char16_t(code); } JSString* str = NewStringCopyN(cx, chars, args.length()); - if (!str) + if (MOZ_UNLIKELY(!str)) return false; args.rval().setString(str); return true; @@ -4330,7 +4330,7 @@ js::str_fromCharCode(JSContext* cx, unsigned argc, Value* vp) return str_fromCharCode_few_args(cx, args); char16_t* chars = cx->pod_malloc(args.length() + 1); - if (!chars) + if (MOZ_UNLIKELY(!chars)) return false; for (unsigned i = 0; i < args.length(); i++) { uint16_t code; @@ -4366,7 +4366,7 @@ js::str_fromCharCode_one_arg(JSContext* cx, HandleValue code, MutableHandleValue char16_t c = char16_t(ucode); JSString* str = NewStringCopyN(cx, &c, 1); - if (!str) + if (MOZ_UNLIKELY(!str)) return false; rval.setString(str); @@ -4408,24 +4408,24 @@ js::InitStringClass(JSContext* cx, HandleObject obj) Rooted empty(cx, cx->runtime()->emptyString); RootedObject proto(cx, global->createBlankPrototype(cx, &StringObject::class_)); - if (!proto || !proto->as().init(cx, empty)) + if (MOZ_UNLIKELY(!proto || !proto->as().init(cx, empty))) return nullptr; /* Now create the String function. */ RootedFunction ctor(cx); ctor = global->createConstructor(cx, StringConstructor, cx->names().String, 1, AllocKind::FUNCTION, &jit::JitInfo_String); - if (!ctor) + if (MOZ_UNLIKELY(!ctor)) return nullptr; - if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_String, ctor, proto)) + if (MOZ_UNLIKELY(!GlobalObject::initBuiltinConstructor(cx, global, JSProto_String, ctor, proto))) return nullptr; - if (!LinkConstructorAndPrototype(cx, ctor, proto)) + if (MOZ_UNLIKELY(!LinkConstructorAndPrototype(cx, ctor, proto))) return nullptr; - if (!DefinePropertiesAndFunctions(cx, proto, nullptr, string_methods) || - !DefinePropertiesAndFunctions(cx, ctor, nullptr, string_static_methods)) + if (MOZ_UNLIKELY(!DefinePropertiesAndFunctions(cx, proto, nullptr, string_methods) || + !DefinePropertiesAndFunctions(cx, ctor, nullptr, string_static_methods))) { return nullptr; } @@ -4434,7 +4434,7 @@ js::InitStringClass(JSContext* cx, HandleObject obj) * Define escape/unescape, the URI encode/decode functions, and maybe * uneval on the global object. */ - if (!JS_DefineFunctions(cx, global, string_functions)) + if (MOZ_UNLIKELY(!JS_DefineFunctions(cx, global, string_functions))) return nullptr; return proto; @@ -4613,10 +4613,10 @@ js::EqualStrings(JSContext* cx, JSString* str1, JSString* str2, bool* result) } JSLinearString* linear1 = str1->ensureLinear(cx); - if (!linear1) + if (MOZ_UNLIKELY(!linear1)) return false; JSLinearString* linear2 = str2->ensureLinear(cx); - if (!linear2) + if (MOZ_UNLIKELY(!linear2)) return false; *result = EqualChars(linear1, linear2); @@ -4677,11 +4677,11 @@ js::CompareStrings(JSContext* cx, JSString* str1, JSString* str2, int32_t* resul } JSLinearString* linear1 = str1->ensureLinear(cx); - if (!linear1) + if (MOZ_UNLIKELY(!linear1)) return false; JSLinearString* linear2 = str2->ensureLinear(cx); - if (!linear2) + if (MOZ_UNLIKELY(!linear2)) return false; *result = CompareStringsImpl(linear1, linear2); @@ -4762,7 +4762,7 @@ js::DuplicateString(const char16_t* s) { size_t n = js_strlen(s) + 1; UniquePtr ret(js_pod_malloc(n)); - if (!ret) + if (MOZ_UNLIKELY(!ret)) return nullptr; PodCopy(ret.get(), s, n); return ret; @@ -4809,7 +4809,7 @@ js::InflateString(ExclusiveContext* cx, const char* bytes, size_t* lengthp) nchars = nbytes; chars = cx->pod_malloc(nchars + 1); - if (!chars) + if (MOZ_UNLIKELY(!chars)) goto bad; for (size_t i = 0; i < nchars; i++) chars[i] = (unsigned char) bytes[i]; @@ -4994,7 +4994,7 @@ static inline bool TransferBufferToString(StringBuffer& sb, MutableHandleValue rval) { JSString* str = sb.finishString(); - if (!str) + if (MOZ_UNLIKELY(!str)) return false; rval.setString(str); return true; @@ -5068,7 +5068,7 @@ Encode(JSContext* cx, HandleLinearString str, const bool* unescapedSet, } StringBuffer sb(cx); - if (!sb.reserve(length)) + if (MOZ_UNLIKELY(!sb.reserve(length))) return false; EncodeResult res; From 33abf8f1cbced554c38d63a707776fe305c260b3 Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Sat, 10 Feb 2018 17:56:28 -0800 Subject: [PATCH 07/11] #465: jsarray.cpp --- js/src/jsarray.cpp | 88 +++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 05849cd3c..f772a3167 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -328,7 +328,7 @@ js::GetElementsWithAdder(JSContext* cx, HandleObject obj, HandleObject receiver, if (!GetElement(cx, obj, receiver, i, &val)) return false; } - if (!adder->append(cx, val)) + if (MOZ_UNLIKELY(!adder->append(cx, val))) return false; } @@ -715,7 +715,7 @@ js::ArraySetLength(JSContext* cx, Handle arr, HandleId id, // We should use radix sort to be O(n), but this is uncommon // enough that we'll punt til someone complains. Vector scratch(cx); - if (!scratch.resize(count)) + if (MOZ_UNLIKELY(!scratch.resize(count))) return false; MOZ_ALWAYS_TRUE(MergeSort(indexes.begin(), count, scratch.begin(), ReverseIndexComparator())); @@ -1101,19 +1101,19 @@ js::ArrayJoin(JSContext* cx, HandleObject obj, HandleLinearString sepstr, uint32 } StringBuffer sb(cx); - if (sepstr->hasTwoByteChars() && !sb.ensureTwoByteChars()) + if (sepstr->hasTwoByteChars() && MOZ_UNLIKELY(!sb.ensureTwoByteChars())) return nullptr; // The separator will be added |length - 1| times, reserve space for that // so that we don't have to unnecessarily grow the buffer. size_t seplen = sepstr->length(); CheckedInt res = CheckedInt(seplen) * (length - 1); - if (length > 0 && !res.isValid()) { + if (length > 0 && MOZ_UNLIKELY(!res.isValid())) { ReportAllocationOverflow(cx); return nullptr; } - if (length > 0 && !sb.reserve(res.value())) + if (length > 0 && MOZ_UNLIKELY(!sb.reserve(res.value()))) return nullptr; // Various optimized versions of steps 7-10. @@ -1172,7 +1172,7 @@ ArrayJoin(JSContext* cx, CallArgs& args) if (!s) return false; sepstr = s->ensureLinear(cx); - if (!sepstr) + if (MOZ_UNLIKELY(!sepstr)) return false; } else { sepstr = cx->names().comma; @@ -1850,7 +1850,7 @@ js::array_sort(JSContext* cx, unsigned argc, Value* vp) * malloc'd vector. */ #if JS_BITS_PER_WORD == 32 - if (size_t(len) > size_t(-1) / (2 * sizeof(Value))) { + if (MOZ_UNLIKELY(size_t(len) > size_t(-1) / (2 * sizeof(Value)))) { ReportAllocationOverflow(cx); return false; } @@ -1868,7 +1868,7 @@ js::array_sort(JSContext* cx, unsigned argc, Value* vp) size_t n, undefs; { AutoValueVector vec(cx); - if (!vec.reserve(2 * size_t(len))) + if (MOZ_UNLIKELY(!vec.reserve(2 * size_t(len)))) return false; /* @@ -1997,7 +1997,7 @@ js::NewbornArrayPush(JSContext* cx, HandleObject obj, const Value& v) uint32_t length = arr->length(); MOZ_ASSERT(length <= arr->getDenseCapacity()); - if (!arr->ensureElements(cx, length + 1)) + if (MOZ_UNLIKELY(!arr->ensureElements(cx, length + 1))) return false; arr->setDenseInitializedLength(length + 1); @@ -2137,7 +2137,7 @@ ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval) return DenseElementResult::Incomplete; RootedObjectGroup group(cx, obj->getGroup(cx)); - if (MOZ_UNLIKELY(!group)) + if (!group) return DenseElementResult::Failure; if (MOZ_UNLIKELY(group->hasAllFlags(OBJECT_FLAG_ITERATED))) @@ -2411,7 +2411,7 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI if (CanOptimizeForDenseStorage(obj, actualStart, actualDeleteCount, cx)) { if (returnValueIsUsed) { arr = NewFullyAllocatedArrayTryReuseGroup(cx, obj, actualDeleteCount); - if (!arr) + if (MOZ_UNLIKELY(!arr)) return false; DebugOnly result = CopyAnyBoxedOrUnboxedDenseElements(cx, arr, obj, 0, actualStart, actualDeleteCount); @@ -2419,7 +2419,7 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI } } else { arr = NewFullyAllocatedArrayTryReuseGroup(cx, obj, actualDeleteCount); - if (!arr) + if (MOZ_UNLIKELY(!arr)) return false; RootedValue fromValue(cx); @@ -2645,7 +2645,7 @@ js::array_concat(JSContext* cx, unsigned argc, Value* vp) size_t initlen = GetAnyBoxedOrUnboxedInitializedLength(aobj); narr = NewFullyAllocatedArrayTryReuseGroup(cx, aobj, initlen); - if (!narr) + if (MOZ_UNLIKELY(!narr)) return false; CopyAnyBoxedOrUnboxedDenseElements(cx, narr, aobj, 0, 0, initlen); SetAnyBoxedOrUnboxedArrayLength(cx, narr, length); @@ -2709,7 +2709,7 @@ js::array_concat(JSContext* cx, unsigned argc, Value* vp) } } else { narr = NewFullyAllocatedArrayTryReuseGroup(cx, aobj, 0); - if (!narr) + if (MOZ_UNLIKELY(!narr)) return false; args.rval().setObject(*narr); length = 0; @@ -2791,7 +2791,7 @@ GetIndexedPropertiesInRange(JSContext* cx, HandleObject obj, uint32_t begin, uin for (uint32_t i = begin; i < initLen && i < end; i++) { if (nativeObj->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) continue; - if (!indexes.append(i)) + if (MOZ_UNLIKELY(!indexes.append(i))) return false; } @@ -2799,7 +2799,7 @@ GetIndexedPropertiesInRange(JSContext* cx, HandleObject obj, uint32_t begin, uin if (IsAnyTypedArray(pobj)) { uint32_t len = AnyTypedArrayLength(pobj); for (uint32_t i = begin; i < len && i < end; i++) { - if (!indexes.append(i)) + if (MOZ_UNLIKELY(!indexes.append(i))) return false; } } @@ -2821,7 +2821,7 @@ GetIndexedPropertiesInRange(JSContext* cx, HandleObject obj, uint32_t begin, uin if (!shape.hasDefaultGetter()) return true; - if (!indexes.append(i)) + if (MOZ_UNLIKELY(!indexes.append(i))) return false; } } @@ -2830,7 +2830,7 @@ GetIndexedPropertiesInRange(JSContext* cx, HandleObject obj, uint32_t begin, uin // Sort the indexes. Vector tmp(cx); size_t n = indexes.length(); - if (!tmp.resize(n)) + if (MOZ_UNLIKELY(!tmp.resize(n))) return false; if (!MergeSort(indexes.begin(), n, tmp.begin(), SortComparatorIndexes())) return false; @@ -2845,7 +2845,7 @@ GetIndexedPropertiesInRange(JSContext* cx, HandleObject obj, uint32_t begin, uin indexes[last] = elem; } } - if (!indexes.resize(last + 1)) + if (MOZ_UNLIKELY(!indexes.resize(last + 1))) return false; } @@ -2952,7 +2952,7 @@ js::array_slice(JSContext* cx, unsigned argc, Value* vp) count = Min(initlen - begin, end - begin); RootedObject narr(cx, NewFullyAllocatedArrayTryReuseGroup(cx, obj, count)); - if (!narr) + if (MOZ_UNLIKELY(!narr)) return false; SetAnyBoxedOrUnboxedArrayLength(cx, narr, end - begin); @@ -2966,7 +2966,7 @@ js::array_slice(JSContext* cx, unsigned argc, Value* vp) } RootedObject narr(cx, NewPartlyAllocatedArrayTryReuseGroup(cx, obj, end - begin)); - if (!narr) + if (MOZ_UNLIKELY(!narr)) return false; if (js::GetElementsOp op = obj->getOps()->getElements) { @@ -3072,7 +3072,7 @@ static bool ArrayFromCallArgs(JSContext* cx, CallArgs& args, HandleObject proto = nullptr) { JSObject* obj = NewCopiedArrayForCallingAllocationSite(cx, args.array(), args.length(), proto); - if (!obj) + if (MOZ_UNLIKELY(!obj)) return false; args.rval().setObject(*obj); @@ -3217,7 +3217,7 @@ js::ArrayConstructor(JSContext* cx, unsigned argc, Value* vp) } JSObject* obj = NewPartlyAllocatedArrayForCallingAllocationSite(cx, length, proto); - if (!obj) + if (MOZ_UNLIKELY(!obj)) return false; args.rval().setObject(*obj); @@ -3227,7 +3227,7 @@ js::ArrayConstructor(JSContext* cx, unsigned argc, Value* vp) JSObject* js::ArrayConstructorOneArg(JSContext* cx, HandleObjectGroup group, int32_t lengthInt) { - if (lengthInt < 0) { + if (MOZ_UNLIKELY(lengthInt < 0)) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH); return nullptr; } @@ -3241,27 +3241,27 @@ CreateArrayPrototype(JSContext* cx, JSProtoKey key) { MOZ_ASSERT(key == JSProto_Array); RootedObject proto(cx, cx->global()->getOrCreateObjectPrototype(cx)); - if (!proto) + if (MOZ_UNLIKELY(!proto)) return nullptr; RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &ArrayObject::class_, TaggedProto(proto))); - if (!group) + if (MOZ_UNLIKELY(!group)) return nullptr; RootedShape shape(cx, EmptyShape::getInitialShape(cx, &ArrayObject::class_, TaggedProto(proto), gc::AllocKind::OBJECT0)); - if (!shape) + if (MOZ_UNLIKELY(!shape)) return nullptr; AutoSetNewObjectMetadata metadata(cx); RootedArrayObject arrayProto(cx, ArrayObject::createArray(cx, gc::AllocKind::OBJECT4, gc::TenuredHeap, shape, group, 0, metadata)); - if (!arrayProto || + if (MOZ_UNLIKELY(!arrayProto || !JSObject::setSingleton(cx, arrayProto) || !arrayProto->setDelegate(cx) || - !AddLengthProperty(cx, arrayProto)) + !AddLengthProperty(cx, arrayProto))) { return nullptr; } @@ -3283,7 +3283,7 @@ array_proto_finish(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto) { // Add Array.prototype[@@unscopables]. ECMA-262 draft (2016 Mar 19) 22.1.3.32. RootedObject unscopables(cx, NewObjectWithGivenProto(cx, nullptr, TenuredObject)); - if (!unscopables) + if (MOZ_UNLIKELY(!unscopables)) return false; RootedValue value(cx, BooleanValue(true)); @@ -3343,7 +3343,7 @@ EnsureNewArrayElements(ExclusiveContext* cx, ArrayObject* obj, uint32_t length) */ DebugOnly cap = obj->getDenseCapacity(); - if (!obj->ensureElements(cx, length)) + if (MOZ_UNLIKELY(!obj->ensureElements(cx, length))) return false; MOZ_ASSERT_IF(cap, !obj->hasDynamicElements()); @@ -3381,7 +3381,7 @@ NewArray(ExclusiveContext* cxArg, uint32_t length, arr->setFixedElements(); arr->setLength(cx, length); if (maxLength > 0 && - !EnsureNewArrayElements(cx, arr, std::min(maxLength, length))) + MOZ_UNLIKELY(!EnsureNewArrayElements(cx, arr, std::min(maxLength, length)))) { return nullptr; } @@ -3392,7 +3392,7 @@ NewArray(ExclusiveContext* cxArg, uint32_t length, RootedObjectGroup group(cxArg, ObjectGroup::defaultNewGroup(cxArg, &ArrayObject::class_, TaggedProto(proto))); - if (!group) + if (MOZ_UNLIKELY(!group)) return nullptr; /* @@ -3402,14 +3402,14 @@ NewArray(ExclusiveContext* cxArg, uint32_t length, RootedShape shape(cxArg, EmptyShape::getInitialShape(cxArg, &ArrayObject::class_, TaggedProto(proto), gc::AllocKind::OBJECT0)); - if (!shape) + if (MOZ_UNLIKELY(!shape)) return nullptr; AutoSetNewObjectMetadata metadata(cxArg); RootedArrayObject arr(cxArg, ArrayObject::createArray(cxArg, allocKind, GetInitialHeap(newKind, &ArrayObject::class_), shape, group, length, metadata)); - if (!arr) + if (MOZ_UNLIKELY(!arr)) return nullptr; if (shape->isEmptyShape()) { @@ -3429,7 +3429,7 @@ NewArray(ExclusiveContext* cxArg, uint32_t length, cache.fillProto(entry, &ArrayObject::class_, taggedProto, allocKind, arr); } - if (maxLength > 0 && !EnsureNewArrayElements(cxArg, arr, std::min(maxLength, length))) + if (maxLength > 0 && MOZ_UNLIKELY(!EnsureNewArrayElements(cxArg, arr, std::min(maxLength, length)))) return nullptr; probes::CreateObject(cxArg, arr); @@ -3474,7 +3474,7 @@ js::NewDenseCopiedArray(ExclusiveContext* cx, uint32_t length, const Value* valu NewObjectKind newKind /* = GenericObject */) { ArrayObject* arr = NewArray(cx, length, proto, newKind); - if (!arr) + if (MOZ_UNLIKELY(!arr)) return nullptr; MOZ_ASSERT(arr->getDenseCapacity() >= length); @@ -3501,10 +3501,10 @@ js::NewDenseFullyAllocatedArrayWithTemplate(JSContext* cx, uint32_t length, JSOb gc::InitialHeap heap = GetInitialHeap(GenericObject, &ArrayObject::class_); Rooted arr(cx, ArrayObject::createArray(cx, allocKind, heap, shape, group, length, metadata)); - if (!arr) + if (MOZ_UNLIKELY(!arr)) return nullptr; - if (!EnsureNewArrayElements(cx, arr, length)) + if (MOZ_UNLIKELY(!EnsureNewArrayElements(cx, arr, length))) return nullptr; probes::CreateObject(cx, arr); @@ -3518,7 +3518,7 @@ js::NewDenseCopyOnWriteArray(JSContext* cx, HandleArrayObject templateObject, gc MOZ_ASSERT(!gc::IsInsideNursery(templateObject)); ArrayObject* arr = ArrayObject::createCopyOnWriteArray(cx, heap, templateObject); - if (!arr) + if (MOZ_UNLIKELY(!arr)) return nullptr; probes::CreateObject(cx, arr); @@ -3550,7 +3550,7 @@ NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length } ArrayObject* res = NewArray(cx, length, proto, newKind); - if (!res) + if (MOZ_UNLIKELY(!res)) return nullptr; res->setGroup(group); @@ -3655,7 +3655,7 @@ js::NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, if (objects->empty()) { size_t nlength = Min(length, 100); JSObject* obj = NewFullyAllocatedArrayTryUseGroup(cx, group, nlength); - if (!obj) + if (MOZ_UNLIKELY(!obj)) return nullptr; DebugOnly result = SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, 0, vp, nlength, updateTypes); @@ -3666,7 +3666,7 @@ js::NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, } JSObject* obj = NewFullyAllocatedArrayTryUseGroup(cx, group, length, newKind, forceAnalyze); - if (!obj) + if (MOZ_UNLIKELY(!obj)) return nullptr; DenseElementResult result = @@ -3707,7 +3707,7 @@ js::NewValuePair(JSContext* cx, const Value& val1, const Value& val2, MutableHan vec[1].set(val2); JSObject* aobj = js::NewDenseCopiedArray(cx, 2, vec.begin()); - if (!aobj) + if (MOZ_UNLIKELY(!aobj)) return false; rval.setObject(*aobj); return true; From 91b97130284851c038e26a5832a2859de06c1b28 Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Sat, 10 Feb 2018 18:22:21 -0800 Subject: [PATCH 08/11] #463: wip 1 --- dom/base/nsGlobalWindow.cpp | 57 +++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 1032c4b33..3cf87e110 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -256,6 +256,8 @@ class nsIScriptTimeoutHandler; #include // for getpid() #endif +#include "mozilla/dom/IdleDeadline.h" // issue 463 + static const char kStorageEnabled[] = "dom.storage.enabled"; using namespace mozilla; @@ -11538,11 +11540,21 @@ nsGlobalWindow::SetInterval(JSContext* aCx, const nsAString& aHandler, } // TenFourFox issue 463 + +static bool +SystemIsIdle() +{ + // XXX: check Mach factor + return false; +} + nsresult nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler, int32_t interval, bool aIsInterval, int32_t *aReturn) { + // XXX: see below about interval versus deadline. we abuse interval for + // when to recheck if idle. return SetTimeoutOrIntervalOrIdleCallback(aHandler, interval, aIsInterval, aReturn, nullptr); } @@ -11574,6 +11586,9 @@ nsGlobalWindow::SetTimeoutOrIntervalOrIdleCallback(nsIScriptTimeoutHandler *aHan RefPtr timeout = new nsTimeout(); timeout->mIsInterval = aIsInterval; + + // XXX: add to Interval a deadline field, and use the interval for when to check + // if idle again. TenFourFox issue 463 timeout->mInterval = interval; if (aCallback) timeout->mCallback = aCallback; @@ -11768,11 +11783,19 @@ nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout, } if (!timeout->mScriptHandler) { - // Time to assess the conditions for requestIdleCallback (issue 463). + // Call the idle callback. TenFourFox issue 463. MOZ_ASSERT(timeout->mCallback); - MOZ_CRASH("RunTimeoutHandler triggered on requestIdleCallback"); - return false; - } + nsCOMPtr me(static_cast(this)); + + ErrorResult error; + RefPtr deadline = + new IdleDeadline(timeout->mWindow, + /* didTimeout */ true, + /* timeRemaining */ 0.0f); + timeout->mCallback->Call(*deadline, error, "requestIdleCallback handler"); + timeout->mCallback = nullptr; + error.SuppressException(); + } else { nsCOMPtr handler(timeout->mScriptHandler); RefPtr callback = handler->GetCallback(); @@ -11805,6 +11828,8 @@ nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout, ignored.SuppressException(); } + } + // We ignore any failures from calling EvaluateString() on the context or // Call() on a Function here since we're in a loop // where we're likely to be running timeouts whose OS timers @@ -11917,6 +11942,8 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout) { // If a modal dialog is open for this window, return early. Pending // timeouts will run when the modal dialog is dismissed. + // (Similarly, do this behaviour for idleCallbacks, since it's too + // much bookwork otherwise. See issue 463.) if (IsInModalState() || mTimeoutsSuspendDepth) { return; } @@ -11974,6 +12001,7 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout) return; } +#if(0) // Record telemetry information about timers set recently. TimeDuration recordingInterval = TimeDuration::FromMilliseconds(STATISTICS_INTERVAL); if (gLastRecordedRecentTimeouts.IsNull() || @@ -11983,6 +12011,7 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout) Telemetry::Accumulate(Telemetry::DOM_TIMERS_RECENTLY_SET, count); gLastRecordedRecentTimeouts = now; } +#endif // Insert a dummy timeout into the list of timeouts between the // portion of the list that we are about to process now and those @@ -12000,7 +12029,7 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout) // the logic in ResetTimersForNonBackgroundWindow will need to change. mTimeoutInsertionPoint = dummy_timeout; - Telemetry::AutoCounter timeoutsRan; + //Telemetry::AutoCounter timeoutsRan; for (nsTimeout *timeout = mTimeouts.getFirst(); timeout != dummy_timeout && !IsFrozen(); @@ -12024,6 +12053,13 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout) // The timeout is on the list to run at this depth, go ahead and // process it. + // If this timeout is an IdleCallback (TenFourFox issue 463), check + // to see if we have hit the deadline. If so, run the timeout. If not, + // check to see if we're idle. If so, run the timeout. If not, reschedule + // to check again. + // + // -- NYI XXX -- + // Get the script context (a strong ref to prevent it going away) // for this timeout and ensure the script language is enabled. nsCOMPtr scx = GetContextInternal(); @@ -12035,7 +12071,7 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout) } // This timeout is good to run - ++timeoutsRan; + //++timeoutsRan; bool timeout_was_cleared = RunTimeoutHandler(timeout, scx); if (timeout_was_cleared) { @@ -13894,6 +13930,11 @@ nsGlobalWindow::RequestIdleCallback(JSContext* aCx, // uint32_t handle = ++mIdleRequestCallbackCounter; fprintf(stderr, "::RequestIdleCallback() is not yet implemented\n"); + + // Plan: + // Check if idle now. If so, set a timeout of zero so it runs right away. + // Else set the deadline, if provided, and set an interval to recheck idle. + // See SystemIsIdle() #if DEBUG MOZ_ASSERT(0); #endif @@ -13906,6 +13947,10 @@ nsGlobalWindow::CancelIdleCallback(uint32_t aHandle) MOZ_RELEASE_ASSERT(IsInnerWindow()); fprintf(stderr, "::CancelIdleCallback() is not yet implemented\n"); + + // Plan: + // Check if this is a timeout with a Callback. If not, fail. + // If so, hand this to RemoveTimeout. #if DEBUG MOZ_ASSERT(0); #endif From 46b6faa6b26bdd008d5d7f9eb7451bd73bab5b32 Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Sun, 11 Feb 2018 13:21:45 -0800 Subject: [PATCH 09/11] closes #472: Element.insertAdjacentText Element.insertAdjacentElement --- dom/base/Element.cpp | 49 +++++++++++++++++++++++++++++++++++++++ dom/base/Element.h | 20 ++++++++++++++++ dom/webidl/Element.webidl | 6 +++++ 3 files changed, 75 insertions(+) diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index ba8d23263..51f6860ff 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -3556,6 +3556,55 @@ Element::InsertAdjacentHTML(const nsAString& aPosition, const nsAString& aText, } } +nsINode* +Element::InsertAdjacent(const nsAString& aWhere, + nsINode* aNode, + ErrorResult& aError) +{ + if (aWhere.LowerCaseEqualsLiteral("beforebegin")) { + nsCOMPtr parent = GetParentNode(); + if (!parent) { + return nullptr; + } + parent->InsertBefore(*aNode, this, aError); + } else if (aWhere.LowerCaseEqualsLiteral("afterbegin")) { + nsCOMPtr refChild = GetFirstChild(); + static_cast(this)->InsertBefore(*aNode, refChild, aError); + } else if (aWhere.LowerCaseEqualsLiteral("beforeend")) { + static_cast(this)->AppendChild(*aNode, aError); + } else if (aWhere.LowerCaseEqualsLiteral("afterend")) { + nsCOMPtr parent = GetParentNode(); + if (!parent) { + return nullptr; + } + nsCOMPtr refChild = GetNextSibling(); + parent->InsertBefore(*aNode, refChild, aError); + } else { + aError.Throw(NS_ERROR_DOM_SYNTAX_ERR); + return nullptr; + } + + return aError.Failed() ? nullptr : aNode; +} + +Element* +Element::InsertAdjacentElement(const nsAString& aWhere, + Element& aElement, + ErrorResult& aError) { + nsINode* newNode = InsertAdjacent(aWhere, &aElement, aError); + MOZ_ASSERT(!newNode || newNode->IsElement()); + + return newNode ? newNode->AsElement() : nullptr; +} + +void +Element::InsertAdjacentText( + const nsAString& aWhere, const nsAString& aData, ErrorResult& aError) +{ + RefPtr textNode = OwnerDoc()->CreateTextNode(aData); + InsertAdjacent(aWhere, textNode, aError); +} + nsIEditor* Element::GetEditorInternal() { diff --git a/dom/base/Element.h b/dom/base/Element.h index f0c431c36..71c1614cd 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -708,6 +708,26 @@ public: ErrorResult& aError); already_AddRefed GetElementsByClassName(const nsAString& aClassNames); + +private: + /** + * Implement the algorithm specified at + * https://dom.spec.whatwg.org/#insert-adjacent for both + * |insertAdjacentElement()| and |insertAdjacentText()| APIs. + */ + nsINode* InsertAdjacent(const nsAString& aWhere, + nsINode* aNode, + ErrorResult& aError); + +public: + Element* InsertAdjacentElement(const nsAString& aWhere, + Element& aElement, + ErrorResult& aError); + + void InsertAdjacentText(const nsAString& aWhere, + const nsAString& aData, + ErrorResult& aError); + void SetPointerCapture(int32_t aPointerId, ErrorResult& aError) { bool activeState = false; diff --git a/dom/webidl/Element.webidl b/dom/webidl/Element.webidl index 7c485aca9..984e37f50 100644 --- a/dom/webidl/Element.webidl +++ b/dom/webidl/Element.webidl @@ -71,6 +71,12 @@ interface Element : Node { [Pure] HTMLCollection getElementsByClassName(DOMString classNames); + [Throws, Pure] + Element? insertAdjacentElement(DOMString where, Element element); // historical + + [Throws] + void insertAdjacentText(DOMString where, DOMString data); // historical + /** * The ratio of font-size-inflated text font size to computed font * size for this element. This will query the element for its primary frame, From aebc3385bd8c7f31255b7bc78acd68914f952f16 Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Sun, 11 Feb 2018 17:44:42 -0800 Subject: [PATCH 10/11] closes #473: implement Canvas Ellipse + M1239835 --- dom/canvas/CanvasPath.h | 3 ++ dom/canvas/CanvasRenderingContext2D.cpp | 50 +++++++++++++++++++--- dom/canvas/CanvasRenderingContext2D.h | 3 ++ dom/webidl/CanvasRenderingContext2D.webidl | 4 +- gfx/2d/PathHelpers.h | 23 +++++----- 5 files changed, 65 insertions(+), 18 deletions(-) diff --git a/dom/canvas/CanvasPath.h b/dom/canvas/CanvasPath.h index 64ceb73d1..e31b375cc 100644 --- a/dom/canvas/CanvasPath.h +++ b/dom/canvas/CanvasPath.h @@ -51,6 +51,9 @@ public: void Arc(double x, double y, double radius, double startAngle, double endAngle, bool anticlockwise, ErrorResult& error); + void Ellipse(double x, double y, double radiusX, double radiusY, + double rotation, double startAngle, double endAngle, + bool anticlockwise, ErrorResult& error); void LineTo(const gfx::Point& aPoint); void BezierTo(const gfx::Point& aCP1, diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 7cf67d04a..dd70cbb8d 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -2498,8 +2498,11 @@ CanvasRenderingContext2D::UpdateFilter() // static bool -ValidateRect(double& aX, double& aY, double& aWidth, double& aHeight) +ValidateRect(double& aX, double& aY, double& aWidth, double& aHeight, bool aIsZeroSizeValid) { + if (!aIsZeroSizeValid && (aWidth == 0.0 || aHeight == 0.0)) { + return false; + } // bug 1018527 // The values of canvas API input are in double precision, but Moz2D APIs are @@ -2530,7 +2533,8 @@ void CanvasRenderingContext2D::ClearRect(double x, double y, double w, double h) { - if(!ValidateRect(x, y, w, h)) { + // Do not allow zeros - it's a no-op at that point per spec. + if (!ValidateRect(x, y, w, h, false)) { return; } @@ -2547,7 +2551,7 @@ CanvasRenderingContext2D::FillRect(double x, double y, double w, { const ContextState &state = CurrentState(); - if(!ValidateRect(x, y, w, h)) { + if(!ValidateRect(x, y, w, h, true)) { return; } @@ -2625,7 +2629,7 @@ CanvasRenderingContext2D::StrokeRect(double x, double y, double w, return; } - if(!ValidateRect(x, y, w, h)) { + if(!ValidateRect(x, y, w, h, true)) { return; } @@ -2991,7 +2995,7 @@ CanvasRenderingContext2D::Arc(double x, double y, double r, double startAngle, double endAngle, bool anticlockwise, ErrorResult& error) { - if (r < 0.0) { + if (MOZ_UNLIKELY(r < 0.0)) { error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return; } @@ -3021,6 +3025,22 @@ CanvasRenderingContext2D::Rect(double x, double y, double w, double h) } } +void +CanvasRenderingContext2D::Ellipse(double aX, double aY, double aRadiusX, double aRadiusY, + double aRotation, double aStartAngle, double aEndAngle, + bool aAnticlockwise, ErrorResult& aError) +{ + if (MOZ_UNLIKELY(aRadiusX < 0.0 || aRadiusY < 0.0)) { + aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); + return; + } + + EnsureWritablePath(); + + ArcToBezier(this, Point(aX, aY), Size(aRadiusX, aRadiusY), aStartAngle, aEndAngle, + aAnticlockwise, aRotation); +} + void CanvasRenderingContext2D::EnsureWritablePath() { @@ -4402,8 +4422,8 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& image, MOZ_ASSERT(optional_argc == 0 || optional_argc == 2 || optional_argc == 6); if (optional_argc == 6) { - if (!ValidateRect(sx, sy, sw, sh) || - !ValidateRect(dx, dy, dw, dh)) { + if (!ValidateRect(sx, sy, sw, sh, true) || + !ValidateRect(dx, dy, dw, dh, true)) { return; } } @@ -5918,6 +5938,22 @@ CanvasPath::Arc(double x, double y, double radius, ArcToBezier(this, Point(x, y), Size(radius, radius), startAngle, endAngle, anticlockwise); } +void +CanvasPath::Ellipse(double x, double y, double radiusX, double radiusY, + double rotation, double startAngle, double endAngle, + bool anticlockwise, ErrorResult& error) +{ + if (MOZ_UNLIKELY(radiusX < 0.0 || radiusY < 0.0)) { + error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); + return; + } + + EnsurePathBuilder(); + + ArcToBezier(this, Point(x, y), Size(radiusX, radiusY), startAngle, endAngle, + anticlockwise, rotation); +} + void CanvasPath::LineTo(const gfx::Point& aPoint) { diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h index ece78e589..5ff594a50 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -347,6 +347,9 @@ public: void Rect(double x, double y, double w, double h); void Arc(double x, double y, double radius, double startAngle, double endAngle, bool anticlockwise, mozilla::ErrorResult& error); + void Ellipse(double aX, double aY, double aRadiusX, double aRadiusY, + double aRotation, double aStartAngle, double aEndAngle, + bool aAnticlockwise, ErrorResult& aError); void GetMozCurrentTransform(JSContext* cx, JS::MutableHandle result, diff --git a/dom/webidl/CanvasRenderingContext2D.webidl b/dom/webidl/CanvasRenderingContext2D.webidl index eaf74a182..dd758b2e1 100644 --- a/dom/webidl/CanvasRenderingContext2D.webidl +++ b/dom/webidl/CanvasRenderingContext2D.webidl @@ -298,7 +298,9 @@ interface CanvasPathMethods { [Throws, LenientFloat] void arc(double x, double y, double radius, double startAngle, double endAngle, optional boolean anticlockwise = false); -// NOT IMPLEMENTED [LenientFloat] void ellipse(double x, double y, double radiusX, double radiusY, double rotation, double startAngle, double endAngle, boolean anticlockwise); + + [Throws, LenientFloat] + void ellipse(double x, double y, double radiusX, double radiusY, double rotation, double startAngle, double endAngle, optional boolean anticlockwise = false); }; interface CanvasGradient { diff --git a/gfx/2d/PathHelpers.h b/gfx/2d/PathHelpers.h index 1eb2d1c79..a5090485e 100644 --- a/gfx/2d/PathHelpers.h +++ b/gfx/2d/PathHelpers.h @@ -34,7 +34,8 @@ inline void PartialArcToBezier(T* aSink, const Size& aRadius, const Point& aStartPoint, const Point& aEndPoint, const Point& aStartOffset, const Point& aEndOffset, - Float aKappaFactor = kKappaFactor) + Float aKappaFactor = kKappaFactor, + const Matrix& aTransform = Matrix()) { Float kappaX = aKappaFactor * aRadius.width; Float kappaY = aKappaFactor * aRadius.height; @@ -45,7 +46,7 @@ inline void PartialArcToBezier(T* aSink, Point cp2 = aEndPoint + Point(aEndOffset.y * kappaX, -aEndOffset.x * kappaY); - aSink->BezierTo(cp1, cp2, aEndPoint); + aSink->BezierTo(aTransform * cp1, aTransform * cp2, aTransform * aEndPoint); } /** @@ -90,7 +91,8 @@ inline void AcuteArcToBezier(T* aSink, template void ArcToBezier(T* aSink, const Point &aOrigin, const Size &aRadius, - float aStartAngle, float aEndAngle, bool aAntiClockwise) + float aStartAngle, float aEndAngle, bool aAntiClockwise, + float aRotation = 0.0f) { Float sweepDirection = aAntiClockwise ? -1.0f : 1.0f; @@ -111,23 +113,24 @@ void ArcToBezier(T* aSink, const Point &aOrigin, const Size &aRadius, Float currentStartAngle = aStartAngle; Point currentStartOffset(cosf(aStartAngle), sinf(aStartAngle)); - Point currentStartPoint(aOrigin.x + currentStartOffset.x * aRadius.width, - aOrigin.y + currentStartOffset.y * aRadius.height); - - aSink->LineTo(currentStartPoint); + Point currentStartPoint(currentStartOffset.x * aRadius.width, + currentStartOffset.y * aRadius.height); + Matrix transform(cosf(aRotation), sinf(aRotation), -sinf(aRotation), cosf(aRotation), aOrigin.x, aOrigin.y); + aSink->LineTo(transform * currentStartPoint); while (arcSweepLeft > 0) { Float currentEndAngle = currentStartAngle + std::min(arcSweepLeft, Float(M_PI / 2.0f)) * sweepDirection; Point currentEndOffset(cosf(currentEndAngle), sinf(currentEndAngle)); - Point currentEndPoint(aOrigin.x + currentEndOffset.x * aRadius.width, - aOrigin.y + currentEndOffset.y * aRadius.height); + Point currentEndPoint(currentEndOffset.x * aRadius.width, + currentEndOffset.y * aRadius.height); PartialArcToBezier(aSink, aRadius, currentStartPoint, currentEndPoint, currentStartOffset, currentEndOffset, - ComputeKappaFactor(currentEndAngle - currentStartAngle)); + ComputeKappaFactor(currentEndAngle - currentStartAngle), + transform); // We guarantee here the current point is the start point of the next // curve segment. From 6e6ed0b4ba8abe2af4df6c05ba388e40c0c91e96 Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Mon, 12 Feb 2018 12:39:39 -0800 Subject: [PATCH 11/11] #405: date picker abstract interface definition --- widget/moz.build | 6 +++ widget/nsBaseDatePicker.cpp | 98 +++++++++++++++++++++++++++++++++++++ widget/nsBaseDatePicker.h | 37 ++++++++++++++ widget/nsIDatePicker.idl | 74 ++++++++++++++++++++++++++++ 4 files changed, 215 insertions(+) create mode 100644 widget/nsBaseDatePicker.cpp create mode 100644 widget/nsBaseDatePicker.h create mode 100644 widget/nsIDatePicker.idl diff --git a/widget/moz.build b/widget/moz.build index b9b0c12f9..b1abc8948 100644 --- a/widget/moz.build +++ b/widget/moz.build @@ -65,6 +65,7 @@ XPIDL_SOURCES += [ 'nsIClipboardHelper.idl', 'nsIClipboardOwner.idl', 'nsIColorPicker.idl', + 'nsIDatePicker.idl', 'nsIDisplayInfo.idl', 'nsIDragService.idl', 'nsIDragSession.idl', @@ -197,6 +198,11 @@ if CONFIG['MOZ_X11']: 'GfxInfoX11.cpp' ] +if toolkit == 'cocoa': + SOURCES += [ + 'nsBaseDatePicker.cpp', + ] + if toolkit in ('cocoa', 'windows'): UNIFIED_SOURCES += [ 'nsBaseClipboard.cpp', diff --git a/widget/nsBaseDatePicker.cpp b/widget/nsBaseDatePicker.cpp new file mode 100644 index 000000000..d89e99fcb --- /dev/null +++ b/widget/nsBaseDatePicker.cpp @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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 "nsCOMPtr.h" +#include "nsPIDOMWindow.h" +#include "nsIDocShell.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsIBaseWindow.h" +#include "nsIWidget.h" + +#include "nsXPIDLString.h" +#include "nsIServiceManager.h" +#include "nsCOMArray.h" +#include "nsEnumeratorUtils.h" +#include "mozilla/Services.h" +#include "WidgetUtils.h" +#include "nsThreadUtils.h" + +#include "nsBaseDatePicker.h" + +using namespace mozilla::widget; +using namespace mozilla::dom; + +/** + * A runnable to dispatch from the main thread to the main thread to display + * the date picker while letting the showAsync method return right away. +*/ +class AsyncShowDatePicker : public nsRunnable +{ +public: + AsyncShowDatePicker(nsIDatePicker *aDatePicker, + nsIDatePickerShownCallback *aCallback) : + mDatePicker(aDatePicker), + mCallback(aCallback) + { + } + + NS_IMETHOD Run() + { + NS_ASSERTION(NS_IsMainThread(), + "AsyncShowDatePicker should be on the main thread!"); + + // It's possible that some widget implementations require GUI operations + // to be on the main thread, so that's why we're not dispatching to another + // thread and calling back to the main after it's done. + int16_t result = nsIDatePicker::returnCancel; + nsresult rv = mDatePicker->Show(&result); + if (NS_FAILED(rv)) { + NS_ERROR("DatePicker's Show() implementation failed!"); + } + + if (mCallback) { + mCallback->Done(result); + } + return NS_OK; + } + +private: + RefPtr mDatePicker; + RefPtr mCallback; +}; + +nsBaseDatePicker::nsBaseDatePicker() +{ +} + +nsBaseDatePicker::~nsBaseDatePicker() +{ +} + +NS_IMETHODIMP nsBaseDatePicker::Init(nsIDOMWindow *aParent, + const nsAString& aTitle) +{ + NS_PRECONDITION(aParent, "Null parent passed to datepicker, no date " + "picker for you!"); + nsCOMPtr widget = WidgetUtils::DOMWindowToWidget(aParent); + NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE); + + mParent = do_QueryInterface(aParent); + if (!mParent->IsInnerWindow()) { + mParent = mParent->GetCurrentInnerWindow(); + } + + InitNative(widget, aTitle); + + return NS_OK; +} + +NS_IMETHODIMP +nsBaseDatePicker::Open(nsIDatePickerShownCallback *aCallback) +{ + nsCOMPtr filePickerEvent = + new AsyncShowDatePicker(this, aCallback); + return NS_DispatchToMainThread(filePickerEvent); +} \ No newline at end of file diff --git a/widget/nsBaseDatePicker.h b/widget/nsBaseDatePicker.h new file mode 100644 index 000000000..637c232fe --- /dev/null +++ b/widget/nsBaseDatePicker.h @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsBaseDatePicker_h__ +#define nsBaseDatePicker_h__ + +#include "nsISupports.h" +#include "nsIDatePicker.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsIWidget.h" + +class nsPIDOMWindow; +class nsIWidget; + +class nsBaseDatePicker : public nsIDatePicker +{ +public: + nsBaseDatePicker(); + virtual ~nsBaseDatePicker(); + + NS_IMETHOD Init(nsIDOMWindow *aParent, + const nsAString& aTitle); + + NS_IMETHOD Open(nsIDatePickerShownCallback *aCallback); + +protected: + virtual void InitNative(nsIWidget *aParent, const nsAString& aTitle) = 0; + + // This is an innerWindow. + nsCOMPtr mParent; +}; + +#endif // nsBaseDatePicker_h__ diff --git a/widget/nsIDatePicker.idl b/widget/nsIDatePicker.idl new file mode 100644 index 000000000..0263dc857 --- /dev/null +++ b/widget/nsIDatePicker.idl @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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 "nsISupports.idl" + +interface nsIURI; +interface nsIDOMWindow; + +[scriptable, function, uuid(0d79adad-b244-49A5-9997-2a8cad93fc45)] +interface nsIDatePickerShownCallback : nsISupports +{ + /** + * Callback which is called when a datepicker is shown and a result + * is returned. + * + * @param aResult One of returnOK, returnCancel + */ + void done(in short aResult); +}; + +[scriptable, uuid(9840d564-42c8-4d78-9a4d-71002343c919)] +interface nsIDatePicker : nsISupports +{ + const short returnOK = 0; // User hit Ok, process selection + const short returnCancel = 1; // User hit cancel, ignore selection + + /** + * Initialize the date picker widget. The date picker is not valid until this + * method is called. + * + * @param title The title for the file widget + */ + void init(in nsIDOMWindow parent, in AString title); + + /** + * The date that should be suggested to the user as a default. + * The date is a string in YYYY-MM-DD format. + * + * @throws NS_ERROR_FAILURE on attempts to get + */ + attribute AString defaultDate; + + /** + * The minimum date range. If null, there is no minimum date. + * The date is a string in YYYY-MM-DD format. + * + * @throws NS_ERROR_FAILURE on attempts to get + */ + attribute AString minDate; + + /** + * The maximum date range. If null, there is no maximum date. + * The date is a string in YYYY-MM-DD format. + * + * @throws NS_ERROR_FAILURE on attempts to get + */ + attribute AString maxDate; + + /** + * Show date dialog. The dialog is displayed modally. + * + * @return returnOK if the user selects OK, returnCancel if the user selects cancel + */ + [deprecated] short show(); + + /** + * Opens the date dialog asynchrounously. + * The passed in object's done method will be called upon completion. + */ + void open(in nsIDatePickerShownCallback aDatePickerShownCallback); +};