• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
GeneratorBuiltinsAssembler(CodeAssemblerState * state)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 
GeneratorPrototypeResume(JSGeneratorObject::ResumeMode resume_mode,char const * const method_name)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 )
TF_BUILTIN(GeneratorPrototypeNext,GeneratorBuiltinsAssembler)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 )
TF_BUILTIN(GeneratorPrototypeReturn,GeneratorBuiltinsAssembler)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 )
TF_BUILTIN(GeneratorPrototypeThrow,GeneratorBuiltinsAssembler)110 TF_BUILTIN(GeneratorPrototypeThrow, GeneratorBuiltinsAssembler) {
111   GeneratorPrototypeResume(JSGeneratorObject::kThrow,
112                            "[Generator].prototype.throw");
113 }
114 
115 }  // namespace internal
116 }  // namespace v8
117