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