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 '../../tree_ir/tree_ir_nodes.dart' as tree_ir; | 9 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir; |
10 import '../../tree_ir/tree_ir_nodes.dart' show BuiltinOperator; | 10 import '../../tree_ir/tree_ir_nodes.dart' show BuiltinOperator; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 new Maplet<VariableElement, String>(); | 44 new Maplet<VariableElement, String>(); |
45 | 45 |
46 /// Variable names that have already been used. Used to avoid name clashes. | 46 /// Variable names that have already been used. Used to avoid name clashes. |
47 Set<String> usedVariableNames = new Set<String>(); | 47 Set<String> usedVariableNames = new Set<String>(); |
48 | 48 |
49 final tree_ir.FallthroughStack fallthrough = new tree_ir.FallthroughStack(); | 49 final tree_ir.FallthroughStack fallthrough = new tree_ir.FallthroughStack(); |
50 | 50 |
51 /// Stacks whose top element is the current target of an unlabeled break | 51 /// Stacks whose top element is the current target of an unlabeled break |
52 /// or continue. For continues, this is the loop node itself. | 52 /// or continue. For continues, this is the loop node itself. |
53 final tree_ir.FallthroughStack shortBreak = new tree_ir.FallthroughStack(); | 53 final tree_ir.FallthroughStack shortBreak = new tree_ir.FallthroughStack(); |
54 final tree_ir.FallthroughStack shortContinue = | 54 final tree_ir.FallthroughStack shortContinue = |
55 new tree_ir.FallthroughStack(); | 55 new tree_ir.FallthroughStack(); |
56 | 56 |
57 Set<tree_ir.Label> usedLabels = new Set<tree_ir.Label>(); | 57 Set<tree_ir.Label> usedLabels = new Set<tree_ir.Label>(); |
58 | 58 |
59 List<js.Statement> accumulator = new List<js.Statement>(); | 59 List<js.Statement> accumulator = new List<js.Statement>(); |
60 | 60 |
61 CodeGenerator(this.glue, this.registry); | 61 CodeGenerator(this.glue, this.registry); |
62 | 62 |
63 /// Generates JavaScript code for the body of [function]. | 63 /// Generates JavaScript code for the body of [function]. |
64 js.Fun buildFunction(tree_ir.FunctionDefinition function) { | 64 js.Fun buildFunction(tree_ir.FunctionDefinition function) { |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 } | 176 } |
177 | 177 |
178 @override | 178 @override |
179 js.Expression visitConditional(tree_ir.Conditional node) { | 179 js.Expression visitConditional(tree_ir.Conditional node) { |
180 return new js.Conditional( | 180 return new js.Conditional( |
181 visitExpression(node.condition), | 181 visitExpression(node.condition), |
182 visitExpression(node.thenExpression), | 182 visitExpression(node.thenExpression), |
183 visitExpression(node.elseExpression)); | 183 visitExpression(node.elseExpression)); |
184 } | 184 } |
185 | 185 |
186 js.Expression buildConstant(ConstantValue constant) { | 186 js.Expression buildConstant(ConstantValue constant, |
| 187 {SourceInformation sourceInformation}) { |
187 registry.registerCompileTimeConstant(constant); | 188 registry.registerCompileTimeConstant(constant); |
188 return glue.constantReference(constant); | 189 return glue.constantReference(constant) |
| 190 .withSourceInformation(sourceInformation); |
189 } | 191 } |
190 | 192 |
191 @override | 193 @override |
192 js.Expression visitConstant(tree_ir.Constant node) { | 194 js.Expression visitConstant(tree_ir.Constant node) { |
193 return buildConstant(node.value); | 195 return buildConstant( |
| 196 node.value, |
| 197 sourceInformation: node.sourceInformation); |
194 } | 198 } |
195 | 199 |
196 js.Expression compileConstant(ParameterElement parameter) { | 200 js.Expression compileConstant(ParameterElement parameter) { |
197 return buildConstant(glue.getConstantValueForVariable(parameter)); | 201 return buildConstant(glue.getConstantValueForVariable(parameter)); |
198 } | 202 } |
199 | 203 |
200 js.Expression buildStaticInvoke(Element target, | 204 js.Expression buildStaticInvoke(Element target, |
201 List<js.Expression> arguments, | 205 List<js.Expression> arguments, |
202 {SourceInformation sourceInformation}) { | 206 {SourceInformation sourceInformation}) { |
203 registry.registerStaticInvocation(target.declaration); | 207 registry.registerStaticInvocation(target.declaration); |
204 js.Expression elementAccess = glue.staticFunctionAccess(target); | 208 js.Expression elementAccess = glue.staticFunctionAccess(target); |
205 return new js.Call(elementAccess, arguments, | 209 return new js.Call(elementAccess, arguments, |
206 sourceInformation: sourceInformation); | 210 sourceInformation: sourceInformation); |
207 } | 211 } |
208 | 212 |
209 @override | 213 @override |
210 js.Expression visitInvokeConstructor(tree_ir.InvokeConstructor node) { | 214 js.Expression visitInvokeConstructor(tree_ir.InvokeConstructor node) { |
211 if (node.constant != null) return giveup(node); | 215 if (node.constant != null) return giveup(node); |
212 | 216 |
213 registry.registerInstantiatedType(node.type); | 217 registry.registerInstantiatedType(node.type); |
214 FunctionElement target = node.target; | 218 FunctionElement target = node.target; |
215 List<js.Expression> arguments = visitExpressionList(node.arguments); | 219 List<js.Expression> arguments = visitExpressionList(node.arguments); |
216 return buildStaticInvoke(target, arguments); | 220 return buildStaticInvoke( |
| 221 target, arguments, sourceInformation: node.sourceInformation); |
217 } | 222 } |
218 | 223 |
219 void registerMethodInvoke(tree_ir.InvokeMethod node) { | 224 void registerMethodInvoke(tree_ir.InvokeMethod node) { |
220 Selector selector = node.selector; | 225 Selector selector = node.selector; |
221 TypeMask mask = node.mask; | 226 TypeMask mask = node.mask; |
222 if (selector.isGetter) { | 227 if (selector.isGetter) { |
223 registry.registerDynamicGetter(new UniverseSelector(selector, mask)); | 228 registry.registerDynamicGetter(new UniverseSelector(selector, mask)); |
224 } else if (selector.isSetter) { | 229 } else if (selector.isSetter) { |
225 registry.registerDynamicSetter(new UniverseSelector(selector, mask)); | 230 registry.registerDynamicSetter(new UniverseSelector(selector, mask)); |
226 } else { | 231 } else { |
227 assert(invariant(CURRENT_ELEMENT_SPANNABLE, | 232 assert(invariant(CURRENT_ELEMENT_SPANNABLE, |
228 selector.isCall || selector.isOperator || | 233 selector.isCall || selector.isOperator || |
229 selector.isIndex || selector.isIndexSet, | 234 selector.isIndex || selector.isIndexSet, |
230 message: 'unexpected kind ${selector.kind}')); | 235 message: 'unexpected kind ${selector.kind}')); |
231 // TODO(sigurdm): We should find a better place to register the call. | 236 // TODO(sigurdm): We should find a better place to register the call. |
232 Selector call = new Selector.callClosureFrom(selector); | 237 Selector call = new Selector.callClosureFrom(selector); |
233 registry.registerDynamicInvocation(new UniverseSelector(call, null)); | 238 registry.registerDynamicInvocation(new UniverseSelector(call, null)); |
234 registry.registerDynamicInvocation(new UniverseSelector(selector, mask)); | 239 registry.registerDynamicInvocation(new UniverseSelector(selector, mask)); |
235 } | 240 } |
236 } | 241 } |
237 | 242 |
238 @override | 243 @override |
239 js.Expression visitInvokeMethod(tree_ir.InvokeMethod node) { | 244 js.Expression visitInvokeMethod(tree_ir.InvokeMethod node) { |
240 registerMethodInvoke(node); | 245 registerMethodInvoke(node); |
241 return js.propertyCall(visitExpression(node.receiver), | 246 return js.propertyCall(visitExpression(node.receiver), |
242 glue.invocationName(node.selector), | 247 glue.invocationName(node.selector), |
243 visitExpressionList(node.arguments)); | 248 visitExpressionList(node.arguments)) |
| 249 .withSourceInformation(node.sourceInformation); |
244 } | 250 } |
245 | 251 |
246 @override | 252 @override |
247 js.Expression visitInvokeStatic(tree_ir.InvokeStatic node) { | 253 js.Expression visitInvokeStatic(tree_ir.InvokeStatic node) { |
248 FunctionElement target = node.target; | 254 FunctionElement target = node.target; |
249 List<js.Expression> arguments = visitExpressionList(node.arguments); | 255 List<js.Expression> arguments = visitExpressionList(node.arguments); |
250 return buildStaticInvoke(target, arguments, | 256 return buildStaticInvoke(target, arguments, |
251 sourceInformation: node.sourceInformation); | 257 sourceInformation: node.sourceInformation); |
252 } | 258 } |
253 | 259 |
254 @override | 260 @override |
255 js.Expression visitInvokeMethodDirectly(tree_ir.InvokeMethodDirectly node) { | 261 js.Expression visitInvokeMethodDirectly(tree_ir.InvokeMethodDirectly node) { |
256 registry.registerDirectInvocation(node.target.declaration); | 262 registry.registerDirectInvocation(node.target.declaration); |
257 if (node.target is ConstructorBodyElement) { | 263 if (node.target is ConstructorBodyElement) { |
258 // A constructor body cannot be overriden or intercepted, so we can | 264 // A constructor body cannot be overriden or intercepted, so we can |
259 // use the short form for this invocation. | 265 // use the short form for this invocation. |
260 return js.js('#.#(#)', | 266 return js.js('#.#(#)', |
261 [visitExpression(node.receiver), | 267 [visitExpression(node.receiver), |
262 glue.instanceMethodName(node.target), | 268 glue.instanceMethodName(node.target), |
263 visitExpressionList(node.arguments)]); | 269 visitExpressionList(node.arguments)]) |
| 270 .withSourceInformation(node.sourceInformation); |
264 } | 271 } |
265 return js.js('#.#.call(#, #)', | 272 return js.js('#.#.call(#, #)', |
266 [glue.prototypeAccess(node.target.enclosingClass), | 273 [glue.prototypeAccess(node.target.enclosingClass), |
267 glue.invocationName(node.selector), | 274 glue.invocationName(node.selector), |
268 visitExpression(node.receiver), | 275 visitExpression(node.receiver), |
269 visitExpressionList(node.arguments)]); | 276 visitExpressionList(node.arguments)]) |
| 277 .withSourceInformation(node.sourceInformation); |
270 } | 278 } |
271 | 279 |
272 @override | 280 @override |
273 js.Expression visitLiteralList(tree_ir.LiteralList node) { | 281 js.Expression visitLiteralList(tree_ir.LiteralList node) { |
274 registry.registerInstantiatedClass(glue.listClass); | 282 registry.registerInstantiatedClass(glue.listClass); |
275 List<js.Expression> entries = visitExpressionList(node.values); | 283 List<js.Expression> entries = visitExpressionList(node.values); |
276 return new js.ArrayInitializer(entries); | 284 return new js.ArrayInitializer(entries); |
277 } | 285 } |
278 | 286 |
279 @override | 287 @override |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 } | 426 } |
419 | 427 |
420 @override | 428 @override |
421 void visitBreak(tree_ir.Break node) { | 429 void visitBreak(tree_ir.Break node) { |
422 if (isEffectiveBreakTarget(node, fallthrough.target)) { | 430 if (isEffectiveBreakTarget(node, fallthrough.target)) { |
423 // Fall through to break target or to equivalent break. | 431 // Fall through to break target or to equivalent break. |
424 fallthrough.use(); | 432 fallthrough.use(); |
425 } else if (isEffectiveBreakTarget(node, shortBreak.target)) { | 433 } else if (isEffectiveBreakTarget(node, shortBreak.target)) { |
426 // Unlabeled break to the break target or to an equivalent break. | 434 // Unlabeled break to the break target or to an equivalent break. |
427 shortBreak.use(); | 435 shortBreak.use(); |
428 accumulator.add(new js.Break(null)); | 436 accumulator.add(new js.Break(null)); |
429 } else { | 437 } else { |
430 usedLabels.add(node.target); | 438 usedLabels.add(node.target); |
431 accumulator.add(new js.Break(node.target.name)); | 439 accumulator.add(new js.Break(node.target.name)); |
432 } | 440 } |
433 } | 441 } |
434 | 442 |
435 @override | 443 @override |
436 void visitExpressionStatement(tree_ir.ExpressionStatement node) { | 444 void visitExpressionStatement(tree_ir.ExpressionStatement node) { |
437 accumulator.add(new js.ExpressionStatement( | 445 accumulator.add(new js.ExpressionStatement( |
438 visitExpression(node.expression))); | 446 visitExpression(node.expression))); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
540 return node is tree_ir.Constant && node.value.isNull; | 548 return node is tree_ir.Constant && node.value.isNull; |
541 } | 549 } |
542 | 550 |
543 @override | 551 @override |
544 void visitReturn(tree_ir.Return node) { | 552 void visitReturn(tree_ir.Return node) { |
545 if (isNull(node.value) && fallthrough.target == null) { | 553 if (isNull(node.value) && fallthrough.target == null) { |
546 // Do nothing. Implicitly return JS undefined by falling over the end. | 554 // Do nothing. Implicitly return JS undefined by falling over the end. |
547 registry.registerCompileTimeConstant(new NullConstantValue()); | 555 registry.registerCompileTimeConstant(new NullConstantValue()); |
548 fallthrough.use(); | 556 fallthrough.use(); |
549 } else { | 557 } else { |
550 accumulator.add(new js.Return(visitExpression(node.value))); | 558 accumulator.add(new js.Return(visitExpression(node.value)) |
| 559 .withSourceInformation(node.sourceInformation)); |
551 } | 560 } |
552 } | 561 } |
553 | 562 |
554 @override | 563 @override |
555 void visitThrow(tree_ir.Throw node) { | 564 void visitThrow(tree_ir.Throw node) { |
556 accumulator.add(new js.Throw(visitExpression(node.value))); | 565 accumulator.add(new js.Throw(visitExpression(node.value))); |
557 } | 566 } |
558 | 567 |
559 @override | 568 @override |
560 void visitRethrow(tree_ir.Rethrow node) { | 569 void visitRethrow(tree_ir.Rethrow node) { |
(...skipping 28 matching lines...) Expand all Loading... |
589 // TODO(asgerf): To allow inlining of InvokeConstructor, CreateInstance must | 598 // TODO(asgerf): To allow inlining of InvokeConstructor, CreateInstance must |
590 // carry a DartType so we can register the instantiated type | 599 // carry a DartType so we can register the instantiated type |
591 // with its type arguments. Otherwise dataflow analysis is | 600 // with its type arguments. Otherwise dataflow analysis is |
592 // needed to reconstruct the instantiated type. | 601 // needed to reconstruct the instantiated type. |
593 registry.registerInstantiatedClass(classElement); | 602 registry.registerInstantiatedClass(classElement); |
594 if (classElement is ClosureClassElement) { | 603 if (classElement is ClosureClassElement) { |
595 registry.registerInstantiatedClosure(classElement.methodElement); | 604 registry.registerInstantiatedClosure(classElement.methodElement); |
596 } | 605 } |
597 js.Expression instance = new js.New( | 606 js.Expression instance = new js.New( |
598 glue.constructorAccess(classElement), | 607 glue.constructorAccess(classElement), |
599 visitExpressionList(node.arguments)); | 608 visitExpressionList(node.arguments)) |
| 609 .withSourceInformation(node.sourceInformation); |
600 | 610 |
601 List<tree_ir.Expression> typeInformation = node.typeInformation; | 611 List<tree_ir.Expression> typeInformation = node.typeInformation; |
602 assert(typeInformation.isEmpty || | 612 assert(typeInformation.isEmpty || |
603 typeInformation.length == classElement.typeVariables.length); | 613 typeInformation.length == classElement.typeVariables.length); |
604 if (typeInformation.isNotEmpty) { | 614 if (typeInformation.isNotEmpty) { |
605 FunctionElement helper = glue.getAddRuntimeTypeInformation(); | 615 FunctionElement helper = glue.getAddRuntimeTypeInformation(); |
606 js.Expression typeArguments = new js.ArrayInitializer( | 616 js.Expression typeArguments = new js.ArrayInitializer( |
607 visitExpressionList(typeInformation)); | 617 visitExpressionList(typeInformation)); |
608 return buildStaticHelperInvocation(helper, | 618 return buildStaticHelperInvocation(helper, |
609 <js.Expression>[instance, typeArguments]); | 619 <js.Expression>[instance, typeArguments], |
| 620 sourceInformation: node.sourceInformation); |
610 } else { | 621 } else { |
611 return instance; | 622 return instance; |
612 } | 623 } |
613 } | 624 } |
614 | 625 |
615 @override | 626 @override |
616 js.Expression visitCreateInvocationMirror( | 627 js.Expression visitCreateInvocationMirror( |
617 tree_ir.CreateInvocationMirror node) { | 628 tree_ir.CreateInvocationMirror node) { |
618 js.Expression name = js.string(node.selector.name); | 629 js.Expression name = js.string(node.selector.name); |
619 js.Expression internalName = | 630 js.Expression internalName = |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
697 } | 708 } |
698 | 709 |
699 @override | 710 @override |
700 js.Expression visitSetIndex(tree_ir.SetIndex node) { | 711 js.Expression visitSetIndex(tree_ir.SetIndex node) { |
701 return js.js('#[#] = #', | 712 return js.js('#[#] = #', |
702 [visitExpression(node.object), | 713 [visitExpression(node.object), |
703 visitExpression(node.index), | 714 visitExpression(node.index), |
704 visitExpression(node.value)]); | 715 visitExpression(node.value)]); |
705 } | 716 } |
706 | 717 |
707 js.Expression buildStaticHelperInvocation(FunctionElement helper, | 718 js.Expression buildStaticHelperInvocation( |
708 List<js.Expression> arguments) { | 719 FunctionElement helper, |
| 720 List<js.Expression> arguments, |
| 721 {SourceInformation sourceInformation}) { |
709 registry.registerStaticUse(helper); | 722 registry.registerStaticUse(helper); |
710 return buildStaticInvoke(helper, arguments); | 723 return buildStaticInvoke( |
| 724 helper, arguments, sourceInformation: sourceInformation); |
711 } | 725 } |
712 | 726 |
713 @override | 727 @override |
714 js.Expression visitReifyRuntimeType(tree_ir.ReifyRuntimeType node) { | 728 js.Expression visitReifyRuntimeType(tree_ir.ReifyRuntimeType node) { |
715 FunctionElement createType = glue.getCreateRuntimeType(); | 729 js.Expression typeToString = buildStaticHelperInvocation( |
716 FunctionElement typeToString = glue.getRuntimeTypeToString(); | 730 glue.getRuntimeTypeToString(), |
717 return buildStaticHelperInvocation(createType, | 731 [visitExpression(node.value)], |
718 [buildStaticHelperInvocation(typeToString, | 732 sourceInformation: node.sourceInformation); |
719 [visitExpression(node.value)])]); | 733 return buildStaticHelperInvocation( |
| 734 glue.getCreateRuntimeType(), |
| 735 [typeToString], |
| 736 sourceInformation: node.sourceInformation); |
720 } | 737 } |
721 | 738 |
722 @override | 739 @override |
723 js.Expression visitReadTypeVariable(tree_ir.ReadTypeVariable node) { | 740 js.Expression visitReadTypeVariable(tree_ir.ReadTypeVariable node) { |
724 ClassElement context = node.variable.element.enclosingClass; | 741 ClassElement context = node.variable.element.enclosingClass; |
725 js.Expression index = js.number(glue.getTypeVariableIndex(node.variable)); | 742 js.Expression index = js.number(glue.getTypeVariableIndex(node.variable)); |
726 if (glue.needsSubstitutionForTypeVariableAccess(context)) { | 743 if (glue.needsSubstitutionForTypeVariableAccess(context)) { |
727 js.Expression typeName = glue.getRuntimeTypeName(context); | 744 js.Expression typeName = glue.getRuntimeTypeName(context); |
728 return buildStaticHelperInvocation( | 745 return buildStaticHelperInvocation( |
729 glue.getRuntimeTypeArgument(), | 746 glue.getRuntimeTypeArgument(), |
730 [visitExpression(node.target), typeName, index]); | 747 [visitExpression(node.target), typeName, index], |
| 748 sourceInformation: node.sourceInformation); |
731 } else { | 749 } else { |
732 return buildStaticHelperInvocation( | 750 return buildStaticHelperInvocation( |
733 glue.getTypeArgumentByIndex(), | 751 glue.getTypeArgumentByIndex(), |
734 [visitExpression(node.target), index]); | 752 [visitExpression(node.target), index], |
| 753 sourceInformation: node.sourceInformation); |
735 } | 754 } |
736 } | 755 } |
737 | 756 |
738 @override | 757 @override |
739 js.Expression visitTypeExpression(tree_ir.TypeExpression node) { | 758 js.Expression visitTypeExpression(tree_ir.TypeExpression node) { |
740 List<js.Expression> arguments = visitExpressionList(node.arguments); | 759 List<js.Expression> arguments = visitExpressionList(node.arguments); |
741 return glue.generateTypeRepresentation(node.dartType, arguments); | 760 return glue.generateTypeRepresentation(node.dartType, arguments); |
742 } | 761 } |
743 | 762 |
744 js.Node handleForeignCode(tree_ir.ForeignCode node) { | 763 js.Node handleForeignCode(tree_ir.ForeignCode node) { |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
806 return js.js("typeof # === 'number' && Math.floor(#) === #", args); | 825 return js.js("typeof # === 'number' && Math.floor(#) === #", args); |
807 } | 826 } |
808 } | 827 } |
809 | 828 |
810 visitFunctionExpression(tree_ir.FunctionExpression node) { | 829 visitFunctionExpression(tree_ir.FunctionExpression node) { |
811 // FunctionExpressions are currently unused. | 830 // FunctionExpressions are currently unused. |
812 // We might need them if we want to emit raw JS nested functions. | 831 // We might need them if we want to emit raw JS nested functions. |
813 throw 'FunctionExpressions should not be used'; | 832 throw 'FunctionExpressions should not be used'; |
814 } | 833 } |
815 } | 834 } |
OLD | NEW |