LCOV - code coverage report
Current view: directory - js/src - jsiter.h (source / functions) Found Hit Coverage
Test: app.info Lines: 52 52 100.0 %
Date: 2012-06-02 Functions: 13 13 100.0 %

       1                 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=8 sw=4 et tw=78:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1 *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla Communicator client code, released
      17                 :  * March 31, 1998.
      18                 :  *
      19                 :  * The Initial Developer of the Original Code is
      20                 :  * Netscape Communications Corporation.
      21                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      22                 :  * the Initial Developer. All Rights Reserved.
      23                 :  *
      24                 :  * Contributor(s):
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #ifndef jsiter_h___
      41                 : #define jsiter_h___
      42                 : 
      43                 : /*
      44                 :  * JavaScript iterators.
      45                 :  */
      46                 : #include "jscntxt.h"
      47                 : #include "jsprvtd.h"
      48                 : #include "jspubtd.h"
      49                 : #include "jsversion.h"
      50                 : 
      51                 : #include "gc/Barrier.h"
      52                 : #include "vm/Stack.h"
      53                 : 
      54                 : /*
      55                 :  * For cacheable native iterators, whether the iterator is currently active.
      56                 :  * Not serialized by XDR.
      57                 :  */
      58                 : #define JSITER_ACTIVE       0x1000
      59                 : #define JSITER_UNREUSABLE   0x2000
      60                 : 
      61                 : namespace js {
      62                 : 
      63                 : struct NativeIterator {
      64                 :     HeapPtrObject obj;
      65                 :     HeapPtr<JSFlatString> *props_array;
      66                 :     HeapPtr<JSFlatString> *props_cursor;
      67                 :     HeapPtr<JSFlatString> *props_end;
      68                 :     const Shape **shapes_array;
      69                 :     uint32_t  shapes_length;
      70                 :     uint32_t  shapes_key;
      71                 :     uint32_t  flags;
      72                 :     JSObject  *next;  /* Forms cx->enumerators list, garbage otherwise. */
      73                 : 
      74        47768440 :     bool isKeyIter() const { return (flags & JSITER_FOREACH) == 0; }
      75                 : 
      76           17203 :     inline HeapPtr<JSFlatString> *begin() const {
      77           17203 :         return props_array;
      78                 :     }
      79                 : 
      80           28801 :     inline HeapPtr<JSFlatString> *end() const {
      81           28801 :         return props_end;
      82                 :     }
      83                 : 
      84              18 :     size_t numKeys() const {
      85              18 :         return end() - begin();
      86                 :     }
      87                 : 
      88        13498559 :     HeapPtr<JSFlatString> *current() const {
      89        13498559 :         JS_ASSERT(props_cursor < props_end);
      90        13498559 :         return props_cursor;
      91                 :     }
      92                 : 
      93        13494832 :     void incCursor() {
      94        13494832 :         props_cursor = props_cursor + 1;
      95        13494832 :     }
      96                 : 
      97                 :     static NativeIterator *allocateIterator(JSContext *cx, uint32_t slength,
      98                 :                                             const js::AutoIdVector &props);
      99                 :     void init(JSObject *obj, unsigned flags, uint32_t slength, uint32_t key);
     100                 : 
     101                 :     void mark(JSTracer *trc);
     102                 : };
     103                 : 
     104                 : class ElementIteratorObject : public JSObject {
     105                 :   public:
     106                 :     enum {
     107                 :         TargetSlot,
     108                 :         IndexSlot,
     109                 :         NumSlots
     110                 :     };
     111                 : 
     112                 :     static JSObject *create(JSContext *cx, JSObject *target);
     113                 : 
     114                 :     inline uint32_t getIndex() const;
     115                 :     inline void setIndex(uint32_t index);
     116                 :     inline JSObject *getTargetObject() const;
     117                 : 
     118                 :     /*
     119                 :         Array iterators are like this:
     120                 : 
     121                 :         Array.prototype[iterate] = function () {
     122                 :             for (var i = 0; i < (this.length >>> 0); i++) {
     123                 :                 var desc = Object.getOwnPropertyDescriptor(this, i);
     124                 :                 yield desc === undefined ? undefined : this[i];
     125                 :             }
     126                 :         }
     127                 : 
     128                 :         This has the following implications:
     129                 : 
     130                 :           - Array iterators are generic; Array.prototype[iterate] can be transferred to
     131                 :             any other object to create iterators over it.
     132                 : 
     133                 :           - The next() method of an Array iterator is non-reentrant. Trying to reenter,
     134                 :             e.g. by using it on an object with a length getter that calls it.next() on
     135                 :             the same iterator, causes a TypeError.
     136                 : 
     137                 :           - The iterator fetches obj.length every time its next() method is called.
     138                 : 
     139                 :           - The iterator converts obj.length to a whole number using ToUint32. As a
     140                 :             consequence the iterator can't go on forever; it can yield at most 2^32-1
     141                 :             values. Then i will be 0xffffffff, and no possible length value will be
     142                 :             greater than that.
     143                 : 
     144                 :           - The iterator does not skip "array holes". When it encounters a hole, it
     145                 :             yields undefined.
     146                 : 
     147                 :           - The iterator never consults the prototype chain.
     148                 : 
     149                 :           - If an element has a getter which throws, the exception is propagated, and
     150                 :             the iterator is closed (that is, all future calls to next() will simply
     151                 :             throw StopIteration).
     152                 : 
     153                 :         Note that if next() were reentrant, even more details of its inner
     154                 :         workings would be observable.
     155                 :     */
     156                 : 
     157                 :     /*
     158                 :      * If there are any more elements to visit, store the value of the next
     159                 :      * element in *vp, increment the index, and return true. If not, call
     160                 :      * vp->setMagic(JS_NO_ITER_VALUE) and return true. Return false on error.
     161                 :      */
     162                 :     bool iteratorNext(JSContext *cx, Value *vp);
     163                 : };
     164                 : 
     165                 : bool
     166                 : VectorToIdArray(JSContext *cx, js::AutoIdVector &props, JSIdArray **idap);
     167                 : 
     168                 : bool
     169                 : GetIterator(JSContext *cx, JSObject *obj, unsigned flags, js::Value *vp);
     170                 : 
     171                 : bool
     172                 : VectorToKeyIterator(JSContext *cx, JSObject *obj, unsigned flags, js::AutoIdVector &props, js::Value *vp);
     173                 : 
     174                 : bool
     175                 : VectorToValueIterator(JSContext *cx, JSObject *obj, unsigned flags, js::AutoIdVector &props, js::Value *vp);
     176                 : 
     177                 : /*
     178                 :  * Creates either a key or value iterator, depending on flags. For a value
     179                 :  * iterator, performs value-lookup to convert the given list of jsids.
     180                 :  */
     181                 : bool
     182                 : EnumeratedIdVectorToIterator(JSContext *cx, JSObject *obj, unsigned flags, js::AutoIdVector &props, js::Value *vp);
     183                 : 
     184                 : /*
     185                 :  * Convert the value stored in *vp to its iteration object. The flags should
     186                 :  * contain JSITER_ENUMERATE if js::ValueToIterator is called when enumerating
     187                 :  * for-in semantics are required, and when the caller can guarantee that the
     188                 :  * iterator will never be exposed to scripts.
     189                 :  */
     190                 : extern JSBool
     191                 : ValueToIterator(JSContext *cx, unsigned flags, js::Value *vp);
     192                 : 
     193                 : extern bool
     194                 : CloseIterator(JSContext *cx, JSObject *iterObj);
     195                 : 
     196                 : extern bool
     197                 : UnwindIteratorForException(JSContext *cx, JSObject *obj);
     198                 : 
     199                 : extern void
     200                 : UnwindIteratorForUncatchableException(JSContext *cx, JSObject *obj);
     201                 : 
     202                 : }
     203                 : 
     204                 : extern bool
     205                 : js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id);
     206                 : 
     207                 : extern bool
     208                 : js_SuppressDeletedElement(JSContext *cx, JSObject *obj, uint32_t index);
     209                 : 
     210                 : extern bool
     211                 : js_SuppressDeletedElements(JSContext *cx, JSObject *obj, uint32_t begin, uint32_t end);
     212                 : 
     213                 : /*
     214                 :  * IteratorMore() indicates whether another value is available. It might
     215                 :  * internally call iterobj.next() and then cache the value until its
     216                 :  * picked up by IteratorNext(). The value is cached in the current context.
     217                 :  */
     218                 : extern JSBool
     219                 : js_IteratorMore(JSContext *cx, JSObject *iterobj, js::Value *rval);
     220                 : 
     221                 : extern JSBool
     222                 : js_IteratorNext(JSContext *cx, JSObject *iterobj, js::Value *rval);
     223                 : 
     224                 : extern JSBool
     225                 : js_ThrowStopIteration(JSContext *cx);
     226                 : 
     227                 : namespace js {
     228                 : 
     229                 : /*
     230                 :  * Get the next value from an iterator object.
     231                 :  *
     232                 :  * On success, store the next value in *vp and return true; if there are no
     233                 :  * more values, store the magic value JS_NO_ITER_VALUE in *vp and return true.
     234                 :  */
     235                 : inline bool
     236            4203 : Next(JSContext *cx, JSObject *iter, Value *vp)
     237                 : {
     238            4203 :     if (!js_IteratorMore(cx, iter, vp))
     239               9 :         return false;
     240            4194 :     if (vp->toBoolean())
     241            3969 :         return js_IteratorNext(cx, iter, vp);
     242             225 :     vp->setMagic(JS_NO_ITER_VALUE);
     243             225 :     return true;
     244                 : }
     245                 : 
     246                 : /*
     247                 :  * Imitate a for-of loop. This does the equivalent of the JS code:
     248                 :  *
     249                 :  *     for (let v of iterable)
     250                 :  *         op(v);
     251                 :  *
     252                 :  * But the actual signature of op must be:
     253                 :  *     bool op(JSContext *cx, const Value &v);
     254                 :  *
     255                 :  * There is no feature like JS 'break'. op must return false only
     256                 :  * in case of exception or error.
     257                 :  */
     258                 : template <class Op>
     259                 : bool
     260             369 : ForOf(JSContext *cx, const Value &iterable, Op op)
     261                 : {
     262             369 :     Value iterv(iterable);
     263             369 :     if (!ValueToIterator(cx, JSITER_FOR_OF, &iterv))
     264              99 :         return false;
     265             270 :     JSObject *iter = &iterv.toObject();
     266                 : 
     267             270 :     bool ok = true;
     268            4518 :     while (ok) {
     269                 :         Value v;
     270            4203 :         ok = Next(cx, iter, &v);
     271            4203 :         if (ok) {
     272            4194 :             if (v.isMagic(JS_NO_ITER_VALUE))
     273             225 :                 break;
     274            3969 :             ok = op(cx, v);
     275                 :         }
     276                 :     }
     277                 : 
     278             270 :     bool throwing = !ok && cx->isExceptionPending();
     279                 :     Value exc;
     280             270 :     if (throwing) {
     281              45 :         exc = cx->getPendingException();
     282              45 :         cx->clearPendingException();
     283                 :     }
     284             270 :     bool closedOK = CloseIterator(cx, iter);
     285             270 :     if (throwing && closedOK)
     286              45 :         cx->setPendingException(exc);
     287             270 :     return ok && closedOK;
     288                 : }
     289                 : 
     290                 : } /* namespace js */
     291                 : 
     292                 : #if JS_HAS_GENERATORS
     293                 : 
     294                 : /*
     295                 :  * Generator state codes.
     296                 :  */
     297                 : typedef enum JSGeneratorState {
     298                 :     JSGEN_NEWBORN,  /* not yet started */
     299                 :     JSGEN_OPEN,     /* started by a .next() or .send(undefined) call */
     300                 :     JSGEN_RUNNING,  /* currently executing via .next(), etc., call */
     301                 :     JSGEN_CLOSING,  /* close method is doing asynchronous return */
     302                 :     JSGEN_CLOSED    /* closed, cannot be started or closed again */
     303                 : } JSGeneratorState;
     304                 : 
     305                 : struct JSGenerator {
     306                 :     js::HeapPtrObject   obj;
     307                 :     JSGeneratorState    state;
     308                 :     js::FrameRegs       regs;
     309                 :     JSObject            *enumerators;
     310                 :     js::StackFrame      *floating;
     311                 :     js::HeapValue       floatingStack[1];
     312                 : 
     313          214794 :     js::StackFrame *floatingFrame() {
     314          214794 :         return floating;
     315                 :     }
     316                 : 
     317           59987 :     js::StackFrame *liveFrame() {
     318           59987 :         JS_ASSERT((state == JSGEN_RUNNING || state == JSGEN_CLOSING) ==
     319          119974 :                   (regs.fp() != floatingFrame()));
     320           59987 :         return regs.fp();
     321                 :     }
     322                 : };
     323                 : 
     324                 : extern JSObject *
     325                 : js_NewGenerator(JSContext *cx);
     326                 : 
     327                 : /*
     328                 :  * Generator stack frames do not have stable pointers since they get copied to
     329                 :  * and from the generator object and the stack (see SendToGenerator). This is a
     330                 :  * problem for Block and With objects, which need to store a pointer to the
     331                 :  * enclosing stack frame. The solution is for Block and With objects to store
     332                 :  * a pointer to the "floating" stack frame stored in the generator object,
     333                 :  * since it is stable, and maintain, in the generator object, a pointer to the
     334                 :  * "live" stack frame (either a copy on the stack or the floating frame). Thus,
     335                 :  * Block and With objects must "normalize" to and from the floating/live frames
     336                 :  * in the case of generators using the following functions.
     337                 :  */
     338                 : inline js::StackFrame *
     339           87329 : js_FloatingFrameIfGenerator(JSContext *cx, js::StackFrame *fp)
     340                 : {
     341           87329 :     if (JS_UNLIKELY(fp->isGeneratorFrame()))
     342            1175 :         return cx->generatorFor(fp)->floatingFrame();
     343           86154 :     return fp;
     344                 : }
     345                 : 
     346                 : /* Given a floating frame, given the JSGenerator containing it. */
     347                 : extern JSGenerator *
     348                 : js_FloatingFrameToGenerator(js::StackFrame *fp);
     349                 : 
     350                 : inline js::StackFrame *
     351          551063 : js_LiveFrameIfGenerator(js::StackFrame *fp)
     352                 : {
     353          551063 :     return fp->isGeneratorFrame() ? js_FloatingFrameToGenerator(fp)->liveFrame() : fp;
     354                 : }
     355                 : 
     356                 : #endif
     357                 : 
     358                 : extern JSObject *
     359                 : js_InitIteratorClasses(JSContext *cx, JSObject *obj);
     360                 : 
     361                 : #endif /* jsiter_h___ */

Generated by: LCOV version 1.7