LCOV - app.info - js/src/jsiter.h

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-07-07 | 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        47768679 :     bool isKeyIter() const { return (flags & JSITER_FOREACH) == 0; }
          75                 :
          76           17191 :     inline HeapPtr<JSFlatString> *begin() const {
          77           17191 :         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        13498600 :     HeapPtr<JSFlatString> *current() const {
          89        13498600 :         JS_ASSERT(props_cursor < props_end);
          90        13498600 :         return props_cursor;
          91                 :     }
          92                 :
          93        13494873 :     void incCursor() {
          94        13494873 :         props_cursor = props_cursor + 1;
          95        13494873 :     }
          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          216550 :     js::StackFrame *floatingFrame() {
         314          216550 :         return floating;
         315                 :     }
         316                 :
         317           60494 :     js::StackFrame *liveFrame() {
         318           60494 :         JS_ASSERT((state == JSGEN_RUNNING || state == JSGEN_CLOSING) ==
         319          120988 :                   (regs.fp() != floatingFrame()));
         320           60494 :         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           87323 : js_FloatingFrameIfGenerator(JSContext *cx, js::StackFrame *fp)
         340                 : {
         341           87323 :     if (JS_UNLIKELY(fp->isGeneratorFrame()))
         342            1175 :         return cx->generatorFor(fp)->floatingFrame();
         343           86148 :     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          551053 : js_LiveFrameIfGenerator(js::StackFrame *fp)
         352                 : {
         353          551053 :     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