Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(210)

Side by Side Diff: pkg/compiler/lib/src/ssa/builder.dart

Issue 1087973002: Rewrite for-in loop as indexing loop for JavaScript indexable arrays (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: retry Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/compiler/lib/src/resolution/registry.dart ('k') | pkg/compiler/lib/src/ssa/codegen.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/resolution/registry.dart ('k') | pkg/compiler/lib/src/ssa/codegen.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698