| 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 '../../js/js.dart' as js; | 10 import '../../js/js.dart' as js; |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 : variable.element.name); | 149 : variable.element.name); |
| 150 while (!usedVariableNames.add(name)) { | 150 while (!usedVariableNames.add(name)) { |
| 151 ++counter; | 151 ++counter; |
| 152 name = '$prefix$counter'; | 152 name = '$prefix$counter'; |
| 153 } | 153 } |
| 154 variableNames[variable] = name; | 154 variableNames[variable] = name; |
| 155 | 155 |
| 156 return name; | 156 return name; |
| 157 } | 157 } |
| 158 | 158 |
| 159 List<js.Expression> visitArguments(List<tree_ir.Expression> arguments) { | 159 List<js.Expression> visitExpressionList( |
| 160 return arguments.map(visitExpression).toList(); | 160 List<tree_ir.Expression> expressions) { |
| 161 return new List<js.Expression>.generate(expressions.length, |
| 162 (int index) => visitExpression(expressions[index]), |
| 163 growable: false); |
| 161 } | 164 } |
| 162 | 165 |
| 163 giveup(tree_ir.Node node, | 166 giveup(tree_ir.Node node, |
| 164 [String reason = 'unimplemented in CodeGenerator']) { | 167 [String reason = 'unimplemented in CodeGenerator']) { |
| 165 throw new CodegenBailout(node, reason); | 168 throw new CodegenBailout(node, reason); |
| 166 } | 169 } |
| 167 | 170 |
| 168 @override | 171 @override |
| 169 js.Expression visitConcatenateStrings(tree_ir.ConcatenateStrings node) { | 172 js.Expression visitConcatenateStrings(tree_ir.ConcatenateStrings node) { |
| 170 js.Expression addStrings(js.Expression left, js.Expression right) { | 173 js.Expression addStrings(js.Expression left, js.Expression right) { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 235 } | 238 } |
| 236 } | 239 } |
| 237 | 240 |
| 238 @override | 241 @override |
| 239 js.Expression visitInvokeConstructor(tree_ir.InvokeConstructor node) { | 242 js.Expression visitInvokeConstructor(tree_ir.InvokeConstructor node) { |
| 240 if (node.constant != null) return giveup(node); | 243 if (node.constant != null) return giveup(node); |
| 241 | 244 |
| 242 registry.registerInstantiatedType(node.type); | 245 registry.registerInstantiatedType(node.type); |
| 243 Selector selector = node.selector; | 246 Selector selector = node.selector; |
| 244 FunctionElement target = node.target; | 247 FunctionElement target = node.target; |
| 245 List<js.Expression> arguments = visitArguments(node.arguments); | 248 List<js.Expression> arguments = visitExpressionList(node.arguments); |
| 246 return buildStaticInvoke(selector, target, arguments); | 249 return buildStaticInvoke(selector, target, arguments); |
| 247 } | 250 } |
| 248 | 251 |
| 249 void registerMethodInvoke(tree_ir.InvokeMethod node) { | 252 void registerMethodInvoke(tree_ir.InvokeMethod node) { |
| 250 Selector selector = node.selector; | 253 Selector selector = node.selector; |
| 251 if (selector.isGetter) { | 254 if (selector.isGetter) { |
| 252 registry.registerDynamicGetter(selector); | 255 registry.registerDynamicGetter(selector); |
| 253 } else if (selector.isSetter) { | 256 } else if (selector.isSetter) { |
| 254 registry.registerDynamicSetter(selector); | 257 registry.registerDynamicSetter(selector); |
| 255 } else { | 258 } else { |
| 256 assert(invariant(CURRENT_ELEMENT_SPANNABLE, | 259 assert(invariant(CURRENT_ELEMENT_SPANNABLE, |
| 257 selector.isCall || selector.isOperator || | 260 selector.isCall || selector.isOperator || |
| 258 selector.isIndex || selector.isIndexSet, | 261 selector.isIndex || selector.isIndexSet, |
| 259 message: 'unexpected kind ${selector.kind}')); | 262 message: 'unexpected kind ${selector.kind}')); |
| 260 // TODO(sigurdm): We should find a better place to register the call. | 263 // TODO(sigurdm): We should find a better place to register the call. |
| 261 Selector call = new Selector.callClosureFrom(selector); | 264 Selector call = new Selector.callClosureFrom(selector); |
| 262 registry.registerDynamicInvocation(call); | 265 registry.registerDynamicInvocation(call); |
| 263 registry.registerDynamicInvocation(selector); | 266 registry.registerDynamicInvocation(selector); |
| 264 } | 267 } |
| 265 } | 268 } |
| 266 | 269 |
| 267 @override | 270 @override |
| 268 js.Expression visitInvokeMethod(tree_ir.InvokeMethod node) { | 271 js.Expression visitInvokeMethod(tree_ir.InvokeMethod node) { |
| 269 registerMethodInvoke(node); | 272 registerMethodInvoke(node); |
| 270 return js.propertyCall(visitExpression(node.receiver), | 273 return js.propertyCall(visitExpression(node.receiver), |
| 271 glue.invocationName(node.selector), | 274 glue.invocationName(node.selector), |
| 272 visitArguments(node.arguments)); | 275 visitExpressionList(node.arguments)); |
| 273 } | 276 } |
| 274 | 277 |
| 275 @override | 278 @override |
| 276 js.Expression visitInvokeStatic(tree_ir.InvokeStatic node) { | 279 js.Expression visitInvokeStatic(tree_ir.InvokeStatic node) { |
| 277 Selector selector = node.selector; | 280 Selector selector = node.selector; |
| 278 assert(selector.isGetter || selector.isSetter || selector.isCall); | 281 assert(selector.isGetter || selector.isSetter || selector.isCall); |
| 279 FunctionElement target = node.target; | 282 FunctionElement target = node.target; |
| 280 List<js.Expression> arguments = visitArguments(node.arguments); | 283 List<js.Expression> arguments = visitExpressionList(node.arguments); |
| 281 return buildStaticInvoke(selector, target, arguments, | 284 return buildStaticInvoke(selector, target, arguments, |
| 282 sourceInformation: node.sourceInformation); | 285 sourceInformation: node.sourceInformation); |
| 283 } | 286 } |
| 284 | 287 |
| 285 @override | 288 @override |
| 286 js.Expression visitInvokeMethodDirectly(tree_ir.InvokeMethodDirectly node) { | 289 js.Expression visitInvokeMethodDirectly(tree_ir.InvokeMethodDirectly node) { |
| 287 registry.registerDirectInvocation(node.target.declaration); | 290 registry.registerDirectInvocation(node.target.declaration); |
| 288 if (node.target is ConstructorBodyElement) { | 291 if (node.target is ConstructorBodyElement) { |
| 289 // A constructor body cannot be overriden or intercepted, so we can | 292 // A constructor body cannot be overriden or intercepted, so we can |
| 290 // use the short form for this invocation. | 293 // use the short form for this invocation. |
| 291 return js.js('#.#(#)', | 294 return js.js('#.#(#)', |
| 292 [visitExpression(node.receiver), | 295 [visitExpression(node.receiver), |
| 293 glue.instanceMethodName(node.target), | 296 glue.instanceMethodName(node.target), |
| 294 visitArguments(node.arguments)]); | 297 visitExpressionList(node.arguments)]); |
| 295 } | 298 } |
| 296 return js.js('#.#.call(#, #)', | 299 return js.js('#.#.call(#, #)', |
| 297 [glue.prototypeAccess(node.target.enclosingClass), | 300 [glue.prototypeAccess(node.target.enclosingClass), |
| 298 glue.invocationName(node.selector), | 301 glue.invocationName(node.selector), |
| 299 visitExpression(node.receiver), | 302 visitExpression(node.receiver), |
| 300 visitArguments(node.arguments)]); | 303 visitExpressionList(node.arguments)]); |
| 301 } | 304 } |
| 302 | 305 |
| 303 @override | 306 @override |
| 304 js.Expression visitLiteralList(tree_ir.LiteralList node) { | 307 js.Expression visitLiteralList(tree_ir.LiteralList node) { |
| 305 registry.registerInstantiatedClass(glue.listClass); | 308 registry.registerInstantiatedClass(glue.listClass); |
| 306 List<js.Expression> entries = node.values.map(visitExpression).toList(); | 309 List<js.Expression> entries = visitExpressionList(node.values); |
| 307 return new js.ArrayInitializer(entries); | 310 return new js.ArrayInitializer(entries); |
| 308 } | 311 } |
| 309 | 312 |
| 310 @override | 313 @override |
| 311 js.Expression visitLiteralMap(tree_ir.LiteralMap node) { | 314 js.Expression visitLiteralMap(tree_ir.LiteralMap node) { |
| 312 ConstructorElement constructor; | 315 ConstructorElement constructor; |
| 313 if (node.entries.isEmpty) { | 316 if (node.entries.isEmpty) { |
| 314 constructor = glue.mapLiteralConstructorEmpty; | 317 constructor = glue.mapLiteralConstructorEmpty; |
| 315 } else { | 318 } else { |
| 316 constructor = glue.mapLiteralConstructor; | 319 constructor = glue.mapLiteralConstructor; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 344 } | 347 } |
| 345 | 348 |
| 346 @override | 349 @override |
| 347 js.Expression visitThis(tree_ir.This node) { | 350 js.Expression visitThis(tree_ir.This node) { |
| 348 return new js.This(); | 351 return new js.This(); |
| 349 } | 352 } |
| 350 | 353 |
| 351 @override | 354 @override |
| 352 js.Expression visitTypeOperator(tree_ir.TypeOperator node) { | 355 js.Expression visitTypeOperator(tree_ir.TypeOperator node) { |
| 353 js.Expression value = visitExpression(node.value); | 356 js.Expression value = visitExpression(node.value); |
| 354 List<js.Expression> typeArguments = | 357 List<js.Expression> typeArguments = visitExpressionList(node.typeArguments); |
| 355 node.typeArguments.map(visitExpression).toList(); | |
| 356 if (!node.isTypeTest) { | 358 if (!node.isTypeTest) { |
| 357 giveup(node, 'type casts not implemented.'); | 359 giveup(node, 'type casts not implemented.'); |
| 358 } | 360 } |
| 359 DartType type = node.type; | 361 DartType type = node.type; |
| 360 // Note that the trivial (but special) cases of Object, dynamic, and Null | 362 // Note that the trivial (but special) cases of Object, dynamic, and Null |
| 361 // are handled at build-time and must not occur in a TypeOperator. | 363 // are handled at build-time and must not occur in a TypeOperator. |
| 362 assert(!type.isObject && !type.isDynamic); | 364 assert(!type.isObject && !type.isDynamic); |
| 363 if (type is InterfaceType) { | 365 if (type is InterfaceType) { |
| 364 glue.registerIsCheck(type, registry); | 366 glue.registerIsCheck(type, registry); |
| 365 ClassElement clazz = type.element; | 367 ClassElement clazz = type.element; |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 550 tree_ir.Variable exceptionVariable = node.catchParameters.first; | 552 tree_ir.Variable exceptionVariable = node.catchParameters.first; |
| 551 js.VariableDeclaration exceptionParameter = | 553 js.VariableDeclaration exceptionParameter = |
| 552 new js.VariableDeclaration(getVariableName(exceptionVariable)); | 554 new js.VariableDeclaration(getVariableName(exceptionVariable)); |
| 553 js.Block catchBlock = buildBodyBlock(node.catchBody); | 555 js.Block catchBlock = buildBodyBlock(node.catchBody); |
| 554 js.Catch catchPart = new js.Catch(exceptionParameter, catchBlock); | 556 js.Catch catchPart = new js.Catch(exceptionParameter, catchBlock); |
| 555 accumulator.add(new js.Try(tryBlock, catchPart, null)); | 557 accumulator.add(new js.Try(tryBlock, catchPart, null)); |
| 556 } | 558 } |
| 557 | 559 |
| 558 @override | 560 @override |
| 559 js.Expression visitCreateBox(tree_ir.CreateBox node) { | 561 js.Expression visitCreateBox(tree_ir.CreateBox node) { |
| 560 return new js.ObjectInitializer([]); | 562 return new js.ObjectInitializer(const <js.Property>[]); |
| 561 } | 563 } |
| 562 | 564 |
| 563 @override | 565 @override |
| 564 js.Expression visitCreateInstance(tree_ir.CreateInstance node) { | 566 js.Expression visitCreateInstance(tree_ir.CreateInstance node) { |
| 565 ClassElement cls = node.classElement; | 567 ClassElement cls = node.classElement; |
| 566 // TODO(asgerf): To allow inlining of InvokeConstructor, CreateInstance must | 568 // TODO(asgerf): To allow inlining of InvokeConstructor, CreateInstance must |
| 567 // carry a DartType so we can register the instantiated type | 569 // carry a DartType so we can register the instantiated type |
| 568 // with its type arguments. Otherwise dataflow analysis is | 570 // with its type arguments. Otherwise dataflow analysis is |
| 569 // needed to reconstruct the instantiated type. | 571 // needed to reconstruct the instantiated type. |
| 570 registry.registerInstantiatedClass(cls); | 572 registry.registerInstantiatedClass(cls); |
| 571 js.Expression instance = new js.New( | 573 js.Expression instance = new js.New( |
| 572 glue.constructorAccess(cls), | 574 glue.constructorAccess(cls), |
| 573 node.arguments.map(visitExpression).toList()); | 575 visitExpressionList(node.arguments)); |
| 574 | 576 |
| 575 List<tree_ir.Expression> typeInformation = node.typeInformation; | 577 List<tree_ir.Expression> typeInformation = node.typeInformation; |
| 576 assert(typeInformation.isEmpty || | 578 assert(typeInformation.isEmpty || |
| 577 typeInformation.length == cls.typeVariables.length); | 579 typeInformation.length == cls.typeVariables.length); |
| 578 if (typeInformation.isNotEmpty) { | 580 if (typeInformation.isNotEmpty) { |
| 579 FunctionElement helper = glue.getAddRuntimeTypeInformation(); | 581 FunctionElement helper = glue.getAddRuntimeTypeInformation(); |
| 580 js.Expression typeArguments = new js.ArrayInitializer( | 582 js.Expression typeArguments = new js.ArrayInitializer( |
| 581 typeInformation.map(visitExpression).toList()); | 583 visitExpressionList(typeInformation)); |
| 582 return buildStaticHelperInvocation(helper, | 584 return buildStaticHelperInvocation(helper, |
| 583 <js.Expression>[instance, typeArguments]); | 585 <js.Expression>[instance, typeArguments]); |
| 584 } else { | 586 } else { |
| 585 return instance; | 587 return instance; |
| 586 } | 588 } |
| 587 } | 589 } |
| 588 | 590 |
| 589 @override | 591 @override |
| 590 js.Expression visitCreateInvocationMirror( | 592 js.Expression visitCreateInvocationMirror( |
| 591 tree_ir.CreateInvocationMirror node) { | 593 tree_ir.CreateInvocationMirror node) { |
| 592 js.Expression name = js.string(node.selector.name); | 594 js.Expression name = js.string(node.selector.name); |
| 593 js.Expression internalName = js.string(glue.invocationName(node.selector)); | 595 js.Expression internalName = js.string(glue.invocationName(node.selector)); |
| 594 js.Expression kind = js.number(node.selector.invocationMirrorKind); | 596 js.Expression kind = js.number(node.selector.invocationMirrorKind); |
| 595 js.Expression arguments = new js.ArrayInitializer( | 597 js.Expression arguments = new js.ArrayInitializer( |
| 596 node.arguments.map(visitExpression).toList()); | 598 visitExpressionList(node.arguments)); |
| 597 js.Expression argumentNames = new js.ArrayInitializer( | 599 js.Expression argumentNames = new js.ArrayInitializer( |
| 598 node.selector.namedArguments.map(js.string).toList()); | 600 node.selector.namedArguments.map(js.string).toList(growable: false)); |
| 599 return buildStaticHelperInvocation(glue.createInvocationMirrorMethod, | 601 return buildStaticHelperInvocation(glue.createInvocationMirrorMethod, |
| 600 [name, internalName, kind, arguments, argumentNames]); | 602 [name, internalName, kind, arguments, argumentNames]); |
| 601 } | 603 } |
| 602 | 604 |
| 603 @override | 605 @override |
| 604 js.Expression visitGetField(tree_ir.GetField node) { | 606 js.Expression visitGetField(tree_ir.GetField node) { |
| 605 return new js.PropertyAccess.field( | 607 return new js.PropertyAccess.field( |
| 606 visitExpression(node.object), | 608 visitExpression(node.object), |
| 607 glue.instanceFieldPropertyName(node.field)); | 609 glue.instanceFieldPropertyName(node.field)); |
| 608 } | 610 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 621 assert(node.element is FieldElement || node.element is FunctionElement); | 623 assert(node.element is FieldElement || node.element is FunctionElement); |
| 622 if (node.element is FunctionElement) { | 624 if (node.element is FunctionElement) { |
| 623 // Tear off a method. | 625 // Tear off a method. |
| 624 registry.registerGetOfStaticFunction(node.element.declaration); | 626 registry.registerGetOfStaticFunction(node.element.declaration); |
| 625 return glue.isolateStaticClosureAccess(node.element); | 627 return glue.isolateStaticClosureAccess(node.element); |
| 626 } | 628 } |
| 627 if (glue.isLazilyInitialized(node.element)) { | 629 if (glue.isLazilyInitialized(node.element)) { |
| 628 // Read a lazily initialized field. | 630 // Read a lazily initialized field. |
| 629 registry.registerStaticUse(node.element.declaration); | 631 registry.registerStaticUse(node.element.declaration); |
| 630 js.Expression getter = glue.isolateLazyInitializerAccess(node.element); | 632 js.Expression getter = glue.isolateLazyInitializerAccess(node.element); |
| 631 return new js.Call(getter, [], sourceInformation: node.sourceInformation); | 633 return new js.Call(getter, <js.Expression>[], |
| 634 sourceInformation: node.sourceInformation); |
| 632 } | 635 } |
| 633 // Read an eagerly initialized field. | 636 // Read an eagerly initialized field. |
| 634 registry.registerStaticUse(node.element.declaration); | 637 registry.registerStaticUse(node.element.declaration); |
| 635 return glue.staticFieldAccess(node.element); | 638 return glue.staticFieldAccess(node.element); |
| 636 } | 639 } |
| 637 | 640 |
| 638 @override | 641 @override |
| 639 js.Expression visitSetStatic(tree_ir.SetStatic node) { | 642 js.Expression visitSetStatic(tree_ir.SetStatic node) { |
| 640 assert(node.element is FieldElement); | 643 assert(node.element is FieldElement); |
| 641 registry.registerStaticUse(node.element.declaration); | 644 registry.registerStaticUse(node.element.declaration); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 671 [visitExpression(node.target), typeName, index]); | 674 [visitExpression(node.target), typeName, index]); |
| 672 } else { | 675 } else { |
| 673 return buildStaticHelperInvocation( | 676 return buildStaticHelperInvocation( |
| 674 glue.getTypeArgumentByIndex(), | 677 glue.getTypeArgumentByIndex(), |
| 675 [visitExpression(node.target), index]); | 678 [visitExpression(node.target), index]); |
| 676 } | 679 } |
| 677 } | 680 } |
| 678 | 681 |
| 679 @override | 682 @override |
| 680 js.Expression visitTypeExpression(tree_ir.TypeExpression node) { | 683 js.Expression visitTypeExpression(tree_ir.TypeExpression node) { |
| 681 List<js.Expression> arguments = | 684 List<js.Expression> arguments = visitExpressionList(node.arguments); |
| 682 node.arguments.map(visitExpression).toList(growable: false); | |
| 683 return glue.generateTypeRepresentation(node.dartType, arguments); | 685 return glue.generateTypeRepresentation(node.dartType, arguments); |
| 684 } | 686 } |
| 685 | 687 |
| 686 visitFunctionExpression(tree_ir.FunctionExpression node) { | 688 visitFunctionExpression(tree_ir.FunctionExpression node) { |
| 687 // FunctionExpressions are currently unused. | 689 // FunctionExpressions are currently unused. |
| 688 // We might need them if we want to emit raw JS nested functions. | 690 // We might need them if we want to emit raw JS nested functions. |
| 689 throw 'FunctionExpressions should not be used'; | 691 throw 'FunctionExpressions should not be used'; |
| 690 } | 692 } |
| 691 } | 693 } |
| OLD | NEW |