Home | History | Annotate | Download | only in builtins
      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.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 typedef compiler::CodeAssemblerState CodeAssemblerState;
     16 
     17 class GeneratorBuiltinsAssembler : public CodeStubAssembler {
     18  public:
     19   explicit GeneratorBuiltinsAssembler(CodeAssemblerState* state)
     20       : CodeStubAssembler(state) {}
     21 
     22  protected:
     23   void GeneratorPrototypeResume(JSGeneratorObject::ResumeMode resume_mode,
     24                                 char const* const method_name);
     25 };
     26 
     27 void GeneratorBuiltinsAssembler::GeneratorPrototypeResume(
     28     JSGeneratorObject::ResumeMode resume_mode, char const* const method_name) {
     29   Node* receiver = Parameter(0);
     30   Node* value = Parameter(1);
     31   Node* context = Parameter(4);
     32   Node* closed = SmiConstant(JSGeneratorObject::kGeneratorClosed);
     33 
     34   // Check if the {receiver} is actually a JSGeneratorObject.
     35   Label if_receiverisincompatible(this, Label::kDeferred);
     36   GotoIf(TaggedIsSmi(receiver), &if_receiverisincompatible);
     37   Node* receiver_instance_type = LoadInstanceType(receiver);
     38   GotoIfNot(Word32Equal(receiver_instance_type,
     39                         Int32Constant(JS_GENERATOR_OBJECT_TYPE)),
     40             &if_receiverisincompatible);
     41 
     42   // Check if the {receiver} is running or already closed.
     43   Node* receiver_continuation =
     44       LoadObjectField(receiver, JSGeneratorObject::kContinuationOffset);
     45   Label if_receiverisclosed(this, Label::kDeferred),
     46       if_receiverisrunning(this, Label::kDeferred);
     47   GotoIf(SmiEqual(receiver_continuation, closed), &if_receiverisclosed);
     48   DCHECK_LT(JSGeneratorObject::kGeneratorExecuting,
     49             JSGeneratorObject::kGeneratorClosed);
     50   GotoIf(SmiLessThan(receiver_continuation, closed), &if_receiverisrunning);
     51 
     52   // Resume the {receiver} using our trampoline.
     53   Node* result = CallStub(CodeFactory::ResumeGenerator(isolate()), context,
     54                           value, receiver, SmiConstant(resume_mode));
     55   Return(result);
     56 
     57   Bind(&if_receiverisincompatible);
     58   {
     59     // The {receiver} is not a valid JSGeneratorObject.
     60     CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context,
     61                 HeapConstant(
     62                     factory()->NewStringFromAsciiChecked(method_name, TENURED)),
     63                 receiver);
     64     Unreachable();
     65   }
     66 
     67   Bind(&if_receiverisclosed);
     68   {
     69     Callable create_iter_result_object =
     70         CodeFactory::CreateIterResultObject(isolate());
     71 
     72     // The {receiver} is closed already.
     73     Node* result = nullptr;
     74     switch (resume_mode) {
     75       case JSGeneratorObject::kNext:
     76         result = CallStub(create_iter_result_object, context,
     77                           UndefinedConstant(), TrueConstant());
     78         break;
     79       case JSGeneratorObject::kReturn:
     80         result =
     81             CallStub(create_iter_result_object, context, value, TrueConstant());
     82         break;
     83       case JSGeneratorObject::kThrow:
     84         result = CallRuntime(Runtime::kThrow, context, value);
     85         break;
     86     }
     87     Return(result);
     88   }
     89 
     90   Bind(&if_receiverisrunning);
     91   {
     92     CallRuntime(Runtime::kThrowGeneratorRunning, context);
     93     Unreachable();
     94   }
     95 }
     96 
     97 // ES6 section 25.3.1.2 Generator.prototype.next ( value )
     98 TF_BUILTIN(GeneratorPrototypeNext, GeneratorBuiltinsAssembler) {
     99   GeneratorPrototypeResume(JSGeneratorObject::kNext,
    100                            "[Generator].prototype.next");
    101 }
    102 
    103 // ES6 section 25.3.1.3 Generator.prototype.return ( value )
    104 TF_BUILTIN(GeneratorPrototypeReturn, GeneratorBuiltinsAssembler) {
    105   GeneratorPrototypeResume(JSGeneratorObject::kReturn,
    106                            "[Generator].prototype.return");
    107 }
    108 
    109 // ES6 section 25.3.1.4 Generator.prototype.throw ( exception )
    110 TF_BUILTIN(GeneratorPrototypeThrow, GeneratorBuiltinsAssembler) {
    111   GeneratorPrototypeResume(JSGeneratorObject::kThrow,
    112                            "[Generator].prototype.throw");
    113 }
    114 
    115 }  // namespace internal
    116 }  // namespace v8
    117