Skip to content

Commit f584070

Browse files
Bug 1950211 - Add telemetry for String methods calling RegExp symbols on primitives r=dminor,iain
This patch adds telemetry for tc39/ecma262#3009. That normative PR has already been approved by TC39, but we need to verify that it's web compatible. Differential Revision: https://phabricator.services.mozilla.com/D241305
1 parent 85b2cdd commit f584070

File tree

7 files changed

+136
-4
lines changed

7 files changed

+136
-4
lines changed

dom/base/UseCounters.conf

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ custom JS_errorstack_setter_nonstring called error.stack setter with non-string
8484
custom JS_errorstack_setter_no_errordata called error.stack setter on object without ErrorData internal slot
8585
custom JS_dateparse called Date.parse
8686
custom JS_dateparse_impl_def call to Date.parse used implementation defined behaviour
87+
custom JS_regexp_symbol_protocol_on_primitive passed a primitive with a custom implementation of the regexp protocol symbols to one of the String methods that accept a regexp
8788

8889
// Console API
8990
method console.assert

dom/base/use_counter_metrics.yaml

+37-3
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ use.counter:
107107
send_in_pings:
108108
- use-counters
109109

110-
# Total of 2395 use counter metrics (excludes denominators).
111-
# Total of 357 'page' use counters.
110+
# Total of 2397 use counter metrics (excludes denominators).
111+
# Total of 358 'page' use counters.
112112
use.counter.page:
113113
svgsvgelement_getelementbyid:
114114
type: counter
@@ -807,6 +807,23 @@ use.counter.page:
807807
send_in_pings:
808808
- use-counters
809809

810+
js_regexp_symbol_protocol_on_primitive:
811+
type: counter
812+
description: >
813+
Whether a page passed a primitive with a custom implementation of the regexp protocol symbols to one of the String methods that accept a regexp.
814+
Compare against `use.counter.top_level_content_documents_destroyed`
815+
to calculate the rate.
816+
bugs:
817+
- https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
818+
data_reviews:
819+
- https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
820+
notification_emails:
821+
822+
823+
expires: never
824+
send_in_pings:
825+
- use-counters
826+
810827
console_assert:
811828
type: counter
812829
description: >
@@ -6179,7 +6196,7 @@ use.counter.page:
61796196
send_in_pings:
61806197
- use-counters
61816198

6182-
# Total of 357 'document' use counters.
6199+
# Total of 358 'document' use counters.
61836200
use.counter.doc:
61846201
svgsvgelement_getelementbyid:
61856202
type: counter
@@ -6878,6 +6895,23 @@ use.counter.doc:
68786895
send_in_pings:
68796896
- use-counters
68806897

6898+
js_regexp_symbol_protocol_on_primitive:
6899+
type: counter
6900+
description: >
6901+
Whether a document passed a primitive with a custom implementation of the regexp protocol symbols to one of the String methods that accept a regexp.
6902+
Compare against `use.counter.content_documents_destroyed`
6903+
to calculate the rate.
6904+
bugs:
6905+
- https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
6906+
data_reviews:
6907+
- https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
6908+
notification_emails:
6909+
6910+
6911+
expires: never
6912+
send_in_pings:
6913+
- use-counters
6914+
68816915
console_assert:
68826916
type: counter
68836917
description: >

js/public/friend/UsageStatistics.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ extern JS_PUBLIC_API void JS_SetAccumulateTelemetryCallback(
119119
_(DATEPARSE, DateParse) \
120120
_(DATEPARSE_IMPL_DEF, DateParseImplDef) \
121121
_(OPTIMIZE_ARRAY_SPECIES_FUSE, OptimizeArraySpeciesFuse) \
122-
_(OPTIMIZE_PROMISE_LOOKUP_FUSE, OptimizePromiseLookupFuse)
122+
_(OPTIMIZE_PROMISE_LOOKUP_FUSE, OptimizePromiseLookupFuse) \
123+
_(REGEXP_SYMBOL_PROTOCOL_ON_PRIMITIVE, RegExpSymbolProtocolOnPrimitive)
123124

124125
/*
125126
* Use counter names passed to the accumulate use counter callback.

js/src/builtin/String.js

+18
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ function String_match(regexp) {
3030

3131
// Step 2.b.
3232
if (matcher !== undefined) {
33+
if (!IsObject(regexp)) {
34+
RegExpSymbolProtocolOnPrimitiveCounter();
35+
}
3336
return callContentFunction(matcher, regexp, this);
3437
}
3538
}
@@ -94,6 +97,9 @@ function String_matchAll(regexp) {
9497

9598
// Step 2.d.
9699
if (matcher !== undefined) {
100+
if (!IsObject(regexp)) {
101+
RegExpSymbolProtocolOnPrimitiveCounter();
102+
}
97103
return callContentFunction(matcher, regexp, this);
98104
}
99105
}
@@ -221,6 +227,9 @@ function String_replace(searchValue, replaceValue) {
221227

222228
// Step 2.b.
223229
if (replacer !== undefined) {
230+
if (!IsObject(searchValue)) {
231+
RegExpSymbolProtocolOnPrimitiveCounter();
232+
}
224233
return callContentFunction(replacer, searchValue, this, replaceValue);
225234
}
226235
}
@@ -313,6 +322,9 @@ function String_replaceAll(searchValue, replaceValue) {
313322

314323
// Step 2.b.
315324
if (replacer !== undefined) {
325+
if (!IsObject(searchValue)) {
326+
RegExpSymbolProtocolOnPrimitiveCounter();
327+
}
316328
return callContentFunction(replacer, searchValue, this, replaceValue);
317329
}
318330
}
@@ -428,6 +440,9 @@ function String_search(regexp) {
428440

429441
// Step 2.b.
430442
if (searcher !== undefined) {
443+
if (!IsObject(regexp)) {
444+
RegExpSymbolProtocolOnPrimitiveCounter();
445+
}
431446
return callContentFunction(searcher, regexp, this);
432447
}
433448
}
@@ -491,6 +506,9 @@ function String_split(separator, limit) {
491506

492507
// Step 2.b.
493508
if (splitter !== undefined) {
509+
if (!IsObject(separator)) {
510+
RegExpSymbolProtocolOnPrimitiveCounter();
511+
}
494512
return callContentFunction(splitter, separator, this, limit);
495513
}
496514
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Test the telemetry added in Bug 1950211
2+
assertEq(getUseCounterResults().RegExpSymbolProtocolOnPrimitive, 0);
3+
4+
"abc".match(/b/);
5+
"abc".match({ [Symbol.match]: () => [] });
6+
"abc".match("b");
7+
"abc".match(42);
8+
assertEq(getUseCounterResults().RegExpSymbolProtocolOnPrimitive, 0);
9+
Number.prototype[Symbol.match] = () => [];
10+
"abc".match(42);
11+
assertEq(getUseCounterResults().RegExpSymbolProtocolOnPrimitive, 1);
12+
delete Number.prototype[Symbol.match];
13+
14+
"abc".matchAll(/b/g);
15+
"abc".matchAll({ [Symbol.matchAll]: () => [] });
16+
"abc".matchAll("b");
17+
"abc".matchAll(42);
18+
assertEq(getUseCounterResults().RegExpSymbolProtocolOnPrimitive, 1);
19+
Number.prototype[Symbol.matchAll] = () => [];
20+
"abc".matchAll(42);
21+
assertEq(getUseCounterResults().RegExpSymbolProtocolOnPrimitive, 2);
22+
delete Number.prototype[Symbol.matchAll];
23+
24+
"abc".replace(/b/, "d");
25+
"abc".replace({ [Symbol.replace]: () => "" });
26+
"abc".replace("b", "d");
27+
"abc".replace(42, "d");
28+
assertEq(getUseCounterResults().RegExpSymbolProtocolOnPrimitive, 2);
29+
Number.prototype[Symbol.replace] = () => "";
30+
"abc".replace(42, "d");
31+
assertEq(getUseCounterResults().RegExpSymbolProtocolOnPrimitive, 3);
32+
delete Number.prototype[Symbol.replace];
33+
34+
"abc".replaceAll(/b/g, "d");
35+
"abc".replaceAll({ [Symbol.replace]: () => "" });
36+
"abc".replaceAll("b", "d");
37+
"abc".replaceAll(42, "d");
38+
assertEq(getUseCounterResults().RegExpSymbolProtocolOnPrimitive, 3);
39+
Number.prototype[Symbol.replace] = () => "";
40+
"abc".replaceAll(42, "d");
41+
assertEq(getUseCounterResults().RegExpSymbolProtocolOnPrimitive, 4);
42+
delete Number.prototype[Symbol.replace];
43+
44+
"abc".search(/b/);
45+
"abc".search({ [Symbol.search]: () => -1 });
46+
"abc".search("b");
47+
"abc".search(42);
48+
assertEq(getUseCounterResults().RegExpSymbolProtocolOnPrimitive, 4);
49+
Number.prototype[Symbol.search] = () => -1;
50+
"abc".search(42);
51+
assertEq(getUseCounterResults().RegExpSymbolProtocolOnPrimitive, 5);
52+
delete Number.prototype[Symbol.search];
53+
54+
"abc".split(/b/);
55+
"abc".split({ [Symbol.split]: () => [] });
56+
"abc".split("b");
57+
"abc".split(42);
58+
assertEq(getUseCounterResults().RegExpSymbolProtocolOnPrimitive, 5);
59+
Number.prototype[Symbol.split] = () => [];
60+
"abc".split(42);
61+
assertEq(getUseCounterResults().RegExpSymbolProtocolOnPrimitive, 6);
62+
delete Number.prototype[Symbol.split];

js/src/vm/SelfHosting.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,16 @@ static bool intrinsic_StringReplaceString(JSContext* cx, unsigned argc,
13821382
return true;
13831383
}
13841384

1385+
static bool intrinsic_RegExpSymbolProtocolOnPrimitiveCounter(JSContext* cx,
1386+
unsigned argc,
1387+
Value* vp) {
1388+
// This telemetry is to assess compatibility for tc39/ecma262#3009 and
1389+
// can later be removed (Bug 1953619).
1390+
cx->runtime()->setUseCounter(
1391+
cx->global(), JSUseCounter::REGEXP_SYMBOL_PROTOCOL_ON_PRIMITIVE);
1392+
return true;
1393+
}
1394+
13851395
static bool intrinsic_StringReplaceAllString(JSContext* cx, unsigned argc,
13861396
Value* vp) {
13871397
CallArgs args = CallArgsFromVp(argc, vp);
@@ -2218,6 +2228,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
22182228
JS_INLINABLE_FN("RegExpSearcher", RegExpSearcher, 3, 0, RegExpSearcher),
22192229
JS_INLINABLE_FN("RegExpSearcherLastLimit", RegExpSearcherLastLimit, 0, 0,
22202230
RegExpSearcherLastLimit),
2231+
JS_FN("RegExpSymbolProtocolOnPrimitiveCounter",
2232+
intrinsic_RegExpSymbolProtocolOnPrimitiveCounter, 0, 0),
22212233
JS_INLINABLE_FN("SameValue", js::obj_is, 2, 0, ObjectIs),
22222234
JS_FN("SetCopy", SetObject::copy, 1, 0),
22232235
JS_FN("SharedArrayBufferByteLength",

js/xpconnect/src/XPCJSRuntime.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -2957,6 +2957,10 @@ static void SetUseCounterCallback(JSObject* obj, JSUseCounter counter) {
29572957
case JSUseCounter::DATEPARSE_IMPL_DEF:
29582958
SetUseCounter(obj, eUseCounter_custom_JS_dateparse_impl_def);
29592959
return;
2960+
case JSUseCounter::REGEXP_SYMBOL_PROTOCOL_ON_PRIMITIVE:
2961+
SetUseCounter(obj,
2962+
eUseCounter_custom_JS_regexp_symbol_protocol_on_primitive);
2963+
return;
29602964
case JSUseCounter::COUNT:
29612965
break;
29622966
}

0 commit comments

Comments
 (0)