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

Unified Diff: sdk/lib/_internal/compiler/js_lib/js_helper.dart

Issue 929053005: Merge request - fixes dart2js async problems. Base URL: http://dart.googlecode.com/svn/trunk/dart/
Patch Set: Created 5 years, 10 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 side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/js_lib/js_helper.dart
===================================================================
--- sdk/lib/_internal/compiler/js_lib/js_helper.dart (revision 43839)
+++ sdk/lib/_internal/compiler/js_lib/js_helper.dart (working copy)
@@ -4,6 +4,8 @@
library _js_helper;
+import 'dart:_async_await_error_codes' as async_error_codes;
+
import 'dart:_js_embedded_names' show
GET_TYPE_FROM_NAME,
GET_ISOLATE_TAG,
@@ -26,13 +28,13 @@
leaveJsAsync;
import 'dart:async' show
- Future,
- DeferredLoadException,
- Completer,
- StreamController,
- Stream,
- StreamSubscription,
- scheduleMicrotask;
+ Future,
+ DeferredLoadException,
+ Completer,
+ StreamController,
+ Stream,
+ StreamSubscription,
+ scheduleMicrotask;
import 'dart:_foreign_helper' show
DART_CLOSURE_TO_JS,
@@ -3477,59 +3479,62 @@
///
/// If [object] is not a future it will be wrapped in a `new Future.value`.
///
-/// If [helperCallback] is null it indicates a return from the async function,
-/// and we complete the completer with object.
+/// If [asyncBody] is [async_error_codes.SUCCESS]/[async_error_codes.ERROR] it
+/// indicates a return or throw from the async function, and
+/// complete/completeError is called on [completer] with [object].
///
-/// Otherwise [helperCallback] is set up to be called when the future is
-/// successfull and [errorCallback] if it is completed with an error.
+/// Otherwise [asyncBody] is set up to be called when the future is completed
+/// with a code [async_error_codes.SUCCESS]/[async_error_codes.ERROR] depending
+/// on the success of the future.
///
-/// If helperCallback or errorCallback throws we complete the completer with the
-/// error.
-///
/// Returns the future of the completer for convenience of the first call.
-dynamic thenHelper(dynamic object,
- dynamic /* js function */ helperCallback,
- Completer completer,
- dynamic /* js function */ errorCallback) {
- if (helperCallback == null) {
+dynamic asyncHelper(dynamic object,
+ dynamic /* js function */ bodyFunctionOrErrorCode,
+ Completer completer) {
+ if (identical(bodyFunctionOrErrorCode, async_error_codes.SUCCESS)) {
completer.complete(object);
return;
+ } else if (identical(bodyFunctionOrErrorCode, async_error_codes.ERROR)) {
+ // The error is a js-error.
+ completer.completeError(unwrapException(object),
+ getTraceFromException(object));
+ return;
}
Future future = object is Future ? object : new Future.value(object);
- future.then(_wrapJsFunctionForThenHelper(helperCallback, completer),
- onError: (errorCallback == null)
- ? null
- : _wrapJsFunctionForThenHelper(errorCallback, completer));
+ future.then(_wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+ async_error_codes.SUCCESS),
+ onError: _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+ async_error_codes.ERROR));
return completer.future;
}
-Function _wrapJsFunctionForThenHelper(dynamic /* js function */ function,
- Completer completer) {
+Function _wrapJsFunctionForAsync(dynamic /* js function */ function,
+ int errorCode) {
return (result) {
- try {
- JS('', '#(#)', function, result);
- } catch (e, st) {
- completer.completeError(e, st);
- }
+ JS('', '#(#, #)', function, errorCode, result);
};
}
-
/// Implements the runtime support for async* functions.
///
/// Called by the transformed function for each original return, await, yield,
/// yield* and before starting the function.
///
-/// When the async* function wants to return it calls this function. with
-/// [helperCallback] == null, the streamHelper takes this as signal to close the
-/// stream.
+/// When the async* function wants to return it calls this function with
+/// [asyncBody] == [async_error_codes.SUCCESS], the asyncStarHelper takes this
+/// as signal to close the stream.
///
-/// If the async* function wants to do a yield or yield* it calls this function
-/// with [object] being an [IterationMarker]. In this case [errorCallback] has a
-/// special meaning; it is a callback that will run all enclosing finalizers.
+/// When the async* function wants to signal that an uncaught error was thrown,
+/// it calls this function with [asyncBody] == [async_error_codes.ERROR],
+/// the streamHelper takes this as signal to addError [object] to the
+/// [controller] and close it.
///
+/// If the async* function wants to do a yield or yield*, it calls this function
+/// with [object] being an [IterationMarker].
+///
/// In the case of a yield or yield*, if the stream subscription has been
-/// canceled [errorCallback] is scheduled.
+/// canceled, schedules [asyncBody] to be called with
+/// [async_error_codes.STREAM_WAS_CANCELED].
///
/// If [object] is a single-yield [IterationMarker], adds the value of the
/// [IterationMarker] to the stream. If the stream subscription has been
@@ -3539,30 +3544,32 @@
/// If [object] is a yield-star [IterationMarker], starts listening to the
/// yielded stream, and adds all events and errors to our own controller (taking
/// care if the subscription has been paused or canceled) - when the sub-stream
-/// is done, schedules [helperCallback] again.
+/// is done, schedules [asyncBody] again.
///
/// If the async* function wants to do an await it calls this function with
/// [object] not and [IterationMarker].
///
/// If [object] is not a [Future], it is wrapped in a `Future.value`.
-/// The [helperCallback] is called on successfull completion of the
-/// future.
-///
-/// If [helperCallback] or [errorCallback] throws the error is added to the
-/// stream.
-void streamHelper(dynamic object,
- dynamic /* js function */ helperCallback,
- AsyncStarStreamController controller,
- dynamic /* js function */ errorCallback) {
- if (helperCallback == null) {
+/// The [asyncBody] is called on completion of the future (see [asyncHelper].
+void asyncStarHelper(dynamic object,
+ dynamic /* int | js function */ bodyFunctionOrErrorCode,
+ AsyncStarStreamController controller) {
+ if (identical(bodyFunctionOrErrorCode, async_error_codes.SUCCESS)) {
// This happens on return from the async* function.
controller.close();
return;
+ } else if (identical(bodyFunctionOrErrorCode, async_error_codes.ERROR)) {
+ // The error is a js-error.
+ controller.addError(unwrapException(object),
+ getTraceFromException(object));
+ controller.close();
+ return;
}
if (object is IterationMarker) {
if (controller.stopRunning) {
- _wrapJsFunctionForStream(errorCallback, controller)();
+ _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+ async_error_codes.STREAM_WAS_CANCELED)(null);
return;
}
if (object.state == IterationMarker.YIELD_SINGLE) {
@@ -3573,7 +3580,9 @@
}
// TODO(sigurdm): We should not suspend here according to the spec.
scheduleMicrotask(() {
- _wrapJsFunctionForStream(helperCallback, controller)(null);
+ _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+ async_error_codes.SUCCESS)
+ (null);
});
return;
} else if (object.state == IterationMarker.YIELD_STAR) {
@@ -3584,7 +3593,8 @@
// TODO(sigurdm): The spec is not very clear here. Clarify with Gilad.
controller.addStream(stream).then((_) {
controller.isAdding = false;
- _wrapJsFunctionForStream(helperCallback, controller)(null);
+ _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+ async_error_codes.SUCCESS)(null);
});
return;
}
@@ -3591,10 +3601,10 @@
}
Future future = object is Future ? object : new Future.value(object);
- future.then(_wrapJsFunctionForStream(helperCallback, controller),
- onError: errorCallback == null
- ? null
- : _wrapJsFunctionForStream(errorCallback, controller));
+ future.then(_wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+ async_error_codes.SUCCESS),
+ onError: _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+ async_error_codes.ERROR));
}
Stream streamOfController(AsyncStarStreamController controller) {
@@ -3622,11 +3632,13 @@
AsyncStarStreamController(helperCallback) {
controller = new StreamController(
onListen: () {
- scheduleMicrotask(() => JS('', '#(null)', helperCallback));
+ scheduleMicrotask(() {
+ JS('', '#(#, null)', helperCallback, async_error_codes.SUCCESS);
+ });
},
onResume: () {
if (!isAdding) {
- streamHelper(null, helperCallback, this, null);
+ asyncStarHelper(null, helperCallback, this);
}
}, onCancel: () {
stopRunning = true;
@@ -3638,22 +3650,11 @@
return new AsyncStarStreamController(helperCallback);
}
-Function _wrapJsFunctionForStream(dynamic /* js function */ function,
- AsyncStarStreamController controller) {
- return (result) {
- try {
- JS('', '#(#)', function, result);
- } catch (e, st) {
- controller.addError(e, st);
- }
- };
-}
-
-
class IterationMarker {
static const YIELD_SINGLE = 0;
static const YIELD_STAR = 1;
static const ITERATION_ENDED = 2;
+ static const UNCAUGHT_ERROR = 3;
final value;
final int state;
@@ -3672,11 +3673,15 @@
return new IterationMarker._(YIELD_SINGLE, value);
}
+ static uncaughtError(dynamic error) {
+ return new IterationMarker._(UNCAUGHT_ERROR, error);
+ }
+
toString() => "IterationMarker($state, $value)";
}
class SyncStarIterator implements Iterator {
- final Function _helper;
+ final Function _body;
// If [runningNested] this is the nested iterator, otherwise it is the
// current value.
@@ -3685,8 +3690,8 @@
get current => _runningNested ? _current.current : _current;
- SyncStarIterator(helper)
- : _helper = ((arg) => JS('', '#(#)', helper, arg));
+ SyncStarIterator(body)
+ : _body = (() => JS('', '#()', body));
bool moveNext() {
if (_runningNested) {
@@ -3696,12 +3701,16 @@
_runningNested = false;
}
}
- _current = _helper(null);
+ _current = _body();
if (_current is IterationMarker) {
if (_current.state == IterationMarker.ITERATION_ENDED) {
_current = null;
- // Rely on [_helper] to repeatedly return `ITERATION_ENDED`.
+ // Rely on [_body] to repeatedly return `ITERATION_ENDED`.
return false;
+ } else if (_current.state == IterationMarker.UNCAUGHT_ERROR) {
+ // Rely on [_body] to repeatedly return `UNCAUGHT_ERROR`.
+ // This is a wrapped exception, so we use JavaScript throw to throw it.
+ JS('', 'throw #', _current.value);
} else {
assert(_current.state == IterationMarker.YIELD_STAR);
_current = _current.value.iterator;
@@ -3720,7 +3729,7 @@
// This is a function that will return a helper function that does the
// iteration of the sync*.
//
- // Each invocation should give a helper with fresh state.
+ // Each invocation should give a body with fresh state.
final dynamic /* js function */ _outerHelper;
SyncStarIterable(this._outerHelper);
« no previous file with comments | « pkg/compiler/lib/src/ssa/builder.dart ('k') | sdk/lib/_internal/compiler/js_lib/shared/async_await_error_codes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698