OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins/builtins-utils-gen.h" | 5 #include "src/builtins/builtins-utils-gen.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stub-assembler.h" | 8 #include "src/code-stub-assembler.h" |
9 #include "src/isolate.h" | 9 #include "src/isolate.h" |
10 #include "src/objects-inl.h" | 10 #include "src/objects-inl.h" |
11 | 11 |
12 namespace v8 { | 12 namespace v8 { |
13 namespace internal { | 13 namespace internal { |
14 | 14 |
15 class GeneratorBuiltinsAssembler : public CodeStubAssembler { | 15 class GeneratorBuiltinsAssembler : public CodeStubAssembler { |
16 public: | 16 public: |
17 explicit GeneratorBuiltinsAssembler(compiler::CodeAssemblerState* state) | 17 explicit GeneratorBuiltinsAssembler(compiler::CodeAssemblerState* state) |
18 : CodeStubAssembler(state) {} | 18 : CodeStubAssembler(state) {} |
19 | 19 |
20 protected: | 20 protected: |
21 void GeneratorPrototypeResume(Node* receiver, Node* value, Node* context, | 21 void GeneratorPrototypeResume(Node* receiver, Node* value, Node* context, |
22 JSGeneratorObject::ResumeMode resume_mode, | 22 JSGeneratorObject::ResumeMode resume_mode, |
23 char const* const method_name); | 23 char const* const method_name); |
24 }; | 24 }; |
25 | 25 |
26 void GeneratorBuiltinsAssembler::GeneratorPrototypeResume( | 26 void GeneratorBuiltinsAssembler::GeneratorPrototypeResume( |
27 Node* receiver, Node* value, Node* context, | 27 Node* receiver, Node* value, Node* context, |
28 JSGeneratorObject::ResumeMode resume_mode, char const* const method_name) { | 28 JSGeneratorObject::ResumeMode resume_mode, char const* const method_name) { |
29 Node* closed = SmiConstant(JSGeneratorObject::kGeneratorClosed); | |
30 | |
31 // Check if the {receiver} is actually a JSGeneratorObject. | 29 // Check if the {receiver} is actually a JSGeneratorObject. |
32 Label if_receiverisincompatible(this, Label::kDeferred); | 30 Label if_receiverisincompatible(this, Label::kDeferred); |
33 GotoIf(TaggedIsSmi(receiver), &if_receiverisincompatible); | 31 GotoIf(TaggedIsSmi(receiver), &if_receiverisincompatible); |
34 Node* receiver_instance_type = LoadInstanceType(receiver); | 32 Node* receiver_instance_type = LoadInstanceType(receiver); |
35 GotoIfNot(Word32Equal(receiver_instance_type, | 33 GotoIfNot(Word32Equal(receiver_instance_type, |
36 Int32Constant(JS_GENERATOR_OBJECT_TYPE)), | 34 Int32Constant(JS_GENERATOR_OBJECT_TYPE)), |
37 &if_receiverisincompatible); | 35 &if_receiverisincompatible); |
38 | 36 |
39 // Check if the {receiver} is running or already closed. | 37 // Check if the {receiver} is running or already closed. |
40 Node* receiver_continuation = | 38 Node* receiver_continuation = |
41 LoadObjectField(receiver, JSGeneratorObject::kContinuationOffset); | 39 LoadObjectField(receiver, JSGeneratorObject::kContinuationOffset); |
42 Label if_receiverisclosed(this, Label::kDeferred), | 40 Label if_receiverisclosed(this, Label::kDeferred), |
43 if_receiverisrunning(this, Label::kDeferred); | 41 if_receiverisrunning(this, Label::kDeferred); |
| 42 Node* closed = SmiConstant(JSGeneratorObject::kGeneratorClosed); |
44 GotoIf(SmiEqual(receiver_continuation, closed), &if_receiverisclosed); | 43 GotoIf(SmiEqual(receiver_continuation, closed), &if_receiverisclosed); |
45 DCHECK_LT(JSGeneratorObject::kGeneratorExecuting, | 44 DCHECK_LT(JSGeneratorObject::kGeneratorExecuting, |
46 JSGeneratorObject::kGeneratorClosed); | 45 JSGeneratorObject::kGeneratorClosed); |
47 GotoIf(SmiLessThan(receiver_continuation, closed), &if_receiverisrunning); | 46 GotoIf(SmiLessThan(receiver_continuation, closed), &if_receiverisrunning); |
48 | 47 |
49 // Resume the {receiver} using our trampoline. | 48 // Resume the {receiver} using our trampoline. |
50 VARIABLE(var_exception, MachineRepresentation::kTagged, UndefinedConstant()); | 49 VARIABLE(var_exception, MachineRepresentation::kTagged, UndefinedConstant()); |
51 Label if_exception(this, Label::kDeferred), if_final_return(this); | 50 Label if_exception(this, Label::kDeferred), if_final_return(this); |
52 Node* result = | 51 Node* result = |
53 CallStub(CodeFactory::ResumeGenerator(isolate()), context, value, | 52 CallStub(CodeFactory::ResumeGenerator(isolate()), context, value, |
54 receiver, SmiConstant(resume_mode), | 53 receiver, SmiConstant(resume_mode), |
55 SmiConstant(static_cast<int>(SuspendFlags::kGeneratorYield))); | 54 SmiConstant(static_cast<int>(SuspendFlags::kGeneratorYield))); |
56 // Make sure we close the generator if there was an exception. | 55 // Make sure we close the generator if there was an exception. |
57 GotoIfException(result, &if_exception, &var_exception); | 56 GotoIfException(result, &if_exception, &var_exception); |
58 | 57 |
59 // If the generator is not suspended (i.e., it's state is 'closed'), | 58 // If the generator is not suspended (i.e., its state is 'executing'), |
60 // wrap the return value in IteratorResult. | 59 // close it and wrap the return value in IteratorResult. |
61 Node* result_continuation = | 60 Node* result_continuation = |
62 LoadObjectField(receiver, JSGeneratorObject::kContinuationOffset); | 61 LoadObjectField(receiver, JSGeneratorObject::kContinuationOffset); |
63 GotoIf(SmiEqual(result_continuation, closed), &if_final_return); | 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 Node* executing = SmiConstant(JSGeneratorObject::kGeneratorExecuting); |
| 68 GotoIf(SmiEqual(result_continuation, executing), &if_final_return); |
| 69 |
64 Return(result); | 70 Return(result); |
65 | 71 |
66 Callable create_iter_result_object = | 72 Callable create_iter_result_object = |
67 Builtins::CallableFor(isolate(), Builtins::kCreateIterResultObject); | 73 Builtins::CallableFor(isolate(), Builtins::kCreateIterResultObject); |
68 | |
69 BIND(&if_final_return); | 74 BIND(&if_final_return); |
70 { | 75 { |
| 76 // Close the generator. |
| 77 StoreObjectFieldNoWriteBarrier( |
| 78 receiver, JSGeneratorObject::kContinuationOffset, closed); |
71 // Return the wrapped result. | 79 // Return the wrapped result. |
72 Return( | 80 Return( |
73 CallStub(create_iter_result_object, context, result, TrueConstant())); | 81 CallStub(create_iter_result_object, context, result, TrueConstant())); |
74 } | 82 } |
75 | 83 |
76 BIND(&if_receiverisincompatible); | 84 BIND(&if_receiverisincompatible); |
77 { | 85 { |
78 // The {receiver} is not a valid JSGeneratorObject. | 86 // The {receiver} is not a valid JSGeneratorObject. |
79 CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context, | 87 CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context, |
80 HeapConstant( | 88 HeapConstant( |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 Node* receiver = Parameter(Descriptor::kReceiver); | 149 Node* receiver = Parameter(Descriptor::kReceiver); |
142 Node* exception = Parameter(Descriptor::kException); | 150 Node* exception = Parameter(Descriptor::kException); |
143 Node* context = Parameter(Descriptor::kContext); | 151 Node* context = Parameter(Descriptor::kContext); |
144 GeneratorPrototypeResume(receiver, exception, context, | 152 GeneratorPrototypeResume(receiver, exception, context, |
145 JSGeneratorObject::kThrow, | 153 JSGeneratorObject::kThrow, |
146 "[Generator].prototype.throw"); | 154 "[Generator].prototype.throw"); |
147 } | 155 } |
148 | 156 |
149 } // namespace internal | 157 } // namespace internal |
150 } // namespace v8 | 158 } // namespace v8 |
OLD | NEW |