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

Unified Diff: sdk/lib/_internal/js_runtime/lib/js_helper.dart

Issue 1281523003: dart2js: Don't zone-register callbacks in async functions for every await. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Use origin instead of declaration. (already has the right type). Created 5 years, 4 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
« no previous file with comments | « sdk/lib/_internal/js_runtime/lib/async_patch.dart ('k') | sdk/lib/async/future_impl.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/_internal/js_runtime/lib/js_helper.dart
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index b62765f76a3fd5f3a12547b461ef64f94256f6d8..e08c8329709e6be2f952fc8b66ad19fe6be6859b 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -4,8 +4,6 @@
library _js_helper;
-import 'dart:_async_await_error_codes' as async_error_codes;
-
import 'dart:_js_embedded_names' show
DEFERRED_LIBRARY_URIS,
DEFERRED_LIBRARY_HASHES,
@@ -2050,6 +2048,15 @@ class UnknownJsTypeError extends Error {
String toString() => _message.isEmpty ? 'Error' : 'Error: $_message';
}
+/// A wrapper around an exception, much like the one created by [wrapException]
+/// but with a pre-given stack-trace.
+class ExceptionAndStackTrace {
+ dynamic dartException;
+ StackTrace stackTrace;
+
+ ExceptionAndStackTrace(this.dartException, this.stackTrace);
+}
+
/**
* Called from catch blocks in generated code to extract the Dart
* exception from the thrown value. The thrown value may have been
@@ -3889,373 +3896,3 @@ void badMain() {
void mainHasTooManyParameters() {
throw new MainError("'main' expects too many parameters.");
}
-
-/// A wrapper around an exception, much like the one created by [wrapException]
-/// but with a pre-given stack-trace.
-class ExceptionAndStackTrace {
- dynamic dartException;
- StackTrace stackTrace;
-
- ExceptionAndStackTrace(this.dartException, this.stackTrace);
-}
-
-/// Runtime support for async-await transformation.
-///
-/// This function is called by a transformed function on each await and return
-/// in the untransformed function, and before starting.
-///
-/// If [object] is not a future it will be wrapped in a `new Future.value`.
-///
-/// 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 [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.
-///
-/// Returns the future of the completer for convenience of the first call.
-dynamic asyncHelper(dynamic object,
- dynamic /* int | WrappedAsyncBody */ 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(
- (result) => bodyFunctionOrErrorCode(async_error_codes.SUCCESS, result),
- onError: (dynamic error, StackTrace stackTrace) {
- ExceptionAndStackTrace wrappedException =
- new ExceptionAndStackTrace(error, stackTrace);
- bodyFunctionOrErrorCode(async_error_codes.ERROR, wrappedException);
- });
- return completer.future;
-}
-
-typedef void WrappedAsyncBody(int errorCode, dynamic result);
-
-WrappedAsyncBody _wrapJsFunctionForAsync(dynamic /* js function */ function) {
- var protected = JS('', """
- // Invokes [function] with [errorCode] and [result].
- //
- // If (and as long as) the invocation throws, calls [function] again,
- // with an error-code.
- function(errorCode, result) {
- while (true) {
- try {
- #(errorCode, result);
- break;
- } catch (error) {
- result = error;
- errorCode = #;
- }
- }
- }""", function, async_error_codes.ERROR);
- return Zone.current.bindBinaryCallback((int errorCode, dynamic result) {
- JS('', '#(#, #)', protected, 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
-/// [asyncBody] == [async_error_codes.SUCCESS], the asyncStarHelper takes this
-/// as signal to close the stream.
-///
-/// 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, 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
-/// paused, return early. Otherwise schedule the helper function to be
-/// executed again.
-///
-/// 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 [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 [asyncBody] is called on completion of the future (see [asyncHelper].
-void asyncStarHelper(dynamic object,
- dynamic /* int | WrappedAsyncBody */ bodyFunctionOrErrorCode,
- AsyncStarStreamController controller) {
- if (identical(bodyFunctionOrErrorCode, async_error_codes.SUCCESS)) {
- // This happens on return from the async* function.
- if (controller.isCanceled) {
- controller.cancelationCompleter.complete();
- } else {
- controller.close();
- }
- return;
- } else if (identical(bodyFunctionOrErrorCode, async_error_codes.ERROR)) {
- // The error is a js-error.
- if (controller.isCanceled) {
- controller.cancelationCompleter.completeError(
- unwrapException(object),
- getTraceFromException(object));
- } else {
- controller.addError(unwrapException(object),
- getTraceFromException(object));
- controller.close();
- }
- return;
- }
-
- if (object is IterationMarker) {
- if (controller.isCanceled) {
- bodyFunctionOrErrorCode(async_error_codes.STREAM_WAS_CANCELED, null);
- return;
- }
- if (object.state == IterationMarker.YIELD_SINGLE) {
- controller.add(object.value);
-
- scheduleMicrotask(() {
- if (controller.isPaused) {
- // We only suspend the thread inside the microtask in order to allow
- // listeners on the output stream to pause in response to the just
- // output value, and have the stream immediately stop producing.
- controller.isSuspended = true;
- return;
- }
- bodyFunctionOrErrorCode(null, async_error_codes.SUCCESS);
- });
- return;
- } else if (object.state == IterationMarker.YIELD_STAR) {
- Stream stream = object.value;
- // Errors of [stream] are passed though to the main stream. (see
- // [AsyncStreamController.addStream]).
- // TODO(sigurdm): The spec is not very clear here. Clarify with Gilad.
- controller.addStream(stream).then((_) {
- // No check for isPaused here because the spec 17.16.2 only
- // demands checks *before* each element in [stream] not after the last
- // one. On the other hand we check for isCanceled, as that check happens
- // after insertion of each element.
- int errorCode = controller.isCanceled
- ? async_error_codes.STREAM_WAS_CANCELED
- : async_error_codes.SUCCESS;
- bodyFunctionOrErrorCode(errorCode, null);
- });
- return;
- }
- }
-
- Future future = object is Future ? object : new Future.value(object);
- future.then(
- (result) => bodyFunctionOrErrorCode(async_error_codes.SUCCESS, result),
- onError: (error, StackTrace stackTrace) {
- ExceptionAndStackTrace wrappedException =
- new ExceptionAndStackTrace(error, stackTrace);
- bodyFunctionOrErrorCode(async_error_codes.ERROR, wrappedException);
- });
-}
-
-Stream streamOfController(AsyncStarStreamController controller) {
- return controller.stream;
-}
-
-/// A wrapper around a [StreamController] that keeps track of the state of
-/// the execution of an async* function.
-/// It can be in 1 of 3 states:
-///
-/// - running/scheduled
-/// - suspended
-/// - canceled
-///
-/// If yielding while the subscription is paused it will become suspended. And
-/// only resume after the subscription is resumed or canceled.
-class AsyncStarStreamController {
- StreamController controller;
- Stream get stream => controller.stream;
-
- /// True when the async* function has yielded while being paused.
- /// When true execution will only resume after a `onResume` or `onCancel`
- /// event.
- bool isSuspended = false;
-
- bool get isPaused => controller.isPaused;
-
- Completer cancelationCompleter = null;
-
- /// True after the StreamSubscription has been cancelled.
- /// When this is true, errors thrown from the async* body should go to the
- /// [cancelationCompleter] instead of adding them to [controller], and
- /// returning from the async function should complete [cancelationCompleter].
- bool get isCanceled => cancelationCompleter != null;
-
- add(event) => controller.add(event);
-
- addStream(Stream stream) {
- return controller.addStream(stream, cancelOnError: false);
- }
-
- addError(error, stackTrace) => controller.addError(error, stackTrace);
-
- close() => controller.close();
-
- AsyncStarStreamController(WrappedAsyncBody body) {
-
- _resumeBody() {
- scheduleMicrotask(() {
- body(async_error_codes.SUCCESS, null);
- });
- }
-
- controller = new StreamController(
- onListen: () {
- _resumeBody();
- }, onResume: () {
- // Only schedule again if the async* function actually is suspended.
- // Resume directly instead of scheduling, so that the sequence
- // `pause-resume-pause` will result in one extra event produced.
- if (isSuspended) {
- isSuspended = false;
- _resumeBody();
- }
- }, onCancel: () {
- // If the async* is finished we ignore cancel events.
- if (!controller.isClosed) {
- cancelationCompleter = new Completer();
- if (isSuspended) {
- // Resume the suspended async* function to run finalizers.
- isSuspended = false;
- scheduleMicrotask(() {
- body(async_error_codes.STREAM_WAS_CANCELED, null);
- });
- }
- return cancelationCompleter.future;
- }
- });
- }
-}
-
-makeAsyncStarController(body) {
- return new AsyncStarStreamController(body);
-}
-
-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;
-
- IterationMarker._(this.state, this.value);
-
- static yieldStar(dynamic /* Iterable or Stream */ values) {
- return new IterationMarker._(YIELD_STAR, values);
- }
-
- static endOfIteration() {
- return new IterationMarker._(ITERATION_ENDED, null);
- }
-
- static yieldSingle(dynamic value) {
- 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 dynamic _body;
-
- // If [runningNested] this is the nested iterator, otherwise it is the
- // current value.
- dynamic _current = null;
- bool _runningNested = false;
-
- get current => _runningNested ? _current.current : _current;
-
- SyncStarIterator(this._body);
-
- _runBody() {
- return JS('', '''
- // Invokes [body] with [errorCode] and [result].
- //
- // If (and as long as) the invocation throws, calls [function] again,
- // with an error-code.
- (function(body) {
- var errorValue, errorCode = #;
- while (true) {
- try {
- return body(errorCode, errorValue);
- } catch (error) {
- errorValue = error;
- errorCode = #
- }
- }
- })(#)''', async_error_codes.SUCCESS, async_error_codes.ERROR, _body);
- }
-
-
- bool moveNext() {
- if (_runningNested) {
- if (_current.moveNext()) {
- return true;
- } else {
- _runningNested = false;
- }
- }
- _current = _runBody();
- if (_current is IterationMarker) {
- if (_current.state == IterationMarker.ITERATION_ENDED) {
- _current = null;
- // 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;
- _runningNested = true;
- return moveNext();
- }
- }
- return true;
- }
-}
-
-/// An Iterable corresponding to a sync* method.
-///
-/// Each invocation of a sync* method will return a new instance of this class.
-class SyncStarIterable extends IterableBase {
- // This is a function that will return a helper function that does the
- // iteration of the sync*.
- //
- // Each invocation should give a body with fresh state.
- final dynamic /* js function */ _outerHelper;
-
- SyncStarIterable(this._outerHelper);
-
- Iterator get iterator => new SyncStarIterator(JS('', '#()', _outerHelper));
-}
« no previous file with comments | « sdk/lib/_internal/js_runtime/lib/async_patch.dart ('k') | sdk/lib/async/future_impl.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698