Skip to content

Commit 94f0ce2

Browse files
trevoradecopybara-github
authored andcommitted
Add $jscomp.polyfillTypedArrayMethod function to reduce repeated code.
PiperOrigin-RevId: 810497633
1 parent 6fff750 commit 94f0ce2

File tree

10 files changed

+264
-172
lines changed

10 files changed

+264
-172
lines changed

src/com/google/javascript/jscomp/RemoveUnusedCode.java

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,31 @@ class RemoveUnusedCode implements CompilerPass {
8787
private static final ImmutableSet<String> IMPLICITLY_USED_PROPERTIES =
8888
ImmutableSet.of("length", "toString", "valueOf", "constructor", "prototype");
8989

90+
/**
91+
* Supported TypedArray subclasses.
92+
*
93+
* <p>Keep in sync with TYPED_ARRAY_CLASSES in js/build_polyfill_table.js.
94+
*/
95+
// LINT.IfChange(typed_array_classes)
96+
private static final ImmutableSet<String> TYPED_ARRAY_CLASSES =
97+
ImmutableSet.of(
98+
"Int8Array",
99+
"Uint8Array",
100+
"Uint8ClampedArray",
101+
"Int16Array",
102+
"Uint16Array",
103+
"Int32Array",
104+
"Uint32Array",
105+
"Float32Array",
106+
"Float64Array",
107+
"BigInt64Array",
108+
"BigUint64Array");
109+
110+
// LINT.ThenChange(
111+
// //depot/google3/third_party/java_src/jscomp/java/com/google/javascript/jscomp/js/build_polyfill_table.js:typed_array_classes,
112+
// //depot/google3/third_party/java_src/jscomp/java/com/google/javascript/jscomp/js/util/polyfill.js:typed_array_classes
113+
// )
114+
90115
private final AbstractCompiler compiler;
91116
private final AstAnalyzer astAnalyzer;
92117

@@ -723,10 +748,26 @@ private void traverseCall(Node callNode, Scope scope) {
723748
// TODO(bradfordcsmith): Should also handle Object.create() and Object.defineProperty().
724749
traverseObjectDefinePropertiesCall(callNode, scope);
725750
} else if (removeUnusedPolyfills && isJscompPolyfill(callee)) {
751+
boolean isPolyfillTypedArrayMethod =
752+
callee.isName()
753+
? callee.getString().equals("$jscomp$polyfillTypedArrayMethod")
754+
: callee.isGetProp() && callee.getString().equals("polyfillTypedArrayMethod");
755+
726756
Node firstArg = callee.getNext();
727-
String polyfillName = firstArg.getString();
728-
PolyfillInfo info = createPolyfillInfo(callNode, scope, polyfillName);
729-
polyfills.put(info.key, info);
757+
String polyfillOrMethodName = firstArg.getString();
758+
759+
if (isPolyfillTypedArrayMethod) {
760+
String methodName = polyfillOrMethodName;
761+
for (String className : TYPED_ARRAY_CLASSES) {
762+
String polyfillName = className + ".prototype." + methodName;
763+
PolyfillInfo info = createPolyfillInfo(callNode, scope, polyfillName);
764+
polyfills.put(info.key, info);
765+
}
766+
} else {
767+
String polyfillName = polyfillOrMethodName;
768+
PolyfillInfo info = createPolyfillInfo(callNode, scope, polyfillName);
769+
polyfills.put(info.key, info);
770+
}
730771
// Only traverse the callee (to mark it as used). The arguments may be traversed later.
731772
traverseNode(callNode.getFirstChild(), scope);
732773
} else if (NodeUtil.isGoogWeakUsageCall(callNode)
@@ -798,16 +839,24 @@ private void traverseCall(Node callNode, Scope scope) {
798839
/** Checks whether this is a recognizable call to $jscomp.polyfill. */
799840
private static boolean isJscompPolyfill(Node n) {
800841
return switch (n.getToken()) {
801-
case NAME ->
802-
// Need to work correctly after CollapseProperties.
803-
(n.getString().equals("$jscomp$polyfill") || n.getString().equals("$jscomp$patch"))
804-
&& n.getNext().isStringLit();
805-
case GETPROP ->
806-
// Need to work correctly without CollapseProperties.
807-
(n.getString().equals("polyfill") || n.getString().equals("patch"))
808-
&& n.getFirstChild().isName()
809-
&& n.getFirstChild().getString().equals("$jscomp")
810-
&& n.getNext().isStringLit();
842+
case NAME -> {
843+
// Need to work correctly after CollapseProperties.
844+
String name = n.getString();
845+
yield (name.equals("$jscomp$polyfill")
846+
|| name.equals("$jscomp$patch")
847+
|| name.equals("$jscomp$polyfillTypedArrayMethod"))
848+
&& n.getNext().isStringLit();
849+
}
850+
case GETPROP -> {
851+
// Need to work correctly without CollapseProperties.
852+
String propertyName = n.getString();
853+
yield (propertyName.equals("polyfill")
854+
|| propertyName.equals("patch")
855+
|| propertyName.equals("polyfillTypedArrayMethod"))
856+
&& n.getFirstChild().isName()
857+
&& n.getFirstChild().getString().equals("$jscomp")
858+
&& n.getNext().isStringLit();
859+
}
811860
default -> false;
812861
};
813862
}
@@ -2352,7 +2401,11 @@ private class Polyfill extends Removable {
23522401

23532402
@Override
23542403
public void removeInternal(AbstractCompiler compiler) {
2355-
NodeUtil.deleteNode(polyfillNode, compiler);
2404+
// When usages of $jscomp.polyfillTypedArrayMethod are removed, it results in multiple
2405+
// attempts to delete the same polyfill function due to the various TypedArray subclasses.
2406+
if (!alreadyRemoved(polyfillNode)) {
2407+
NodeUtil.deleteNode(polyfillNode, compiler);
2408+
}
23562409
}
23572410

23582411
@Override

src/com/google/javascript/jscomp/js/build_polyfill_table.js

Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,30 @@ const ORDER = [
3131
'es_next', 'es_unstable'
3232
];
3333

34+
/**
35+
* Supported TypedArray subclasses.
36+
*
37+
* @const {!Array<string>}
38+
*/
39+
// LINT.IfChange(typed_array_classes)
40+
const TYPED_ARRAY_CLASSES = [
41+
'Int8Array',
42+
'Uint8Array',
43+
'Uint8ClampedArray',
44+
'Int16Array',
45+
'Uint16Array',
46+
'Int32Array',
47+
'Uint32Array',
48+
'Float32Array',
49+
'Float64Array',
50+
'BigInt64Array',
51+
'BigUint64Array',
52+
];
53+
// LINT.ThenChange(
54+
// //depot/google3/third_party/java_src/jscomp/java/com/google/javascript/jscomp/RemoveUnusedCode.java:typed_array_classes,
55+
// //depot/google3/third_party/java_src/jscomp/java/com/google/javascript/jscomp/js/util/polyfill.js:typed_array_classes
56+
// )
57+
3458
/**
3559
* Prints to stderr and exits.
3660
* @param {string} message
@@ -63,13 +87,11 @@ class PolyfillTable {
6387
polyfill(lib) {
6488
return (polyfill, impl, fromLang, toLang) => {
6589
if (!ORDER.includes(fromLang)) {
66-
throw new Error(
67-
`Unknown language version ${fromLang} for ${polyfill}`);
90+
throw new Error(`Unknown language version ${fromLang} for ${polyfill}`);
6891
}
6992

7093
if (!ORDER.includes(toLang)) {
71-
throw new Error(
72-
`Unknown language version ${toLang} for ${polyfill}`);
94+
throw new Error(`Unknown language version ${toLang} for ${polyfill}`);
7395
}
7496

7597
this.symbolToFile.set(polyfill, this.symbolToFile.get(polyfill) || []);
@@ -83,6 +105,21 @@ class PolyfillTable {
83105
};
84106
}
85107

108+
/**
109+
* Returns a shim for $jscomp.polyfillTypedArrayMethod.
110+
* @param {string} lib Library currently being scanned.
111+
* @return {function(string, ?Function, string, string)}
112+
*/
113+
polyfillTypedArrayMethod(lib) {
114+
return (methodName, impl, fromLang, toLang) => {
115+
for (let i = 0; i < TYPED_ARRAY_CLASSES.length; i++) {
116+
const className = TYPED_ARRAY_CLASSES[i];
117+
const target = className + '.prototype.' + methodName;
118+
this.polyfill(lib)(target, impl, fromLang, toLang);
119+
}
120+
};
121+
}
122+
86123
/**
87124
* Reads a JS file and adds it to the table.
88125
* @param {string} lib Name of the library.
@@ -101,7 +138,8 @@ class PolyfillTable {
101138
try {
102139
new Function('$jscomp', data)({
103140
global: global,
104-
polyfill: this.polyfill(lib, table),
141+
polyfill: this.polyfill(lib),
142+
polyfillTypedArrayMethod: this.polyfillTypedArrayMethod(lib),
105143
});
106144
} catch (err) {
107145
throw new Error('Failed to parse file: ' + lib + ': ' + err);
@@ -119,9 +157,8 @@ class PolyfillTable {
119157
// First check for duplicate provided symbols.
120158
for (const entry of this.symbolToFile.entries()) {
121159
if (entry[1].length != 1) {
122-
errors.add(
123-
`ERROR - ${entry[0]} provided by multiple files:${
124-
entry[1].map(f => '\n ' + f).join('')}`);
160+
errors.add(`ERROR - ${entry[0]} provided by multiple files:${
161+
entry[1].map(f => '\n ' + f).join('')}`);
125162
}
126163
}
127164
// Next ensure all deps have nonincreasing versions.
@@ -186,22 +223,21 @@ function maxVersion(version1, version2) {
186223

187224
const table = new PolyfillTable();
188225

189-
const reads = process.argv.slice(2).map(filename =>
190-
new Promise((fulfill, reject) =>
191-
fs.readFile(filename, 'utf8', (err, data) => {
192-
try {
193-
if (err) {
194-
reject(err);
195-
} else {
196-
const lib = filename.replace(/^.*?\/js\/|\.js$/g, '');
197-
table.readFile(lib, data);
198-
fulfill('');
199-
}
200-
} catch (err) {
201-
reject(err);
202-
}
203-
})));
226+
const reads = process.argv.slice(2).map(
227+
filename => new Promise(
228+
(fulfill, reject) => fs.readFile(filename, 'utf8', (err, data) => {
229+
try {
230+
if (err) {
231+
reject(err);
232+
} else {
233+
const lib = filename.replace(/^.*?\/js\/|\.js$/g, '');
234+
table.readFile(lib, data);
235+
fulfill('');
236+
}
237+
} catch (err) {
238+
reject(err);
239+
}
240+
})));
204241

205242
Promise.all(reads).then(
206-
success => console.log(table.build()),
207-
failure => fail(failure.stack));
243+
success => console.log(table.build()), failure => fail(failure.stack));

src/com/google/javascript/jscomp/js/es6/typedarray/at.js

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,4 @@ $jscomp.typedArrayAt = function(orig) {
3030
return $jscomp.atMethod;
3131
};
3232

33-
$jscomp.polyfill(
34-
'BigInt64Array.prototype.at', $jscomp.typedArrayAt, 'es_next', 'es_2020');
35-
$jscomp.polyfill(
36-
'BigUint64Array.prototype.at', $jscomp.typedArrayAt, 'es_next', 'es_2020');
37-
$jscomp.polyfill(
38-
'Int8Array.prototype.at', $jscomp.typedArrayAt, 'es_next', 'es5');
39-
$jscomp.polyfill(
40-
'Uint8Array.prototype.at', $jscomp.typedArrayAt, 'es_next', 'es5');
41-
$jscomp.polyfill(
42-
'Uint8ClampedArray.prototype.at', $jscomp.typedArrayAt, 'es_next', 'es5');
43-
$jscomp.polyfill(
44-
'Int16Array.prototype.at', $jscomp.typedArrayAt, 'es_next', 'es5');
45-
$jscomp.polyfill(
46-
'Uint16Array.prototype.at', $jscomp.typedArrayAt, 'es_next', 'es5');
47-
$jscomp.polyfill(
48-
'Int32Array.prototype.at', $jscomp.typedArrayAt, 'es_next', 'es5');
49-
$jscomp.polyfill(
50-
'Uint32Array.prototype.at', $jscomp.typedArrayAt, 'es_next', 'es5');
51-
$jscomp.polyfill(
52-
'Float32Array.prototype.at', $jscomp.typedArrayAt, 'es_next', 'es5');
53-
$jscomp.polyfill(
54-
'Float64Array.prototype.at', $jscomp.typedArrayAt, 'es_next', 'es5');
33+
$jscomp.polyfillTypedArrayMethod('at', $jscomp.typedArrayAt, 'es_next', 'es5');

src/com/google/javascript/jscomp/js/es6/typedarray/copywithin.js

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,30 +29,5 @@ $jscomp.typedArrayCopyWithin = function(orig) {
2929
return Array.prototype.copyWithin;
3030
};
3131

32-
$jscomp.polyfill(
33-
'Int8Array.prototype.copyWithin', $jscomp.typedArrayCopyWithin, 'es6',
34-
'es5');
35-
$jscomp.polyfill(
36-
'Uint8Array.prototype.copyWithin', $jscomp.typedArrayCopyWithin, 'es6',
37-
'es5');
38-
$jscomp.polyfill(
39-
'Uint8ClampedArray.prototype.copyWithin', $jscomp.typedArrayCopyWithin,
40-
'es6', 'es5');
41-
$jscomp.polyfill(
42-
'Int16Array.prototype.copyWithin', $jscomp.typedArrayCopyWithin, 'es6',
43-
'es5');
44-
$jscomp.polyfill(
45-
'Uint16Array.prototype.copyWithin', $jscomp.typedArrayCopyWithin, 'es6',
46-
'es5');
47-
$jscomp.polyfill(
48-
'Int32Array.prototype.copyWithin', $jscomp.typedArrayCopyWithin, 'es6',
49-
'es5');
50-
$jscomp.polyfill(
51-
'Uint32Array.prototype.copyWithin', $jscomp.typedArrayCopyWithin, 'es6',
52-
'es5');
53-
$jscomp.polyfill(
54-
'Float32Array.prototype.copyWithin', $jscomp.typedArrayCopyWithin, 'es6',
55-
'es5');
56-
$jscomp.polyfill(
57-
'Float64Array.prototype.copyWithin', $jscomp.typedArrayCopyWithin, 'es6',
58-
'es5');
32+
$jscomp.polyfillTypedArrayMethod(
33+
'copyWithin', $jscomp.typedArrayCopyWithin, 'es6', 'es5');

src/com/google/javascript/jscomp/js/es6/typedarray/fill.js

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,5 @@ $jscomp.typedArrayFill = function(orig) {
2929
return Array.prototype.fill;
3030
};
3131

32-
$jscomp.polyfill(
33-
'Int8Array.prototype.fill', $jscomp.typedArrayFill, 'es6', 'es5');
34-
$jscomp.polyfill(
35-
'Uint8Array.prototype.fill', $jscomp.typedArrayFill, 'es6', 'es5');
36-
$jscomp.polyfill(
37-
'Uint8ClampedArray.prototype.fill', $jscomp.typedArrayFill, 'es6', 'es5');
38-
$jscomp.polyfill(
39-
'Int16Array.prototype.fill', $jscomp.typedArrayFill, 'es6', 'es5');
40-
$jscomp.polyfill(
41-
'Uint16Array.prototype.fill', $jscomp.typedArrayFill, 'es6', 'es5');
42-
$jscomp.polyfill(
43-
'Int32Array.prototype.fill', $jscomp.typedArrayFill, 'es6', 'es5');
44-
$jscomp.polyfill(
45-
'Uint32Array.prototype.fill', $jscomp.typedArrayFill, 'es6', 'es5');
46-
$jscomp.polyfill(
47-
'Float32Array.prototype.fill', $jscomp.typedArrayFill, 'es6', 'es5');
48-
$jscomp.polyfill(
49-
'Float64Array.prototype.fill', $jscomp.typedArrayFill, 'es6', 'es5');
32+
$jscomp.polyfillTypedArrayMethod(
33+
'fill', $jscomp.typedArrayFill, 'es6', 'es5');

src/com/google/javascript/jscomp/js/es6/typedarray/findlast.js

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -46,36 +46,5 @@ $jscomp.typedArrayFindLast = function(orig) {
4646
return polyfill;
4747
};
4848

49-
$jscomp.polyfill(
50-
'BigInt64Array.prototype.findLast', $jscomp.typedArrayFindLast, 'es_next',
51-
'es_2020');
52-
$jscomp.polyfill(
53-
'BigUint64Array.prototype.findLast', $jscomp.typedArrayFindLast, 'es_next',
54-
'es_2020');
55-
$jscomp.polyfill(
56-
'Int8Array.prototype.findLast', $jscomp.typedArrayFindLast, 'es_next',
57-
'es5');
58-
$jscomp.polyfill(
59-
'Uint8Array.prototype.findLast', $jscomp.typedArrayFindLast, 'es_next',
60-
'es5');
61-
$jscomp.polyfill(
62-
'Uint8ClampedArray.prototype.findLast', $jscomp.typedArrayFindLast,
63-
'es_next', 'es5');
64-
$jscomp.polyfill(
65-
'Int16Array.prototype.findLast', $jscomp.typedArrayFindLast, 'es_next',
66-
'es5');
67-
$jscomp.polyfill(
68-
'Uint16Array.prototype.findLast', $jscomp.typedArrayFindLast, 'es_next',
69-
'es5');
70-
$jscomp.polyfill(
71-
'Int32Array.prototype.findLast', $jscomp.typedArrayFindLast, 'es_next',
72-
'es5');
73-
$jscomp.polyfill(
74-
'Uint32Array.prototype.findLast', $jscomp.typedArrayFindLast, 'es_next',
75-
'es5');
76-
$jscomp.polyfill(
77-
'Float32Array.prototype.findLast', $jscomp.typedArrayFindLast, 'es_next',
78-
'es5');
79-
$jscomp.polyfill(
80-
'Float64Array.prototype.findLast', $jscomp.typedArrayFindLast, 'es_next',
81-
'es5');
49+
$jscomp.polyfillTypedArrayMethod(
50+
'findLast', $jscomp.typedArrayFindLast, 'es_next', 'es5');

0 commit comments

Comments
 (0)