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