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