LCOV - code coverage report
Current view: top level - js/src/vm - GeneratorObject.h (source / functions) Hit Total Coverage
Test: output.info Lines: 89 98 90.8 %
Date: 2017-07-14 16:53:18 Functions: 30 33 90.9 %
Legend: Lines: hit not hit

          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 */

Generated by: LCOV version 1.13