LCOV - code coverage report
Current view: top level - src/builtins - builtins-async-iterator-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 85 85 100.0 %
Date: 2017-04-26 Functions: 10 10 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             : 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             :   void Generate_AsyncFromSyncIteratorMethod(
      32             :       Node* const context, Node* const iterator, Node* const sent_value,
      33             :       Handle<Name> method_name, UndefinedMethodHandler&& if_method_undefined,
      34             :       const char* operation_name,
      35             :       Label::Type reject_label_type = Label::kDeferred,
      36             :       Node* const initial_exception_value = nullptr);
      37             : 
      38             :   // Load "value" and "done" from an iterator result object. If an exception
      39             :   // is thrown at any point, jumps to te `if_exception` label with exception
      40             :   // stored in `var_exception`.
      41             :   //
      42             :   // Returns a Pair of Nodes, whose first element is the value of the "value"
      43             :   // property, and whose second element is the value of the "done" property,
      44             :   // converted to a Boolean if needed.
      45             :   std::pair<Node*, Node*> LoadIteratorResult(Node* const context,
      46             :                                              Node* const native_context,
      47             :                                              Node* const iter_result,
      48             :                                              Label* if_exception,
      49             :                                              Variable* var_exception);
      50             : };
      51             : 
      52         129 : void AsyncFromSyncBuiltinsAssembler::ThrowIfNotAsyncFromSyncIterator(
      53             :     Node* const context, Node* const object, Label* if_exception,
      54             :     Variable* var_exception, const char* method_name) {
      55         258 :   Label if_receiverisincompatible(this, Label::kDeferred), done(this);
      56             : 
      57         129 :   GotoIf(TaggedIsSmi(object), &if_receiverisincompatible);
      58             :   Branch(HasInstanceType(object, JS_ASYNC_FROM_SYNC_ITERATOR_TYPE), &done,
      59         129 :          &if_receiverisincompatible);
      60             : 
      61         129 :   BIND(&if_receiverisincompatible);
      62             :   {
      63             :     // If Type(O) is not Object, or if O does not have a [[SyncIterator]]
      64             :     // internal slot, then
      65             : 
      66             :     // Let badIteratorError be a new TypeError exception.
      67             :     Node* const error =
      68             :         MakeTypeError(MessageTemplate::kIncompatibleMethodReceiver, context,
      69         129 :                       CStringConstant(method_name), object);
      70             : 
      71             :     // Perform ! Call(promiseCapability.[[Reject]], undefined,
      72             :     //                « badIteratorError »).
      73         129 :     var_exception->Bind(error);
      74         129 :     Goto(if_exception);
      75             :   }
      76             : 
      77         258 :   BIND(&done);
      78         129 : }
      79             : 
      80         129 : void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod(
      81             :     Node* const context, Node* const iterator, Node* const sent_value,
      82             :     Handle<Name> method_name, UndefinedMethodHandler&& if_method_undefined,
      83             :     const char* operation_name, Label::Type reject_label_type,
      84             :     Node* const initial_exception_value) {
      85         129 :   Node* const native_context = LoadNativeContext(context);
      86         129 :   Node* const promise = AllocateAndInitJSPromise(context);
      87             : 
      88         129 :   VARIABLE(var_exception, MachineRepresentation::kTagged,
      89             :            initial_exception_value == nullptr ? UndefinedConstant()
      90             :                                               : initial_exception_value);
      91         129 :   Label reject_promise(this, reject_label_type);
      92             : 
      93             :   ThrowIfNotAsyncFromSyncIterator(context, iterator, &reject_promise,
      94         129 :                                   &var_exception, operation_name);
      95             : 
      96             :   Node* const sync_iterator =
      97         129 :       LoadObjectField(iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset);
      98             : 
      99         129 :   Node* const method = GetProperty(context, sync_iterator, method_name);
     100             : 
     101         129 :   if (if_method_undefined) {
     102             :     Label if_isnotundefined(this);
     103             : 
     104          86 :     GotoIfNot(IsUndefined(method), &if_isnotundefined);
     105          86 :     if_method_undefined(native_context, promise, &reject_promise);
     106             : 
     107          86 :     BIND(&if_isnotundefined);
     108             :   }
     109             : 
     110             :   Node* const iter_result = CallJS(CodeFactory::Call(isolate()), context,
     111         258 :                                    method, sync_iterator, sent_value);
     112         129 :   GotoIfException(iter_result, &reject_promise, &var_exception);
     113             : 
     114             :   Node* value;
     115             :   Node* done;
     116         258 :   std::tie(value, done) = LoadIteratorResult(
     117             :       context, native_context, iter_result, &reject_promise, &var_exception);
     118         129 :   Node* const wrapper = AllocateAndInitJSPromise(context);
     119             : 
     120             :   // Perform ! Call(valueWrapperCapability.[[Resolve]], undefined, «
     121             :   // throwValue »).
     122         129 :   CallBuiltin(Builtins::kResolveNativePromise, context, wrapper, value);
     123             : 
     124             :   // Let onFulfilled be a new built-in function object as defined in
     125             :   // Async Iterator Value Unwrap Functions.
     126             :   // Set onFulfilled.[[Done]] to throwDone.
     127         129 :   Node* const on_fulfilled = CreateUnwrapClosure(native_context, done);
     128             : 
     129             :   // Perform ! PerformPromiseThen(valueWrapperCapability.[[Promise]],
     130             :   //     onFulfilled, undefined, promiseCapability).
     131             :   Return(CallBuiltin(Builtins::kPerformNativePromiseThen, context, wrapper,
     132         129 :                      on_fulfilled, UndefinedConstant(), promise));
     133             : 
     134         129 :   BIND(&reject_promise);
     135             :   {
     136         129 :     Node* const exception = var_exception.value();
     137             :     CallBuiltin(Builtins::kRejectNativePromise, context, promise, exception,
     138         129 :                 TrueConstant());
     139         129 :     Return(promise);
     140         129 :   }
     141         129 : }
     142             : 
     143         129 : std::pair<Node*, Node*> AsyncFromSyncBuiltinsAssembler::LoadIteratorResult(
     144             :     Node* const context, Node* const native_context, Node* const iter_result,
     145             :     Label* if_exception, Variable* var_exception) {
     146         258 :   Label if_fastpath(this), if_slowpath(this), merge(this), to_boolean(this),
     147         129 :       done(this), if_notanobject(this, Label::kDeferred);
     148         129 :   GotoIf(TaggedIsSmi(iter_result), &if_notanobject);
     149             : 
     150         129 :   Node* const iter_result_map = LoadMap(iter_result);
     151         129 :   GotoIfNot(IsJSReceiverMap(iter_result_map), &if_notanobject);
     152             : 
     153             :   Node* const fast_iter_result_map =
     154         129 :       LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
     155             : 
     156         258 :   VARIABLE(var_value, MachineRepresentation::kTagged);
     157         258 :   VARIABLE(var_done, MachineRepresentation::kTagged);
     158             :   Branch(WordEqual(iter_result_map, fast_iter_result_map), &if_fastpath,
     159         129 :          &if_slowpath);
     160             : 
     161         129 :   BIND(&if_fastpath);
     162             :   {
     163         129 :     var_done.Bind(LoadObjectField(iter_result, JSIteratorResult::kDoneOffset));
     164             :     var_value.Bind(
     165         129 :         LoadObjectField(iter_result, JSIteratorResult::kValueOffset));
     166         129 :     Goto(&merge);
     167             :   }
     168             : 
     169         129 :   BIND(&if_slowpath);
     170             :   {
     171             :     // Let nextDone be IteratorComplete(nextResult).
     172             :     // IfAbruptRejectPromise(nextDone, promiseCapability).
     173             :     Node* const done =
     174         258 :         GetProperty(context, iter_result, factory()->done_string());
     175         129 :     GotoIfException(done, if_exception, var_exception);
     176             : 
     177             :     // Let nextValue be IteratorValue(nextResult).
     178             :     // IfAbruptRejectPromise(nextValue, promiseCapability).
     179             :     Node* const value =
     180         258 :         GetProperty(context, iter_result, factory()->value_string());
     181         129 :     GotoIfException(value, if_exception, var_exception);
     182             : 
     183         129 :     var_value.Bind(value);
     184         129 :     var_done.Bind(done);
     185         129 :     Goto(&merge);
     186             :   }
     187             : 
     188         129 :   BIND(&if_notanobject);
     189             :   {
     190             :     // Sync iterator result is not an object --- Produce a TypeError and jump
     191             :     // to the `if_exception` path.
     192             :     Node* const error = MakeTypeError(
     193         129 :         MessageTemplate::kIteratorResultNotAnObject, context, iter_result);
     194         129 :     var_exception->Bind(error);
     195         129 :     Goto(if_exception);
     196             :   }
     197             : 
     198         129 :   BIND(&merge);
     199             :   // Ensure `iterResult.done` is a Boolean.
     200         129 :   GotoIf(TaggedIsSmi(var_done.value()), &to_boolean);
     201         129 :   Branch(IsBoolean(var_done.value()), &done, &to_boolean);
     202             : 
     203         129 :   BIND(&to_boolean);
     204             :   {
     205             :     Node* const result =
     206         258 :         CallStub(CodeFactory::ToBoolean(isolate()), context, var_done.value());
     207         129 :     var_done.Bind(result);
     208         129 :     Goto(&done);
     209             :   }
     210             : 
     211         129 :   BIND(&done);
     212         258 :   return std::make_pair(var_value.value(), var_done.value());
     213             : }
     214             : }  // namespace
     215             : 
     216             : // https://tc39.github.io/proposal-async-iteration/
     217             : // Section #sec-%asyncfromsynciteratorprototype%.next
     218         172 : TF_BUILTIN(AsyncFromSyncIteratorPrototypeNext, AsyncFromSyncBuiltinsAssembler) {
     219             :   Node* const iterator = Parameter(Descriptor::kReceiver);
     220             :   Node* const value = Parameter(Descriptor::kValue);
     221             :   Node* const context = Parameter(Descriptor::kContext);
     222             : 
     223             :   Generate_AsyncFromSyncIteratorMethod(
     224             :       context, iterator, value, factory()->next_string(),
     225         129 :       UndefinedMethodHandler(), "[Async-from-Sync Iterator].prototype.next");
     226          43 : }
     227             : 
     228             : // https://tc39.github.io/proposal-async-iteration/
     229             : // Section #sec-%asyncfromsynciteratorprototype%.return
     230         172 : TF_BUILTIN(AsyncFromSyncIteratorPrototypeReturn,
     231             :            AsyncFromSyncBuiltinsAssembler) {
     232             :   Node* const iterator = Parameter(Descriptor::kReceiver);
     233             :   Node* const value = Parameter(Descriptor::kValue);
     234             :   Node* const context = Parameter(Descriptor::kContext);
     235             : 
     236             :   auto if_return_undefined = [=](Node* const native_context,
     237          43 :                                  Node* const promise, Label* if_exception) {
     238             :     // If return is undefined, then
     239             :     // Let iterResult be ! CreateIterResultObject(value, true)
     240             :     Node* const iter_result =
     241             :         CallStub(CodeFactory::CreateIterResultObject(isolate()), context, value,
     242          86 :                  TrueConstant());
     243             : 
     244             :     // Perform ! Call(promiseCapability.[[Resolve]], undefined, « iterResult »).
     245             :     // IfAbruptRejectPromise(nextDone, promiseCapability).
     246             :     // Return promiseCapability.[[Promise]].
     247          43 :     PromiseFulfill(context, promise, iter_result, v8::Promise::kFulfilled);
     248          43 :     Return(promise);
     249          43 :   };
     250             : 
     251             :   Generate_AsyncFromSyncIteratorMethod(
     252             :       context, iterator, value, factory()->return_string(), if_return_undefined,
     253         129 :       "[Async-from-Sync Iterator].prototype.return");
     254          43 : }
     255             : 
     256             : // https://tc39.github.io/proposal-async-iteration/
     257             : // Section #sec-%asyncfromsynciteratorprototype%.throw
     258         172 : TF_BUILTIN(AsyncFromSyncIteratorPrototypeThrow,
     259             :            AsyncFromSyncBuiltinsAssembler) {
     260             :   Node* const iterator = Parameter(Descriptor::kReceiver);
     261             :   Node* const reason = Parameter(Descriptor::kReason);
     262             :   Node* const context = Parameter(Descriptor::kContext);
     263             : 
     264             :   auto if_throw_undefined = [=](Node* const native_context, Node* const promise,
     265          43 :                                 Label* if_exception) { Goto(if_exception); };
     266             : 
     267             :   Generate_AsyncFromSyncIteratorMethod(
     268             :       context, iterator, reason, factory()->throw_string(), if_throw_undefined,
     269             :       "[Async-from-Sync Iterator].prototype.throw", Label::kNonDeferred,
     270         129 :       reason);
     271          43 : }
     272             : 
     273             : }  // namespace internal
     274             : }  // namespace v8

Generated by: LCOV version 1.10