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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
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 library _js_helper; 5 library _js_helper;
6 6
7 import 'dart:_async_await_error_codes' as async_error_codes;
8
7 import 'dart:_js_embedded_names' show 9 import 'dart:_js_embedded_names' show
8 GET_TYPE_FROM_NAME, 10 GET_TYPE_FROM_NAME,
9 GET_ISOLATE_TAG, 11 GET_ISOLATE_TAG,
10 INTERCEPTED_NAMES, 12 INTERCEPTED_NAMES,
11 INTERCEPTORS_BY_TAG, 13 INTERCEPTORS_BY_TAG,
12 LEAF_TAGS, 14 LEAF_TAGS,
13 METADATA, 15 METADATA,
14 DEFERRED_LIBRARY_URIS, 16 DEFERRED_LIBRARY_URIS,
15 DEFERRED_LIBRARY_HASHES, 17 DEFERRED_LIBRARY_HASHES,
16 INITIALIZE_LOADED_HUNK, 18 INITIALIZE_LOADED_HUNK,
17 IS_HUNK_LOADED, 19 IS_HUNK_LOADED,
18 IS_HUNK_INITIALIZED, 20 IS_HUNK_INITIALIZED,
19 NATIVE_SUPERCLASS_TAG_NAME; 21 NATIVE_SUPERCLASS_TAG_NAME;
20 22
21 import 'dart:collection'; 23 import 'dart:collection';
22 import 'dart:_isolate_helper' show 24 import 'dart:_isolate_helper' show
23 IsolateNatives, 25 IsolateNatives,
24 enterJsAsync, 26 enterJsAsync,
25 isWorker, 27 isWorker,
26 leaveJsAsync; 28 leaveJsAsync;
27 29
28 import 'dart:async' show 30 import 'dart:async' show
29 Future, 31 Future,
30 DeferredLoadException, 32 DeferredLoadException,
31 Completer, 33 Completer,
32 StreamController, 34 StreamController,
33 Stream, 35 Stream,
34 StreamSubscription, 36 StreamSubscription,
35 scheduleMicrotask; 37 scheduleMicrotask;
36 38
37 import 'dart:_foreign_helper' show 39 import 'dart:_foreign_helper' show
38 DART_CLOSURE_TO_JS, 40 DART_CLOSURE_TO_JS,
39 JS, 41 JS,
40 JS_CALL_IN_ISOLATE, 42 JS_CALL_IN_ISOLATE,
41 JS_CONST, 43 JS_CONST,
42 JS_CURRENT_ISOLATE, 44 JS_CURRENT_ISOLATE,
43 JS_CURRENT_ISOLATE_CONTEXT, 45 JS_CURRENT_ISOLATE_CONTEXT,
44 JS_DART_OBJECT_CONSTRUCTOR, 46 JS_DART_OBJECT_CONSTRUCTOR,
45 JS_EFFECT, 47 JS_EFFECT,
(...skipping 3424 matching lines...) Expand 10 before | Expand all | Expand 10 after
3470 throw new MainError("'main' expects too many parameters."); 3472 throw new MainError("'main' expects too many parameters.");
3471 } 3473 }
3472 3474
3473 /// Runtime support for async-await transformation. 3475 /// Runtime support for async-await transformation.
3474 /// 3476 ///
3475 /// This function is called by a transformed function on each await and return 3477 /// This function is called by a transformed function on each await and return
3476 /// in the untransformed function, and before starting. 3478 /// in the untransformed function, and before starting.
3477 /// 3479 ///
3478 /// If [object] is not a future it will be wrapped in a `new Future.value`. 3480 /// If [object] is not a future it will be wrapped in a `new Future.value`.
3479 /// 3481 ///
3480 /// If [helperCallback] is null it indicates a return from the async function, 3482 /// If [asyncBody] is [async_error_codes.SUCCESS]/[async_error_codes.ERROR] it
3481 /// and we complete the completer with object. 3483 /// indicates a return or throw from the async function, and
3484 /// complete/completeError is called on [completer] with [object].
3482 /// 3485 ///
3483 /// Otherwise [helperCallback] is set up to be called when the future is 3486 /// Otherwise [asyncBody] is set up to be called when the future is completed
3484 /// successfull and [errorCallback] if it is completed with an error. 3487 /// with a code [async_error_codes.SUCCESS]/[async_error_codes.ERROR] depending
3485 /// 3488 /// on the success of the future.
3486 /// If helperCallback or errorCallback throws we complete the completer with the
3487 /// error.
3488 /// 3489 ///
3489 /// Returns the future of the completer for convenience of the first call. 3490 /// Returns the future of the completer for convenience of the first call.
3490 dynamic thenHelper(dynamic object, 3491 dynamic asyncHelper(dynamic object,
3491 dynamic /* js function */ helperCallback, 3492 dynamic /* js function */ bodyFunctionOrErrorCode,
3492 Completer completer, 3493 Completer completer) {
3493 dynamic /* js function */ errorCallback) { 3494 if (identical(bodyFunctionOrErrorCode, async_error_codes.SUCCESS)) {
3494 if (helperCallback == null) {
3495 completer.complete(object); 3495 completer.complete(object);
3496 return; 3496 return;
3497 } else if (identical(bodyFunctionOrErrorCode, async_error_codes.ERROR)) {
3498 // The error is a js-error.
3499 completer.completeError(unwrapException(object),
3500 getTraceFromException(object));
3501 return;
3497 } 3502 }
3498 Future future = object is Future ? object : new Future.value(object); 3503 Future future = object is Future ? object : new Future.value(object);
3499 future.then(_wrapJsFunctionForThenHelper(helperCallback, completer), 3504 future.then(_wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
3500 onError: (errorCallback == null) 3505 async_error_codes.SUCCESS),
3501 ? null 3506 onError: _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
3502 : _wrapJsFunctionForThenHelper(errorCallback, completer)); 3507 async_error_codes.ERROR));
3503 return completer.future; 3508 return completer.future;
3504 } 3509 }
3505 3510
3506 Function _wrapJsFunctionForThenHelper(dynamic /* js function */ function, 3511 Function _wrapJsFunctionForAsync(dynamic /* js function */ function,
3507 Completer completer) { 3512 int errorCode) {
3508 return (result) { 3513 return (result) {
3509 try { 3514 JS('', '#(#, #)', function, errorCode, result);
3510 JS('', '#(#)', function, result);
3511 } catch (e, st) {
3512 completer.completeError(e, st);
3513 }
3514 }; 3515 };
3515 } 3516 }
3516 3517
3517
3518 /// Implements the runtime support for async* functions. 3518 /// Implements the runtime support for async* functions.
3519 /// 3519 ///
3520 /// Called by the transformed function for each original return, await, yield, 3520 /// Called by the transformed function for each original return, await, yield,
3521 /// yield* and before starting the function. 3521 /// yield* and before starting the function.
3522 /// 3522 ///
3523 /// When the async* function wants to return it calls this function. with 3523 /// When the async* function wants to return it calls this function with
3524 /// [helperCallback] == null, the streamHelper takes this as signal to close the 3524 /// [asyncBody] == [async_error_codes.SUCCESS], the asyncStarHelper takes this
3525 /// stream. 3525 /// as signal to close the stream.
3526 /// 3526 ///
3527 /// If the async* function wants to do a yield or yield* it calls this function 3527 /// When the async* function wants to signal that an uncaught error was thrown,
3528 /// with [object] being an [IterationMarker]. In this case [errorCallback] has a 3528 /// it calls this function with [asyncBody] == [async_error_codes.ERROR],
3529 /// special meaning; it is a callback that will run all enclosing finalizers. 3529 /// the streamHelper takes this as signal to addError [object] to the
3530 /// [controller] and close it.
3531 ///
3532 /// If the async* function wants to do a yield or yield*, it calls this function
3533 /// with [object] being an [IterationMarker].
3530 /// 3534 ///
3531 /// In the case of a yield or yield*, if the stream subscription has been 3535 /// In the case of a yield or yield*, if the stream subscription has been
3532 /// canceled [errorCallback] is scheduled. 3536 /// canceled, schedules [asyncBody] to be called with
3537 /// [async_error_codes.STREAM_WAS_CANCELED].
3533 /// 3538 ///
3534 /// If [object] is a single-yield [IterationMarker], adds the value of the 3539 /// If [object] is a single-yield [IterationMarker], adds the value of the
3535 /// [IterationMarker] to the stream. If the stream subscription has been 3540 /// [IterationMarker] to the stream. If the stream subscription has been
3536 /// paused, return early. Otherwise schedule the helper function to be 3541 /// paused, return early. Otherwise schedule the helper function to be
3537 /// executed again. 3542 /// executed again.
3538 /// 3543 ///
3539 /// If [object] is a yield-star [IterationMarker], starts listening to the 3544 /// If [object] is a yield-star [IterationMarker], starts listening to the
3540 /// yielded stream, and adds all events and errors to our own controller (taking 3545 /// yielded stream, and adds all events and errors to our own controller (taking
3541 /// care if the subscription has been paused or canceled) - when the sub-stream 3546 /// care if the subscription has been paused or canceled) - when the sub-stream
3542 /// is done, schedules [helperCallback] again. 3547 /// is done, schedules [asyncBody] again.
3543 /// 3548 ///
3544 /// If the async* function wants to do an await it calls this function with 3549 /// If the async* function wants to do an await it calls this function with
3545 /// [object] not and [IterationMarker]. 3550 /// [object] not and [IterationMarker].
3546 /// 3551 ///
3547 /// If [object] is not a [Future], it is wrapped in a `Future.value`. 3552 /// If [object] is not a [Future], it is wrapped in a `Future.value`.
3548 /// The [helperCallback] is called on successfull completion of the 3553 /// The [asyncBody] is called on completion of the future (see [asyncHelper].
3549 /// future. 3554 void asyncStarHelper(dynamic object,
3550 /// 3555 dynamic /* int | js function */ bodyFunctionOrErrorCode,
3551 /// If [helperCallback] or [errorCallback] throws the error is added to the 3556 AsyncStarStreamController controller) {
3552 /// stream. 3557 if (identical(bodyFunctionOrErrorCode, async_error_codes.SUCCESS)) {
3553 void streamHelper(dynamic object,
3554 dynamic /* js function */ helperCallback,
3555 AsyncStarStreamController controller,
3556 dynamic /* js function */ errorCallback) {
3557 if (helperCallback == null) {
3558 // This happens on return from the async* function. 3558 // This happens on return from the async* function.
3559 controller.close(); 3559 controller.close();
3560 return; 3560 return;
3561 } else if (identical(bodyFunctionOrErrorCode, async_error_codes.ERROR)) {
3562 // The error is a js-error.
3563 controller.addError(unwrapException(object),
3564 getTraceFromException(object));
3565 controller.close();
3566 return;
3561 } 3567 }
3562 3568
3563 if (object is IterationMarker) { 3569 if (object is IterationMarker) {
3564 if (controller.stopRunning) { 3570 if (controller.stopRunning) {
3565 _wrapJsFunctionForStream(errorCallback, controller)(); 3571 _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
3572 async_error_codes.STREAM_WAS_CANCELED)(null);
3566 return; 3573 return;
3567 } 3574 }
3568 if (object.state == IterationMarker.YIELD_SINGLE) { 3575 if (object.state == IterationMarker.YIELD_SINGLE) {
3569 controller.add(object.value); 3576 controller.add(object.value);
3570 // If the controller is paused we stop producing more values. 3577 // If the controller is paused we stop producing more values.
3571 if (controller.isPaused) { 3578 if (controller.isPaused) {
3572 return; 3579 return;
3573 } 3580 }
3574 // TODO(sigurdm): We should not suspend here according to the spec. 3581 // TODO(sigurdm): We should not suspend here according to the spec.
3575 scheduleMicrotask(() { 3582 scheduleMicrotask(() {
3576 _wrapJsFunctionForStream(helperCallback, controller)(null); 3583 _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
3584 async_error_codes.SUCCESS)
3585 (null);
3577 }); 3586 });
3578 return; 3587 return;
3579 } else if (object.state == IterationMarker.YIELD_STAR) { 3588 } else if (object.state == IterationMarker.YIELD_STAR) {
3580 Stream stream = object.value; 3589 Stream stream = object.value;
3581 controller.isAdding = true; 3590 controller.isAdding = true;
3582 // Errors of [stream] are passed though to the main stream. (see 3591 // Errors of [stream] are passed though to the main stream. (see
3583 // [AsyncStreamController.addStream]. 3592 // [AsyncStreamController.addStream].
3584 // TODO(sigurdm): The spec is not very clear here. Clarify with Gilad. 3593 // TODO(sigurdm): The spec is not very clear here. Clarify with Gilad.
3585 controller.addStream(stream).then((_) { 3594 controller.addStream(stream).then((_) {
3586 controller.isAdding = false; 3595 controller.isAdding = false;
3587 _wrapJsFunctionForStream(helperCallback, controller)(null); 3596 _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
3597 async_error_codes.SUCCESS)(null);
3588 }); 3598 });
3589 return; 3599 return;
3590 } 3600 }
3591 } 3601 }
3592 3602
3593 Future future = object is Future ? object : new Future.value(object); 3603 Future future = object is Future ? object : new Future.value(object);
3594 future.then(_wrapJsFunctionForStream(helperCallback, controller), 3604 future.then(_wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
3595 onError: errorCallback == null 3605 async_error_codes.SUCCESS),
3596 ? null 3606 onError: _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
3597 : _wrapJsFunctionForStream(errorCallback, controller)); 3607 async_error_codes.ERROR));
3598 } 3608 }
3599 3609
3600 Stream streamOfController(AsyncStarStreamController controller) { 3610 Stream streamOfController(AsyncStarStreamController controller) {
3601 return controller.stream; 3611 return controller.stream;
3602 } 3612 }
3603 3613
3604 /// A wrapper around a [StreamController] that remembers if that controller 3614 /// A wrapper around a [StreamController] that remembers if that controller
3605 /// got a cancel. 3615 /// got a cancel.
3606 /// 3616 ///
3607 /// Also has a subSubscription that when not null will provide events for the 3617 /// Also has a subSubscription that when not null will provide events for the
3608 /// stream, and will be paused and resumed along with this controller. 3618 /// stream, and will be paused and resumed along with this controller.
3609 class AsyncStarStreamController { 3619 class AsyncStarStreamController {
3610 StreamController controller; 3620 StreamController controller;
3611 Stream get stream => controller.stream; 3621 Stream get stream => controller.stream;
3612 bool stopRunning = false; 3622 bool stopRunning = false;
3613 bool isAdding = false; 3623 bool isAdding = false;
3614 bool get isPaused => controller.isPaused; 3624 bool get isPaused => controller.isPaused;
3615 add(event) => controller.add(event); 3625 add(event) => controller.add(event);
3616 addStream(Stream stream) { 3626 addStream(Stream stream) {
3617 return controller.addStream(stream, cancelOnError: false); 3627 return controller.addStream(stream, cancelOnError: false);
3618 } 3628 }
3619 addError(error, stackTrace) => controller.addError(error, stackTrace); 3629 addError(error, stackTrace) => controller.addError(error, stackTrace);
3620 close() => controller.close(); 3630 close() => controller.close();
3621 3631
3622 AsyncStarStreamController(helperCallback) { 3632 AsyncStarStreamController(helperCallback) {
3623 controller = new StreamController( 3633 controller = new StreamController(
3624 onListen: () { 3634 onListen: () {
3625 scheduleMicrotask(() => JS('', '#(null)', helperCallback)); 3635 scheduleMicrotask(() {
3636 JS('', '#(#, null)', helperCallback, async_error_codes.SUCCESS);
3637 });
3626 }, 3638 },
3627 onResume: () { 3639 onResume: () {
3628 if (!isAdding) { 3640 if (!isAdding) {
3629 streamHelper(null, helperCallback, this, null); 3641 asyncStarHelper(null, helperCallback, this);
3630 } 3642 }
3631 }, onCancel: () { 3643 }, onCancel: () {
3632 stopRunning = true; 3644 stopRunning = true;
3633 }); 3645 });
3634 } 3646 }
3635 } 3647 }
3636 3648
3637 makeAsyncStarController(helperCallback) { 3649 makeAsyncStarController(helperCallback) {
3638 return new AsyncStarStreamController(helperCallback); 3650 return new AsyncStarStreamController(helperCallback);
3639 } 3651 }
3640 3652
3641 Function _wrapJsFunctionForStream(dynamic /* js function */ function,
3642 AsyncStarStreamController controller) {
3643 return (result) {
3644 try {
3645 JS('', '#(#)', function, result);
3646 } catch (e, st) {
3647 controller.addError(e, st);
3648 }
3649 };
3650 }
3651
3652
3653 class IterationMarker { 3653 class IterationMarker {
3654 static const YIELD_SINGLE = 0; 3654 static const YIELD_SINGLE = 0;
3655 static const YIELD_STAR = 1; 3655 static const YIELD_STAR = 1;
3656 static const ITERATION_ENDED = 2; 3656 static const ITERATION_ENDED = 2;
3657 static const UNCAUGHT_ERROR = 3;
3657 3658
3658 final value; 3659 final value;
3659 final int state; 3660 final int state;
3660 3661
3661 IterationMarker._(this.state, this.value); 3662 IterationMarker._(this.state, this.value);
3662 3663
3663 static yieldStar(dynamic /* Iterable or Stream */ values) { 3664 static yieldStar(dynamic /* Iterable or Stream */ values) {
3664 return new IterationMarker._(YIELD_STAR, values); 3665 return new IterationMarker._(YIELD_STAR, values);
3665 } 3666 }
3666 3667
3667 static endOfIteration() { 3668 static endOfIteration() {
3668 return new IterationMarker._(ITERATION_ENDED, null); 3669 return new IterationMarker._(ITERATION_ENDED, null);
3669 } 3670 }
3670 3671
3671 static yieldSingle(dynamic value) { 3672 static yieldSingle(dynamic value) {
3672 return new IterationMarker._(YIELD_SINGLE, value); 3673 return new IterationMarker._(YIELD_SINGLE, value);
3673 } 3674 }
3674 3675
3676 static uncaughtError(dynamic error) {
3677 return new IterationMarker._(UNCAUGHT_ERROR, error);
3678 }
3679
3675 toString() => "IterationMarker($state, $value)"; 3680 toString() => "IterationMarker($state, $value)";
3676 } 3681 }
3677 3682
3678 class SyncStarIterator implements Iterator { 3683 class SyncStarIterator implements Iterator {
3679 final Function _helper; 3684 final Function _body;
3680 3685
3681 // If [runningNested] this is the nested iterator, otherwise it is the 3686 // If [runningNested] this is the nested iterator, otherwise it is the
3682 // current value. 3687 // current value.
3683 dynamic _current = null; 3688 dynamic _current = null;
3684 bool _runningNested = false; 3689 bool _runningNested = false;
3685 3690
3686 get current => _runningNested ? _current.current : _current; 3691 get current => _runningNested ? _current.current : _current;
3687 3692
3688 SyncStarIterator(helper) 3693 SyncStarIterator(body)
3689 : _helper = ((arg) => JS('', '#(#)', helper, arg)); 3694 : _body = (() => JS('', '#()', body));
3690 3695
3691 bool moveNext() { 3696 bool moveNext() {
3692 if (_runningNested) { 3697 if (_runningNested) {
3693 if (_current.moveNext()) { 3698 if (_current.moveNext()) {
3694 return true; 3699 return true;
3695 } else { 3700 } else {
3696 _runningNested = false; 3701 _runningNested = false;
3697 } 3702 }
3698 } 3703 }
3699 _current = _helper(null); 3704 _current = _body();
3700 if (_current is IterationMarker) { 3705 if (_current is IterationMarker) {
3701 if (_current.state == IterationMarker.ITERATION_ENDED) { 3706 if (_current.state == IterationMarker.ITERATION_ENDED) {
3702 _current = null; 3707 _current = null;
3703 // Rely on [_helper] to repeatedly return `ITERATION_ENDED`. 3708 // Rely on [_body] to repeatedly return `ITERATION_ENDED`.
3704 return false; 3709 return false;
3710 } else if (_current.state == IterationMarker.UNCAUGHT_ERROR) {
3711 // Rely on [_body] to repeatedly return `UNCAUGHT_ERROR`.
3712 // This is a wrapped exception, so we use JavaScript throw to throw it.
3713 JS('', 'throw #', _current.value);
3705 } else { 3714 } else {
3706 assert(_current.state == IterationMarker.YIELD_STAR); 3715 assert(_current.state == IterationMarker.YIELD_STAR);
3707 _current = _current.value.iterator; 3716 _current = _current.value.iterator;
3708 _runningNested = true; 3717 _runningNested = true;
3709 return moveNext(); 3718 return moveNext();
3710 } 3719 }
3711 } 3720 }
3712 return true; 3721 return true;
3713 } 3722 }
3714 } 3723 }
3715 3724
3716 /// An Iterable corresponding to a sync* method. 3725 /// An Iterable corresponding to a sync* method.
3717 /// 3726 ///
3718 /// Each invocation of a sync* method will return a new instance of this class. 3727 /// Each invocation of a sync* method will return a new instance of this class.
3719 class SyncStarIterable extends IterableBase { 3728 class SyncStarIterable extends IterableBase {
3720 // This is a function that will return a helper function that does the 3729 // This is a function that will return a helper function that does the
3721 // iteration of the sync*. 3730 // iteration of the sync*.
3722 // 3731 //
3723 // Each invocation should give a helper with fresh state. 3732 // Each invocation should give a body with fresh state.
3724 final dynamic /* js function */ _outerHelper; 3733 final dynamic /* js function */ _outerHelper;
3725 3734
3726 SyncStarIterable(this._outerHelper); 3735 SyncStarIterable(this._outerHelper);
3727 3736
3728 Iterator get iterator => new SyncStarIterator(JS('', '#()', _outerHelper)); 3737 Iterator get iterator => new SyncStarIterator(JS('', '#()', _outerHelper));
3729 } 3738 }
OLDNEW
« 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