| OLD | NEW | 
|---|
| 1 // Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 import 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; | 
| 6 | 6 | 
| 7 import '../common.dart'; | 7 import '../common.dart'; | 
| 8 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; | 8 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; | 
|  | 9 import '../common/names.dart'; | 
| 9 import '../common/tasks.dart' show CompilerTask; | 10 import '../common/tasks.dart' show CompilerTask; | 
| 10 import '../compiler.dart'; | 11 import '../compiler.dart'; | 
| 11 import '../dart_types.dart'; | 12 import '../dart_types.dart'; | 
| 12 import '../elements/elements.dart'; | 13 import '../elements/elements.dart'; | 
| 13 import '../io/source_information.dart'; | 14 import '../io/source_information.dart'; | 
| 14 import '../js_backend/backend.dart' show JavaScriptBackend; | 15 import '../js_backend/backend.dart' show JavaScriptBackend; | 
| 15 import '../kernel/kernel.dart'; | 16 import '../kernel/kernel.dart'; | 
| 16 import '../resolution/tree_elements.dart'; | 17 import '../resolution/tree_elements.dart'; | 
| 17 import '../tree/dartstring.dart'; | 18 import '../tree/dartstring.dart'; | 
| 18 import '../types/masks.dart'; | 19 import '../types/masks.dart'; | 
| 19 import '../universe/selector.dart'; | 20 import '../universe/selector.dart'; | 
| 20 |  | 
| 21 import 'graph_builder.dart'; | 21 import 'graph_builder.dart'; | 
| 22 import 'kernel_ast_adapter.dart'; | 22 import 'kernel_ast_adapter.dart'; | 
| 23 import 'kernel_string_builder.dart'; | 23 import 'kernel_string_builder.dart'; | 
| 24 import 'locals_handler.dart'; | 24 import 'locals_handler.dart'; | 
| 25 import 'loop_handler.dart'; | 25 import 'loop_handler.dart'; | 
| 26 import 'nodes.dart'; | 26 import 'nodes.dart'; | 
| 27 import 'ssa_branch_builder.dart'; | 27 import 'ssa_branch_builder.dart'; | 
| 28 | 28 | 
| 29 class SsaKernelBuilderTask extends CompilerTask { | 29 class SsaKernelBuilderTask extends CompilerTask { | 
| 30   final JavaScriptBackend backend; | 30   final JavaScriptBackend backend; | 
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 235 | 235 | 
| 236     void buildBody() { | 236     void buildBody() { | 
| 237       forStatement.body.accept(this); | 237       forStatement.body.accept(this); | 
| 238     } | 238     } | 
| 239 | 239 | 
| 240     loopHandler.handleLoop( | 240     loopHandler.handleLoop( | 
| 241         forStatement, buildInitializer, buildCondition, buildUpdate, buildBody); | 241         forStatement, buildInitializer, buildCondition, buildUpdate, buildBody); | 
| 242   } | 242   } | 
| 243 | 243 | 
| 244   @override | 244   @override | 
|  | 245   void visitForInStatement(ir.ForInStatement forInStatement) { | 
|  | 246     if (forInStatement.isAsync) { | 
|  | 247       compiler.reporter.internalError(astAdapter.getNode(forInStatement), | 
|  | 248           "Cannot compile async for-in using kernel."); | 
|  | 249     } | 
|  | 250     // If the expression being iterated over is a JS indexable type, we can | 
|  | 251     // generate an optimized version of for-in that uses indexing. | 
|  | 252     if (astAdapter.isJsIndexableIterator(forInStatement)) { | 
|  | 253       _buildForInIndexable(forInStatement); | 
|  | 254     } else { | 
|  | 255       _buildForInIterator(forInStatement); | 
|  | 256     } | 
|  | 257   } | 
|  | 258 | 
|  | 259   /// Builds the graph for a for-in node with an indexable expression. | 
|  | 260   /// | 
|  | 261   /// In this case we build: | 
|  | 262   /// | 
|  | 263   ///    int end = a.length; | 
|  | 264   ///    for (int i = 0; | 
|  | 265   ///         i < a.length; | 
|  | 266   ///         checkConcurrentModificationError(a.length == end, a), ++i) { | 
|  | 267   ///      <declaredIdentifier> = a[i]; | 
|  | 268   ///      <body> | 
|  | 269   ///    } | 
|  | 270   _buildForInIndexable(ir.ForInStatement forInStatement) { | 
|  | 271     SyntheticLocal indexVariable = new SyntheticLocal('_i', targetElement); | 
|  | 272 | 
|  | 273     // These variables are shared by initializer, condition, body and update. | 
|  | 274     HInstruction array; // Set in buildInitializer. | 
|  | 275     bool isFixed; // Set in buildInitializer. | 
|  | 276     HInstruction originalLength = null; // Set for growable lists. | 
|  | 277 | 
|  | 278     HInstruction buildGetLength() { | 
|  | 279       HFieldGet result = new HFieldGet( | 
|  | 280           astAdapter.jsIndexableLength, array, backend.positiveIntType, | 
|  | 281           isAssignable: !isFixed); | 
|  | 282       add(result); | 
|  | 283       return result; | 
|  | 284     } | 
|  | 285 | 
|  | 286     void buildConcurrentModificationErrorCheck() { | 
|  | 287       if (originalLength == null) return; | 
|  | 288       // The static call checkConcurrentModificationError() is expanded in | 
|  | 289       // codegen to: | 
|  | 290       // | 
|  | 291       //     array.length == _end || throwConcurrentModificationError(array) | 
|  | 292       // | 
|  | 293       HInstruction length = buildGetLength(); | 
|  | 294       push(new HIdentity(length, originalLength, null, backend.boolType)); | 
|  | 295       _pushStaticInvocation( | 
|  | 296           astAdapter.checkConcurrentModificationError, | 
|  | 297           [pop(), array], | 
|  | 298           astAdapter.checkConcurrentModificationErrorReturnType); | 
|  | 299       pop(); | 
|  | 300     } | 
|  | 301 | 
|  | 302     void buildInitializer() { | 
|  | 303       forInStatement.iterable.accept(this); | 
|  | 304       array = pop(); | 
|  | 305       isFixed = astAdapter.isFixedLength(array.instructionType); | 
|  | 306       localsHandler.updateLocal( | 
|  | 307           indexVariable, graph.addConstantInt(0, compiler)); | 
|  | 308       originalLength = buildGetLength(); | 
|  | 309     } | 
|  | 310 | 
|  | 311     HInstruction buildCondition() { | 
|  | 312       HInstruction index = localsHandler.readLocal(indexVariable); | 
|  | 313       HInstruction length = buildGetLength(); | 
|  | 314       HInstruction compare = new HLess(index, length, null, backend.boolType); | 
|  | 315       add(compare); | 
|  | 316       return compare; | 
|  | 317     } | 
|  | 318 | 
|  | 319     void buildBody() { | 
|  | 320       // If we had mechanically inlined ArrayIterator.moveNext(), it would have | 
|  | 321       // inserted the ConcurrentModificationError check as part of the | 
|  | 322       // condition.  It is not necessary on the first iteration since there is | 
|  | 323       // no code between calls to `get iterator` and `moveNext`, so the test is | 
|  | 324       // moved to the loop update. | 
|  | 325 | 
|  | 326       // Find a type for the element. Use the element type of the indexer of the | 
|  | 327       // array, as this is stronger than the iterator's `get current` type, for | 
|  | 328       // example, `get current` includes null. | 
|  | 329       // TODO(sra): The element type of a container type mask might be better. | 
|  | 330       TypeMask type = astAdapter.inferredIndexType(forInStatement); | 
|  | 331 | 
|  | 332       HInstruction index = localsHandler.readLocal(indexVariable); | 
|  | 333       HInstruction value = new HIndex(array, index, null, type); | 
|  | 334       add(value); | 
|  | 335 | 
|  | 336       localsHandler.updateLocal( | 
|  | 337           astAdapter.getLocal(forInStatement.variable), value); | 
|  | 338 | 
|  | 339       forInStatement.body.accept(this); | 
|  | 340     } | 
|  | 341 | 
|  | 342     void buildUpdate() { | 
|  | 343       // See buildBody as to why we check here. | 
|  | 344       buildConcurrentModificationErrorCheck(); | 
|  | 345 | 
|  | 346       // TODO(sra): It would be slightly shorter to generate `a[i++]` in the | 
|  | 347       // body (and that more closely follows what an inlined iterator would do) | 
|  | 348       // but the code is horrible as `i+1` is carried around the loop in an | 
|  | 349       // additional variable. | 
|  | 350       HInstruction index = localsHandler.readLocal(indexVariable); | 
|  | 351       HInstruction one = graph.addConstantInt(1, compiler); | 
|  | 352       HInstruction addInstruction = | 
|  | 353           new HAdd(index, one, null, backend.positiveIntType); | 
|  | 354       add(addInstruction); | 
|  | 355       localsHandler.updateLocal(indexVariable, addInstruction); | 
|  | 356     } | 
|  | 357 | 
|  | 358     loopHandler.handleLoop(forInStatement, buildInitializer, buildCondition, | 
|  | 359         buildUpdate, buildBody); | 
|  | 360   } | 
|  | 361 | 
|  | 362   _buildForInIterator(ir.ForInStatement forInStatement) { | 
|  | 363     // Generate a structure equivalent to: | 
|  | 364     //   Iterator<E> $iter = <iterable>.iterator; | 
|  | 365     //   while ($iter.moveNext()) { | 
|  | 366     //     <declaredIdentifier> = $iter.current; | 
|  | 367     //     <body> | 
|  | 368     //   } | 
|  | 369 | 
|  | 370     // The iterator is shared between initializer, condition and body. | 
|  | 371     HInstruction iterator; | 
|  | 372 | 
|  | 373     void buildInitializer() { | 
|  | 374       TypeMask mask = astAdapter.typeOfIterator(forInStatement); | 
|  | 375       forInStatement.iterable.accept(this); | 
|  | 376       HInstruction receiver = pop(); | 
|  | 377       _pushDynamicInvocation(forInStatement, mask, <HInstruction>[receiver], | 
|  | 378           selector: Selectors.iterator); | 
|  | 379       iterator = pop(); | 
|  | 380     } | 
|  | 381 | 
|  | 382     HInstruction buildCondition() { | 
|  | 383       TypeMask mask = astAdapter.typeOfIteratorMoveNext(forInStatement); | 
|  | 384       _pushDynamicInvocation(forInStatement, mask, <HInstruction>[iterator], | 
|  | 385           selector: Selectors.moveNext); | 
|  | 386       return popBoolified(); | 
|  | 387     } | 
|  | 388 | 
|  | 389     void buildBody() { | 
|  | 390       TypeMask mask = astAdapter.typeOfIteratorCurrent(forInStatement); | 
|  | 391       _pushDynamicInvocation(forInStatement, mask, [iterator], | 
|  | 392           selector: Selectors.current); | 
|  | 393       localsHandler.updateLocal( | 
|  | 394           astAdapter.getLocal(forInStatement.variable), pop()); | 
|  | 395       forInStatement.body.accept(this); | 
|  | 396     } | 
|  | 397 | 
|  | 398     loopHandler.handleLoop( | 
|  | 399         forInStatement, buildInitializer, buildCondition, () {}, buildBody); | 
|  | 400   } | 
|  | 401 | 
|  | 402   @override | 
| 245   void visitWhileStatement(ir.WhileStatement whileStatement) { | 403   void visitWhileStatement(ir.WhileStatement whileStatement) { | 
| 246     assert(isReachable); | 404     assert(isReachable); | 
| 247     HInstruction buildCondition() { | 405     HInstruction buildCondition() { | 
| 248       whileStatement.condition.accept(this); | 406       whileStatement.condition.accept(this); | 
| 249       return popBoolified(); | 407       return popBoolified(); | 
| 250     } | 408     } | 
| 251 | 409 | 
| 252     loopHandler.handleLoop(whileStatement, () {}, buildCondition, () {}, () { | 410     loopHandler.handleLoop(whileStatement, () {}, buildCondition, () {}, () { | 
| 253       whileStatement.body.accept(this); | 411       whileStatement.body.accept(this); | 
| 254     }); | 412     }); | 
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 323       List<HInstruction> elements = <HInstruction>[]; | 481       List<HInstruction> elements = <HInstruction>[]; | 
| 324       for (ir.Expression element in listLiteral.expressions) { | 482       for (ir.Expression element in listLiteral.expressions) { | 
| 325         element.accept(this); | 483         element.accept(this); | 
| 326         elements.add(pop()); | 484         elements.add(pop()); | 
| 327       } | 485       } | 
| 328       listInstruction = new HLiteralList(elements, backend.extendableArrayType); | 486       listInstruction = new HLiteralList(elements, backend.extendableArrayType); | 
| 329       add(listInstruction); | 487       add(listInstruction); | 
| 330       // TODO(het): set runtime type info | 488       // TODO(het): set runtime type info | 
| 331     } | 489     } | 
| 332 | 490 | 
| 333     // TODO(het): Set the instruction type to the list type given by inference | 491     TypeMask type = astAdapter.typeOfNewList(targetElement, listLiteral); | 
|  | 492     if (!type.containsAll(compiler.closedWorld)) { | 
|  | 493       listInstruction.instructionType = type; | 
|  | 494     } | 
| 334     stack.add(listInstruction); | 495     stack.add(listInstruction); | 
| 335   } | 496   } | 
| 336 | 497 | 
| 337   @override | 498   @override | 
| 338   void visitMapLiteral(ir.MapLiteral mapLiteral) { | 499   void visitMapLiteral(ir.MapLiteral mapLiteral) { | 
| 339     if (mapLiteral.isConst) { | 500     if (mapLiteral.isConst) { | 
| 340       stack.add( | 501       stack.add( | 
| 341           graph.addConstant(astAdapter.getConstantFor(mapLiteral), compiler)); | 502           graph.addConstant(astAdapter.getConstantFor(mapLiteral), compiler)); | 
| 342       return; | 503       return; | 
| 343     } | 504     } | 
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 405       add(new HStaticStore(astAdapter.getElement(staticTarget), value)); | 566       add(new HStaticStore(astAdapter.getElement(staticTarget), value)); | 
| 406     } | 567     } | 
| 407     stack.add(value); | 568     stack.add(value); | 
| 408   } | 569   } | 
| 409 | 570 | 
| 410   @override | 571   @override | 
| 411   void visitPropertyGet(ir.PropertyGet propertyGet) { | 572   void visitPropertyGet(ir.PropertyGet propertyGet) { | 
| 412     propertyGet.receiver.accept(this); | 573     propertyGet.receiver.accept(this); | 
| 413     HInstruction receiver = pop(); | 574     HInstruction receiver = pop(); | 
| 414 | 575 | 
| 415     List<HInstruction> inputs = <HInstruction>[]; | 576     _pushDynamicInvocation(propertyGet, astAdapter.typeOfGet(propertyGet), | 
| 416     bool isIntercepted = astAdapter.isIntercepted(propertyGet); | 577         <HInstruction>[receiver]); | 
| 417     if (isIntercepted) { |  | 
| 418       HInterceptor interceptor = _interceptorFor(receiver); |  | 
| 419       inputs.add(interceptor); |  | 
| 420     } |  | 
| 421     inputs.add(receiver); |  | 
| 422 |  | 
| 423     TypeMask type = astAdapter.selectorGetterTypeOf(propertyGet); |  | 
| 424 |  | 
| 425     push(new HInvokeDynamicGetter(astAdapter.getGetterSelector(propertyGet), |  | 
| 426         astAdapter.typeOfGet(propertyGet), null, inputs, type)); |  | 
| 427   } | 578   } | 
| 428 | 579 | 
| 429   @override | 580   @override | 
| 430   void visitVariableGet(ir.VariableGet variableGet) { | 581   void visitVariableGet(ir.VariableGet variableGet) { | 
| 431     LocalElement local = astAdapter.getElement(variableGet.variable); | 582     Local local = astAdapter.getLocal(variableGet.variable); | 
| 432     stack.add(localsHandler.readLocal(local)); | 583     stack.add(localsHandler.readLocal(local)); | 
| 433   } | 584   } | 
| 434 | 585 | 
| 435   @override | 586   @override | 
| 436   void visitVariableSet(ir.VariableSet variableSet) { | 587   void visitVariableSet(ir.VariableSet variableSet) { | 
| 437     variableSet.value.accept(this); | 588     variableSet.value.accept(this); | 
| 438     HInstruction value = pop(); | 589     HInstruction value = pop(); | 
| 439     _visitLocalSetter(variableSet.variable, value); | 590     _visitLocalSetter(variableSet.variable, value); | 
| 440   } | 591   } | 
| 441 | 592 | 
| 442   @override | 593   @override | 
| 443   void visitVariableDeclaration(ir.VariableDeclaration declaration) { | 594   void visitVariableDeclaration(ir.VariableDeclaration declaration) { | 
| 444     LocalElement local = astAdapter.getElement(declaration); | 595     Local local = astAdapter.getLocal(declaration); | 
| 445     if (declaration.initializer == null) { | 596     if (declaration.initializer == null) { | 
| 446       HInstruction initialValue = graph.addConstantNull(compiler); | 597       HInstruction initialValue = graph.addConstantNull(compiler); | 
| 447       localsHandler.updateLocal(local, initialValue); | 598       localsHandler.updateLocal(local, initialValue); | 
| 448     } else { | 599     } else { | 
| 449       // TODO(het): handle case where the variable is top-level or static | 600       // TODO(het): handle case where the variable is top-level or static | 
| 450       declaration.initializer.accept(this); | 601       declaration.initializer.accept(this); | 
| 451       HInstruction initialValue = pop(); | 602       HInstruction initialValue = pop(); | 
| 452 | 603 | 
| 453       _visitLocalSetter(declaration, initialValue); | 604       _visitLocalSetter(declaration, initialValue); | 
| 454 | 605 | 
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 501   void _pushStaticInvocation( | 652   void _pushStaticInvocation( | 
| 502       ir.Node target, List<HInstruction> arguments, TypeMask typeMask) { | 653       ir.Node target, List<HInstruction> arguments, TypeMask typeMask) { | 
| 503     HInstruction instruction = new HInvokeStatic( | 654     HInstruction instruction = new HInvokeStatic( | 
| 504         astAdapter.getElement(target).declaration, arguments, typeMask, | 655         astAdapter.getElement(target).declaration, arguments, typeMask, | 
| 505         targetCanThrow: astAdapter.getCanThrow(target)); | 656         targetCanThrow: astAdapter.getCanThrow(target)); | 
| 506     instruction.sideEffects = astAdapter.getSideEffects(target); | 657     instruction.sideEffects = astAdapter.getSideEffects(target); | 
| 507 | 658 | 
| 508     push(instruction); | 659     push(instruction); | 
| 509   } | 660   } | 
| 510 | 661 | 
|  | 662   void _pushDynamicInvocation( | 
|  | 663       ir.Node node, TypeMask mask, List<HInstruction> arguments, | 
|  | 664       {Selector selector}) { | 
|  | 665     HInstruction receiver = arguments.first; | 
|  | 666     List<HInstruction> inputs = <HInstruction>[]; | 
|  | 667 | 
|  | 668     selector ??= astAdapter.getSelector(node); | 
|  | 669     bool isIntercepted = astAdapter.isInterceptedSelector(selector); | 
|  | 670 | 
|  | 671     if (isIntercepted) { | 
|  | 672       HInterceptor interceptor = _interceptorFor(receiver); | 
|  | 673       inputs.add(interceptor); | 
|  | 674     } | 
|  | 675     inputs.addAll(arguments); | 
|  | 676 | 
|  | 677     TypeMask type = astAdapter.selectorTypeOf(selector, mask); | 
|  | 678     if (selector.isGetter) { | 
|  | 679       push(new HInvokeDynamicGetter(selector, mask, null, inputs, type)); | 
|  | 680     } else if (selector.isSetter) { | 
|  | 681       push(new HInvokeDynamicSetter(selector, mask, null, inputs, type)); | 
|  | 682     } else { | 
|  | 683       push(new HInvokeDynamicMethod( | 
|  | 684           selector, mask, inputs, type, isIntercepted)); | 
|  | 685     } | 
|  | 686   } | 
|  | 687 | 
| 511   // TODO(het): Decide when to inline | 688   // TODO(het): Decide when to inline | 
| 512   @override | 689   @override | 
| 513   void visitMethodInvocation(ir.MethodInvocation invocation) { | 690   void visitMethodInvocation(ir.MethodInvocation invocation) { | 
| 514     invocation.receiver.accept(this); | 691     invocation.receiver.accept(this); | 
| 515     HInstruction receiver = pop(); | 692     HInstruction receiver = pop(); | 
| 516 | 693 | 
| 517     List<HInstruction> arguments = <HInstruction>[receiver] | 694     _pushDynamicInvocation( | 
| 518       ..addAll(_visitArguments(invocation.arguments)); | 695         invocation, | 
| 519 | 696         astAdapter.typeOfInvocation(invocation), | 
| 520     List<HInstruction> inputs = <HInstruction>[]; | 697         <HInstruction>[receiver] | 
| 521 | 698           ..addAll(_visitArguments(invocation.arguments))); | 
| 522     bool isIntercepted = astAdapter.isIntercepted(invocation); |  | 
| 523     if (isIntercepted) { |  | 
| 524       HInterceptor interceptor = _interceptorFor(receiver); |  | 
| 525       inputs.add(interceptor); |  | 
| 526     } |  | 
| 527     inputs.addAll(arguments); |  | 
| 528 |  | 
| 529     TypeMask type = astAdapter.selectorTypeOf(invocation); |  | 
| 530 |  | 
| 531     push(new HInvokeDynamicMethod(astAdapter.getSelector(invocation), |  | 
| 532         astAdapter.typeOfInvocation(invocation), inputs, type, isIntercepted)); |  | 
| 533   } | 699   } | 
| 534 | 700 | 
| 535   HInterceptor _interceptorFor(HInstruction intercepted) { | 701   HInterceptor _interceptorFor(HInstruction intercepted) { | 
| 536     HInterceptor interceptor = | 702     HInterceptor interceptor = | 
| 537         new HInterceptor(intercepted, backend.nonNullType); | 703         new HInterceptor(intercepted, backend.nonNullType); | 
| 538     add(interceptor); | 704     add(interceptor); | 
| 539     return interceptor; | 705     return interceptor; | 
| 540   } | 706   } | 
| 541 | 707 | 
| 542   static ir.Class _containingClass(ir.TreeNode node) { | 708   static ir.Class _containingClass(ir.TreeNode node) { | 
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 622     push(new HNot(popBoolified(), backend.boolType)); | 788     push(new HNot(popBoolified(), backend.boolType)); | 
| 623   } | 789   } | 
| 624 | 790 | 
| 625   @override | 791   @override | 
| 626   void visitStringConcatenation(ir.StringConcatenation stringConcat) { | 792   void visitStringConcatenation(ir.StringConcatenation stringConcat) { | 
| 627     KernelStringBuilder stringBuilder = new KernelStringBuilder(this); | 793     KernelStringBuilder stringBuilder = new KernelStringBuilder(this); | 
| 628     stringConcat.accept(stringBuilder); | 794     stringConcat.accept(stringBuilder); | 
| 629     stack.add(stringBuilder.result); | 795     stack.add(stringBuilder.result); | 
| 630   } | 796   } | 
| 631 } | 797 } | 
| OLD | NEW | 
|---|