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_INDEX_RUNNING = INT32_MAX; 25 static const int32_t YIELD_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_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: getResumeKind(jsbytecode * pc)44 static inline ResumeKind getResumeKind(jsbytecode* pc) { 45 MOZ_ASSERT(*pc == JSOP_RESUME); 46 unsigned arg = GET_UINT16(pc); 47 MOZ_ASSERT(arg <= CLOSE); 48 return static_cast<ResumeKind>(arg); 49 } 50 getResumeKind(ExclusiveContext * cx,JSAtom * atom)51 static inline ResumeKind getResumeKind(ExclusiveContext* cx, JSAtom* atom) { 52 if (atom == cx->names().next) 53 return NEXT; 54 if (atom == cx->names().throw_) 55 return THROW; 56 MOZ_ASSERT(atom == cx->names().close); 57 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 initialSuspend(JSContext * cx,HandleObject obj,AbstractFramePtr frame,jsbytecode * pc)65 static bool initialSuspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc) { 66 return suspend(cx, obj, frame, pc, nullptr, 0); 67 } 68 normalSuspend(JSContext * cx,HandleObject obj,AbstractFramePtr frame,jsbytecode * pc,Value * vp,unsigned nvalues)69 static bool normalSuspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc, 70 Value* vp, unsigned nvalues) { 71 return suspend(cx, obj, frame, pc, vp, nvalues); 72 } 73 74 static bool finalSuspend(JSContext* cx, HandleObject obj); 75 callee()76 JSFunction& callee() const { 77 return getFixedSlot(CALLEE_SLOT).toObject().as<JSFunction>(); 78 } setCallee(JSFunction & callee)79 void setCallee(JSFunction& callee) { 80 setFixedSlot(CALLEE_SLOT, ObjectValue(callee)); 81 } 82 environmentChain()83 JSObject& environmentChain() const { 84 return getFixedSlot(ENV_CHAIN_SLOT).toObject(); 85 } setEnvironmentChain(JSObject & envChain)86 void setEnvironmentChain(JSObject& envChain) { 87 setFixedSlot(ENV_CHAIN_SLOT, ObjectValue(envChain)); 88 } 89 hasArgsObj()90 bool hasArgsObj() const { 91 return getFixedSlot(ARGS_OBJ_SLOT).isObject(); 92 } argsObj()93 ArgumentsObject& argsObj() const { 94 return getFixedSlot(ARGS_OBJ_SLOT).toObject().as<ArgumentsObject>(); 95 } setArgsObj(ArgumentsObject & argsObj)96 void setArgsObj(ArgumentsObject& argsObj) { 97 setFixedSlot(ARGS_OBJ_SLOT, ObjectValue(argsObj)); 98 } 99 hasExpressionStack()100 bool hasExpressionStack() const { 101 return getFixedSlot(EXPRESSION_STACK_SLOT).isObject(); 102 } expressionStack()103 ArrayObject& expressionStack() const { 104 return getFixedSlot(EXPRESSION_STACK_SLOT).toObject().as<ArrayObject>(); 105 } setExpressionStack(ArrayObject & expressionStack)106 void setExpressionStack(ArrayObject& expressionStack) { 107 setFixedSlot(EXPRESSION_STACK_SLOT, ObjectValue(expressionStack)); 108 } clearExpressionStack()109 void clearExpressionStack() { 110 setFixedSlot(EXPRESSION_STACK_SLOT, NullValue()); 111 } 112 isConstructing()113 bool isConstructing() const { 114 return getFixedSlot(NEWTARGET_SLOT).isObject(); 115 } newTarget()116 const Value& newTarget() const { 117 return getFixedSlot(NEWTARGET_SLOT); 118 } setNewTarget(const Value & newTarget)119 void setNewTarget(const Value& newTarget) { 120 setFixedSlot(NEWTARGET_SLOT, newTarget); 121 } 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_INDEX_RUNNING. If the generator is in that bizarre "closing" 128 // state, the yield index is YIELD_INDEX_CLOSING. 129 // 130 // If the generator is suspended, it's the yield index (stored as 131 // JSOP_INITIALYIELD/JSOP_YIELD operand) of the yield instruction that 132 // suspended the generator. The yield index can be mapped to the bytecode 133 // offset (interpreter) or to the native code offset (JIT). 134 isRunning()135 bool isRunning() const { 136 MOZ_ASSERT(!isClosed()); 137 return getFixedSlot(YIELD_INDEX_SLOT).toInt32() == YIELD_INDEX_RUNNING; 138 } isClosing()139 bool isClosing() const { 140 return getFixedSlot(YIELD_INDEX_SLOT).toInt32() == YIELD_INDEX_CLOSING; 141 } isSuspended()142 bool isSuspended() const { 143 // Note: also update Baseline's IsSuspendedStarGenerator code if this 144 // changes. 145 MOZ_ASSERT(!isClosed()); 146 static_assert(YIELD_INDEX_CLOSING < YIELD_INDEX_RUNNING, 147 "test below should return false for YIELD_INDEX_RUNNING"); 148 return getFixedSlot(YIELD_INDEX_SLOT).toInt32() < YIELD_INDEX_CLOSING; 149 } setRunning()150 void setRunning() { 151 MOZ_ASSERT(isSuspended()); 152 setFixedSlot(YIELD_INDEX_SLOT, Int32Value(YIELD_INDEX_RUNNING)); 153 } setClosing()154 void setClosing() { 155 MOZ_ASSERT(isSuspended()); 156 setFixedSlot(YIELD_INDEX_SLOT, Int32Value(YIELD_INDEX_CLOSING)); 157 } setYieldIndex(uint32_t yieldIndex)158 void setYieldIndex(uint32_t yieldIndex) { 159 MOZ_ASSERT_IF(yieldIndex == 0, getFixedSlot(YIELD_INDEX_SLOT).isUndefined()); 160 MOZ_ASSERT_IF(yieldIndex != 0, isRunning() || isClosing()); 161 MOZ_ASSERT(yieldIndex < uint32_t(YIELD_INDEX_CLOSING)); 162 setFixedSlot(YIELD_INDEX_SLOT, Int32Value(yieldIndex)); 163 MOZ_ASSERT(isSuspended()); 164 } yieldIndex()165 uint32_t yieldIndex() const { 166 MOZ_ASSERT(isSuspended()); 167 return getFixedSlot(YIELD_INDEX_SLOT).toInt32(); 168 } isClosed()169 bool isClosed() const { 170 return getFixedSlot(CALLEE_SLOT).isNull(); 171 } setClosed()172 void setClosed() { 173 setFixedSlot(CALLEE_SLOT, NullValue()); 174 setFixedSlot(ENV_CHAIN_SLOT, NullValue()); 175 setFixedSlot(ARGS_OBJ_SLOT, NullValue()); 176 setFixedSlot(EXPRESSION_STACK_SLOT, NullValue()); 177 setFixedSlot(YIELD_INDEX_SLOT, NullValue()); 178 setFixedSlot(NEWTARGET_SLOT, NullValue()); 179 } 180 offsetOfCalleeSlot()181 static size_t offsetOfCalleeSlot() { 182 return getFixedSlotOffset(CALLEE_SLOT); 183 } offsetOfEnvironmentChainSlot()184 static size_t offsetOfEnvironmentChainSlot() { 185 return getFixedSlotOffset(ENV_CHAIN_SLOT); 186 } offsetOfArgsObjSlot()187 static size_t offsetOfArgsObjSlot() { 188 return getFixedSlotOffset(ARGS_OBJ_SLOT); 189 } offsetOfYieldIndexSlot()190 static size_t offsetOfYieldIndexSlot() { 191 return getFixedSlotOffset(YIELD_INDEX_SLOT); 192 } offsetOfExpressionStackSlot()193 static size_t offsetOfExpressionStackSlot() { 194 return getFixedSlotOffset(EXPRESSION_STACK_SLOT); 195 } offsetOfNewTargetSlot()196 static size_t offsetOfNewTargetSlot() { 197 return getFixedSlotOffset(NEWTARGET_SLOT); 198 } 199 }; 200 201 class LegacyGeneratorObject : public GeneratorObject 202 { 203 public: 204 static const Class class_; 205 206 static bool close(JSContext* cx, HandleObject obj); 207 }; 208 209 class StarGeneratorObject : public GeneratorObject 210 { 211 public: 212 static const Class class_; 213 }; 214 215 bool GeneratorThrowOrClose(JSContext* cx, AbstractFramePtr frame, Handle<GeneratorObject*> obj, 216 HandleValue val, uint32_t resumeKind); 217 void SetReturnValueForClosingGenerator(JSContext* cx, AbstractFramePtr frame); 218 219 MOZ_MUST_USE bool 220 CheckStarGeneratorResumptionValue(JSContext* cx, HandleValue v); 221 222 } // namespace js 223 224 template<> 225 inline bool 226 JSObject::is<js::GeneratorObject>() const 227 { 228 return is<js::LegacyGeneratorObject>() || is<js::StarGeneratorObject>(); 229 } 230 231 #endif /* vm_GeneratorObject_h */ 232