LCOV - code coverage report
Current view: top level - src/builtins - builtins-generator-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 61 61 100.0 %
Date: 2017-10-20 Functions: 7 7 100.0 %

          Line data    Source code
       1             : // Copyright 2016 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-utils-gen.h"
       6             : #include "src/builtins/builtins.h"
       7             : #include "src/code-factory.h"
       8             : #include "src/code-stub-assembler.h"
       9             : #include "src/isolate.h"
      10             : #include "src/objects-inl.h"
      11             : 
      12             : namespace v8 {
      13             : namespace internal {
      14             : 
      15             : class GeneratorBuiltinsAssembler : public CodeStubAssembler {
      16             :  public:
      17             :   explicit GeneratorBuiltinsAssembler(compiler::CodeAssemblerState* state)
      18          93 :       : CodeStubAssembler(state) {}
      19             : 
      20             :  protected:
      21             :   void GeneratorPrototypeResume(CodeStubArguments* args, Node* receiver,
      22             :                                 Node* value, Node* context,
      23             :                                 JSGeneratorObject::ResumeMode resume_mode,
      24             :                                 char const* const method_name);
      25             : };
      26             : 
      27          93 : void GeneratorBuiltinsAssembler::GeneratorPrototypeResume(
      28             :     CodeStubArguments* args, Node* receiver, Node* value, Node* context,
      29             :     JSGeneratorObject::ResumeMode resume_mode, char const* const method_name) {
      30             :   // Check if the {receiver} is actually a JSGeneratorObject.
      31          93 :   Label if_receiverisincompatible(this, Label::kDeferred);
      32         186 :   GotoIf(TaggedIsSmi(receiver), &if_receiverisincompatible);
      33         186 :   Node* receiver_instance_type = LoadInstanceType(receiver);
      34             :   GotoIfNot(InstanceTypeEqual(receiver_instance_type, JS_GENERATOR_OBJECT_TYPE),
      35         186 :             &if_receiverisincompatible);
      36             : 
      37             :   // Check if the {receiver} is running or already closed.
      38             :   Node* receiver_continuation =
      39             :       LoadObjectField(receiver, JSGeneratorObject::kContinuationOffset);
      40          93 :   Label if_receiverisclosed(this, Label::kDeferred),
      41          93 :       if_receiverisrunning(this, Label::kDeferred);
      42         186 :   Node* closed = SmiConstant(JSGeneratorObject::kGeneratorClosed);
      43         186 :   GotoIf(SmiEqual(receiver_continuation, closed), &if_receiverisclosed);
      44             :   DCHECK_LT(JSGeneratorObject::kGeneratorExecuting,
      45             :             JSGeneratorObject::kGeneratorClosed);
      46         186 :   GotoIf(SmiLessThan(receiver_continuation, closed), &if_receiverisrunning);
      47             : 
      48             :   // Resume the {receiver} using our trampoline.
      49         279 :   VARIABLE(var_exception, MachineRepresentation::kTagged, UndefinedConstant());
      50          93 :   Label if_exception(this, Label::kDeferred), if_final_return(this);
      51             :   Node* result = CallStub(CodeFactory::ResumeGenerator(isolate()), context,
      52         186 :                           value, receiver, SmiConstant(resume_mode));
      53             :   // Make sure we close the generator if there was an exception.
      54          93 :   GotoIfException(result, &if_exception, &var_exception);
      55             : 
      56             :   // If the generator is not suspended (i.e., its state is 'executing'),
      57             :   // close it and wrap the return value in IteratorResult.
      58             :   Node* result_continuation =
      59             :       LoadObjectField(receiver, JSGeneratorObject::kContinuationOffset);
      60             : 
      61             :   // The generator function should not close the generator by itself, let's
      62             :   // check it is indeed not closed yet.
      63             :   CSA_ASSERT(this, SmiNotEqual(result_continuation, closed));
      64             : 
      65         186 :   Node* executing = SmiConstant(JSGeneratorObject::kGeneratorExecuting);
      66         186 :   GotoIf(SmiEqual(result_continuation, executing), &if_final_return);
      67             : 
      68          93 :   args->PopAndReturn(result);
      69             : 
      70          93 :   BIND(&if_final_return);
      71             :   {
      72             :     // Close the generator.
      73             :     StoreObjectFieldNoWriteBarrier(
      74          93 :         receiver, JSGeneratorObject::kContinuationOffset, closed);
      75             :     // Return the wrapped result.
      76             :     args->PopAndReturn(CallBuiltin(Builtins::kCreateIterResultObject, context,
      77          93 :                                    result, TrueConstant()));
      78             :   }
      79             : 
      80          93 :   BIND(&if_receiverisincompatible);
      81             :   {
      82             :     // The {receiver} is not a valid JSGeneratorObject.
      83             :     CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context,
      84          93 :                 StringConstant(method_name), receiver);
      85          93 :     Unreachable();
      86             :   }
      87             : 
      88          93 :   BIND(&if_receiverisclosed);
      89             :   {
      90             :     // The {receiver} is closed already.
      91             :     Node* result = nullptr;
      92          93 :     switch (resume_mode) {
      93             :       case JSGeneratorObject::kNext:
      94             :         result = CallBuiltin(Builtins::kCreateIterResultObject, context,
      95          31 :                              UndefinedConstant(), TrueConstant());
      96          31 :         break;
      97             :       case JSGeneratorObject::kReturn:
      98             :         result = CallBuiltin(Builtins::kCreateIterResultObject, context, value,
      99          31 :                              TrueConstant());
     100          31 :         break;
     101             :       case JSGeneratorObject::kThrow:
     102             :         result = CallRuntime(Runtime::kThrow, context, value);
     103          31 :         break;
     104             :     }
     105          93 :     args->PopAndReturn(result);
     106             :   }
     107             : 
     108          93 :   BIND(&if_receiverisrunning);
     109             :   {
     110             :     CallRuntime(Runtime::kThrowGeneratorRunning, context);
     111          93 :     Unreachable();
     112             :   }
     113             : 
     114          93 :   BIND(&if_exception);
     115             :   {
     116             :     StoreObjectFieldNoWriteBarrier(
     117          93 :         receiver, JSGeneratorObject::kContinuationOffset, closed);
     118          93 :     CallRuntime(Runtime::kReThrow, context, var_exception.value());
     119          93 :     Unreachable();
     120          93 :   }
     121          93 : }
     122             : 
     123             : // ES6 #sec-generator.prototype.next
     124         155 : TF_BUILTIN(GeneratorPrototypeNext, GeneratorBuiltinsAssembler) {
     125             :   const int kValueArg = 0;
     126             : 
     127             :   Node* argc =
     128          62 :       ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
     129          31 :   CodeStubArguments args(this, argc);
     130             : 
     131          62 :   Node* receiver = args.GetReceiver();
     132          62 :   Node* value = args.GetOptionalArgumentValue(kValueArg);
     133             :   Node* context = Parameter(BuiltinDescriptor::kContext);
     134             : 
     135             :   GeneratorPrototypeResume(&args, receiver, value, context,
     136             :                            JSGeneratorObject::kNext,
     137          31 :                            "[Generator].prototype.next");
     138          31 : }
     139             : 
     140             : // ES6 #sec-generator.prototype.return
     141         155 : TF_BUILTIN(GeneratorPrototypeReturn, GeneratorBuiltinsAssembler) {
     142             :   const int kValueArg = 0;
     143             : 
     144             :   Node* argc =
     145          62 :       ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
     146          31 :   CodeStubArguments args(this, argc);
     147             : 
     148          62 :   Node* receiver = args.GetReceiver();
     149          62 :   Node* value = args.GetOptionalArgumentValue(kValueArg);
     150             :   Node* context = Parameter(BuiltinDescriptor::kContext);
     151             : 
     152             :   GeneratorPrototypeResume(&args, receiver, value, context,
     153             :                            JSGeneratorObject::kReturn,
     154          31 :                            "[Generator].prototype.return");
     155          31 : }
     156             : 
     157             : // ES6 #sec-generator.prototype.throw
     158         155 : TF_BUILTIN(GeneratorPrototypeThrow, GeneratorBuiltinsAssembler) {
     159             :   const int kExceptionArg = 0;
     160             : 
     161             :   Node* argc =
     162          62 :       ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
     163          31 :   CodeStubArguments args(this, argc);
     164             : 
     165          62 :   Node* receiver = args.GetReceiver();
     166          62 :   Node* exception = args.GetOptionalArgumentValue(kExceptionArg);
     167             :   Node* context = Parameter(BuiltinDescriptor::kContext);
     168             : 
     169             :   GeneratorPrototypeResume(&args, receiver, exception, context,
     170             :                            JSGeneratorObject::kThrow,
     171          31 :                            "[Generator].prototype.throw");
     172          31 : }
     173             : 
     174             : }  // namespace internal
     175             : }  // namespace v8

Generated by: LCOV version 1.10