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

Side by Side Diff: runtime/lib/core_patch.dart

Issue 1073623002: Fix spurious resume when awaiting future in async* code (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: 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 | « no previous file | runtime/vm/parser.h » ('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) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 "dart:math"; 5 import "dart:math";
6 import "dart:typed_data"; 6 import "dart:typed_data";
7 7
8 // Equivalent of calling FATAL from C++ code. 8 // Equivalent of calling FATAL from C++ code.
9 _fatal(msg) native "DartCore_fatal"; 9 _fatal(msg) native "DartCore_fatal";
10 10
(...skipping 18 matching lines...) Expand all
29 29
30 30
31 // _AsyncStarStreamController is used by the compiler to implement 31 // _AsyncStarStreamController is used by the compiler to implement
32 // async* generator functions. 32 // async* generator functions.
33 class _AsyncStarStreamController { 33 class _AsyncStarStreamController {
34 StreamController controller; 34 StreamController controller;
35 Function asyncStarBody; 35 Function asyncStarBody;
36 bool isAdding = false; 36 bool isAdding = false;
37 bool onListenReceived = false; 37 bool onListenReceived = false;
38 bool isScheduled = false; 38 bool isScheduled = false;
39 bool isSuspendedAtYield = false;
39 Completer cancellationCompleter = null; 40 Completer cancellationCompleter = null;
40 41
41 Stream get stream => controller.stream; 42 Stream get stream => controller.stream;
42 43
43 void runBody() { 44 void runBody() {
44 isScheduled = false; 45 isScheduled = false;
46 isSuspendedAtYield = false;
Lasse Reichstein Nielsen 2015/04/09 06:35:30 If I understand this correctly, your possible stat
hausner 2015/04/09 17:10:19 I agree that the code and comments could be cleare
45 asyncStarBody(); 47 asyncStarBody();
46 } 48 }
47 49
48 void scheduleGenerator() { 50 void scheduleGenerator() {
49 if (isScheduled || controller.isPaused || isAdding) { 51 if (isScheduled || controller.isPaused || isAdding) {
50 return; 52 return;
51 } 53 }
52 isScheduled = true; 54 isScheduled = true;
53 scheduleMicrotask(runBody); 55 scheduleMicrotask(runBody);
54 } 56 }
55 57
56 // Adds element to steam, returns true if the caller should terminate 58 // Adds element to steam, returns true if the caller should terminate
57 // execution of the generator. 59 // execution of the generator.
58 // 60 //
59 // TODO(hausner): Per spec, the generator should be suspended before 61 // TODO(hausner): Per spec, the generator should be suspended before
60 // exiting when the stream is closed. We could add a getter like this: 62 // exiting when the stream is closed. We could add a getter like this:
61 // get isCancelled => controller.hasListener; 63 // get isCancelled => controller.hasListener;
62 // The generator would translate a 'yield e' statement to 64 // The generator would translate a 'yield e' statement to
63 // controller.add(e); 65 // controller.add(e);
64 // suspend; 66 // suspend;
65 // if (controller.isCanelled) return; 67 // if (controller.isCancelled) return;
66 bool add(event) { 68 bool add(event) {
67 if (!onListenReceived) _fatal("yield before stream is listened to!"); 69 if (!onListenReceived) _fatal("yield before stream is listened to!");
70 if (isSuspendedAtYield) _fatal("unexpected yield");
68 // If stream is cancelled, tell caller to exit the async generator. 71 // If stream is cancelled, tell caller to exit the async generator.
69 if (!controller.hasListener) { 72 if (!controller.hasListener) {
70 return true; 73 return true;
71 } 74 }
72 controller.add(event); 75 controller.add(event);
73 scheduleGenerator(); 76 scheduleGenerator();
77 isSuspendedAtYield = true;
74 return false; 78 return false;
75 } 79 }
76 80
77 // Adds the elements of stream into this controller's stream. 81 // Adds the elements of stream into this controller's stream.
78 // The generator will be scheduled again when all of the 82 // The generator will be scheduled again when all of the
79 // elements of the added stream have been consumed. 83 // elements of the added stream have been consumed.
80 // Returns true if the caller should terminate 84 // Returns true if the caller should terminate
81 // execution of the generator. 85 // execution of the generator.
82 bool addStream(Stream stream) { 86 bool addStream(Stream stream) {
83 if (!onListenReceived) _fatal("yield before stream is listened to!"); 87 if (!onListenReceived) _fatal("yield before stream is listened to!");
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 onCancel: this.onCancel); 128 onCancel: this.onCancel);
125 } 129 }
126 130
127 onListen() { 131 onListen() {
128 assert(!onListenReceived); 132 assert(!onListenReceived);
129 onListenReceived = true; 133 onListenReceived = true;
130 scheduleGenerator(); 134 scheduleGenerator();
131 } 135 }
132 136
133 onResume() { 137 onResume() {
134 scheduleGenerator(); 138 if (isSuspendedAtYield) {
139 scheduleGenerator();
140 }
135 } 141 }
136 142
137 onCancel() { 143 onCancel() {
138 if (controller.isClosed) { 144 if (controller.isClosed) {
139 return null; 145 return null;
140 } 146 }
141 if (cancellationCompleter == null) { 147 if (cancellationCompleter == null) {
142 cancellationCompleter = new Completer(); 148 cancellationCompleter = new Completer();
143 scheduleGenerator(); 149 scheduleGenerator();
144 } 150 }
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 if (isYieldEach) { 199 if (isYieldEach) {
194 // Spec mandates: it is a dynamic error if the class of [the object 200 // Spec mandates: it is a dynamic error if the class of [the object
195 // returned by yield*] does not implement Iterable. 201 // returned by yield*] does not implement Iterable.
196 yieldEachIterator = (current as Iterable).iterator; 202 yieldEachIterator = (current as Iterable).iterator;
197 continue; 203 continue;
198 } 204 }
199 return true; 205 return true;
200 } 206 }
201 } 207 }
202 } 208 }
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/parser.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698