LCOV - code coverage report
Current view: top level - src/builtins - builtins-async-iterator-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 103 103 100.0 %
Date: 2019-04-17 Functions: 13 13 100.0 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/builtins/builtins-async-gen.h"
       6             : #include "src/builtins/builtins-utils-gen.h"
       7             : #include "src/builtins/builtins.h"
       8             : #include "src/code-factory.h"
       9             : #include "src/code-stub-assembler.h"
      10             : #include "src/frames-inl.h"
      11             : 
      12             : namespace v8 {
      13             : namespace internal {
      14             : 
      15             : using compiler::Node;
      16             : 
      17             : namespace {
      18         168 : class AsyncFromSyncBuiltinsAssembler : public AsyncBuiltinsAssembler {
      19             :  public:
      20             :   explicit AsyncFromSyncBuiltinsAssembler(compiler::CodeAssemblerState* state)
      21             :       : AsyncBuiltinsAssembler(state) {}
      22             : 
      23             :   void ThrowIfNotAsyncFromSyncIterator(Node* const context, Node* const object,
      24             :                                        Label* if_exception,
      25             :                                        Variable* var_exception,
      26             :                                        const char* method_name);
      27             : 
      28             :   typedef std::function<void(Node* const context, Node* const promise,
      29             :                              Label* if_exception)>
      30             :       UndefinedMethodHandler;
      31             :   typedef std::function<Node*(Node*)> SyncIteratorNodeGenerator;
      32             :   void Generate_AsyncFromSyncIteratorMethod(
      33             :       Node* const context, Node* const iterator, Node* const sent_value,
      34             :       const SyncIteratorNodeGenerator& get_method,
      35             :       const UndefinedMethodHandler& if_method_undefined,
      36             :       const char* operation_name,
      37             :       Label::Type reject_label_type = Label::kDeferred,
      38             :       Node* const initial_exception_value = nullptr);
      39             : 
      40         112 :   void Generate_AsyncFromSyncIteratorMethod(
      41             :       Node* const context, Node* const iterator, Node* const sent_value,
      42             :       Handle<String> name, const UndefinedMethodHandler& if_method_undefined,
      43             :       const char* operation_name,
      44             :       Label::Type reject_label_type = Label::kDeferred,
      45             :       Node* const initial_exception_value = nullptr) {
      46             :     auto get_method = [=](Node* const sync_iterator) {
      47         336 :       return GetProperty(context, sync_iterator, name);
      48         224 :     };
      49         112 :     return Generate_AsyncFromSyncIteratorMethod(
      50             :         context, iterator, sent_value, get_method, if_method_undefined,
      51         224 :         operation_name, reject_label_type, initial_exception_value);
      52             :   }
      53             : 
      54             :   // Load "value" and "done" from an iterator result object. If an exception
      55             :   // is thrown at any point, jumps to te `if_exception` label with exception
      56             :   // stored in `var_exception`.
      57             :   //
      58             :   // Returns a Pair of Nodes, whose first element is the value of the "value"
      59             :   // property, and whose second element is the value of the "done" property,
      60             :   // converted to a Boolean if needed.
      61             :   std::pair<Node*, Node*> LoadIteratorResult(Node* const context,
      62             :                                              Node* const native_context,
      63             :                                              Node* const iter_result,
      64             :                                              Label* if_exception,
      65             :                                              Variable* var_exception);
      66             : };
      67             : 
      68         168 : void AsyncFromSyncBuiltinsAssembler::ThrowIfNotAsyncFromSyncIterator(
      69             :     Node* const context, Node* const object, Label* if_exception,
      70             :     Variable* var_exception, const char* method_name) {
      71         336 :   Label if_receiverisincompatible(this, Label::kDeferred), done(this);
      72             : 
      73         336 :   GotoIf(TaggedIsSmi(object), &if_receiverisincompatible);
      74         336 :   Branch(HasInstanceType(object, JS_ASYNC_FROM_SYNC_ITERATOR_TYPE), &done,
      75         168 :          &if_receiverisincompatible);
      76             : 
      77         168 :   BIND(&if_receiverisincompatible);
      78             :   {
      79             :     // If Type(O) is not Object, or if O does not have a [[SyncIterator]]
      80             :     // internal slot, then
      81             : 
      82             :     // Let badIteratorError be a new TypeError exception.
      83             :     Node* const error =
      84         168 :         MakeTypeError(MessageTemplate::kIncompatibleMethodReceiver, context,
      85         168 :                       StringConstant(method_name), object);
      86             : 
      87             :     // Perform ! Call(promiseCapability.[[Reject]], undefined,
      88             :     //                « badIteratorError »).
      89         168 :     var_exception->Bind(error);
      90         168 :     Goto(if_exception);
      91             :   }
      92             : 
      93         168 :   BIND(&done);
      94         168 : }
      95             : 
      96         168 : void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod(
      97             :     Node* const context, Node* const iterator, Node* const sent_value,
      98             :     const SyncIteratorNodeGenerator& get_method,
      99             :     const UndefinedMethodHandler& if_method_undefined,
     100             :     const char* operation_name, Label::Type reject_label_type,
     101             :     Node* const initial_exception_value) {
     102         336 :   Node* const native_context = LoadNativeContext(context);
     103         168 :   Node* const promise = AllocateAndInitJSPromise(context);
     104             : 
     105         504 :   VARIABLE(var_exception, MachineRepresentation::kTagged,
     106             :            initial_exception_value == nullptr ? UndefinedConstant()
     107             :                                               : initial_exception_value);
     108         168 :   Label reject_promise(this, reject_label_type);
     109             : 
     110             :   ThrowIfNotAsyncFromSyncIterator(context, iterator, &reject_promise,
     111         168 :                                   &var_exception, operation_name);
     112             : 
     113             :   Node* const sync_iterator =
     114             :       LoadObjectField(iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset);
     115             : 
     116             :   Node* const method = get_method(sync_iterator);
     117             : 
     118         168 :   if (if_method_undefined) {
     119         112 :     Label if_isnotundefined(this);
     120             : 
     121         224 :     GotoIfNot(IsUndefined(method), &if_isnotundefined);
     122             :     if_method_undefined(native_context, promise, &reject_promise);
     123             : 
     124         112 :     BIND(&if_isnotundefined);
     125             :   }
     126             : 
     127         336 :   Node* const iter_result = CallJS(CodeFactory::Call(isolate()), context,
     128         168 :                                    method, sync_iterator, sent_value);
     129         168 :   GotoIfException(iter_result, &reject_promise, &var_exception);
     130             : 
     131             :   Node* value;
     132             :   Node* done;
     133         336 :   std::tie(value, done) = LoadIteratorResult(
     134             :       context, native_context, iter_result, &reject_promise, &var_exception);
     135             : 
     136             :   Node* const promise_fun =
     137         336 :       LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
     138             :   CSA_ASSERT(this, IsConstructor(promise_fun));
     139             : 
     140             :   // Let valueWrapper be PromiseResolve(%Promise%, « value »).
     141         336 :   Node* const value_wrapper = CallBuiltin(Builtins::kPromiseResolve,
     142         168 :                                           native_context, promise_fun, value);
     143             :   // IfAbruptRejectPromise(valueWrapper, promiseCapability).
     144         168 :   GotoIfException(value_wrapper, &reject_promise, &var_exception);
     145             : 
     146             :   // Let onFulfilled be a new built-in function object as defined in
     147             :   // Async Iterator Value Unwrap Functions.
     148             :   // Set onFulfilled.[[Done]] to throwDone.
     149         168 :   Node* const on_fulfilled = CreateUnwrapClosure(native_context, done);
     150             : 
     151             :   // Perform ! PerformPromiseThen(valueWrapper,
     152             :   //     onFulfilled, undefined, promiseCapability).
     153         336 :   Return(CallBuiltin(Builtins::kPerformPromiseThen, context, value_wrapper,
     154         504 :                      on_fulfilled, UndefinedConstant(), promise));
     155             : 
     156         168 :   BIND(&reject_promise);
     157             :   {
     158         168 :     Node* const exception = var_exception.value();
     159             :     CallBuiltin(Builtins::kRejectPromise, context, promise, exception,
     160         336 :                 TrueConstant());
     161         168 :     Return(promise);
     162             :   }
     163         168 : }
     164         168 : std::pair<Node*, Node*> AsyncFromSyncBuiltinsAssembler::LoadIteratorResult(
     165             :     Node* const context, Node* const native_context, Node* const iter_result,
     166             :     Label* if_exception, Variable* var_exception) {
     167         336 :   Label if_fastpath(this), if_slowpath(this), merge(this), to_boolean(this),
     168         168 :       done(this), if_notanobject(this, Label::kDeferred);
     169         336 :   GotoIf(TaggedIsSmi(iter_result), &if_notanobject);
     170             : 
     171         336 :   Node* const iter_result_map = LoadMap(iter_result);
     172         336 :   GotoIfNot(IsJSReceiverMap(iter_result_map), &if_notanobject);
     173             : 
     174             :   Node* const fast_iter_result_map =
     175         336 :       LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
     176             : 
     177         336 :   VARIABLE(var_value, MachineRepresentation::kTagged);
     178         336 :   VARIABLE(var_done, MachineRepresentation::kTagged);
     179         336 :   Branch(WordEqual(iter_result_map, fast_iter_result_map), &if_fastpath,
     180         168 :          &if_slowpath);
     181             : 
     182         168 :   BIND(&if_fastpath);
     183             :   {
     184         168 :     var_done.Bind(LoadObjectField(iter_result, JSIteratorResult::kDoneOffset));
     185             :     var_value.Bind(
     186         168 :         LoadObjectField(iter_result, JSIteratorResult::kValueOffset));
     187         168 :     Goto(&merge);
     188             :   }
     189             : 
     190         168 :   BIND(&if_slowpath);
     191             :   {
     192             :     // Let nextDone be IteratorComplete(nextResult).
     193             :     // IfAbruptRejectPromise(nextDone, promiseCapability).
     194             :     Node* const done =
     195         504 :         GetProperty(context, iter_result, factory()->done_string());
     196         168 :     GotoIfException(done, if_exception, var_exception);
     197             : 
     198             :     // Let nextValue be IteratorValue(nextResult).
     199             :     // IfAbruptRejectPromise(nextValue, promiseCapability).
     200             :     Node* const value =
     201         504 :         GetProperty(context, iter_result, factory()->value_string());
     202         168 :     GotoIfException(value, if_exception, var_exception);
     203             : 
     204         168 :     var_value.Bind(value);
     205         168 :     var_done.Bind(done);
     206         168 :     Goto(&merge);
     207             :   }
     208             : 
     209         168 :   BIND(&if_notanobject);
     210             :   {
     211             :     // Sync iterator result is not an object --- Produce a TypeError and jump
     212             :     // to the `if_exception` path.
     213             :     Node* const error = MakeTypeError(
     214         168 :         MessageTemplate::kIteratorResultNotAnObject, context, iter_result);
     215         168 :     var_exception->Bind(error);
     216         168 :     Goto(if_exception);
     217             :   }
     218             : 
     219         168 :   BIND(&merge);
     220             :   // Ensure `iterResult.done` is a Boolean.
     221         504 :   GotoIf(TaggedIsSmi(var_done.value()), &to_boolean);
     222         504 :   Branch(IsBoolean(var_done.value()), &done, &to_boolean);
     223             : 
     224         168 :   BIND(&to_boolean);
     225             :   {
     226             :     Node* const result =
     227         504 :         CallBuiltin(Builtins::kToBoolean, context, var_done.value());
     228         168 :     var_done.Bind(result);
     229         168 :     Goto(&done);
     230             :   }
     231             : 
     232         168 :   BIND(&done);
     233         336 :   return std::make_pair(var_value.value(), var_done.value());
     234             : }
     235             : 
     236             : }  // namespace
     237             : 
     238             : // https://tc39.github.io/proposal-async-iteration/
     239             : // Section #sec-%asyncfromsynciteratorprototype%.next
     240         224 : TF_BUILTIN(AsyncFromSyncIteratorPrototypeNext, AsyncFromSyncBuiltinsAssembler) {
     241             :   Node* const iterator = Parameter(Descriptor::kReceiver);
     242             :   Node* const value = Parameter(Descriptor::kValue);
     243             :   Node* const context = Parameter(Descriptor::kContext);
     244             : 
     245          56 :   auto get_method = [=](Node* const unused) {
     246          56 :     return LoadObjectField(iterator, JSAsyncFromSyncIterator::kNextOffset);
     247          56 :   };
     248         168 :   Generate_AsyncFromSyncIteratorMethod(
     249             :       context, iterator, value, get_method, UndefinedMethodHandler(),
     250          56 :       "[Async-from-Sync Iterator].prototype.next");
     251          56 : }
     252             : 
     253             : // https://tc39.github.io/proposal-async-iteration/
     254             : // Section #sec-%asyncfromsynciteratorprototype%.return
     255         224 : TF_BUILTIN(AsyncFromSyncIteratorPrototypeReturn,
     256             :            AsyncFromSyncBuiltinsAssembler) {
     257             :   Node* const iterator = Parameter(Descriptor::kReceiver);
     258             :   Node* const value = Parameter(Descriptor::kValue);
     259             :   Node* const context = Parameter(Descriptor::kContext);
     260             : 
     261             :   auto if_return_undefined = [=](Node* const native_context,
     262          56 :                                  Node* const promise, Label* if_exception) {
     263             :     // If return is undefined, then
     264             :     // Let iterResult be ! CreateIterResultObject(value, true)
     265         112 :     Node* const iter_result = CallBuiltin(Builtins::kCreateIterResultObject,
     266         280 :                                           context, value, TrueConstant());
     267             : 
     268             :     // Perform ! Call(promiseCapability.[[Resolve]], undefined, « iterResult »).
     269             :     // IfAbruptRejectPromise(nextDone, promiseCapability).
     270             :     // Return promiseCapability.[[Promise]].
     271          56 :     CallBuiltin(Builtins::kResolvePromise, context, promise, iter_result);
     272          56 :     Return(promise);
     273          56 :   };
     274             : 
     275         168 :   Generate_AsyncFromSyncIteratorMethod(
     276             :       context, iterator, value, factory()->return_string(), if_return_undefined,
     277          56 :       "[Async-from-Sync Iterator].prototype.return");
     278          56 : }
     279             : 
     280             : // https://tc39.github.io/proposal-async-iteration/
     281             : // Section #sec-%asyncfromsynciteratorprototype%.throw
     282         224 : TF_BUILTIN(AsyncFromSyncIteratorPrototypeThrow,
     283             :            AsyncFromSyncBuiltinsAssembler) {
     284             :   Node* const iterator = Parameter(Descriptor::kReceiver);
     285             :   Node* const reason = Parameter(Descriptor::kReason);
     286             :   Node* const context = Parameter(Descriptor::kContext);
     287             : 
     288             :   auto if_throw_undefined = [=](Node* const native_context, Node* const promise,
     289          56 :                                 Label* if_exception) { Goto(if_exception); };
     290             : 
     291         168 :   Generate_AsyncFromSyncIteratorMethod(
     292             :       context, iterator, reason, factory()->throw_string(), if_throw_undefined,
     293             :       "[Async-from-Sync Iterator].prototype.throw", Label::kNonDeferred,
     294          56 :       reason);
     295          56 : }
     296             : 
     297             : }  // namespace internal
     298       59456 : }  // namespace v8

Generated by: LCOV version 1.10