/[jscoverage]/trunk/js/jsiter.cpp
ViewVC logotype

Diff of /trunk/js/jsiter.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 506 by siliconforks, Sat Sep 26 23:15:22 2009 UTC revision 507 by siliconforks, Sun Jan 10 07:23:34 2010 UTC
# Line 1  Line 1 
1  /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-  /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2   * vim: set ts=8 sw=4 et tw=78:   * vim: set ts=8 sw=4 et tw=78:
3   *   *
4   * ***** BEGIN LICENSE BLOCK *****   * ***** BEGIN LICENSE BLOCK *****
# Line 41  Line 41 
41  /*  /*
42   * JavaScript iterators.   * JavaScript iterators.
43   */   */
 #include "jsstddef.h"  
44  #include <string.h>     /* for memcpy */  #include <string.h>     /* for memcpy */
45  #include "jstypes.h"  #include "jstypes.h"
46    #include "jsstdint.h"
47  #include "jsutil.h"  #include "jsutil.h"
48  #include "jsarena.h"  #include "jsarena.h"
49  #include "jsapi.h"  #include "jsapi.h"
50  #include "jsarray.h"  #include "jsarray.h"
51  #include "jsatom.h"  #include "jsatom.h"
52  #include "jsbool.h"  #include "jsbool.h"
53    #include "jsbuiltins.h"
54  #include "jscntxt.h"  #include "jscntxt.h"
55  #include "jsversion.h"  #include "jsversion.h"
56  #include "jsexn.h"  #include "jsexn.h"
# Line 71  Line 72 
72  #include "jsxml.h"  #include "jsxml.h"
73  #endif  #endif
74    
75  #if JSSLOT_ITER_FLAGS >= JS_INITIAL_NSLOTS  JS_STATIC_ASSERT(JSSLOT_ITER_FLAGS < JS_INITIAL_NSLOTS);
 #error JS_INITIAL_NSLOTS must be greater than JSSLOT_ITER_FLAGS.  
 #endif  
76    
77  #if JS_HAS_GENERATORS  #if JS_HAS_GENERATORS
78    
# Line 100  Line 99 
99          return;          return;
100    
101      /* Protect against failure to fully initialize obj. */      /* Protect against failure to fully initialize obj. */
102      iterable = STOBJ_GET_PARENT(iterobj);      iterable = iterobj->getParent();
103      if (iterable) {      if (iterable) {
104  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
105          uintN flags = JSVAL_TO_INT(STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_FLAGS));          uintN flags = JSVAL_TO_INT(STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_FLAGS));
# Line 109  Line 108 
108                                    NULL, NULL);                                    NULL, NULL);
109          } else          } else
110  #endif  #endif
111              OBJ_ENUMERATE(cx, iterable, JSENUMERATE_DESTROY, &state, NULL);              iterable->enumerate(cx, JSENUMERATE_DESTROY, &state, NULL);
112      }      }
113      STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, JSVAL_NULL);      STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, JSVAL_NULL);
114  }  }
115    
116    static void
117    iterator_trace(JSTracer *trc, JSObject *obj)
118    {
119        /*
120         * The GC marks iter_state during the normal slot scanning if
121         * JSVAL_IS_TRACEABLE(iter_state) is true duplicating the efforts of
122         * js_MarkEnumeratorState. But this is rare so we optimize for code
123         * simplicity.
124         */
125        JSObject *iterable = obj->getParent();
126        if (!iterable) {
127            /* for (x in null) creates an iterator object with a null parent. */
128            return;
129        }
130        jsval iter_state = obj->fslots[JSSLOT_ITER_STATE];
131        js_MarkEnumeratorState(trc, iterable, iter_state);
132    }
133    
134  JSClass js_IteratorClass = {  JSClass js_IteratorClass = {
135      "Iterator",      "Iterator",
136      JSCLASS_HAS_RESERVED_SLOTS(2) | /* slots for state and flags */      JSCLASS_HAS_RESERVED_SLOTS(2) | /* slots for state and flags */
137      JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator),      JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator) |
138        JSCLASS_MARK_IS_TRACE,
139      JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,      JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,
140      JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   JS_FinalizeStub,      JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   NULL,
141      JSCLASS_NO_OPTIONAL_MEMBERS      NULL,             NULL,            NULL,            NULL,
142        NULL,             NULL,            JS_CLASS_TRACE(iterator_trace), NULL
143  };  };
144    
145  static JSBool  static JSBool
# Line 146  Line 165 
165           ? js_EnumerateXMLValues(cx, obj, JSENUMERATE_INIT, &state, NULL, NULL)           ? js_EnumerateXMLValues(cx, obj, JSENUMERATE_INIT, &state, NULL, NULL)
166           :           :
167  #endif  #endif
168             OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &state, NULL);             obj->enumerate(cx, JSENUMERATE_INIT, &state, NULL);
169      if (!ok)      if (!ok)
170          return JS_FALSE;          return JS_FALSE;
171    
# Line 236  Line 255 
255                                   &id, rval)                                   &id, rval)
256           :           :
257  #endif  #endif
258             OBJ_ENUMERATE(cx, iterable, JSENUMERATE_NEXT, &state, &id);             iterable->enumerate(cx, JSENUMERATE_NEXT, &state, &id);
259      if (!ok)      if (!ok)
260          return JS_FALSE;          return JS_FALSE;
261    
# Line 247  Line 266 
266      if (foreach) {      if (foreach) {
267  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
268          if (!OBJECT_IS_XML(cx, iterable) &&          if (!OBJECT_IS_XML(cx, iterable) &&
269              !OBJ_GET_PROPERTY(cx, iterable, id, rval)) {              !iterable->getProperty(cx, id, rval)) {
270              return JS_FALSE;              return JS_FALSE;
271          }          }
272  #endif  #endif
# Line 387  Line 406 
406               * we use the parent slot to keep track of the iterable, we must               * we use the parent slot to keep track of the iterable, we must
407               * fix it up after.               * fix it up after.
408               */               */
409              iterobj = js_NewObject(cx, &js_IteratorClass, NULL, NULL, 0);              iterobj = js_NewObject(cx, &js_IteratorClass, NULL, NULL);
410              if (!iterobj)              if (!iterobj)
411                  goto bad;                  goto bad;
412    
# Line 443  Line 462 
462  #endif  #endif
463      return JS_TRUE;      return JS_TRUE;
464  }  }
465    JS_DEFINE_CALLINFO_2(FRIEND, BOOL, js_CloseIterator, CONTEXT, JSVAL, 0, 0)
466    
467  static JSBool  static JSBool
468  CallEnumeratorNext(JSContext *cx, JSObject *iterobj, uintN flags, jsval *rval)  CallEnumeratorNext(JSContext *cx, JSObject *iterobj, uintN flags, jsval *rval)
# Line 480  Line 500 
500                  return JS_FALSE;                  return JS_FALSE;
501              }              }
502          } else {          } else {
503              if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &state, &id))              if (!obj->enumerate(cx, JSENUMERATE_NEXT, &state, &id))
504                  return JS_FALSE;                  return JS_FALSE;
505          }          }
506          STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, state);          STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, state);
# Line 490  Line 510 
510  #endif  #endif
511      {      {
512        restart:        restart:
513          if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &state, &id))          if (!obj->enumerate(cx, JSENUMERATE_NEXT, &state, &id))
514              return JS_FALSE;              return JS_FALSE;
515    
516          STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, state);          STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, state);
# Line 511  Line 531 
531                  obj = OBJ_GET_PROTO(cx, obj);                  obj = OBJ_GET_PROTO(cx, obj);
532                  if (obj) {                  if (obj) {
533                      STOBJ_SET_PARENT(iterobj, obj);                      STOBJ_SET_PARENT(iterobj, obj);
534                      if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &state, NULL))                      if (!obj->enumerate(cx, JSENUMERATE_INIT, &state, NULL))
535                          return JS_FALSE;                          return JS_FALSE;
536                      STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, state);                      STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, state);
537                      if (!JSVAL_IS_NULL(state))                      if (!JSVAL_IS_NULL(state))
# Line 522  Line 542 
542          }          }
543    
544          /* Skip properties not in obj when looking from origobj. */          /* Skip properties not in obj when looking from origobj. */
545          if (!OBJ_LOOKUP_PROPERTY(cx, origobj, id, &obj2, &prop))          if (!origobj->lookupProperty(cx, id, &obj2, &prop))
546              return JS_FALSE;              return JS_FALSE;
547          if (!prop)          if (!prop)
548              goto restart;              goto restart;
549          OBJ_DROP_PROPERTY(cx, obj2, prop);          obj2->dropProperty(cx, prop);
550    
551          /*          /*
552           * If the id was found in a prototype object or an unrelated object           * If the id was found in a prototype object or an unrelated object
553           * (specifically, not in an inner object for obj), skip it. This step           * (specifically, not in an inner object for obj), skip it. This step
554           * means that all OBJ_LOOKUP_PROPERTY implementations must return an           * means that all lookupProperty implementations must return an
555           * object further along on the prototype chain, or else possibly an           * object further along on the prototype chain, or else possibly an
556           * object returned by the JSExtendedClass.outerObject optional hook.           * object returned by the JSExtendedClass.outerObject optional hook.
557           */           */
# Line 549  Line 569 
569    
570          if (foreach) {          if (foreach) {
571              /* Get property querying the original object. */              /* Get property querying the original object. */
572              if (!OBJ_GET_PROPERTY(cx, origobj, id, rval))              if (!origobj->getProperty(cx, id, rval))
573                  return JS_FALSE;                  return JS_FALSE;
574          }          }
575      }      }
# Line 625  Line 645 
645      JS_PropertyStub,  JS_PropertyStub,      JS_PropertyStub,  JS_PropertyStub,
646      JS_PropertyStub,  JS_PropertyStub,      JS_PropertyStub,  JS_PropertyStub,
647      JS_EnumerateStub, JS_ResolveStub,      JS_EnumerateStub, JS_ResolveStub,
648      JS_ConvertStub,   JS_FinalizeStub,      JS_ConvertStub,   NULL,
649      NULL,             NULL,      NULL,             NULL,
650      NULL,             NULL,      NULL,             NULL,
651      NULL,             stopiter_hasInstance,      NULL,             stopiter_hasInstance,
# Line 637  Line 657 
657  static void  static void
658  generator_finalize(JSContext *cx, JSObject *obj)  generator_finalize(JSContext *cx, JSObject *obj)
659  {  {
660      JSGenerator *gen;      JSGenerator *gen = (JSGenerator *) obj->getPrivate();
661        if (!gen)
662            return;
663    
664      gen = (JSGenerator *) JS_GetPrivate(cx, obj);      /*
665      if (gen) {       * gen is open when a script has not called its close method while
666          /*       * explicitly manipulating it.
667           * gen can be open on shutdown when close hooks are ignored or when       */
668           * the embedding cancels scheduled close hooks.      JS_ASSERT(gen->state == JSGEN_NEWBORN ||
669           */                gen->state == JSGEN_CLOSED ||
670          JS_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_CLOSED ||                gen->state == JSGEN_OPEN);
671                    gen->state == JSGEN_OPEN);      cx->free(gen);
         JS_free(cx, gen);  
     }  
672  }  }
673    
674  static void  static void
675  generator_trace(JSTracer *trc, JSObject *obj)  generator_trace(JSTracer *trc, JSObject *obj)
676  {  {
677      JSGenerator *gen;      JSGenerator *gen = (JSGenerator *) obj->getPrivate();
   
     gen = (JSGenerator *) JS_GetPrivate(trc->context, obj);  
678      if (!gen)      if (!gen)
679          return;          return;
680    
# Line 702  Line 720 
720      JSGenerator *gen;      JSGenerator *gen;
721      jsval *slots;      jsval *slots;
722    
723      /* After the following return, failing control flow must goto bad. */      obj = js_NewObject(cx, &js_GeneratorClass, NULL, NULL);
     obj = js_NewObject(cx, &js_GeneratorClass, NULL, NULL, 0);  
724      if (!obj)      if (!obj)
725          return NULL;          return NULL;
726    
# Line 714  Line 731 
731    
732      /* Allocate obj's private data struct. */      /* Allocate obj's private data struct. */
733      gen = (JSGenerator *)      gen = (JSGenerator *)
734            JS_malloc(cx, sizeof(JSGenerator) + (nslots - 1) * sizeof(jsval));          cx->malloc(sizeof(JSGenerator) + (nslots - 1) * sizeof(jsval));
735      if (!gen)      if (!gen)
736          goto bad;          return NULL;
737    
738      gen->obj = obj;      gen->obj = obj;
739    
740      /* Steal away objects reflecting fp and point them at gen->frame. */      /* Steal away objects reflecting fp and point them at gen->frame. */
741      gen->frame.callobj = fp->callobj;      gen->frame.callobj = fp->callobj;
742      if (fp->callobj) {      if (fp->callobj) {
743          JS_SetPrivate(cx, fp->callobj, &gen->frame);          fp->callobj->setPrivate(&gen->frame);
744          fp->callobj = NULL;          fp->callobj = NULL;
745      }      }
746      gen->frame.argsobj = fp->argsobj;      gen->frame.argsobj = fp->argsobj;
747      if (fp->argsobj) {      if (fp->argsobj) {
748          JS_SetPrivate(cx, fp->argsobj, &gen->frame);          JSVAL_TO_OBJECT(fp->argsobj)->setPrivate(&gen->frame);
749          fp->argsobj = NULL;          fp->argsobj = NULL;
750      }      }
751    
# Line 738  Line 755 
755    
756      /* Copy call-invariant script and function references. */      /* Copy call-invariant script and function references. */
757      gen->frame.script = fp->script;      gen->frame.script = fp->script;
     gen->frame.callee = fp->callee;  
758      gen->frame.fun = fp->fun;      gen->frame.fun = fp->fun;
759    
760      /* Use slots to carve space out of gen->slots. */      /* Use slots to carve space out of gen->slots. */
# Line 772  Line 788 
788      gen->frame.sharpArray = NULL;      gen->frame.sharpArray = NULL;
789      gen->frame.flags = (fp->flags & ~JSFRAME_ROOTED_ARGV) | JSFRAME_GENERATOR;      gen->frame.flags = (fp->flags & ~JSFRAME_ROOTED_ARGV) | JSFRAME_GENERATOR;
790      gen->frame.dormantNext = NULL;      gen->frame.dormantNext = NULL;
     gen->frame.xmlNamespace = NULL;  
791      /* JSOP_GENERATOR appears in the prologue, outside all blocks.  */      /* JSOP_GENERATOR appears in the prologue, outside all blocks.  */
792      JS_ASSERT(!fp->blockChain);      JS_ASSERT(!fp->blockChain);
793      gen->frame.blockChain = NULL;      gen->frame.blockChain = NULL;
# Line 780  Line 795 
795      /* Note that gen is newborn. */      /* Note that gen is newborn. */
796      gen->state = JSGEN_NEWBORN;      gen->state = JSGEN_NEWBORN;
797    
798      if (!JS_SetPrivate(cx, obj, gen)) {      obj->setPrivate(gen);
         JS_free(cx, gen);  
         goto bad;  
     }  
799      return obj;      return obj;
   
   bad:  
     cx->weakRoots.newborn[GCX_OBJECT] = NULL;  
     return NULL;  
800  }  }
801    
802  typedef enum JSGeneratorOp {  typedef enum JSGeneratorOp {
# Line 895  Line 903 
903  static JS_REQUIRES_STACK JSBool  static JS_REQUIRES_STACK JSBool
904  CloseGenerator(JSContext *cx, JSObject *obj)  CloseGenerator(JSContext *cx, JSObject *obj)
905  {  {
     JSGenerator *gen;  
   
906      JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_GeneratorClass);      JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_GeneratorClass);
907      gen = (JSGenerator *) JS_GetPrivate(cx, obj);  
908        JSGenerator *gen = (JSGenerator *) obj->getPrivate();
909      if (!gen) {      if (!gen) {
910          /* Generator prototype object. */          /* Generator prototype object. */
911          return JS_TRUE;          return JS_TRUE;
# Line 917  Line 924 
924  generator_op(JSContext *cx, JSGeneratorOp op, jsval *vp, uintN argc)  generator_op(JSContext *cx, JSGeneratorOp op, jsval *vp, uintN argc)
925  {  {
926      JSObject *obj;      JSObject *obj;
     JSGenerator *gen;  
927      jsval arg;      jsval arg;
928    
929      js_LeaveTrace(cx);      js_LeaveTrace(cx);
# Line 926  Line 932 
932      if (!JS_InstanceOf(cx, obj, &js_GeneratorClass, vp + 2))      if (!JS_InstanceOf(cx, obj, &js_GeneratorClass, vp + 2))
933          return JS_FALSE;          return JS_FALSE;
934    
935      gen = (JSGenerator *) JS_GetPrivate(cx, obj);      JSGenerator *gen = (JSGenerator *) obj->getPrivate();
936      if (gen == NULL) {      if (!gen) {
937          /* This happens when obj is the generator prototype. See bug 352885. */          /* This happens when obj is the generator prototype. See bug 352885. */
938          goto closed_generator;          goto closed_generator;
939      }      }
# Line 1026  Line 1032 
1032      if (!proto)      if (!proto)
1033          return NULL;          return NULL;
1034      STOBJ_SET_SLOT(proto, JSSLOT_ITER_STATE, JSVAL_NULL);      STOBJ_SET_SLOT(proto, JSSLOT_ITER_STATE, JSVAL_NULL);
1035        STOBJ_SET_SLOT(proto, JSSLOT_ITER_FLAGS, JSVAL_ZERO);
1036    
1037  #if JS_HAS_GENERATORS  #if JS_HAS_GENERATORS
1038      /* Initialize the generator internals if configured. */      /* Initialize the generator internals if configured. */

Legend:
Removed from v.506  
changed lines
  Added in v.507

  ViewVC Help
Powered by ViewVC 1.1.24