Bug 1842773 - Part 32: Allow constructing growable SharedArrayBuffers. r=sfink
[gecko.git] / js / src / vm / GeneratorObject.h
blobddc11ba781ed8debd62fcd2aaa40b274915e9c8d
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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/. */
7 #ifndef vm_GeneratorObject_h
8 #define vm_GeneratorObject_h
10 #include "js/Class.h"
11 #include "vm/ArgumentsObject.h"
12 #include "vm/ArrayObject.h"
13 #include "vm/BytecodeUtil.h"
14 #include "vm/GeneratorResumeKind.h" // GeneratorResumeKind
15 #include "vm/JSObject.h"
16 #include "vm/Stack.h"
18 namespace js {
20 class InterpreterActivation;
22 namespace frontend {
23 class TaggedParserAtomIndex;
26 extern const JSClass GeneratorFunctionClass;
28 class AbstractGeneratorObject : public NativeObject {
29 public:
30 // Magic value stored in the resumeIndex slot when the generator is
31 // running or closing. See the resumeIndex comment below.
32 static const int32_t RESUME_INDEX_RUNNING = INT32_MAX;
34 enum {
35 CALLEE_SLOT = 0,
36 ENV_CHAIN_SLOT,
37 ARGS_OBJ_SLOT,
38 STACK_STORAGE_SLOT,
39 RESUME_INDEX_SLOT,
40 RESERVED_SLOTS
43 private:
44 static JSObject* createModuleGenerator(JSContext* cx, AbstractFramePtr frame);
46 public:
47 static JSObject* createFromFrame(JSContext* cx, AbstractFramePtr frame);
48 static AbstractGeneratorObject* create(JSContext* cx, HandleFunction callee,
49 HandleScript script,
50 HandleObject environmentChain,
51 Handle<ArgumentsObject*> argsObject);
53 static bool resume(JSContext* cx, InterpreterActivation& activation,
54 Handle<AbstractGeneratorObject*> genObj, HandleValue arg,
55 HandleValue resumeKind);
57 static bool suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame,
58 const jsbytecode* pc, unsigned nvalues);
60 static void finalSuspend(HandleObject obj);
62 JSFunction& callee() const {
63 return getFixedSlot(CALLEE_SLOT).toObject().as<JSFunction>();
65 void setCallee(JSFunction& callee) {
66 setFixedSlot(CALLEE_SLOT, ObjectValue(callee));
69 JSObject& environmentChain() const {
70 return getFixedSlot(ENV_CHAIN_SLOT).toObject();
72 void setEnvironmentChain(JSObject& envChain) {
73 setFixedSlot(ENV_CHAIN_SLOT, ObjectValue(envChain));
76 bool hasArgsObj() const { return getFixedSlot(ARGS_OBJ_SLOT).isObject(); }
77 ArgumentsObject& argsObj() const {
78 return getFixedSlot(ARGS_OBJ_SLOT).toObject().as<ArgumentsObject>();
80 void setArgsObj(ArgumentsObject& argsObj) {
81 setFixedSlot(ARGS_OBJ_SLOT, ObjectValue(argsObj));
84 bool hasStackStorage() const {
85 return getFixedSlot(STACK_STORAGE_SLOT).isObject();
87 bool isStackStorageEmpty() const {
88 return stackStorage().getDenseInitializedLength() == 0;
90 ArrayObject& stackStorage() const {
91 return getFixedSlot(STACK_STORAGE_SLOT).toObject().as<ArrayObject>();
93 void setStackStorage(ArrayObject& stackStorage) {
94 setFixedSlot(STACK_STORAGE_SLOT, ObjectValue(stackStorage));
97 // Access stack storage. Requires `hasStackStorage() && isSuspended()`.
98 // `slot` is the index of the desired local in the stack frame when this
99 // generator is *not* suspended.
100 const Value& getUnaliasedLocal(uint32_t slot) const;
101 void setUnaliasedLocal(uint32_t slot, const Value& value);
103 // The resumeIndex slot is abused for a few purposes. It's undefined if
104 // it hasn't been set yet (before the initial yield), and null if the
105 // generator is closed. If the generator is running, the resumeIndex is
106 // RESUME_INDEX_RUNNING.
108 // If the generator is suspended, it's the resumeIndex (stored as
109 // JSOp::InitialYield/JSOp::Yield/JSOp::Await operand) of the yield
110 // instruction that suspended the generator. The resumeIndex can be mapped to
111 // the bytecode offset (interpreter) or to the native code offset (JIT).
113 bool isBeforeInitialYield() const {
114 return getFixedSlot(RESUME_INDEX_SLOT).isUndefined();
116 bool isRunning() const {
117 return getFixedSlot(RESUME_INDEX_SLOT) == Int32Value(RESUME_INDEX_RUNNING);
119 bool isSuspended() const {
120 // Note: also update Baseline's IsSuspendedGenerator code if this
121 // changes.
122 Value resumeIndex = getFixedSlot(RESUME_INDEX_SLOT);
123 return resumeIndex.isInt32() &&
124 resumeIndex.toInt32() < RESUME_INDEX_RUNNING;
126 void setRunning() {
127 MOZ_ASSERT(isSuspended());
128 setFixedSlot(RESUME_INDEX_SLOT, Int32Value(RESUME_INDEX_RUNNING));
130 void setResumeIndex(const jsbytecode* pc) {
131 MOZ_ASSERT(JSOp(*pc) == JSOp::InitialYield || JSOp(*pc) == JSOp::Yield ||
132 JSOp(*pc) == JSOp::Await);
134 MOZ_ASSERT_IF(JSOp(*pc) == JSOp::InitialYield,
135 getFixedSlot(RESUME_INDEX_SLOT).isUndefined());
136 MOZ_ASSERT_IF(JSOp(*pc) != JSOp::InitialYield, isRunning());
138 uint32_t resumeIndex = GET_UINT24(pc);
139 MOZ_ASSERT(resumeIndex < uint32_t(RESUME_INDEX_RUNNING));
141 setFixedSlot(RESUME_INDEX_SLOT, Int32Value(resumeIndex));
142 MOZ_ASSERT(isSuspended());
144 void setResumeIndex(int32_t resumeIndex) {
145 setFixedSlot(RESUME_INDEX_SLOT, Int32Value(resumeIndex));
147 uint32_t resumeIndex() const {
148 MOZ_ASSERT(isSuspended());
149 return getFixedSlot(RESUME_INDEX_SLOT).toInt32();
151 bool isClosed() const { return getFixedSlot(CALLEE_SLOT).isNull(); }
152 void setClosed() {
153 setFixedSlot(CALLEE_SLOT, NullValue());
154 setFixedSlot(ENV_CHAIN_SLOT, NullValue());
155 setFixedSlot(ARGS_OBJ_SLOT, NullValue());
156 setFixedSlot(STACK_STORAGE_SLOT, NullValue());
157 setFixedSlot(RESUME_INDEX_SLOT, NullValue());
160 bool isAfterYield();
161 bool isAfterAwait();
163 private:
164 bool isAfterYieldOrAwait(JSOp op);
166 public:
167 void trace(JSTracer* trc);
169 static size_t offsetOfCalleeSlot() { return getFixedSlotOffset(CALLEE_SLOT); }
170 static size_t offsetOfEnvironmentChainSlot() {
171 return getFixedSlotOffset(ENV_CHAIN_SLOT);
173 static size_t offsetOfArgsObjSlot() {
174 return getFixedSlotOffset(ARGS_OBJ_SLOT);
176 static size_t offsetOfResumeIndexSlot() {
177 return getFixedSlotOffset(RESUME_INDEX_SLOT);
179 static size_t offsetOfStackStorageSlot() {
180 return getFixedSlotOffset(STACK_STORAGE_SLOT);
183 static size_t calleeSlot() { return CALLEE_SLOT; }
184 static size_t envChainSlot() { return ENV_CHAIN_SLOT; }
185 static size_t argsObjectSlot() { return ARGS_OBJ_SLOT; }
186 static size_t stackStorageSlot() { return STACK_STORAGE_SLOT; }
187 static size_t resumeIndexSlot() { return RESUME_INDEX_SLOT; }
189 #ifdef DEBUG
190 void dump() const;
191 #endif
194 class GeneratorObject : public AbstractGeneratorObject {
195 public:
196 enum { RESERVED_SLOTS = AbstractGeneratorObject::RESERVED_SLOTS };
198 static const JSClass class_;
199 static const JSClassOps classOps_;
201 static GeneratorObject* create(JSContext* cx, HandleFunction fun);
204 bool GeneratorThrowOrReturn(JSContext* cx, AbstractFramePtr frame,
205 Handle<AbstractGeneratorObject*> obj,
206 HandleValue val, GeneratorResumeKind resumeKind);
209 * Return the generator object associated with the given frame. The frame must
210 * be a call frame for a generator.
212 * This may return nullptr at certain points in the generator lifecycle:
214 * - While a generator call evaluates default argument values and performs
215 * destructuring, which occurs before the generator object is created.
217 * - Between the `Generator` instruction and the `SetAliasedVar .generator`
218 * instruction, at which point the generator object does exist, but is held
219 * only on the stack, and not the `.generator` pseudo-variable this function
220 * consults.
222 AbstractGeneratorObject* GetGeneratorObjectForFrame(JSContext* cx,
223 AbstractFramePtr frame);
226 * If `env` or any enclosing environment is a `CallObject` associated with a
227 * generator object, return the generator.
229 * Otherwise `env` is not in a generator or async function, or the generator
230 * object hasn't been created yet; return nullptr with no pending exception.
232 AbstractGeneratorObject* GetGeneratorObjectForEnvironment(JSContext* cx,
233 HandleObject env);
235 GeneratorResumeKind ParserAtomToResumeKind(
236 frontend::TaggedParserAtomIndex atom);
237 JSAtom* ResumeKindToAtom(JSContext* cx, GeneratorResumeKind kind);
239 } // namespace js
241 template <>
242 bool JSObject::is<js::AbstractGeneratorObject>() const;
244 #endif /* vm_GeneratorObject_h */