tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 679bcbcb587b3a7692b3f0744ba9b3207a5ad2da
parent 24e7c78b7eccf83db91186aba9e2de458685c3f6
Author: Alexandru Marc <amarc@mozilla.com>
Date:   Wed, 17 Dec 2025 19:02:49 +0200

Revert "Bug 2002635 - Disable asm.js. r=bvisness" for causing dt failures @ browser_dbg-features-asm.js

This reverts commit 415f58c3f99a4d451366698b58e6cf75b74e863e.

Revert "Bug 2002635 - Move asm.js deprecation warning into parsing so it always fires. r=arai"

This reverts commit 502003fa685f6dc68ceb5282db1330bc4b5fc1f0.

Revert "Bug 2002635 - Revert "Bug 1980396: Add a new probe that records 5 minutes of JS activity for documents with asm.js." r=smaug"

This reverts commit 1ef03f99181acd3e9e2bf88acbb9fc9e23aa1832.

Revert "Bug 2002635 - Revert "Bug 1980396: Add javascript.options.asmjs feature to Nimbus feature manifest." r=denispal"

This reverts commit 485d9c1f017171aae044681c473ac839800b557c.

Diffstat:
Mdom/base/Document.cpp | 94++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mdom/base/Document.h | 8++++++++
Mdom/metrics.yaml | 16++++++++++++++++
Mjs/src/frontend/Parser.cpp | 30+++++++-----------------------
Mjs/src/frontend/Parser.h | 6+++---
Mjs/src/jit-test/tests/asm.js/directives.txt | 2+-
Djs/src/jit-test/tests/asm.js/disabled-warning.js | 7-------
Mjs/src/jit-test/tests/debug/Object-createSource-forceEnableAsmJS.js | 2+-
Mjs/src/shell/js.cpp | 4++--
Mjs/src/tests/lib/tests.py | 1+
Mjs/src/wasm/WasmModule.cpp | 9+++++++++
Mmodules/libpref/init/StaticPrefList.yaml | 2+-
Mtoolkit/components/nimbus/FeatureManifest.yaml | 12++++++++++++
13 files changed, 154 insertions(+), 39 deletions(-)

diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp @@ -2058,6 +2058,91 @@ void Document::LoadEventFired() { } } +static void RecordExecutionTimeForAsmJS(Document* aDoc) { + if (aDoc->GetScopeObject()) { + AutoJSAPI jsapi; + if (!jsapi.Init(aDoc->GetScopeObject())) { + return; + } + + if (JSContext* cx = jsapi.cx()) { + // Disable the execution timer. + JS::SetMeasuringExecutionTimeEnabled(cx, false); + + // Get the execution time and accumulate it. + JS::JSTimers timers = JS::GetJSTimers(cx); + mozilla::glean::perf::js_exec_asm_js.AccumulateRawDuration( + timers.executionTime); + } + } +} + +class ASMJSExecutionTimeRecorder final : public nsITimerCallback, + public nsINamed { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSITIMERCALLBACK + NS_DECL_NSINAMED + + explicit ASMJSExecutionTimeRecorder(Document* aDocument) + : mDocument(aDocument) {} + + private: + ~ASMJSExecutionTimeRecorder() = default; + WeakPtr<Document> mDocument; +}; + +NS_IMPL_ISUPPORTS(ASMJSExecutionTimeRecorder, nsITimerCallback, nsINamed) + +NS_IMETHODIMP +ASMJSExecutionTimeRecorder::Notify(nsITimer* aTimer) { + RefPtr<Document> doc(mDocument); + if (!doc) { + return NS_OK; + } + + // Record the JS execution time to Glean. + RecordExecutionTimeForAsmJS(doc); + return NS_OK; +} + +NS_IMETHODIMP +ASMJSExecutionTimeRecorder::GetName(nsACString& aName) { + aName.AssignLiteral("ASMJSExecutionTimeRecorder"); + return NS_OK; +} + +// If an asm.js use counter is set, then enable the JS execution +// timer and record it after 5 minutes of activity. +void Document::RecordASMJSExecutionTime() { + // Skip if the document is being destroyed. + if (mIsGoingAway) { + return; + } + + // If the timer has already fired, or the use counter is already set, + // then nothing more needs to be done. + if (mASMJSExecutionTimer || HasUseCounter(eUseCounter_custom_JS_use_asm)) { + return; + } + + AutoJSContext cx; + if (static_cast<JSContext*>(cx)) { + JS::SetMeasuringExecutionTimeEnabled(cx, true); + } + + RefPtr<ASMJSExecutionTimeRecorder> callback = + new ASMJSExecutionTimeRecorder(this); + nsresult rv = + NS_NewTimerWithCallback(getter_AddRefs(mASMJSExecutionTimer), callback, + 5 * 60 * 1000, // 5min delay + nsITimer::TYPE_ONE_SHOT); + + if (NS_FAILED(rv)) { + mASMJSExecutionTimer = nullptr; + } +} + void Document::RecordPageLoadEventTelemetry() { // If the page load time is empty, then the content wasn't something we want // to report (i.e. not a top level document). @@ -12240,6 +12325,11 @@ void Document::Destroy() { mIsGoingAway = true; + if (mASMJSExecutionTimer) { + mASMJSExecutionTimer->Cancel(); + mASMJSExecutionTimer = nullptr; + RecordExecutionTimeForAsmJS(this); + } if (mScriptLoader) { mScriptLoader->Destroy(); } @@ -20731,7 +20821,9 @@ void Document::RemoveToplevelLoadingDocument(Document* aDoc) { } // Stop the JS execution timer once the page is loaded. - { + // If the asm.js counter is active, then continue the timer + // for telemetry purposes. + if (!aDoc->HasUseCounter(eUseCounter_custom_JS_use_asm)) { AutoJSContext cx; if (static_cast<JSContext*>(cx)) { JS::SetMeasuringExecutionTimeEnabled(cx, false); diff --git a/dom/base/Document.h b/dom/base/Document.h @@ -3858,7 +3858,12 @@ class Document : public nsINode, // call it just before the document loses its window. void SendPageUseCounters(); + void RecordASMJSExecutionTime(); + void SetUseCounter(UseCounter aUseCounter) { + if (aUseCounter == eUseCounter_custom_JS_use_asm) { + RecordASMJSExecutionTime(); + } mUseCounters[aUseCounter] = true; } @@ -5344,6 +5349,9 @@ class Document : public nsINode, // This only applies to error pages. Might be null. nsCOMPtr<nsIChannel> mFailedChannel; + // Timer for delayed ASMJS execution time recording + nsCOMPtr<nsITimer> mASMJSExecutionTimer; + // if this document is part of a multipart document, // the ID can be used to distinguish it from the other parts. uint32_t mPartID; diff --git a/dom/metrics.yaml b/dom/metrics.yaml @@ -238,6 +238,22 @@ perf: send_in_pings: - pageload-base-domain + js_exec_asm_js: + type: timing_distribution + description: > + Time in milliseconds spent executing Javascript for top level + documents that contain the asm.js use counter. Measures 5min + of activity after the use counter is set then records + the value in this histogram. + time_unit: millisecond + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1980396 + data_reviews: + - https://phabricator.services.mozilla.com/D259436 + notification_emails: + - perf-telemetry-alerts@mozilla.com + expires: never + h3p_page_load_time: type: labeled_timing_distribution description: > diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp @@ -49,9 +49,8 @@ #include "js/ErrorReport.h" // JSErrorBase #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_* #include "js/HashTable.h" -#include "js/RegExpFlags.h" // JS::RegExpFlags -#include "js/Stack.h" // JS::NativeStackLimit -#include "util/DifferentialTesting.h" +#include "js/RegExpFlags.h" // JS::RegExpFlags +#include "js/Stack.h" // JS::NativeStackLimit #include "util/StringBuilder.h" // StringBuilder #include "vm/BytecodeUtil.h" #include "vm/FunctionFlags.h" // js::FunctionFlags @@ -3835,8 +3834,7 @@ static inline bool IsUseAsmDirective(const TokenPos& pos, } template <typename Unit> -bool Parser<SyntaxParseHandler, Unit>::asmJS(TokenPos directivePos, - ListNodeType list) { +bool Parser<SyntaxParseHandler, Unit>::asmJS(ListNodeType list) { // While asm.js could technically be validated and compiled during syntax // parsing, we have no guarantee that some later JS wouldn't abort the // syntax parse and cause us to re-parse (and re-compile) the asm.js module. @@ -3848,8 +3846,7 @@ bool Parser<SyntaxParseHandler, Unit>::asmJS(TokenPos directivePos, } template <typename Unit> -bool Parser<FullParseHandler, Unit>::asmJS(TokenPos directivePos, - ListNodeType list) { +bool Parser<FullParseHandler, Unit>::asmJS(ListNodeType list) { // Disable syntax parsing in anything nested inside the asm.js module. disableSyntaxParser(); @@ -3881,18 +3878,6 @@ bool Parser<FullParseHandler, Unit>::asmJS(TokenPos directivePos, if (!CompileAsmJS(this->fc_, this->parserAtoms(), *this, list, &validated)) { return false; } - - // Warn about asm.js deprecation even if we failed validation. Do this after - // compilation so that this warning is the last one we emit. This makes - // testing in asm.js/disabled-warning.js easier. - if (!js::SupportDifferentialTesting() && - JS::Prefs::warn_asmjs_deprecation()) { - if (!warningAt(directivePos.begin, JSMSG_USE_ASM_DEPRECATED)) { - return false; - } - } - - // If we failed validation, trigger a reparse. See above. if (!validated) { pc_->newDirectives->setAsmJS(); return false; @@ -3902,9 +3887,8 @@ bool Parser<FullParseHandler, Unit>::asmJS(TokenPos directivePos, } template <class ParseHandler, typename Unit> -inline bool GeneralParser<ParseHandler, Unit>::asmJS(TokenPos directivePos, - ListNodeType list) { - return asFinalParser()->asmJS(directivePos, list); +inline bool GeneralParser<ParseHandler, Unit>::asmJS(ListNodeType list) { + return asFinalParser()->asmJS(list); } /* @@ -4019,7 +4003,7 @@ bool GeneralParser<ParseHandler, Unit>::maybeParseDirective( } } else if (IsUseAsmDirective(directivePos, directive)) { if (pc_->isFunctionBox()) { - return asmJS(directivePos, list); + return asmJS(list); } return warningAt(directivePos.begin, JSMSG_USE_ASM_DIRECTIVE_FAIL); } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h @@ -1529,7 +1529,7 @@ class MOZ_STACK_CLASS GeneralParser : public PerHandlerParser<ParseHandler> { TokenPos pos); private: - inline bool asmJS(TokenPos directivePos, ListNodeType list); + inline bool asmJS(ListNodeType list); }; template <typename Unit> @@ -1664,7 +1664,7 @@ class MOZ_STACK_CLASS Parser<SyntaxParseHandler, Unit> final bool skipLazyInnerFunction(FunctionNodeType funNode, uint32_t toStringStart, bool tryAnnexB); - bool asmJS(TokenPos directivePos, ListNodeType list); + bool asmJS(ListNodeType list); // Functions present only in Parser<SyntaxParseHandler, Unit>. }; @@ -1848,7 +1848,7 @@ class MOZ_STACK_CLASS Parser<FullParseHandler, Unit> final return checkLabelOrIdentifierReference(ident, offset, YieldIsName); } - bool asmJS(TokenPos directivePos, ListNodeType list); + bool asmJS(ListNodeType list); }; template <class Parser> diff --git a/js/src/jit-test/tests/asm.js/directives.txt b/js/src/jit-test/tests/asm.js/directives.txt @@ -1 +1 @@ -|jit-test| test-also=--asmjs; test-also=--disable-wasm-huge-memory; skip-variant-if: --disable-wasm-huge-memory, !wasmHugeMemorySupported(); +|jit-test| test-also=--no-asmjs; test-also=--disable-wasm-huge-memory; skip-variant-if: --disable-wasm-huge-memory, !wasmHugeMemorySupported(); diff --git a/js/src/jit-test/tests/asm.js/disabled-warning.js b/js/src/jit-test/tests/asm.js/disabled-warning.js @@ -1,7 +0,0 @@ -enableLastWarning(); -new Function(`"use asm"; return {};`); -var warning = getLastWarning(); -assertEq(warning !== null, true, "warning should be caught"); -assertEq(warning.name, "Warning"); -assertEq(warning.lineNumber, 3); -assertEq(warning.columnNumber, 1); diff --git a/js/src/jit-test/tests/debug/Object-createSource-forceEnableAsmJS.js b/js/src/jit-test/tests/debug/Object-createSource-forceEnableAsmJS.js @@ -1,4 +1,4 @@ -// |jit-test| --asmjs; skip-if: !wasmDebuggingEnabled() +// |jit-test| skip-if: !wasmDebuggingEnabled() gczeal(0); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp @@ -12958,7 +12958,7 @@ bool InitOptionParser(OptionParser& op) { -1) || !op.addBoolOption('\0', "only-inline-selfhosted", "Only inline selfhosted functions") || - !op.addBoolOption('\0', "asmjs", "Enable asm.js compilation") || + !op.addBoolOption('\0', "no-asmjs", "Disable asm.js compilation") || !op.addStringOption( '\0', "wasm-compiler", "[option]", "Choose to enable a subset of the wasm compilers, valid options are " @@ -13756,7 +13756,7 @@ bool SetContextOptions(JSContext* cx, const OptionParser& op) { } bool SetContextWasmOptions(JSContext* cx, const OptionParser& op) { - enableAsmJS = op.getBoolOption("asmjs"); + enableAsmJS = !op.getBoolOption("no-asmjs"); enableWasm = true; enableWasmBaseline = true; diff --git a/js/src/tests/lib/tests.py b/js/src/tests/lib/tests.py @@ -76,6 +76,7 @@ JITFLAGS = { [ "--no-blinterp", "--no-baseline", + "--no-asmjs", "--wasm-compiler=none", "--no-native-regexp", ] diff --git a/js/src/wasm/WasmModule.cpp b/js/src/wasm/WasmModule.cpp @@ -1032,6 +1032,15 @@ bool Module::instantiate(JSContext* cx, ImportValues& imports, } } } + + // Warn if the user is using asm.js still. + if (JS::Prefs::warn_asmjs_deprecation() && codeMeta().isAsmJS()) { + if (!js::WarnNumberASCII(cx, JSMSG_USE_ASM_DEPRECATED)) { + if (cx->isExceptionPending()) { + cx->clearPendingException(); + } + } + } } if (cx->options().testWasmAwaitTier2() && diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml @@ -9521,7 +9521,7 @@ # asm.js - name: javascript.options.asmjs type: bool - value: false + value: true mirror: always # Whether to throw a TypeError if asm.js code hits validation failure. diff --git a/toolkit/components/nimbus/FeatureManifest.yaml b/toolkit/components/nimbus/FeatureManifest.yaml @@ -4204,6 +4204,18 @@ jitHintsCache: branch: user pref: "javascript.options.jithints" +asmjs: + description: Pref to toggle support for asm.js. + owner: dpalmeiro@mozilla.com + hasExposure: false + variables: + enabled: + description: True to enable the asm.js feature. + type: boolean + setPref: + branch: user + pref: "javascript.options.asmjs" + scriptloader: description: Prefs that control scriptloader heuristics. owner: dpalmeiro@mozilla.com