Index: pkg/compiler/lib/src/ssa/builder_kernel.dart |
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart |
index 597d6fa9a55ef78c336b36dad2bf14199f7a9a31..60fda9d01b2ad6d19493b83e39f353a42f8f884e 100644 |
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart |
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart |
@@ -32,7 +32,7 @@ import '../tree/nodes.dart' show Node; |
import '../types/masks.dart'; |
import '../universe/selector.dart'; |
import '../universe/side_effects.dart' show SideEffects; |
-import '../universe/use.dart' show DynamicUse; |
+import '../universe/use.dart' show ConstantUse, DynamicUse; |
import '../universe/world_builder.dart' show CodegenWorldBuilder; |
import '../world.dart'; |
import 'graph_builder.dart'; |
@@ -145,6 +145,7 @@ class KernelSsaGraphBuilder extends ir.Visitor |
} |
buildField(target); |
} else if (target is ir.Constructor) { |
+ _targetFunction = (target as ir.Constructor).function; |
if (targetElement is ConstructorBodyEntity) { |
buildConstructorBody(target); |
} else { |
@@ -161,10 +162,43 @@ class KernelSsaGraphBuilder extends ir.Visitor |
'$target for $targetElement'; |
} |
assert(graph.isValid()); |
+ if (_targetFunction != null) { |
+ _ensureDefaultArgumentValues(_targetFunction); |
+ } |
return graph; |
}); |
} |
+ void _ensureDefaultArgumentValues(ir.FunctionNode function) { |
+ // Register all [function]'s default argument values. |
+ // |
+ // Default values might be (or contain) functions that are not referenced |
+ // from anywhere else so we need to ensure these are enqueued. Stubs and |
+ // `Function.apply` data are created after the codegen queue is closed, so |
+ // we force these functions into the queue by registering the constants as |
+ // used in advance. See language/cyclic_default_values_test.dart for an |
+ // example. |
+ // |
+ // TODO(sra): We could be more precise if stubs and `Function.apply` data |
+ // were generated by the codegen enqueuer. In practice even in huge programs |
+ // there are only very small number of constants created here that are not |
+ // actually used. |
+ void registerDefaultValue(ir.VariableDeclaration node) { |
+ ConstantValue constantValue = |
+ _elementMap.getConstantValue(node.initializer, implicitNull: true); |
+ assert( |
+ constantValue != null, |
+ failedAt(_elementMap.getMethod(function.parent), |
+ 'No constant computed for $node')); |
+ registry?.registerConstantUse(new ConstantUse.init(constantValue)); |
+ } |
+ |
+ function.positionalParameters |
+ .skip(function.requiredParameterCount) |
+ .forEach(registerDefaultValue); |
+ function.namedParameters.forEach(registerDefaultValue); |
+ } |
+ |
@override |
ConstantValue getFieldInitialConstantValue(FieldEntity field) { |
assert(field == targetElement); |