Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef vm_AsyncIteration_h
8 : #define vm_AsyncIteration_h
9 :
10 : #include "jscntxt.h"
11 : #include "jsobj.h"
12 :
13 : #include "builtin/Promise.h"
14 : #include "vm/GeneratorObject.h"
15 :
16 : namespace js {
17 :
18 : // Async generator consists of 2 functions, |wrapped| and |unwrapped|.
19 : // |unwrapped| is a generator function compiled from async generator script,
20 : // |await| behaves just like |yield| there. |unwrapped| isn't exposed to user
21 : // script.
22 : // |wrapped| is a native function that is the value of async generator.
23 :
24 : JSObject*
25 : WrapAsyncGeneratorWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto);
26 :
27 : JSObject*
28 : WrapAsyncGenerator(JSContext* cx, HandleFunction unwrapped);
29 :
30 : bool
31 : IsWrappedAsyncGenerator(JSFunction* fun);
32 :
33 : JSFunction*
34 : GetWrappedAsyncGenerator(JSFunction* unwrapped);
35 :
36 : JSFunction*
37 : GetUnwrappedAsyncGenerator(JSFunction* wrapped);
38 :
39 : MOZ_MUST_USE bool
40 : AsyncGeneratorAwaitedFulfilled(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
41 : HandleValue value);
42 :
43 : MOZ_MUST_USE bool
44 : AsyncGeneratorAwaitedRejected(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
45 : HandleValue reason);
46 :
47 : class AsyncGeneratorRequest : public NativeObject
48 : {
49 : private:
50 : enum AsyncGeneratorRequestSlots {
51 : Slot_CompletionKind = 0,
52 : Slot_CompletionValue,
53 : Slot_Promise,
54 : Slots,
55 : };
56 :
57 0 : void setCompletionKind(CompletionKind completionKind_) {
58 0 : setFixedSlot(Slot_CompletionKind,
59 0 : Int32Value(static_cast<int32_t>(completionKind_)));
60 0 : }
61 0 : void setCompletionValue(HandleValue completionValue_) {
62 0 : setFixedSlot(Slot_CompletionValue, completionValue_);
63 0 : }
64 0 : void setPromise(HandleObject promise_) {
65 0 : setFixedSlot(Slot_Promise, ObjectValue(*promise_));
66 0 : }
67 :
68 : public:
69 : static const Class class_;
70 :
71 : static AsyncGeneratorRequest*
72 : create(JSContext* cx, CompletionKind completionKind, HandleValue completionValue,
73 : HandleObject promise);
74 :
75 0 : CompletionKind completionKind() const {
76 0 : return static_cast<CompletionKind>(getFixedSlot(Slot_CompletionKind).toInt32());
77 : }
78 0 : JS::Value completionValue() const {
79 0 : return getFixedSlot(Slot_CompletionValue);
80 : }
81 0 : JSObject* promise() const {
82 0 : return &getFixedSlot(Slot_Promise).toObject();
83 : }
84 : };
85 :
86 : class AsyncGeneratorObject : public NativeObject
87 : {
88 : private:
89 : enum AsyncGeneratorObjectSlots {
90 : Slot_State = 0,
91 : Slot_Generator,
92 : Slot_QueueOrRequest,
93 : Slots
94 : };
95 :
96 : enum State {
97 : State_SuspendedStart,
98 : State_SuspendedYield,
99 : State_Executing,
100 : State_Completed
101 : };
102 :
103 0 : State state() const {
104 0 : return static_cast<State>(getFixedSlot(Slot_State).toInt32());
105 : }
106 0 : void setState(State state_) {
107 0 : setFixedSlot(Slot_State, Int32Value(state_));
108 0 : }
109 :
110 0 : void setGenerator(const Value& value) {
111 0 : setFixedSlot(Slot_Generator, value);
112 0 : }
113 :
114 : // Queue is implemented in 2 ways. If only one request is queued ever,
115 : // request is stored directly to the slot. Once 2 requests are queued, an
116 : // array is created and requests are pushed into it, and the array is
117 : // stored to the slot.
118 :
119 0 : bool isSingleQueue() const {
120 0 : return getFixedSlot(Slot_QueueOrRequest).isNull() ||
121 0 : getFixedSlot(Slot_QueueOrRequest).toObject().is<AsyncGeneratorRequest>();
122 : }
123 0 : bool isSingleQueueEmpty() const {
124 0 : return getFixedSlot(Slot_QueueOrRequest).isNull();
125 : }
126 0 : void setSingleQueueRequest(AsyncGeneratorRequest* request) {
127 0 : setFixedSlot(Slot_QueueOrRequest, ObjectValue(*request));
128 0 : }
129 0 : void clearSingleQueueRequest() {
130 0 : setFixedSlot(Slot_QueueOrRequest, NullHandleValue);
131 0 : }
132 0 : AsyncGeneratorRequest* singleQueueRequest() const {
133 0 : return &getFixedSlot(Slot_QueueOrRequest).toObject().as<AsyncGeneratorRequest>();
134 : }
135 :
136 0 : ArrayObject* queue() const {
137 0 : return &getFixedSlot(Slot_QueueOrRequest).toObject().as<ArrayObject>();
138 : }
139 0 : void setQueue(JSObject* queue_) {
140 0 : setFixedSlot(Slot_QueueOrRequest, ObjectValue(*queue_));
141 0 : }
142 :
143 : public:
144 : static const Class class_;
145 :
146 : static AsyncGeneratorObject*
147 : create(JSContext* cx, HandleFunction asyncGen, HandleValue generatorVal);
148 :
149 0 : bool isSuspendedStart() const {
150 0 : return state() == State_SuspendedStart;
151 : }
152 0 : bool isSuspendedYield() const {
153 0 : return state() == State_SuspendedYield;
154 : }
155 0 : bool isExecuting() const {
156 0 : return state() == State_Executing;
157 : }
158 0 : bool isCompleted() const {
159 0 : return state() == State_Completed;
160 : }
161 :
162 0 : void setSuspendedStart() {
163 0 : setState(State_SuspendedStart);
164 0 : }
165 0 : void setSuspendedYield() {
166 0 : setState(State_SuspendedYield);
167 0 : }
168 0 : void setExecuting() {
169 0 : setState(State_Executing);
170 0 : }
171 0 : void setCompleted() {
172 0 : setState(State_Completed);
173 0 : }
174 :
175 0 : JS::Value generatorVal() const {
176 0 : return getFixedSlot(Slot_Generator);
177 : }
178 0 : GeneratorObject* generatorObj() const {
179 0 : return &getFixedSlot(Slot_Generator).toObject().as<GeneratorObject>();
180 : }
181 :
182 : static MOZ_MUST_USE bool
183 : enqueueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
184 : Handle<AsyncGeneratorRequest*> request);
185 :
186 : static AsyncGeneratorRequest*
187 : dequeueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
188 :
189 : static AsyncGeneratorRequest*
190 : peekRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
191 :
192 0 : bool isQueueEmpty() const {
193 0 : if (isSingleQueue())
194 0 : return isSingleQueueEmpty();
195 0 : return queue()->length() == 0;
196 : }
197 : };
198 :
199 : JSObject*
200 : CreateAsyncFromSyncIterator(JSContext* cx, HandleObject iter);
201 :
202 : class AsyncFromSyncIteratorObject : public NativeObject
203 : {
204 : private:
205 : enum AsyncFromSyncIteratorObjectSlots {
206 : Slot_Iterator = 0,
207 : Slots
208 : };
209 :
210 0 : void setIterator(HandleObject iterator_) {
211 0 : setFixedSlot(Slot_Iterator, ObjectValue(*iterator_));
212 0 : }
213 :
214 : public:
215 : static const Class class_;
216 :
217 : static JSObject*
218 : create(JSContext* cx, HandleObject iter);
219 :
220 0 : JSObject* iterator() const {
221 0 : return &getFixedSlot(Slot_Iterator).toObject();
222 : }
223 : };
224 :
225 : MOZ_MUST_USE bool
226 : AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
227 :
228 : } // namespace js
229 :
230 : #endif /* vm_AsyncIteration_h */
|