Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/compile_time_constants.dart

Issue 221873002: Compute frontend/backend specific constants. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fixes Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart2js; 5 part of dart2js;
6 6
7 /// A [ConstantEnvironment] provides access for constants compiled for variable
8 /// initializers.
9 abstract class ConstantEnvironment {
10 /// Returns the constant for the initializer of [element].
11 Constant getConstantForVariable(VariableElement element);
12 }
13
14 /// A class that can compile and provide constants for variables, nodes and
15 /// metadata.
16 abstract class ConstantCompiler extends ConstantEnvironment {
17 /// Compiles the compile-time constant for the initializer of [element], or
18 /// reports an error if the initializer is not a compile-time constant.
19 ///
20 /// Depending on implementation, the constant compiler might also compute
21 /// the compile-time constant for the backend interpretation of constants.
22 ///
23 /// The returned constant is always of the frontend interpretation.
24 Constant compileConstant(VariableElement element);
25
26 /// Computes the compile-time constant for the variable initializer,
27 /// if possible.
28 void compileVariable(VariableElement element);
29
30 /// Compiles the compile-time constant for [node], or reports an error if
31 /// [node] is not a compile-time constant.
32 ///
33 /// Depending on implementation, the constant compiler might also compute
34 /// the compile-time constant for the backend interpretation of constants.
35 ///
36 /// The returned constant is always of the frontend interpretation.
37 Constant compileNode(Node node, TreeElements elements);
38
39 /// Compiles the compile-time constant for the value [metadata], or reports an
40 /// error if the value is not a compile-time constant.
41 ///
42 /// Depending on implementation, the constant compiler might also compute
43 /// the compile-time constant for the backend interpretation of constants.
44 ///
45 /// The returned constant is always of the frontend interpretation.
46 Constant compileMetadata(MetadataAnnotation metadata,
47 Node node, TreeElements elements);
48 }
49
50 /// A [BackendConstantEnvironment] provides access to constants needed for
51 /// backend implementation.
52 abstract class BackendConstantEnvironment extends ConstantEnvironment {
53 /// Returns the compile-time constant associated with [node].
54 ///
55 /// Depending on implementation, the constant might be stored in [elements].
56 Constant getConstantForNode(Node node, TreeElements elements);
57
58 /// Returns the compile-time constant value of [metadata].
59 Constant getConstantForMetadata(MetadataAnnotation metadata);
60 }
61
62 /// Interface for the task that compiles the constant environments for the
63 /// frontend and backend interpretation of compile-time constants.
64 abstract class ConstantCompilerTask extends CompilerTask
65 implements ConstantCompiler {
66 ConstantCompilerTask(Compiler compiler) : super(compiler);
67 }
68
7 /** 69 /**
8 * The [ConstantHandler] keeps track of compile-time constants, 70 * The [ConstantCompilerBase] is provides base implementation for compilation of
9 * initializations of global and static fields, and default values of 71 * compile-time constants for both the Dart and JavaScript interpretation of
10 * optional parameters. 72 * constants. It keeps track of compile-time constants for initializations of
73 * global and static fields, and default values of optional parameters.
11 */ 74 */
12 class ConstantHandler extends CompilerTask { 75 abstract class ConstantCompilerBase implements ConstantCompiler {
76 final Compiler compiler;
13 final ConstantSystem constantSystem; 77 final ConstantSystem constantSystem;
14 final bool isMetadata;
15 78
16 /** 79 /**
17 * Contains the initial value of fields. Must contain all static and global 80 * Contains the initial value of fields. Must contain all static and global
18 * initializations of const fields. May contain eagerly compiled values for 81 * initializations of const fields. May contain eagerly compiled values for
19 * statics and instance fields. 82 * statics and instance fields.
20 * 83 *
21 * Invariant: The keys in this map are declarations. 84 * Invariant: The keys in this map are declarations.
22 */ 85 */
23 final Map<VariableElement, Constant> initialVariableValues; 86 final Map<VariableElement, Constant> initialVariableValues =
24 87 new Map<VariableElement, Constant>();
25 /** Set of all registered compiled constants. */
26 final Set<Constant> compiledConstants;
27 88
28 /** The set of variable elements that are in the process of being computed. */ 89 /** The set of variable elements that are in the process of being computed. */
29 final Set<VariableElement> pendingVariables; 90 final Set<VariableElement> pendingVariables = new Set<VariableElement>();
30 91
31 /** Caches the statics where the initial value cannot be eagerly compiled. */ 92 ConstantCompilerBase(this.compiler, this.constantSystem);
32 final Set<VariableElement> lazyStatics;
33
34 ConstantHandler(Compiler compiler, this.constantSystem,
35 { bool this.isMetadata: false })
36 : initialVariableValues = new Map<VariableElement, dynamic>(),
37 compiledConstants = new Set<Constant>(),
38 pendingVariables = new Set<VariableElement>(),
39 lazyStatics = new Set<VariableElement>(),
40 super(compiler);
41
42 String get name => 'ConstantHandler';
43
44 void addCompileTimeConstantForEmission(Constant constant) {
45 compiledConstants.add(constant);
46 }
47 93
48 Constant getConstantForVariable(VariableElement element) { 94 Constant getConstantForVariable(VariableElement element) {
49 return initialVariableValues[element.declaration]; 95 return initialVariableValues[element.declaration];
50 } 96 }
51 97
52 /**
53 * Returns a compile-time constant, or reports an error if the element is not
54 * a compile-time constant.
55 */
56 Constant compileConstant(VariableElement element) { 98 Constant compileConstant(VariableElement element) {
57 return compileVariable(element, isConst: true); 99 return compileVariable(element, isConst: true);
58 } 100 }
59 101
60 /**
61 * Returns the a compile-time constant if the variable could be compiled
62 * eagerly. Otherwise returns `null`.
63 */
64 Constant compileVariable(VariableElement element, {bool isConst: false}) { 102 Constant compileVariable(VariableElement element, {bool isConst: false}) {
65 return measure(() { 103
66 if (initialVariableValues.containsKey(element.declaration)) { 104 if (initialVariableValues.containsKey(element.declaration)) {
67 Constant result = initialVariableValues[element.declaration]; 105 Constant result = initialVariableValues[element.declaration];
68 return result; 106 return result;
69 } 107 }
70 Element currentElement = element; 108 Element currentElement = element;
71 if (element.isParameter() 109 if (element.isParameter() ||
72 || element.isFieldParameter() 110 element.isFieldParameter() ||
73 || element.isVariable()) { 111 element.isVariable()) {
74 currentElement = element.enclosingElement; 112 currentElement = element.enclosingElement;
75 } 113 }
76 return compiler.withCurrentElement(currentElement, () { 114 return compiler.withCurrentElement(currentElement, () {
77 TreeElements definitions = 115 TreeElements definitions =
78 compiler.analyzeElement(currentElement.declaration); 116 compiler.analyzeElement(currentElement.declaration);
79 Constant constant = compileVariableWithDefinitions( 117 Constant constant = compileVariableWithDefinitions(
80 element, definitions, isConst: isConst); 118 element, definitions, isConst: isConst);
81 return constant; 119 return constant;
82 });
83 }); 120 });
84 } 121 }
85 122
86 /** 123 /**
87 * Returns the a compile-time constant if the variable could be compiled 124 * Returns the a compile-time constant if the variable could be compiled
88 * eagerly. If the variable needs to be initialized lazily returns `null`. 125 * eagerly. If the variable needs to be initialized lazily returns `null`.
89 * If the variable is `const` but cannot be compiled eagerly reports an 126 * If the variable is `const` but cannot be compiled eagerly reports an
90 * error. 127 * error.
91 */ 128 */
92 Constant compileVariableWithDefinitions(VariableElement element, 129 Constant compileVariableWithDefinitions(VariableElement element,
93 TreeElements definitions, 130 TreeElements definitions,
94 {bool isConst: false}) { 131 {bool isConst: false}) {
95 return measure(() { 132 Node node = element.parseNode(compiler);
96 if (!isConst && lazyStatics.contains(element)) return null; 133 if (pendingVariables.contains(element)) {
134 if (isConst) {
135 compiler.reportFatalError(
136 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS);
137 }
138 return null;
139 }
140 pendingVariables.add(element);
97 141
98 Node node = element.parseNode(compiler); 142 Expression initializer = element.initializer;
99 if (pendingVariables.contains(element)) { 143 Constant value;
100 if (isConst) { 144 if (initializer == null) {
101 compiler.reportFatalError( 145 // No initial value.
102 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); 146 value = new NullConstant();
147 } else {
148 value = compileNodeWithDefinitions(
149 initializer, definitions, isConst: isConst);
150 if (compiler.enableTypeAssertions &&
151 value != null &&
152 element.isField()) {
153 DartType elementType = element.type;
154 if (elementType.kind == TypeKind.MALFORMED_TYPE && !value.isNull) {
155 if (isConst) {
156 ErroneousElement element = elementType.element;
157 compiler.reportFatalError(
158 node, element.messageKind, element.messageArguments);
159 } else {
160 // We need to throw an exception at runtime.
161 value = null;
162 }
103 } else { 163 } else {
104 lazyStatics.add(element); 164 DartType constantType = value.computeType(compiler);
105 return null; 165 if (!constantSystem.isSubtype(compiler,
106 } 166 constantType, elementType)) {
107 }
108 pendingVariables.add(element);
109
110 Expression initializer = element.initializer;
111 Constant value;
112 if (initializer == null) {
113 // No initial value.
114 value = new NullConstant();
115 } else {
116 value = compileNodeWithDefinitions(
117 initializer, definitions, isConst: isConst);
118 if (compiler.enableTypeAssertions &&
119 value != null &&
120 element.isField()) {
121 DartType elementType = element.type;
122 if (elementType.kind == TypeKind.MALFORMED_TYPE && !value.isNull) {
123 if (isConst) { 167 if (isConst) {
124 ErroneousElement element = elementType.element;
125 compiler.reportFatalError( 168 compiler.reportFatalError(
126 node, element.messageKind, element.messageArguments); 169 node, MessageKind.NOT_ASSIGNABLE,
170 {'fromType': constantType, 'toType': elementType});
127 } else { 171 } else {
128 // We need to throw an exception at runtime. 172 // If the field cannot be lazily initialized, we will throw
173 // the exception at runtime.
129 value = null; 174 value = null;
130 } 175 }
131 } else {
132 DartType constantType = value.computeType(compiler);
133 if (!constantSystem.isSubtype(compiler,
134 constantType, elementType)) {
135 if (isConst) {
136 compiler.reportFatalError(
137 node, MessageKind.NOT_ASSIGNABLE,
138 {'fromType': constantType, 'toType': elementType});
139 } else {
140 // If the field cannot be lazily initialized, we will throw
141 // the exception at runtime.
142 value = null;
143 }
144 }
145 } 176 }
146 } 177 }
147 } 178 }
148 if (value != null) { 179 }
149 initialVariableValues[element.declaration] = value; 180 if (value != null) {
150 } else { 181 initialVariableValues[element.declaration] = value;
151 assert(!isConst); 182 } else {
152 lazyStatics.add(element); 183 assert(!isConst);
153 } 184 }
154 pendingVariables.remove(element); 185 pendingVariables.remove(element);
155 return value; 186 return value;
156 });
157 } 187 }
158 188
159 Constant compileNodeWithDefinitions(Node node, 189 Constant compileNodeWithDefinitions(Node node,
160 TreeElements definitions, 190 TreeElements definitions,
161 {bool isConst: false}) { 191 {bool isConst: true}) {
162 return measure(() { 192 assert(node != null);
163 assert(node != null); 193 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator(
164 Constant constant = definitions.getConstant(node); 194 this, definitions, compiler, isConst: isConst);
165 if (constant != null) { 195 return evaluator.evaluate(node);
166 return constant;
167 }
168 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator(
169 this, definitions, compiler, isConst: isConst);
170 constant = evaluator.evaluate(node);
171 if (constant != null) {
172 definitions.setConstant(node, constant);
173 }
174 return constant;
175 });
176 } 196 }
177 197
178 /** 198 Constant compileNode(Node node, TreeElements elements) {
179 * Returns an [Iterable] of static non final fields that need to be 199 return compileNodeWithDefinitions(node, elements);
180 * initialized. The fields list must be evaluated in order since they might
181 * depend on each other.
182 */
183 Iterable<VariableElement> getStaticNonFinalFieldsForEmission() {
184 return initialVariableValues.keys.where((element) {
185 return element.kind == ElementKind.FIELD
186 && !element.isInstanceMember()
187 && !element.modifiers.isFinal()
188 // The const fields are all either emitted elsewhere or inlined.
189 && !element.modifiers.isConst();
190 });
191 } 200 }
192 201
193 List<VariableElement> getLazilyInitializedFieldsForEmission() { 202 Constant compileMetadata(MetadataAnnotation metadata,
194 return new List<VariableElement>.from(lazyStatics); 203 Node node,
204 TreeElements elements) {
205 return compileNodeWithDefinitions(node, elements);
206 }
207 }
208
209 /// [ConstantCompiler] that uses the Dart semantics for the compile-time
210 /// constant evaluation.
211 class DartConstantCompiler extends ConstantCompilerBase {
212 DartConstantCompiler(Compiler compiler)
213 : super(compiler, const DartConstantSystem());
214
215 Constant getConstantForNode(Node node, TreeElements definitions) {
216 return definitions.getConstant(node);
195 } 217 }
196 218
197 /** 219 Constant getConstantForMetadata(MetadataAnnotation metadata) {
198 * Returns a list of constants topologically sorted so that dependencies 220 return metadata.value;
199 * appear before the dependent constant. [preSortCompare] is a comparator
200 * function that gives the constants a consistent order prior to the
201 * topological sort which gives the constants an ordering that is less
202 * sensitive to perturbations in the source code.
203 */
204 List<Constant> getConstantsForEmission([preSortCompare]) {
205 // We must emit dependencies before their uses.
206 Set<Constant> seenConstants = new Set<Constant>();
207 List<Constant> result = new List<Constant>();
208
209 void addConstant(Constant constant) {
210 if (!seenConstants.contains(constant)) {
211 constant.getDependencies().forEach(addConstant);
212 assert(!seenConstants.contains(constant));
213 result.add(constant);
214 seenConstants.add(constant);
215 }
216 }
217
218 List<Constant> sorted = compiledConstants.toList();
219 if (preSortCompare != null) {
220 sorted.sort(preSortCompare);
221 }
222 sorted.forEach(addConstant);
223 return result;
224 } 221 }
225 222
226 Constant getInitialValueFor(VariableElement element) { 223 Constant compileNodeWithDefinitions(Node node,
227 Constant initialValue = initialVariableValues[element.declaration]; 224 TreeElements definitions,
228 if (initialValue == null) { 225 {bool isConst: true}) {
229 compiler.internalError(element, "No initial value for given element."); 226 Constant constant = definitions.getConstant(node);
227 if (constant != null) {
228 return constant;
230 } 229 }
231 return initialValue; 230 constant =
231 super.compileNodeWithDefinitions(node, definitions, isConst: isConst);
232 if (constant != null) {
233 definitions.setConstant(node, constant);
234 }
235 return constant;
232 } 236 }
233 } 237 }
234 238
235 class CompileTimeConstantEvaluator extends Visitor { 239 class CompileTimeConstantEvaluator extends Visitor {
236 bool isEvaluatingConstant; 240 bool isEvaluatingConstant;
237 final ConstantHandler handler; 241 final ConstantCompilerBase handler;
238 final TreeElements elements; 242 final TreeElements elements;
239 final Compiler compiler; 243 final Compiler compiler;
240 244
241 CompileTimeConstantEvaluator(this.handler, 245 CompileTimeConstantEvaluator(this.handler,
242 this.elements, 246 this.elements,
243 this.compiler, 247 this.compiler,
244 {bool isConst: false}) 248 {bool isConst: false})
245 : this.isEvaluatingConstant = isConst; 249 : this.isEvaluatingConstant = isConst;
246 250
247 ConstantSystem get constantSystem => handler.constantSystem; 251 ConstantSystem get constantSystem => handler.constantSystem;
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 if (prefixNode != null) { 437 if (prefixNode != null) {
434 Element maybePrefix = elements[prefixNode.asIdentifier()]; 438 Element maybePrefix = elements[prefixNode.asIdentifier()];
435 if (maybePrefix != null && maybePrefix.isPrefix() && 439 if (maybePrefix != null && maybePrefix.isPrefix() &&
436 (maybePrefix as PrefixElement).isDeferred) { 440 (maybePrefix as PrefixElement).isDeferred) {
437 return true; 441 return true;
438 } 442 }
439 } 443 }
440 return false; 444 return false;
441 } 445 }
442 446
447 Constant visitIdentifier(Identifier node) {
448 Element element = elements[node];
449 if (Elements.isClass(element) || Elements.isTypedef(element)) {
450 return makeTypeConstant(element);
451 }
452 return signalNotCompileTimeConstant(node);
453 }
454
443 // TODO(floitsch): provide better error-messages. 455 // TODO(floitsch): provide better error-messages.
444 Constant visitSend(Send send) { 456 Constant visitSend(Send send) {
445 Element element = elements[send]; 457 Element element = elements[send];
446 if (send.isPropertyAccess) { 458 if (send.isPropertyAccess) {
447 if (isDeferredUse(send)) { 459 if (isDeferredUse(send)) {
448 return signalNotCompileTimeConstant(send, 460 return signalNotCompileTimeConstant(send,
449 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); 461 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT);
450 } 462 }
451 if (Elements.isStaticOrTopLevelFunction(element)) { 463 if (Elements.isStaticOrTopLevelFunction(element)) {
452 return new FunctionConstant(element); 464 return new FunctionConstant(element);
(...skipping 17 matching lines...) Expand all
470 if (result != null) return result; 482 if (result != null) return result;
471 } 483 }
472 return signalNotCompileTimeConstant(send); 484 return signalNotCompileTimeConstant(send);
473 } else if (send.isCall) { 485 } else if (send.isCall) {
474 if (identical(element, compiler.identicalFunction) 486 if (identical(element, compiler.identicalFunction)
475 && send.argumentCount() == 2) { 487 && send.argumentCount() == 2) {
476 Constant left = evaluate(send.argumentsNode.nodes.head); 488 Constant left = evaluate(send.argumentsNode.nodes.head);
477 Constant right = evaluate(send.argumentsNode.nodes.tail.head); 489 Constant right = evaluate(send.argumentsNode.nodes.tail.head);
478 Constant result = constantSystem.identity.fold(left, right); 490 Constant result = constantSystem.identity.fold(left, right);
479 if (result != null) return result; 491 if (result != null) return result;
480 } else if (Elements.isClass(element) || Elements.isTypedef(element)) {
481 // The node itself is not a constant but we register the selector (the
482 // identifier that refers to the class/typedef) as a constant.
483 Constant typeConstant = makeTypeConstant(element);
484 elements.setConstant(send.selector, typeConstant);
485 } 492 }
486 return signalNotCompileTimeConstant(send); 493 return signalNotCompileTimeConstant(send);
487 } else if (send.isPrefix) { 494 } else if (send.isPrefix) {
488 assert(send.isOperator); 495 assert(send.isOperator);
489 Constant receiverConstant = evaluate(send.receiver); 496 Constant receiverConstant = evaluate(send.receiver);
490 if (receiverConstant == null) return null; 497 if (receiverConstant == null) return null;
491 Operator op = send.selector; 498 Operator op = send.selector;
492 Constant folded; 499 Constant folded;
493 switch (op.source) { 500 switch (op.source) {
494 case "!": 501 case "!":
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after
803 final FunctionElement constructor; 810 final FunctionElement constructor;
804 final Map<Element, Constant> definitions; 811 final Map<Element, Constant> definitions;
805 final Map<Element, Constant> fieldValues; 812 final Map<Element, Constant> fieldValues;
806 813
807 /** 814 /**
808 * Documentation wanted -- johnniwinther 815 * Documentation wanted -- johnniwinther
809 * 816 *
810 * Invariant: [constructor] must be an implementation element. 817 * Invariant: [constructor] must be an implementation element.
811 */ 818 */
812 ConstructorEvaluator(FunctionElement constructor, 819 ConstructorEvaluator(FunctionElement constructor,
813 ConstantHandler handler, 820 ConstantCompiler handler,
814 Compiler compiler) 821 Compiler compiler)
815 : this.constructor = constructor, 822 : this.constructor = constructor,
816 this.definitions = new Map<Element, Constant>(), 823 this.definitions = new Map<Element, Constant>(),
817 this.fieldValues = new Map<Element, Constant>(), 824 this.fieldValues = new Map<Element, Constant>(),
818 super(handler, 825 super(handler,
819 compiler.resolver.resolveMethodElement(constructor.declaration), 826 compiler.resolver.resolveMethodElement(constructor.declaration),
820 compiler, 827 compiler,
821 isConst: true) { 828 isConst: true) {
822 assert(invariant(constructor, constructor.isImplementation)); 829 assert(invariant(constructor, constructor.isImplementation));
823 } 830 }
(...skipping 12 matching lines...) Expand all
836 843
837 void potentiallyCheckType(Node node, 844 void potentiallyCheckType(Node node,
838 TypedElement element, 845 TypedElement element,
839 Constant constant) { 846 Constant constant) {
840 if (compiler.enableTypeAssertions) { 847 if (compiler.enableTypeAssertions) {
841 DartType elementType = element.type; 848 DartType elementType = element.type;
842 DartType constantType = constant.computeType(compiler); 849 DartType constantType = constant.computeType(compiler);
843 // TODO(ngeoffray): Handle type parameters. 850 // TODO(ngeoffray): Handle type parameters.
844 if (elementType.element.isTypeVariable()) return; 851 if (elementType.element.isTypeVariable()) return;
845 if (!constantSystem.isSubtype(compiler, constantType, elementType)) { 852 if (!constantSystem.isSubtype(compiler, constantType, elementType)) {
853 // TODO(johnniwinther): Provide better [node] values that point to the
854 // origin of the constant and not (just) the assignment.
846 compiler.reportFatalError( 855 compiler.reportFatalError(
847 node, MessageKind.NOT_ASSIGNABLE, 856 node, MessageKind.NOT_ASSIGNABLE,
848 {'fromType': elementType, 'toType': constantType}); 857 {'fromType': elementType, 'toType': constantType});
849 } 858 }
850 } 859 }
851 } 860 }
852 861
853 void updateFieldValue(Node node, TypedElement element, Constant constant) { 862 void updateFieldValue(Node node, TypedElement element, Constant constant) {
854 potentiallyCheckType(node, element, constant); 863 potentiallyCheckType(node, element, constant);
855 fieldValues[element] = constant; 864 fieldValues[element] = constant;
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
981 if (fieldValue == null) { 990 if (fieldValue == null) {
982 // Use the default value. 991 // Use the default value.
983 fieldValue = handler.compileConstant(field); 992 fieldValue = handler.compileConstant(field);
984 } 993 }
985 jsNewArguments.add(fieldValue); 994 jsNewArguments.add(fieldValue);
986 }, 995 },
987 includeSuperAndInjectedMembers: true); 996 includeSuperAndInjectedMembers: true);
988 return jsNewArguments; 997 return jsNewArguments;
989 } 998 }
990 } 999 }
OLDNEW
« no previous file with comments | « sdk/lib/_internal/compiler/implementation/common.dart ('k') | sdk/lib/_internal/compiler/implementation/compiler.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698