Advanced tracking of field initialization
Change-Id: I8c8edb517bc3a3805ac0d72388f4e5c7fc34247f
Reviewed-on: https://dart-review.googlesource.com/c/93680
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/js_backend/field_analysis.dart b/pkg/compiler/lib/src/js_backend/field_analysis.dart
index 8489a25..33cb6c5 100644
--- a/pkg/compiler/lib/src/js_backend/field_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/field_analysis.dart
@@ -37,7 +37,7 @@
class KFieldAnalysis implements FieldAnalysis {
final KernelToElementMap _elementMap;
- final Map<KField, AllocatorData> _fixedInitializers = {};
+ final Map<KClass, ClassData> _classData = {};
KFieldAnalysis(KernelFrontEndStrategy kernelStrategy)
: _elementMap = kernelStrategy.elementMap;
@@ -47,22 +47,27 @@
void registerInstantiatedClass(KClass class_) {
ir.Class classNode = _elementMap.getClassNode(class_);
- Map<ir.Field, AllocatorData> fieldData = {};
+ List<KConstructor> constructors = [];
+ Map<KField, AllocatorData> fieldData = {};
for (ir.Field field in classNode.fields) {
if (!field.isInstanceMember) continue;
+
+ FieldEntity fieldElement = _elementMap.getField(field);
ir.Expression expression = field.initializer;
ConstantValue value = _elementMap.getConstantValue(expression,
requireConstant: false, implicitNull: true);
if (value != null && value.isConstant) {
- fieldData[field] = new AllocatorData(value);
+ fieldData[fieldElement] = new AllocatorData(value);
}
}
for (ir.Constructor constructor in classNode.constructors) {
KConstructor constructorElement = _elementMap.getConstructor(constructor);
+ constructors.add(constructorElement);
for (ir.Initializer initializer in constructor.initializers) {
if (initializer is ir.FieldInitializer) {
- AllocatorData data = fieldData[initializer.field];
+ AllocatorData data =
+ fieldData[_elementMap.getField(initializer.field)];
if (data == null) {
// TODO(johnniwinther): Support initializers with side-effects?
@@ -111,13 +116,19 @@
}
}
- fieldData.forEach((ir.Field fieldNode, AllocatorData data) {
- _fixedInitializers[_elementMap.getField(fieldNode)] = data;
- });
+ _classData[class_] = new ClassData(constructors, fieldData);
}
- AllocatorData getFixedInitializerForTesting(KField field) =>
- _fixedInitializers[field];
+ AllocatorData getFixedInitializerForTesting(KField field) {
+ return _classData[field.enclosingClass].fieldData[field];
+ }
+}
+
+class ClassData {
+ final List<KConstructor> constructors;
+ final Map<KField, AllocatorData> fieldData;
+
+ ClassData(this.constructors, this.fieldData);
}
class AllocatorData {
@@ -159,7 +170,7 @@
name = null,
value = null;
- String shortText() {
+ String get shortText {
switch (kind) {
case InitializerKind.direct:
return value.toStructuredText();
@@ -172,6 +183,8 @@
}
throw new UnsupportedError('Unexpected kind $kind');
}
+
+ String toString() => shortText;
}
class JFieldAnalysis implements FieldAnalysis {
@@ -223,41 +236,103 @@
!closedWorld.nativeData.isNativeMember(field);
}
- closedWorld.fieldAnalysis._fixedInitializers
- .forEach((KField kField, AllocatorData data) {
- JField jField = map.toBackendMember(kField);
- if (jField == null) {
- return;
- }
-
- // TODO(johnniwinther): Should elided static fields be removed from the
- // J model? Static setters might still assign to them.
-
- MemberUsage memberUsage = closedWorld.liveMemberUsage[kField];
- if (!memberUsage.hasRead) {
- if (canBeElided(kField)) {
- elidedFields.add(jField);
+ closedWorld.fieldAnalysis._classData
+ .forEach((ClassEntity cls, ClassData classData) {
+ classData.fieldData.forEach((KField kField, AllocatorData data) {
+ JField jField = map.toBackendMember(kField);
+ if (jField == null) {
+ return;
}
- } else {
- // TODO(johnniwinther): Use liveness of constructors and elided optional
- // parameters to recognize more constant initializers.
- if (data.initialValue != null && data.initializers.isEmpty) {
- ConstantValue value = map.toBackendConstant(data.initialValue);
- assert(value != null);
- if (!memberUsage.hasWrite && canBeElided(kField)) {
+
+ // TODO(johnniwinther): Should elided static fields be removed from the
+ // J model? Static setters might still assign to them.
+
+ MemberUsage memberUsage = closedWorld.liveMemberUsage[kField];
+ if (!memberUsage.hasRead) {
+ if (canBeElided(kField)) {
elidedFields.add(jField);
- effectivelyConstantFields[jField] = value;
- } else if (value.isNull ||
- value.isInt ||
- value.isBool ||
- value.isString) {
- // TODO(johnniwinther,sra): Support non-primitive constants in
- // allocators when it does cause allocators to deoptimized because
- // of deferred loading.
- fixedInitializers[jField] = value;
+ }
+ } else {
+ // TODO(johnniwinther): Use liveness of constructors and elided optional
+ // parameters to recognize more constant initializers.
+ if (data.initialValue != null) {
+ ConstantValue initialValue;
+ bool isTooComplex = false;
+
+ void includeInitialValue(ConstantValue value) {
+ if (isTooComplex) return;
+ if (initialValue == null) {
+ initialValue = value;
+ } else if (initialValue != value) {
+ initialValue = null;
+ isTooComplex = true;
+ }
+ }
+
+ bool inAllConstructors = true;
+ for (KConstructor constructor in classData.constructors) {
+ if (isTooComplex) {
+ break;
+ }
+
+ MemberUsage constructorUsage =
+ closedWorld.liveMemberUsage[constructor];
+ if (constructorUsage == null) return;
+ ParameterStructure invokedParameters =
+ constructorUsage.invokedParameters;
+
+ Initializer initializer = data.initializers[constructor];
+ if (initializer == null) {
+ inAllConstructors = false;
+ } else {
+ switch (initializer.kind) {
+ case InitializerKind.direct:
+ includeInitialValue(initializer.value);
+ break;
+ case InitializerKind.positional:
+ if (initializer.index >=
+ invokedParameters.positionalParameters) {
+ includeInitialValue(initializer.value);
+ } else {
+ isTooComplex = true;
+ }
+ break;
+ case InitializerKind.named:
+ if (!invokedParameters.namedParameters
+ .contains(initializer.name)) {
+ includeInitialValue(initializer.value);
+ } else {
+ isTooComplex = true;
+ }
+ break;
+ case InitializerKind.complex:
+ isTooComplex = true;
+ break;
+ }
+ }
+ }
+ if (!inAllConstructors) {
+ includeInitialValue(data.initialValue);
+ }
+ if (!isTooComplex && initialValue != null) {
+ ConstantValue value = map.toBackendConstant(initialValue);
+ assert(value != null);
+ if (!memberUsage.hasWrite && canBeElided(kField)) {
+ elidedFields.add(jField);
+ effectivelyConstantFields[jField] = value;
+ } else if (value.isNull ||
+ value.isInt ||
+ value.isBool ||
+ value.isString) {
+ // TODO(johnniwinther,sra): Support non-primitive constants in
+ // allocators when it does cause allocators to deoptimized
+ // because of deferred loading.
+ fixedInitializers[jField] = value;
+ }
+ }
}
}
- }
+ });
});
// TODO(johnniwinther): Recognize effectively constant top level/static
diff --git a/tests/compiler/dart2js/codegen/expect_annotations2_test.dart b/tests/compiler/dart2js/codegen/expect_annotations2_test.dart
index 5b0ba5c..803520e 100644
--- a/tests/compiler/dart2js/codegen/expect_annotations2_test.dart
+++ b/tests/compiler/dart2js/codegen/expect_annotations2_test.dart
@@ -5,6 +5,7 @@
import "package:expect/expect.dart";
import "package:async_helper/async_helper.dart";
import 'package:compiler/compiler_new.dart';
+import 'package:compiler/src/commandline_options.dart';
import '../helpers/memory_compiler.dart';
const MEMORY_SOURCE_FILES = const {
@@ -15,6 +16,7 @@
foo(y) => 49912344 + y;
class A {
+ @pragma('dart2js:noElision')
var field;
@NoInline()
@@ -39,7 +41,9 @@
runTest() async {
OutputCollector collector = new OutputCollector();
await runCompiler(
- memorySourceFiles: MEMORY_SOURCE_FILES, outputProvider: collector);
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ outputProvider: collector,
+ options: [Flags.testMode]);
// Simply check that the constants of the small functions are still in the
// output, and that we don't see the result of constant folding.
String jsOutput = collector.getOutput('', OutputType.js);
diff --git a/tests/compiler/dart2js/codegen/model_data/effectively_constant_state.dart b/tests/compiler/dart2js/codegen/model_data/effectively_constant_state.dart
new file mode 100644
index 0000000..fc33c4b
--- /dev/null
+++ b/tests/compiler/dart2js/codegen/model_data/effectively_constant_state.dart
@@ -0,0 +1,92 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+enum Enum {
+ a,
+ b,
+ c,
+}
+
+/*element: tester1:params=0*/
+@pragma('dart2js:noInline')
+tester1() {}
+
+/*element: tester2:params=0*/
+@pragma('dart2js:noInline')
+tester2() {}
+
+/*element: tester3:params=0*/
+@pragma('dart2js:noInline')
+tester3() {}
+
+class Class {
+ /*element: Class.state1:elided*/
+ final int state1;
+
+ /*element: Class.state2:elided*/
+ final Enum state2;
+
+ Class({this.state1: 1, this.state2: Enum.c});
+
+ /*element: Class.method1a:calls=[tester2(0)],params=0*/
+ @pragma('dart2js:noInline')
+ method1a() {
+ if (state1 == 0) {
+ return tester1();
+ } else if (state1 == 1) {
+ return tester2();
+ } else if (state1 == 2) {
+ return tester3();
+ }
+ }
+
+ // TODO(johnniwinther): Inline switch cases with constant expressions.
+ /*element: Class.method1b:calls=[tester2(0)],params=0,switch*/
+ @pragma('dart2js:noInline')
+ method1b() {
+ switch (state1) {
+ case 0:
+ return tester1();
+ case 1:
+ return tester2();
+ case 2:
+ return tester3();
+ }
+ }
+
+ /*element: Class.method2a:calls=[tester3(0)],params=0*/
+ @pragma('dart2js:noInline')
+ method2a() {
+ if (state2 == Enum.a) {
+ return tester1();
+ } else if (state2 == Enum.b) {
+ return tester2();
+ } else if (state2 == Enum.c) {
+ return tester3();
+ }
+ }
+
+ /*element: Class.method2b:calls=[tester1(0),tester2(0),tester3(0)],params=0,switch*/
+ @pragma('dart2js:noInline')
+ method2b() {
+ // TODO(johnniwinther): Eliminate dead code in enum switch.
+ switch (state2) {
+ case Enum.a:
+ return tester1();
+ case Enum.b:
+ return tester2();
+ case Enum.c:
+ return tester3();
+ }
+ }
+}
+
+/*element: main:calls=*,params=0*/
+main() {
+ var c = new Class();
+ c.method1a();
+ c.method1b();
+ c.method2a();
+ c.method2b();
+}
diff --git a/tests/compiler/dart2js/codegen/model_test.dart b/tests/compiler/dart2js/codegen/model_test.dart
index 974ca4a..7e1262d 100644
--- a/tests/compiler/dart2js/codegen/model_test.dart
+++ b/tests/compiler/dart2js/codegen/model_test.dart
@@ -64,6 +64,7 @@
static const String assignment = 'assign';
static const String isLazy = 'lazy';
static const String propertyAccess = 'access';
+ static const String switchCase = 'switch';
}
/// AST visitor for computing inference data for a member.
@@ -222,6 +223,11 @@
features.addElement(Tags.propertyAccess, '${name}');
}
});
+
+ forEachNode(code, onSwitch: (js.Switch node) {
+ features.add(Tags.switchCase);
+ });
+
return features;
}
}
diff --git a/tests/compiler/dart2js/field_analysis/jdata/effectively_constant_state.dart b/tests/compiler/dart2js/field_analysis/jdata/effectively_constant_state.dart
new file mode 100644
index 0000000..84f532e
--- /dev/null
+++ b/tests/compiler/dart2js/field_analysis/jdata/effectively_constant_state.dart
@@ -0,0 +1,82 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+enum Enum {
+ a,
+ b,
+ c,
+}
+
+@pragma('dart2js:noInline')
+tester1() {}
+
+@pragma('dart2js:noInline')
+tester2() {}
+
+@pragma('dart2js:noInline')
+tester3() {}
+
+class Class {
+ /*element: Class.state1:constant=IntConstant(1)*/
+ final int state1;
+
+ /*element: Class.state2:constant=ConstructedConstant(Enum(_name=StringConstant("Enum.c"),index=IntConstant(2)))*/
+ final Enum state2;
+
+ Class({this.state1: 1, this.state2: Enum.c});
+
+ @pragma('dart2js:noInline')
+ method1a() {
+ if (state1 == 0) {
+ return tester1();
+ } else if (state1 == 1) {
+ return tester2();
+ } else if (state1 == 2) {
+ return tester3();
+ }
+ }
+
+ @pragma('dart2js:noInline')
+ method1b() {
+ switch (state1) {
+ case 0:
+ return tester1();
+ case 1:
+ return tester2();
+ case 2:
+ return tester3();
+ }
+ }
+
+ @pragma('dart2js:noInline')
+ method2a() {
+ if (state2 == Enum.a) {
+ return tester1();
+ } else if (state2 == Enum.b) {
+ return tester2();
+ } else if (state2 == Enum.c) {
+ return tester3();
+ }
+ }
+
+ @pragma('dart2js:noInline')
+ method2b() {
+ switch (state2) {
+ case Enum.a:
+ return tester1();
+ case Enum.b:
+ return tester2();
+ case Enum.c:
+ return tester3();
+ }
+ }
+}
+
+main() {
+ var c = new Class();
+ c.method1a();
+ c.method1b();
+ c.method2a();
+ c.method2b();
+}
diff --git a/tests/compiler/dart2js/field_analysis/jdata/multi_initializers.dart b/tests/compiler/dart2js/field_analysis/jdata/multi_initializers.dart
index d72731d..f7d423f 100644
--- a/tests/compiler/dart2js/field_analysis/jdata/multi_initializers.dart
+++ b/tests/compiler/dart2js/field_analysis/jdata/multi_initializers.dart
@@ -4,21 +4,30 @@
main() {
var c = new Class1.a();
+ c.field3a = null;
c.field4a = null;
+ c.field5a = null;
new Class1.b();
print(c.field1);
print(c.field2);
- print(c.field3);
+ print(c.field3a);
+ print(c.field3b);
print(c.field4a);
print(c.field4b);
- print(c.field5);
+ print(c.field5a);
+ print(c.field5b);
}
class Class1 {
var field1 = 0;
var field2;
- var field3;
+
+ /*element: Class1.field3a:initial=IntConstant(3)*/
+ var field3a;
+
+ /*element: Class1.field3b:constant=IntConstant(3)*/
+ var field3b;
/*element: Class1.field4a:initial=IntConstant(4)*/
var field4a = 4;
@@ -26,16 +35,24 @@
/*element: Class1.field4b:constant=IntConstant(4)*/
var field4b = 4;
- var field5 = 5;
+ /*element: Class1.field5a:initial=IntConstant(5)*/
+ var field5a = 5;
+
+ /*element: Class1.field5b:constant=IntConstant(5)*/
+ var field5b = 5;
Class1.a()
: field1 = 1,
field2 = 1,
- field3 = 3,
- field5 = 5;
+ field3a = 3,
+ field3b = 3,
+ field5a = 5,
+ field5b = 5;
Class1.b()
: field2 = 2,
- field3 = 3,
- field5 = 5;
+ field3a = 3,
+ field3b = 3,
+ field5a = 5,
+ field5b = 5;
}
diff --git a/tests/compiler/dart2js/field_analysis/jdata/optional_parameters.dart b/tests/compiler/dart2js/field_analysis/jdata/optional_parameters.dart
index cad9372..2f63ffb 100644
--- a/tests/compiler/dart2js/field_analysis/jdata/optional_parameters.dart
+++ b/tests/compiler/dart2js/field_analysis/jdata/optional_parameters.dart
@@ -3,24 +3,85 @@
// BSD-style license that can be found in the LICENSE file.
main() {
- new Class1(0);
- new Class1(0, 1);
- new Class2(0);
- new Class2(0, field2: 1);
+ var c1a = new Class1a(0);
+ new Class1a(0, 1);
+ c1a.field1 = null;
+ c1a.field2 = null;
+ c1a.field3 = null;
+ print(c1a.field1);
+ print(c1a.field2);
+ print(c1a.field3);
+
+ var c1b = new Class1b(0);
+ new Class1b(0, 1);
+ print(c1b.field1);
+ print(c1b.field2);
+ print(c1b.field3);
+
+ var c2a = new Class2a(0);
+ new Class2a(0, field2: 1);
+ c2a.field1 = null;
+ c2a.field2 = null;
+ c2a.field3 = null;
+ print(c2a.field1);
+ print(c2a.field2);
+ print(c2a.field3);
+
+ var c2b = new Class2b(0);
+ new Class2b(0, field2: 1);
+ print(c2b.field1);
+ print(c2b.field2);
+ print(c2b.field3);
}
-class Class1 {
+class Class1a {
+ /*element: Class1a.field1:*/
var field1;
+
+ /*element: Class1a.field2:*/
var field2;
+
+ /*element: Class1a.field3:initial=IntConstant(3)*/
var field3;
- Class1(this.field1, [this.field2 = 2, this.field3 = 3]);
+ Class1a(this.field1, [this.field2 = 2, this.field3 = 3]);
}
-class Class2 {
+class Class1b {
+ /*element: Class1b.field1:*/
var field1;
+
+ /*element: Class1b.field2:*/
var field2;
+
+ /*element: Class1b.field3:constant=IntConstant(3)*/
var field3;
- Class2(this.field1, {this.field2 = 2, this.field3 = 3});
+ Class1b(this.field1, [this.field2 = 2, this.field3 = 3]);
+}
+
+class Class2a {
+ /*element: Class2a.field1:*/
+ var field1;
+
+ /*element: Class2a.field2:*/
+ var field2;
+
+ /*element: Class2a.field3:initial=IntConstant(3)*/
+ var field3;
+
+ Class2a(this.field1, {this.field2 = 2, this.field3 = 3});
+}
+
+class Class2b {
+ /*element: Class2b.field1:*/
+ var field1;
+
+ /*element: Class2b.field2:*/
+ var field2;
+
+ /*element: Class2b.field3:constant=IntConstant(3)*/
+ var field3;
+
+ Class2b(this.field1, {this.field2 = 2, this.field3 = 3});
}
diff --git a/tests/compiler/dart2js/field_analysis/jdata/simple_initializers.dart b/tests/compiler/dart2js/field_analysis/jdata/simple_initializers.dart
index 0a5a612..a18580f 100644
--- a/tests/compiler/dart2js/field_analysis/jdata/simple_initializers.dart
+++ b/tests/compiler/dart2js/field_analysis/jdata/simple_initializers.dart
@@ -214,94 +214,94 @@
}
class Class2 {
- /*element: Class2.field1a:*/
+ /*element: Class2.field1a:initial=NullConstant*/
var field1a;
- /*element: Class2.field1b:*/
+ /*element: Class2.field1b:constant=NullConstant*/
var field1b;
- /*element: Class2.field2a:*/
+ /*element: Class2.field2a:initial=BoolConstant(true)*/
var field2a;
- /*element: Class2.field2b:*/
+ /*element: Class2.field2b:constant=BoolConstant(true)*/
var field2b;
- /*element: Class2.field3a:*/
+ /*element: Class2.field3a:initial=BoolConstant(false)*/
var field3a;
- /*element: Class2.field3b:*/
+ /*element: Class2.field3b:constant=BoolConstant(false)*/
var field3b;
- /*element: Class2.field4a:*/
+ /*element: Class2.field4a:initial=IntConstant(0)*/
var field4a;
- /*element: Class2.field4b:*/
+ /*element: Class2.field4b:constant=IntConstant(0)*/
var field4b;
- /*element: Class2.field5a:*/
+ /*element: Class2.field5a:initial=IntConstant(1)*/
var field5a;
- /*element: Class2.field5b:*/
+ /*element: Class2.field5b:constant=IntConstant(1)*/
var field5b;
- /*element: Class2.field6a:*/
+ /*element: Class2.field6a:initial=StringConstant("")*/
var field6a;
- /*element: Class2.field6b:*/
+ /*element: Class2.field6b:constant=StringConstant("")*/
var field6b;
- /*element: Class2.field7a:*/
+ /*element: Class2.field7a:initial=StringConstant("foo")*/
var field7a;
- /*element: Class2.field7b:*/
+ /*element: Class2.field7b:constant=StringConstant("foo")*/
var field7b;
/*element: Class2.field8a:*/
var field8a;
- /*element: Class2.field8b:*/
+ /*element: Class2.field8b:constant=DoubleConstant(0.5)*/
var field8b;
/*element: Class2.field9a:*/
var field9a;
- /*element: Class2.field9b:*/
+ /*element: Class2.field9b:constant=ListConstant([])*/
var field9b;
/*element: Class2.field9c:*/
var field9c;
- /*element: Class2.field9d:*/
+ /*element: Class2.field9d:constant=ListConstant(<int>[IntConstant(0), IntConstant(1), IntConstant(2)])*/
var field9d;
/*element: Class2.field10a:*/
var field10a;
- /*element: Class2.field10b:*/
+ /*element: Class2.field10b:constant=MapConstant({})*/
var field10b;
/*element: Class2.field10c:*/
var field10c;
- /*element: Class2.field10d:*/
+ /*element: Class2.field10d:constant=MapConstant(<int, int>{IntConstant(0): IntConstant(1), IntConstant(2): IntConstant(3), IntConstant(4): IntConstant(5)})*/
var field10d;
/*element: Class2.field11a:*/
var field11a;
- /*element: Class2.field11b:*/
+ /*element: Class2.field11b:constant=ConstructedConstant(Symbol(_name=StringConstant("foo")))*/
var field11b;
- /*element: Class2.field12a:*/
+ /*element: Class2.field12a:initial=IntConstant(5)*/
var field12a;
- /*element: Class2.field12b:*/
+ /*element: Class2.field12b:constant=IntConstant(5)*/
var field12b;
- /*element: Class2.field13a:*/
+ /*element: Class2.field13a:initial=BoolConstant(true)*/
var field13a;
- /*element: Class2.field13b:*/
+ /*element: Class2.field13b:constant=BoolConstant(true)*/
var field13b;
Class2()
diff --git a/tests/compiler/dart2js/field_analysis/kfield_analysis_test.dart b/tests/compiler/dart2js/field_analysis/kfield_analysis_test.dart
index fbc8b7e..124ff4c 100644
--- a/tests/compiler/dart2js/field_analysis/kfield_analysis_test.dart
+++ b/tests/compiler/dart2js/field_analysis/kfield_analysis_test.dart
@@ -47,7 +47,7 @@
}
data.initializers.forEach((constructor, value) {
features['${constructor.enclosingClass.name}.${constructor.name}'] =
- value?.shortText();
+ value?.shortText;
});
}
Id id = computeEntityId(node);
diff --git a/tests/compiler/dart2js/helpers/program_lookup.dart b/tests/compiler/dart2js/helpers/program_lookup.dart
index cac728c..ccbf049 100644
--- a/tests/compiler/dart2js/helpers/program_lookup.dart
+++ b/tests/compiler/dart2js/helpers/program_lookup.dart
@@ -227,11 +227,13 @@
void forEachNode(js.Node root,
{void Function(js.Call) onCall,
void Function(js.PropertyAccess) onPropertyAccess,
- void Function(js.Assignment) onAssignment}) {
+ void Function(js.Assignment) onAssignment,
+ void Function(js.Switch) onSwitch}) {
CallbackVisitor visitor = new CallbackVisitor(
onCall: onCall,
onPropertyAccess: onPropertyAccess,
- onAssignment: onAssignment);
+ onAssignment: onAssignment,
+ onSwitch: onSwitch);
root.accept(visitor);
}
@@ -239,8 +241,10 @@
final void Function(js.Call) onCall;
final void Function(js.PropertyAccess) onPropertyAccess;
final void Function(js.Assignment) onAssignment;
+ final void Function(js.Switch) onSwitch;
- CallbackVisitor({this.onCall, this.onPropertyAccess, this.onAssignment});
+ CallbackVisitor(
+ {this.onCall, this.onPropertyAccess, this.onAssignment, this.onSwitch});
@override
visitCall(js.Call node) {
@@ -259,4 +263,10 @@
if (onAssignment != null) onAssignment(node);
return super.visitAssignment(node);
}
+
+ @override
+ visitSwitch(js.Switch node) {
+ if (onSwitch != null) onSwitch(node);
+ return super.visitSwitch(node);
+ }
}
diff --git a/tests/compiler/dart2js/inlining/meta_annotations2_test.dart b/tests/compiler/dart2js/inlining/meta_annotations2_test.dart
index 27e0277..d809601 100644
--- a/tests/compiler/dart2js/inlining/meta_annotations2_test.dart
+++ b/tests/compiler/dart2js/inlining/meta_annotations2_test.dart
@@ -7,6 +7,7 @@
import "package:expect/expect.dart";
import "package:async_helper/async_helper.dart";
import 'package:compiler/compiler_new.dart';
+import 'package:compiler/src/commandline_options.dart';
import '../helpers/memory_compiler.dart';
const MEMORY_SOURCE_FILES = const {
@@ -17,6 +18,7 @@
foo(y) => 49912344 + y;
class A {
+ @pragma('dart2js:noElision')
var field;
@noInline
@@ -41,7 +43,9 @@
runTests() async {
OutputCollector collector = new OutputCollector();
await runCompiler(
- memorySourceFiles: MEMORY_SOURCE_FILES, outputProvider: collector);
+ memorySourceFiles: MEMORY_SOURCE_FILES,
+ outputProvider: collector,
+ options: [Flags.testMode]);
// Simply check that the constants of the small functions are still in the
// output, and that we don't see the result of constant folding.
String jsOutput = collector.getOutput('', OutputType.js);