author | Ryan VanderMeulen <ryanvm@gmail.com> |
Fri, 21 Oct 2016 17:12:27 -0400 | |
changeset 318961 | 5639a9f476d08f300c079117e61697f5026b6367 |
parent 318938 | 806054dd12bdcbdee81dbd75f1583156cef9b649 (current diff) |
parent 318960 | 619ccb0d81f1adc30894807a13196d63ddbe7966 (diff) |
child 318962 | 60dd82380d43a2b681f50842238f829204486290 |
child 318974 | 4b2363bd94e72797913817ae8bb9195afd978169 |
child 319022 | 32f298a71ce9f6d52387a929dd82b66d6cf13af8 |
push id | 30855 |
push user | ryanvm@gmail.com |
push date | Fri, 21 Oct 2016 21:12:44 +0000 |
treeherder | mozilla-central@5639a9f476d0 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 52.0a1 |
first release with | nightly linux32
5639a9f476d0
/
52.0a1
/
20161022030204
/
files
nightly linux64
5639a9f476d0
/
52.0a1
/
20161022030204
/
files
nightly mac
5639a9f476d0
/
52.0a1
/
20161022030204
/
files
nightly win32
5639a9f476d0
/
52.0a1
/
20161022030204
/
files
nightly win64
5639a9f476d0
/
52.0a1
/
20161022030204
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
52.0a1
/
20161022030204
/
pushlog to previous
nightly linux64
52.0a1
/
20161022030204
/
pushlog to previous
nightly mac
52.0a1
/
20161022030204
/
pushlog to previous
nightly win32
52.0a1
/
20161022030204
/
pushlog to previous
nightly win64
52.0a1
/
20161022030204
/
pushlog to previous
|
devtools/client/animationinspector/test/browser_animation_timeline_pause_button.js | file | annotate | diff | comparison | revisions | |
js/src/jit/CodeGenerator.cpp | file | annotate | diff | comparison | revisions | |
js/src/jit/Ion.cpp | file | annotate | diff | comparison | revisions | |
js/src/jit/IonAnalysis.cpp | file | annotate | diff | comparison | revisions | |
js/src/jit/MIR.cpp | file | annotate | diff | comparison | revisions | |
js/src/jit/Recover.cpp | file | annotate | diff | comparison | revisions | |
js/src/jit/ValueNumbering.cpp | file | annotate | diff | comparison | revisions | |
js/src/jsapi.h | file | annotate | diff | comparison | revisions | |
js/src/moz.build | file | annotate | diff | comparison | revisions | |
js/src/shell/js.cpp | file | annotate | diff | comparison | revisions | |
layout/base/nsCSSFrameConstructor.cpp | file | annotate | diff | comparison | revisions | |
security/manager/pki/resources/content/viewCertDetails.js | file | annotate | diff | comparison | revisions |
--- a/browser/components/extensions/ext-windows.js +++ b/browser/components/extensions/ext-windows.js @@ -34,22 +34,26 @@ extensions.registerSchemaAPI("windows", fire(WindowManager.getId(window)); }).api(), onFocusChanged: new EventManager(context, "windows.onFocusChanged", fire => { // Keep track of the last windowId used to fire an onFocusChanged event let lastOnFocusChangedWindowId; let listener = event => { - let window = WindowManager.topWindow; - let windowId = window ? WindowManager.getId(window) : WindowManager.WINDOW_ID_NONE; - if (windowId !== lastOnFocusChangedWindowId) { - fire(windowId); - lastOnFocusChangedWindowId = windowId; - } + // Wait a tick to avoid firing a superfluous WINDOW_ID_NONE + // event when switching focus between two Firefox windows. + Promise.resolve().then(() => { + let window = Services.focus.activeWindow; + let windowId = window ? WindowManager.getId(window) : WindowManager.WINDOW_ID_NONE; + if (windowId !== lastOnFocusChangedWindowId) { + fire(windowId); + lastOnFocusChangedWindowId = windowId; + } + }); }; AllWindowEvents.addListener("focus", listener); AllWindowEvents.addListener("blur", listener); return () => { AllWindowEvents.removeListener("focus", listener); AllWindowEvents.removeListener("blur", listener); }; }).api(),
--- a/browser/components/extensions/test/browser/browser_ext_windows_events.js +++ b/browser/components/extensions/test/browser/browser_ext_windows_events.js @@ -11,20 +11,25 @@ add_task(function* testWindowsEvents() { browser.test.assertTrue(Number.isInteger(window.id), "Window object's id is an integer"); browser.test.assertEq("normal", window.type, "Window object returned with the correct type"); browser.test.sendMessage("window-created", window.id); }); - let lastWindowId; + let lastWindowId, os; browser.windows.onFocusChanged.addListener(function listener(windowId) { browser.test.log(`onFocusChange: windowId=${windowId} lastWindowId=${lastWindowId}`); + if (windowId === browser.windows.WINDOW_ID_NONE && os === "linux") { + browser.test.log("Ignoring a superfluous WINDOW_ID_NONE (blur) event on Linux"); + return; + } + browser.test.assertTrue(lastWindowId !== windowId, "onFocusChanged fired once for the given window"); lastWindowId = windowId; browser.test.assertTrue(Number.isInteger(windowId), "windowId is an integer"); browser.windows.getLastFocused().then(window => { @@ -38,17 +43,20 @@ add_task(function* testWindowsEvents() { browser.test.log(`onRemoved: windowId=${windowId}`); browser.test.assertTrue(Number.isInteger(windowId), "windowId is an integer"); browser.test.sendMessage(`window-removed`, windowId); browser.test.notifyPass("windows.events"); }); - browser.test.sendMessage("ready"); + browser.runtime.getPlatformInfo(info => { + os = info.os; + browser.test.sendMessage("ready"); + }); } let extension = ExtensionTestUtils.loadExtension({ background: `(${background})()`, }); yield extension.startup(); yield extension.awaitMessage("ready");
--- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -149,18 +149,18 @@ GetPrincipalDomainOrigin(nsIPrincipal* a inline void SetPendingExceptionASCII(JSContext *cx, const char *aMsg) { JS_ReportErrorASCII(cx, "%s", aMsg); } inline void SetPendingException(JSContext *cx, const char16_t *aMsg) { - // FIXME: Need to convert to UTF-8 (bug XXX). - JS_ReportErrorLatin1(cx, "%hs", aMsg); + NS_ConvertUTF16toUTF8 msg(aMsg); + JS_ReportErrorUTF8(cx, "%s", msg.get()); } // Helper class to get stuff from the ClassInfo and not waste extra time with // virtual method calls for things it has already gotten class ClassInfoData { public: ClassInfoData(nsIClassInfo *aClassInfo, const char *aName)
--- a/devtools/client/animationinspector/test/browser.ini +++ b/devtools/client/animationinspector/test/browser.ini @@ -43,18 +43,19 @@ skip-if = os == "linux" && !debug # Bug [browser_animation_shows_player_on_valid_node.js] [browser_animation_spacebar_toggles_animations.js] [browser_animation_spacebar_toggles_node_animations.js] [browser_animation_target_highlight_select.js] [browser_animation_target_highlighter_lock.js] [browser_animation_timeline_currentTime.js] [browser_animation_timeline_header.js] [browser_animation_timeline_iterationStart.js] -[browser_animation_timeline_pause_button.js] -skip-if = os == "linux" && bits == 32 # Bug 1220974 +[browser_animation_timeline_pause_button_01.js] +[browser_animation_timeline_pause_button_02.js] +[browser_animation_timeline_pause_button_03.js] [browser_animation_timeline_rate_selector.js] [browser_animation_timeline_rewind_button.js] [browser_animation_timeline_scrubber_exists.js] [browser_animation_timeline_scrubber_movable.js] [browser_animation_timeline_scrubber_moves.js] [browser_animation_timeline_shows_delay.js] [browser_animation_timeline_shows_endDelay.js] [browser_animation_timeline_shows_iterations.js]
rename from devtools/client/animationinspector/test/browser_animation_timeline_pause_button.js rename to devtools/client/animationinspector/test/browser_animation_timeline_pause_button_01.js --- a/devtools/client/animationinspector/test/browser_animation_timeline_pause_button.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_pause_button_01.js @@ -1,110 +1,34 @@ /* vim: set ts=2 et sw=2 tw=80: */ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; requestLongerTimeout(2); -// Check that the timeline toolbar contains a pause button and that this pause -// button can be clicked. Check that when it is, the current animations -// displayed in the timeline get their playstates changed accordingly, and check -// that the scrubber resumes/stops moving. -// Also checks that the button goes to the right state when the scrubber has -// reached the end of the timeline: continues to be in playing mode for infinite -// animations, goes to paused mode otherwise. -// And test that clicking the button once the scrubber has reached the end of -// the timeline does the right thing. +// Check that the timeline toolbar contains a pause button and that this pause button can +// be clicked. Check that when it is, the button changes state and the scrubber stops and +// resumes. add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); - let {panel, inspector} = yield openAnimationInspector(); - let timeline = panel.animationsTimelineComponent; + let {panel} = yield openAnimationInspector(); let btn = panel.playTimelineButtonEl; ok(btn, "The play/pause button exists"); - ok(!btn.classList.contains("paused"), - "The play/pause button is in its playing state"); + ok(!btn.classList.contains("paused"), "The play/pause button is in its playing state"); info("Click on the button to pause all timeline animations"); yield clickTimelinePlayPauseButton(panel); - ok(btn.classList.contains("paused"), - "The play/pause button is in its paused state"); + ok(btn.classList.contains("paused"), "The play/pause button is in its paused state"); yield assertScrubberMoving(panel, false); info("Click again on the button to play all timeline animations"); yield clickTimelinePlayPauseButton(panel); ok(!btn.classList.contains("paused"), "The play/pause button is in its playing state again"); yield assertScrubberMoving(panel, true); - - // Some animations on the test page are infinite, so the scrubber won't stop - // at the end of the timeline, and the button should remain in play mode. - info("Select an infinite animation, reload the page and wait for the " + - "animation to complete"); - yield selectNodeAndWaitForAnimations(".multi", inspector); - yield reloadTab(inspector); - yield waitForOutOfBoundScrubber(timeline); - - ok(!btn.classList.contains("paused"), - "The button is in its playing state still, animations are infinite."); - yield assertScrubberMoving(panel, true); - - info("Click on the button after the scrubber has moved out of bounds"); - yield clickTimelinePlayPauseButton(panel); - - ok(btn.classList.contains("paused"), - "The button can be paused after the scrubber has moved out of bounds"); - yield assertScrubberMoving(panel, false); - - // For a finite animation though, once the scrubber reaches the end of the - // timeline, it should go back to paused mode. - info("Select a finite animation, reload the page and wait for the " + - "animation to complete"); - yield selectNodeAndWaitForAnimations(".negative-delay", inspector); - - let onScrubberStopped = waitForScrubberStopped(timeline); - yield reloadTab(inspector); - yield onScrubberStopped; - - ok(btn.classList.contains("paused"), - "The button is in paused state once finite animations are done"); - yield assertScrubberMoving(panel, false); - - info("Click again on the button to play the animation from the start again"); - yield clickTimelinePlayPauseButton(panel); - - ok(!btn.classList.contains("paused"), - "Clicking the button once finite animations are done should restart them"); - yield assertScrubberMoving(panel, true); }); - -function waitForOutOfBoundScrubber({win, scrubberEl}) { - return new Promise(resolve => { - function check() { - let pos = scrubberEl.getBoxQuads()[0].bounds.right; - let width = win.document.documentElement.offsetWidth; - if (pos >= width) { - setTimeout(resolve, 50); - } else { - setTimeout(check, 50); - } - } - check(); - }); -} - -function waitForScrubberStopped(timeline) { - return new Promise(resolve => { - timeline.on("timeline-data-changed", - function onTimelineData(e, {isMoving}) { - if (!isMoving) { - timeline.off("timeline-data-changed", onTimelineData); - resolve(); - } - }); - }); -}
new file mode 100644 --- /dev/null +++ b/devtools/client/animationinspector/test/browser_animation_timeline_pause_button_02.js @@ -0,0 +1,48 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +requestLongerTimeout(2); + +// Checks that the play/pause button goes to the right state when the scrubber has reached +// the end of the timeline but there are infinite animations playing. + +add_task(function* () { + yield addTab(URL_ROOT + "doc_simple_animation.html"); + + let {panel, inspector} = yield openAnimationInspector(); + let timeline = panel.animationsTimelineComponent; + let btn = panel.playTimelineButtonEl; + + info("Select an infinite animation and wait for the scrubber to reach the end"); + yield selectNodeAndWaitForAnimations(".multi", inspector); + yield waitForOutOfBoundScrubber(timeline); + + ok(!btn.classList.contains("paused"), + "The button is in its playing state still, animations are infinite."); + yield assertScrubberMoving(panel, true); + + info("Click on the button after the scrubber has moved out of bounds"); + yield clickTimelinePlayPauseButton(panel); + + ok(btn.classList.contains("paused"), + "The button can be paused after the scrubber has moved out of bounds"); + yield assertScrubberMoving(panel, false); +}); + +function waitForOutOfBoundScrubber({win, scrubberEl}) { + return new Promise(resolve => { + function check() { + let pos = scrubberEl.getBoxQuads()[0].bounds.right; + let width = win.document.documentElement.offsetWidth; + if (pos >= width) { + setTimeout(resolve, 50); + } else { + setTimeout(check, 50); + } + } + check(); + }); +}
new file mode 100644 --- /dev/null +++ b/devtools/client/animationinspector/test/browser_animation_timeline_pause_button_03.js @@ -0,0 +1,54 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +requestLongerTimeout(2); + +// Also checks that the button goes to the right state when the scrubber has +// reached the end of the timeline: continues to be in playing mode for infinite +// animations, goes to paused mode otherwise. +// And test that clicking the button once the scrubber has reached the end of +// the timeline does the right thing. + +add_task(function* () { + yield addTab(URL_ROOT + "doc_simple_animation.html"); + + let {panel, inspector} = yield openAnimationInspector(); + let timeline = panel.animationsTimelineComponent; + let btn = panel.playTimelineButtonEl; + + // For a finite animation, once the scrubber reaches the end of the timeline, the pause + // button should go back to paused mode. + info("Select a finite animation and wait for the animation to complete"); + yield selectNodeAndWaitForAnimations(".negative-delay", inspector); + + let onScrubberStopped = waitForScrubberStopped(timeline); + // The page is reloaded to avoid missing the animation. + yield reloadTab(inspector); + yield onScrubberStopped; + + ok(btn.classList.contains("paused"), + "The button is in paused state once finite animations are done"); + yield assertScrubberMoving(panel, false); + + info("Click again on the button to play the animation from the start again"); + yield clickTimelinePlayPauseButton(panel); + + ok(!btn.classList.contains("paused"), + "Clicking the button once finite animations are done should restart them"); + yield assertScrubberMoving(panel, true); +}); + +function waitForScrubberStopped(timeline) { + return new Promise(resolve => { + timeline.on("timeline-data-changed", + function onTimelineData(e, {isMoving}) { + if (!isMoving) { + timeline.off("timeline-data-changed", onTimelineData); + resolve(); + } + }); + }); +}
--- a/devtools/client/themes/inspector.css +++ b/devtools/client/themes/inspector.css @@ -100,34 +100,16 @@ window { overflow: hidden; margin-inline-end: 2px; } #inspector-search { flex: unset; } -/* TODO: bug 1265759: should apply to .devtools-searchinput once all searchbox - is converted to html*/ -#inspector-searchbox { - width: 100%; -} - -/* Make sure the text is vertically centered in Inspector's - search box. This can be removed when the search box is - switched to HTML. - See also: https://bugzilla.mozilla.org/show_bug.cgi?id=1265759 */ -.theme-dark #inspector-searchbox, -.theme-light #inspector-searchbox { - line-height: 19px; -} -.theme-firebug #inspector-searchbox { - line-height: 17px; -} - /* Eyedropper toolbar button */ #inspector-eyedropper-toggle { /* hidden by default, until we can check that the required highlighter exists */ display: none; } #inspector-eyedropper-toggle::before {
--- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -633,17 +633,17 @@ ThrowJSExceptionASCII(JSContext *cx, con if (str) { JS::Rooted<JS::Value> exn(cx, JS::StringValue(str)); ::JS_SetPendingException(cx, exn); } PopException(); } else { - ::JS_ReportErrorASCII(cx, message); + ::JS_ReportErrorASCII(cx, "%s", message); } } static bool ReportExceptionIfPending(JSContext *cx) { const char *ex = PeekException();
--- a/js/src/asmjs/AsmJS.cpp +++ b/js/src/asmjs/AsmJS.cpp @@ -2245,25 +2245,25 @@ class MOZ_STACK_CLASS ModuleValidator MOZ_ASSERT(!hasAlreadyFailed()); MOZ_ASSERT(errorOffset_ == UINT32_MAX); MOZ_ASSERT(fmt); errorOffset_ = offset; errorString_.reset(JS_vsmprintf(fmt, ap)); return false; } - bool failfOffset(uint32_t offset, const char* fmt, ...) { + bool failfOffset(uint32_t offset, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4) { va_list ap; va_start(ap, fmt); failfVAOffset(offset, fmt, ap); va_end(ap); return false; } - bool failf(ParseNode* pn, const char* fmt, ...) { + bool failf(ParseNode* pn, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4) { va_list ap; va_start(ap, fmt); failfVAOffset(pn->pn_pos.begin, fmt, ap); va_end(ap); return false; } bool failNameOffset(uint32_t offset, const char* fmt, PropertyName* name) { @@ -2939,17 +2939,17 @@ class MOZ_STACK_CLASS FunctionValidator return m_.mg().finishFuncDef(funcIndex, &fg_); } bool fail(ParseNode* pn, const char* str) { return m_.fail(pn, str); } - bool failf(ParseNode* pn, const char* fmt, ...) { + bool failf(ParseNode* pn, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4) { va_list ap; va_start(ap, fmt); m_.failfVAOffset(pn->pn_pos.begin, fmt, ap); va_end(ap); return false; } bool failName(ParseNode* pn, const char* fmt, PropertyName* name) { @@ -4715,17 +4715,18 @@ CheckCallArgs(FunctionValidator& f, Pars } return true; } static bool CheckSignatureAgainstExisting(ModuleValidator& m, ParseNode* usepn, const Sig& sig, const Sig& existing) { if (sig.args().length() != existing.args().length()) { - return m.failf(usepn, "incompatible number of arguments (%u here vs. %u before)", + return m.failf(usepn, "incompatible number of arguments (%" PRIuSIZE + " here vs. %" PRIuSIZE " before)", sig.args().length(), existing.args().length()); } for (unsigned i = 0; i < sig.args().length(); i++) { if (sig.arg(i) != existing.arg(i)) { return m.failf(usepn, "incompatible type for argument %u: (%s here vs. %s before)", i, ToCString(sig.arg(i)), ToCString(existing.arg(i))); }
--- a/js/src/asmjs/WasmBinary.cpp +++ b/js/src/asmjs/WasmBinary.cpp @@ -36,33 +36,34 @@ Decoder::fail(const char* msg, ...) { return false; return fail(Move(str)); } bool Decoder::fail(UniqueChars msg) { MOZ_ASSERT(error_); - UniqueChars strWithOffset(JS_smprintf("at offset %zu: %s", currentOffset(), msg.get())); + UniqueChars strWithOffset(JS_smprintf("at offset %" PRIuSIZE ": %s", + currentOffset(), msg.get())); if (!strWithOffset) return false; *error_ = Move(strWithOffset); return false; } bool wasm::DecodePreamble(Decoder& d) { uint32_t u32; if (!d.readFixedU32(&u32) || u32 != MagicNumber) return d.fail("failed to match magic number"); if (!d.readFixedU32(&u32) || u32 != EncodingVersion) - return d.fail("binary version 0x%lx does not match expected version 0x%lx", + return d.fail("binary version 0x%" PRIx32 " does not match expected version 0x%" PRIx32, u32, EncodingVersion); return true; } bool wasm::EncodeLocalEntries(Encoder& e, const ValTypeVector& locals) { @@ -146,29 +147,29 @@ wasm::DecodeLimits(Decoder& d, Limits* l { uint32_t flags; if (!d.readVarU32(&flags)) return d.fail("expected flags"); // TODO (bug 1310149): tighten this check (s/3/1) when the AngryBots demo // gets updated. if (flags & ~uint32_t(0x3)) - return d.fail("unexpected bits set in flags: %lu", (flags & ~uint32_t(0x3))); + return d.fail("unexpected bits set in flags: %" PRIu32, (flags & ~uint32_t(0x3))); if (!d.readVarU32(&limits->initial)) return d.fail("expected initial length"); if (flags & 0x1) { uint32_t maximum; if (!d.readVarU32(&maximum)) return d.fail("expected maximum length"); if (limits->initial > maximum) { return d.fail("memory size minimum must not be greater than maximum; " - "maximum length %lu is less than initial length %lu", + "maximum length %" PRIu32 " is less than initial length %" PRIu32 , maximum, limits->initial); } limits->maximum.emplace(maximum); } return true; }
--- a/js/src/asmjs/WasmBinary.h +++ b/js/src/asmjs/WasmBinary.h @@ -773,17 +773,17 @@ class Decoder } explicit Decoder(const Bytes& bytes, UniqueChars* error = nullptr) : beg_(bytes.begin()), end_(bytes.end()), cur_(bytes.begin()), error_(error) {} - bool fail(const char* msg, ...); + bool fail(const char* msg, ...) MOZ_FORMAT_PRINTF(2, 3); bool fail(UniqueChars msg); void clearError() { if (error_) error_->reset(); } bool done() const { MOZ_ASSERT(cur_ <= end_);
--- a/js/src/asmjs/WasmBinaryIterator.h +++ b/js/src/asmjs/WasmBinaryIterator.h @@ -720,17 +720,17 @@ ExprIter<Policy>::unrecognizedOpcode(Exp return fail(error.get()); } template <typename Policy> bool ExprIter<Policy>::fail(const char* msg) { - return d_.fail(msg); + return d_.fail("%s", msg); } template <typename Policy> inline bool ExprIter<Policy>::pushControl(LabelKind kind, ExprType type, bool reachable) { return controlStack_.emplaceBack(kind, type, reachable, valueStack_.length()); }
--- a/js/src/asmjs/WasmCode.cpp +++ b/js/src/asmjs/WasmCode.cpp @@ -791,18 +791,20 @@ Code::ensureProfilingState(JSContext* cx continue; TwoByteName name(cx); if (!getFuncDefName(cx, codeRange.funcDefIndex(), &name)) return false; if (!name.append('\0')) return false; - UniqueChars label(JS_smprintf("%hs (%s:%u)", - name.begin(), + TwoByteChars chars(name.begin(), name.length()); + UniqueChars utf8Name(JS::CharsToNewUTF8CharsZ(nullptr, chars).c_str()); + UniqueChars label(JS_smprintf("%s (%s:%u)", + utf8Name.get(), metadata_->filename.get(), codeRange.funcLineOrBytecode())); if (!label) { ReportOutOfMemory(cx); return false; } if (codeRange.funcDefIndex() >= funcLabels_.length()) {
--- a/js/src/asmjs/WasmTextToBinary.cpp +++ b/js/src/asmjs/WasmTextToBinary.cpp @@ -1483,17 +1483,17 @@ struct WasmParseContext WasmParseContext(const char16_t* text, LifoAlloc& lifo, UniqueChars* error) : ts(text, error), lifo(lifo), error(error), dtoaState(NewDtoaState()) {} bool fail(const char* message) { - error->reset(JS_smprintf(message)); + error->reset(js_strdup(message)); return false; } ~WasmParseContext() { DestroyDtoaState(dtoaState); } }; } // end anonymous namespace @@ -3331,22 +3331,19 @@ class Resolver AstNameMap::Ptr p = map.lookup(ref.name()); if (p) { ref.setIndex(p->value()); return true; } return false; } bool failResolveLabel(const char* kind, AstName name) { - Vector<char16_t, 0, SystemAllocPolicy> nameWithNull; - if (!nameWithNull.append(name.begin(), name.length())) - return false; - if (!nameWithNull.append(0)) - return false; - error_->reset(JS_smprintf("%s label '%hs' not found", kind, nameWithNull.begin())); + TwoByteChars chars(name.begin(), name.length()); + UniqueChars utf8Chars(CharsToNewUTF8CharsZ(nullptr, chars).c_str()); + error_->reset(JS_smprintf("%s label '%s' not found", kind, utf8Chars.get())); return false; } public: explicit Resolver(LifoAlloc& lifo, UniqueChars* error) : error_(error), varMap_(lifo), globalMap_(lifo),
--- a/js/src/builtin/Profilers.cpp +++ b/js/src/builtin/Profilers.cpp @@ -36,19 +36,17 @@ using namespace js; using mozilla::ArrayLength; /* Thread-unsafe error management */ static char gLastError[2000]; #if defined(__APPLE__) || defined(__linux__) || defined(MOZ_CALLGRIND) static void -#ifdef __GNUC__ -__attribute__((format(printf,1,2))) -#endif +MOZ_FORMAT_PRINTF(1, 2) UnsafeError(const char* format, ...) { va_list args; va_start(args, format); (void) VsprintfLiteral(gLastError, format, args); va_end(args); } #endif
--- a/js/src/devtools/gctrace/gcstats.cpp +++ b/js/src/devtools/gctrace/gcstats.cpp @@ -160,16 +160,17 @@ Array<uint64_t, MaxClasses> objectCountB std::vector<uint64_t> objectCountByType; Array<Array<uint64_t, MaxClasses>, HeapKinds> objectCountByHeapAndClass; Array<Array<Array<uint64_t, MaxLifetimeBins>, MaxClasses>, HeapKinds> objectCountByHeapClassAndLifetime; Array<Array<uint64_t, MaxLifetimeBins>, FinalizerKinds> heapObjectCountByFinalizerAndLifetime; Array<Array<uint64_t, MaxLifetimeBins>, MaxClasses> finalizedHeapObjectCountByClassAndLifetime; std::vector<Array<Array<uint64_t, MaxLifetimeBins>, HeapKinds> > objectCountByTypeHeapAndLifetime; static void +MOZ_FORMAT_PRINTF(1, 2) die(const char* format, ...) { va_list va; va_start(va, format); vfprintf(stderr, format, va); fprintf(stderr, "\n"); va_end(va); exit(1);
--- a/js/src/gc/Verifier.cpp +++ b/js/src/gc/Verifier.cpp @@ -530,17 +530,17 @@ CheckHeapTracer::check(AutoLockForExclus stack.back().processed = true; } } if (oom) return; if (failures) { - fprintf(stderr, "Heap check: %zu failure(s) out of %" PRIu32 " pointers checked\n", + fprintf(stderr, "Heap check: %" PRIuSIZE " failure(s) out of %" PRIu32 " pointers checked\n", failures, visited.count()); } MOZ_RELEASE_ASSERT(failures == 0); } void js::gc::CheckHeapAfterGC(JSRuntime* rt) {
--- a/js/src/irregexp/RegExpEngine.cpp +++ b/js/src/irregexp/RegExpEngine.cpp @@ -1867,17 +1867,17 @@ irregexp::CompilePattern(JSContext* cx, } if (node == nullptr) node = alloc.newInfallible<EndNode>(&alloc, EndNode::BACKTRACK); Analysis analysis(cx, ignore_case, is_ascii, unicode); analysis.EnsureAnalyzed(node); if (analysis.has_failed()) { - JS_ReportErrorASCII(cx, analysis.errorMessage()); + JS_ReportErrorASCII(cx, "%s", analysis.errorMessage()); return RegExpCode(); } Maybe<jit::JitContext> ctx; Maybe<NativeRegExpMacroAssembler> native_assembler; Maybe<InterpretedRegExpMacroAssembler> interpreted_assembler; RegExpMacroAssembler* assembler;
--- a/js/src/jit/BacktrackingAllocator.cpp +++ b/js/src/jit/BacktrackingAllocator.cpp @@ -1240,17 +1240,17 @@ BacktrackingAllocator::tryAllocateNonFix MOZ_ASSERT(!*success); return true; } bool BacktrackingAllocator::processBundle(MIRGenerator* mir, LiveBundle* bundle) { if (JitSpewEnabled(JitSpew_RegAlloc)) { - JitSpew(JitSpew_RegAlloc, "Allocating %s [priority %lu] [weight %lu]", + JitSpew(JitSpew_RegAlloc, "Allocating %s [priority %" PRIuSIZE "] [weight %" PRIuSIZE "]", bundle->toString().get(), computePriority(bundle), computeSpillWeight(bundle)); } // A bundle can be processed by doing any of the following: // // - Assigning the bundle a register. The bundle cannot overlap any other // bundle allocated for that physical register. // @@ -1432,23 +1432,23 @@ BacktrackingAllocator::tryAllocateRegist // case of multiple conflicting sets keep track of the set with the // lowest maximum spill weight. // The #ifdef guards against "unused variable 'existing'" bustage. #ifdef JS_JITSPEW if (JitSpewEnabled(JitSpew_RegAlloc)) { if (aliasedConflicting.length() == 1) { LiveBundle* existing = aliasedConflicting[0]; - JitSpew(JitSpew_RegAlloc, " %s collides with %s [weight %lu]", + JitSpew(JitSpew_RegAlloc, " %s collides with %s [weight %" PRIuSIZE "]", r.reg.name(), existing->toString().get(), computeSpillWeight(existing)); } else { JitSpew(JitSpew_RegAlloc, " %s collides with the following", r.reg.name()); for (size_t i = 0; i < aliasedConflicting.length(); i++) { LiveBundle* existing = aliasedConflicting[i]; - JitSpew(JitSpew_RegAlloc, " %s [weight %lu]", + JitSpew(JitSpew_RegAlloc, " %s [weight %" PRIuSIZE "]", existing->toString().get(), computeSpillWeight(existing)); } } } #endif if (conflicting.empty()) { if (!conflicting.appendAll(aliasedConflicting)) @@ -1477,17 +1477,17 @@ BacktrackingAllocator::tryAllocateRegist *success = true; return true; } bool BacktrackingAllocator::evictBundle(LiveBundle* bundle) { if (JitSpewEnabled(JitSpew_RegAlloc)) { - JitSpew(JitSpew_RegAlloc, " Evicting %s [priority %lu] [weight %lu]", + JitSpew(JitSpew_RegAlloc, " Evicting %s [priority %" PRIuSIZE "] [weight %" PRIuSIZE "]", bundle->toString().get(), computePriority(bundle), computeSpillWeight(bundle)); } AnyRegister reg(bundle->allocation().toRegister()); PhysicalRegister& physical = registers[reg.code()]; MOZ_ASSERT(physical.reg == reg && physical.allocatable); for (LiveRange::BundleLinkIterator iter = bundle->rangesBegin(); iter; iter++) { @@ -2291,17 +2291,18 @@ LiveRange::toString() const return UniqueChars(buf); } UniqueChars LiveBundle::toString() const { AutoEnterOOMUnsafeRegion oomUnsafe; - char *buf = JS_smprintf(""); + // Suppress -Wformat warning. + char *buf = JS_smprintf("%s", ""); for (LiveRange::BundleLinkIterator iter = rangesBegin(); buf && iter; iter++) { buf = JS_sprintf_append(buf, "%s %s", (iter == rangesBegin()) ? "" : " ##", LiveRange::get(*iter)->toString().get()); } if (!buf)
--- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -225,33 +225,33 @@ struct BaselineStackBuilder } MOZ_MUST_USE bool writeWord(size_t w, const char* info) { if (!write<size_t>(w)) return false; if (info) { if (sizeof(size_t) == 4) { JitSpew(JitSpew_BaselineBailouts, - " WRITE_WRD %p/%p %-15s %08x", + " WRITE_WRD %p/%p %-15s %08" PRIxSIZE, header_->copyStackBottom, virtualPointerAtStackOffset(0), info, w); } else { JitSpew(JitSpew_BaselineBailouts, - " WRITE_WRD %p/%p %-15s %016llx", + " WRITE_WRD %p/%p %-15s %016" PRIxSIZE, header_->copyStackBottom, virtualPointerAtStackOffset(0), info, w); } } return true; } MOZ_MUST_USE bool writeValue(const Value& val, const char* info) { if (!write<Value>(val)) return false; if (info) { JitSpew(JitSpew_BaselineBailouts, - " WRITE_VAL %p/%p %-15s %016llx", + " WRITE_VAL %p/%p %-15s %016" PRIx64, header_->copyStackBottom, virtualPointerAtStackOffset(0), info, *((uint64_t*) &val)); } return true; } MOZ_MUST_USE bool maybeWritePadding(size_t alignment, size_t after, const char* info) { MOZ_ASSERT(framePushed_ % sizeof(Value) == 0); @@ -632,17 +632,17 @@ InitFromBailout(JSContext* cx, HandleScr // +---------------+ // | StackS | // +---------------+ --- IF NOT LAST INLINE FRAME, // | Descr(BLJS) | --- CALLING INFO STARTS HERE // +---------------+ // | ReturnAddr | <-- return into main jitcode after IC // +===============+ - JitSpew(JitSpew_BaselineBailouts, " Unpacking %s:%d", script->filename(), script->lineno()); + JitSpew(JitSpew_BaselineBailouts, " Unpacking %s:%" PRIuSIZE, script->filename(), script->lineno()); JitSpew(JitSpew_BaselineBailouts, " [BASELINE-JS FRAME]"); // Calculate and write the previous frame pointer value. // Record the virtual stack offset at this location. Later on, if we end up // writing out a BaselineStub frame for the next callee, we'll need to save the // address. void* prevFramePtr = builder.calculatePrevFramePtr(); if (!builder.writePtr(prevFramePtr, "PrevFramePtr")) @@ -744,54 +744,54 @@ InitFromBailout(JSContext* cx, HandleScr v = iter.read(); MOZ_ASSERT(v.isObject() || v.isUndefined() || v.isMagic(JS_OPTIMIZED_OUT)); if (v.isObject()) argsObj = &v.toObject().as<ArgumentsObject>(); } } JitSpew(JitSpew_BaselineBailouts, " EnvChain=%p", envChain); blFrame->setEnvironmentChain(envChain); - JitSpew(JitSpew_BaselineBailouts, " ReturnValue=%016llx", *((uint64_t*) &returnValue)); + JitSpew(JitSpew_BaselineBailouts, " ReturnValue=%016" PRIx64, *((uint64_t*) &returnValue)); blFrame->setReturnValue(returnValue); // Do not need to initialize scratchValue field in BaselineFrame. blFrame->setFlags(flags); // initArgsObjUnchecked modifies the frame's flags, so call it after setFlags. if (argsObj) blFrame->initArgsObjUnchecked(*argsObj); if (fun) { // The unpacked thisv and arguments should overwrite the pushed args present // in the calling frame. Value thisv = iter.read(); JitSpew(JitSpew_BaselineBailouts, " Is function!"); - JitSpew(JitSpew_BaselineBailouts, " thisv=%016llx", *((uint64_t*) &thisv)); + JitSpew(JitSpew_BaselineBailouts, " thisv=%016" PRIx64, *((uint64_t*) &thisv)); size_t thisvOffset = builder.framePushed() + JitFrameLayout::offsetOfThis(); builder.valuePointerAtStackOffset(thisvOffset).set(thisv); MOZ_ASSERT(iter.numAllocations() >= CountArgSlots(script, fun)); - JitSpew(JitSpew_BaselineBailouts, " frame slots %u, nargs %u, nfixed %u", + JitSpew(JitSpew_BaselineBailouts, " frame slots %u, nargs %" PRIuSIZE ", nfixed %" PRIuSIZE, iter.numAllocations(), fun->nargs(), script->nfixed()); if (!callerPC) { // This is the first frame. Store the formals in a Vector until we // are done. Due to UCE and phi elimination, we could store an // UndefinedValue() here for formals we think are unused, but // locals may still reference the original argument slot // (MParameter/LArgument) and expect the original Value. MOZ_ASSERT(startFrameFormals.empty()); if (!startFrameFormals.resize(fun->nargs())) return false; } for (uint32_t i = 0; i < fun->nargs(); i++) { Value arg = iter.read(); - JitSpew(JitSpew_BaselineBailouts, " arg %d = %016llx", + JitSpew(JitSpew_BaselineBailouts, " arg %d = %016" PRIx64, (int) i, *((uint64_t*) &arg)); if (callerPC) { size_t argOffset = builder.framePushed() + JitFrameLayout::offsetOfActualArg(i); builder.valuePointerAtStackOffset(argOffset).set(arg); } else { startFrameFormals[i].set(arg); } } @@ -1309,17 +1309,17 @@ InitFromBailout(JSContext* cx, HandleScr JitFrame_BaselineStub, JitFrameLayout::Size()); // Push actual argc if (!builder.writeWord(actualArgc, "ActualArgc")) return false; // Push callee token (must be a JS Function) - JitSpew(JitSpew_BaselineBailouts, " Callee = %016llx", callee.asRawBits()); + JitSpew(JitSpew_BaselineBailouts, " Callee = %016" PRIx64, callee.asRawBits()); JSFunction* calleeFun = &callee.toObject().as<JSFunction>(); if (!builder.writePtr(CalleeToToken(calleeFun, JSOp(*pc) == JSOP_NEW), "CalleeToken")) return false; nextCallee.set(calleeFun); // Push BaselineStub frame descriptor if (!builder.writeWord(baselineStubFrameDescr, "Descriptor")) @@ -1489,17 +1489,17 @@ jit::BailoutIonToBaseline(JSContext* cx, // +---------------+ // | ReturnAddr | // +---------------+ // | ||||| | <---- Overwrite starting here. // | ||||| | // | ||||| | // +---------------+ - JitSpew(JitSpew_BaselineBailouts, "Bailing to baseline %s:%u (IonScript=%p) (FrameType=%d)", + JitSpew(JitSpew_BaselineBailouts, "Bailing to baseline %s:%" PRIuSIZE " (IonScript=%p) (FrameType=%d)", iter.script()->filename(), iter.script()->lineno(), (void*) iter.ionScript(), (int) prevFrameType); bool catchingException; bool propagatingExceptionForDebugMode; if (excInfo) { catchingException = excInfo->catchingException(); propagatingExceptionForDebugMode = excInfo->propagatingIonExceptionForDebugMode(); @@ -1509,17 +1509,17 @@ jit::BailoutIonToBaseline(JSContext* cx, if (propagatingExceptionForDebugMode) JitSpew(JitSpew_BaselineBailouts, "Resuming in-place for debug mode"); } else { catchingException = false; propagatingExceptionForDebugMode = false; } - JitSpew(JitSpew_BaselineBailouts, " Reading from snapshot offset %u size %u", + JitSpew(JitSpew_BaselineBailouts, " Reading from snapshot offset %u size %" PRIuSIZE, iter.snapshotOffset(), iter.ionScript()->snapshotsListSize()); if (!excInfo) iter.ionScript()->incNumBailouts(); iter.script()->updateBaselineOrIonRaw(cx->runtime()); // Allocate buffer to hold stack replacement data. BaselineStackBuilder builder(iter, 1024); @@ -1535,17 +1535,17 @@ jit::BailoutIonToBaseline(JSContext* cx, #ifdef TRACK_SNAPSHOTS snapIter.spewBailingFrom(); #endif RootedFunction callee(cx, iter.maybeCallee()); RootedScript scr(cx, iter.script()); if (callee) { - JitSpew(JitSpew_BaselineBailouts, " Callee function (%s:%u)", + JitSpew(JitSpew_BaselineBailouts, " Callee function (%s:%" PRIuSIZE ")", scr->filename(), scr->lineno()); } else { JitSpew(JitSpew_BaselineBailouts, " No callee!"); } if (iter.isConstructing()) JitSpew(JitSpew_BaselineBailouts, " Constructing!"); else @@ -1570,17 +1570,17 @@ jit::BailoutIonToBaseline(JSContext* cx, // TraceLogger doesn't create entries for inlined frames. But we // see them in Baseline. Here we create the start events of those // entries. So they correspond to what we will see in Baseline. TraceLoggerEvent scriptEvent(logger, TraceLogger_Scripts, scr); TraceLogStartEvent(logger, scriptEvent); TraceLogStartEvent(logger, TraceLogger_Baseline); } - JitSpew(JitSpew_BaselineBailouts, " FrameNo %d", frameNo); + JitSpew(JitSpew_BaselineBailouts, " FrameNo %" PRIuSIZE, frameNo); // If we are bailing out to a catch or finally block in this frame, // pass excInfo to InitFromBailout and don't unpack any other frames. bool handleException = (catchingException && excInfo->frameNo() == frameNo); // We also need to pass excInfo if we're bailing out in place for // debug mode. bool passExcInfo = handleException || propagatingExceptionForDebugMode; @@ -1666,57 +1666,57 @@ InvalidateAfterBailout(JSContext* cx, Ha JitSpew(JitSpew_BaselineBailouts, "Invalidating due to %s", reason); Invalidate(cx, outerScript); } static void HandleBoundsCheckFailure(JSContext* cx, HandleScript outerScript, HandleScript innerScript) { - JitSpew(JitSpew_IonBailouts, "Bounds check failure %s:%d, inlined into %s:%d", + JitSpew(JitSpew_IonBailouts, "Bounds check failure %s:%" PRIuSIZE ", inlined into %s:%" PRIuSIZE, innerScript->filename(), innerScript->lineno(), outerScript->filename(), outerScript->lineno()); if (!innerScript->failedBoundsCheck()) innerScript->setFailedBoundsCheck(); InvalidateAfterBailout(cx, outerScript, "bounds check failure"); if (innerScript->hasIonScript()) Invalidate(cx, innerScript); } static void HandleShapeGuardFailure(JSContext* cx, HandleScript outerScript, HandleScript innerScript) { - JitSpew(JitSpew_IonBailouts, "Shape guard failure %s:%d, inlined into %s:%d", + JitSpew(JitSpew_IonBailouts, "Shape guard failure %s:%" PRIuSIZE ", inlined into %s:%" PRIuSIZE, innerScript->filename(), innerScript->lineno(), outerScript->filename(), outerScript->lineno()); // TODO: Currently this mimic's Ion's handling of this case. Investigate setting // the flag on innerScript as opposed to outerScript, and maybe invalidating both // inner and outer scripts, instead of just the outer one. outerScript->setFailedShapeGuard(); InvalidateAfterBailout(cx, outerScript, "shape guard failure"); } static void HandleBaselineInfoBailout(JSContext* cx, HandleScript outerScript, HandleScript innerScript) { - JitSpew(JitSpew_IonBailouts, "Baseline info failure %s:%d, inlined into %s:%d", + JitSpew(JitSpew_IonBailouts, "Baseline info failure %s:%" PRIuSIZE ", inlined into %s:%" PRIuSIZE, innerScript->filename(), innerScript->lineno(), outerScript->filename(), outerScript->lineno()); InvalidateAfterBailout(cx, outerScript, "invalid baseline info"); } static void HandleLexicalCheckFailure(JSContext* cx, HandleScript outerScript, HandleScript innerScript) { - JitSpew(JitSpew_IonBailouts, "Lexical check failure %s:%d, inlined into %s:%d", + JitSpew(JitSpew_IonBailouts, "Lexical check failure %s:%" PRIuSIZE ", inlined into %s:%" PRIuSIZE, innerScript->filename(), innerScript->lineno(), outerScript->filename(), outerScript->lineno()); if (!innerScript->failedLexicalCheck()) innerScript->setFailedLexicalCheck(); InvalidateAfterBailout(cx, outerScript, "lexical check failure"); if (innerScript->hasIonScript()) @@ -1749,17 +1749,17 @@ CopyFromRematerializedFrame(JSContext* c *frame->valueSlot(i) = rematFrame->locals()[i]; frame->setReturnValue(rematFrame->returnValue()); if (rematFrame->hasCachedSavedFrame()) frame->setHasCachedSavedFrame(); JitSpew(JitSpew_BaselineBailouts, - " Copied from rematerialized frame at (%p,%u)", + " Copied from rematerialized frame at (%p,%" PRIuSIZE ")", fp, inlineDepth); // Propagate the debuggee frame flag. For the case where the Debugger did // not rematerialize an Ion frame, the baseline frame has its debuggee // flag set iff its script is considered a debuggee. See the debuggee case // in InitFromBailout. if (rematFrame->isDebuggee()) { frame->setIsDebuggee(); @@ -1886,17 +1886,17 @@ jit::FinishBailoutToBaseline(BaselineBai // the table to keep the table up to date. act->removeRematerializedFrame(outerFp); if (!ok) return false; } JitSpew(JitSpew_BaselineBailouts, - " Restored outerScript=(%s:%u,%u) innerScript=(%s:%u,%u) (bailoutKind=%u)", + " Restored outerScript=(%s:%" PRIuSIZE ",%u) innerScript=(%s:%" PRIuSIZE ",%u) (bailoutKind=%u)", outerScript->filename(), outerScript->lineno(), outerScript->getWarmUpCount(), innerScript->filename(), innerScript->lineno(), innerScript->getWarmUpCount(), (unsigned) bailoutKind); switch (bailoutKind) { // Normal bailouts. case Bailout_Inevitable: case Bailout_DuringVMCall:
--- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -2,16 +2,17 @@ * vim: set ts=8 sts=4 et sw=4 tw=99: * 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 "jit/BaselineCompiler.h" #include "mozilla/Casting.h" +#include "mozilla/SizePrintfMacros.h" #include "jit/BaselineIC.h" #include "jit/BaselineJIT.h" #include "jit/FixedList.h" #include "jit/IonAnalysis.h" #include "jit/JitcodeMap.h" #include "jit/JitSpewer.h" #include "jit/Linker.h" @@ -77,20 +78,20 @@ BaselineCompiler::addPCMappingEntry(bool entry.addIndexEntry = addIndexEntry; return pcMappingEntries_.append(entry); } MethodStatus BaselineCompiler::compile() { - JitSpew(JitSpew_BaselineScripts, "Baseline compiling script %s:%d (%p)", + JitSpew(JitSpew_BaselineScripts, "Baseline compiling script %s:%" PRIuSIZE " (%p)", script->filename(), script->lineno(), script); - JitSpew(JitSpew_Codegen, "# Emitting baseline code for script %s:%d", + JitSpew(JitSpew_Codegen, "# Emitting baseline code for script %s:%" PRIuSIZE, script->filename(), script->lineno()); TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime()); TraceLoggerEvent scriptEvent(logger, TraceLogger_AnnotateScripts, script); AutoTraceLog logScript(logger, scriptEvent); AutoTraceLog logCompile(logger, TraceLogger_BaselineCompilation); if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx)) @@ -212,17 +213,17 @@ BaselineCompiler::compile() if (!baselineScript) { ReportOutOfMemory(cx); return Method_Error; } baselineScript->setMethod(code); baselineScript->setTemplateEnvironment(templateEnv); - JitSpew(JitSpew_BaselineScripts, "Created BaselineScript %p (raw %p) for %s:%d", + JitSpew(JitSpew_BaselineScripts, "Created BaselineScript %p (raw %p) for %s:%" PRIuSIZE, (void*) baselineScript.get(), (void*) code->raw(), script->filename(), script->lineno()); #ifdef JS_ION_PERF writePerfSpewerBaselineProfile(script, code); #endif MOZ_ASSERT(pcMappingIndexEntries.length() > 0); @@ -274,17 +275,17 @@ BaselineCompiler::compile() baselineScript->copyYieldEntries(script, yieldOffsets_); if (compileDebugInstrumentation_) baselineScript->setHasDebugInstrumentation(); // Always register a native => bytecode mapping entry, since profiler can be // turned on with baseline jitcode on stack, and baseline jitcode cannot be invalidated. { - JitSpew(JitSpew_Profiling, "Added JitcodeGlobalEntry for baseline script %s:%d (%p)", + JitSpew(JitSpew_Profiling, "Added JitcodeGlobalEntry for baseline script %s:%" PRIuSIZE " (%p)", script->filename(), script->lineno(), baselineScript.get()); // Generate profiling string. char* str = JitcodeGlobalEntry::createScriptString(cx, script); if (!str) return Method_Error; JitcodeGlobalEntry::BaselineEntry entry;
--- a/js/src/jit/BaselineDebugModeOSR.cpp +++ b/js/src/jit/BaselineDebugModeOSR.cpp @@ -2,16 +2,17 @@ * vim: set ts=8 sts=4 et sw=4 tw=99: * 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 "jit/BaselineDebugModeOSR.h" #include "mozilla/DebugOnly.h" +#include "mozilla/SizePrintfMacros.h" #include "jit/BaselineIC.h" #include "jit/JitcodeMap.h" #include "jit/Linker.h" #include "jit/PerfSpewer.h" #include "jit/JitFrames-inl.h" #include "jit/MacroAssembler-inl.h" @@ -317,27 +318,27 @@ ICEntryKindToString(ICEntry::Kind kind) } #endif // JS_JITSPEW static void SpewPatchBaselineFrame(uint8_t* oldReturnAddress, uint8_t* newReturnAddress, JSScript* script, ICEntry::Kind frameKind, jsbytecode* pc) { JitSpew(JitSpew_BaselineDebugModeOSR, - "Patch return %p -> %p on BaselineJS frame (%s:%d) from %s at %s", + "Patch return %p -> %p on BaselineJS frame (%s:%" PRIuSIZE ") from %s at %s", oldReturnAddress, newReturnAddress, script->filename(), script->lineno(), ICEntryKindToString(frameKind), CodeName[(JSOp)*pc]); } static void SpewPatchBaselineFrameFromExceptionHandler(uint8_t* oldReturnAddress, uint8_t* newReturnAddress, JSScript* script, jsbytecode* pc) { JitSpew(JitSpew_BaselineDebugModeOSR, - "Patch return %p -> %p on BaselineJS frame (%s:%d) from exception handler at %s", + "Patch return %p -> %p on BaselineJS frame (%s:%" PRIuSIZE ") from exception handler at %s", oldReturnAddress, newReturnAddress, script->filename(), script->lineno(), CodeName[(JSOp)*pc]); } static void SpewPatchStubFrame(ICStub* oldStub, ICStub* newStub) { JitSpew(JitSpew_BaselineDebugModeOSR, @@ -662,17 +663,17 @@ RecompileBaselineScriptForDebugMode(JSCo { BaselineScript* oldBaselineScript = script->baselineScript(); // If a script is on the stack multiple times, it may have already // been recompiled. if (oldBaselineScript->hasDebugInstrumentation() == observing) return true; - JitSpew(JitSpew_BaselineDebugModeOSR, "Recompiling (%s:%d) for %s", + JitSpew(JitSpew_BaselineDebugModeOSR, "Recompiling (%s:%" PRIuSIZE ") for %s", script->filename(), script->lineno(), observing ? "DEBUGGING" : "NORMAL EXECUTION"); script->setBaselineScript(cx->runtime(), nullptr); MethodStatus status = BaselineCompile(cx, script, /* forceDebugMode = */ observing); if (status != Method_Compiled) { // We will only fail to recompile for debug mode due to OOM. Restore // the old baseline script in case something doesn't properly
--- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -2581,17 +2581,17 @@ DoSetElemFallback(JSContext* cx, Baselin return false; if (addingCase && !DenseOrUnboxedArraySetElemStubExists(cx, ICStub::SetElem_DenseOrUnboxedArrayAdd, stub, obj)) { JitSpew(JitSpew_BaselineIC, " Generating SetElem_DenseOrUnboxedArrayAdd stub " - "(shape=%p, group=%p, protoDepth=%u)", + "(shape=%p, group=%p, protoDepth=%" PRIuSIZE ")", shape.get(), group.get(), protoDepth); ICSetElemDenseOrUnboxedArrayAddCompiler compiler(cx, obj, protoDepth); ICUpdatedStub* newStub = compiler.getStub(compiler.getStubSpace(outerScript)); if (!newStub) return false; if (compiler.needsUpdateStubs() && !newStub->addUpdateStubForValue(cx, outerScript, obj, JSID_VOIDHANDLE, rhs)) {
--- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -9239,17 +9239,17 @@ CodeGenerator::generateWasm(wasm::SigIdD MOZ_ASSERT(safepoints_.size() == 0); MOZ_ASSERT(!scriptCounts_); return true; } bool CodeGenerator::generate() { - JitSpew(JitSpew_Codegen, "# Emitting code for script %s:%d", + JitSpew(JitSpew_Codegen, "# Emitting code for script %s:%" PRIuSIZE, gen->info().script()->filename(), gen->info().script()->lineno()); // Initialize native code table with an entry to the start of // top-level script. InlineScriptTree* tree = gen->info().inlineScriptTree(); jsbytecode* startPC = tree->script()->code(); BytecodeSite* startSite = new(gen->alloc()) BytecodeSite(tree, startPC);
--- a/js/src/jit/FlowAliasAnalysis.cpp +++ b/js/src/jit/FlowAliasAnalysis.cpp @@ -397,17 +397,17 @@ DumpLoopInvariant(MDefinition* load, MBa static void DumpImprovement(MDefinition *load, MDefinitionVector& input, MDefinitionVector& output) { #ifdef JS_JITSPEW if (JitSpewEnabled(JitSpew_Alias)) { Fprinter &print = JitSpewPrinter(); JitSpewHeader(JitSpew_Alias); - print.printf(" Improve dependency from ", load->id()); + print.printf(" Improve dependency from %d", load->id()); DumpStoreList(input); print.printf(" to "); DumpStoreList(output); print.printf("\n"); } #endif }
--- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -1,16 +1,17 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * 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 "jit/Ion.h" +#include "mozilla/IntegerPrintfMacros.h" #include "mozilla/MemoryReporting.h" #include "mozilla/SizePrintfMacros.h" #include "mozilla/ThreadLocal.h" #include "jscompartment.h" #include "jsgc.h" #include "jsprf.h" @@ -2131,17 +2132,17 @@ TrackIonAbort(JSContext* cx, JSScript* s void* ptr = script->baselineScript()->method()->raw(); JitcodeGlobalEntry& entry = table->lookupInfallible(ptr); entry.baselineEntry().trackIonAbort(pc, message); } static void TrackAndSpewIonAbort(JSContext* cx, JSScript* script, const char* message) { - JitSpew(JitSpew_IonAbort, message); + JitSpew(JitSpew_IonAbort, "%s", message); TrackIonAbort(cx, script, script->code(), message); } static AbortReason IonCompile(JSContext* cx, JSScript* script, BaselineFrame* baselineFrame, jsbytecode* osrPc, bool recompile, OptimizationLevel optimizationLevel) { @@ -2390,17 +2391,17 @@ CheckScriptSize(JSContext* cx, JSScript* return Method_Compiled; uint32_t numLocalsAndArgs = NumLocalsAndArgs(script); if (script->length() > MAX_MAIN_THREAD_SCRIPT_SIZE || numLocalsAndArgs > MAX_MAIN_THREAD_LOCALS_AND_ARGS) { if (!OffThreadCompilationAvailable(cx)) { - JitSpew(JitSpew_IonAbort, "Script too large (%u bytes) (%u locals/args)", + JitSpew(JitSpew_IonAbort, "Script too large (%" PRIuSIZE " bytes) (%u locals/args)", script->length(), numLocalsAndArgs); TrackIonAbort(cx, script, script->code(), "too large"); return Method_CantCompile; } } return Method_Compiled; } @@ -3007,51 +3008,51 @@ InvalidateActivation(FreeOp* fop, const size_t frameno = 1; for (JitFrameIterator it(activations); !it.done(); ++it, ++frameno) { MOZ_ASSERT_IF(frameno == 1, it.isExitFrame() || it.type() == JitFrame_Bailout); #ifdef JS_JITSPEW switch (it.type()) { case JitFrame_Exit: - JitSpew(JitSpew_IonInvalidate, "#%d exit frame @ %p", frameno, it.fp()); + JitSpew(JitSpew_IonInvalidate, "#%" PRIuSIZE " exit frame @ %p", frameno, it.fp()); break; case JitFrame_BaselineJS: case JitFrame_IonJS: case JitFrame_Bailout: { MOZ_ASSERT(it.isScripted()); const char* type = "Unknown"; if (it.isIonJS()) type = "Optimized"; else if (it.isBaselineJS()) type = "Baseline"; else if (it.isBailoutJS()) type = "Bailing"; JitSpew(JitSpew_IonInvalidate, - "#%d %s JS frame @ %p, %s:%" PRIuSIZE " (fun: %p, script: %p, pc %p)", + "#%" PRIuSIZE " %s JS frame @ %p, %s:%" PRIuSIZE " (fun: %p, script: %p, pc %p)", frameno, type, it.fp(), it.script()->maybeForwardedFilename(), it.script()->lineno(), it.maybeCallee(), (JSScript*)it.script(), it.returnAddressToFp()); break; } case JitFrame_IonStub: - JitSpew(JitSpew_IonInvalidate, "#%d ion stub frame @ %p", frameno, it.fp()); + JitSpew(JitSpew_IonInvalidate, "#%" PRIuSIZE " ion stub frame @ %p", frameno, it.fp()); break; case JitFrame_BaselineStub: - JitSpew(JitSpew_IonInvalidate, "#%d baseline stub frame @ %p", frameno, it.fp()); + JitSpew(JitSpew_IonInvalidate, "#%" PRIuSIZE " baseline stub frame @ %p", frameno, it.fp()); break; case JitFrame_Rectifier: - JitSpew(JitSpew_IonInvalidate, "#%d rectifier frame @ %p", frameno, it.fp()); + JitSpew(JitSpew_IonInvalidate, "#%" PRIuSIZE " rectifier frame @ %p", frameno, it.fp()); break; case JitFrame_IonAccessorIC: - JitSpew(JitSpew_IonInvalidate, "#%d ion IC getter/setter frame @ %p", frameno, it.fp()); + JitSpew(JitSpew_IonInvalidate, "#%" PRIuSIZE " ion IC getter/setter frame @ %p", frameno, it.fp()); break; case JitFrame_Entry: - JitSpew(JitSpew_IonInvalidate, "#%d entry frame @ %p", frameno, it.fp()); + JitSpew(JitSpew_IonInvalidate, "#%" PRIuSIZE " entry frame @ %p", frameno, it.fp()); break; } #endif // JS_JITSPEW if (!it.isIonScripted()) continue; bool calledFromLinkStub = false; @@ -3136,17 +3137,17 @@ InvalidateActivation(FreeOp* fop, const CodeLocationLabel dataLabelToMunge(it.returnAddressToFp()); ptrdiff_t delta = ionScript->invalidateEpilogueDataOffset() - (it.returnAddressToFp() - ionCode->raw()); Assembler::PatchWrite_Imm32(dataLabelToMunge, Imm32(delta)); CodeLocationLabel osiPatchPoint = SafepointReader::InvalidationPatchPoint(ionScript, si); CodeLocationLabel invalidateEpilogue(ionCode, CodeOffset(ionScript->invalidateEpilogueOffset())); - JitSpew(JitSpew_IonInvalidate, " ! Invalidate ionScript %p (inv count %u) -> patching osipoint %p", + JitSpew(JitSpew_IonInvalidate, " ! Invalidate ionScript %p (inv count %" PRIuSIZE ") -> patching osipoint %p", ionScript, ionScript->invalidationCount(), (void*) osiPatchPoint.raw()); Assembler::PatchWrite_NearCall(osiPatchPoint, invalidateEpilogue); } JitSpew(JitSpew_IonInvalidate, "END invalidating activation"); } void @@ -3353,17 +3354,17 @@ PerThreadData::setAutoFlushICache(AutoFl // AutoFlushICache context. void AutoFlushICache::setRange(uintptr_t start, size_t len) { #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) AutoFlushICache* afc = TlsPerThreadData.get()->PerThreadData::autoFlushICache(); MOZ_ASSERT(afc); MOZ_ASSERT(!afc->start_); - JitSpewCont(JitSpew_CacheFlush, "(%x %x):", start, len); + JitSpewCont(JitSpew_CacheFlush, "(%" PRIxPTR " %" PRIxSIZE "):", start, len); uintptr_t stop = start + len; afc->start_ = start; afc->stop_ = stop; #endif } // Flush the instruction cache.
--- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -1,16 +1,18 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * 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 "jit/IonAnalysis.h" +#include "mozilla/SizePrintfMacros.h" + #include "jit/AliasAnalysis.h" #include "jit/BaselineInspector.h" #include "jit/BaselineJIT.h" #include "jit/FlowAliasAnalysis.h" #include "jit/Ion.h" #include "jit/IonBuilder.h" #include "jit/IonOptimizationLevels.h" #include "jit/LIR.h" @@ -440,19 +442,20 @@ jit::PruneUnusedBranches(MIRGenerator* m // Interpreters are often implemented as a table switch within a for // loop. What might happen is that the interpreter heats up in a // subset of instructions, but might need other instructions for the // rest of the evaluation. if (numSuccessorsOfPreds > 8) shouldBailout = false; JitSpew(JitSpew_Prune, "info: block %d," - " predCount: %lu, domInst: %lu, span: %lu, effectful: %lu, " - " isLoopExit: %s, numSuccessorsOfPred: %lu." - " (score: %lu, shouldBailout: %s)", + " predCount: %" PRIuSIZE ", domInst: %" PRIuSIZE + ", span: %" PRIuSIZE ", effectful: %" PRIuSIZE ", " + " isLoopExit: %s, numSuccessorsOfPred: %" PRIuSIZE "." + " (score: %" PRIuSIZE ", shouldBailout: %s)", block->id(), predCount, numDominatedInst, branchSpan, numEffectfulInst, isLoopExit ? "true" : "false", numSuccessorsOfPreds, score, shouldBailout ? "true" : "false"); } // Continue to the next basic block if the current basic block can // remain unchanged. if (!isUnreachable && !shouldBailout)
--- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -224,17 +224,17 @@ class IonBuilder private: MOZ_MUST_USE bool traverseBytecode(); ControlStatus snoopControlFlow(JSOp op); MOZ_MUST_USE bool processIterators(); MOZ_MUST_USE bool inspectOpcode(JSOp op); uint32_t readIndex(jsbytecode* pc); JSAtom* readAtom(jsbytecode* pc); - bool abort(const char* message, ...); + bool abort(const char* message, ...) MOZ_FORMAT_PRINTF(2, 3); void trackActionableAbort(const char* message); void spew(const char* message); JSFunction* getSingleCallTarget(TemporaryTypeSet* calleeTypes); MOZ_MUST_USE bool getPolyCallTargets(TemporaryTypeSet* calleeTypes, bool constructing, ObjectVector& targets, uint32_t maxTargets); void popCfgStack();
--- a/js/src/jit/JSONSpewer.cpp +++ b/js/src/jit/JSONSpewer.cpp @@ -3,16 +3,18 @@ * 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/. */ #ifdef JS_JITSPEW #include "jit/JSONSpewer.h" +#include "mozilla/SizePrintfMacros.h" + #include <stdarg.h> #include "jit/BacktrackingAllocator.h" #include "jit/LIR.h" #include "jit/MIR.h" #include "jit/MIRGraph.h" #include "jit/RangeAnalysis.h" @@ -141,27 +143,27 @@ JSONSpewer::endList() first_ = false; } void JSONSpewer::beginFunction(JSScript* script) { beginObject(); if (script) - stringProperty("name", "%s:%d", script->filename(), script->lineno()); + stringProperty("name", "%s:%" PRIuSIZE, script->filename(), script->lineno()); else stringProperty("name", "asm.js compilation"); beginListProperty("passes"); } void JSONSpewer::beginPass(const char* pass) { beginObject(); - stringProperty("name", pass); + stringProperty("name", "%s", pass); } void JSONSpewer::spewMResumePoint(MResumePoint* rp) { if (!rp) return;
--- a/js/src/jit/JSONSpewer.h +++ b/js/src/jit/JSONSpewer.h @@ -31,18 +31,18 @@ class JSONSpewer GenericPrinter& out_; void indent(); void property(const char* name); void beginObject(); void beginObjectProperty(const char* name); void beginListProperty(const char* name); - void stringValue(const char* format, ...); - void stringProperty(const char* name, const char* format, ...); + void stringValue(const char* format, ...) MOZ_FORMAT_PRINTF(2, 3); + void stringProperty(const char* name, const char* format, ...) MOZ_FORMAT_PRINTF(3, 4); void beginStringProperty(const char* name); void endStringProperty(); void integerValue(int value); void integerProperty(const char* name, int value); void endObject(); void endList(); public:
--- a/js/src/jit/JitSpewer.h +++ b/js/src/jit/JitSpewer.h @@ -167,19 +167,19 @@ class JitSpewIndent { JitSpewChannel channel_; public: explicit JitSpewIndent(JitSpewChannel channel); ~JitSpewIndent(); }; -void JitSpew(JitSpewChannel channel, const char* fmt, ...); -void JitSpewStart(JitSpewChannel channel, const char* fmt, ...); -void JitSpewCont(JitSpewChannel channel, const char* fmt, ...); +void JitSpew(JitSpewChannel channel, const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3); +void JitSpewStart(JitSpewChannel channel, const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3); +void JitSpewCont(JitSpewChannel channel, const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3); void JitSpewFin(JitSpewChannel channel); void JitSpewHeader(JitSpewChannel channel); bool JitSpewEnabled(JitSpewChannel channel); void JitSpewVA(JitSpewChannel channel, const char* fmt, va_list ap); void JitSpewStartVA(JitSpewChannel channel, const char* fmt, va_list ap); void JitSpewContVA(JitSpewChannel channel, const char* fmt, va_list ap); void JitSpewDef(JitSpewChannel channel, const char* str, MDefinition* def);
--- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -5157,17 +5157,17 @@ MLoadSlot::printOpcode(GenericPrinter& o MDefinition::printOpcode(out); out.printf(" %d", slot()); } void MStoreSlot::printOpcode(GenericPrinter& out) const { PrintOpcodeName(out, op()); - out.printf(" ", slot()); + out.printf(" "); getOperand(0)->printName(out); out.printf(" %d ", slot()); getOperand(1)->printName(out); } MDefinition* MFunctionEnvironment::foldsTo(TempAllocator& alloc) {
--- a/js/src/jit/MIRGenerator.h +++ b/js/src/jit/MIRGenerator.h @@ -67,17 +67,17 @@ class MIRGenerator size_t bytes; if (MOZ_UNLIKELY(!CalculateAllocSize<T>(count, &bytes))) return nullptr; return static_cast<T*>(alloc().allocate(bytes)); } // Set an error state and prints a message. Returns false so errors can be // propagated up. - bool abort(const char* message, ...); // always returns false + bool abort(const char* message, ...) MOZ_FORMAT_PRINTF(2, 3); // always returns false bool abortFmt(const char* message, va_list ap); // always returns false bool errored() const { return error_; } MOZ_MUST_USE bool instrumentedProfiling() { if (!instrumentedProfilingIsCached_) {
--- a/js/src/jit/OptimizationTracking.cpp +++ b/js/src/jit/OptimizationTracking.cpp @@ -321,17 +321,17 @@ UniqueTrackedOptimizations::sortByFreque for (size_t i = 0; i < entries.length(); i++) { Key key; key.types = entries[i].types; key.attempts = entries[i].attempts; AttemptsMap::Ptr p = map_.lookup(key); MOZ_ASSERT(p); p->value().index = sorted_.length(); - JitSpew(JitSpew_OptimizationTracking, " Entry %u has frequency %u", + JitSpew(JitSpew_OptimizationTracking, " Entry %" PRIuSIZE " has frequency %" PRIu32, sorted_.length(), p->value().frequency); if (!sorted_.append(entries[i])) return false; } return true; } @@ -760,41 +760,41 @@ IonTrackedOptimizationsRegion::WriteDelt /* static */ bool IonTrackedOptimizationsRegion::WriteRun(CompactBufferWriter& writer, const NativeToTrackedOptimizations* start, const NativeToTrackedOptimizations* end, const UniqueTrackedOptimizations& unique) { // Write the header, which is the range that this whole run encompasses. - JitSpew(JitSpew_OptimizationTracking, " Header: [%u, %u]", + JitSpew(JitSpew_OptimizationTracking, " Header: [%" PRIuSIZE ", %" PRIuSIZE "]", start->startOffset.offset(), (end - 1)->endOffset.offset()); writer.writeUnsigned(start->startOffset.offset()); writer.writeUnsigned((end - 1)->endOffset.offset()); // Write the first entry of the run, which is not delta-encoded. JitSpew(JitSpew_OptimizationTracking, - " [%6u, %6u] vector %3u, offset %4u", + " [%6" PRIuSIZE ", %6" PRIuSIZE "] vector %3u, offset %4" PRIuSIZE, start->startOffset.offset(), start->endOffset.offset(), unique.indexOf(start->optimizations), writer.length()); uint32_t prevEndOffset = start->endOffset.offset(); writer.writeUnsigned(prevEndOffset); writer.writeByte(unique.indexOf(start->optimizations)); // Delta encode the run. for (const NativeToTrackedOptimizations* entry = start + 1; entry != end; entry++) { uint32_t startOffset = entry->startOffset.offset(); uint32_t endOffset = entry->endOffset.offset(); uint32_t startDelta = startOffset - prevEndOffset; uint32_t length = endOffset - startOffset; uint8_t index = unique.indexOf(entry->optimizations); JitSpew(JitSpew_OptimizationTracking, - " [%6u, %6u] delta [+%5u, +%5u] vector %3u, offset %4u", + " [%6u, %6u] delta [+%5u, +%5u] vector %3u, offset %4" PRIuSIZE, startOffset, endOffset, startDelta, length, index, writer.length()); WriteDelta(writer, startDelta, length, index); prevEndOffset = endOffset; } if (writer.oom()) @@ -820,17 +820,17 @@ WriteOffsetsTable(CompactBufferWriter& w uint32_t tableOffset = writer.length(); // Write how many bytes were padded and numEntries. writer.writeNativeEndianUint32_t(padding); writer.writeNativeEndianUint32_t(offsets.length()); // Write entry offset table. for (size_t i = 0; i < offsets.length(); i++) { - JitSpew(JitSpew_OptimizationTracking, " Entry %u reverse offset %u", + JitSpew(JitSpew_OptimizationTracking, " Entry %" PRIuSIZE " reverse offset %u", i, tableOffset - padding - offsets[i]); writer.writeNativeEndianUint32_t(tableOffset - padding - offsets[i]); } if (writer.oom()) return false; *tableOffsetp = tableOffset; @@ -880,17 +880,17 @@ SpewConstructor(TypeSet::Type ty, JSFunc PutEscapedString(buf, 512, constructor->displayAtom(), 0); else snprintf(buf, mozilla::ArrayLength(buf), "??"); const char* filename; Maybe<unsigned> lineno; InterpretedFunctionFilenameAndLineNumber(constructor, &filename, &lineno); - JitSpew(JitSpew_OptimizationTracking, " Unique type %s has constructor %s (%s:%" PRIuSIZE ")", + JitSpew(JitSpew_OptimizationTracking, " Unique type %s has constructor %s (%s:%u)", TypeSet::TypeString(ty), buf, filename, lineno.isSome() ? *lineno : 0); #endif } static void SpewAllocationSite(TypeSet::Type ty, JSScript* script, uint32_t offset) { #ifdef JS_JITSPEW @@ -914,32 +914,33 @@ jit::WriteIonTrackedOptimizationsTable(J MOZ_ASSERT(unique.sorted()); #ifdef JS_JITSPEW // Spew training data, which may be fed into a script to determine a good // encoding strategy. if (JitSpewEnabled(JitSpew_OptimizationTracking)) { JitSpewStart(JitSpew_OptimizationTracking, "=> Training data: "); for (const NativeToTrackedOptimizations* entry = start; entry != end; entry++) { - JitSpewCont(JitSpew_OptimizationTracking, "%u,%u,%u ", + JitSpewCont(JitSpew_OptimizationTracking, "%" PRIuSIZE ",%" PRIuSIZE ",%u ", entry->startOffset.offset(), entry->endOffset.offset(), unique.indexOf(entry->optimizations)); } JitSpewFin(JitSpew_OptimizationTracking); } #endif Vector<uint32_t, 16> offsets(cx); const NativeToTrackedOptimizations* entry = start; // Write out region offloads, partitioned into runs. JitSpew(JitSpew_Profiling, "=> Writing regions"); while (entry != end) { uint32_t runLength = IonTrackedOptimizationsRegion::ExpectedRunLength(entry, end); - JitSpew(JitSpew_OptimizationTracking, " Run at entry %u, length %u, offset %u", + JitSpew(JitSpew_OptimizationTracking, + " Run at entry %" PRIuSIZE ", length %" PRIu32 ", offset %" PRIuSIZE, entry - start, runLength, writer.length()); if (!offsets.append(writer.length())) return false; if (!IonTrackedOptimizationsRegion::WriteRun(writer, entry, entry + runLength, unique)) return false; @@ -952,27 +953,28 @@ jit::WriteIonTrackedOptimizationsTable(J *numRegions = offsets.length(); // Clear offsets so that it may be reused below for the unique // optimizations table. offsets.clear(); const UniqueTrackedOptimizations::SortedVector& vec = unique.sortedVector(); - JitSpew(JitSpew_OptimizationTracking, "=> Writing unique optimizations table with %u entr%s", + JitSpew(JitSpew_OptimizationTracking, "=> Writing unique optimizations table with %" PRIuSIZE " entr%s", vec.length(), vec.length() == 1 ? "y" : "ies"); // Write out type info payloads. UniqueTrackedTypes uniqueTypes(cx); if (!uniqueTypes.init()) return false; for (const UniqueTrackedOptimizations::SortEntry* p = vec.begin(); p != vec.end(); p++) { const TempOptimizationTypeInfoVector* v = p->types; - JitSpew(JitSpew_OptimizationTracking, " Type info entry %u of length %u, offset %u", + JitSpew(JitSpew_OptimizationTracking, + " Type info entry %" PRIuSIZE " of length %" PRIuSIZE ", offset %" PRIuSIZE, p - vec.begin(), v->length(), writer.length()); SpewTempOptimizationTypeInfoVector(v, " "); if (!offsets.append(writer.length())) return false; for (const OptimizationTypeInfo* t = v->begin(); t != v->end(); t++) { if (!t->writeCompact(cx, writer, uniqueTypes)) @@ -1012,17 +1014,18 @@ jit::WriteIonTrackedOptimizationsTable(J if (!WriteOffsetsTable(writer, offsets, typesTableOffsetp)) return false; offsets.clear(); // Write out attempts payloads. for (const UniqueTrackedOptimizations::SortEntry* p = vec.begin(); p != vec.end(); p++) { const TempOptimizationAttemptsVector* v = p->attempts; - JitSpew(JitSpew_OptimizationTracking, " Attempts entry %u of length %u, offset %u", + JitSpew(JitSpew_OptimizationTracking, + " Attempts entry %" PRIuSIZE " of length %" PRIuSIZE ", offset %" PRIuSIZE, p - vec.begin(), v->length(), writer.length()); SpewTempOptimizationAttemptsVector(v, " "); if (!offsets.append(writer.length())) return false; for (const OptimizationAttempt* a = v->begin(); a != v->end(); a++) a->writeCompact(writer);
--- a/js/src/jit/Recover.cpp +++ b/js/src/jit/Recover.cpp @@ -1,16 +1,18 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * 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 "jit/Recover.h" +#include "mozilla/SizePrintfMacros.h" + #include "jsapi.h" #include "jscntxt.h" #include "jsmath.h" #include "jsobj.h" #include "jsstr.h" #include "builtin/RegExp.h" #include "builtin/SIMD.h" @@ -118,17 +120,17 @@ MResumePoint::writeRecoverData(CompactBu MOZ_ASSERT(CountArgSlots(script, fun) < SNAPSHOT_MAX_NARGS + 4); #ifdef JS_JITSPEW uint32_t implicit = StartArgSlot(script); #endif uint32_t formalArgs = CountArgSlots(script, fun); uint32_t nallocs = formalArgs + script->nfixed() + exprStack; - JitSpew(JitSpew_IonSnapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u", + JitSpew(JitSpew_IonSnapshots, "Starting frame; implicit %u, formals %u, fixed %" PRIuSIZE ", exprs %u", implicit, formalArgs - implicit, script->nfixed(), exprStack); uint32_t pcoff = script->pcToOffset(pc()); JitSpew(JitSpew_IonSnapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs); writer.writeUnsigned(pcoff); writer.writeUnsigned(nallocs); return true; }
--- a/js/src/jit/Safepoints.cpp +++ b/js/src/jit/Safepoints.cpp @@ -2,16 +2,17 @@ * vim: set ts=8 sts=4 et sw=4 tw=99: * 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 "jit/Safepoints.h" #include "mozilla/MathAlgorithms.h" +#include "mozilla/SizePrintfMacros.h" #include "jit/BitSet.h" #include "jit/JitSpewer.h" #include "jit/LIR.h" using namespace js; using namespace jit; @@ -26,17 +27,17 @@ bool SafepointWriter::init(TempAllocator& alloc) { return frameSlots_.init(alloc) && argumentSlots_.init(alloc); } uint32_t SafepointWriter::startEntry() { - JitSpew(JitSpew_Safepoints, "Encoding safepoint (position %d):", stream_.length()); + JitSpew(JitSpew_Safepoints, "Encoding safepoint (position %" PRIuSIZE "):", stream_.length()); return uint32_t(stream_.length()); } void SafepointWriter::writeOsiCallPointOffset(uint32_t osiCallPointOffset) { stream_.writeUnsigned(osiCallPointOffset); }
--- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -2127,17 +2127,17 @@ UpdateExistingGenerationalDOMProxyStub(I for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) { if (iter->isGetProp_CallDOMProxyWithGenerationNative()) { ICGetProp_CallDOMProxyWithGenerationNative* updateStub = iter->toGetProp_CallDOMProxyWithGenerationNative(); if (updateStub->expandoAndGeneration() == expandoAndGeneration) { // Update generation uint64_t generation = expandoAndGeneration->generation; JitSpew(JitSpew_BaselineIC, - " Updating existing stub with generation, old value: %i, " + " Updating existing stub with generation, old value: %" PRIu64 ", " "new value: %" PRIu64 "", updateStub->generation(), generation); updateStub->setGeneration(generation); return true; } } } return false;
--- a/js/src/jit/SharedIC.h +++ b/js/src/jit/SharedIC.h @@ -197,18 +197,20 @@ class ICStub; class ICFallbackStub; #define FORWARD_DECLARE_STUBS(kindName) class IC##kindName; IC_BASELINE_STUB_KIND_LIST(FORWARD_DECLARE_STUBS) IC_SHARED_STUB_KIND_LIST(FORWARD_DECLARE_STUBS) #undef FORWARD_DECLARE_STUBS #ifdef JS_JITSPEW -void FallbackICSpew(JSContext* cx, ICFallbackStub* stub, const char* fmt, ...); -void TypeFallbackICSpew(JSContext* cx, ICTypeMonitor_Fallback* stub, const char* fmt, ...); +void FallbackICSpew(JSContext* cx, ICFallbackStub* stub, const char* fmt, ...) + MOZ_FORMAT_PRINTF(3, 4); +void TypeFallbackICSpew(JSContext* cx, ICTypeMonitor_Fallback* stub, const char* fmt, ...) + MOZ_FORMAT_PRINTF(3, 4); #else #define FallbackICSpew(...) #define TypeFallbackICSpew(...) #endif // // An entry in the JIT IC descriptor table. //
--- a/js/src/jit/ValueNumbering.cpp +++ b/js/src/jit/ValueNumbering.cpp @@ -997,17 +997,17 @@ ValueNumberer::visitBlock(MBasicBlock* b return visitControlInstruction(block, dominatorRoot); } // Visit all the blocks dominated by dominatorRoot. bool ValueNumberer::visitDominatorTree(MBasicBlock* dominatorRoot) { - JitSpew(JitSpew_GVN, " Visiting dominator tree (with %llu blocks) rooted at block%u%s", + JitSpew(JitSpew_GVN, " Visiting dominator tree (with %" PRIu64 " blocks) rooted at block%u%s", uint64_t(dominatorRoot->numDominated()), dominatorRoot->id(), dominatorRoot == graph_.entryBlock() ? " (normal entry block)" : dominatorRoot == graph_.osrBlock() ? " (OSR entry block)" : dominatorRoot->numPredecessors() == 0 ? " (odd unreachable block)" : " (merge point from normal entry and OSR entry)"); MOZ_ASSERT(dominatorRoot->immediateDominator() == dominatorRoot, "root is not a dominator tree root"); @@ -1223,17 +1223,17 @@ ValueNumberer::init() return values_.init(); } bool ValueNumberer::run(UpdateAliasAnalysisFlag updateAliasAnalysis) { updateAliasAnalysis_ = updateAliasAnalysis == UpdateAliasAnalysis; - JitSpew(JitSpew_GVN, "Running GVN on graph (with %llu blocks)", + JitSpew(JitSpew_GVN, "Running GVN on graph (with %" PRIu64 " blocks)", uint64_t(graph_.numBlocks())); // Adding fixup blocks only make sense iff we have a second entry point into // the graph which cannot be reached any more from the entry point. if (graph_.osrBlock()) { if (!insertOSRFixups()) return false; } @@ -1283,17 +1283,17 @@ ValueNumberer::run(UpdateAliasAnalysisFl // re-run we discard the construct which triggered the re-run), but it // does help avoid slow compile times on pathological code. ++runs; if (runs == 6) { JitSpew(JitSpew_GVN, "Re-run cutoff of %d reached. Terminating GVN!", runs); break; } - JitSpew(JitSpew_GVN, "Re-running GVN on graph (run %d, now with %llu blocks)", + JitSpew(JitSpew_GVN, "Re-running GVN on graph (run %d, now with %" PRIu64 " blocks)", runs, uint64_t(graph_.numBlocks())); } if (MOZ_UNLIKELY(hasOSRFixups_)) { if (!cleanupOSRFixups()) return false; hasOSRFixups_ = false; }
--- a/js/src/jit/arm/Assembler-arm.h +++ b/js/src/jit/arm/Assembler-arm.h @@ -1358,17 +1358,17 @@ class Assembler : public AssemblerShared SpewNodes spewNodes_; uint32_t spewNext_; Sprinter* printer_; bool spewDisabled(); uint32_t spewResolve(Label* l); uint32_t spewProbe(Label* l); uint32_t spewDefine(Label* l); - void spew(const char* fmt, ...); + void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3); void spew(const char* fmt, va_list args); #endif public: // For the alignment fill use NOP: 0x0320f000 or (Always | InstNOP::NopInst). // For the nopFill use a branch to the next instruction: 0xeaffffff. Assembler() : m_buffer(1, 1, 8, GetPoolMaxOffset(), 8, 0xe320f000, 0xeaffffff, GetNopFill()),
--- a/js/src/jit/arm/disasm/Disasm-arm.cpp +++ b/js/src/jit/arm/disasm/Disasm-arm.cpp @@ -38,16 +38,17 @@ namespace js { namespace jit { namespace disasm { // Helper function for printing to a Vector. static int +MOZ_FORMAT_PRINTF(2, 3) SNPrintF(V8Vector<char> str, const char* format, ...) { va_list args; va_start(args, format); int result = vsnprintf(str.start(), str.length(), format, args); va_end(args); return result; }
--- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -2,16 +2,17 @@ * vim: set ts=8 sts=4 et sw=4 tw=99: * 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 "jit/shared/CodeGenerator-shared-inl.h" #include "mozilla/DebugOnly.h" +#include "mozilla/SizePrintfMacros.h" #include "jit/CompactBuffer.h" #include "jit/IonCaches.h" #include "jit/JitcodeMap.h" #include "jit/JitSpewer.h" #include "jit/MacroAssembler.h" #include "jit/MIR.h" #include "jit/MIRGenerator.h" @@ -228,17 +229,17 @@ CodeGeneratorShared::addNativeToBytecode NativeToBytecode& lastEntry = nativeToBytecodeList_[lastIdx]; MOZ_ASSERT(nativeOffset >= lastEntry.nativeOffset.offset()); // If the new entry is for the same inlineScriptTree and same // bytecodeOffset, but the nativeOffset has changed, do nothing. // The same site just generated some more code. if (lastEntry.tree == tree && lastEntry.pc == pc) { - JitSpew(JitSpew_Profiling, " => In-place update [%u-%u]", + JitSpew(JitSpew_Profiling, " => In-place update [%" PRIuSIZE "-%" PRIu32 "]", lastEntry.nativeOffset.offset(), nativeOffset); return true; } // If the new entry is for the same native offset, then update the // previous entry with the new bytecode site, since the previous // bytecode site did not generate any native code. if (lastEntry.nativeOffset.offset() == nativeOffset) { @@ -275,17 +276,17 @@ CodeGeneratorShared::addNativeToBytecode return true; } void CodeGeneratorShared::dumpNativeToBytecodeEntries() { #ifdef JS_JITSPEW InlineScriptTree* topTree = gen->info().inlineScriptTree(); - JitSpewStart(JitSpew_Profiling, "Native To Bytecode Entries for %s:%d\n", + JitSpewStart(JitSpew_Profiling, "Native To Bytecode Entries for %s:%" PRIuSIZE "\n", topTree->script()->filename(), topTree->script()->lineno()); for (unsigned i = 0; i < nativeToBytecodeList_.length(); i++) dumpNativeToBytecodeEntry(i); #endif } void CodeGeneratorShared::dumpNativeToBytecodeEntry(uint32_t idx) @@ -298,26 +299,26 @@ CodeGeneratorShared::dumpNativeToBytecod unsigned nativeDelta = 0; unsigned pcDelta = 0; if (idx + 1 < nativeToBytecodeList_.length()) { NativeToBytecode* nextRef = &ref + 1; nativeDelta = nextRef->nativeOffset.offset() - nativeOffset; if (nextRef->tree == ref.tree) pcDelta = nextRef->pc - ref.pc; } - JitSpewStart(JitSpew_Profiling, " %08x [+%-6d] => %-6d [%-4d] {%-10s} (%s:%d", + JitSpewStart(JitSpew_Profiling, " %08" PRIxSIZE " [+%-6d] => %-6ld [%-4d] {%-10s} (%s:%" PRIuSIZE, ref.nativeOffset.offset(), nativeDelta, - ref.pc - script->code(), + (long) (ref.pc - script->code()), pcDelta, CodeName[JSOp(*ref.pc)], script->filename(), script->lineno()); for (tree = tree->caller(); tree; tree = tree->caller()) { - JitSpewCont(JitSpew_Profiling, " <= %s:%d", tree->script()->filename(), + JitSpewCont(JitSpew_Profiling, " <= %s:%" PRIuSIZE, tree->script()->filename(), tree->script()->lineno()); } JitSpewCont(JitSpew_Profiling, ")"); JitSpewFin(JitSpew_Profiling); #endif } bool @@ -922,17 +923,17 @@ CodeGeneratorShared::generateCompactTrac trackedOptimizationsAttemptsTableOffset_ = attemptsTableOffset; verifyCompactTrackedOptimizationsMap(code, numRegions, unique, allTypes); JitSpew(JitSpew_OptimizationTracking, "== Compact Native To Optimizations Map [%p-%p] size %u", data, data + trackedOptimizationsMapSize_, trackedOptimizationsMapSize_); JitSpew(JitSpew_OptimizationTracking, - " with type list of length %u, size %u", + " with type list of length %" PRIuSIZE ", size %" PRIuSIZE, allTypes->length(), allTypes->length() * sizeof(IonTrackedTypeWithAddendum)); return true; } #ifdef DEBUG class ReadTempAttemptsVectorOp : public JS::ForEachTrackedOptimizationAttemptOp {
--- a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h +++ b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h @@ -3,16 +3,17 @@ * 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 jit_shared_IonAssemblerBufferWithConstantPools_h #define jit_shared_IonAssemblerBufferWithConstantPools_h #include "mozilla/MathAlgorithms.h" +#include "mozilla/SizePrintfMacros.h" #include <algorithm> #include "jit/JitSpewer.h" #include "jit/shared/IonAssemblerBuffer.h" // This code extends the AssemblerBuffer to support the pooling of values loaded // using program-counter relative addressing modes. This is necessary with the @@ -787,17 +788,17 @@ struct AssemblerBufferWithConstantPools // range check. if (numPoolEntries) pool_.updateLimiter(BufferOffset(sizeExcludingCurrentPool())); if (!hasSpaceForInsts(numInst, numPoolEntries)) { if (numPoolEntries) JitSpew(JitSpew_Pools, "[%d] Inserting pool entry caused a spill", id); else - JitSpew(JitSpew_Pools, "[%d] Inserting instruction(%d) caused a spill", id, + JitSpew(JitSpew_Pools, "[%d] Inserting instruction(%" PRIuSIZE ") caused a spill", id, sizeExcludingCurrentPool()); finishPool(); if (this->oom()) return OOM_FAIL; return insertEntryForwards(numInst, numPoolEntries, inst, data); } if (numPoolEntries) { @@ -858,17 +859,17 @@ struct AssemblerBufferWithConstantPools // Insert the pool value. unsigned index = insertEntryForwards(numInst, numPoolEntries, inst, data); if (this->oom()) return BufferOffset(); // Now to get an instruction to write. PoolEntry retPE; if (numPoolEntries) { - JitSpew(JitSpew_Pools, "[%d] Entry has index %u, offset %u", id, index, + JitSpew(JitSpew_Pools, "[%d] Entry has index %u, offset %" PRIuSIZE, id, index, sizeExcludingCurrentPool()); Asm::InsertIndexIntoTag(inst, index); // Figure out the offset within the pool entries. retPE = PoolEntry(poolEntryCount); poolEntryCount += numPoolEntries; } // Now inst is a valid thing to insert into the instruction stream. if (pe != nullptr) @@ -930,18 +931,18 @@ struct AssemblerBufferWithConstantPools // Include branches that would expire in the next N bytes. // The hysteresis avoids the needless creation of many tiny constant // pools. return this->nextOffset().getOffset() + ShortRangeBranchHysteresis > size_t(branchDeadlines_.earliestDeadline().getOffset()); } void finishPool() { - JitSpew(JitSpew_Pools, "[%d] Attempting to finish pool %d with %d entries.", id, - poolInfo_.length(), pool_.numEntries()); + JitSpew(JitSpew_Pools, "[%d] Attempting to finish pool %" PRIuSIZE " with %u entries.", + id, poolInfo_.length(), pool_.numEntries()); if (pool_.numEntries() == 0 && !hasExpirableShortRangeBranches()) { // If there is no data in the pool being dumped, don't dump anything. JitSpew(JitSpew_Pools, "[%d] Aborting because the pool is empty", id); return; } // Should not be placing a pool in a no-pool region, check. @@ -999,17 +1000,17 @@ struct AssemblerBufferWithConstantPools // substitutions. Inst* inst = this->getInst(*iter); size_t codeOffset = poolOffset - iter->getOffset(); // That is, PatchConstantPoolLoad wants to be handed the address of // the pool entry that is being loaded. We need to do a non-trivial // amount of math here, since the pool that we've made does not // actually reside there in memory. - JitSpew(JitSpew_Pools, "[%d] Fixing entry %d offset to %u", id, idx, codeOffset); + JitSpew(JitSpew_Pools, "[%d] Fixing entry %d offset to %" PRIuSIZE, id, idx, codeOffset); Asm::PatchConstantPoolLoad(inst, (uint8_t*)inst + codeOffset); } // Record the pool info. unsigned firstEntry = poolEntryCount - pool_.numEntries(); if (!poolInfo_.append(PoolInfo(firstEntry, data))) { this->fail_oom(); return; @@ -1032,17 +1033,17 @@ struct AssemblerBufferWithConstantPools MOZ_ASSERT(!canNotPlacePool_); insertNopFill(); // Check if the pool will spill by adding maxInst instructions, and if // so then finish the pool before entering the no-pool region. It is // assumed that no pool entries are allocated in a no-pool region and // this is asserted when allocating entries. if (!hasSpaceForInsts(maxInst, 0)) { - JitSpew(JitSpew_Pools, "[%d] No-Pool instruction(%d) caused a spill.", id, + JitSpew(JitSpew_Pools, "[%d] No-Pool instruction(%" PRIuSIZE ") caused a spill.", id, sizeExcludingCurrentPool()); finishPool(); } #ifdef DEBUG // Record the buffer position to allow validating maxInst when leaving // the region. canNotPlacePoolStartOffset_ = this->nextOffset().getOffset(); @@ -1072,18 +1073,18 @@ struct AssemblerBufferWithConstantPools if (requiredFill == 0) return; requiredFill = alignment - requiredFill; // Add an InstSize because it is probably not useful for a pool to be // dumped at the aligned code position. if (!hasSpaceForInsts(requiredFill / InstSize + 1, 0)) { // Alignment would cause a pool dump, so dump the pool now. - JitSpew(JitSpew_Pools, "[%d] Alignment of %d at %d caused a spill.", id, alignment, - sizeExcludingCurrentPool()); + JitSpew(JitSpew_Pools, "[%d] Alignment of %d at %" PRIuSIZE " caused a spill.", + id, alignment, sizeExcludingCurrentPool()); finishPool(); } inhibitNops_ = true; while ((sizeExcludingCurrentPool() & (alignment - 1)) && !this->oom()) putInt(alignFillInst_); inhibitNops_ = false; }
--- a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h +++ b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h @@ -181,20 +181,17 @@ namespace jit { GenericAssembler() : printer(NULL) {} void setPrinter(Sprinter* sp) { printer = sp; } - void spew(const char* fmt, ...) -#ifdef __GNUC__ - __attribute__ ((format (printf, 2, 3))) -#endif + void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3) { if (MOZ_UNLIKELY(printer || JitSpewEnabled(JitSpew_Codegen))) { va_list va; va_start(va, fmt); spew(fmt, va); va_end(va); } }
--- a/js/src/jsapi-tests/moz.build +++ b/js/src/jsapi-tests/moz.build @@ -68,16 +68,17 @@ UNIFIED_SOURCES += [ 'testNewObject.cpp', 'testNewTargetInvokeConstructor.cpp', 'testNullRoot.cpp', 'testObjectEmulatingUndefined.cpp', 'testOOM.cpp', 'testParseJSON.cpp', 'testPersistentRooted.cpp', 'testPreserveJitCode.cpp', + 'testPrintf.cpp', 'testPrivateGCThingValue.cpp', 'testProfileStrings.cpp', 'testPropCache.cpp', 'testRegExp.cpp', 'testResolveRecursion.cpp', 'tests.cpp', 'testSameValue.cpp', 'testSavedStacks.cpp', @@ -141,16 +142,16 @@ if CONFIG['ENABLE_INTL_API'] and CONFIG[ USE_LIBS += [ 'static:js', ] OS_LIBS += CONFIG['MOZ_ZLIB_LIBS'] if CONFIG['GNU_CXX']: - CXXFLAGS += ['-Wno-shadow'] + CXXFLAGS += ['-Wno-shadow', '-Werror=format'] # This is intended as a temporary workaround to enable VS2015. if CONFIG['_MSC_VER']: CXXFLAGS += ['-wd4312'] DEFINES['topsrcdir'] = '%s/js/src' % TOPSRCDIR OBJDIR_PP_FILES.js.src['jsapi-tests'] += ['jsapi-tests-gdb.py.in']
new file mode 100644 --- /dev/null +++ b/js/src/jsapi-tests/testPrintf.cpp @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + */ +/* 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 "mozilla/IntegerPrintfMacros.h" +#include "mozilla/SizePrintfMacros.h" + +#include <stdarg.h> + +#include "jsprf.h" + +#include "jsapi-tests/tests.h" + +static bool +MOZ_FORMAT_PRINTF(2, 3) +print_one (const char *expect, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + char *output = JS_vsmprintf (fmt, ap); + va_end(ap); + + bool result = output && !strcmp(output, expect); + JS_smprintf_free(output); + + return result; +} + +static const char * +zero() +{ + return nullptr; +} + +BEGIN_TEST(testPrintf) +{ + CHECK(print_one("23", "%d", 23)); + CHECK(print_one("-1", "%d", -1)); + CHECK(print_one("23", "%u", 23u)); + CHECK(print_one("0x17", "0x%x", 23u)); + CHECK(print_one("0xFF", "0x%X", 255u)); + CHECK(print_one("027", "0%o", 23u)); + CHECK(print_one("-1", "%hd", (short) -1)); + // This could be expanded if need be, it's just convenient to do + // it this way. + if (sizeof(short) == 2) { + CHECK(print_one("8000", "%hx", (unsigned short) 0x8000)); + } + CHECK(print_one("0xf0f0", "0x%lx", 0xf0f0ul)); + CHECK(print_one("0xF0F0", "0x%llX", 0xf0f0ull)); + CHECK(print_one("27270", "%zu", (size_t) 27270)); + CHECK(print_one("27270", "%" PRIuSIZE, (size_t) 27270)); + CHECK(print_one("hello", "he%so", "ll")); + CHECK(print_one("(null)", "%s", zero())); + CHECK(print_one("0", "%p", (char *) 0)); + CHECK(print_one("h", "%c", 'h')); + CHECK(print_one("1.500000", "%f", 1.5f)); + CHECK(print_one("1.5", "%g", 1.5)); + + CHECK(print_one("2727", "%" PRIu32, (uint32_t) 2727)); + CHECK(print_one("aa7", "%" PRIx32, (uint32_t) 2727)); + CHECK(print_one("2727", "%" PRIu64, (uint64_t) 2727)); + CHECK(print_one("aa7", "%" PRIx64, (uint64_t) 2727)); + + return true; +} +END_TEST(testPrintf)
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -5194,23 +5194,26 @@ namespace JS { const uint16_t MaxNumErrorArguments = 10; }; /** * Report an exception represented by the sprintf-like conversion of format * and its arguments. */ extern JS_PUBLIC_API(void) -JS_ReportErrorASCII(JSContext* cx, const char* format, ...); +JS_ReportErrorASCII(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); extern JS_PUBLIC_API(void) -JS_ReportErrorLatin1(JSContext* cx, const char* format, ...); +JS_ReportErrorLatin1(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); extern JS_PUBLIC_API(void) -JS_ReportErrorUTF8(JSContext* cx, const char* format, ...); +JS_ReportErrorUTF8(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); /* * Use an errorNumber to retrieve the format string, args are char* */ extern JS_PUBLIC_API(void) JS_ReportErrorNumberASCII(JSContext* cx, JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber, ...); @@ -5252,23 +5255,26 @@ JS_ReportErrorNumberUCArray(JSContext* c /** * As above, but report a warning instead (JSREPORT_IS_WARNING(report.flags)). * Return true if there was no error trying to issue the warning, and if the * warning was not converted into an error due to the JSOPTION_WERROR option * being set, false otherwise. */ extern JS_PUBLIC_API(bool) -JS_ReportWarningASCII(JSContext* cx, const char* format, ...); - -extern JS_PUBLIC_API(bool) -JS_ReportWarningLatin1(JSContext* cx, const char* format, ...); - -extern JS_PUBLIC_API(bool) -JS_ReportWarningUTF8(JSContext* cx, const char* format, ...); +JS_ReportWarningASCII(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API(bool) +JS_ReportWarningLatin1(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API(bool) +JS_ReportWarningUTF8(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); extern JS_PUBLIC_API(bool) JS_ReportErrorFlagsAndNumberASCII(JSContext* cx, unsigned flags, JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber, ...); extern JS_PUBLIC_API(bool) JS_ReportErrorFlagsAndNumberLatin1(JSContext* cx, unsigned flags,
--- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -758,21 +758,26 @@ FormatValue(JSContext* cx, const Value& const char* found = strstr(buf, "function "); if (found && (found - buf <= 2)) return "[function]"; return buf; } // Wrapper for JS_sprintf_append() that reports allocation failure to the // context. -template <typename... Args> static char* -sprintf_append(JSContext* cx, char* buf, Args&&... args) +MOZ_FORMAT_PRINTF(3, 4) +sprintf_append(JSContext* cx, char* buf, const char* fmt, ...) { - char* result = JS_sprintf_append(buf, mozilla::Forward<Args>(args)...); + va_list ap; + + va_start(ap, fmt); + char* result = JS_vsprintf_append(buf, fmt, ap); + va_end(ap); + if (!result) { ReportOutOfMemory(cx); return nullptr; } return result; }
--- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -3625,21 +3625,21 @@ js::DumpBacktrace(JSContext* cx, FILE* f } char frameType = i.isInterp() ? 'i' : i.isBaseline() ? 'b' : i.isIon() ? 'I' : i.isWasm() ? 'W' : '?'; - sprinter.printf("#%d %14p %c %s:%d", + sprinter.printf("#%" PRIuSIZE " %14p %c %s:%d", depth, i.rawFramePtr(), frameType, filename, line); if (i.hasScript()) { - sprinter.printf(" (%p @ %d)\n", + sprinter.printf(" (%p @ %" PRIuSIZE ")\n", i.script(), i.script()->pcToOffset(i.pc())); } else { sprinter.printf(" (%p)\n", i.pc()); } } fprintf(fp, "%s", sprinter.string()); #ifdef XP_WIN32 if (IsDebuggerPresent())
--- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -146,37 +146,37 @@ js::StackDefs(JSScript* script, jsbyteco return cs.ndefs; } const char * PCCounts::numExecName = "interp"; static MOZ_MUST_USE bool DumpIonScriptCounts(Sprinter* sp, HandleScript script, jit::IonScriptCounts* ionCounts) { - if (!sp->jsprintf("IonScript [%lu blocks]:\n", ionCounts->numBlocks())) + if (!sp->jsprintf("IonScript [%" PRIuSIZE " blocks]:\n", ionCounts->numBlocks())) return false; for (size_t i = 0; i < ionCounts->numBlocks(); i++) { const jit::IonBlockCounts& block = ionCounts->block(i); unsigned lineNumber = 0, columnNumber = 0; lineNumber = PCToLineNumber(script, script->offsetToPC(block.offset()), &columnNumber); - if (!sp->jsprintf("BB #%lu [%05u,%u,%u]", + if (!sp->jsprintf("BB #%" PRIu32 " [%05u,%u,%u]", block.id(), block.offset(), lineNumber, columnNumber)) { return false; } if (block.description()) { if (!sp->jsprintf(" [inlined %s]", block.description())) return false; } for (size_t j = 0; j < block.numSuccessors(); j++) { - if (!sp->jsprintf(" -> #%lu", block.successor(j))) + if (!sp->jsprintf(" -> #%" PRIu32, block.successor(j))) return false; } - if (!sp->jsprintf(" :: %llu hits\n", block.hitCount())) + if (!sp->jsprintf(" :: %" PRIu64 " hits\n", block.hitCount())) return false; if (!sp->jsprintf("%s\n", block.code())) return false; } return true; }
--- a/js/src/jsprf.cpp +++ b/js/src/jsprf.cpp @@ -58,67 +58,45 @@ struct NumArgState { int type; // type of the current ap va_list ap; // point to the corresponding position on ap }; typedef mozilla::Vector<NumArgState, 20, js::SystemAllocPolicy> NumArgStateVector; -#define TYPE_INT16 0 -#define TYPE_UINT16 1 +#define TYPE_SHORT 0 +#define TYPE_USHORT 1 #define TYPE_INTN 2 #define TYPE_UINTN 3 -#define TYPE_INT32 4 -#define TYPE_UINT32 5 -#define TYPE_INT64 6 -#define TYPE_UINT64 7 +#define TYPE_LONG 4 +#define TYPE_ULONG 5 +#define TYPE_LONGLONG 6 +#define TYPE_ULONGLONG 7 #define TYPE_STRING 8 #define TYPE_DOUBLE 9 #define TYPE_INTSTR 10 -#define TYPE_WSTRING 11 +#define TYPE_POINTER 11 #define TYPE_UNKNOWN 20 #define FLAG_LEFT 0x1 #define FLAG_SIGNED 0x2 #define FLAG_SPACED 0x4 #define FLAG_ZEROS 0x8 #define FLAG_NEG 0x10 inline bool generic_write(SprintfState* ss, const char* src, size_t srclen) { return (*ss->stuff)(ss, src, srclen); } -inline bool -generic_write(SprintfState* ss, const char16_t* src, size_t srclen) -{ - const size_t CHUNK_SIZE = 64; - char chunk[CHUNK_SIZE]; - - size_t j = 0; - size_t i = 0; - while (i < srclen) { - // FIXME: truncates characters to 8 bits - chunk[j++] = char(src[i++]); - - if (j == CHUNK_SIZE || i == srclen) { - if (!(*ss->stuff)(ss, chunk, j)) - return false; - j = 0; - } - } - return true; -} - // Fill into the buffer using the data in src -template <typename Char> static bool -fill2(SprintfState* ss, const Char* src, int srclen, int width, int flags) +fill2(SprintfState* ss, const char* src, int srclen, int width, int flags) { char space = ' '; width -= srclen; if (width > 0 && (flags & FLAG_LEFT) == 0) { // Right adjusting if (flags & FLAG_ZEROS) space = '0'; while (--width >= 0) { @@ -313,29 +291,26 @@ static bool cvt_f(SprintfState* ss, doub } #endif SprintfLiteral(fout, fin, d); return (*ss->stuff)(ss, fout, strlen(fout)); } static inline const char* generic_null_str(const char*) { return "(null)"; } -static inline const char16_t* generic_null_str(const char16_t*) { return u"(null)"; } static inline size_t generic_strlen(const char* s) { return strlen(s); } -static inline size_t generic_strlen(const char16_t* s) { return js_strlen(s); } /* * Convert a string into its printable form. "width" is the output * width. "prec" is the maximum number of characters of "s" to output, * where -1 means until NUL. */ -template <typename Char> static bool -cvt_s(SprintfState* ss, const Char* s, int width, int prec, int flags) +cvt_s(SprintfState* ss, const char* s, int width, int prec, int flags) { if (prec == 0) return true; if (!s) s = generic_null_str(s); // Limit string length by precision value int slen = int(generic_strlen(s)); @@ -447,33 +422,34 @@ BuildArgArray(const char* fmt, va_list a while ((c >= '0') && (c <= '9')) { c = *p++; } } // size nas[cn].type = TYPE_INTN; if (c == 'h') { - nas[cn].type = TYPE_INT16; + nas[cn].type = TYPE_SHORT; c = *p++; } else if (c == 'L') { - // XXX not quite sure here - nas[cn].type = TYPE_INT64; + nas[cn].type = TYPE_LONGLONG; c = *p++; } else if (c == 'l') { - nas[cn].type = TYPE_INT32; + nas[cn].type = TYPE_LONG; c = *p++; if (c == 'l') { - nas[cn].type = TYPE_INT64; + nas[cn].type = TYPE_LONGLONG; c = *p++; } } else if (c == 'z' || c == 'I') { - static_assert(sizeof(size_t) == sizeof(int32_t) || sizeof(size_t) == sizeof(int64_t), + static_assert(sizeof(size_t) == sizeof(int) || sizeof(size_t) == sizeof(long) || + sizeof(size_t) == sizeof(long long), "size_t is not one of the expected sizes"); - nas[cn].type = sizeof(size_t) == sizeof(int64_t) ? TYPE_INT64 : TYPE_INT32; + nas[cn].type = sizeof(size_t) == sizeof(int) ? TYPE_INTN : + sizeof(size_t) == sizeof(long) ? TYPE_LONG : TYPE_LONGLONG; c = *p++; } // format switch (c) { case 'd': case 'c': case 'i': @@ -485,39 +461,30 @@ BuildArgArray(const char* fmt, va_list a case 'e': case 'f': case 'g': nas[cn].type = TYPE_DOUBLE; break; case 'p': - // XXX should use cpp - if (sizeof(void*) == sizeof(int32_t)) { - nas[cn].type = TYPE_UINT32; - } else if (sizeof(void*) == sizeof(int64_t)) { - nas[cn].type = TYPE_UINT64; - } else if (sizeof(void*) == sizeof(int)) { - nas[cn].type = TYPE_UINTN; - } else { - nas[cn].type = TYPE_UNKNOWN; - } + nas[cn].type = TYPE_POINTER; break; case 'C': case 'S': case 'E': case 'G': // XXX not supported I suppose MOZ_ASSERT(0); nas[cn].type = TYPE_UNKNOWN; break; case 's': - nas[cn].type = (nas[cn].type == TYPE_UINT16) ? TYPE_WSTRING : TYPE_STRING; + nas[cn].type = TYPE_STRING; break; case 'n': nas[cn].type = TYPE_INTSTR; break; default: MOZ_ASSERT(0); @@ -539,28 +506,28 @@ BuildArgArray(const char* fmt, va_list a if (nas[cn].type == TYPE_UNKNOWN) { cn++; continue; } VARARGS_ASSIGN(nas[cn].ap, ap); switch (nas[cn].type) { - case TYPE_INT16: - case TYPE_UINT16: + case TYPE_SHORT: + case TYPE_USHORT: case TYPE_INTN: case TYPE_UINTN: (void) va_arg(ap, int); break; - case TYPE_INT32: (void) va_arg(ap, int32_t); break; - case TYPE_UINT32: (void) va_arg(ap, uint32_t); break; - case TYPE_INT64: (void) va_arg(ap, int64_t); break; - case TYPE_UINT64: (void) va_arg(ap, uint64_t); break; + case TYPE_LONG: (void) va_arg(ap, long); break; + case TYPE_ULONG: (void) va_arg(ap, unsigned long); break; + case TYPE_LONGLONG: (void) va_arg(ap, long long); break; + case TYPE_ULONGLONG: (void) va_arg(ap, unsigned long long); break; case TYPE_STRING: (void) va_arg(ap, char*); break; - case TYPE_WSTRING: (void) va_arg(ap, char16_t*); break; case TYPE_INTSTR: (void) va_arg(ap, int*); break; case TYPE_DOUBLE: (void) va_arg(ap, double); break; + case TYPE_POINTER: (void) va_arg(ap, void*); break; default: MOZ_CRASH(); } cn++; } return true; @@ -571,24 +538,23 @@ BuildArgArray(const char* fmt, va_list a */ static bool dosprintf(SprintfState* ss, const char* fmt, va_list ap) { char c; int flags, width, prec, radix, type; union { char ch; - char16_t wch; int i; long l; - int64_t ll; + long long ll; double d; const char* s; - const char16_t* ws; int* ip; + void* p; } u; const char* fmt0; static const char hex[] = "0123456789abcdef"; static const char HEX[] = "0123456789ABCDEF"; const char* hexp; int i; char pattern[20]; const char* dolPt = nullptr; // in "%4$.2f", dolPt will point to '.' @@ -680,33 +646,34 @@ dosprintf(SprintfState* ss, const char* c = *fmt++; } } } // size type = TYPE_INTN; if (c == 'h') { - type = TYPE_INT16; + type = TYPE_SHORT; c = *fmt++; } else if (c == 'L') { - // XXX not quite sure here - type = TYPE_INT64; + type = TYPE_LONGLONG; c = *fmt++; } else if (c == 'l') { - type = TYPE_INT32; + type = TYPE_LONG; c = *fmt++; if (c == 'l') { - type = TYPE_INT64; + type = TYPE_LONGLONG; c = *fmt++; } } else if (c == 'z' || c == 'I') { - static_assert(sizeof(size_t) == sizeof(int32_t) || sizeof(size_t) == sizeof(int64_t), + static_assert(sizeof(size_t) == sizeof(int) || sizeof(size_t) == sizeof(long) || + sizeof(size_t) == sizeof(long long), "size_t is not one of the expected sizes"); - type = sizeof(size_t) == sizeof(int64_t) ? TYPE_INT64 : TYPE_INT32; + type = sizeof(size_t) == sizeof(int) ? TYPE_INTN : + sizeof(size_t) == sizeof(long) ? TYPE_LONG : TYPE_LONGLONG; c = *fmt++; } // format hexp = hex; switch (c) { case 'd': case 'i': // decimal/integer radix = 10; @@ -730,61 +697,64 @@ dosprintf(SprintfState* ss, const char* case 'X': // unsigned HEX radix = 16; hexp = HEX; type |= 1; goto fetch_and_convert; fetch_and_convert: switch (type) { - case TYPE_INT16: + case TYPE_SHORT: u.l = va_arg(ap, int); if (u.l < 0) { u.l = -u.l; flags |= FLAG_NEG; } goto do_long; - case TYPE_UINT16: - u.l = va_arg(ap, int) & 0xffff; + case TYPE_USHORT: + u.l = (unsigned short) va_arg(ap, unsigned int); goto do_long; case TYPE_INTN: u.l = va_arg(ap, int); if (u.l < 0) { u.l = -u.l; flags |= FLAG_NEG; } goto do_long; case TYPE_UINTN: u.l = (long)va_arg(ap, unsigned int); goto do_long; - case TYPE_INT32: - u.l = va_arg(ap, int32_t); + case TYPE_LONG: + u.l = va_arg(ap, long); if (u.l < 0) { u.l = -u.l; flags |= FLAG_NEG; } goto do_long; - case TYPE_UINT32: - u.l = (long)va_arg(ap, uint32_t); + case TYPE_ULONG: + u.l = (long)va_arg(ap, unsigned long); do_long: if (!cvt_l(ss, u.l, width, prec, radix, type, flags, hexp)) return false; break; - case TYPE_INT64: - u.ll = va_arg(ap, int64_t); + case TYPE_LONGLONG: + u.ll = va_arg(ap, long long); if (u.ll < 0) { u.ll = -u.ll; flags |= FLAG_NEG; } goto do_longlong; - case TYPE_UINT64: - u.ll = va_arg(ap, uint64_t); + case TYPE_POINTER: + u.ll = (uintptr_t)va_arg(ap, void*); + goto do_longlong; + case TYPE_ULONGLONG: + u.ll = va_arg(ap, unsigned long long); do_longlong: if (!cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp)) return false; break; } break; @@ -811,65 +781,50 @@ dosprintf(SprintfState* ss, const char* case 'c': if ((flags & FLAG_LEFT) == 0) { while (width-- > 1) { if (!(*ss->stuff)(ss, " ", 1)) return false; } } switch (type) { - case TYPE_INT16: + case TYPE_SHORT: case TYPE_INTN: u.ch = va_arg(ap, int); if (!(*ss->stuff)(ss, &u.ch, 1)) return false; break; } if (flags & FLAG_LEFT) { while (width-- > 1) { if (!(*ss->stuff)(ss, " ", 1)) return false; } } break; case 'p': - if (sizeof(void*) == sizeof(int32_t)) { - type = TYPE_UINT32; - } else if (sizeof(void*) == sizeof(int64_t)) { - type = TYPE_UINT64; - } else if (sizeof(void*) == sizeof(int)) { - type = TYPE_UINTN; - } else { - MOZ_ASSERT(0); - break; - } + type = TYPE_POINTER; radix = 16; goto fetch_and_convert; #if 0 case 'C': case 'S': case 'E': case 'G': // XXX not supported I suppose MOZ_ASSERT(0); break; #endif case 's': - if(type == TYPE_INT16) { - u.ws = va_arg(ap, const char16_t*); - if (!cvt_s(ss, u.ws, width, prec, flags)) - return false; - } else { - u.s = va_arg(ap, const char*); - if (!cvt_s(ss, u.s, width, prec, flags)) - return false; - } + u.s = va_arg(ap, const char*); + if (!cvt_s(ss, u.s, width, prec, flags)) + return false; break; case 'n': u.ip = va_arg(ap, int*); if (u.ip) { *u.ip = ss->cur - ss->base; } break; @@ -999,27 +954,27 @@ JS_vsprintf_append(char* last, const cha } if (!dosprintf(&ss, fmt, ap)) { js_free(ss.base); return 0; } return ss.base; } -#undef TYPE_INT16 -#undef TYPE_UINT16 +#undef TYPE_SHORT +#undef TYPE_USHORT #undef TYPE_INTN #undef TYPE_UINTN -#undef TYPE_INT32 -#undef TYPE_UINT32 -#undef TYPE_INT64 -#undef TYPE_UINT64 +#undef TYPE_LONG +#undef TYPE_ULONG +#undef TYPE_LONGLONG +#undef TYPE_ULONGLONG #undef TYPE_STRING #undef TYPE_DOUBLE #undef TYPE_INTSTR -#undef TYPE_WSTRING +#undef TYPE_POINTER #undef TYPE_UNKNOWN #undef FLAG_LEFT #undef FLAG_SIGNED #undef FLAG_SPACED #undef FLAG_ZEROS #undef FLAG_NEG
--- a/js/src/jsprf.h +++ b/js/src/jsprf.h @@ -9,21 +9,23 @@ /* ** API for PR printf like routines. Supports the following formats ** %d - decimal ** %u - unsigned decimal ** %x - unsigned hex ** %X - unsigned uppercase hex ** %o - unsigned octal -** %hd, %hu, %hx, %hX, %ho - 16-bit versions of above -** %ld, %lu, %lx, %lX, %lo - 32-bit versions of above -** %lld, %llu, %llx, %llX, %llo - 64 bit versions of above -** %s - ascii string -** %hs - ucs2 string +** %hd, %hu, %hx, %hX, %ho - "short" versions of above +** %ld, %lu, %lx, %lX, %lo - "long" versions of above +** %lld, %llu, %llx, %llX, %llo - "long long" versions of above +** %zd, %zo, %zu, %zx, %zX - size_t versions of above +** %Id, %Io, %Iu, %Ix, %IX - size_t versions of above (for Windows compat) +** You should use PRI*SIZE macros instead +** %s - string ** %c - character ** %p - pointer (deals with machine dependent pointer size) ** %f - float ** %g - float */ #include "mozilla/IntegerPrintfMacros.h" #include "mozilla/SizePrintfMacros.h" @@ -32,31 +34,33 @@ #include "jstypes.h" /* ** sprintf into a malloc'd buffer. Return a pointer to the malloc'd ** buffer on success, nullptr on failure. Call "JS_smprintf_free" to release ** the memory returned. */ -extern JS_PUBLIC_API(char*) JS_smprintf(const char* fmt, ...); +extern JS_PUBLIC_API(char*) JS_smprintf(const char* fmt, ...) + MOZ_FORMAT_PRINTF(1, 2); /* ** Free the memory allocated, for the caller, by JS_smprintf */ extern JS_PUBLIC_API(void) JS_smprintf_free(char* mem); /* ** "append" sprintf into a malloc'd buffer. "last" is the last value of ** the malloc'd buffer. sprintf will append data to the end of last, ** growing it as necessary using realloc. If last is nullptr, JS_sprintf_append ** will allocate the initial string. The return value is the new value of ** last for subsequent calls, or nullptr if there is a malloc failure. */ -extern JS_PUBLIC_API(char*) JS_sprintf_append(char* last, const char* fmt, ...); +extern JS_PUBLIC_API(char*) JS_sprintf_append(char* last, const char* fmt, ...) + MOZ_FORMAT_PRINTF(2, 3); /* ** va_list forms of the above. */ extern JS_PUBLIC_API(char*) JS_vsmprintf(const char* fmt, va_list ap); extern JS_PUBLIC_API(char*) JS_vsprintf_append(char* last, const char* fmt, va_list ap); #endif /* jsprf_h */
--- a/js/src/moz.build +++ b/js/src/moz.build @@ -779,13 +779,13 @@ if CONFIG['SPIDERMONKEY_PROMISE']: if CONFIG['JS_HAS_CTYPES']: if CONFIG['MOZ_SYSTEM_FFI']: CXXFLAGS += CONFIG['MOZ_FFI_CFLAGS'] else: # Windows needs this to be linked with a static library. DEFINES['FFI_BUILDING'] = True if CONFIG['GNU_CXX']: - CXXFLAGS += ['-Wno-shadow'] + CXXFLAGS += ['-Wno-shadow', '-Werror=format'] # Suppress warnings in third-party code. if CONFIG['CLANG_CXX']: SOURCES['jsdtoa.cpp'].flags += ['-Wno-implicit-fallthrough']
--- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -5242,17 +5242,17 @@ ReflectTrackedOptimizations(JSContext* c // Use endOffset, as startOffset may be associated with a // previous, adjacent region ending exactly at startOffset. That // is, suppose we have two regions [0, startOffset], [startOffset, // endOffset]. Since we are not querying a return address, we want // the second region and not the first. uint8_t* addr = ion->method()->raw() + endOffset; entry.youngestFrameLocationAtAddr(rt, addr, &script, &pc); - if (!sp.jsprintf("{\"location\":\"%s:%u\",\"offset\":%u,\"index\":%u}%s", + if (!sp.jsprintf("{\"location\":\"%s:%" PRIuSIZE "\",\"offset\":%" PRIuSIZE ",\"index\":%u}%s", script->filename(), script->lineno(), script->pcToOffset(pc), index, iter.more() ? "," : "")) { return false; } } }
--- a/js/src/shell/jsoptparse.cpp +++ b/js/src/shell/jsoptparse.cpp @@ -259,17 +259,17 @@ OptionParser::printVersion() OptionParser::Result OptionParser::extractValue(size_t argc, char** argv, size_t* i, char** value) { MOZ_ASSERT(*i < argc); char* eq = strchr(argv[*i], '='); if (eq) { *value = eq + 1; if (*value[0] == '\0') - return error("A value is required for option %.*s", eq - argv[*i], argv[*i]); + return error("A value is required for option %.*s", (int) (eq - argv[*i]), argv[*i]); return Okay; } if (argc == *i + 1) return error("Expected a value for option %s", argv[*i]); *i += 1; *value = argv[*i];
--- a/js/src/shell/jsoptparse.h +++ b/js/src/shell/jsoptparse.h @@ -223,17 +223,17 @@ class OptionParser Option* findOption(char shortflag); const Option* findOption(char shortflag) const; Option* findOption(const char* longflag); const Option* findOption(const char* longflag) const; int findArgumentIndex(const char* name) const; Option* findArgument(const char* name); const Option* findArgument(const char* name) const; - Result error(const char* fmt, ...); + Result error(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3); Result extractValue(size_t argc, char** argv, size_t* i, char** value); Result handleArg(size_t argc, char** argv, size_t* i, bool* optsAllowed); Result handleOption(Option* opt, size_t argc, char** argv, size_t* i, bool* optsAllowed); public: explicit OptionParser(const char* usage) : helpOption('h', "help", "Display help information"), versionOption('v', "version", "Display version information and exit"),
--- a/js/src/shell/moz.build +++ b/js/src/shell/moz.build @@ -46,17 +46,17 @@ GENERATED_FILES += ['shellmoduleloader.o shellmoduleloader = GENERATED_FILES['shellmoduleloader.out.h'] shellmoduleloader.script = '../builtin/embedjs.py:generate_shellmoduleloader' shellmoduleloader.inputs = [ '../js.msg', 'ModuleLoader.js', ] if CONFIG['GNU_CXX']: - CXXFLAGS += ['-Wno-shadow'] + CXXFLAGS += ['-Wno-shadow', '-Werror=format'] # This is intended as a temporary workaround to enable VS2015. if CONFIG['_MSC_VER']: CXXFLAGS += ['-wd4312'] # Place a GDB Python auto-load file next to the shell executable, both in # the build directory and in the dist/bin directory. DEFINES['topsrcdir'] = '%s/js/src' % TOPSRCDIR
--- a/js/src/vm/CodeCoverage.cpp +++ b/js/src/vm/CodeCoverage.cpp @@ -86,26 +86,26 @@ LCovSource::exportInto(GenericPrinter& o // Only write if everything got recorded. if (!hasFilename_ || !hasTopLevelScript_) return; outSF_.exportInto(out); outFN_.exportInto(out); outFNDA_.exportInto(out); - out.printf("FNF:%d\n", numFunctionsFound_); - out.printf("FNH:%d\n", numFunctionsHit_); + out.printf("FNF:%" PRIuSIZE "\n", numFunctionsFound_); + out.printf("FNH:%" PRIuSIZE "\n", numFunctionsHit_); outBRDA_.exportInto(out); - out.printf("BRF:%d\n", numBranchesFound_); - out.printf("BRH:%d\n", numBranchesHit_); + out.printf("BRF:%" PRIuSIZE "\n", numBranchesFound_); + out.printf("BRH:%" PRIuSIZE "\n", numBranchesHit_); outDA_.exportInto(out); - out.printf("LF:%d\n", numLinesInstrumented_); - out.printf("LH:%d\n", numLinesHit_); + out.printf("LF:%" PRIuSIZE "\n", numLinesInstrumented_); + out.printf("LH:%" PRIuSIZE "\n", numLinesHit_); out.put("end_of_record\n"); } bool LCovSource::writeSourceFilename(ScriptSourceObject* sso) { outSF_.printf("SF:%s\n", sso->source()->filename()); @@ -125,17 +125,17 @@ LCovSource::writeScriptName(LSprinter& o out.printf("top-level"); return true; } bool LCovSource::writeScript(JSScript* script) { numFunctionsFound_++; - outFN_.printf("FN:%d,", script->lineno()); + outFN_.printf("FN:%" PRIuSIZE ",", script->lineno()); if (!writeScriptName(outFN_, script)) return false; outFN_.put("\n", 1); uint64_t hits = 0; ScriptCounts* sc = nullptr; if (script->hasScriptCounts()) { sc = &script->getScriptCounts(); @@ -186,17 +186,17 @@ LCovSource::writeScript(JSScript* script else if (type == SRC_TABLESWITCH) tableswitchExitOffset = GetSrcNoteOffset(sn, 0); sn = SN_NEXT(sn); snpc += SN_DELTA(sn); } if (oldLine != lineno && fallsthrough) { - outDA_.printf("DA:%d,%" PRIu64 "\n", lineno, hits); + outDA_.printf("DA:%" PRIuSIZE ",%" PRIu64 "\n", lineno, hits); // Count the number of lines instrumented & hit. numLinesInstrumented_++; if (hits) numLinesHit_++; } } @@ -215,23 +215,23 @@ LCovSource::writeScript(JSScript* script uint64_t fallthroughHits = 0; if (sc) { const PCCounts* counts = sc->maybeGetPCCounts(script->pcToOffset(fallthroughTarget)); if (counts) fallthroughHits = counts->numExec(); } uint64_t taken = hits - fallthroughHits; - outBRDA_.printf("BRDA:%d,%d,0,", lineno, branchId); + outBRDA_.printf("BRDA:%" PRIuSIZE ",%" PRIuSIZE ",0,", lineno, branchId); if (taken) outBRDA_.printf("%" PRIu64 "\n", taken); else outBRDA_.put("-\n", 2); - outBRDA_.printf("BRDA:%d,%d,1,", lineno, branchId); + outBRDA_.printf("BRDA:%" PRIuSIZE ",%" PRIuSIZE ",1,", lineno, branchId); if (fallthroughHits) outBRDA_.printf("%" PRIu64 "\n", fallthroughHits); else outBRDA_.put("-\n", 2); // Count the number of branches, and the number of branches hit. numBranchesFound_ += 2; if (hits) @@ -303,17 +303,18 @@ LCovSource::writeScript(JSScript* script if (BytecodeFallsThrough(JSOp(*endpc))) fallsThroughHits = script->getHitCount(endpc); } caseHits -= fallsThroughHits; } - outBRDA_.printf("BRDA:%d,%d,%d,", lineno, branchId, caseId); + outBRDA_.printf("BRDA:%" PRIuSIZE ",%" PRIuSIZE ",%" PRIuSIZE ",", + lineno, branchId, caseId); if (caseHits) outBRDA_.printf("%" PRIu64 "\n", caseHits); else outBRDA_.put("-\n", 2); numBranchesFound_++; numBranchesHit_ += !!caseHits; defaultHits -= caseHits; @@ -354,17 +355,18 @@ LCovSource::writeScript(JSScript* script const PCCounts* counts = sc->maybeGetPCCounts(script->pcToOffset(defaultpc)); if (counts) defaultHits = counts->numExec(); } defaultHits -= fallsThroughHits; } if (defaultHasOwnClause) { - outBRDA_.printf("BRDA:%d,%d,%d,", lineno, branchId, caseId); + outBRDA_.printf("BRDA:%" PRIuSIZE ",%" PRIuSIZE ",%" PRIuSIZE ",", + lineno, branchId, caseId); if (defaultHits) outBRDA_.printf("%" PRIu64 "\n", defaultHits); else outBRDA_.put("-\n", 2); numBranchesFound_++; numBranchesHit_ += !!defaultHits; }
--- a/js/src/vm/Printer.h +++ b/js/src/vm/Printer.h @@ -38,17 +38,17 @@ class GenericPrinter // the beginning of this new data. virtual int put(const char* s, size_t len) = 0; inline int put(const char* s) { return put(s, strlen(s)); } // Prints a formatted string into the buffer. - virtual int printf(const char* fmt, ...); + virtual int printf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3); virtual int vprintf(const char* fmt, va_list ap); // Report that a string operation failed to get the memory it requested. The // first call to this function calls JS_ReportOutOfMemory, and sets this // Sprinter's outOfMemory flag; subsequent calls do nothing. virtual void reportOutOfMemory(); // Return true if this Sprinter ran out of memory. @@ -110,17 +110,17 @@ class Sprinter final : public GenericPri // Puts |len| characters from |s| at the current position and return an offset to // the beginning of this new data. virtual int put(const char* s, size_t len) override; using GenericPrinter::put; // pick up |inline int put(const char* s);| // Format the given format/arguments as if by JS_vsmprintf, then put it. // Return true on success, else return false and report an error (typically // OOM). - MOZ_MUST_USE bool jsprintf(const char* fmt, ...); + MOZ_MUST_USE bool jsprintf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3); // Prints a formatted string into the buffer. virtual int vprintf(const char* fmt, va_list ap) override; int putString(JSString* str); ptrdiff_t getOffset() const; @@ -152,17 +152,17 @@ class Fprinter final : public GenericPri void finish(); // Puts |len| characters from |s| at the current position and return an // offset to the beginning of this new data. virtual int put(const char* s, size_t len) override; using GenericPrinter::put; // pick up |inline int put(const char* s);| // Prints a formatted string into the buffer. - virtual int printf(const char* fmt, ...) override; + virtual int printf(const char* fmt, ...) override MOZ_FORMAT_PRINTF(2, 3); virtual int vprintf(const char* fmt, va_list ap) override; }; // LSprinter, is similar to Sprinter except that instead of using an // ExclusiveContext to allocate strings, it use a LifoAlloc as a backend for the // allocation of the chunk of the string. class LSprinter final : public GenericPrinter { @@ -198,17 +198,17 @@ class LSprinter final : public GenericPr void clear(); // Puts |len| characters from |s| at the current position and return an // offset to the beginning of this new data. virtual int put(const char* s, size_t len) override; using GenericPrinter::put; // pick up |inline int put(const char* s);| // Prints a formatted string into the buffer. - virtual int printf(const char* fmt, ...) override; + virtual int printf(const char* fmt, ...) override MOZ_FORMAT_PRINTF(2, 3); virtual int vprintf(const char* fmt, va_list ap) override; // Report that a string operation failed to get the memory it requested. The // first call to this function calls JS_ReportOutOfMemory, and sets this // Sprinter's outOfMemory flag; subsequent calls do nothing. virtual void reportOutOfMemory() override; // Return true if this Sprinter ran out of memory.
--- a/js/src/vm/String.cpp +++ b/js/src/vm/String.cpp @@ -5,16 +5,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "vm/String-inl.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/MemoryReporting.h" #include "mozilla/PodOperations.h" #include "mozilla/RangedPtr.h" +#include "mozilla/SizePrintfMacros.h" #include "mozilla/TypeTraits.h" #include "mozilla/Unused.h" #include "gc/Marking.h" #include "js/UbiNode.h" #include "vm/SPSProfiler.h" #include "jscntxtinlines.h" @@ -182,17 +183,17 @@ JSString::dumpRepresentation(FILE* fp, i } void JSString::dumpRepresentationHeader(FILE* fp, int indent, const char* subclass) const { uint32_t flags = d.u1.flags; // Print the string's address as an actual C++ expression, to facilitate // copy-and-paste into a debugger. - fprintf(fp, "((%s*) %p) length: %zu flags: 0x%x", subclass, this, length(), flags); + fprintf(fp, "((%s*) %p) length: %" PRIuSIZE " flags: 0x%x", subclass, this, length(), flags); if (flags & FLAT_BIT) fputs(" FLAT", fp); if (flags & HAS_BASE_BIT) fputs(" HAS_BASE", fp); if (flags & INLINE_CHARS_BIT) fputs(" INLINE_CHARS", fp); if (flags & ATOM_BIT) fputs(" ATOM", fp); if (isPermanentAtom()) fputs(" PERMANENT", fp); if (flags & LATIN1_CHARS_BIT) fputs(" LATIN1", fp); fputc('\n', fp); } @@ -698,17 +699,17 @@ JSDependentString::undepend(ExclusiveCon #ifdef DEBUG void JSDependentString::dumpRepresentation(FILE* fp, int indent) const { dumpRepresentationHeader(fp, indent, "JSDependentString"); indent += 2; - fprintf(fp, "%*soffset: %zu\n", indent, "", baseOffset()); + fprintf(fp, "%*soffset: %" PRIuSIZE "\n", indent, "", baseOffset()); fprintf(fp, "%*sbase: ", indent, ""); base()->dumpRepresentation(fp, indent); } #endif template <typename CharT> /* static */ bool JSFlatString::isIndexSlow(const CharT* s, size_t length, uint32_t* indexp) @@ -1358,17 +1359,17 @@ NewStringCopyUTF8N<CanGC>(JSContext* cx, #ifdef DEBUG void JSExtensibleString::dumpRepresentation(FILE* fp, int indent) const { dumpRepresentationHeader(fp, indent, "JSExtensibleString"); indent += 2; - fprintf(fp, "%*scapacity: %zu\n", indent, "", capacity()); + fprintf(fp, "%*scapacity: %" PRIuSIZE "\n", indent, "", capacity()); dumpRepresentationChars(fp, indent); } void JSInlineString::dumpRepresentation(FILE* fp, int indent) const { dumpRepresentationHeader(fp, indent, isFatInline() ? "JSFatInlineString" : "JSThinInlineString");
--- a/js/src/vm/TraceLoggingGraph.cpp +++ b/js/src/vm/TraceLoggingGraph.cpp @@ -45,16 +45,17 @@ TraceLoggerGraphState* traceLoggerGraphS #endif #define MAX_LOGGERS 999 // Return a filename relative to the output directory. %u and %d substitutions // are allowed, with %u standing for a full 32-bit number and %d standing for // an up to 3-digit number. static js::UniqueChars +MOZ_FORMAT_PRINTF(1, 2) AllocTraceLogFilename(const char* pattern, ...) { js::UniqueChars filename; va_list ap; static const char* outdir = getenv("TLDIR") ? getenv("TLDIR") : DEFAULT_TRACE_LOG_DIR; size_t len = strlen(outdir) + 1; // "+ 1" is for the '/'
--- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -232,16 +232,17 @@ js::InferSpewImpl(const char* fmt, ...) fprintf(stderr, "[infer] "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); } #endif MOZ_NORETURN MOZ_COLD static void +MOZ_FORMAT_PRINTF(2, 3) TypeFailure(JSContext* cx, const char* fmt, ...) { char msgbuf[1024]; /* Larger error messages will be truncated */ char errbuf[1024]; va_list ap; va_start(ap, fmt); VsprintfLiteral(errbuf, fmt, ap); @@ -3283,17 +3284,17 @@ js::TypeMonitorResult(JSContext* cx, JSS assertSameCompartment(cx, script, type); AutoEnterAnalysis enter(cx); StackTypeSet* types = TypeScript::BytecodeTypes(script, pc); if (types->hasType(type)) return; - InferSpew(ISpewOps, "bytecodeType: %p %05u: %s", + InferSpew(ISpewOps, "bytecodeType: %p %05" PRIuSIZE ": %s", script, script->pcToOffset(pc), TypeSet::TypeString(type)); types->addType(cx, type); } void js::TypeMonitorResult(JSContext* cx, JSScript* script, jsbytecode* pc, const js::Value& rval) { /* Allow the non-TYPESET scenario to simplify stubs used in compound opcodes. */
--- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -1291,17 +1291,17 @@ enum SpewChannel { #ifdef DEBUG bool InferSpewActive(SpewChannel channel); const char * InferSpewColorReset(); const char * InferSpewColor(TypeConstraint* constraint); const char * InferSpewColor(TypeSet* types); #define InferSpew(channel, ...) if (InferSpewActive(channel)) { InferSpewImpl(__VA_ARGS__); } else {} -void InferSpewImpl(const char* fmt, ...); +void InferSpewImpl(const char* fmt, ...) MOZ_FORMAT_PRINTF(1, 2); /* Check that the type property for id in group contains value. */ bool ObjectGroupHasProperty(JSContext* cx, ObjectGroup* group, jsid id, const Value& value); #else inline const char * InferSpewColorReset() { return nullptr; } inline const char * InferSpewColor(TypeConstraint* constraint) { return nullptr; }
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -149,16 +149,17 @@ private: char* mBuf; // prevent copying and assignment JSCLContextHelper(const JSCLContextHelper&) = delete; const JSCLContextHelper& operator=(const JSCLContextHelper&) = delete; }; static nsresult +MOZ_FORMAT_PRINTF(2, 3) ReportOnCallerUTF8(JSContext* callerContext, const char* format, ...) { if (!callerContext) { return NS_ERROR_FAILURE; } va_list ap; va_start(ap, format); @@ -172,16 +173,17 @@ ReportOnCallerUTF8(JSContext* callerCont JS_ReportErrorUTF8(callerContext, "%s", buf); JS_smprintf_free(buf); va_end(ap); return NS_OK; } static nsresult +MOZ_FORMAT_PRINTF(2, 3) ReportOnCallerUTF8(JSCLContextHelper& helper, const char* format, ...) { va_list ap; va_start(ap, format); char* buf = JS_vsmprintf(format, ap); if (!buf) {
--- a/js/xpconnect/src/XPCThrower.cpp +++ b/js/xpconnect/src/XPCThrower.cpp @@ -111,19 +111,19 @@ XPCThrower::ThrowBadResult(nsresult rv, return; // else... if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format) || !format) format = ""; if (nsXPCException::NameAndFormatForNSResult(result, &name, nullptr) && name) - sz = JS_smprintf("%s 0x%x (%s)", format, result, name); + sz = JS_smprintf("%s 0x%x (%s)", format, (unsigned) result, name); else - sz = JS_smprintf("%s 0x%x", format, result); + sz = JS_smprintf("%s 0x%x", format, (unsigned) result); NS_ENSURE_TRUE_VOID(sz); if (sz && sVerbose) Verbosify(ccx, &sz, true); dom::Throw(ccx, result, nsDependentCString(sz)); if (sz)
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp +++ b/js/xpconnect/src/XPCWrappedJSClass.cpp @@ -966,17 +966,17 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra return NS_ERROR_FAILURE; // [implicit_jscontext] and [optional_argc] have a different calling // convention, which we don't support for JS-implemented components. if (info->WantsOptArgc() || info->WantsContext()) { const char* str = "IDL methods marked with [implicit_jscontext] " "or [optional_argc] may not be implemented in JS"; // Throw and warn for good measure. - JS_ReportErrorASCII(cx, str); + JS_ReportErrorASCII(cx, "%s", str); NS_WARNING(str); return CheckForException(ccx, aes, name, GetInterfaceName()); } RootedValue fval(cx); RootedObject obj(cx, wrapper->GetJSObject()); RootedObject thisObj(cx, obj);
--- a/js/xpconnect/src/moz.build +++ b/js/xpconnect/src/moz.build @@ -67,9 +67,9 @@ LOCAL_INCLUDES += [ ] if CONFIG['MOZ_B2G_BT']: LOCAL_INCLUDES += [ '/dom/bluetooth/common', ] if CONFIG['GNU_CXX']: - CXXFLAGS += ['-Wno-shadow'] + CXXFLAGS += ['-Wno-shadow', '-Werror=format']
--- a/js/xpconnect/wrappers/AccessCheck.cpp +++ b/js/xpconnect/wrappers/AccessCheck.cpp @@ -269,17 +269,17 @@ AccessCheck::checkPassToPrivilegedCode(J } enum Access { READ = (1<<0), WRITE = (1<<1), NO_ACCESS = 0 }; static void EnterAndThrowASCII(JSContext* cx, JSObject* wrapper, const char* msg) { JSAutoCompartment ac(cx, wrapper); - JS_ReportErrorASCII(cx, msg); + JS_ReportErrorASCII(cx, "%s", msg); } bool ExposedPropertiesOnly::check(JSContext* cx, HandleObject wrapper, HandleId id, Wrapper::Action act) { RootedObject wrappedObject(cx, Wrapper::wrappedObject(wrapper)); if (act == Wrapper::CALL)
--- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -12800,21 +12800,17 @@ Iterator::AppendItemsToList(const Iterat !aTargetList.mUndisplayedItems.IsEmpty()) { do { AppendItemToList(aTargetList); } while (*this != aEnd); return; } // Move our entire list of items into the empty target list. - // XXX: If LinkedList supports move assignment, we could use - // aTargetList.mItems = Move(mList.mItems); - aTargetList.mItems.~LinkedList<FrameConstructionItem>(); - new (&aTargetList.mItems) LinkedList<FrameConstructionItem>( - Move(mList.mItems)); + aTargetList.mItems = Move(mList.mItems); // Copy over the various counters aTargetList.mInlineCount = mList.mInlineCount; aTargetList.mBlockCount = mList.mBlockCount; aTargetList.mLineParticipantCount = mList.mLineParticipantCount; aTargetList.mItemCount = mList.mItemCount; memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts, sizeof(aTargetList.mDesiredParentCounts));
--- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -1405,22 +1405,21 @@ nsBlockFrame::Reflow(nsPresContext* } if (cbHeightChanged) { flags |= AbsPosReflowFlags::eCBHeightChanged; } // Setup the line cursor here to optimize line searching for // calculating hypothetical position of absolutely-positioned // frames. The line cursor is immediately cleared afterward to // avoid affecting the display list generation. - SetupLineCursor(); + AutoLineCursorSetup autoLineCursor(this); absoluteContainer->Reflow(this, aPresContext, *reflowInput, state.mReflowStatus, containingBlock, flags, &aMetrics.mOverflowAreas); - ClearLineCursor(); } } FinishAndStoreOverflow(&aMetrics); // Clear the float manager pointer in the block reflow state so we // don't waste time translating the coordinate system back on a dead // float manager.
--- a/layout/generic/nsBlockFrame.h +++ b/layout/generic/nsBlockFrame.h @@ -148,18 +148,22 @@ public: virtual nsFrameState GetDebugStateBits() const override; const char* LineReflowStatusToString(LineReflowStatus aLineReflowStatus) const; #endif #ifdef ACCESSIBILITY virtual mozilla::a11y::AccType AccessibleType() override; #endif - // line cursor methods to speed up searching for the line(s) - // containing a point. The basic idea is that we set the cursor + // Line cursor methods to speed up line searching in which one query + // result is expected to be close to the next in general. This is + // mainly for searching line(s) containing a point. It is also used + // as a cache for local computation. Use AutoLineCursorSetup for the + // latter case so that it wouldn't interact unexpectedly with the + // former. The basic idea for the former is that we set the cursor // property if the lines' overflowArea.VisualOverflow().ys and // overflowArea.VisualOverflow().yMosts are non-decreasing // (considering only non-empty overflowArea.VisualOverflow()s; empty // overflowArea.VisualOverflow()s never participate in event handling // or painting), and the block has sufficient number of lines. The // cursor property points to a "recently used" line. If we get a // series of requests that work on lines // "near" the cursor, then we can find those nearby lines quickly by @@ -174,16 +178,46 @@ public: // to be before any line which does contain 'y'. nsLineBox* GetFirstLineContaining(nscoord y); // Set the line cursor to our first line. Only call this if you // guarantee that either the lines' combinedArea.ys and combinedArea. // yMosts are non-decreasing, or the line cursor is cleared before // building the display list of this frame. void SetupLineCursor(); + /** + * Helper RAII class for automatically set and clear line cursor for + * temporary use. If the frame already has line cursor, this would be + * a no-op. + */ + class MOZ_STACK_CLASS AutoLineCursorSetup + { + public: + explicit AutoLineCursorSetup(nsBlockFrame* aFrame) + : mFrame(aFrame) + , mOrigCursor(aFrame->GetLineCursor()) + { + if (!mOrigCursor) { + mFrame->SetupLineCursor(); + } + } + ~AutoLineCursorSetup() + { + if (mOrigCursor) { + mFrame->Properties().Set(LineCursorProperty(), mOrigCursor); + } else { + mFrame->ClearLineCursor(); + } + } + + private: + nsBlockFrame* mFrame; + nsLineBox* mOrigCursor; + }; + virtual void ChildIsDirty(nsIFrame* aChild) override; virtual bool IsVisibleInSelection(nsISelection* aSelection) override; virtual bool IsEmpty() override; virtual bool CachedIsEmpty() override; virtual bool IsSelfEmpty() override; // Given that we have a bullet, does it actually draw something, i.e., @@ -363,19 +397,19 @@ protected: } virtual ~nsBlockFrame(); #ifdef DEBUG already_AddRefed<nsStyleContext> GetFirstLetterStyle(nsPresContext* aPresContext); #endif NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(LineCursorProperty, nsLineBox) + bool HasLineCursor() { return GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR; } nsLineBox* GetLineCursor() { - return (GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR) ? - Properties().Get(LineCursorProperty()) : nullptr; + return HasLineCursor() ? Properties().Get(LineCursorProperty()) : nullptr; } nsLineBox* NewLineBox(nsIFrame* aFrame, bool aIsBlock) { return NS_NewLineBox(PresContext()->PresShell(), aFrame, aIsBlock); } nsLineBox* NewLineBox(nsLineBox* aFromLine, nsIFrame* aFrame, int32_t aCount) { return NS_NewLineBox(PresContext()->PresShell(), aFromLine, aFrame, aCount); }
--- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -9629,27 +9629,20 @@ static void TransformChars(nsTextFrame* } else { // Should not happen (see assertion above), but as a fallback... aOut.Append(fragString); } } } static bool -LineEndsInHardLineBreak(nsTextFrame* aFrame) -{ - nsIFrame* lineContainer = FindLineContainer(aFrame); - nsBlockFrame* block = do_QueryFrame(lineContainer); - if (!block) { - // Weird situation where we have a line layout without a block. - // No soft breaks occur in this situation. - return true; - } +LineEndsInHardLineBreak(nsTextFrame* aFrame, nsBlockFrame* aLineContainer) +{ bool foundValidLine; - nsBlockInFlowLineIterator iter(block, aFrame, &foundValidLine); + nsBlockInFlowLineIterator iter(aLineContainer, aFrame, &foundValidLine); if (!foundValidLine) { NS_ERROR("Invalid line!"); return true; } return !iter.GetLine()->IsLineWrapped(); } nsIFrame::RenderedText @@ -9657,40 +9650,62 @@ nsTextFrame::GetRenderedText(uint32_t aS uint32_t aEndOffset, TextOffsetType aOffsetType, TrailingWhitespace aTrimTrailingWhitespace) { NS_ASSERTION(!GetPrevContinuation(), "Must be called on first-in-flow"); // The handling of offsets could be more efficient... RenderedText result; + nsBlockFrame* lineContainer = nullptr; nsTextFrame* textFrame; const nsTextFragment* textFrag = mContent->GetText(); uint32_t offsetInRenderedString = 0; bool haveOffsets = false; + Maybe<nsBlockFrame::AutoLineCursorSetup> autoLineCursor; for (textFrame = this; textFrame; textFrame = static_cast<nsTextFrame*>(textFrame->GetNextContinuation())) { if (textFrame->GetStateBits() & NS_FRAME_IS_DIRTY) { // We don't trust dirty frames, especially when computing rendered text. break; } // Ensure the text run and grab the gfxSkipCharsIterator for it gfxSkipCharsIterator iter = textFrame->EnsureTextRun(nsTextFrame::eInflated); if (!textFrame->mTextRun) { break; } gfxSkipCharsIterator tmpIter = iter; + // Whether we need to trim whitespaces after the text frame. + bool trimAfter; + if (!textFrame->IsAtEndOfLine() || + aTrimTrailingWhitespace != + TrailingWhitespace::TRIM_TRAILING_WHITESPACE) { + trimAfter = false; + } else if (nsBlockFrame* thisLc = + do_QueryFrame(FindLineContainer(textFrame))) { + if (thisLc != lineContainer) { + // Setup line cursor when needed. + lineContainer = thisLc; + autoLineCursor.reset(); + autoLineCursor.emplace(lineContainer); + } + trimAfter = LineEndsInHardLineBreak(textFrame, lineContainer); + } else { + // Weird situation where we have a line layout without a block. + // No soft breaks occur in this situation. + trimAfter = true; + } + // Skip to the start of the text run, past ignored chars at start of line - TrimmedOffsets trimmedOffsets = textFrame->GetTrimmedOffsets(textFrag, - textFrame->IsAtEndOfLine() && LineEndsInHardLineBreak(textFrame) && - aTrimTrailingWhitespace == TrailingWhitespace::TRIM_TRAILING_WHITESPACE); + TrimmedOffsets trimmedOffsets = + textFrame->GetTrimmedOffsets(textFrag, trimAfter); bool trimmedSignificantNewline = trimmedOffsets.GetEnd() < GetContentEnd() && HasSignificantTerminalNewline(); uint32_t skippedToRenderedStringOffset = offsetInRenderedString - tmpIter.ConvertOriginalToSkipped(trimmedOffsets.mStart); uint32_t nextOffsetInRenderedString = tmpIter.ConvertOriginalToSkipped(trimmedOffsets.GetEnd()) + (trimmedSignificantNewline ? 1 : 0) + skippedToRenderedStringOffset;
--- a/mfbt/Attributes.h +++ b/mfbt/Attributes.h @@ -564,9 +564,41 @@ # include "mozilla/Compiler.h" # if MOZ_GCC_VERSION_AT_LEAST(4, 8, 1) # define MOZ_HAVE_REF_QUALIFIERS # endif #endif #endif /* __cplusplus */ +/** + * Printf style formats. MOZ_FORMAT_PRINTF can be used to annotate a + * function or method that is "printf-like"; this will let (some) + * compilers check that the arguments match the template string. + * + * This macro takes two arguments. The first argument is the argument + * number of the template string. The second argument is the argument + * number of the '...' argument holding the arguments. + * + * Argument numbers start at 1. Note that the implicit "this" + * argument of a non-static member function counts as an argument. + * + * So, for a simple case like: + * void print_something (int whatever, const char *fmt, ...); + * The corresponding annotation would be + * MOZ_FORMAT_PRINTF(2, 3) + * However, if "print_something" were a non-static member function, + * then the annotation would be: + * MOZ_FORMAT_PRINTF(3, 4) + * + * Note that the checking is limited to standards-conforming + * printf-likes, and in particular this should not be used for + * PR_snprintf and friends, which are "printf-like" but which assign + * different meanings to the various formats. + */ +#ifdef __GNUC__ +#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) \ + __attribute__ ((format (printf, stringIndex, firstToCheck))) +#else +#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) +#endif + #endif /* mozilla_Attributes_h */
--- a/mfbt/LinkedList.h +++ b/mfbt/LinkedList.h @@ -120,44 +120,33 @@ private: public: LinkedListElement() : mNext(this), mPrev(this), mIsSentinel(false) { } - LinkedListElement(LinkedListElement<T>&& other) - : mIsSentinel(other.mIsSentinel) + /* + * Moves |aOther| into |*this|. If |aOther| is already in a list, then + * |aOther| is removed from the list and replaced by |*this|. + */ + LinkedListElement(LinkedListElement<T>&& aOther) + : mIsSentinel(aOther.mIsSentinel) { - if (!other.isInList()) { - mNext = this; - mPrev = this; - return; - } - - MOZ_ASSERT(other.mNext->mPrev == &other); - MOZ_ASSERT(other.mPrev->mNext == &other); + adjustLinkForMove(Move(aOther)); + } - /* - * Initialize |this| with |other|'s mPrev/mNext pointers, and adjust those - * element to point to this one. - */ - mNext = other.mNext; - mPrev = other.mPrev; - - mNext->mPrev = this; - mPrev->mNext = this; - - /* - * Adjust |other| so it doesn't think it's in a list. This makes it - * safely destructable. - */ - other.mNext = &other; - other.mPrev = &other; + LinkedListElement& operator=(LinkedListElement<T>&& aOther) + { + MOZ_ASSERT(mIsSentinel == aOther.mIsSentinel, "Mismatch NodeKind!"); + MOZ_ASSERT(!isInList(), + "Assigning to an element in a list messes up that list!"); + adjustLinkForMove(Move(aOther)); + return *this; } ~LinkedListElement() { if (!mIsSentinel && isInList()) { remove(); } } @@ -228,25 +217,25 @@ public: { MOZ_ASSERT((mNext == this) == (mPrev == this)); return mNext != this; } private: friend class LinkedList<T>; - enum NodeKind { - NODE_KIND_NORMAL, - NODE_KIND_SENTINEL + enum class NodeKind { + Normal, + Sentinel }; explicit LinkedListElement(NodeKind nodeKind) : mNext(this), mPrev(this), - mIsSentinel(nodeKind == NODE_KIND_SENTINEL) + mIsSentinel(nodeKind == NodeKind::Sentinel) { } /* * Return |this| cast to T* if we're a normal node, or return nullptr if * we're a sentinel node. */ T* asT() { @@ -282,17 +271,49 @@ private: MOZ_ASSERT(!listElem->isInList()); listElem->mNext = this; listElem->mPrev = this->mPrev; this->mPrev->mNext = listElem; this->mPrev = listElem; } -private: + /* + * Adjust mNext and mPrev for implementing move constructor and move + * assignment. + */ + void adjustLinkForMove(LinkedListElement<T>&& aOther) + { + if (!aOther.isInList()) { + mNext = this; + mPrev = this; + return; + } + + MOZ_ASSERT(aOther.mNext->mPrev == &aOther); + MOZ_ASSERT(aOther.mPrev->mNext == &aOther); + + /* + * Initialize |this| with |aOther|'s mPrev/mNext pointers, and adjust those + * element to point to this one. + */ + mNext = aOther.mNext; + mPrev = aOther.mPrev; + + mNext->mPrev = this; + mPrev->mNext = this; + + /* + * Adjust |aOther| so it doesn't think it's in a list. This makes it + * safely destructable. + */ + aOther.mNext = &aOther; + aOther.mPrev = &aOther; + } + LinkedListElement& operator=(const LinkedListElement<T>& aOther) = delete; LinkedListElement(const LinkedListElement<T>& aOther) = delete; }; template<typename T> class LinkedList { private: @@ -314,22 +335,29 @@ public: return *this; } bool operator!=(Iterator& aOther) const { return mCurrent != aOther.mCurrent; } }; - LinkedList() : sentinel(LinkedListElement<T>::NODE_KIND_SENTINEL) { } + LinkedList() : sentinel(LinkedListElement<T>::NodeKind::Sentinel) { } LinkedList(LinkedList<T>&& aOther) : sentinel(mozilla::Move(aOther.sentinel)) { } + LinkedList& operator=(LinkedList<T>&& aOther) + { + MOZ_ASSERT(isEmpty(), "Assigning to a non-empty list leaks elements in that list!"); + sentinel = mozilla::Move(aOther.sentinel); + return *this; + } + ~LinkedList() { MOZ_ASSERT(isEmpty(), "failing this assertion means this LinkedList's creator is " "buggy: it should have removed all this list's elements before " "the list's destruction"); } /*
--- a/mfbt/Sprintf.h +++ b/mfbt/Sprintf.h @@ -8,32 +8,31 @@ #ifndef mozilla_Sprintf_h_ #define mozilla_Sprintf_h_ #include <stdio.h> #include <stdarg.h> #include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" #ifdef __cplusplus template <size_t N> int VsprintfLiteral(char (&buffer)[N], const char* format, va_list args) { MOZ_ASSERT(format != buffer); int result = vsnprintf(buffer, N, format, args); buffer[N - 1] = '\0'; return result; } template <size_t N> -#if defined(__GNUC__) - __attribute__((format(printf, 2, 3))) -#endif +MOZ_FORMAT_PRINTF(2, 3) int SprintfLiteral(char (&buffer)[N], const char* format, ...) { va_list args; va_start(args, format); int result = VsprintfLiteral(buffer, format, args); va_end(args); return result; }
--- a/mfbt/tests/TestLinkedList.cpp +++ b/mfbt/tests/TestLinkedList.cpp @@ -7,17 +7,17 @@ #include "mozilla/Assertions.h" #include "mozilla/LinkedList.h" using mozilla::LinkedList; using mozilla::LinkedListElement; struct SomeClass : public LinkedListElement<SomeClass> { unsigned int mValue; - explicit SomeClass(int aValue) : mValue(aValue) {} + explicit SomeClass(int aValue = 0) : mValue(aValue) {} void incr() { ++mValue; } }; template <size_t N> static void CheckListValues(LinkedList<SomeClass>& list, unsigned int (&values)[N]) { size_t count = 0; @@ -29,17 +29,17 @@ CheckListValues(LinkedList<SomeClass>& l } static void TestList() { LinkedList<SomeClass> list; SomeClass one(1), two(2), three(3); - + MOZ_RELEASE_ASSERT(list.isEmpty()); MOZ_RELEASE_ASSERT(!list.getFirst()); MOZ_RELEASE_ASSERT(!list.getLast()); MOZ_RELEASE_ASSERT(!list.popFirst()); MOZ_RELEASE_ASSERT(!list.popLast()); for (SomeClass* x : list) { MOZ_RELEASE_ASSERT(x); @@ -47,17 +47,17 @@ TestList() } list.insertFront(&one); { unsigned int check[] { 1 }; CheckListValues(list, check); } MOZ_RELEASE_ASSERT(one.isInList()); MOZ_RELEASE_ASSERT(!two.isInList()); MOZ_RELEASE_ASSERT(!three.isInList()); - + MOZ_RELEASE_ASSERT(!list.isEmpty()); MOZ_RELEASE_ASSERT(list.getFirst()->mValue == 1); MOZ_RELEASE_ASSERT(list.getLast()->mValue == 1); list.insertFront(&two); { unsigned int check[] { 2, 1 }; CheckListValues(list, check); } MOZ_RELEASE_ASSERT(list.getFirst()->mValue == 2); @@ -112,16 +112,55 @@ TestList() } MOZ_RELEASE_ASSERT(list.getFirst() == &two); MOZ_RELEASE_ASSERT(list.getLast() == &three); MOZ_RELEASE_ASSERT(list.getFirst()->mValue == 3); MOZ_RELEASE_ASSERT(list.getLast()->mValue == 4); } +static void +TestMove() +{ + auto MakeSomeClass = + [] (unsigned int aValue) -> SomeClass { return SomeClass(aValue); }; + + LinkedList<SomeClass> list1; + + // Test move constructor for LinkedListElement. + SomeClass c1(MakeSomeClass(1)); + list1.insertBack(&c1); + + // Test move assignment for LinkedListElement from an element not in a + // list. + SomeClass c2; + c2 = MakeSomeClass(2); + list1.insertBack(&c2); + + // Test move assignment of LinkedListElement from an element already in a + // list. + SomeClass c3; + c3 = Move(c2); + MOZ_RELEASE_ASSERT(!c2.isInList()); + MOZ_RELEASE_ASSERT(c3.isInList()); + + // Test move constructor for LinkedList. + LinkedList<SomeClass> list2(Move(list1)); + { unsigned int check[] { 1, 2 }; CheckListValues(list2, check); } + MOZ_RELEASE_ASSERT(list1.isEmpty()); + + // Test move assignment for LinkedList. + LinkedList<SomeClass> list3; + list3 = Move(list2); + { unsigned int check[] { 1, 2 }; CheckListValues(list3, check); } + MOZ_RELEASE_ASSERT(list2.isEmpty()); + + list3.clear(); +} + struct PrivateClass : private LinkedListElement<PrivateClass> { friend class mozilla::LinkedList<PrivateClass>; friend class mozilla::LinkedListElement<PrivateClass>; }; static void TestPrivate() { @@ -138,10 +177,11 @@ TestPrivate() MOZ_RELEASE_ASSERT(count == 2); } int main() { TestList(); TestPrivate(); + TestMove(); return 0; }
--- a/moz.configure +++ b/moz.configure @@ -311,17 +311,19 @@ def nsis_version(nsis): out = check_cmd_output(nsis, '-version', onerror=lambda: die('Failed to get nsis version.')) m = re.search(r'(?<=v)[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?', out) if not m: raise FatalCheckError('Unknown version of makensis') ver = Version(m.group(0)) - if ver < nsis_min_version: + # Versions comparisons don't quite work well with beta versions, so ensure + # it works for the non-beta version. + if ver < nsis_min_version and (ver >= '3.0a' or ver < '3'): raise FatalCheckError('To build the installer you must have NSIS' ' version %s or greater in your path' % nsis_min_version) return ver # And that makensis is 32-bit. @depends_if(nsis)
--- a/python/mozbuild/mozbuild/test/configure/test_moz_configure.py +++ b/python/mozbuild/mozbuild/test/configure/test_moz_configure.py @@ -52,11 +52,42 @@ class TestMozConfigure(BaseConfigureTest self.assertEquals('--enable-application=browser --with-foo', get_value_for(['--enable-application=browser', '--with-foo'])) self.assertEquals("--enable-application=browser '--with-foo=foo bar'", get_value_for(['--enable-application=browser', '--with-foo=foo bar'])) + def test_nsis_version(self): + this = self + + class FakeNSIS(object): + def __init__(self, version): + self.version = version + + def __call__(self, stdin, args): + this.assertEquals(args, ('-version',)) + return 0, self.version, '' + + def check_nsis_version(version): + sandbox = self.get_sandbox( + {'/usr/bin/makensis': FakeNSIS(version)}, {}, [], + {'PATH': '/usr/bin', 'MAKENSISU': '/usr/bin/makensis'}) + return sandbox._value_for(sandbox['nsis_version']) + + with self.assertRaises(SystemExit) as e: + check_nsis_version('v2.5') + + with self.assertRaises(SystemExit) as e: + check_nsis_version('v3.0a2') + + self.assertEquals(check_nsis_version('v3.0b1'), '3.0b1') + self.assertEquals(check_nsis_version('v3.0b2'), '3.0b2') + self.assertEquals(check_nsis_version('v3.0rc1'), '3.0rc1') + self.assertEquals(check_nsis_version('v3.0'), '3.0') + self.assertEquals(check_nsis_version('v3.0-2'), '3.0') + self.assertEquals(check_nsis_version('v3.0.1'), '3.0') + self.assertEquals(check_nsis_version('v3.1'), '3.1') + if __name__ == '__main__': main()
--- a/security/manager/locales/en-US/chrome/pippki/pippki.properties +++ b/security/manager/locales/en-US/chrome/pippki/pippki.properties @@ -106,17 +106,19 @@ pageInfo_EncryptionWithBitsAndProtocol=C pageInfo_BrokenEncryption=Broken Encryption (%1$S, %2$S bit keys, %3$S) pageInfo_Privacy_Encrypted1=The page you are viewing was encrypted before being transmitted over the Internet. pageInfo_Privacy_Encrypted2=Encryption makes it difficult for unauthorized people to view information traveling between computers. It is therefore unlikely that anyone read this page as it traveled across the network. pageInfo_MixedContent=Connection Partially Encrypted pageInfo_MixedContent2=Parts of the page you are viewing were not encrypted before being transmitted over the Internet. pageInfo_WeakCipher=Your connection to this website uses weak encryption and is not private. Other people can view your information or modify the website’s behavior. # Cert Viewer -certDetails=Certificate Viewer: +# LOCALIZATION NOTE(certViewerTitle): Title used for the Certificate Viewer. +# %1$S is a string representative of the certificate being viewed. +certViewerTitle=Certificate Viewer: “%1$S” notPresent=<Not Part Of Certificate> # Token Manager password_not_set=(not set) failed_pw_change=Unable to change Master Password. incorrect_pw=You did not enter the correct current Master Password. Please try again. pw_change_ok=Master Password successfully changed. pw_erased_ok=Warning! You have deleted your Master Password.
--- a/security/manager/pki/nsNSSDialogHelper.h +++ b/security/manager/pki/nsNSSDialogHelper.h @@ -6,22 +6,33 @@ #ifndef nsNSSDialogHelper_h #define nsNSSDialogHelper_h class mozIDOMWindowProxy; class nsISupports; /** - * Common class that uses the window watcher service to open a - * standard dialog, with or without a parent context. The params - * parameter can be an nsISupportsArray so any number of additional - * arguments can be used. + * Helper class that uses the window watcher service to open a standard dialog, + * with or without a parent context. */ class nsNSSDialogHelper { public: - // params is a nsIDialogParamBlock or a nsIKeygenThread + /** + * Opens a XUL dialog. + * + * @param window + * Parent window of the dialog, or nullptr to signal no parent. + * @param url + * URL to the XUL dialog. + * @param params + * Parameters to pass to the dialog. Same semantics as the + * nsIWindowWatcher.openWindow() |aArguments| parameter. + * @param modal + * true if the dialog should be modal, false otherwise. + * @return The result of opening the dialog. + */ static nsresult openDialog(mozIDOMWindowProxy* window, const char* url, nsISupports* params, bool modal = true); }; -#endif +#endif // nsNSSDialogHelper_h
--- a/security/manager/pki/nsNSSDialogs.cpp +++ b/security/manager/pki/nsNSSDialogs.cpp @@ -2,45 +2,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/. */ /* * Dialog services for PIP. */ + +#include "nsNSSDialogs.h" + #include "mozIDOMWindow.h" #include "mozilla/Assertions.h" #include "mozilla/Casting.h" #include "nsArray.h" -#include "nsDateTimeFormatCID.h" #include "nsEmbedCID.h" -#include "nsIComponentManager.h" -#include "nsIDateTimeFormat.h" #include "nsIDialogParamBlock.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIKeygenThread.h" #include "nsIPromptService.h" #include "nsIProtectedAuthThread.h" -#include "nsIServiceManager.h" #include "nsIWindowWatcher.h" #include "nsIX509CertDB.h" #include "nsIX509Cert.h" -#include "nsIX509CertValidity.h" #include "nsNSSDialogHelper.h" -#include "nsNSSDialogs.h" -#include "nsPromiseFlatString.h" -#include "nsReadableUtils.h" #include "nsString.h" #define PIPSTRING_BUNDLE_URL "chrome://pippki/locale/pippki.properties" -/* ==== */ - nsNSSDialogs::nsNSSDialogs() { } nsNSSDialogs::~nsNSSDialogs() { } @@ -324,43 +317,28 @@ nsNSSDialogs::GetPKCS12FilePassword(nsII if (*_retval) { _password.Assign(pwTemp); free(pwTemp); } return NS_OK; } -NS_IMETHODIMP +NS_IMETHODIMP nsNSSDialogs::ViewCert(nsIInterfaceRequestor* ctx, nsIX509Cert* cert) { - nsCOMPtr<nsIMutableArray> dlgArray = nsArrayBase::Create(); - if (!dlgArray) { - return NS_ERROR_FAILURE; - } - nsresult rv = dlgArray->AppendElement(cert, false); - if (NS_FAILED(rv)) { - return rv; - } - nsCOMPtr<nsIDialogParamBlock> dlgParamBlock( - do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID)); - if (!dlgParamBlock) { - return NS_ERROR_FAILURE; - } - rv = dlgParamBlock->SetObjects(dlgArray); - if (NS_FAILED(rv)) { - return rv; - } + // |ctx| is allowed to be null. + NS_ENSURE_ARG(cert); // Get the parent window for the dialog nsCOMPtr<mozIDOMWindowProxy> parent = do_GetInterface(ctx); return nsNSSDialogHelper::openDialog(parent, "chrome://pippki/content/certViewer.xul", - dlgParamBlock, - false); + cert, + false /*modal*/); } NS_IMETHODIMP nsNSSDialogs::DisplayGeneratingKeypairInfo(nsIInterfaceRequestor *aCtx, nsIKeygenThread *runnable) { nsresult rv; // Get the parent window for the dialog
rename from security/manager/pki/resources/content/viewCertDetails.js rename to security/manager/pki/resources/content/certViewer.js --- a/security/manager/pki/resources/content/viewCertDetails.js +++ b/security/manager/pki/resources/content/certViewer.js @@ -1,27 +1,34 @@ /* 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/. */ "use strict"; +/** + * @file Implements functionality for certViewer.xul and its tabs certDump.xul + * and viewCertDetails.xul: a dialog that allows various attributes of a + * certificate to be viewed. + * @argument {nsISupports} window.arguments[0] + * The cert to view, queryable to nsIX509Cert. + */ + const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; const { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); const nsIX509Cert = Ci.nsIX509Cert; const nsX509CertDB = "@mozilla.org/security/x509certdb;1"; const nsIX509CertDB = Ci.nsIX509CertDB; const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1"; const nsIPK11TokenDB = Ci.nsIPK11TokenDB; const nsIASN1Object = Ci.nsIASN1Object; const nsIASN1Sequence = Ci.nsIASN1Sequence; const nsIASN1PrintableItem = Ci.nsIASN1PrintableItem; const nsIASN1Tree = Ci.nsIASN1Tree; const nsASN1Tree = "@mozilla.org/security/nsASN1Tree;1"; -const nsIDialogParamBlock = Ci.nsIDialogParamBlock; var bundle; function doPrompt(msg) { let prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]. getService(Components.interfaces.nsIPromptService); prompts.alert(window, null, msg); @@ -66,31 +73,21 @@ function AddUsage(usage) text.setAttribute("style", "margin: 2px 5px"); text.setAttribute("readonly", "true"); text.setAttribute("class", "scrollfield"); verifyInfoBox.appendChild(text); } function setWindowName() { - // Get the cert from the cert database - var certdb = Components.classes[nsX509CertDB].getService(nsIX509CertDB); - var myName = self.name; bundle = document.getElementById("pippki_bundle"); - var cert; - var certDetails = bundle.getString('certDetails'); - if (myName != "") { - document.title = certDetails + '"' + myName + '"'; // XXX l10n? - cert = certdb.findCertByNickname(myName); - } else { - var params = window.arguments[0].QueryInterface(nsIDialogParamBlock); - cert = params.objects.queryElementAt(0, nsIX509Cert); - document.title = certDetails + '"' + cert.windowTitle + '"'; // XXX l10n? - } + let cert = window.arguments[0].QueryInterface(Ci.nsIX509Cert); + document.title = bundle.getFormattedString("certViewerTitle", + [cert.windowTitle]); // // Set the cert attributes for viewing // // The chain of trust AddCertChain("treesetDump", cert.getChain()); DisplayGeneralDataFromCert(cert);
--- a/security/manager/pki/resources/content/certViewer.xul +++ b/security/manager/pki/resources/content/certViewer.xul @@ -15,17 +15,18 @@ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" buttons="accept" buttonlabelaccept="&certmgr.close.label;" buttonaccesskeyaccept="&certmgr.close.accesskey;" onload="setWindowName();"> <stringbundle id="pippki_bundle" src="chrome://pippki/locale/pippki.properties"/> -<script type="application/javascript" src="chrome://pippki/content/viewCertDetails.js"/> +<script type="application/javascript" + src="chrome://pippki/content/certViewer.js"/> <script type="application/javascript" src="chrome://pippki/content/pippki.js"/> <tabbox flex="1"> <tabs> <tab id="general_tab" label="&certmgr.detail.general_tab.title;" accesskey="&certmgr.detail.general_tab.accesskey;"/> <tab id="prettyprint_tab" label="&certmgr.detail.prettyprint_tab.title;" accesskey="&certmgr.detail.prettyprint_tab.accesskey;"/>
--- a/security/manager/pki/resources/jar.mn +++ b/security/manager/pki/resources/jar.mn @@ -19,22 +19,22 @@ pippki.jar: content/pippki/OrphanOverlay.xul (content/OrphanOverlay.xul) content/pippki/viewCertDetails.xul (content/viewCertDetails.xul) content/pippki/editcacert.xul (content/editcacert.xul) content/pippki/editcacert.js (content/editcacert.js) * content/pippki/exceptionDialog.xul (content/exceptionDialog.xul) content/pippki/exceptionDialog.js (content/exceptionDialog.js) content/pippki/deletecert.xul (content/deletecert.xul) content/pippki/deletecert.js (content/deletecert.js) - content/pippki/viewCertDetails.js (content/viewCertDetails.js) content/pippki/setp12password.xul (content/setp12password.xul) content/pippki/pippki.js (content/pippki.js) content/pippki/clientauthask.xul (content/clientauthask.xul) content/pippki/clientauthask.js (content/clientauthask.js) content/pippki/certViewer.xul (content/certViewer.xul) + content/pippki/certViewer.js (content/certViewer.js) content/pippki/certDump.xul (content/certDump.xul) content/pippki/device_manager.xul (content/device_manager.xul) content/pippki/device_manager.js (content/device_manager.js) content/pippki/load_device.xul (content/load_device.xul) content/pippki/choosetoken.xul (content/choosetoken.xul) content/pippki/choosetoken.js (content/choosetoken.js) content/pippki/createCertInfo.xul (content/createCertInfo.xul) content/pippki/createCertInfo.js (content/createCertInfo.js)
--- a/security/manager/ssl/tests/mochitest/browser/browser_certViewer.js +++ b/security/manager/ssl/tests/mochitest/browser/browser_certViewer.js @@ -5,113 +5,118 @@ // Repeatedly opens the certificate viewer dialog with various certificates and // determines that the viewer correctly identifies either what usages those // certificates are valid for or what errors prevented the certificates from // being verified. var { OS } = Cu.import("resource://gre/modules/osfile.jsm", {}); -add_task(function* () { +add_task(function* testCAandTitle() { let cert = yield readCertificate("ca.pem", "CTu,CTu,CTu"); let win = yield displayCertificate(cert); checkUsages(win, ["SSL Certificate Authority"]); + + // There's no real need to test the title for every cert, so we just test it + // once here. + Assert.equal(win.document.title, "Certificate Viewer: \u201Cca\u201D", + "Actual and expected title should match"); yield BrowserTestUtils.closeWindow(win); }); -add_task(function* () { +add_task(function* testSSLEndEntity() { let cert = yield readCertificate("ssl-ee.pem", ",,"); let win = yield displayCertificate(cert); checkUsages(win, ["SSL Server Certificate", "SSL Client Certificate"]); yield BrowserTestUtils.closeWindow(win); }); -add_task(function* () { +add_task(function* testEmailEndEntity() { let cert = yield readCertificate("email-ee.pem", ",,"); let win = yield displayCertificate(cert); checkUsages(win, ["Email Recipient Certificate", "Email Signer Certificate"]); yield BrowserTestUtils.closeWindow(win); }); -add_task(function* () { +add_task(function* testCodeSignEndEntity() { let cert = yield readCertificate("code-ee.pem", ",,"); let win = yield displayCertificate(cert); checkUsages(win, ["Object Signer"]); yield BrowserTestUtils.closeWindow(win); }); -add_task(function* () { +add_task(function* testExpired() { let cert = yield readCertificate("expired-ca.pem", ",,"); let win = yield displayCertificate(cert); checkError(win, "Could not verify this certificate because it has expired."); yield BrowserTestUtils.closeWindow(win); }); -add_task(function* () { +add_task(function* testIssuerExpired() { let cert = yield readCertificate("ee-from-expired-ca.pem", ",,"); let win = yield displayCertificate(cert); checkError(win, "Could not verify this certificate because the CA certificate " + "is invalid."); yield BrowserTestUtils.closeWindow(win); }); -add_task(function* () { +add_task(function* testUnknownIssuer() { let cert = yield readCertificate("unknown-issuer.pem", ",,"); let win = yield displayCertificate(cert); checkError(win, "Could not verify this certificate because the issuer is " + "unknown."); yield BrowserTestUtils.closeWindow(win); }); -add_task(function* () { +add_task(function* testInsecureAlgo() { let cert = yield readCertificate("md5-ee.pem", ",,"); let win = yield displayCertificate(cert); checkError(win, "Could not verify this certificate because it was signed using " + "a signature algorithm that was disabled because that algorithm " + "is not secure."); yield BrowserTestUtils.closeWindow(win); }); -add_task(function* () { +add_task(function* testUntrusted() { let cert = yield readCertificate("untrusted-ca.pem", "p,p,p"); let win = yield displayCertificate(cert); checkError(win, "Could not verify this certificate because it is not trusted."); yield BrowserTestUtils.closeWindow(win); }); -add_task(function* () { +add_task(function* testUntrustedIssuer() { let cert = yield readCertificate("ee-from-untrusted-ca.pem", ",,"); let win = yield displayCertificate(cert); checkError(win, "Could not verify this certificate because the issuer is not " + "trusted."); yield BrowserTestUtils.closeWindow(win); }); -add_task(function* () { +add_task(function* testRevoked() { // Note that there's currently no way to un-do this. This should only be a // problem if another test re-uses a certificate with this same key (perhaps // likely) and subject (less likely). let certBlocklist = Cc["@mozilla.org/security/certblocklist;1"] .getService(Ci.nsICertBlocklist); certBlocklist.revokeCertBySubjectAndPubKey( "MBIxEDAOBgNVBAMMB3Jldm9rZWQ=", // CN=revoked "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8="); // hash of the shared key let cert = yield readCertificate("revoked.pem", ",,"); let win = yield displayCertificate(cert); checkError(win, "Could not verify this certificate because it has been revoked."); yield BrowserTestUtils.closeWindow(win); }); -add_task(function* () { +add_task(function* testInvalid() { // This certificate has a keyUsage extension asserting cRLSign and // keyCertSign, but it doesn't have a basicConstraints extension. This // shouldn't be valid for any usage. Sadly, we give a pretty lame error // message in this case. let cert = yield readCertificate("invalid.pem", ",,"); let win = yield displayCertificate(cert); checkError(win, "Could not verify this certificate for unknown reasons."); yield BrowserTestUtils.closeWindow(win); @@ -124,23 +129,18 @@ add_task(function* () { * * @param {nsIX509Cert} certificate * The certificate to view and determine usages for. * @return {Promise} * A promise that will resolve with a handle on the opened certificate * viewer window when the usages have been determined. */ function displayCertificate(certificate) { - let array = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); - array.appendElement(certificate, false); - let params = Cc["@mozilla.org/embedcomp/dialogparam;1"] - .createInstance(Ci.nsIDialogParamBlock); - params.objects = array; let win = window.openDialog("chrome://pippki/content/certViewer.xul", "", - "", params); + "", certificate); return TestUtils.topicObserved("ViewCertDetails:CertUsagesDone", (subject, data) => subject == win) .then(([subject, data]) => subject, error => { throw error; }); } /** * Given a certificate viewer window, finds the usages the certificate is valid * for.
--- a/taskcluster/ci/desktop-test/test-platforms.yml +++ b/taskcluster/ci/desktop-test/test-platforms.yml @@ -20,14 +20,47 @@ linux64/opt: # TODO: use 'pgo' and 'asan' labels here, instead of -pgo/opt linux64-pgo/opt: build-platform: linux64-pgo/opt test-set: all-tests linux64-asan/opt: build-platform: linux64-asan/opt test-set: asan-tests + linux64-ccov/opt: build-platform: linux64-ccov/opt test-set: ccov-code-coverage-tests linux64-jsdcov/opt: build-platform: linux64-jsdcov/opt - test-set: jsdcov-code-coverage-tests \ No newline at end of file + test-set: jsdcov-code-coverage-tests + +# win32 vm +windows7-32-vm/debug: + build-platform: win32/debug + test-set: windows-vm-tests +windows7-32-vm/opt: + build-platform: win32/opt + test-set: windows-vm-tests + +# win32 gpu +#windows7-32/debug: +# build-platform: win32/debug +# test-set: windows-gpu-tests +#windows7-32/opt: +# build-platform: win32/opt +# test-set: windows-gpu-tests + +# win64 vm +windows10-64-vm/debug: + build-platform: win64/debug + test-set: windows-vm-tests +windows10-64-vm/opt: + build-platform: win64/opt + test-set: windows-vm-tests + +# win64 gpu +#windows10-64/debug: +# build-platform: win64/debug +# test-set: windows-gpu-tests +#windows10-64/opt: +# build-platform: win64/opt +# test-set: windows-gpu-tests
--- a/taskcluster/ci/desktop-test/test-sets.yml +++ b/taskcluster/ci/desktop-test/test-sets.yml @@ -53,13 +53,42 @@ asan-tests: - mochitest-gpu - mochitest-jetpack - mochitest-media - mochitest-webgl - reftest - reftest-no-accel - xpcshell +windows-vm-tests: + - cppunit + #- crashtest + #- external-media-tests + #- gtest + #- jittest + #- jsreftest + #- marionette + #- mochitest + #- mochitest-browser-chrome + #- mochitest-devtools-chrome + #- mochitest-jetpack + #- mochitest-media + #- web-platform-tests + #- web-platform-tests-reftests + #- xpcshell + +# windows-gpu-tests: +# - reftest +# - reftest-no-accel +# - mochitest-webgl + +# these tests currently run on hardware, but may migrate above when validated +# note: on win, mochitest-a11y and mochitest-chrome come under mochitest-other +# windows-hw-tests: +# - mochitest-clipboard +# - mochitest-gpu +# - mochitest-other + ccov-code-coverage-tests: - mochitest-browser-chrome jsdcov-code-coverage-tests: - mochitest-browser-chrome \ No newline at end of file
--- a/taskcluster/ci/desktop-test/tests.yml +++ b/taskcluster/ci/desktop-test/tests.yml @@ -10,38 +10,42 @@ cppunit: suite: cppunittest treeherder-symbol: tc(Cpp) e10s: false mozharness: script: desktop_unittest.py no-read-buildbot-config: true config: by-test-platform: - # Coming soon: - # win.*: - # - unittests/win_unittest.py - # - remove_executables.py - # ... + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --cppunittest-suite=cppunittest crashtest: description: "Crashtest run" suite: reftest/crashtest treeherder-symbol: tc-R(C) docker-image: {"in-tree": "desktop1604-test"} + e10s: + by-test-platform: + # Bug 1304435 + win.*: false + default: both mozharness: script: desktop_unittest.py chunked: true no-read-buildbot-config: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --reftest-suite=crashtest external-media-tests: description: "External Media Test run" @@ -49,18 +53,22 @@ external-media-tests: treeherder-symbol: tc-VP(b-m) e10s: false tier: 2 max-run-time: 5400 mozharness: script: firefox_media_tests_buildbot.py no-read-buildbot-config: true config: - - mediatests/buildbot_posix_config.py - - remove_executables.py + by-test-platform: + win.*: + - mediatests/taskcluster_windows_config.py + default: + - mediatests/buildbot_posix_config.py + - remove_executables.py firefox-ui-functional-local: description: "Firefox-ui-tests functional run" suite: "firefox-ui/functional local" treeherder-symbol: tc-Fxfn-l(en-US) max-run-time: 5400 tier: 1 docker-image: {"in-tree": "desktop1604-test"} @@ -93,80 +101,101 @@ gtest: treeherder-symbol: tc(GTest) e10s: false instance-size: xlarge mozharness: script: desktop_unittest.py no-read-buildbot-config: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --gtest-suite=gtest jittest: description: "JIT Test run" suite: jittest/jittest-chunked treeherder-symbol: tc(Jit) e10s: false - chunks: 6 + chunks: + by-test-platform: + win.*: 1 + default: 6 mozharness: script: desktop_unittest.py no-read-buildbot-config: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --jittest-suite=jittest-chunked jsreftest: description: "JS Reftest run" suite: reftest/jsreftest treeherder-symbol: tc-R(J) - chunks: 2 + chunks: + by-test-platform: + win.*: 1 + default: 2 mozharness: script: desktop_unittest.py no-read-buildbot-config: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --reftest-suite=jsreftest marionette: description: "Marionette unittest run" suite: marionette treeherder-symbol: tc(Mn) max-run-time: 5400 mozharness: script: marionette.py no-read-buildbot-config: true config: - - marionette/prod_config.py - - remove_executables.py + by-test-platform: + win.*: + - marionette/windows_taskcluster_config.py + default: + - marionette/prod_config.py + - remove_executables.py mochitest: description: "Mochitest plain run" suite: mochitest/plain-chunked treeherder-symbol: tc-M() loopback-video: true - chunks: 10 + chunks: + by-test-platform: + win.*: 5 + default: 10 max-run-time: 5400 mozharness: script: desktop_unittest.py no-read-buildbot-config: true chunked: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --mochitest-suite=plain-chunked # Bug 1281241: migrating to m3.large instances instance-size: legacy allow-software-gl-layers: false @@ -178,16 +207,18 @@ mochitest-a11y: loopback-video: true e10s: false mozharness: script: desktop_unittest.py no-read-buildbot-config: true chunked: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --mochitest-suite=a11y mochitest-browser-chrome: description: "Mochitest browser-chrome run" @@ -217,16 +248,18 @@ mochitest-browser-chrome: linux64-ccov/opt: 7200 linux64/debug: 5400 default: 3600 mozharness: script: desktop_unittest.py no-read-buildbot-config: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: by-test-platform: linux64-jsdcov/opt: - --mochitest-suite=browser-chrome-coverage linux64-ccov/opt: @@ -249,16 +282,18 @@ mochitest-chrome: loopback-video: true chunks: 3 e10s: false mozharness: script: desktop_unittest.py no-read-buildbot-config: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --mochitest-suite=chrome mochitest-clipboard: description: "Mochitest clipboard run" @@ -267,39 +302,46 @@ mochitest-clipboard: loopback-video: true instance-size: xlarge mozharness: script: desktop_unittest.py no-read-buildbot-config: true chunked: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --mochitest-suite=plain-clipboard,chrome-clipboard,browser-chrome-clipboard,jetpack-package-clipboard mochitest-devtools-chrome: description: "Mochitest devtools-chrome run" suite: mochitest/mochitest-devtools-chrome-chunked treeherder-symbol: tc-M(dt) loopback-video: true max-run-time: 5400 - chunks: 10 + chunks: + by-test-platform: + win.*: 8 + default: 10 e10s: by-test-platform: # Bug 1242986: linux64/debug mochitest-devtools-chrome e10s is not greened up yet linux64/debug: false default: both mozharness: script: desktop_unittest.py no-read-buildbot-config: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --mochitest-suite=mochitest-devtools-chrome-chunked instance-size: by-test-platform: # Bug 1281241: migrating to m3.large instances @@ -308,22 +350,28 @@ mochitest-devtools-chrome: # Bug 1296086: high number of intermittents observed with software GL and large instances allow-software-gl-layers: false mochitest-gpu: description: "Mochitest GPU run" suite: mochitest/plain-gpu,chrome-gpu,browser-chrome-gpu treeherder-symbol: tc-M(gpu) loopback-video: true + e10s: + by-test-platform: + win.*: both + default: true mozharness: script: desktop_unittest.py no-read-buildbot-config: true chunked: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --mochitest-suite=plain-gpu,chrome-gpu,browser-chrome-gpu mochitest-jetpack: description: "Mochitest jetpack run" @@ -333,36 +381,41 @@ mochitest-jetpack: e10s: false max-run-time: 5400 mozharness: script: desktop_unittest.py no-read-buildbot-config: true chunked: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --mochitest-suite=jetpack-package + - --mochitest-suite=jetpack-addon mochitest-media: description: "Mochitest media run" suite: mochitest/mochitest-media treeherder-symbol: tc-M(mda) max-run-time: 5400 loopback-video: true instance-size: large docker-image: {"in-tree": "desktop1604-test"} mozharness: script: desktop_unittest.py no-read-buildbot-config: true chunked: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --mochitest-suite=mochitest-media mochitest-webgl: description: "Mochitest webgl run" @@ -371,16 +424,18 @@ mochitest-webgl: chunks: 3 loopback-video: true mozharness: script: desktop_unittest.py no-read-buildbot-config: true chunked: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --mochitest-suite=mochitest-gl # Bug 1296733: llvmpipe with mesa 9.2.1 lacks thread safety allow-software-gl-layers: false @@ -390,16 +445,18 @@ reftest: treeherder-symbol: tc-R(R) chunks: 8 docker-image: {"in-tree": "desktop1604-test"} mozharness: script: desktop_unittest.py no-read-buildbot-config: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --reftest-suite=reftest reftest-no-accel: description: "Reftest not accelerated run" @@ -407,16 +464,18 @@ reftest-no-accel: treeherder-symbol: tc-R(Ru) chunks: 8 docker-image: {"in-tree": "desktop1604-test"} mozharness: script: desktop_unittest.py no-read-buildbot-config: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --reftest-suite=reftest-no-accel web-platform-tests: description: "Web platform test run" @@ -426,70 +485,85 @@ web-platform-tests: max-run-time: 7200 instance-size: xlarge docker-image: {"in-tree": "desktop1604-test"} checkout: true mozharness: script: web_platform_tests.py no-read-buildbot-config: true config: - - web_platform_tests/prod_config.py - - remove_executables.py + by-test-platform: + win.*: + - web_platform_tests/prod_config_windows_taskcluster.py + default: + - web_platform_tests/prod_config.py + - remove_executables.py extra-options: - --test-type=testharness web-platform-tests-reftests: description: "Web platform reftest run" suite: web-platform-tests-reftests treeherder-symbol: tc-W(Wr) max-run-time: 5400 instance-size: xlarge docker-image: {"in-tree": "desktop1604-test"} checkout: true mozharness: script: web_platform_tests.py no-read-buildbot-config: true config: - - web_platform_tests/prod_config.py - - remove_executables.py + by-test-platform: + win.*: + - web_platform_tests/prod_config_windows_taskcluster.py + default: + - web_platform_tests/prod_config.py + - remove_executables.py extra-options: - --test-type=reftest web-platform-tests-wdspec: description: "Web platform webdriver-spec run" suite: web-platform-tests-wdspec treeherder-symbol: tc-W(Wd) max-run-time: 5400 instance-size: xlarge docker-image: {"in-tree": "desktop1604-test"} checkout: true mozharness: script: web_platform_tests.py no-read-buildbot-config: true config: - - web_platform_tests/prod_config.py - - remove_executables.py + by-test-platform: + win.*: + - web_platform_tests/prod_config_windows_taskcluster.py + default: + - web_platform_tests/prod_config.py + - remove_executables.py extra-options: - --test-type=wdspec xpcshell: description: "xpcshell test run" suite: xpcshell treeherder-symbol: tc-X() chunks: by-test-platform: + # win.*: 1 linux64/debug: 10 default: 8 max-run-time: 5400 e10s: false mozharness: script: desktop_unittest.py no-read-buildbot-config: true config: by-test-platform: + win.*: + - unittests/win_taskcluster_unittest.py default: - unittests/linux_unittest.py - remove_executables.py extra-options: - --xpcshell-suite=xpcshell # Bug 1281241: migrating to m3.large instances instance-size: legacy allow-software-gl-layers: false
--- a/taskcluster/taskgraph/transforms/task.py +++ b/taskcluster/taskgraph/transforms/task.py @@ -200,33 +200,36 @@ task_description_schema = Schema({ # the exit status code that indicates the task should be retried Optional('retry-exit-status'): int, }, { Required('implementation'): 'generic-worker', # command is a list of commands to run, sequentially - 'command': [basestring], + 'command': [taskref_or_string], # artifacts to extract from the task image after completion; note that artifacts # for the generic worker cannot have names Optional('artifacts'): [{ # type of artifact -- simple file, or recursive directory 'type': Any('file', 'directory'), # task image path from which to read artifact 'path': basestring, }], # environment variables Required('env', default={}): {basestring: taskref_or_string}, # the maximum time to run, in seconds 'max-run-time': int, + + # os user groups for test task workers + Optional('os-groups', default=[]): [basestring], }, { Required('implementation'): 'buildbot-bridge', # see # https://github.com/mozilla/buildbot-bridge/blob/master/bbb/schemas/payload.yml 'buildername': basestring, 'sourcestamp': { 'branch': basestring, @@ -395,18 +398,19 @@ def build_generic_worker_payload(config, 'path': artifact['path'], 'type': artifact['type'], 'expires': task_def['expires'], # always expire with the task }) task_def['payload'] = { 'command': worker['command'], 'artifacts': artifacts, - 'env': worker['env'], + 'env': worker.get('env', {}), 'maxRunTime': worker['max-run-time'], + 'osGroups': worker.get('os-groups', []), } if 'retry-exit-status' in worker: raise Exception("retry-exit-status not supported in generic-worker") transforms = TransformSequence()
--- a/taskcluster/taskgraph/transforms/tests/all_kinds.py +++ b/taskcluster/taskgraph/transforms/tests/all_kinds.py @@ -19,18 +19,20 @@ import copy transforms = TransformSequence() @transforms.add def set_worker_implementation(config, tests): """Set the worker implementation based on the test platform.""" for test in tests: - # this is simple for now, but soon will not be! - test['worker-implementation'] = 'docker-worker' + if test['test-platform'].startswith('win'): + test['worker-implementation'] = 'generic-worker' + else: + test['worker-implementation'] = 'docker-worker' yield test @transforms.add def set_tier(config, tests): """Set the tier based on policy for all test descriptions that do not specify a tier otherwise.""" for test in tests:
--- a/taskcluster/taskgraph/transforms/tests/desktop_test.py +++ b/taskcluster/taskgraph/transforms/tests/desktop_test.py @@ -30,21 +30,22 @@ def set_defaults(config, tests): @transforms.add def set_treeherder_machine_platform(config, tests): """Set the appropriate task.extra.treeherder.machine.platform""" # Linux64 build platforms for asan and pgo are specified differently to # treeherder. This is temporary until we can clean up the handling of # platforms translation = { 'linux64-asan/opt': 'linux64/asan', - 'linux64-pgo/opt': 'linux64/pgo', + 'linux64-pgo/opt': 'linux64/pgo' } for test in tests: build_platform = test['build-platform'] - test['treeherder-machine-platform'] = translation.get(build_platform, build_platform) + test_platform = test['test-platform'] + test['treeherder-machine-platform'] = translation.get(build_platform, test_platform) yield test @transforms.add def set_asan_docker_image(config, tests): """Set the appropriate task.extra.treeherder.docker-image""" # Linux64-asan has many leaks with running mochitest-media jobs # on Ubuntu 16.04, please remove this when bug 1289209 is resolved @@ -78,19 +79,33 @@ def split_e10s(config, tests): test['treeherder-symbol'] = join_symbol(group, symbol) test['mozharness'].setdefault('extra-options', []).append('--e10s') yield test @transforms.add def allow_software_gl_layers(config, tests): for test in tests: - allow = get_keyed_by(item=test, field='allow-software-gl-layers', + + # since this value defaults to true, but is not applicable on windows, + # it's overriden for that platform here. + allow = not test['test-platform'].startswith('win') \ + and get_keyed_by(item=test, field='allow-software-gl-layers', item_name=test['test-name']) if allow: assert test['instance-size'] != 'legacy',\ 'Software GL layers on a legacy instance is disallowed (bug 1296086).' # This should be set always once bug 1296086 is resolved. test['mozharness'].setdefault('extra-options', [])\ .append("--allow-software-gl-layers") yield test + + +@transforms.add +def add_os_groups(config, tests): + for test in tests: + if test['test-platform'].startswith('win'): + groups = get_keyed_by(item=test, field='os-groups', item_name=test['test-name']) + if groups: + test['os-groups'] = groups + yield test
--- a/taskcluster/taskgraph/transforms/tests/make_task_description.py +++ b/taskcluster/taskgraph/transforms/tests/make_task_description.py @@ -22,23 +22,28 @@ from __future__ import absolute_import, from taskgraph.transforms.base import TransformSequence from taskgraph.transforms.job.common import ( docker_worker_support_vcs_checkout, ) import logging ARTIFACT_URL = 'https://queue.taskcluster.net/v1/task/{}/artifacts/{}' - -ARTIFACTS = [ - # (artifact name prefix, in-image path) - ("public/logs/", "/home/worker/workspace/build/upload/logs/"), - ("public/test", "/home/worker/artifacts/"), - ("public/test_info/", "/home/worker/workspace/build/blobber_upload_dir/"), -] +WORKER_TYPE = { + # default worker types keyed by instance-size + 'large': 'aws-provisioner-v1/desktop-test-large', + 'xlarge': 'aws-provisioner-v1/desktop-test-xlarge', + 'legacy': 'aws-provisioner-v1/desktop-test', + 'default': 'aws-provisioner-v1/desktop-test-large', + # windows worker types keyed by test-platform + 'windows7-32-vm': 'aws-provisioner-v1/gecko-t-win7-32', + 'windows7-32': 'aws-provisioner-v1/gecko-t-win7-32-gpu', + 'windows10-64-vm': 'aws-provisioner-v1/gecko-t-win10-64', + 'windows10-64': 'aws-provisioner-v1/gecko-t-win10-64-gpu' +} logger = logging.getLogger(__name__) transforms = TransformSequence() @transforms.add def make_task_description(config, tests): @@ -117,47 +122,49 @@ def worker_setup_function(name): worker_setup_functions[name] = func return func return wrap @worker_setup_function("docker-engine") @worker_setup_function("docker-worker") def docker_worker_setup(config, test, taskdesc): + + artifacts = [ + # (artifact name prefix, in-image path) + ("public/logs/", "/home/worker/workspace/build/upload/logs/"), + ("public/test", "/home/worker/artifacts/"), + ("public/test_info/", "/home/worker/workspace/build/blobber_upload_dir/"), + ] mozharness = test['mozharness'] installer_url = ARTIFACT_URL.format('<build>', mozharness['build-artifact-name']) test_packages_url = ARTIFACT_URL.format('<build>', 'public/build/target.test_packages.json') mozharness_url = ARTIFACT_URL.format('<build>', 'public/build/mozharness.zip') - taskdesc['worker-type'] = { - 'default': 'aws-provisioner-v1/desktop-test-large', - 'large': 'aws-provisioner-v1/desktop-test-large', - 'xlarge': 'aws-provisioner-v1/desktop-test-xlarge', - 'legacy': 'aws-provisioner-v1/desktop-test', - }[test['instance-size']] + taskdesc['worker-type'] = WORKER_TYPE[test['instance-size']] worker = taskdesc['worker'] = {} worker['implementation'] = test['worker-implementation'] worker['docker-image'] = test['docker-image'] worker['allow-ptrace'] = True # required for all tests, for crashreporter worker['relengapi-proxy'] = False # but maybe enabled for tooltool below worker['loopback-video'] = test['loopback-video'] worker['loopback-audio'] = test['loopback-audio'] worker['max-run-time'] = test['max-run-time'] worker['retry-exit-status'] = test['retry-exit-status'] worker['artifacts'] = [{ 'name': prefix, 'path': path, 'type': 'directory', - } for (prefix, path) in ARTIFACTS] + } for (prefix, path) in artifacts] worker['caches'] = [{ 'type': 'persistent', 'name': 'level-{}-{}-test-workspace'.format( config.params['level'], config.params['project']), 'mount-point': "/home/worker/workspace", }] @@ -237,8 +244,116 @@ def docker_worker_setup(config, test, ta command[i] += suffix if 'download-symbols' in mozharness: download_symbols = mozharness['download-symbols'] download_symbols = {True: 'true', False: 'false'}.get(download_symbols, download_symbols) command.append('--download-symbols=' + download_symbols) worker['command'] = command + + +def normpath(path): + return path.replace('/', '\\') + + +def get_firefox_version(): + with open('browser/config/version.txt', 'r') as f: + return f.readline().strip() + + +@worker_setup_function('generic-worker') +def generic_worker_setup(config, test, taskdesc): + artifacts = [ + { + 'path': 'public\\logs\\localconfig.json', + 'type': 'file' + }, + { + 'path': 'public\\logs\\log_critical.log', + 'type': 'file' + }, + { + 'path': 'public\\logs\\log_error.log', + 'type': 'file' + }, + { + 'path': 'public\\logs\\log_fatal.log', + 'type': 'file' + }, + { + 'path': 'public\\logs\\log_info.log', + 'type': 'file' + }, + { + 'path': 'public\\logs\\log_raw.log', + 'type': 'file' + }, + { + 'path': 'public\\logs\\log_warning.log', + 'type': 'file' + }, + { + 'path': 'public\\test_info', + 'type': 'directory' + } + ] + mozharness = test['mozharness'] + + build_platform = taskdesc['attributes']['build_platform'] + test_platform = test['test-platform'].split('/')[0] + + target = 'firefox-{}.en-US.{}'.format(get_firefox_version(), build_platform) + + installer_url = ARTIFACT_URL.format( + '<build>', 'public/build/{}.zip'.format(target)) + test_packages_url = ARTIFACT_URL.format( + '<build>', 'public/build/{}.test_packages.json'.format(target)) + mozharness_url = ARTIFACT_URL.format( + '<build>', 'public/build/mozharness.zip') + + taskdesc['worker-type'] = WORKER_TYPE[test_platform] + + taskdesc['scopes'].extend( + ['generic-worker:os-group:{}'.format(group) for group in test['os-groups']]) + + worker = taskdesc['worker'] = {} + worker['os-groups'] = test['os-groups'] + worker['implementation'] = test['worker-implementation'] + worker['max-run-time'] = test['max-run-time'] + worker['artifacts'] = artifacts + + env = worker['env'] = { + # Bug 1306989 + 'APPDATA': '%cd%\\AppData\\Roaming', + 'LOCALAPPDATA': '%cd%\\AppData\\Local', + 'TEMP': '%cd%\\AppData\\Local\\Temp', + 'TMP': '%cd%\\AppData\\Local\\Temp', + 'USERPROFILE': '%cd%', + } + + # assemble the command line + mh_command = [ + 'c:\\mozilla-build\\python\\python.exe', + '-u', + 'mozharness\\scripts\\' + normpath(mozharness['script']) + ] + for mh_config in mozharness['config']: + mh_command.extend(['--cfg', 'mozharness\\configs\\' + normpath(mh_config)]) + mh_command.extend(mozharness.get('extra-options', [])) + if mozharness.get('no-read-buildbot-config'): + mh_command.append('--no-read-buildbot-config') + mh_command.extend(['--installer-url', installer_url]) + mh_command.extend(['--test-packages-url', test_packages_url]) + if mozharness.get('download-symbols'): + if isinstance(mozharness['download-symbols'], basestring): + mh_command.extend(['--download-symbols', mozharness['download-symbols']]) + else: + mh_command.extend(['--download-symbols', 'true']) + + worker['command'] = [ + 'mkdir {} {}'.format(env['APPDATA'], env['TMP']), + {'task-reference': 'c:\\mozilla-build\\wget\\wget.exe {}'.format(mozharness_url)}, + 'c:\\mozilla-build\\info-zip\\unzip.exe mozharness.zip', + {'task-reference': ' '.join(mh_command)}, + 'xcopy build\\blobber_upload_dir public\\test_info /e /i', + 'copy /y logs\\*.* public\\logs\\' + ]
--- a/taskcluster/taskgraph/transforms/tests/test_description.py +++ b/taskcluster/taskgraph/transforms/tests/test_description.py @@ -101,18 +101,18 @@ test_description_schema = Schema({ # using the GL compositor. May not be used with "legacy" sized instances # due to poor LLVMPipe performance (bug 1296086). Optional('allow-software-gl-layers', default=True): bool, # The worker implementation for this test, as dictated by policy and by the # test platform. Optional('worker-implementation'): Any( 'docker-worker', + 'generic-worker', # coming soon: - 'generic-worker', 'docker-engine', 'buildbot-bridge', ), # For tasks that will run in docker-worker or docker-engine, this is the # name of the docker image or in-tree docker image to run the task in. If # in-tree, then a dependency will be created automatically. This is # generally `desktop-test`, or an image that acts an awful lot like it. @@ -194,16 +194,24 @@ test_description_schema = Schema({ # chunking-args = test-suite-suffix; "<CHUNK>" in this string will # be replaced with the chunk number. Optional('chunk-suffix'): basestring, }), # The current chunk; this is filled in by `all_kinds.py` Optional('this-chunk'): int, + # os user groups for test task workers; required scopes, will be + # added automatically + Optional('os-groups', default=[]): Any( + [basestring], + # todo: create a dedicated elevated worker group and name here + {'by-test-platform': {basestring: [basestring]}}, + ), + # -- values supplied by the task-generation infrastructure # the platform of the build this task is testing 'build-platform': basestring, # the label of the build task generating the materials to test 'build-label': basestring,
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/marionette/windows_taskcluster_config.py @@ -0,0 +1,122 @@ +# This is a template config file for marionette production on Windows. +import os +import sys + +config = { + # marionette options + "marionette_address": "localhost:2828", + "test_manifest": "unit-tests.ini", + + "virtualenv_python_dll": os.path.join(os.path.dirname(sys.executable), 'python27.dll'), + "virtualenv_path": 'venv', + "exes": { + 'python': sys.executable, + 'virtualenv': [ + sys.executable, + os.path.join(os.path.dirname(sys.executable), 'Lib', 'site-packages', 'virtualenv.py') + ], + 'mozinstall': ['build/venv/scripts/python', 'build/venv/scripts/mozinstall-script.py'], + 'tooltool.py': [sys.executable, os.path.join(os.environ['MOZILLABUILD'], 'tooltool.py')], + 'hg': os.path.join(os.environ['PROGRAMFILES'], 'Mercurial', 'hg') + }, + + "find_links": [ + "http://pypi.pvt.build.mozilla.org/pub", + "http://pypi.pub.build.mozilla.org/pub", + ], + "pip_index": False, + + "default_actions": [ + 'clobber', + 'download-and-extract', + 'create-virtualenv', + 'install', + 'run-tests', + ], + "default_blob_upload_servers": [ + "https://blobupload.elasticbeanstalk.com", + ], + "blob_uploader_auth_file" : 'C:/builds/oauth.txt', + "download_minidump_stackwalk": True, + "download_symbols": "ondemand", + "suite_definitions": { + "gaiatest_desktop": { + "options": [ + "--restart", + "--timeout=%(timeout)s", + "--testvars=%(testvars)s", + "--profile=%(profile)s", + "--symbols-path=%(symbols_path)s", + "--gecko-log=%(gecko_log)s", + "--log-xunit=%(xml_output)s", + "--html-output=%(html_output)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--binary=%(binary)s", + "--address=%(address)s", + "--total-chunks=%(total_chunks)s", + "--this-chunk=%(this_chunk)s" + ], + "run_filename": "", + "testsdir": "" + }, + "gaiatest_emulator": { + "options": [ + "--restart", + "--timeout=%(timeout)s", + "--testvars=%(testvars)s", + "--profile=%(profile)s", + "--symbols-path=%(symbols_path)s", + "--log-xunit=%(xml_output)s", + "--html-output=%(html_output)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s" + ], + "run_filename": "", + "testsdir": "" + }, + "marionette_desktop": { + "options": [ + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--binary=%(binary)s", + "--address=%(address)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "", + "testsdir": "" + }, + "marionette_emulator": { + "options": [ + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "", + "testsdir": "" + }, + "webapi_desktop": { + "options": [], + "run_filename": "", + "testsdir": "" + }, + "webapi_emulator": { + "options": [ + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--symbols-path=%(symbols_path)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s" + ], + "run_filename": "", + "testsdir": "" + } + }, +}
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/mediatests/taskcluster_windows_config.py @@ -0,0 +1,54 @@ +import os +import sys +import mozharness + +external_tools_path = os.path.join( + os.path.abspath(os.path.dirname(os.path.dirname(mozharness.__file__))), + 'external_tools', +) + +config = { + "virtualenv_python_dll": os.path.join(os.path.dirname(sys.executable), 'python27.dll'), + "virtualenv_path": 'venv', + "exes": { + 'python': sys.executable, + 'virtualenv': [ + sys.executable, + os.path.join(os.path.dirname(sys.executable), 'Lib', 'site-packages', 'virtualenv.py') + ], + 'mozinstall': ['build/venv/scripts/python', 'build/venv/scripts/mozinstall-script.py'], + 'tooltool.py': [sys.executable, os.path.join(os.environ['MOZILLABUILD'], 'tooltool.py')], + 'hg': os.path.join(os.environ['PROGRAMFILES'], 'Mercurial', 'hg') + }, + "find_links": [ + "http://pypi.pvt.build.mozilla.org/pub", + "http://pypi.pub.build.mozilla.org/pub", + ], + "pip_index": False, + + "default_actions": [ + 'clobber', + 'download-and-extract', + 'create-virtualenv', + 'install', + 'run-media-tests', + ], + "default_blob_upload_servers": [ + "https://blobupload.elasticbeanstalk.com", + ], + "blob_uploader_auth_file" : 'C:/builds/oauth.txt', + "in_tree_config": "config/mozharness/marionette.py", + "download_minidump_stackwalk": True, + "download_symbols": "ondemand", + + "suite_definitions": { + "media-tests": { + "options": [], + }, + "media-youtube-tests": { + "options": [ + "%(test_manifest)s" + ], + }, + }, +}
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/unittests/win_taskcluster_unittest.py @@ -0,0 +1,282 @@ +import os +import sys + +# OS Specifics +ABS_WORK_DIR = os.path.join(os.getcwd(), "build") +BINARY_PATH = os.path.join(ABS_WORK_DIR, "firefox", "firefox.exe") +INSTALLER_PATH = os.path.join(ABS_WORK_DIR, "installer.zip") +XPCSHELL_NAME = 'xpcshell.exe' +EXE_SUFFIX = '.exe' +DISABLE_SCREEN_SAVER = False +ADJUST_MOUSE_AND_SCREEN = True +##### +config = { + "exes": { + 'python': sys.executable, + 'virtualenv': [ + sys.executable, + os.path.join(os.path.dirname(sys.executable), 'Lib', 'site-packages', 'virtualenv.py') + ], + 'mozinstall': ['build/venv/scripts/python', 'build/venv/scripts/mozinstall-script.py'], + 'tooltool.py': [sys.executable, os.path.join(os.environ['MOZILLABUILD'], 'tooltool.py')], + 'hg': os.path.join(os.environ['PROGRAMFILES'], 'Mercurial', 'hg') + }, + ### + "installer_path": INSTALLER_PATH, + "binary_path": BINARY_PATH, + "xpcshell_name": XPCSHELL_NAME, + "virtualenv_path": 'venv', + "virtualenv_python_dll": os.path.join(os.path.dirname(sys.executable), "python27.dll"), + + "find_links": [ + "http://pypi.pvt.build.mozilla.org/pub", + "http://pypi.pub.build.mozilla.org/pub", + ], + "pip_index": False, + "exe_suffix": EXE_SUFFIX, + "run_file_names": { + "mochitest": "runtests.py", + "reftest": "runreftest.py", + "xpcshell": "runxpcshelltests.py", + "cppunittest": "runcppunittests.py", + "gtest": "rungtests.py", + "jittest": "jit_test.py", + "mozbase": "test.py", + "mozmill": "runtestlist.py", + }, + "minimum_tests_zip_dirs": [ + "bin/*", + "certs/*", + "config/*", + "mach", + "marionette/*", + "modules/*", + "mozbase/*", + "tools/*", + ], + "specific_tests_zip_dirs": { + "mochitest": ["mochitest/*"], + "reftest": ["reftest/*", "jsreftest/*"], + "xpcshell": ["xpcshell/*"], + "cppunittest": ["cppunittest/*"], + "gtest": ["gtest/*"], + "jittest": ["jit-test/*"], + "mozbase": ["mozbase/*"], + "mozmill": ["mozmill/*"], + }, + "suite_definitions": { + "cppunittest": { + "options": [ + "--symbols-path=%(symbols_path)s", + "--xre-path=%(abs_app_dir)s" + ], + "run_filename": "runcppunittests.py", + "testsdir": "cppunittest" + }, + "jittest": { + "options": [ + "tests/bin/js", + "--no-slow", + "--no-progress", + "--format=automation", + "--jitflags=all", + "--timeout=970" # Keep in sync with run_timeout below. + ], + "run_filename": "jit_test.py", + "testsdir": "jit-test/jit-test", + "run_timeout": 1000 # Keep in sync with --timeout above. + }, + "mochitest": { + "options": [ + "--appname=%(binary_path)s", + "--utility-path=tests/bin", + "--extra-profile-file=tests/bin/plugins", + "--symbols-path=%(symbols_path)s", + "--certificate-path=tests/certs", + "--quiet", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--screenshot-on-fail", + "--cleanup-crashes", + ], + "run_filename": "runtests.py", + "testsdir": "mochitest" + }, + "mozbase": { + "options": [ + "-b", + "%(binary_path)s" + ], + "run_filename": "test.py", + "testsdir": "mozbase" + }, + "mozmill": { + "options": [ + "--binary=%(binary_path)s", + "--testing-modules-dir=test/modules", + "--plugins-path=%(test_plugin_path)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "runtestlist.py", + "testsdir": "mozmill" + }, + "reftest": { + "options": [ + "--appname=%(binary_path)s", + "--utility-path=tests/bin", + "--extra-profile-file=tests/bin/plugins", + "--symbols-path=%(symbols_path)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--cleanup-crashes", + ], + "run_filename": "runreftest.py", + "testsdir": "reftest" + }, + "xpcshell": { + "options": [ + "--symbols-path=%(symbols_path)s", + "--test-plugin-path=%(test_plugin_path)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--utility-path=tests/bin", + ], + "run_filename": "runxpcshelltests.py", + "testsdir": "xpcshell" + }, + "gtest": { + "options": [ + "--xre-path=%(abs_res_dir)s", + "--cwd=%(gtest_dir)s", + "--symbols-path=%(symbols_path)s", + "--utility-path=tests/bin", + "%(binary_path)s", + ], + "run_filename": "rungtests.py", + }, + }, + # local mochi suites + "all_mochitest_suites": + { + "plain": [], + "plain-gpu": ["--subsuite=gpu"], + "plain-clipboard": ["--subsuite=clipboard"], + "plain-chunked": ["--chunk-by-dir=4"], + "mochitest-media": ["--subsuite=media"], + "chrome": ["--flavor=chrome"], + "chrome-gpu": ["--flavor=chrome", "--subsuite=gpu"], + "chrome-clipboard": ["--flavor=chrome", "--subsuite=clipboard"], + "chrome-chunked": ["--flavor=chrome", "--chunk-by-dir=4"], + "browser-chrome": ["--flavor=browser"], + "browser-chrome-gpu": ["--flavor=browser", "--subsuite=gpu"], + "browser-chrome-clipboard": ["--flavor=browser", "--subsuite=clipboard"], + "browser-chrome-chunked": ["--flavor=browser", "--chunk-by-runtime"], + "browser-chrome-addons": ["--flavor=browser", "--chunk-by-runtime", "--tag=addons"], + "browser-chrome-screenshots": ["--flavor=browser", "--subsuite=screenshots"], + "mochitest-gl": ["--subsuite=webgl"], + "mochitest-devtools-chrome": ["--flavor=browser", "--subsuite=devtools"], + "mochitest-devtools-chrome-chunked": ["--flavor=browser", "--subsuite=devtools", "--chunk-by-runtime"], + "mochitest-metro-chrome": ["--flavor=browser", "--metro-immersive"], + "jetpack-package": ["--flavor=jetpack-package"], + "jetpack-package-clipboard": ["--flavor=jetpack-package", "--subsuite=clipboard"], + "jetpack-addon": ["--flavor=jetpack-addon"], + "a11y": ["--flavor=a11y"], + }, + # local reftest suites + "all_reftest_suites": { + "reftest": { + 'options': ["--suite=reftest"], + 'tests': ["tests/reftest/tests/layout/reftests/reftest.list"] + }, + "crashtest": { + 'options': ["--suite=crashtest"], + 'tests': ["tests/reftest/tests/testing/crashtest/crashtests.list"] + }, + "jsreftest": { + 'options':["--extra-profile-file=tests/jsreftest/tests/user.js"], + 'tests': ["tests/jsreftest/tests/jstests.list"] + }, + "reftest-ipc": { + 'options': ['--suite=reftest', + '--setpref=browser.tabs.remote=true', + '--setpref=browser.tabs.remote.autostart=true', + '--setpref=extensions.e10sBlocksEnabling=false', + '--setpref=layers.async-pan-zoom.enabled=true'], + 'tests': ['tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list'] + }, + "reftest-no-accel": { + "options": ["--suite=reftest", + "--setpref=gfx.direct2d.disabled=true", + "--setpref=layers.acceleration.disabled=true"], + "tests": ["tests/reftest/tests/layout/reftests/reftest.list"] + }, + "crashtest-ipc": { + "options": ["--suite=crashtest", + '--setpref=browser.tabs.remote=true', + '--setpref=browser.tabs.remote.autostart=true', + '--setpref=extensions.e10sBlocksEnabling=false', + '--setpref=layers.async-pan-zoom.enabled=true'], + "tests": ['tests/reftest/tests/testing/crashtest/crashtests.list'], + }, + }, + "all_xpcshell_suites": { + "xpcshell": { + 'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, + "--manifest=tests/xpcshell/tests/xpcshell.ini"], + 'tests': [] + }, + "xpcshell-addons": { + 'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, + "--tag=addons", + "--manifest=tests/xpcshell/tests/xpcshell.ini"], + 'tests': [] + }, + }, + "all_cppunittest_suites": { + "cppunittest": ['tests/cppunittest'] + }, + "all_gtest_suites": { + "gtest": [] + }, + "all_jittest_suites": { + "jittest": [] + }, + "all_mozbase_suites": { + "mozbase": [] + }, + "run_cmd_checks_enabled": True, + "preflight_run_cmd_suites": [ + { + 'name': 'disable_screen_saver', + 'cmd': ['xset', 's', 'off', 's', 'reset'], + 'architectures': ['32bit', '64bit'], + 'halt_on_failure': False, + 'enabled': DISABLE_SCREEN_SAVER + }, + { + 'name': 'run mouse & screen adjustment script', + 'cmd': [ + sys.executable, + os.path.join(os.getcwd(), + 'mozharness', 'external_tools', 'mouse_and_screen_resolution.py'), + '--configuration-file', + os.path.join(os.getcwd(), + 'mozharness', 'external_tools', 'machine-configuration.json') + ], + 'architectures': ['32bit'], + 'halt_on_failure': True, + 'enabled': ADJUST_MOUSE_AND_SCREEN + } + ], + "vcs_output_timeout": 1000, + "minidump_save_path": "%(abs_work_dir)s/../minidumps", + "buildbot_max_log_size": 52428800, + "default_blob_upload_servers": [ + "https://blobupload.elasticbeanstalk.com", + ], + "structured_suites": ["reftest"], + 'blob_uploader_auth_file': 'C:/builds/oauth.txt', + "download_minidump_stackwalk": True, + "minidump_stackwalk_path": "win32-minidump_stackwalk.exe", + "minidump_tooltool_manifest_path": "config/tooltool-manifests/win32/releng.manifest" +}
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/web_platform_tests/prod_config_windows_taskcluster.py @@ -0,0 +1,48 @@ +# ***** BEGIN LICENSE BLOCK ***** +# 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/. +# ***** END LICENSE BLOCK ***** + +# This is a template config file for web-platform-tests test. + +import os +import sys + +config = { + "options": [ + "--prefs-root=%(test_path)s/prefs", + "--processes=1", + "--config=%(test_path)s/wptrunner.ini", + "--ca-cert-path=%(test_path)s/certs/cacert.pem", + "--host-key-path=%(test_path)s/certs/web-platform.test.key", + "--host-cert-path=%(test_path)s/certs/web-platform.test.pem", + "--certutil-binary=%(test_install_path)s/bin/certutil", + ], + + "exes": { + 'python': sys.executable, + 'virtualenv': [ + sys.executable, + os.path.join(os.path.dirname(sys.executable), 'Lib', 'site-packages', 'virtualenv.py') + ], + 'mozinstall': ['build/venv/scripts/python', 'build/venv/scripts/mozinstall-script.py'], + 'tooltool.py': [sys.executable, os.path.join(os.environ['MOZILLABUILD'], 'tooltool.py')], + 'hg': os.path.join(os.environ['PROGRAMFILES'], 'Mercurial', 'hg') + }, + + "find_links": [ + "http://pypi.pvt.build.mozilla.org/pub", + "http://pypi.pub.build.mozilla.org/pub", + ], + + "pip_index": False, + + "default_blob_upload_servers": [ + "https://blobupload.elasticbeanstalk.com", + ], + + "blob_uploader_auth_file" : 'C:/builds/oauth.txt', + + "download_minidump_stackwalk": True, +}
--- a/toolkit/components/extensions/ExtensionContent.jsm +++ b/toolkit/components/extensions/ExtensionContent.jsm @@ -90,16 +90,17 @@ var apiManager = new class extends Schem // Represents a content script. function Script(extension, options, deferred = PromiseUtils.defer()) { this.extension = extension; this.options = options; this.run_at = this.options.run_at; this.js = this.options.js || []; this.css = this.options.css || []; this.remove_css = this.options.remove_css; + this.match_about_blank = this.options.match_about_blank; this.deferred = deferred; this.matches_ = new MatchPattern(this.options.matches); this.exclude_matches_ = new MatchPattern(this.options.exclude_matches || null); // TODO: MatchPattern should pre-mangle host-only patterns so that we // don't need to call a separate match function. this.matches_host_ = new MatchPattern(this.options.matchesHost || null); @@ -129,16 +130,22 @@ Script.prototype = { let uri = window.document.documentURIObject; // If mozAddonManager is present on this page, don't allow // content scripts. if (window.navigator.mozAddonManager !== undefined) { return false; } + if (this.match_about_blank && ["about:blank", "about:srcdoc"].includes(uri.spec)) { + // When matching about:blank/srcdoc documents, the checks below + // need to be performed against the "owner" document's URI. + uri = window.document.nodePrincipal.URI; + } + if (!(this.matches_.matches(uri) || this.matches_host_.matchesIgnoringPath(uri))) { return false; } if (this.exclude_matches_.matches(uri)) { return false; } @@ -155,18 +162,16 @@ Script.prototype = { if (this.options.frame_id != null) { if (WebNavigationFrames.getFrameId(window) != this.options.frame_id) { return false; } } else if (!this.options.all_frames && window.top != window) { return false; } - // TODO: match_about_blank. - return true; }, cleanup(window) { if (!this.remove_css) { let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils); @@ -411,44 +416,60 @@ DocumentManager = { // Map[windowId -> Map[extensionId -> ExtensionContext]] contentScriptWindows: new Map(), // Map[windowId -> ExtensionContext] extensionPageWindows: new Map(), init() { + Services.obs.addObserver(this, "content-document-global-created", false); Services.obs.addObserver(this, "document-element-inserted", false); Services.obs.addObserver(this, "inner-window-destroyed", false); }, uninit() { + Services.obs.removeObserver(this, "content-document-global-created"); Services.obs.removeObserver(this, "document-element-inserted"); Services.obs.removeObserver(this, "inner-window-destroyed"); }, getWindowState(contentWindow) { let readyState = contentWindow.document.readyState; if (readyState == "complete") { return "document_idle"; } if (readyState == "interactive") { return "document_end"; } return "document_start"; }, observe: function(subject, topic, data) { - if (topic == "document-element-inserted") { + // For some types of documents (about:blank), we only see the first + // notification, for others (data: URIs) we only observe the second. + if (topic == "content-document-global-created" || topic == "document-element-inserted") { let document = subject; let window = document && document.defaultView; + + if (topic == "content-document-global-created") { + window = subject; + document = window && window.document; + } + if (!document || !document.location || !window) { return; } + // Make sure we always load exactly once (notice != used as logical XOR), + // usually on document-element-inserted, except for about:blank documents. + if ((topic == "content-document-global-created") != (window.location.href == "about:blank")) { + return; + } + // Make sure we only load into frames that ExtensionContent.init // was called on (i.e., not frames for social or sidebars). let mm = getWindowMessageManager(window); if (!mm || !ExtensionContent.globals.has(mm)) { return; } // Enable the content script APIs should be available in subframes' window @@ -458,17 +479,18 @@ DocumentManager = { if (ExtensionManagement.getAPILevelForWindow(window, extensionId) == CONTENTSCRIPT_PRIVILEGES) { let extension = ExtensionManager.get(extensionId); if (extension) { DocumentManager.getExtensionPageContext(extension, window); } } - this.trigger("document_start", window); + this.trigger(window); + /* eslint-disable mozilla/balanced-listeners */ window.addEventListener("DOMContentLoaded", this, true); window.addEventListener("load", this, true); /* eslint-enable mozilla/balanced-listeners */ } else if (topic == "inner-window-destroyed") { let windowId = subject.QueryInterface(Ci.nsISupportsPRUint64).data; MessageChannel.abortResponses({innerWindowID: windowId}); @@ -500,19 +522,19 @@ DocumentManager = { // listening on. return; } window.removeEventListener(event.type, this, true); // Need to check if we're still on the right page? Greasemonkey does this. if (event.type == "DOMContentLoaded") { - this.trigger("document_end", window); + this.trigger(window); } else if (event.type == "load") { - this.trigger("document_idle", window); + this.trigger(window); } }, // Used to executeScript, insertCSS and removeCSS. executeScript(global, extensionId, options) { let extension = ExtensionManager.get(extensionId); let executeInWin = (window) => { @@ -638,17 +660,17 @@ DocumentManager = { MessageChannel.abortResponses({extensionId}); this.extensionCount--; if (this.extensionCount == 0) { this.uninit(); } }, - trigger(when, window) { + trigger(window) { let state = this.getWindowState(window); if (state == "document_start") { for (let extension of ExtensionManager.extensions.values()) { for (let script of extension.scripts) { if (script.matches(window)) { let context = this.getContentScriptContext(extension, window); context.addScript(script);
new file mode 100644 --- /dev/null +++ b/toolkit/components/extensions/test/mochitest/file_with_about_blank.html @@ -0,0 +1,10 @@ +<!doctype html> +<html> +<head> + <meta charset="utf-8"> +</head> +<body> + <iframe id="a_b" src="about:blank"></iframe> + <iframe srcdoc="galactica actual" src="adama"></iframe> +</body> +</html>
--- a/toolkit/components/extensions/test/mochitest/mochitest.ini +++ b/toolkit/components/extensions/test/mochitest/mochitest.ini @@ -13,16 +13,17 @@ support-files = file_webNavigation_frameClientRedirect.html file_webNavigation_frameRedirect.html file_webNavigation_manualSubframe.html file_webNavigation_manualSubframe_page1.html file_webNavigation_manualSubframe_page2.html file_WebNavigation_page1.html file_WebNavigation_page2.html file_WebNavigation_page3.html + file_with_about_blank.html file_image_good.png file_image_bad.png file_image_redirect.png file_style_good.css file_style_bad.css file_style_redirect.css file_script_good.js file_script_bad.js @@ -45,16 +46,17 @@ skip-if = os == 'android' # Android does [test_ext_content_security_policy.html] [test_ext_contentscript.html] [test_ext_contentscript_api_injection.html] [test_ext_contentscript_context.html] [test_ext_contentscript_create_iframe.html] [test_ext_contentscript_devtools_metadata.html] [test_ext_contentscript_exporthelpers.html] [test_ext_contentscript_css.html] +[test_ext_contentscript_about_blank.html] [test_ext_contentscript_teardown.html] skip-if = (os == 'android') # Android does not support tabs API. Bug 1260250 [test_ext_exclude_include_globs.html] [test_ext_i18n_css.html] [test_ext_generate.html] [test_ext_notifications.html] [test_ext_permission_xhr.html] [test_ext_runtime_connect.html]
new file mode 100644 --- /dev/null +++ b/toolkit/components/extensions/test/mochitest/test_ext_contentscript_about_blank.html @@ -0,0 +1,117 @@ +<!doctype html> +<html> +<head> + <title>Test content script match_about_blank option</title> + <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> + +<script type="text/javascript"> +"use strict"; + +add_task(function* test_contentscript_about_blank() { + const manifest = { + content_scripts: [ + { + match_about_blank: true, + matches: ["http://mochi.test/*/file_with_about_blank.html", "http://example.com/*"], + all_frames: true, + css: ["all.css"], + js: ["all.js"], + }, { + matches: ["http://mochi.test/*/file_with_about_blank.html"], + css: ["mochi_without.css"], + js: ["mochi_without.js"], + all_frames: true, + }, { + match_about_blank: true, + matches: ["http://mochi.test/*/file_with_about_blank.html"], + css: ["mochi_with.css"], + js: ["mochi_with.js"], + all_frames: true, + }, + ], + }; + + const files = { + "all.js": function() { + browser.runtime.sendMessage("all"); + }, + "all.css": ` + body { color: red; } + `, + "mochi_without.js": function() { + browser.runtime.sendMessage("mochi_without"); + }, + "mochi_without.css": ` + body { background: yellow; } + `, + "mochi_with.js": function() { + browser.runtime.sendMessage("mochi_with"); + }, + "mochi_with.css": ` + body { text-align: right; } + `, + }; + + function background() { + browser.runtime.onMessage.addListener((script, {url}) => { + const kind = url.startsWith("about:") ? url : "top"; + browser.test.sendMessage("script", [script, kind, url]); + browser.test.sendMessage(`${script}:${kind}`); + }); + } + + const PATH = "tests/toolkit/components/extensions/test/mochitest/file_with_about_blank.html"; + const extension = ExtensionTestUtils.loadExtension({manifest, files, background}); + yield extension.startup(); + + let count = 0; + extension.onMessage("script", script => { + info(`script ran: ${script}`); + count++; + }); + + let win = window.open("http://example.com/" + PATH); + yield Promise.all([ + extension.awaitMessage("all:top"), + extension.awaitMessage("all:about:blank"), + extension.awaitMessage("all:about:srcdoc"), + ]); + is(count, 3, "exactly 3 scripts ran"); + win.close(); + + win = window.open("http://mochi.test:8888/" + PATH); + yield Promise.all([ + extension.awaitMessage("all:top"), + extension.awaitMessage("all:about:blank"), + extension.awaitMessage("all:about:srcdoc"), + extension.awaitMessage("mochi_without:top"), + extension.awaitMessage("mochi_with:top"), + extension.awaitMessage("mochi_with:about:blank"), + extension.awaitMessage("mochi_with:about:srcdoc"), + ]); + + let style = win.getComputedStyle(win.document.body); + is(style.color, "rgb(255, 0, 0)", "top window text color is red"); + is(style.backgroundColor, "rgb(255, 255, 0)", "top window background is yellow"); + is(style.textAlign, "right", "top window text is right-aligned"); + + let a_b = win.document.getElementById("a_b"); + style = a_b.contentWindow.getComputedStyle(a_b.contentDocument.body); + is(style.color, "rgb(255, 0, 0)", "about:blank iframe text color is red"); + is(style.backgroundColor, "transparent", "about:blank iframe background is transparent"); + is(style.textAlign, "right", "about:blank text is right-aligned"); + + is(count, 10, "exactly 7 more scripts ran"); + win.close(); + + yield extension.unload(); +}); +</script> + +</body> +</html>
--- a/toolkit/components/url-classifier/ProtocolParser.cpp +++ b/toolkit/components/url-classifier/ProtocolParser.cpp @@ -64,16 +64,17 @@ ParseChunkRange(nsACString::const_iterat return false; } /////////////////////////////////////////////////////////////// // ProtocolParser implementation ProtocolParser::ProtocolParser() : mUpdateStatus(NS_OK) + , mUpdateWaitSec(0) { } ProtocolParser::~ProtocolParser() { CleanupUpdates(); } @@ -111,17 +112,16 @@ ProtocolParser::GetTableUpdate(const nsA return update; } /////////////////////////////////////////////////////////////////////// // ProtocolParserV2 ProtocolParserV2::ProtocolParserV2() : mState(PROTOCOL_STATE_CONTROL) - , mUpdateWait(0) , mResetRequested(false) , mTableUpdate(nullptr) { } ProtocolParserV2::~ProtocolParserV2() { } @@ -175,18 +175,18 @@ ProtocolParserV2::ProcessControl(bool* a *aDone = true; while (NextLine(line)) { PARSER_LOG(("Processing %s\n", line.get())); if (StringBeginsWith(line, NS_LITERAL_CSTRING("i:"))) { // Set the table name from the table header line. SetCurrentTable(Substring(line, 2)); } else if (StringBeginsWith(line, NS_LITERAL_CSTRING("n:"))) { - if (PR_sscanf(line.get(), "n:%d", &mUpdateWait) != 1) { - PARSER_LOG(("Error parsing n: '%s' (%d)", line.get(), mUpdateWait)); + if (PR_sscanf(line.get(), "n:%d", &mUpdateWaitSec) != 1) { + PARSER_LOG(("Error parsing n: '%s' (%d)", line.get(), mUpdateWaitSec)); return NS_ERROR_FAILURE; } } else if (line.EqualsLiteral("r:pleasereset")) { mResetRequested = true; } else if (StringBeginsWith(line, NS_LITERAL_CSTRING("u:"))) { rv = ProcessForward(line); NS_ENSURE_SUCCESS(rv, rv); } else if (StringBeginsWith(line, NS_LITERAL_CSTRING("a:")) || @@ -766,16 +766,20 @@ ProtocolParserProtobuf::End() mUpdateStatus = NS_ERROR_FAILURE; FetchThreatListUpdatesResponse response; if (!response.ParseFromArray(mPending.get(), mPending.Length())) { NS_WARNING("ProtocolParserProtobuf failed parsing data."); return; } + auto minWaitDuration = response.minimum_wait_duration(); + mUpdateWaitSec = minWaitDuration.seconds() + + minWaitDuration.nanos() / 1000000000; + for (int i = 0; i < response.list_update_responses_size(); i++) { auto r = response.list_update_responses(i); nsresult rv = ProcessOneResponse(r); if (NS_SUCCEEDED(rv)) { mUpdateStatus = rv; } else { NS_WARNING("Failed to process one response."); }
--- a/toolkit/components/url-classifier/ProtocolParser.h +++ b/toolkit/components/url-classifier/ProtocolParser.h @@ -35,32 +35,33 @@ public: void SetRequestedTables(const nsTArray<nsCString>& aRequestTables) { mRequestedTables = aRequestTables; } nsresult Begin(); virtual nsresult AppendStream(const nsACString& aData) = 0; + uint32_t UpdateWaitSec() { return mUpdateWaitSec; } + // Notify that the inbound data is ready for parsing if progressive // parsing is not supported, for example in V4. virtual void End() = 0; // Forget the table updates that were created by this pass. It // becomes the caller's responsibility to free them. This is shitty. TableUpdate *GetTableUpdate(const nsACString& aTable); void ForgetTableUpdates() { mTableUpdates.Clear(); } nsTArray<TableUpdate*> &GetTableUpdates() { return mTableUpdates; } // These are only meaningful to V2. Since they were originally public, // moving them to ProtocolParserV2 requires a dymamic cast in the call - // sites. As a result, we will leave them until we remove support + // sites. As a result, we will leave them until we remove support // for V2 entirely.. virtual const nsTArray<ForwardedUpdate> &Forwards() const { return mForwards; } - virtual int32_t UpdateWait() { return 0; } virtual bool ResetRequested() { return false; } protected: virtual TableUpdate* CreateTableUpdate(const nsACString& aTableName) const = 0; nsCString mPending; nsresult mUpdateStatus; @@ -68,16 +69,19 @@ protected: nsTArray<TableUpdate*> mTableUpdates; nsTArray<ForwardedUpdate> mForwards; nsCOMPtr<nsICryptoHash> mCryptoHash; // The table names that were requested from the client. nsTArray<nsCString> mRequestedTables; + // How long we should wait until the next update. + uint32_t mUpdateWaitSec; + private: void CleanupUpdates(); }; /** * Helpers to parse the "shavar", "digest256" and "simple" list formats. */ class ProtocolParserV2 final : public ProtocolParser { @@ -86,17 +90,16 @@ public: virtual ~ProtocolParserV2(); virtual void SetCurrentTable(const nsACString& aTable) override; virtual nsresult AppendStream(const nsACString& aData) override; virtual void End() override; // Update information. virtual const nsTArray<ForwardedUpdate> &Forwards() const override { return mForwards; } - virtual int32_t UpdateWait() override { return mUpdateWait; } virtual bool ResetRequested() override { return mResetRequested; } private: virtual TableUpdate* CreateTableUpdate(const nsACString& aTableName) const override; nsresult ProcessControl(bool* aDone); nsresult ProcessExpirations(const nsCString& aLine); nsresult ProcessChunkControl(const nsCString& aLine); @@ -142,17 +145,16 @@ private: ChunkType type; uint32_t num; uint32_t hashSize; uint32_t length; void Clear() { num = 0; hashSize = 0; length = 0; } }; ChunkState mChunkState; - uint32_t mUpdateWait; bool mResetRequested; // Updates to apply to the current table being parsed. TableUpdateV2 *mTableUpdate; }; // Helpers to parse the "proto" list format. class ProtocolParserProtobuf final : public ProtocolParser {
--- a/toolkit/components/url-classifier/content/listmanager.js +++ b/toolkit/components/url-classifier/content/listmanager.js @@ -199,17 +199,17 @@ PROT_ListManager.prototype.kickoffUpdate // Add a fuzz of 0-1 minutes for both v2 and v4 according to Bug 1305478. initialUpdateDelay += Math.floor(Math.random() * (1 * 60 * 1000)); // If the user has never downloaded tables, do the check now. log("needsUpdate: " + JSON.stringify(this.needsUpdate_, undefined, 2)); for (var updateUrl in this.needsUpdate_) { // If we haven't already kicked off updates for this updateUrl, set a // non-repeating timer for it. The timer delay will be reset either on - // updateSuccess to this.updateinterval, or backed off on downloadError. + // updateSuccess to this.updateInterval, or backed off on downloadError. // Don't set the updateChecker unless at least one table has updates // enabled. if (this.updatesNeeded_(updateUrl) && !this.updateCheckers_[updateUrl]) { let provider = null; Object.keys(this.tablesData).forEach(function(table) { if (this.tablesData[table].updateUrl === updateUrl) { let newProvider = this.tablesData[table].provider; if (provider) { @@ -487,22 +487,25 @@ PROT_ListManager.prototype.makeUpdateReq } /** * Callback function if the update request succeeded. * @param waitForUpdate String The number of seconds that the client should * wait before requesting again. */ PROT_ListManager.prototype.updateSuccess_ = function(tableList, updateUrl, - waitForUpdate) { + waitForUpdateSec) { log("update success for " + tableList + " from " + updateUrl + ": " + - waitForUpdate + "\n"); + waitForUpdateSec + "\n"); + + // The time unit below are all milliseconds if not specified. + var delay = 0; - if (waitForUpdate) { - delay = parseInt(waitForUpdate, 10) * 1000; + if (waitForUpdateSec) { + delay = parseInt(waitForUpdateSec, 10) * 1000; } // As long as the delay is something sane (5 min to 1 day), update // our delay time for requesting updates. We always use a non-repeating // timer since the delay is set differently at every callback. if (delay > maxDelayMs) { log("Ignoring delay from server (too long), waiting " + maxDelayMs + "ms"); delay = maxDelayMs; @@ -551,17 +554,17 @@ PROT_ListManager.prototype.updateSuccess /** * Callback function if the update request succeeded. * @param result String The error code of the failure */ PROT_ListManager.prototype.updateError_ = function(table, updateUrl, result) { log("update error for " + table + " from " + updateUrl + ": " + result + "\n"); // There was some trouble applying the updates. Don't try again for at least - // updateInterval seconds. + // updateInterval milliseconds. this.updateCheckers_[updateUrl] = new G_Alarm(BindToObject(this.checkForUpdates, this, updateUrl), this.updateInterval, false); } /** * Callback function when the download failed * @param status String http status or an empty string if connection refused.
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp @@ -387,17 +387,17 @@ nsUrlClassifierDBServiceWorker::ResetStr mInStream = false; mProtocolParser = nullptr; } void nsUrlClassifierDBServiceWorker::ResetUpdate() { LOG(("ResetUpdate")); - mUpdateWait = 0; + mUpdateWaitSec = 0; mUpdateStatus = NS_OK; mUpdateObserver = nullptr; } NS_IMETHODIMP nsUrlClassifierDBServiceWorker::SetHashCompleter(const nsACString &tableName, nsIUrlClassifierHashCompleter *completer) { @@ -538,18 +538,18 @@ nsUrlClassifierDBServiceWorker::FinishSt NS_ENSURE_STATE(mInStream); NS_ENSURE_STATE(mUpdateObserver); mInStream = false; mProtocolParser->End(); if (NS_SUCCEEDED(mProtocolParser->Status())) { - if (mProtocolParser->UpdateWait()) { - mUpdateWait = mProtocolParser->UpdateWait(); + if (mProtocolParser->UpdateWaitSec()) { + mUpdateWaitSec = mProtocolParser->UpdateWaitSec(); } // XXX: Only allow forwards from the initial update? const nsTArray<ProtocolParser::ForwardedUpdate> &forwards = mProtocolParser->Forwards(); for (uint32_t i = 0; i < forwards.Length(); i++) { const ProtocolParser::ForwardedUpdate &forward = forwards[i]; mUpdateObserver->UpdateUrlRequested(forward.url, forward.table); } @@ -587,18 +587,18 @@ nsUrlClassifierDBServiceWorker::FinishUp } else { LOG(("nsUrlClassifierDBServiceWorker::FinishUpdate() Not running " "ApplyUpdate() since the update has already failed.")); } mMissCache.Clear(); if (NS_SUCCEEDED(mUpdateStatus)) { - LOG(("Notifying success: %d", mUpdateWait)); - mUpdateObserver->UpdateSuccess(mUpdateWait); + LOG(("Notifying success: %d", mUpdateWaitSec)); + mUpdateObserver->UpdateSuccess(mUpdateWaitSec); } else if (NS_ERROR_NOT_IMPLEMENTED == mUpdateStatus) { LOG(("Treating NS_ERROR_NOT_IMPLEMENTED a successful update " "but still mark it spoiled.")); mUpdateObserver->UpdateSuccess(0); mClassifier->MarkSpoiled(mUpdateTables); } else { if (LOG_ENABLED()) { nsAutoCString errorName;
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.h +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.h @@ -212,17 +212,17 @@ private: // Directory where to store the SB databases. nsCOMPtr<nsIFile> mCacheDir; // XXX: maybe an array of autoptrs. Or maybe a class specifically // storing a series of updates. nsTArray<mozilla::safebrowsing::TableUpdate*> mTableUpdates; - int32_t mUpdateWait; + uint32_t mUpdateWaitSec; // Entries that cannot be completed. We expect them to die at // the next update PrefixArray mMissCache; // Stores the last results that triggered a table update. CacheResultArray mLastResults;
new file mode 100644 --- /dev/null +++ b/toolkit/components/url-classifier/tests/gtest/TestProtocolParser.cpp @@ -0,0 +1,87 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +#include "gtest/gtest.h" +#include "ProtocolParser.h" +#include "mozilla/EndianUtils.h" + +using namespace mozilla; +using namespace mozilla::safebrowsing; + +typedef FetchThreatListUpdatesResponse_ListUpdateResponse ListUpdateResponse; + +static void +InitUpdateResponse(ListUpdateResponse* aUpdateResponse, + ThreatType aThreatType, + const nsACString& aState, + const nsACString& aChecksum, + bool isFullUpdate, + const nsTArray<uint32_t>& aFixedLengthPrefixes); + +static void +DumpBinary(const nsACString& aBinary); + +TEST(ProtocolParser, UpdateWait) +{ + // Top level response which contains a list of update response + // for different lists. + FetchThreatListUpdatesResponse response; + + auto r = response.mutable_list_update_responses()->Add(); + InitUpdateResponse(r, SOCIAL_ENGINEERING_PUBLIC, + nsCString("sta\x00te", 6), + nsCString("check\x0sum", 9), + true, + {0, 1, 2, 3}); + + // Set min wait duration. + auto minWaitDuration = response.mutable_minimum_wait_duration(); + minWaitDuration->set_seconds(8); + minWaitDuration->set_nanos(1 * 1000000000); + + std::string s; + response.SerializeToString(&s); + + DumpBinary(nsCString(s.c_str(), s.length())); + + ProtocolParser* p = new ProtocolParserProtobuf(); + p->AppendStream(nsCString(s.c_str(), s.length())); + p->End(); + ASSERT_EQ(p->UpdateWaitSec(), 9u); + delete p; +} + +static void +InitUpdateResponse(ListUpdateResponse* aUpdateResponse, + ThreatType aThreatType, + const nsACString& aState, + const nsACString& aChecksum, + bool isFullUpdate, + const nsTArray<uint32_t>& aFixedLengthPrefixes) +{ + aUpdateResponse->set_threat_type(aThreatType); + aUpdateResponse->set_new_client_state(aState.BeginReading(), aState.Length()); + aUpdateResponse->mutable_checksum()->set_sha256(aChecksum.BeginReading(), aChecksum.Length()); + aUpdateResponse->set_response_type(isFullUpdate ? ListUpdateResponse::FULL_UPDATE + : ListUpdateResponse::PARTIAL_UPDATE); + + auto additions = aUpdateResponse->mutable_additions()->Add(); + additions->set_compression_type(RAW); + auto rawHashes = additions->mutable_raw_hashes(); + rawHashes->set_prefix_size(4); + auto prefixes = rawHashes->mutable_raw_hashes(); + for (auto p : aFixedLengthPrefixes) { + char buffer[4]; + NativeEndian::copyAndSwapToBigEndian(buffer, &p, 1); + prefixes->append(buffer, 4); + } +} + +static void DumpBinary(const nsACString& aBinary) +{ + nsCString s; + for (size_t i = 0; i < aBinary.Length(); i++) { + s.AppendPrintf("\\x%.2X", (uint8_t)aBinary[i]); + } + printf("%s\n", s.get()); +} \ No newline at end of file
--- a/toolkit/components/url-classifier/tests/gtest/moz.build +++ b/toolkit/components/url-classifier/tests/gtest/moz.build @@ -6,16 +6,17 @@ LOCAL_INCLUDES += [ '../..', ] UNIFIED_SOURCES += [ 'TestChunkSet.cpp', 'TestPerProviderDirectory.cpp', + 'TestProtocolParser.cpp', 'TestRiceDeltaDecoder.cpp', 'TestSafebrowsingHash.cpp', 'TestSafeBrowsingProtobuf.cpp', 'TestTable.cpp', 'TestUrlClassifierTableUpdateV4.cpp', 'TestUrlClassifierUtils.cpp', 'TestVariableLengthPrefixSet.cpp', ]
--- a/xpcom/base/nscore.h +++ b/xpcom/base/nscore.h @@ -155,26 +155,16 @@ # define MOZ_DEPRECATED __attribute__((deprecated)) #elif defined(_MSC_VER) # define MOZ_DEPRECATED __declspec(deprecated) #else # define MOZ_DEPRECATED #endif /** - * Printf style formats - */ -#ifdef __GNUC__ -#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) \ - __attribute__ ((format (printf, stringIndex, firstToCheck))) -#else -#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) -#endif - -/** * Generic API modifiers which return the standard XPCOM nsresult type * * - NS_IMETHOD: use for in-class declarations and definitions. * - NS_IMETHODIMP: use for out-of-class definitions. * - NS_METHOD: usually used in conjunction with NS_CALLBACK. * - NS_CALLBACK: used in some legacy situations. Best avoided. */ #define NS_IMETHOD NS_IMETHOD_(nsresult)