OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library code_generator; | 5 library code_generator; |
6 | 6 |
7 import 'glue.dart'; | 7 import 'glue.dart'; |
8 | 8 |
9 import '../../closure.dart' show | 9 import '../../closure.dart' show ClosureClassElement; |
10 ClosureClassElement; | 10 import '../../common/codegen.dart' show CodegenRegistry; |
11 import '../../common/codegen.dart' show | |
12 CodegenRegistry; | |
13 import '../../constants/values.dart'; | 11 import '../../constants/values.dart'; |
14 import '../../dart_types.dart'; | 12 import '../../dart_types.dart'; |
15 import '../../elements/elements.dart'; | 13 import '../../elements/elements.dart'; |
16 import '../../io/source_information.dart' show | 14 import '../../io/source_information.dart' show SourceInformation; |
17 SourceInformation; | |
18 import '../../js/js.dart' as js; | 15 import '../../js/js.dart' as js; |
19 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir; | 16 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir; |
20 import '../../tree_ir/tree_ir_nodes.dart' show | 17 import '../../tree_ir/tree_ir_nodes.dart' |
21 BuiltinMethod, | 18 show BuiltinMethod, BuiltinOperator, isCompoundableOperator; |
22 BuiltinOperator, | 19 import '../../types/types.dart' show TypeMask; |
23 isCompoundableOperator; | 20 import '../../universe/call_structure.dart' show CallStructure; |
24 import '../../types/types.dart' show | 21 import '../../universe/selector.dart' show Selector; |
25 TypeMask; | 22 import '../../universe/use.dart' show DynamicUse, StaticUse, TypeUse; |
26 import '../../universe/call_structure.dart' show | |
27 CallStructure; | |
28 import '../../universe/selector.dart' show | |
29 Selector; | |
30 import '../../universe/use.dart' show | |
31 DynamicUse, | |
32 StaticUse, | |
33 TypeUse; | |
34 import '../../util/maplet.dart'; | 23 import '../../util/maplet.dart'; |
35 | 24 |
36 class CodegenBailout { | 25 class CodegenBailout { |
37 final tree_ir.Node node; | 26 final tree_ir.Node node; |
38 final String reason; | 27 final String reason; |
39 CodegenBailout(this.node, this.reason); | 28 CodegenBailout(this.node, this.reason); |
40 String get message { | 29 String get message { |
41 return 'bailout${node != null ? " on $node" : ""}: $reason'; | 30 return 'bailout${node != null ? " on $node" : ""}: $reason'; |
42 } | 31 } |
43 } | 32 } |
44 | 33 |
45 class CodeGenerator extends tree_ir.StatementVisitor | 34 class CodeGenerator extends tree_ir.StatementVisitor |
46 with tree_ir.ExpressionVisitor<js.Expression> { | 35 with tree_ir.ExpressionVisitor<js.Expression> { |
47 final CodegenRegistry registry; | 36 final CodegenRegistry registry; |
48 | 37 |
49 final Glue glue; | 38 final Glue glue; |
50 | 39 |
51 ExecutableElement currentFunction; | 40 ExecutableElement currentFunction; |
52 | 41 |
53 /// Maps variables to their name. | 42 /// Maps variables to their name. |
54 Map<tree_ir.Variable, String> variableNames = <tree_ir.Variable, String>{}; | 43 Map<tree_ir.Variable, String> variableNames = <tree_ir.Variable, String>{}; |
55 | 44 |
56 /// Maps local constants to their name. | 45 /// Maps local constants to their name. |
57 Maplet<VariableElement, String> constantNames = | 46 Maplet<VariableElement, String> constantNames = |
58 new Maplet<VariableElement, String>(); | 47 new Maplet<VariableElement, String>(); |
59 | 48 |
60 /// Variable names that have already been used. Used to avoid name clashes. | 49 /// Variable names that have already been used. Used to avoid name clashes. |
61 Set<String> usedVariableNames = new Set<String>(); | 50 Set<String> usedVariableNames = new Set<String>(); |
62 | 51 |
63 final tree_ir.FallthroughStack fallthrough = new tree_ir.FallthroughStack(); | 52 final tree_ir.FallthroughStack fallthrough = new tree_ir.FallthroughStack(); |
64 | 53 |
65 /// Stacks whose top element is the current target of an unlabeled break | 54 /// Stacks whose top element is the current target of an unlabeled break |
66 /// or continue. For continues, this is the loop node itself. | 55 /// or continue. For continues, this is the loop node itself. |
67 final tree_ir.FallthroughStack shortBreak = new tree_ir.FallthroughStack(); | 56 final tree_ir.FallthroughStack shortBreak = new tree_ir.FallthroughStack(); |
68 final tree_ir.FallthroughStack shortContinue = | 57 final tree_ir.FallthroughStack shortContinue = new tree_ir.FallthroughStack(); |
69 new tree_ir.FallthroughStack(); | |
70 | 58 |
71 /// When the top element is true, [Unreachable] statements will be emitted | 59 /// When the top element is true, [Unreachable] statements will be emitted |
72 /// as [Return]s, otherwise they are emitted as empty because they are | 60 /// as [Return]s, otherwise they are emitted as empty because they are |
73 /// followed by the end of the method. | 61 /// followed by the end of the method. |
74 /// | 62 /// |
75 /// Note on why the [fallthrough] stack should not be used for this: | 63 /// Note on why the [fallthrough] stack should not be used for this: |
76 /// Ordinary statements may choose whether to use the [fallthrough] target, | 64 /// Ordinary statements may choose whether to use the [fallthrough] target, |
77 /// and the choice to do so may disable an optimization in [visitIf]. | 65 /// and the choice to do so may disable an optimization in [visitIf]. |
78 /// But omitting an unreachable 'return' should have lower priority than | 66 /// But omitting an unreachable 'return' should have lower priority than |
79 /// the optimizations in [visitIf], so [visitIf] will instead tell the | 67 /// the optimizations in [visitIf], so [visitIf] will instead tell the |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 if (assign.op != null) break; // Compound assignment. | 111 if (assign.op != null) break; // Compound assignment. |
124 js.VariableUse use = assign.leftHandSide; | 112 js.VariableUse use = assign.leftHandSide; |
125 | 113 |
126 // Do not touch non-local variables. | 114 // Do not touch non-local variables. |
127 if (!usedVariableNames.contains(use.name)) break; | 115 if (!usedVariableNames.contains(use.name)) break; |
128 | 116 |
129 // We cannot declare a variable more than once. | 117 // We cannot declare a variable more than once. |
130 if (!declaredVariables.add(use.name)) break; | 118 if (!declaredVariables.add(use.name)) break; |
131 | 119 |
132 js.VariableInitialization jsVariable = new js.VariableInitialization( | 120 js.VariableInitialization jsVariable = new js.VariableInitialization( |
133 new js.VariableDeclaration(use.name), | 121 new js.VariableDeclaration(use.name), assign.value); |
134 assign.value); | |
135 jsVariables.add(jsVariable); | 122 jsVariables.add(jsVariable); |
136 | 123 |
137 ++accumulatorIndex; | 124 ++accumulatorIndex; |
138 } | 125 } |
139 | 126 |
140 // If the last statement is a for loop with an initializer expression, try | 127 // If the last statement is a for loop with an initializer expression, try |
141 // to pull that expression into an initializer as well. | 128 // to pull that expression into an initializer as well. |
142 pullFromForLoop: | 129 pullFromForLoop: if (accumulatorIndex < accumulator.length && |
143 if (accumulatorIndex < accumulator.length && | |
144 accumulator[accumulatorIndex] is js.For) { | 130 accumulator[accumulatorIndex] is js.For) { |
145 js.For forLoop = accumulator[accumulatorIndex]; | 131 js.For forLoop = accumulator[accumulatorIndex]; |
146 if (forLoop.init is! js.Assignment) break pullFromForLoop; | 132 if (forLoop.init is! js.Assignment) break pullFromForLoop; |
147 js.Assignment assign = forLoop.init; | 133 js.Assignment assign = forLoop.init; |
148 if (assign.leftHandSide is! js.VariableUse) break pullFromForLoop; | 134 if (assign.leftHandSide is! js.VariableUse) break pullFromForLoop; |
149 if (assign.op != null) break pullFromForLoop; // Compound assignment. | 135 if (assign.op != null) break pullFromForLoop; // Compound assignment. |
150 js.VariableUse use = assign.leftHandSide; | 136 js.VariableUse use = assign.leftHandSide; |
151 | 137 |
152 // Do not touch non-local variables. | 138 // Do not touch non-local variables. |
153 if (!usedVariableNames.contains(use.name)) break pullFromForLoop; | 139 if (!usedVariableNames.contains(use.name)) break pullFromForLoop; |
154 | 140 |
155 // We cannot declare a variable more than once. | 141 // We cannot declare a variable more than once. |
156 if (!declaredVariables.add(use.name)) break pullFromForLoop; | 142 if (!declaredVariables.add(use.name)) break pullFromForLoop; |
157 | 143 |
158 js.VariableInitialization jsVariable = new js.VariableInitialization( | 144 js.VariableInitialization jsVariable = new js.VariableInitialization( |
159 new js.VariableDeclaration(use.name), | 145 new js.VariableDeclaration(use.name), assign.value); |
160 assign.value); | |
161 jsVariables.add(jsVariable); | 146 jsVariables.add(jsVariable); |
162 | 147 |
163 // Remove the initializer from the for loop. | 148 // Remove the initializer from the for loop. |
164 accumulator[accumulatorIndex] = | 149 accumulator[accumulatorIndex] = |
165 new js.For(null, forLoop.condition, forLoop.update, forLoop.body); | 150 new js.For(null, forLoop.condition, forLoop.update, forLoop.body); |
166 } | 151 } |
167 | 152 |
168 // Discard the statements that were pulled in the initializer. | 153 // Discard the statements that were pulled in the initializer. |
169 if (accumulatorIndex > 0) { | 154 if (accumulatorIndex > 0) { |
170 accumulator = accumulator.sublist(accumulatorIndex); | 155 accumulator = accumulator.sublist(accumulatorIndex); |
171 } | 156 } |
172 | 157 |
173 // Declare remaining variables. | 158 // Declare remaining variables. |
174 for (tree_ir.Variable variable in variableNames.keys) { | 159 for (tree_ir.Variable variable in variableNames.keys) { |
175 String name = getVariableName(variable); | 160 String name = getVariableName(variable); |
176 if (declaredVariables.contains(name)) continue; | 161 if (declaredVariables.contains(name)) continue; |
177 js.VariableInitialization jsVariable = new js.VariableInitialization( | 162 js.VariableInitialization jsVariable = |
178 new js.VariableDeclaration(name), | 163 new js.VariableInitialization(new js.VariableDeclaration(name), null); |
179 null); | |
180 jsVariables.add(jsVariable); | 164 jsVariables.add(jsVariable); |
181 } | 165 } |
182 | 166 |
183 if (jsVariables.length > 0) { | 167 if (jsVariables.length > 0) { |
184 // Would be nice to avoid inserting at the beginning of list. | 168 // Would be nice to avoid inserting at the beginning of list. |
185 accumulator.insert(0, new js.ExpressionStatement( | 169 accumulator.insert( |
186 new js.VariableDeclarationList(jsVariables) | 170 0, |
| 171 new js.ExpressionStatement(new js.VariableDeclarationList(jsVariables) |
187 .withSourceInformation(function.sourceInformation))); | 172 .withSourceInformation(function.sourceInformation))); |
188 } | 173 } |
189 return new js.Fun(parameters, new js.Block(accumulator)); | 174 return new js.Fun(parameters, new js.Block(accumulator)); |
190 } | 175 } |
191 | 176 |
192 @override | 177 @override |
193 js.Expression visitExpression(tree_ir.Expression node) { | 178 js.Expression visitExpression(tree_ir.Expression node) { |
194 js.Expression result = node.accept(this); | 179 js.Expression result = node.accept(this); |
195 if (result == null) { | 180 if (result == null) { |
196 glue.reportInternalError('$node did not produce code.'); | 181 glue.reportInternalError('$node did not produce code.'); |
197 } | 182 } |
198 return result; | 183 return result; |
199 } | 184 } |
200 | 185 |
201 /// Generates a name for the given variable. First trying with the name of | 186 /// Generates a name for the given variable. First trying with the name of |
202 /// the [Variable.element] if it is non-null. | 187 /// the [Variable.element] if it is non-null. |
203 String getVariableName(tree_ir.Variable variable) { | 188 String getVariableName(tree_ir.Variable variable) { |
204 // Functions are not nested in the JS backend. | 189 // Functions are not nested in the JS backend. |
205 assert(variable.host == currentFunction); | 190 assert(variable.host == currentFunction); |
206 | 191 |
207 // Get the name if we already have one. | 192 // Get the name if we already have one. |
208 String name = variableNames[variable]; | 193 String name = variableNames[variable]; |
209 if (name != null) { | 194 if (name != null) { |
210 return name; | 195 return name; |
211 } | 196 } |
212 | 197 |
213 // Synthesize a variable name that isn't used elsewhere. | 198 // Synthesize a variable name that isn't used elsewhere. |
214 String prefix = variable.element == null ? 'v' : variable.element.name; | 199 String prefix = variable.element == null ? 'v' : variable.element.name; |
215 int counter = 0; | 200 int counter = 0; |
216 name = glue.safeVariableName(variable.element == null | 201 name = glue.safeVariableName( |
217 ? '$prefix$counter' | 202 variable.element == null ? '$prefix$counter' : variable.element.name); |
218 : variable.element.name); | |
219 while (!usedVariableNames.add(name)) { | 203 while (!usedVariableNames.add(name)) { |
220 ++counter; | 204 ++counter; |
221 name = '$prefix$counter'; | 205 name = '$prefix$counter'; |
222 } | 206 } |
223 variableNames[variable] = name; | 207 variableNames[variable] = name; |
224 | 208 |
225 return name; | 209 return name; |
226 } | 210 } |
227 | 211 |
228 List<js.Expression> visitExpressionList( | 212 List<js.Expression> visitExpressionList( |
229 List<tree_ir.Expression> expressions) { | 213 List<tree_ir.Expression> expressions) { |
230 List<js.Expression> result = new List<js.Expression>(expressions.length); | 214 List<js.Expression> result = new List<js.Expression>(expressions.length); |
231 for (int i = 0; i < expressions.length; ++i) { | 215 for (int i = 0; i < expressions.length; ++i) { |
232 result[i] = visitExpression(expressions[i]); | 216 result[i] = visitExpression(expressions[i]); |
233 } | 217 } |
234 return result; | 218 return result; |
235 } | 219 } |
236 | 220 |
237 giveup(tree_ir.Node node, | 221 giveup(tree_ir.Node node, |
238 [String reason = 'unimplemented in CodeGenerator']) { | 222 [String reason = 'unimplemented in CodeGenerator']) { |
239 throw new CodegenBailout(node, reason); | 223 throw new CodegenBailout(node, reason); |
240 } | 224 } |
241 | 225 |
242 @override | 226 @override |
243 js.Expression visitConditional(tree_ir.Conditional node) { | 227 js.Expression visitConditional(tree_ir.Conditional node) { |
244 return new js.Conditional( | 228 return new js.Conditional( |
245 visitExpression(node.condition), | 229 visitExpression(node.condition), |
246 visitExpression(node.thenExpression), | 230 visitExpression(node.thenExpression), |
247 visitExpression(node.elseExpression)); | 231 visitExpression(node.elseExpression)); |
248 } | 232 } |
249 | 233 |
250 js.Expression buildConstant(ConstantValue constant, | 234 js.Expression buildConstant(ConstantValue constant, |
251 {SourceInformation sourceInformation}) { | 235 {SourceInformation sourceInformation}) { |
252 registry.registerCompileTimeConstant(constant); | 236 registry.registerCompileTimeConstant(constant); |
253 return glue.constantReference(constant) | 237 return glue |
| 238 .constantReference(constant) |
254 .withSourceInformation(sourceInformation); | 239 .withSourceInformation(sourceInformation); |
255 } | 240 } |
256 | 241 |
257 @override | 242 @override |
258 js.Expression visitConstant(tree_ir.Constant node) { | 243 js.Expression visitConstant(tree_ir.Constant node) { |
259 return buildConstant( | 244 return buildConstant(node.value, sourceInformation: node.sourceInformation); |
260 node.value, | |
261 sourceInformation: node.sourceInformation); | |
262 } | 245 } |
263 | 246 |
264 js.Expression buildStaticInvoke(Element target, | 247 js.Expression buildStaticInvoke(Element target, List<js.Expression> arguments, |
265 List<js.Expression> arguments, | 248 {SourceInformation sourceInformation}) { |
266 {SourceInformation sourceInformation}) { | |
267 if (target.isConstructor) { | 249 if (target.isConstructor) { |
268 // TODO(johnniwinther): Avoid dependency on [isGenerativeConstructor] by | 250 // TODO(johnniwinther): Avoid dependency on [isGenerativeConstructor] by |
269 // using backend-specific [StatisUse] classes. | 251 // using backend-specific [StatisUse] classes. |
270 registry.registerStaticUse( | 252 registry.registerStaticUse(new StaticUse.constructorInvoke( |
271 new StaticUse.constructorInvoke(target.declaration, | 253 target.declaration, new CallStructure.unnamed(arguments.length))); |
272 new CallStructure.unnamed(arguments.length))); | |
273 } else { | 254 } else { |
274 registry.registerStaticUse( | 255 registry.registerStaticUse(new StaticUse.staticInvoke( |
275 new StaticUse.staticInvoke(target.declaration, | 256 target.declaration, new CallStructure.unnamed(arguments.length))); |
276 new CallStructure.unnamed(arguments.length))); | |
277 } | 257 } |
278 js.Expression elementAccess = glue.staticFunctionAccess(target); | 258 js.Expression elementAccess = glue.staticFunctionAccess(target); |
279 return new js.Call(elementAccess, arguments, | 259 return new js.Call(elementAccess, arguments, |
280 sourceInformation: sourceInformation); | 260 sourceInformation: sourceInformation); |
281 } | 261 } |
282 | 262 |
283 @override | 263 @override |
284 js.Expression visitInvokeConstructor(tree_ir.InvokeConstructor node) { | 264 js.Expression visitInvokeConstructor(tree_ir.InvokeConstructor node) { |
285 if (node.constant != null) return giveup(node); | 265 if (node.constant != null) return giveup(node); |
286 | 266 |
287 registry.registerInstantiation(node.type); | 267 registry.registerInstantiation(node.type); |
288 FunctionElement target = node.target; | 268 FunctionElement target = node.target; |
289 List<js.Expression> arguments = visitExpressionList(node.arguments); | 269 List<js.Expression> arguments = visitExpressionList(node.arguments); |
290 return buildStaticInvoke( | 270 return buildStaticInvoke(target, arguments, |
291 target, | |
292 arguments, | |
293 sourceInformation: node.sourceInformation); | 271 sourceInformation: node.sourceInformation); |
294 } | 272 } |
295 | 273 |
296 void registerMethodInvoke(Selector selector, TypeMask receiverType) { | 274 void registerMethodInvoke(Selector selector, TypeMask receiverType) { |
297 registry.registerDynamicUse(new DynamicUse(selector, receiverType)); | 275 registry.registerDynamicUse(new DynamicUse(selector, receiverType)); |
298 if (!selector.isGetter && !selector.isSetter) { | 276 if (!selector.isGetter && !selector.isSetter) { |
299 // TODO(sigurdm): We should find a better place to register the call. | 277 // TODO(sigurdm): We should find a better place to register the call. |
300 Selector call = new Selector.callClosureFrom(selector); | 278 Selector call = new Selector.callClosureFrom(selector); |
301 registry.registerDynamicUse(new DynamicUse(call, null)); | 279 registry.registerDynamicUse(new DynamicUse(call, null)); |
302 } | 280 } |
303 } | 281 } |
304 | 282 |
305 @override | 283 @override |
306 js.Expression visitInvokeMethod(tree_ir.InvokeMethod node) { | 284 js.Expression visitInvokeMethod(tree_ir.InvokeMethod node) { |
307 TypeMask mask = glue.extendMaskIfReachesAll(node.selector, node.mask); | 285 TypeMask mask = glue.extendMaskIfReachesAll(node.selector, node.mask); |
308 registerMethodInvoke(node.selector, mask); | 286 registerMethodInvoke(node.selector, mask); |
309 return js.propertyCall(visitExpression(node.receiver), | 287 return js |
310 glue.invocationName(node.selector), | 288 .propertyCall( |
311 visitExpressionList(node.arguments)) | 289 visitExpression(node.receiver), |
| 290 glue.invocationName(node.selector), |
| 291 visitExpressionList(node.arguments)) |
312 .withSourceInformation(node.sourceInformation); | 292 .withSourceInformation(node.sourceInformation); |
313 } | 293 } |
314 | 294 |
315 @override | 295 @override |
316 js.Expression visitInvokeStatic(tree_ir.InvokeStatic node) { | 296 js.Expression visitInvokeStatic(tree_ir.InvokeStatic node) { |
317 FunctionElement target = node.target; | 297 FunctionElement target = node.target; |
318 List<js.Expression> arguments = visitExpressionList(node.arguments); | 298 List<js.Expression> arguments = visitExpressionList(node.arguments); |
319 return buildStaticInvoke(target, arguments, | 299 return buildStaticInvoke(target, arguments, |
320 sourceInformation: node.sourceInformation); | 300 sourceInformation: node.sourceInformation); |
321 } | 301 } |
322 | 302 |
323 @override | 303 @override |
324 js.Expression visitInvokeMethodDirectly(tree_ir.InvokeMethodDirectly node) { | 304 js.Expression visitInvokeMethodDirectly(tree_ir.InvokeMethodDirectly node) { |
325 if (node.isTearOff) { | 305 if (node.isTearOff) { |
326 // If this is a tear-off, register the fact that a tear-off closure | 306 // If this is a tear-off, register the fact that a tear-off closure |
327 // will be created, and that this tear-off must bypass ordinary | 307 // will be created, and that this tear-off must bypass ordinary |
328 // dispatch to ensure the super method is invoked. | 308 // dispatch to ensure the super method is invoked. |
329 registry.registerStaticUse(new StaticUse.staticInvoke( | 309 registry.registerStaticUse(new StaticUse.staticInvoke( |
330 glue.closureFromTearOff, new CallStructure.unnamed( | 310 glue.closureFromTearOff, |
331 glue.closureFromTearOff.parameters.length))); | 311 new CallStructure.unnamed( |
| 312 glue.closureFromTearOff.parameters.length))); |
332 registry.registerStaticUse(new StaticUse.superTearOff(node.target)); | 313 registry.registerStaticUse(new StaticUse.superTearOff(node.target)); |
333 } | 314 } |
334 if (node.target is ConstructorBodyElement) { | 315 if (node.target is ConstructorBodyElement) { |
335 registry.registerStaticUse( | 316 registry.registerStaticUse(new StaticUse.constructorBodyInvoke( |
336 new StaticUse.constructorBodyInvoke( | 317 node.target.declaration, |
337 node.target.declaration, | 318 new CallStructure.unnamed(node.arguments.length))); |
338 new CallStructure.unnamed(node.arguments.length))); | |
339 // A constructor body cannot be overriden or intercepted, so we can | 319 // A constructor body cannot be overriden or intercepted, so we can |
340 // use the short form for this invocation. | 320 // use the short form for this invocation. |
341 return js.js('#.#(#)', | 321 return js.js('#.#(#)', [ |
342 [visitExpression(node.receiver), | 322 visitExpression(node.receiver), |
343 glue.instanceMethodName(node.target), | 323 glue.instanceMethodName(node.target), |
344 visitExpressionList(node.arguments)]) | 324 visitExpressionList(node.arguments) |
345 .withSourceInformation(node.sourceInformation); | 325 ]).withSourceInformation(node.sourceInformation); |
346 } | 326 } |
347 registry.registerStaticUse( | 327 registry.registerStaticUse(new StaticUse.superInvoke( |
348 new StaticUse.superInvoke( | 328 node.target.declaration, |
349 node.target.declaration, | 329 new CallStructure.unnamed(node.arguments.length))); |
350 new CallStructure.unnamed(node.arguments.length))); | 330 return js.js('#.#.call(#, #)', [ |
351 return js.js('#.#.call(#, #)', | 331 glue.prototypeAccess(node.target.enclosingClass), |
352 [glue.prototypeAccess(node.target.enclosingClass), | 332 glue.invocationName(node.selector), |
353 glue.invocationName(node.selector), | 333 visitExpression(node.receiver), |
354 visitExpression(node.receiver), | 334 visitExpressionList(node.arguments) |
355 visitExpressionList(node.arguments)]) | 335 ]).withSourceInformation(node.sourceInformation); |
356 .withSourceInformation(node.sourceInformation); | |
357 } | 336 } |
358 | 337 |
359 @override | 338 @override |
360 js.Expression visitOneShotInterceptor(tree_ir.OneShotInterceptor node) { | 339 js.Expression visitOneShotInterceptor(tree_ir.OneShotInterceptor node) { |
361 registerMethodInvoke(node.selector, node.mask); | 340 registerMethodInvoke(node.selector, node.mask); |
362 registry.registerUseInterceptor(); | 341 registry.registerUseInterceptor(); |
363 return js.js('#.#(#)', | 342 return js.js('#.#(#)', [ |
364 [glue.getInterceptorLibrary(), | 343 glue.getInterceptorLibrary(), |
365 glue.registerOneShotInterceptor(node.selector), | 344 glue.registerOneShotInterceptor(node.selector), |
366 visitExpressionList(node.arguments)]) | 345 visitExpressionList(node.arguments) |
367 .withSourceInformation(node.sourceInformation); | 346 ]).withSourceInformation(node.sourceInformation); |
368 } | 347 } |
369 | 348 |
370 @override | 349 @override |
371 js.Expression visitLiteralList(tree_ir.LiteralList node) { | 350 js.Expression visitLiteralList(tree_ir.LiteralList node) { |
372 registry.registerInstantiatedClass(glue.listClass); | 351 registry.registerInstantiatedClass(glue.listClass); |
373 List<js.Expression> entries = visitExpressionList(node.values); | 352 List<js.Expression> entries = visitExpressionList(node.values); |
374 return new js.ArrayInitializer(entries); | 353 return new js.ArrayInitializer(entries); |
375 } | 354 } |
376 | 355 |
377 @override | 356 @override |
378 js.Expression visitLogicalOperator(tree_ir.LogicalOperator node) { | 357 js.Expression visitLogicalOperator(tree_ir.LogicalOperator node) { |
379 return new js.Binary( | 358 return new js.Binary( |
380 node.operator, | 359 node.operator, visitExpression(node.left), visitExpression(node.right)); |
381 visitExpression(node.left), | |
382 visitExpression(node.right)); | |
383 } | 360 } |
384 | 361 |
385 @override | 362 @override |
386 js.Expression visitNot(tree_ir.Not node) { | 363 js.Expression visitNot(tree_ir.Not node) { |
387 return new js.Prefix("!", visitExpression(node.operand)); | 364 return new js.Prefix("!", visitExpression(node.operand)); |
388 } | 365 } |
389 | 366 |
390 @override | 367 @override |
391 js.Expression visitThis(tree_ir.This node) { | 368 js.Expression visitThis(tree_ir.This node) { |
392 return new js.This(); | 369 return new js.This(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
424 if (node.isTypeTest) { | 401 if (node.isTypeTest) { |
425 return js.js(r'typeof # === "string"', <js.Expression>[value]); | 402 return js.js(r'typeof # === "string"', <js.Expression>[value]); |
426 } | 403 } |
427 // TODO(sra): Implement fast cast via calling 'stringTypeCast'. | 404 // TODO(sra): Implement fast cast via calling 'stringTypeCast'. |
428 } else if (glue.isBoolClass(clazz)) { | 405 } else if (glue.isBoolClass(clazz)) { |
429 if (node.isTypeTest) { | 406 if (node.isTypeTest) { |
430 return js.js(r'typeof # === "boolean"', <js.Expression>[value]); | 407 return js.js(r'typeof # === "boolean"', <js.Expression>[value]); |
431 } | 408 } |
432 // TODO(sra): Implement fast cast via calling 'boolTypeCast'. | 409 // TODO(sra): Implement fast cast via calling 'boolTypeCast'. |
433 } else if (node.isTypeTest && | 410 } else if (node.isTypeTest && |
434 node.typeArguments.isEmpty && | 411 node.typeArguments.isEmpty && |
435 glue.mayGenerateInstanceofCheck(type) && | 412 glue.mayGenerateInstanceofCheck(type) && |
436 tryRegisterInstanceofCheck(clazz)) { | 413 tryRegisterInstanceofCheck(clazz)) { |
437 return js.js('# instanceof #', [value, glue.constructorAccess(clazz)]); | 414 return js.js('# instanceof #', [value, glue.constructorAccess(clazz)]); |
438 } | 415 } |
439 | 416 |
440 // The helper we use needs the JSArray class to exist, but for some | 417 // The helper we use needs the JSArray class to exist, but for some |
441 // reason the helper does not cause this dependency to be registered. | 418 // reason the helper does not cause this dependency to be registered. |
442 // TODO(asgerf): Most programs need List anyway, but we should fix this. | 419 // TODO(asgerf): Most programs need List anyway, but we should fix this. |
443 registry.registerInstantiatedClass(glue.listClass); | 420 registry.registerInstantiatedClass(glue.listClass); |
444 | 421 |
445 // We use one of the two helpers: | 422 // We use one of the two helpers: |
446 // | 423 // |
447 // checkSubtype(value, $isT, typeArgs, $asT) | 424 // checkSubtype(value, $isT, typeArgs, $asT) |
448 // subtypeCast(value, $isT, typeArgs, $asT) | 425 // subtypeCast(value, $isT, typeArgs, $asT) |
449 // | 426 // |
450 // Any of the last two arguments may be null if there are no type | 427 // Any of the last two arguments may be null if there are no type |
451 // arguments, and/or if no substitution is required. | 428 // arguments, and/or if no substitution is required. |
452 Element function = node.isTypeTest | 429 Element function = |
453 ? glue.getCheckSubtype() | 430 node.isTypeTest ? glue.getCheckSubtype() : glue.getSubtypeCast(); |
454 : glue.getSubtypeCast(); | |
455 | 431 |
456 js.Expression isT = js.quoteName(glue.getTypeTestTag(type)); | 432 js.Expression isT = js.quoteName(glue.getTypeTestTag(type)); |
457 | 433 |
458 js.Expression typeArgumentArray = typeArguments.isNotEmpty | 434 js.Expression typeArgumentArray = typeArguments.isNotEmpty |
459 ? new js.ArrayInitializer(typeArguments) | 435 ? new js.ArrayInitializer(typeArguments) |
460 : new js.LiteralNull(); | 436 : new js.LiteralNull(); |
461 | 437 |
462 js.Expression asT = glue.hasStrictSubtype(clazz) | 438 js.Expression asT = glue.hasStrictSubtype(clazz) |
463 ? js.quoteName(glue.getTypeSubstitutionTag(clazz)) | 439 ? js.quoteName(glue.getTypeSubstitutionTag(clazz)) |
464 : new js.LiteralNull(); | 440 : new js.LiteralNull(); |
465 | 441 |
466 return buildStaticHelperInvocation( | 442 return buildStaticHelperInvocation( |
467 function, | 443 function, <js.Expression>[value, isT, typeArgumentArray, asT]); |
468 <js.Expression>[value, isT, typeArgumentArray, asT]); | |
469 } else if (type is TypeVariableType || type is FunctionType) { | 444 } else if (type is TypeVariableType || type is FunctionType) { |
470 registry.registerTypeUse(new TypeUse.isCheck(type)); | 445 registry.registerTypeUse(new TypeUse.isCheck(type)); |
471 | 446 |
472 Element function = node.isTypeTest | 447 Element function = node.isTypeTest |
473 ? glue.getCheckSubtypeOfRuntimeType() | 448 ? glue.getCheckSubtypeOfRuntimeType() |
474 : glue.getSubtypeOfRuntimeTypeCast(); | 449 : glue.getSubtypeOfRuntimeTypeCast(); |
475 | 450 |
476 // The only type argument is the type held in the type variable. | 451 // The only type argument is the type held in the type variable. |
477 js.Expression typeValue = typeArguments.single; | 452 js.Expression typeValue = typeArguments.single; |
478 | 453 |
479 return buildStaticHelperInvocation( | 454 return buildStaticHelperInvocation( |
480 function, | 455 function, <js.Expression>[value, typeValue]); |
481 <js.Expression>[value, typeValue]); | |
482 } | 456 } |
483 return giveup(node, 'type check unimplemented for $type.'); | 457 return giveup(node, 'type check unimplemented for $type.'); |
484 } | 458 } |
485 | 459 |
486 @override | 460 @override |
487 js.Expression visitGetTypeTestProperty(tree_ir.GetTypeTestProperty node) { | 461 js.Expression visitGetTypeTestProperty(tree_ir.GetTypeTestProperty node) { |
488 js.Expression object = visitExpression(node.object); | 462 js.Expression object = visitExpression(node.object); |
489 DartType dartType = node.dartType; | 463 DartType dartType = node.dartType; |
490 assert(dartType.isInterfaceType); | 464 assert(dartType.isInterfaceType); |
491 registry.registerTypeUse(new TypeUse.isCheck(dartType)); | 465 registry.registerTypeUse(new TypeUse.isCheck(dartType)); |
(...skipping 27 matching lines...) Expand all Loading... |
519 return '/'; | 493 return '/'; |
520 case BuiltinOperator.NumRemainder: | 494 case BuiltinOperator.NumRemainder: |
521 return '%'; | 495 return '%'; |
522 default: | 496 default: |
523 throw 'Not a compoundable operator: $operator'; | 497 throw 'Not a compoundable operator: $operator'; |
524 } | 498 } |
525 } | 499 } |
526 | 500 |
527 bool isCompoundableBuiltin(tree_ir.Expression exp) { | 501 bool isCompoundableBuiltin(tree_ir.Expression exp) { |
528 return exp is tree_ir.ApplyBuiltinOperator && | 502 return exp is tree_ir.ApplyBuiltinOperator && |
529 exp.arguments.length == 2 && | 503 exp.arguments.length == 2 && |
530 isCompoundableOperator(exp.operator); | 504 isCompoundableOperator(exp.operator); |
531 } | 505 } |
532 | 506 |
533 bool isOneConstant(tree_ir.Expression exp) { | 507 bool isOneConstant(tree_ir.Expression exp) { |
534 return exp is tree_ir.Constant && exp.value.isOne; | 508 return exp is tree_ir.Constant && exp.value.isOne; |
535 } | 509 } |
536 | 510 |
537 js.Expression makeAssignment( | 511 js.Expression makeAssignment(js.Expression leftHand, tree_ir.Expression value, |
538 js.Expression leftHand, | 512 {SourceInformation sourceInformation, BuiltinOperator compound}) { |
539 tree_ir.Expression value, | |
540 {SourceInformation sourceInformation, | |
541 BuiltinOperator compound}) { | |
542 if (isOneConstant(value)) { | 513 if (isOneConstant(value)) { |
543 if (compound == BuiltinOperator.NumAdd) { | 514 if (compound == BuiltinOperator.NumAdd) { |
544 return new js.Prefix('++', leftHand) | 515 return new js.Prefix('++', leftHand) |
545 .withSourceInformation(sourceInformation); | 516 .withSourceInformation(sourceInformation); |
546 } | 517 } |
547 if (compound == BuiltinOperator.NumSubtract) { | 518 if (compound == BuiltinOperator.NumSubtract) { |
548 return new js.Prefix('--', leftHand) | 519 return new js.Prefix('--', leftHand) |
549 .withSourceInformation(sourceInformation); | 520 .withSourceInformation(sourceInformation); |
550 } | 521 } |
551 } | 522 } |
552 if (compound != null) { | 523 if (compound != null) { |
553 return new js.Assignment.compound(leftHand, | 524 return new js.Assignment.compound( |
554 getAsCompoundOperator(compound), visitExpression(value)) | 525 leftHand, getAsCompoundOperator(compound), visitExpression(value)) |
555 .withSourceInformation(sourceInformation); | 526 .withSourceInformation(sourceInformation); |
556 } | 527 } |
557 return new js.Assignment(leftHand, visitExpression(value)) | 528 return new js.Assignment(leftHand, visitExpression(value)) |
558 .withSourceInformation(sourceInformation); | 529 .withSourceInformation(sourceInformation); |
559 } | 530 } |
560 | 531 |
561 @override | 532 @override |
562 js.Expression visitAssign(tree_ir.Assign node) { | 533 js.Expression visitAssign(tree_ir.Assign node) { |
563 js.Expression variable = buildVariableAccess(node.variable); | 534 js.Expression variable = buildVariableAccess(node.variable); |
564 if (isCompoundableBuiltin(node.value)) { | 535 if (isCompoundableBuiltin(node.value)) { |
565 tree_ir.ApplyBuiltinOperator rhs = node.value; | 536 tree_ir.ApplyBuiltinOperator rhs = node.value; |
566 tree_ir.Expression left = rhs.arguments[0]; | 537 tree_ir.Expression left = rhs.arguments[0]; |
567 tree_ir.Expression right = rhs.arguments[1]; | 538 tree_ir.Expression right = rhs.arguments[1]; |
568 if (left is tree_ir.VariableUse && left.variable == node.variable) { | 539 if (left is tree_ir.VariableUse && left.variable == node.variable) { |
569 return makeAssignment(variable, right, compound: rhs.operator, | 540 return makeAssignment(variable, right, |
570 sourceInformation: node.sourceInformation); | 541 compound: rhs.operator, sourceInformation: node.sourceInformation); |
571 } | 542 } |
572 } | 543 } |
573 return makeAssignment( | 544 return makeAssignment(variable, node.value, |
574 variable, node.value, sourceInformation: node.sourceInformation); | 545 sourceInformation: node.sourceInformation); |
575 } | 546 } |
576 | 547 |
577 @override | 548 @override |
578 void visitContinue(tree_ir.Continue node) { | 549 void visitContinue(tree_ir.Continue node) { |
579 tree_ir.Statement next = fallthrough.target; | 550 tree_ir.Statement next = fallthrough.target; |
580 if (node.target.binding == next || | 551 if (node.target.binding == next || |
581 next is tree_ir.Continue && node.target == next.target) { | 552 next is tree_ir.Continue && node.target == next.target) { |
582 // Fall through to continue target or to equivalent continue. | 553 // Fall through to continue target or to equivalent continue. |
583 fallthrough.use(); | 554 fallthrough.use(); |
584 } else if (node.target.binding == shortContinue.target) { | 555 } else if (node.target.binding == shortContinue.target) { |
585 // The target is the immediately enclosing loop. | 556 // The target is the immediately enclosing loop. |
586 shortContinue.use(); | 557 shortContinue.use(); |
587 accumulator.add(new js.Continue(null)); | 558 accumulator.add(new js.Continue(null)); |
588 } else { | 559 } else { |
589 accumulator.add(new js.Continue(makeLabel(node.target))); | 560 accumulator.add(new js.Continue(makeLabel(node.target))); |
590 } | 561 } |
591 } | 562 } |
592 | 563 |
593 /// True if [other] is the target of [node] or is a [Break] with the same | 564 /// True if [other] is the target of [node] or is a [Break] with the same |
594 /// target. This means jumping to [other] is equivalent to executing [node]. | 565 /// target. This means jumping to [other] is equivalent to executing [node]. |
595 bool isEffectiveBreakTarget(tree_ir.Break node, tree_ir.Statement other) { | 566 bool isEffectiveBreakTarget(tree_ir.Break node, tree_ir.Statement other) { |
596 return node.target.binding.next == other || | 567 return node.target.binding.next == other || |
597 other is tree_ir.Break && node.target == other.target; | 568 other is tree_ir.Break && node.target == other.target; |
598 } | 569 } |
599 | 570 |
600 /// True if the given break is equivalent to an unlabeled continue. | 571 /// True if the given break is equivalent to an unlabeled continue. |
601 bool isShortContinue(tree_ir.Break node) { | 572 bool isShortContinue(tree_ir.Break node) { |
602 tree_ir.Statement next = node.target.binding.next; | 573 tree_ir.Statement next = node.target.binding.next; |
603 return next is tree_ir.Continue && | 574 return next is tree_ir.Continue && |
604 next.target.binding == shortContinue.target; | 575 next.target.binding == shortContinue.target; |
605 } | 576 } |
606 | 577 |
607 @override | 578 @override |
608 void visitBreak(tree_ir.Break node) { | 579 void visitBreak(tree_ir.Break node) { |
609 if (isEffectiveBreakTarget(node, fallthrough.target)) { | 580 if (isEffectiveBreakTarget(node, fallthrough.target)) { |
610 // Fall through to break target or to equivalent break. | 581 // Fall through to break target or to equivalent break. |
611 fallthrough.use(); | 582 fallthrough.use(); |
612 } else if (isEffectiveBreakTarget(node, shortBreak.target)) { | 583 } else if (isEffectiveBreakTarget(node, shortBreak.target)) { |
613 // Unlabeled break to the break target or to an equivalent break. | 584 // Unlabeled break to the break target or to an equivalent break. |
614 shortBreak.use(); | 585 shortBreak.use(); |
615 accumulator.add(new js.Break(null)); | 586 accumulator.add(new js.Break(null)); |
616 } else if (isShortContinue(node)) { | 587 } else if (isShortContinue(node)) { |
617 // An unlabeled continue is better than a labeled break. | 588 // An unlabeled continue is better than a labeled break. |
618 shortContinue.use(); | 589 shortContinue.use(); |
619 accumulator.add(new js.Continue(null)); | 590 accumulator.add(new js.Continue(null)); |
620 } else { | 591 } else { |
621 accumulator.add(new js.Break(makeLabel(node.target))); | 592 accumulator.add(new js.Break(makeLabel(node.target))); |
622 } | 593 } |
623 } | 594 } |
624 | 595 |
625 @override | 596 @override |
626 visitExpressionStatement(tree_ir.ExpressionStatement node) { | 597 visitExpressionStatement(tree_ir.ExpressionStatement node) { |
627 js.Expression exp = visitExpression(node.expression); | 598 js.Expression exp = visitExpression(node.expression); |
628 if (node.next is tree_ir.Unreachable && emitUnreachableAsReturn.last) { | 599 if (node.next is tree_ir.Unreachable && emitUnreachableAsReturn.last) { |
629 // Emit as 'return exp' to assist local analysis in the VM. | 600 // Emit as 'return exp' to assist local analysis in the VM. |
630 SourceInformation sourceInformation = node.expression.sourceInformation; | 601 SourceInformation sourceInformation = node.expression.sourceInformation; |
631 accumulator.add( | 602 accumulator |
632 new js.Return(exp).withSourceInformation(sourceInformation)); | 603 .add(new js.Return(exp).withSourceInformation(sourceInformation)); |
633 return null; | 604 return null; |
634 } else { | 605 } else { |
635 accumulator.add(new js.ExpressionStatement(exp)); | 606 accumulator.add(new js.ExpressionStatement(exp)); |
636 return node.next; | 607 return node.next; |
637 } | 608 } |
638 } | 609 } |
639 | 610 |
640 bool isNullReturn(tree_ir.Statement node) { | 611 bool isNullReturn(tree_ir.Statement node) { |
641 return node is tree_ir.Return && isNull(node.value); | 612 return node is tree_ir.Return && isNull(node.value); |
642 } | 613 } |
643 | 614 |
644 bool isEndOfMethod(tree_ir.Statement node) { | 615 bool isEndOfMethod(tree_ir.Statement node) { |
645 return isNullReturn(node) || | 616 return isNullReturn(node) || |
646 node is tree_ir.Break && isNullReturn(node.target.binding.next); | 617 node is tree_ir.Break && isNullReturn(node.target.binding.next); |
647 } | 618 } |
648 | 619 |
649 @override | 620 @override |
650 visitIf(tree_ir.If node) { | 621 visitIf(tree_ir.If node) { |
651 js.Expression condition = visitExpression(node.condition); | 622 js.Expression condition = visitExpression(node.condition); |
652 int usesBefore = fallthrough.useCount; | 623 int usesBefore = fallthrough.useCount; |
653 // Unless the 'else' part ends the method. make sure to terminate any | 624 // Unless the 'else' part ends the method. make sure to terminate any |
654 // uncompletable code paths in the 'then' part. | 625 // uncompletable code paths in the 'then' part. |
655 emitUnreachableAsReturn.add(!isEndOfMethod(node.elseStatement)); | 626 emitUnreachableAsReturn.add(!isEndOfMethod(node.elseStatement)); |
656 js.Statement thenBody = buildBodyStatement(node.thenStatement); | 627 js.Statement thenBody = buildBodyStatement(node.thenStatement); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
721 accumulator = <js.Statement>[]; | 692 accumulator = <js.Statement>[]; |
722 while (statement != null) { | 693 while (statement != null) { |
723 statement = visitStatement(statement); | 694 statement = visitStatement(statement); |
724 } | 695 } |
725 js.Statement result = new js.Block(accumulator); | 696 js.Statement result = new js.Block(accumulator); |
726 accumulator = savedAccumulator; | 697 accumulator = savedAccumulator; |
727 return result; | 698 return result; |
728 } | 699 } |
729 | 700 |
730 js.Expression makeSequence(List<tree_ir.Expression> list) { | 701 js.Expression makeSequence(List<tree_ir.Expression> list) { |
731 return list.map(visitExpression).reduce((x,y) => new js.Binary(',', x, y)); | 702 return list.map(visitExpression).reduce((x, y) => new js.Binary(',', x, y)); |
732 } | 703 } |
733 | 704 |
734 @override | 705 @override |
735 visitFor(tree_ir.For node) { | 706 visitFor(tree_ir.For node) { |
736 js.Expression condition = visitExpression(node.condition); | 707 js.Expression condition = visitExpression(node.condition); |
737 shortBreak.push(node.next); | 708 shortBreak.push(node.next); |
738 shortContinue.push(node); | 709 shortContinue.push(node); |
739 fallthrough.push(node); | 710 fallthrough.push(node); |
740 emitUnreachableAsReturn.add(true); | 711 emitUnreachableAsReturn.add(true); |
741 js.Statement body = buildBodyStatement(node.body); | 712 js.Statement body = buildBodyStatement(node.body); |
742 emitUnreachableAsReturn.removeLast(); | 713 emitUnreachableAsReturn.removeLast(); |
743 fallthrough.pop(); | 714 fallthrough.pop(); |
744 shortContinue.pop(); | 715 shortContinue.pop(); |
745 shortBreak.pop(); | 716 shortBreak.pop(); |
746 js.Statement loopNode; | 717 js.Statement loopNode; |
747 if (node.updates.isEmpty) { | 718 if (node.updates.isEmpty) { |
748 loopNode = new js.While(condition, body); | 719 loopNode = new js.While(condition, body); |
749 } else { // Compile as a for loop. | 720 } else { |
| 721 // Compile as a for loop. |
750 js.Expression init; | 722 js.Expression init; |
751 if (accumulator.isNotEmpty && | 723 if (accumulator.isNotEmpty && |
752 accumulator.last is js.ExpressionStatement) { | 724 accumulator.last is js.ExpressionStatement) { |
753 // Take the preceding expression from the accumulator and use | 725 // Take the preceding expression from the accumulator and use |
754 // it as the initializer expression. | 726 // it as the initializer expression. |
755 js.ExpressionStatement initStmt = accumulator.removeLast(); | 727 js.ExpressionStatement initStmt = accumulator.removeLast(); |
756 init = initStmt.expression; | 728 init = initStmt.expression; |
757 } | 729 } |
758 js.Expression update = makeSequence(node.updates); | 730 js.Expression update = makeSequence(node.updates); |
759 loopNode = new js.For(init, condition, update, body); | 731 loopNode = new js.For(init, condition, update, body); |
(...skipping 11 matching lines...) Expand all Loading... |
771 emitUnreachableAsReturn.add(true); | 743 emitUnreachableAsReturn.add(true); |
772 js.Statement jsBody = buildBodyStatement(node.body); | 744 js.Statement jsBody = buildBodyStatement(node.body); |
773 emitUnreachableAsReturn.removeLast(); | 745 emitUnreachableAsReturn.removeLast(); |
774 fallthrough.pop(); | 746 fallthrough.pop(); |
775 shortContinue.pop(); | 747 shortContinue.pop(); |
776 if (shortBreak.useCount > 0) { | 748 if (shortBreak.useCount > 0) { |
777 // Short breaks use the current fallthrough target. | 749 // Short breaks use the current fallthrough target. |
778 fallthrough.use(); | 750 fallthrough.use(); |
779 } | 751 } |
780 shortBreak.pop(); | 752 shortBreak.pop(); |
781 accumulator.add( | 753 accumulator |
782 insertLabel(node.label, new js.For(null, null, null, jsBody))); | 754 .add(insertLabel(node.label, new js.For(null, null, null, jsBody))); |
783 } | 755 } |
784 | 756 |
785 bool isNull(tree_ir.Expression node) { | 757 bool isNull(tree_ir.Expression node) { |
786 return node is tree_ir.Constant && node.value.isNull; | 758 return node is tree_ir.Constant && node.value.isNull; |
787 } | 759 } |
788 | 760 |
789 @override | 761 @override |
790 void visitReturn(tree_ir.Return node) { | 762 void visitReturn(tree_ir.Return node) { |
791 if (isNull(node.value) && fallthrough.target == null) { | 763 if (isNull(node.value) && fallthrough.target == null) { |
792 // Do nothing. Implicitly return JS undefined by falling over the end. | 764 // Do nothing. Implicitly return JS undefined by falling over the end. |
793 registry.registerCompileTimeConstant(new NullConstantValue()); | 765 registry.registerCompileTimeConstant(new NullConstantValue()); |
794 fallthrough.use(); | 766 fallthrough.use(); |
795 } else { | 767 } else { |
796 accumulator.add(new js.Return(visitExpression(node.value)) | 768 accumulator.add(new js.Return(visitExpression(node.value)) |
797 .withSourceInformation(node.sourceInformation)); | 769 .withSourceInformation(node.sourceInformation)); |
798 } | 770 } |
799 } | 771 } |
800 | 772 |
801 @override | 773 @override |
802 void visitThrow(tree_ir.Throw node) { | 774 void visitThrow(tree_ir.Throw node) { |
803 accumulator.add(new js.Throw(visitExpression(node.value))); | 775 accumulator.add(new js.Throw(visitExpression(node.value))); |
804 } | 776 } |
805 | 777 |
806 @override | 778 @override |
807 void visitUnreachable(tree_ir.Unreachable node) { | 779 void visitUnreachable(tree_ir.Unreachable node) { |
(...skipping 23 matching lines...) Expand all Loading... |
831 js.Expression visitCreateInstance(tree_ir.CreateInstance node) { | 803 js.Expression visitCreateInstance(tree_ir.CreateInstance node) { |
832 ClassElement classElement = node.classElement; | 804 ClassElement classElement = node.classElement; |
833 // TODO(asgerf): To allow inlining of InvokeConstructor, CreateInstance must | 805 // TODO(asgerf): To allow inlining of InvokeConstructor, CreateInstance must |
834 // carry a DartType so we can register the instantiated type | 806 // carry a DartType so we can register the instantiated type |
835 // with its type arguments. Otherwise dataflow analysis is | 807 // with its type arguments. Otherwise dataflow analysis is |
836 // needed to reconstruct the instantiated type. | 808 // needed to reconstruct the instantiated type. |
837 registry.registerInstantiation(classElement.rawType); | 809 registry.registerInstantiation(classElement.rawType); |
838 if (classElement is ClosureClassElement) { | 810 if (classElement is ClosureClassElement) { |
839 registry.registerInstantiatedClosure(classElement.methodElement); | 811 registry.registerInstantiatedClosure(classElement.methodElement); |
840 } | 812 } |
841 js.Expression instance = new js.New( | 813 js.Expression instance = new js.New(glue.constructorAccess(classElement), |
842 glue.constructorAccess(classElement), | |
843 visitExpressionList(node.arguments)) | 814 visitExpressionList(node.arguments)) |
844 .withSourceInformation(node.sourceInformation); | 815 .withSourceInformation(node.sourceInformation); |
845 | 816 |
846 tree_ir.Expression typeInformation = node.typeInformation; | 817 tree_ir.Expression typeInformation = node.typeInformation; |
847 if (typeInformation != null) { | 818 if (typeInformation != null) { |
848 FunctionElement helper = glue.getAddRuntimeTypeInformation(); | 819 FunctionElement helper = glue.getAddRuntimeTypeInformation(); |
849 js.Expression typeArguments = visitExpression(typeInformation); | 820 js.Expression typeArguments = visitExpression(typeInformation); |
850 return buildStaticHelperInvocation(helper, | 821 return buildStaticHelperInvocation( |
851 <js.Expression>[instance, typeArguments], | 822 helper, <js.Expression>[instance, typeArguments], |
852 sourceInformation: node.sourceInformation); | 823 sourceInformation: node.sourceInformation); |
853 } else { | 824 } else { |
854 return instance; | 825 return instance; |
855 } | 826 } |
856 } | 827 } |
857 | 828 |
858 @override | 829 @override |
859 js.Expression visitCreateInvocationMirror( | 830 js.Expression visitCreateInvocationMirror( |
860 tree_ir.CreateInvocationMirror node) { | 831 tree_ir.CreateInvocationMirror node) { |
861 js.Expression name = js.string(node.selector.name); | 832 js.Expression name = js.string(node.selector.name); |
862 js.Expression internalName = | 833 js.Expression internalName = |
863 js.quoteName(glue.invocationName(node.selector)); | 834 js.quoteName(glue.invocationName(node.selector)); |
864 js.Expression kind = js.number(node.selector.invocationMirrorKind); | 835 js.Expression kind = js.number(node.selector.invocationMirrorKind); |
865 js.Expression arguments = new js.ArrayInitializer( | 836 js.Expression arguments = |
866 visitExpressionList(node.arguments)); | 837 new js.ArrayInitializer(visitExpressionList(node.arguments)); |
867 js.Expression argumentNames = new js.ArrayInitializer( | 838 js.Expression argumentNames = new js.ArrayInitializer( |
868 node.selector.namedArguments.map(js.string).toList(growable: false)); | 839 node.selector.namedArguments.map(js.string).toList(growable: false)); |
869 return buildStaticHelperInvocation(glue.createInvocationMirrorMethod, | 840 return buildStaticHelperInvocation(glue.createInvocationMirrorMethod, |
870 <js.Expression>[name, internalName, kind, arguments, argumentNames]); | 841 <js.Expression>[name, internalName, kind, arguments, argumentNames]); |
871 } | 842 } |
872 | 843 |
873 @override | 844 @override |
874 js.Expression visitInterceptor(tree_ir.Interceptor node) { | 845 js.Expression visitInterceptor(tree_ir.Interceptor node) { |
875 registry.registerUseInterceptor(); | 846 registry.registerUseInterceptor(); |
876 // Default to all intercepted classes if they have not been computed. | 847 // Default to all intercepted classes if they have not been computed. |
877 // This is to ensure we can run codegen without prior optimization passes. | 848 // This is to ensure we can run codegen without prior optimization passes. |
878 Set<ClassElement> interceptedClasses = node.interceptedClasses.isEmpty | 849 Set<ClassElement> interceptedClasses = node.interceptedClasses.isEmpty |
879 ? glue.interceptedClasses | 850 ? glue.interceptedClasses |
880 : node.interceptedClasses; | 851 : node.interceptedClasses; |
881 registry.registerSpecializedGetInterceptor(interceptedClasses); | 852 registry.registerSpecializedGetInterceptor(interceptedClasses); |
882 js.Name helperName = glue.getInterceptorName(interceptedClasses); | 853 js.Name helperName = glue.getInterceptorName(interceptedClasses); |
883 js.Expression globalHolder = glue.getInterceptorLibrary(); | 854 js.Expression globalHolder = glue.getInterceptorLibrary(); |
884 return js.js('#.#(#)', | 855 return js.js('#.#(#)', [ |
885 [globalHolder, helperName, visitExpression(node.input)]) | 856 globalHolder, |
886 .withSourceInformation(node.sourceInformation); | 857 helperName, |
| 858 visitExpression(node.input) |
| 859 ]).withSourceInformation(node.sourceInformation); |
887 } | 860 } |
888 | 861 |
889 @override | 862 @override |
890 js.Expression visitGetField(tree_ir.GetField node) { | 863 js.Expression visitGetField(tree_ir.GetField node) { |
891 registry.registerStaticUse(new StaticUse.fieldGet(node.field)); | 864 registry.registerStaticUse(new StaticUse.fieldGet(node.field)); |
892 return new js.PropertyAccess( | 865 return new js.PropertyAccess(visitExpression(node.object), |
893 visitExpression(node.object), | 866 glue.instanceFieldPropertyName(node.field)) |
894 glue.instanceFieldPropertyName(node.field)) | |
895 .withSourceInformation(node.sourceInformation); | 867 .withSourceInformation(node.sourceInformation); |
896 } | 868 } |
897 | 869 |
898 @override | 870 @override |
899 js.Expression visitSetField(tree_ir.SetField node) { | 871 js.Expression visitSetField(tree_ir.SetField node) { |
900 registry.registerStaticUse(new StaticUse.fieldSet(node.field)); | 872 registry.registerStaticUse(new StaticUse.fieldSet(node.field)); |
901 js.PropertyAccess field = | 873 js.PropertyAccess field = new js.PropertyAccess( |
902 new js.PropertyAccess( | 874 visitExpression(node.object), |
903 visitExpression(node.object), | 875 glue.instanceFieldPropertyName(node.field)); |
904 glue.instanceFieldPropertyName(node.field)); | 876 return makeAssignment(field, node.value, |
905 return makeAssignment(field, node.value, compound: node.compound, | 877 compound: node.compound, sourceInformation: node.sourceInformation); |
906 sourceInformation: node.sourceInformation); | |
907 } | 878 } |
908 | 879 |
909 @override | 880 @override |
910 js.Expression visitGetStatic(tree_ir.GetStatic node) { | 881 js.Expression visitGetStatic(tree_ir.GetStatic node) { |
911 assert(node.element is FieldElement || node.element is FunctionElement); | 882 assert(node.element is FieldElement || node.element is FunctionElement); |
912 if (node.element is FunctionElement) { | 883 if (node.element is FunctionElement) { |
913 // Tear off a method. | 884 // Tear off a method. |
914 registry.registerStaticUse( | 885 registry.registerStaticUse( |
915 new StaticUse.staticTearOff(node.element.declaration)); | 886 new StaticUse.staticTearOff(node.element.declaration)); |
916 return glue.isolateStaticClosureAccess(node.element) | 887 return glue |
917 .withSourceInformation(node.sourceInformation); | 888 .isolateStaticClosureAccess(node.element) |
| 889 .withSourceInformation(node.sourceInformation); |
918 } | 890 } |
919 if (node.useLazyGetter) { | 891 if (node.useLazyGetter) { |
920 // Read a lazily initialized field. | 892 // Read a lazily initialized field. |
921 registry.registerStaticUse( | 893 registry.registerStaticUse( |
922 new StaticUse.staticInit(node.element.declaration)); | 894 new StaticUse.staticInit(node.element.declaration)); |
923 js.Expression getter = glue.isolateLazyInitializerAccess(node.element); | 895 js.Expression getter = glue.isolateLazyInitializerAccess(node.element); |
924 return new js.Call(getter, <js.Expression>[], | 896 return new js.Call(getter, <js.Expression>[], |
925 sourceInformation: node.sourceInformation); | 897 sourceInformation: node.sourceInformation); |
926 } | 898 } |
927 // Read an eagerly initialized field. | 899 // Read an eagerly initialized field. |
928 registry.registerStaticUse( | 900 registry |
929 new StaticUse.staticGet(node.element.declaration)); | 901 .registerStaticUse(new StaticUse.staticGet(node.element.declaration)); |
930 return glue.staticFieldAccess(node.element) | 902 return glue |
| 903 .staticFieldAccess(node.element) |
931 .withSourceInformation(node.sourceInformation); | 904 .withSourceInformation(node.sourceInformation); |
932 } | 905 } |
933 | 906 |
934 @override | 907 @override |
935 js.Expression visitSetStatic(tree_ir.SetStatic node) { | 908 js.Expression visitSetStatic(tree_ir.SetStatic node) { |
936 assert(node.element is FieldElement); | 909 assert(node.element is FieldElement); |
937 registry.registerStaticUse( | 910 registry |
938 new StaticUse.staticSet(node.element.declaration)); | 911 .registerStaticUse(new StaticUse.staticSet(node.element.declaration)); |
939 js.Expression field = glue.staticFieldAccess(node.element); | 912 js.Expression field = glue.staticFieldAccess(node.element); |
940 return makeAssignment(field, node.value, compound: node.compound, | 913 return makeAssignment(field, node.value, |
941 sourceInformation: node.sourceInformation); | 914 compound: node.compound, sourceInformation: node.sourceInformation); |
942 } | 915 } |
943 | 916 |
944 @override | 917 @override |
945 js.Expression visitGetLength(tree_ir.GetLength node) { | 918 js.Expression visitGetLength(tree_ir.GetLength node) { |
946 return new js.PropertyAccess.field(visitExpression(node.object), 'length'); | 919 return new js.PropertyAccess.field(visitExpression(node.object), 'length'); |
947 } | 920 } |
948 | 921 |
949 @override | 922 @override |
950 js.Expression visitGetIndex(tree_ir.GetIndex node) { | 923 js.Expression visitGetIndex(tree_ir.GetIndex node) { |
951 return new js.PropertyAccess( | 924 return new js.PropertyAccess( |
952 visitExpression(node.object), | 925 visitExpression(node.object), visitExpression(node.index)); |
953 visitExpression(node.index)); | |
954 } | 926 } |
955 | 927 |
956 @override | 928 @override |
957 js.Expression visitSetIndex(tree_ir.SetIndex node) { | 929 js.Expression visitSetIndex(tree_ir.SetIndex node) { |
958 js.Expression index = new js.PropertyAccess( | 930 js.Expression index = new js.PropertyAccess( |
959 visitExpression(node.object), visitExpression(node.index)); | 931 visitExpression(node.object), visitExpression(node.index)); |
960 return makeAssignment(index, node.value, compound: node.compound); | 932 return makeAssignment(index, node.value, compound: node.compound); |
961 } | 933 } |
962 | 934 |
963 js.Expression buildStaticHelperInvocation( | 935 js.Expression buildStaticHelperInvocation( |
964 FunctionElement helper, | 936 FunctionElement helper, List<js.Expression> arguments, |
965 List<js.Expression> arguments, | |
966 {SourceInformation sourceInformation}) { | 937 {SourceInformation sourceInformation}) { |
967 registry.registerStaticUse(new StaticUse.staticInvoke( | 938 registry.registerStaticUse(new StaticUse.staticInvoke( |
968 helper, new CallStructure.unnamed(arguments.length))); | 939 helper, new CallStructure.unnamed(arguments.length))); |
969 return buildStaticInvoke( | 940 return buildStaticInvoke(helper, arguments, |
970 helper, arguments, sourceInformation: sourceInformation); | 941 sourceInformation: sourceInformation); |
971 } | 942 } |
972 | 943 |
973 @override | 944 @override |
974 js.Expression visitReifyRuntimeType(tree_ir.ReifyRuntimeType node) { | 945 js.Expression visitReifyRuntimeType(tree_ir.ReifyRuntimeType node) { |
975 js.Expression typeToString = buildStaticHelperInvocation( | 946 js.Expression typeToString = buildStaticHelperInvocation( |
976 glue.getRuntimeTypeToString(), | 947 glue.getRuntimeTypeToString(), [visitExpression(node.value)], |
977 [visitExpression(node.value)], | |
978 sourceInformation: node.sourceInformation); | 948 sourceInformation: node.sourceInformation); |
979 return buildStaticHelperInvocation( | 949 return buildStaticHelperInvocation( |
980 glue.getCreateRuntimeType(), | 950 glue.getCreateRuntimeType(), [typeToString], |
981 [typeToString], | |
982 sourceInformation: node.sourceInformation); | 951 sourceInformation: node.sourceInformation); |
983 } | 952 } |
984 | 953 |
985 @override | 954 @override |
986 js.Expression visitReadTypeVariable(tree_ir.ReadTypeVariable node) { | 955 js.Expression visitReadTypeVariable(tree_ir.ReadTypeVariable node) { |
987 ClassElement context = node.variable.element.enclosingClass; | 956 ClassElement context = node.variable.element.enclosingClass; |
988 js.Expression index = js.number(glue.getTypeVariableIndex(node.variable)); | 957 js.Expression index = js.number(glue.getTypeVariableIndex(node.variable)); |
989 if (glue.needsSubstitutionForTypeVariableAccess(context)) { | 958 if (glue.needsSubstitutionForTypeVariableAccess(context)) { |
990 js.Expression typeName = glue.getRuntimeTypeName(context); | 959 js.Expression typeName = glue.getRuntimeTypeName(context); |
991 return buildStaticHelperInvocation( | 960 return buildStaticHelperInvocation(glue.getRuntimeTypeArgument(), |
992 glue.getRuntimeTypeArgument(), | |
993 [visitExpression(node.target), typeName, index], | 961 [visitExpression(node.target), typeName, index], |
994 sourceInformation: node.sourceInformation); | 962 sourceInformation: node.sourceInformation); |
995 } else { | 963 } else { |
996 return buildStaticHelperInvocation( | 964 return buildStaticHelperInvocation( |
997 glue.getTypeArgumentByIndex(), | 965 glue.getTypeArgumentByIndex(), [visitExpression(node.target), index], |
998 [visitExpression(node.target), index], | |
999 sourceInformation: node.sourceInformation); | 966 sourceInformation: node.sourceInformation); |
1000 } | 967 } |
1001 } | 968 } |
1002 | 969 |
1003 @override | 970 @override |
1004 js.Expression visitTypeExpression(tree_ir.TypeExpression node) { | 971 js.Expression visitTypeExpression(tree_ir.TypeExpression node) { |
1005 List<js.Expression> arguments = visitExpressionList(node.arguments); | 972 List<js.Expression> arguments = visitExpressionList(node.arguments); |
1006 switch (node.kind) { | 973 switch (node.kind) { |
1007 case tree_ir.TypeExpressionKind.COMPLETE: | 974 case tree_ir.TypeExpressionKind.COMPLETE: |
1008 return glue.generateTypeRepresentation( | 975 return glue.generateTypeRepresentation( |
1009 node.dartType, arguments, registry); | 976 node.dartType, arguments, registry); |
1010 case tree_ir.TypeExpressionKind.INSTANCE: | 977 case tree_ir.TypeExpressionKind.INSTANCE: |
1011 // We expect only flat types for the INSTANCE representation. | 978 // We expect only flat types for the INSTANCE representation. |
1012 assert(node.dartType == | 979 assert( |
1013 (node.dartType.element as ClassElement).thisType); | 980 node.dartType == (node.dartType.element as ClassElement).thisType); |
1014 registry.registerInstantiatedClass(glue.listClass); | 981 registry.registerInstantiatedClass(glue.listClass); |
1015 return new js.ArrayInitializer(arguments); | 982 return new js.ArrayInitializer(arguments); |
1016 } | 983 } |
1017 } | 984 } |
1018 | 985 |
1019 js.Node handleForeignCode(tree_ir.ForeignCode node) { | 986 js.Node handleForeignCode(tree_ir.ForeignCode node) { |
1020 if (node.dependency != null) { | 987 if (node.dependency != null) { |
1021 // Dependency is only used if [node] calls a Dart function. Currently only | 988 // Dependency is only used if [node] calls a Dart function. Currently only |
1022 // through foreign function `RAW_DART_FUNCTION_REF`. | 989 // through foreign function `RAW_DART_FUNCTION_REF`. |
1023 registry.registerStaticUse( | 990 registry.registerStaticUse(new StaticUse.staticInvoke( |
1024 new StaticUse.staticInvoke( | 991 node.dependency, new CallStructure.unnamed(node.arguments.length))); |
1025 node.dependency, | |
1026 new CallStructure.unnamed(node.arguments.length))); | |
1027 } | 992 } |
1028 // TODO(sra,johnniwinther): Should this be in CodegenRegistry? | 993 // TODO(sra,johnniwinther): Should this be in CodegenRegistry? |
1029 glue.registerNativeBehavior(node.nativeBehavior, node); | 994 glue.registerNativeBehavior(node.nativeBehavior, node); |
1030 return node.codeTemplate.instantiate(visitExpressionList(node.arguments)) | 995 return node.codeTemplate |
| 996 .instantiate(visitExpressionList(node.arguments)) |
1031 .withSourceInformation(node.sourceInformation); | 997 .withSourceInformation(node.sourceInformation); |
1032 } | 998 } |
1033 | 999 |
1034 @override | 1000 @override |
1035 js.Expression visitForeignExpression(tree_ir.ForeignExpression node) { | 1001 js.Expression visitForeignExpression(tree_ir.ForeignExpression node) { |
1036 return handleForeignCode(node); | 1002 return handleForeignCode(node); |
1037 } | 1003 } |
1038 | 1004 |
1039 @override | 1005 @override |
1040 void visitForeignStatement(tree_ir.ForeignStatement node) { | 1006 void visitForeignStatement(tree_ir.ForeignStatement node) { |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1113 return normalizeBitOp(js.js('# << #', args), node); | 1079 return normalizeBitOp(js.js('# << #', args), node); |
1114 case BuiltinOperator.NumShr: | 1080 case BuiltinOperator.NumShr: |
1115 // No normalization required since output is always uint32. | 1081 // No normalization required since output is always uint32. |
1116 return js.js('# >>> #', args); | 1082 return js.js('# >>> #', args); |
1117 case BuiltinOperator.NumBitNot: | 1083 case BuiltinOperator.NumBitNot: |
1118 return js.js('(~#) >>> 0', args); | 1084 return js.js('(~#) >>> 0', args); |
1119 case BuiltinOperator.NumNegate: | 1085 case BuiltinOperator.NumNegate: |
1120 return js.js('-#', args); | 1086 return js.js('-#', args); |
1121 case BuiltinOperator.StringConcatenate: | 1087 case BuiltinOperator.StringConcatenate: |
1122 if (args.isEmpty) return js.string(''); | 1088 if (args.isEmpty) return js.string(''); |
1123 return args.reduce((e1,e2) => new js.Binary('+', e1, e2)); | 1089 return args.reduce((e1, e2) => new js.Binary('+', e1, e2)); |
1124 case BuiltinOperator.CharCodeAt: | 1090 case BuiltinOperator.CharCodeAt: |
1125 return js.js('#.charCodeAt(#)', args); | 1091 return js.js('#.charCodeAt(#)', args); |
1126 case BuiltinOperator.Identical: | 1092 case BuiltinOperator.Identical: |
1127 registry.registerStaticUse(new StaticUse.staticInvoke( | 1093 registry.registerStaticUse(new StaticUse.staticInvoke( |
1128 glue.identicalFunction, new CallStructure.unnamed(args.length))); | 1094 glue.identicalFunction, new CallStructure.unnamed(args.length))); |
1129 return buildStaticHelperInvocation(glue.identicalFunction, args); | 1095 return buildStaticHelperInvocation(glue.identicalFunction, args); |
1130 case BuiltinOperator.StrictEq: | 1096 case BuiltinOperator.StrictEq: |
1131 return new js.Binary('===', args[0], args[1]); | 1097 return new js.Binary('===', args[0], args[1]); |
1132 case BuiltinOperator.StrictNeq: | 1098 case BuiltinOperator.StrictNeq: |
1133 return new js.Binary('!==', args[0], args[1]); | 1099 return new js.Binary('!==', args[0], args[1]); |
(...skipping 28 matching lines...) Expand all Loading... |
1162 // TODO(sra): Remove boolify (i.e. !!). | 1128 // TODO(sra): Remove boolify (i.e. !!). |
1163 return js.js(r'!!#.immutable$list', args); | 1129 return js.js(r'!!#.immutable$list', args); |
1164 } | 1130 } |
1165 } | 1131 } |
1166 | 1132 |
1167 return createExpression().withSourceInformation(node.sourceInformation); | 1133 return createExpression().withSourceInformation(node.sourceInformation); |
1168 } | 1134 } |
1169 | 1135 |
1170 /// Add a uint32 normalization `op >>> 0` to [op] if it is not in 31-bit | 1136 /// Add a uint32 normalization `op >>> 0` to [op] if it is not in 31-bit |
1171 /// range. | 1137 /// range. |
1172 js.Expression normalizeBitOp(js.Expression op, | 1138 js.Expression normalizeBitOp( |
1173 tree_ir.ApplyBuiltinOperator node) { | 1139 js.Expression op, tree_ir.ApplyBuiltinOperator node) { |
1174 const MAX_UINT31 = 0x7fffffff; | 1140 const MAX_UINT31 = 0x7fffffff; |
1175 const MAX_UINT32 = 0xffffffff; | 1141 const MAX_UINT32 = 0xffffffff; |
1176 | 1142 |
1177 int constantValue(tree_ir.Expression e) { | 1143 int constantValue(tree_ir.Expression e) { |
1178 if (e is tree_ir.Constant) { | 1144 if (e is tree_ir.Constant) { |
1179 ConstantValue value = e.value; | 1145 ConstantValue value = e.value; |
1180 if (!value.isInt) return null; | 1146 if (!value.isInt) return null; |
1181 IntConstantValue intConstant = value; | 1147 IntConstantValue intConstant = value; |
1182 if (intConstant.primitiveValue < 0) return null; | 1148 if (intConstant.primitiveValue < 0) return null; |
1183 if (intConstant.primitiveValue > MAX_UINT32) return null; | 1149 if (intConstant.primitiveValue > MAX_UINT32) return null; |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1266 void registerDefaultParameterValues(ExecutableElement element) { | 1232 void registerDefaultParameterValues(ExecutableElement element) { |
1267 if (element is! FunctionElement) return; | 1233 if (element is! FunctionElement) return; |
1268 FunctionElement function = element; | 1234 FunctionElement function = element; |
1269 if (function.isStatic) return; // Defaults are inlined at call sites. | 1235 if (function.isStatic) return; // Defaults are inlined at call sites. |
1270 function.functionSignature.forEachOptionalParameter((param) { | 1236 function.functionSignature.forEachOptionalParameter((param) { |
1271 ConstantValue constant = glue.getDefaultParameterValue(param); | 1237 ConstantValue constant = glue.getDefaultParameterValue(param); |
1272 registry.registerCompileTimeConstant(constant); | 1238 registry.registerCompileTimeConstant(constant); |
1273 }); | 1239 }); |
1274 } | 1240 } |
1275 } | 1241 } |
OLD | NEW |