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_GeneratorObject_h
8 : #define vm_GeneratorObject_h
9 :
10 : #include "jscntxt.h"
11 : #include "jsobj.h"
12 :
13 : #include "vm/ArgumentsObject.h"
14 : #include "vm/ArrayObject.h"
15 : #include "vm/Stack.h"
16 :
17 : namespace js {
18 :
19 : class GeneratorObject : public NativeObject
20 : {
21 : public:
22 : // Magic values stored in the yield index slot when the generator is
23 : // running or closing. See the yield index comment below.
24 : static const int32_t YIELD_AND_AWAIT_INDEX_RUNNING = INT32_MAX;
25 : static const int32_t YIELD_AND_AWAIT_INDEX_CLOSING = INT32_MAX - 1;
26 :
27 : enum {
28 : CALLEE_SLOT = 0,
29 : ENV_CHAIN_SLOT,
30 : ARGS_OBJ_SLOT,
31 : EXPRESSION_STACK_SLOT,
32 : YIELD_AND_AWAIT_INDEX_SLOT,
33 : NEWTARGET_SLOT,
34 : RESERVED_SLOTS
35 : };
36 :
37 : enum ResumeKind { NEXT, THROW, CLOSE };
38 :
39 : private:
40 : static bool suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc,
41 : Value* vp, unsigned nvalues);
42 :
43 : public:
44 202 : static inline ResumeKind getResumeKind(jsbytecode* pc) {
45 202 : MOZ_ASSERT(*pc == JSOP_RESUME);
46 202 : unsigned arg = GET_UINT16(pc);
47 202 : MOZ_ASSERT(arg <= CLOSE);
48 202 : return static_cast<ResumeKind>(arg);
49 : }
50 :
51 27 : static inline ResumeKind getResumeKind(JSContext* cx, JSAtom* atom) {
52 27 : if (atom == cx->names().next)
53 9 : return NEXT;
54 18 : if (atom == cx->names().throw_)
55 9 : return THROW;
56 9 : MOZ_ASSERT(atom == cx->names().close);
57 9 : return CLOSE;
58 : }
59 :
60 : static JSObject* create(JSContext* cx, AbstractFramePtr frame);
61 :
62 : static bool resume(JSContext* cx, InterpreterActivation& activation,
63 : HandleObject obj, HandleValue arg, ResumeKind resumeKind);
64 :
65 72 : static bool initialSuspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc) {
66 72 : return suspend(cx, obj, frame, pc, nullptr, 0);
67 : }
68 :
69 568 : static bool normalSuspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc,
70 : Value* vp, unsigned nvalues) {
71 568 : return suspend(cx, obj, frame, pc, vp, nvalues);
72 : }
73 :
74 : static bool finalSuspend(JSContext* cx, HandleObject obj);
75 :
76 837 : JSFunction& callee() const {
77 837 : return getFixedSlot(CALLEE_SLOT).toObject().as<JSFunction>();
78 : }
79 136 : void setCallee(JSFunction& callee) {
80 136 : setFixedSlot(CALLEE_SLOT, ObjectValue(callee));
81 136 : }
82 :
83 198 : JSObject& environmentChain() const {
84 198 : return getFixedSlot(ENV_CHAIN_SLOT).toObject();
85 : }
86 776 : void setEnvironmentChain(JSObject& envChain) {
87 776 : setFixedSlot(ENV_CHAIN_SLOT, ObjectValue(envChain));
88 776 : }
89 :
90 198 : bool hasArgsObj() const {
91 198 : return getFixedSlot(ARGS_OBJ_SLOT).isObject();
92 : }
93 0 : ArgumentsObject& argsObj() const {
94 0 : return getFixedSlot(ARGS_OBJ_SLOT).toObject().as<ArgumentsObject>();
95 : }
96 0 : void setArgsObj(ArgumentsObject& argsObj) {
97 0 : setFixedSlot(ARGS_OBJ_SLOT, ObjectValue(argsObj));
98 0 : }
99 :
100 838 : bool hasExpressionStack() const {
101 838 : return getFixedSlot(EXPRESSION_STACK_SLOT).isObject();
102 : }
103 176 : ArrayObject& expressionStack() const {
104 176 : return getFixedSlot(EXPRESSION_STACK_SLOT).toObject().as<ArrayObject>();
105 : }
106 513 : void setExpressionStack(ArrayObject& expressionStack) {
107 513 : setFixedSlot(EXPRESSION_STACK_SLOT, ObjectValue(expressionStack));
108 513 : }
109 224 : void clearExpressionStack() {
110 224 : setFixedSlot(EXPRESSION_STACK_SLOT, NullValue());
111 224 : }
112 :
113 : bool isConstructing() const {
114 : return getFixedSlot(NEWTARGET_SLOT).isObject();
115 : }
116 198 : const Value& newTarget() const {
117 198 : return getFixedSlot(NEWTARGET_SLOT);
118 : }
119 136 : void setNewTarget(const Value& newTarget) {
120 136 : setFixedSlot(NEWTARGET_SLOT, newTarget);
121 136 : }
122 :
123 :
124 : // The yield index slot is abused for a few purposes. It's undefined if
125 : // it hasn't been set yet (before the initial yield), and null if the
126 : // generator is closed. If the generator is running, the yield index is
127 : // YIELD_AND_AWAIT_INDEX_RUNNING. If the generator is in that bizarre
128 : // "closing" state, the yield index is YIELD_AND_AWAIT_INDEX_CLOSING.
129 : //
130 : // If the generator is suspended, it's the yield index (stored as
131 : // JSOP_INITIALYIELD/JSOP_YIELD/JSOP_AWAIT operand) of the yield
132 : // instruction that suspended the generator. The yield index can be mapped
133 : // to the bytecode offset (interpreter) or to the native code offset (JIT).
134 :
135 756 : bool isRunning() const {
136 756 : MOZ_ASSERT(!isClosed());
137 756 : return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() == YIELD_AND_AWAIT_INDEX_RUNNING;
138 : }
139 685 : bool isClosing() const {
140 685 : return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() == YIELD_AND_AWAIT_INDEX_CLOSING;
141 : }
142 1431 : bool isSuspended() const {
143 : // Note: also update Baseline's IsSuspendedStarGenerator code if this
144 : // changes.
145 1431 : MOZ_ASSERT(!isClosed());
146 : static_assert(YIELD_AND_AWAIT_INDEX_CLOSING < YIELD_AND_AWAIT_INDEX_RUNNING,
147 : "test below should return false for YIELD_AND_AWAIT_INDEX_RUNNING");
148 1431 : return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() < YIELD_AND_AWAIT_INDEX_CLOSING;
149 : }
150 198 : void setRunning() {
151 198 : MOZ_ASSERT(isSuspended());
152 198 : setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(YIELD_AND_AWAIT_INDEX_RUNNING));
153 198 : }
154 0 : void setClosing() {
155 0 : MOZ_ASSERT(isSuspended());
156 0 : setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(YIELD_AND_AWAIT_INDEX_CLOSING));
157 0 : }
158 640 : void setYieldAndAwaitIndex(uint32_t yieldAndAwaitIndex) {
159 640 : MOZ_ASSERT_IF(yieldAndAwaitIndex == 0,
160 : getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).isUndefined());
161 640 : MOZ_ASSERT_IF(yieldAndAwaitIndex != 0, isRunning() || isClosing());
162 640 : MOZ_ASSERT(yieldAndAwaitIndex < uint32_t(YIELD_AND_AWAIT_INDEX_CLOSING));
163 640 : setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(yieldAndAwaitIndex));
164 640 : MOZ_ASSERT(isSuspended());
165 640 : }
166 269 : uint32_t yieldAndAwaitIndex() const {
167 269 : MOZ_ASSERT(isSuspended());
168 269 : return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32();
169 : }
170 2417 : bool isClosed() const {
171 2417 : return getFixedSlot(CALLEE_SLOT).isNull();
172 : }
173 117 : void setClosed() {
174 117 : setFixedSlot(CALLEE_SLOT, NullValue());
175 117 : setFixedSlot(ENV_CHAIN_SLOT, NullValue());
176 117 : setFixedSlot(ARGS_OBJ_SLOT, NullValue());
177 117 : setFixedSlot(EXPRESSION_STACK_SLOT, NullValue());
178 117 : setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, NullValue());
179 117 : setFixedSlot(NEWTARGET_SLOT, NullValue());
180 117 : }
181 :
182 : bool isAfterYield();
183 : bool isAfterAwait();
184 :
185 : private:
186 : bool isAfterYieldOrAwait(JSOp op);
187 :
188 : public:
189 4 : static size_t offsetOfCalleeSlot() {
190 4 : return getFixedSlotOffset(CALLEE_SLOT);
191 : }
192 12 : static size_t offsetOfEnvironmentChainSlot() {
193 12 : return getFixedSlotOffset(ENV_CHAIN_SLOT);
194 : }
195 4 : static size_t offsetOfArgsObjSlot() {
196 4 : return getFixedSlotOffset(ARGS_OBJ_SLOT);
197 : }
198 20 : static size_t offsetOfYieldAndAwaitIndexSlot() {
199 20 : return getFixedSlotOffset(YIELD_AND_AWAIT_INDEX_SLOT);
200 : }
201 4 : static size_t offsetOfExpressionStackSlot() {
202 4 : return getFixedSlotOffset(EXPRESSION_STACK_SLOT);
203 : }
204 4 : static size_t offsetOfNewTargetSlot() {
205 4 : return getFixedSlotOffset(NEWTARGET_SLOT);
206 : }
207 : };
208 :
209 : class LegacyGeneratorObject : public GeneratorObject
210 : {
211 : public:
212 : static const Class class_;
213 :
214 : static bool close(JSContext* cx, HandleObject obj);
215 : };
216 :
217 : class StarGeneratorObject : public GeneratorObject
218 : {
219 : public:
220 : static const Class class_;
221 : };
222 :
223 : bool GeneratorThrowOrClose(JSContext* cx, AbstractFramePtr frame, Handle<GeneratorObject*> obj,
224 : HandleValue val, uint32_t resumeKind);
225 : void SetReturnValueForClosingGenerator(JSContext* cx, AbstractFramePtr frame);
226 :
227 : MOZ_MUST_USE bool
228 : CheckStarGeneratorResumptionValue(JSContext* cx, HandleValue v);
229 :
230 : } // namespace js
231 :
232 : template<>
233 : inline bool
234 1271 : JSObject::is<js::GeneratorObject>() const
235 : {
236 1271 : return is<js::LegacyGeneratorObject>() || is<js::StarGeneratorObject>();
237 : }
238 :
239 : #endif /* vm_GeneratorObject_h */
|