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