Avoid modifying the set returned by getInterceptorsOn()
The returned set is shared.
This program generates a broken short-circuit interceptor ($n -> $din) due to modifying the cached shared set {n} to {d,i,n}
--------
J.toInt$0$n = function(receiver) {
return J.getInterceptor$din(receiver).toInt$0(receiver);
};
--------
import 'package:expect/expect.dart';
@NoInline()
@AssumeDynamic()
confuse(x) => x;
@NoInline()
foo(x) {
print(x.toInt());
bar(x);
}
@NoInline()
bar(x) {
print(x.toInt());
print(x.runtimeType);
}
main() {
int i = confuse(1);
foo(i);
double d = confuse(2.3);
foo(d);
}
--------
TBR=sigmund@google.com
Review URL: https://codereview.chromium.org/2215133003 .
diff --git a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
index 3249c31..6a5c82d 100644
--- a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
+++ b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
@@ -232,17 +232,24 @@
if (interceptedClasses.contains(helpers.jsNumberClass) &&
!(interceptedClasses.contains(helpers.jsDoubleClass) ||
interceptedClasses.contains(helpers.jsIntClass))) {
+ Set<ClassElement> required;
for (HInstruction user in node.usedBy) {
if (user is! HInvoke) continue;
Set<ClassElement> intercepted =
backend.getInterceptedClassesOn(user.selector.name);
if (intercepted.contains(helpers.jsIntClass)) {
- interceptedClasses.add(helpers.jsIntClass);
+ required ??= new Set<ClassElement>();
+ required.add(helpers.jsIntClass);
}
if (intercepted.contains(helpers.jsDoubleClass)) {
- interceptedClasses.add(helpers.jsDoubleClass);
+ required ??= new Set<ClassElement>();
+ required.add(helpers.jsDoubleClass);
}
}
+ // Don't modify the result of [backend.getInterceptedClassesOn].
+ if (required != null) {
+ interceptedClasses = interceptedClasses.union(required);
+ }
}
} else {
interceptedClasses = new Set<ClassElement>();