OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 part of ssa; | 5 part of ssa; |
6 | 6 |
7 class SsaFunctionCompiler implements FunctionCompiler { | 7 class SsaFunctionCompiler implements FunctionCompiler { |
8 SsaCodeGeneratorTask generator; | 8 SsaCodeGeneratorTask generator; |
9 SsaBuilderTask builder; | 9 SsaBuilderTask builder; |
10 SsaOptimizerTask optimizer; | 10 SsaOptimizerTask optimizer; |
(...skipping 5508 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5519 }, () { | 5519 }, () { |
5520 pushInvokeDynamic(node, new Selector.call("cancel", null, 0), | 5520 pushInvokeDynamic(node, new Selector.call("cancel", null, 0), |
5521 [streamIterator]); | 5521 [streamIterator]); |
5522 push(new HAwait(pop(), new TypeMask.subclass(compiler.objectClass, | 5522 push(new HAwait(pop(), new TypeMask.subclass(compiler.objectClass, |
5523 compiler.world))); | 5523 compiler.world))); |
5524 pop(); | 5524 pop(); |
5525 }); | 5525 }); |
5526 } | 5526 } |
5527 | 5527 |
5528 visitSyncForIn(ast.SyncForIn node) { | 5528 visitSyncForIn(ast.SyncForIn node) { |
| 5529 // The 'get iterator' selector for this node has the inferred receiver type. |
| 5530 // If the receiver supports JavaScript indexing we generate an indexing loop |
| 5531 // instead of allocating an iterator object. |
| 5532 |
| 5533 // This scheme recognizes for-in on direct lists. It does not recognize all |
| 5534 // uses of ArrayIterator. They still occur when the receiver is an Iterable |
| 5535 // with a `get iterator` method that delegate to another Iterable and the |
| 5536 // method is inlined. We would require full scalar replacement in that |
| 5537 // case. |
| 5538 |
| 5539 Selector selector = elements.getIteratorSelector(node); |
| 5540 TypeMask mask = selector.mask; |
| 5541 |
| 5542 ClassWorld classWorld = compiler.world; |
| 5543 if (mask != null && mask.satisfies(backend.jsIndexableClass, classWorld)) { |
| 5544 return buildSyncForInIndexable(node, mask); |
| 5545 } |
| 5546 buildSyncForInIterator(node); |
| 5547 } |
| 5548 |
| 5549 buildSyncForInIterator(ast.SyncForIn node) { |
5529 // Generate a structure equivalent to: | 5550 // Generate a structure equivalent to: |
5530 // Iterator<E> $iter = <iterable>.iterator; | 5551 // Iterator<E> $iter = <iterable>.iterator; |
5531 // while ($iter.moveNext()) { | 5552 // while ($iter.moveNext()) { |
5532 // E <declaredIdentifier> = $iter.current; | 5553 // <declaredIdentifier> = $iter.current; |
5533 // <body> | 5554 // <body> |
5534 // } | 5555 // } |
5535 | 5556 |
5536 // The iterator is shared between initializer, condition and body. | 5557 // The iterator is shared between initializer, condition and body. |
5537 HInstruction iterator; | 5558 HInstruction iterator; |
| 5559 |
5538 void buildInitializer() { | 5560 void buildInitializer() { |
5539 Selector selector = elements.getIteratorSelector(node); | 5561 Selector selector = elements.getIteratorSelector(node); |
5540 visit(node.expression); | 5562 visit(node.expression); |
5541 HInstruction receiver = pop(); | 5563 HInstruction receiver = pop(); |
5542 pushInvokeDynamic(node, selector, [receiver]); | 5564 pushInvokeDynamic(node, selector, [receiver]); |
5543 iterator = pop(); | 5565 iterator = pop(); |
5544 } | 5566 } |
| 5567 |
5545 HInstruction buildCondition() { | 5568 HInstruction buildCondition() { |
5546 Selector selector = elements.getMoveNextSelector(node); | 5569 Selector selector = elements.getMoveNextSelector(node); |
5547 pushInvokeDynamic(node, selector, [iterator]); | 5570 pushInvokeDynamic(node, selector, [iterator]); |
5548 return popBoolified(); | 5571 return popBoolified(); |
5549 } | 5572 } |
| 5573 |
5550 void buildBody() { | 5574 void buildBody() { |
5551 Selector call = elements.getCurrentSelector(node); | 5575 Selector call = elements.getCurrentSelector(node); |
5552 pushInvokeDynamic(node, call, [iterator]); | 5576 pushInvokeDynamic(node, call, [iterator]); |
5553 | 5577 buildAssignLoopVariable(node, pop()); |
5554 ast.Node identifier = node.declaredIdentifier; | |
5555 Element variable = elements.getForInVariable(node); | |
5556 Selector selector = elements.getSelector(identifier); | |
5557 | |
5558 HInstruction value = pop(); | |
5559 if (identifier.asSend() != null | |
5560 && Elements.isInstanceSend(identifier, elements)) { | |
5561 HInstruction receiver = generateInstanceSendReceiver(identifier); | |
5562 assert(receiver != null); | |
5563 generateInstanceSetterWithCompiledReceiver( | |
5564 null, | |
5565 receiver, | |
5566 value, | |
5567 selector: selector, | |
5568 location: identifier); | |
5569 } else { | |
5570 generateNonInstanceSetter(null, variable, value, location: identifier); | |
5571 } | |
5572 pop(); // Pop the value pushed by the setter call. | |
5573 | |
5574 visit(node.body); | 5578 visit(node.body); |
5575 } | 5579 } |
| 5580 |
5576 handleLoop(node, buildInitializer, buildCondition, () {}, buildBody); | 5581 handleLoop(node, buildInitializer, buildCondition, () {}, buildBody); |
5577 } | 5582 } |
5578 | 5583 |
| 5584 buildAssignLoopVariable(ast.ForIn node, HInstruction value) { |
| 5585 ast.Node identifier = node.declaredIdentifier; |
| 5586 Element variable = elements.getForInVariable(node); |
| 5587 Selector selector = elements.getSelector(identifier); |
| 5588 |
| 5589 if (identifier.asSend() != null && |
| 5590 Elements.isInstanceSend(identifier, elements)) { |
| 5591 HInstruction receiver = generateInstanceSendReceiver(identifier); |
| 5592 assert(receiver != null); |
| 5593 generateInstanceSetterWithCompiledReceiver( |
| 5594 null, |
| 5595 receiver, |
| 5596 value, |
| 5597 selector: selector, |
| 5598 location: identifier); |
| 5599 } else { |
| 5600 generateNonInstanceSetter(null, variable, value, location: identifier); |
| 5601 } |
| 5602 pop(); // Discard the value pushed by the setter call. |
| 5603 } |
| 5604 |
| 5605 buildSyncForInIndexable(ast.ForIn node, TypeMask arrayType) { |
| 5606 // Generate a structure equivalent to: |
| 5607 // |
| 5608 // int end = a.length; |
| 5609 // for (int i = 0; |
| 5610 // i < a.length; |
| 5611 // checkConcurrentModificationError(a.length == end, a), ++i) { |
| 5612 // <declaredIdentifier> = a[i]; |
| 5613 // <body> |
| 5614 // } |
| 5615 Element loopVariable = elements.getForInVariable(node); |
| 5616 SyntheticLocal indexVariable = new SyntheticLocal('_i', loopVariable); |
| 5617 TypeMask boolType = backend.boolType; |
| 5618 |
| 5619 // These variables are shared by initializer, condition, body and update. |
| 5620 HInstruction array; // Set in buildInitializer. |
| 5621 bool isFixed; // Set in buildInitializer. |
| 5622 HInstruction originalLength = null; // Set for growable lists. |
| 5623 |
| 5624 HInstruction buildGetLength() { |
| 5625 Element lengthElement = backend.jsIndexableLength; |
| 5626 HFieldGet result = new HFieldGet( |
| 5627 lengthElement, array, backend.positiveIntType, |
| 5628 isAssignable: !isFixed); |
| 5629 add(result); |
| 5630 return result; |
| 5631 } |
| 5632 |
| 5633 void buildConcurrentModificationErrorCheck() { |
| 5634 if (originalLength == null) return; |
| 5635 // The static call checkConcurrentModificationError() is expanded in |
| 5636 // codegen to: |
| 5637 // |
| 5638 // array.length == _end || throwConcurrentModificationError(array) |
| 5639 // |
| 5640 HInstruction length = buildGetLength(); |
| 5641 push(new HIdentity(length, originalLength, null, boolType)); |
| 5642 pushInvokeStatic(node, |
| 5643 backend.getCheckConcurrentModificationError(), |
| 5644 [pop(), array]); |
| 5645 pop(); |
| 5646 } |
| 5647 |
| 5648 void buildInitializer() { |
| 5649 visit(node.expression); |
| 5650 array = pop(); |
| 5651 isFixed = isFixedLength(array.instructionType, compiler); |
| 5652 localsHandler.updateLocal(indexVariable, |
| 5653 graph.addConstantInt(0, compiler)); |
| 5654 originalLength = buildGetLength(); |
| 5655 } |
| 5656 |
| 5657 HInstruction buildCondition() { |
| 5658 HInstruction index = localsHandler.readLocal(indexVariable); |
| 5659 HInstruction length = buildGetLength(); |
| 5660 HInstruction compare = new HLess(index, length, null, boolType); |
| 5661 add(compare); |
| 5662 return compare; |
| 5663 } |
| 5664 |
| 5665 void buildBody() { |
| 5666 // If we had mechanically inlined ArrayIterator.moveNext(), it would have |
| 5667 // inserted the ConcurrentModificationError check as part of the |
| 5668 // condition. It is not necessary on the first iteration since there is |
| 5669 // no code between calls to `get iterator` and `moveNext`, so the test is |
| 5670 // moved to the loop update. |
| 5671 |
| 5672 // Find a type for the element. Use the element type of the indexer of the |
| 5673 // array, as this is stronger than the iterator's `get current` type, for |
| 5674 // example, `get current` includes null. |
| 5675 // TODO(sra): The element type of a container type mask might be better. |
| 5676 Selector selector = new Selector.index(); |
| 5677 Selector refined = new TypedSelector(arrayType, selector, compiler.world); |
| 5678 TypeMask type = |
| 5679 TypeMaskFactory.inferredTypeForSelector(refined, compiler); |
| 5680 |
| 5681 HInstruction index = localsHandler.readLocal(indexVariable); |
| 5682 HInstruction value = new HIndex(array, index, null, type); |
| 5683 add(value); |
| 5684 |
| 5685 buildAssignLoopVariable(node, value); |
| 5686 visit(node.body); |
| 5687 } |
| 5688 |
| 5689 void buildUpdate() { |
| 5690 // See buildBody as to why we check here. |
| 5691 buildConcurrentModificationErrorCheck(); |
| 5692 |
| 5693 // TODO(sra): It would be slightly shorter to generate `a[i++]` in the |
| 5694 // body (and that more closely follows what an inlined iterator would do) |
| 5695 // but the code is horrible as `i+1` is carried around the loop in an |
| 5696 // additional variable. |
| 5697 HInstruction index = localsHandler.readLocal(indexVariable); |
| 5698 HInstruction one = graph.addConstantInt(1, compiler); |
| 5699 HInstruction addInstruction = |
| 5700 new HAdd(index, one, null, backend.positiveIntType); |
| 5701 add(addInstruction); |
| 5702 localsHandler.updateLocal(indexVariable, addInstruction); |
| 5703 } |
| 5704 |
| 5705 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); |
| 5706 } |
| 5707 |
5579 visitLabel(ast.Label node) { | 5708 visitLabel(ast.Label node) { |
5580 compiler.internalError(node, 'SsaFromAstMixin.visitLabel.'); | 5709 compiler.internalError(node, 'SsaFromAstMixin.visitLabel.'); |
5581 } | 5710 } |
5582 | 5711 |
5583 visitLabeledStatement(ast.LabeledStatement node) { | 5712 visitLabeledStatement(ast.LabeledStatement node) { |
5584 ast.Statement body = node.statement; | 5713 ast.Statement body = node.statement; |
5585 if (body is ast.Loop | 5714 if (body is ast.Loop |
5586 || body is ast.SwitchStatement | 5715 || body is ast.SwitchStatement |
5587 || Elements.isUnusedLabel(node, elements)) { | 5716 || Elements.isUnusedLabel(node, elements)) { |
5588 // Loops and switches handle their own labels. | 5717 // Loops and switches handle their own labels. |
(...skipping 1415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7004 if (unaliased is TypedefType) throw 'unable to unalias $type'; | 7133 if (unaliased is TypedefType) throw 'unable to unalias $type'; |
7005 unaliased.accept(this, builder); | 7134 unaliased.accept(this, builder); |
7006 } | 7135 } |
7007 | 7136 |
7008 void visitDynamicType(DynamicType type, SsaBuilder builder) { | 7137 void visitDynamicType(DynamicType type, SsaBuilder builder) { |
7009 JavaScriptBackend backend = builder.compiler.backend; | 7138 JavaScriptBackend backend = builder.compiler.backend; |
7010 ClassElement cls = backend.findHelper('DynamicRuntimeType'); | 7139 ClassElement cls = backend.findHelper('DynamicRuntimeType'); |
7011 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); | 7140 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); |
7012 } | 7141 } |
7013 } | 7142 } |
OLD | NEW |