~ubuntu-branches/ubuntu/gutsy/firefox/gutsy

« back to all changes in this revision

Viewing changes to js/src/jsiter.c

  • Committer: Bazaar Package Importer
  • Author(s): Ian Jackson
  • Date: 2006-10-10 18:49:32 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20061010184932-da75izt7y0e59afq
Tags: 1.99+2.0rc2+dfsg-0ubuntu1
* New upstream version 2.0rc2.
* Fix/workaround for epiphany GtkSocket lifetype crash:
  apply patch id=241087 from Mozilla Bugzilla #241535 to fix LP #63814.
* Change application name to `Firefox', as requested by mdz.
  Files changed:
    - browser/locales/en-US/chrome/branding/brand.dtd
    - browser/locales/en-US/chrome/branding/brand.properties;
  New values:
    - brandShortName and brandFullName: `Bon Echo' => `Firefox'
    - vendorShortName: `Mozilla' => `Ubuntu'
* Make preferences dialogue fit again (bah!).

Show diffs side-by-side

added added

removed removed

Lines of Context:
124
124
#if JS_HAS_GENERATORS
125
125
 
126
126
static JSBool
127
 
Iterator(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
128
 
{
 
127
InitNativeIterator(JSContext *cx, JSObject *iterobj, JSObject *obj, uintN flags)
 
128
{
 
129
    jsval state;
 
130
    JSBool ok;
 
131
 
 
132
    JS_ASSERT(JSVAL_TO_PRIVATE(iterobj->slots[JSSLOT_CLASS]) ==
 
133
              &js_IteratorClass);
 
134
 
 
135
    /* Initialize iterobj in case of enumerate hook failure. */
 
136
    iterobj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(obj);
 
137
    iterobj->slots[JSSLOT_ITER_STATE] = JSVAL_NULL;
 
138
    iterobj->slots[JSSLOT_ITER_FLAGS] = INT_TO_JSVAL(flags);
 
139
    if (!js_RegisterCloseableIterator(cx, iterobj))
 
140
        return JS_FALSE;
 
141
 
 
142
    ok =
 
143
#if JS_HAS_XML_SUPPORT
 
144
         ((flags & JSITER_FOREACH) && OBJECT_IS_XML(cx, obj))
 
145
         ? ((JSXMLObjectOps *) obj->map->ops)->
 
146
               enumerateValues(cx, obj, JSENUMERATE_INIT, &state, NULL, NULL)
 
147
         :
 
148
#endif
 
149
           OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &state, NULL);
 
150
    if (!ok)
 
151
        return JS_FALSE;
 
152
 
 
153
    iterobj->slots[JSSLOT_ITER_STATE] = state;
 
154
    return JS_TRUE;
 
155
}
 
156
 
 
157
static JSBool
 
158
Iterator(JSContext *cx, JSObject *iterobj, uintN argc, jsval *argv, jsval *rval)
 
159
{
 
160
    JSObject *obj;
 
161
    JSBool keyonly;
 
162
    jsid id;
 
163
    JSObject *obj2;
129
164
    jsval fval;
130
 
    const jsid id = ATOM_TO_JSID(cx->runtime->atomState.iteratorAtom);
131
165
 
132
166
    /* XXX work around old valueOf call hidden beneath js_ValueToObject */
133
167
    if (!JSVAL_IS_PRIMITIVE(argv[0])) {
136
170
        obj = js_ValueToNonNullObject(cx, argv[0]);
137
171
        if (!obj)
138
172
            return JS_FALSE;
139
 
    }
140
 
 
141
 
    return JS_GetMethodById(cx, obj, id, &obj, &fval) &&
142
 
           js_InternalCall(cx, obj, fval, argc - 1, argv + 1, rval);
 
173
        argv[0] = OBJECT_TO_JSVAL(obj);
 
174
    }
 
175
 
 
176
    if (cx->fp->flags & JSFRAME_CONSTRUCTING) {
 
177
        keyonly = JS_FALSE;
 
178
        return js_ValueToBoolean(cx, argv[1], &keyonly) &&
 
179
               InitNativeIterator(cx, iterobj, obj,
 
180
                                  keyonly ? 0 : JSITER_FOREACH);
 
181
    }
 
182
 
 
183
    id = ATOM_TO_JSID(cx->runtime->atomState.iteratorAtom);
 
184
    if (!JS_GetMethodById(cx, obj, id, &obj2, &fval))
 
185
        return JS_FALSE;
 
186
 
 
187
    if (JSVAL_IS_VOID(fval)) {
 
188
        /* Fail over to the default enumerating native iterator. */
 
189
        keyonly = JS_FALSE;
 
190
        return js_ValueToBoolean(cx, argv[1], &keyonly) &&
 
191
               js_NewNativeIterator(cx, obj,
 
192
                                    keyonly ? 0 : JSITER_FOREACH,
 
193
                                    rval);
 
194
    }
 
195
    argv[0] = OBJECT_TO_JSVAL(obj2);
 
196
    return js_InternalCall(cx, obj2, fval, argc - 1, argv + 1, rval);
143
197
}
144
198
 
145
199
static JSBool
280
334
}
281
335
 
282
336
static JSFunctionSpec iterator_methods[] = {
283
 
    {js_iterator_str, iterator_self, 0,0,0},
284
 
    {js_next_str,     iterator_next, 0,0,0},
 
337
    {js_iterator_str, iterator_self, 0,JSPROP_READONLY|JSPROP_PERMANENT,0},
 
338
    {js_next_str,     iterator_next, 0,JSPROP_READONLY|JSPROP_PERMANENT,0},
285
339
    {0,0,0,0,0}
286
340
};
287
341
 
291
345
js_NewNativeIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp)
292
346
{
293
347
    JSObject *iterobj;
294
 
    jsval state;
295
 
    JSBool ok;
296
348
 
297
349
    /*
298
350
     * Create iterobj with a NULL parent to ensure that we use the correct
306
358
    /* Store iterobj in *vp to protect it from GC (callers must root vp). */
307
359
    *vp = OBJECT_TO_JSVAL(iterobj);
308
360
 
309
 
    /* Initialize iterobj in case of enumerate hook failure. */
310
 
    iterobj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(obj);
311
 
    iterobj->slots[JSSLOT_ITER_STATE] = JSVAL_NULL;
312
 
    iterobj->slots[JSSLOT_ITER_FLAGS] = INT_TO_JSVAL(flags);
313
 
    if (!js_RegisterCloseableIterator(cx, iterobj))
314
 
        return JS_FALSE;
315
 
 
316
 
    ok =
317
 
#if JS_HAS_XML_SUPPORT
318
 
         ((flags & JSITER_FOREACH) && OBJECT_IS_XML(cx, obj))
319
 
         ? ((JSXMLObjectOps *) obj->map->ops)->
320
 
               enumerateValues(cx, obj, JSENUMERATE_INIT, &state, NULL, NULL)
321
 
         :
322
 
#endif
323
 
           OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &state, NULL);
324
 
    if (!ok)
325
 
        return JS_FALSE;
326
 
 
327
 
    iterobj->slots[JSSLOT_ITER_STATE] = state;
328
 
    return JS_TRUE;
 
361
    return InitNativeIterator(cx, iterobj, obj, flags);
329
362
}
330
363
 
331
364
uintN
367
400
    js_CloseIteratorState(cx, iterobj);
368
401
}
369
402
 
370
 
JSBool
371
 
js_DefaultIterator(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
372
 
                   jsval *rval)
373
 
{
374
 
    JSBool keyonly;
375
 
 
376
 
    if (OBJ_GET_CLASS(cx, obj) == &js_IteratorClass) {
377
 
        *rval = OBJECT_TO_JSVAL(obj);
378
 
        return JS_TRUE;
379
 
    }
380
 
 
381
 
    keyonly = JS_FALSE;
382
 
    if (argc != 0 && !js_ValueToBoolean(cx, argv[0], &keyonly))
383
 
        return JS_FALSE;
384
 
    return js_NewNativeIterator(cx, obj, keyonly ? 0 : JSITER_FOREACH, rval);
385
 
}
386
 
 
387
403
/*
388
404
 * Inline expansion of Iterator, with extra logic to constrain the result of
389
405
 * ToObject(v).__iterator__.
395
411
    JSTempValueRooter tvr;
396
412
    jsval arg, fval, rval;
397
413
    JSString *str;
398
 
    JSFunction *fun;
399
414
    const JSAtom *atom = cx->runtime->atomState.iteratorAtom;
400
415
 
401
416
    /* XXX work around old valueOf call hidden beneath js_ValueToObject */
407
422
            return NULL;
408
423
    }
409
424
 
410
 
    arg = BOOLEAN_TO_JSVAL((flags & JSITER_FOREACH) == 0);
411
 
 
412
425
    JS_PUSH_SINGLE_TEMP_ROOT(cx, obj, &tvr);
413
426
    if (!JS_GetMethodById(cx, obj, ATOM_TO_JSID(atom), &obj, &fval))
414
427
        goto bad;
415
428
    if (JSVAL_IS_VOID(fval)) {
416
 
        /* Fail over to the default native iterator, called directly. */
417
 
        if (!js_DefaultIterator(cx, obj, 1, &arg, &rval))
418
 
            goto bad;
 
429
        /* Fail over to the default enumerating native iterator. */
 
430
        if (!js_NewNativeIterator(cx, obj,
 
431
                                  (flags & JSITER_FOREACH) | JSITER_ENUMERATE,
 
432
                                  &rval)) {
 
433
            goto bad;
 
434
        }
 
435
    } else {
 
436
        arg = BOOLEAN_TO_JSVAL((flags & JSITER_FOREACH) == 0);
 
437
        if (!js_InternalInvoke(cx, obj, fval, JSINVOKE_ITERATOR, 1, &arg,
 
438
                               &rval)) {
 
439
            goto bad;
 
440
        }
419
441
        if (JSVAL_IS_PRIMITIVE(rval))
420
442
            goto bad_iterator;
421
 
        iterobj = JSVAL_TO_OBJECT(rval);
422
 
        JS_ASSERT(OBJ_GET_CLASS(cx, iterobj) == &js_IteratorClass);
423
 
        iterobj->slots[JSSLOT_ITER_FLAGS] |= INT_TO_JSVAL(JSITER_ENUMERATE);
424
 
        goto out;
425
443
    }
426
444
 
427
 
    if (!js_InternalInvoke(cx, obj, fval, JSINVOKE_ITERATOR, 1, &arg, &rval))
428
 
        goto bad;
429
 
 
430
 
    if (JSVAL_IS_PRIMITIVE(rval))
431
 
        goto bad_iterator;
432
 
 
433
445
    iterobj = JSVAL_TO_OBJECT(rval);
434
446
 
435
 
    /*
436
 
     * If __iterator__ is the default native method, the native iterator it
437
 
     * returns can be flagged as hidden from script access.  This flagging is
438
 
     * predicated on js_ValueToIterator being called only by the for-in loop
439
 
     * code -- the js_CloseNativeIterator early-finalization optimization
440
 
     * based on it will break badly if script can reach iterobj.
441
 
     */
442
 
    if (OBJ_GET_CLASS(cx, iterobj) == &js_IteratorClass &&
443
 
        VALUE_IS_FUNCTION(cx, fval)) {
444
 
        fun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(fval));
445
 
        if (!FUN_INTERPRETED(fun) && fun->u.n.native == js_DefaultIterator)
446
 
            iterobj->slots[JSSLOT_ITER_FLAGS] |= INT_TO_JSVAL(JSITER_ENUMERATE);
447
 
    }
448
 
 
449
447
out:
450
448
    JS_POP_TEMP_ROOT(cx, &tvr);
451
449
    return iterobj;
478
476
    const jsid id = ATOM_TO_JSID(cx->runtime->atomState.nextAtom);
479
477
 
480
478
    /* Fastest path for repeated call from for-in loop bytecode. */
481
 
    if (iterobj == cx->cachedIterObj) {
 
479
    if (flags & JSITER_ENUMERATE) {
482
480
        JS_ASSERT(OBJ_GET_CLASS(cx, iterobj) == &js_IteratorClass);
483
 
        JS_ASSERT(flags & JSITER_ENUMERATE);
484
481
        if (!iterator_next(cx, iterobj, 0, NULL, rval) ||
485
482
            !CheckKeyValueReturn(cx, flags, idp, rval)) {
486
 
            cx->cachedIterObj = NULL;
487
483
            return JS_FALSE;
488
484
        }
489
485
        return JS_TRUE;
524
520
                    !CheckKeyValueReturn(cx, flags, idp, rval)) {
525
521
                    return JS_FALSE;
526
522
                }
527
 
                if (flags & JSITER_ENUMERATE)
528
 
                    cx->cachedIterObj = iterobj;
529
523
                return JS_TRUE;
530
524
            }
531
525
        }
560
554
    NULL,             NULL
561
555
};
562
556
 
563
 
static JSBool
564
 
genexit_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
565
 
{
566
 
    *bp = !JSVAL_IS_PRIMITIVE(v) &&
567
 
          OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_GeneratorExitClass;
568
 
    return JS_TRUE;
569
 
}
570
 
 
571
 
JSClass js_GeneratorExitClass = {
572
 
    js_GeneratorExit_str,
573
 
    JSCLASS_HAS_CACHED_PROTO(JSProto_GeneratorExit),
574
 
    JS_PropertyStub,  JS_PropertyStub,
575
 
    JS_PropertyStub,  JS_PropertyStub,
576
 
    JS_EnumerateStub, JS_ResolveStub,
577
 
    JS_ConvertStub,   JS_FinalizeStub,
578
 
    NULL,             NULL,
579
 
    NULL,             NULL,
580
 
    NULL,             genexit_hasInstance,
581
 
    NULL,             NULL
582
 
};
583
 
 
584
557
JSBool
585
558
js_ThrowStopIteration(JSContext *cx, JSObject *obj)
586
559
{
594
567
 
595
568
#if JS_HAS_GENERATORS
596
569
 
597
 
/*
598
 
 * Execute generator's close hook after GC detects that the object has become
599
 
 * unreachable.
600
 
 */
601
 
JSBool
602
 
js_CloseGeneratorObject(JSContext *cx, JSGenerator *gen)
603
 
{
604
 
    JSObject *obj, *proto;
605
 
    jsval fval, rval;
606
 
    const jsid id = ATOM_TO_JSID(cx->runtime->atomState.closeAtom);
607
 
 
608
 
    /* JSGenerator.closeLink must be already unlinked from all lists. */
609
 
    JS_ASSERT(!gen->next);
610
 
    JS_ASSERT(gen != cx->runtime->gcCloseState.reachableList);
611
 
    JS_ASSERT(gen != cx->runtime->gcCloseState.todoHead);
612
 
 
613
 
    /*
614
 
     * Get generator_close from cached class object for gen's scope chain, so
615
 
     * as not to depend on gen->obj's mutable prototype chain.
616
 
     */
617
 
    obj = gen->obj;
618
 
    if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Generator), &proto))
619
 
        return JS_FALSE;
620
 
    if (!JS_GetMethodById(cx, proto, id, &proto, &fval))
621
 
        return JS_FALSE;
622
 
 
623
 
    return js_InternalCall(cx, obj, fval, 0, NULL, &rval);
624
 
}
625
 
 
626
570
static void
627
571
generator_finalize(JSContext *cx, JSObject *obj)
628
572
{
629
573
    JSGenerator *gen;
630
574
 
631
575
    gen = (JSGenerator *) JS_GetPrivate(cx, obj);
632
 
    if (gen)
 
576
    if (gen) {
 
577
        /*
 
578
         * gen can be open on shutdown when close hooks are ignored or when
 
579
         * the embedding cancels scheduled close hooks.
 
580
         */
 
581
        JS_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_CLOSED ||
 
582
                  gen->state == JSGEN_OPEN);
633
583
        JS_free(cx, gen);
 
584
    }
634
585
}
635
586
 
636
587
static uint32
746
697
        goto bad;
747
698
    }
748
699
 
749
 
    /* Register after we have properly initialized the private slot. */
750
 
    js_RegisterGeneratorObject(cx, gen);
751
 
 
 
700
    /*
 
701
     * Register with GC to ensure that suspended finally blocks will be
 
702
     * executed.
 
703
     */
 
704
    js_RegisterGenerator(cx, gen);
752
705
    return obj;
753
706
 
754
707
  bad:
756
709
    return NULL;
757
710
}
758
711
 
 
712
typedef enum JSGeneratorOp {
 
713
    JSGENOP_NEXT,
 
714
    JSGENOP_SEND,
 
715
    JSGENOP_THROW,
 
716
    JSGENOP_CLOSE
 
717
} JSGeneratorOp;
 
718
 
 
719
/*
 
720
 * Start newborn or restart yielding generator and perform the requested
 
721
 * operation inside its frame.
 
722
 */
759
723
static JSBool
760
 
generator_send(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
761
 
               jsval *rval)
 
724
SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
 
725
                JSGenerator *gen, jsval arg, jsval *rval)
762
726
{
763
 
    JSGenerator *gen;
764
 
    JSString *str;
765
727
    JSStackFrame *fp;
 
728
    jsval junk;
766
729
    JSArena *arena;
767
730
    JSBool ok;
768
 
    jsval junk;
769
 
 
770
 
    if (!JS_InstanceOf(cx, obj, &js_GeneratorClass, argv))
771
 
        return JS_FALSE;
772
 
 
773
 
    gen = (JSGenerator *)JS_GetPrivate(cx, obj);
774
 
    if (!gen || gen->state == JSGEN_CLOSED)
775
 
        return !JS_IsExceptionPending(cx) && js_ThrowStopIteration(cx, obj);
776
 
 
777
 
    if (gen->state == JSGEN_NEWBORN && argc != 0 && !JSVAL_IS_VOID(argv[0])) {
778
 
        str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, argv[0], NULL);
779
 
        if (str) {
780
 
            JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
781
 
                                   JSMSG_BAD_GENERATOR_SEND,
782
 
                                   JSSTRING_CHARS(str));
 
731
 
 
732
    JS_ASSERT(gen->state ==  JSGEN_NEWBORN || gen->state == JSGEN_OPEN);
 
733
    switch (op) {
 
734
      case JSGENOP_NEXT:
 
735
      case JSGENOP_SEND:
 
736
        if (gen->state == JSGEN_OPEN) {
 
737
            /*
 
738
             * Store the argument to send as the result of the yield
 
739
             * expression.
 
740
             */
 
741
            gen->frame.sp[-1] = arg;
783
742
        }
784
 
        return JS_FALSE;
 
743
        gen->state = JSGEN_RUNNING;
 
744
        break;
 
745
 
 
746
      case JSGENOP_THROW:
 
747
        JS_SetPendingException(cx, arg);
 
748
        gen->state = JSGEN_RUNNING;
 
749
        break;
 
750
 
 
751
      default:
 
752
        JS_ASSERT(op == JSGENOP_CLOSE);
 
753
        JS_SetPendingException(cx, JSVAL_ARETURN);
 
754
        gen->state = JSGEN_CLOSING;
 
755
        break;
785
756
    }
786
757
 
 
758
    /* Extend the current stack pool with gen->arena. */
 
759
    arena = cx->stackPool.current;
 
760
    JS_ASSERT(!arena->next);
 
761
    JS_ASSERT(!gen->arena.next);
 
762
    JS_ASSERT(cx->stackPool.current != &gen->arena);
 
763
    cx->stackPool.current = arena->next = &gen->arena;
 
764
 
 
765
    /* Push gen->frame around the interpreter activation. */
787
766
    fp = cx->fp;
788
 
    arena = cx->stackPool.current;
789
 
    cx->stackPool.current = &gen->arena;
790
767
    cx->fp = &gen->frame;
791
768
    gen->frame.down = fp;
792
 
 
793
 
    /* Store the argument to send as the result of the yield expression. */
794
 
    gen->frame.sp[-1] = (argc != 0) ? argv[0] : JSVAL_VOID;
795
769
    ok = js_Interpret(cx, gen->frame.pc, &junk);
796
770
    cx->fp = fp;
 
771
    gen->frame.down = NULL;
 
772
 
 
773
    /* Retract the stack pool and sanitize gen->arena. */
 
774
    JS_ASSERT(!gen->arena.next);
 
775
    JS_ASSERT(arena->next == &gen->arena);
 
776
    JS_ASSERT(cx->stackPool.current == &gen->arena);
797
777
    cx->stackPool.current = arena;
 
778
    arena->next = NULL;
798
779
 
799
 
    if (!ok) {
800
 
        if (cx->throwing)
801
 
            gen->state = JSGEN_CLOSED;
802
 
        return JS_FALSE;
 
780
    if (gen->frame.flags & JSFRAME_YIELDING) {
 
781
        /* Yield cannot fail, throw or be called on closing. */
 
782
        JS_ASSERT(ok);
 
783
        JS_ASSERT(!cx->throwing);
 
784
        JS_ASSERT(gen->state == JSGEN_RUNNING);
 
785
        JS_ASSERT(op != JSGENOP_CLOSE);
 
786
        gen->frame.flags &= ~JSFRAME_YIELDING;
 
787
        gen->state = JSGEN_OPEN;
 
788
        *rval = gen->frame.rval;
 
789
        return JS_TRUE;
803
790
    }
804
791
 
805
 
    if (!(gen->frame.flags & JSFRAME_YIELDING)) {
 
792
    gen->state = JSGEN_CLOSED;
 
793
 
 
794
    if (ok) {
806
795
        /* Returned, explicitly or by falling off the end. */
807
 
        gen->state = JSGEN_CLOSED;
 
796
        if (op == JSGENOP_CLOSE)
 
797
            return JS_TRUE;
808
798
        return js_ThrowStopIteration(cx, obj);
809
799
    }
810
800
 
811
 
    gen->state = JSGEN_RUNNING;
812
 
    gen->frame.flags &= ~JSFRAME_YIELDING;
813
 
    *rval = gen->frame.rval;
 
801
    /*
 
802
     * An error, silent termination by branch callback or an exception.
 
803
     * Propagate the condition to the caller.
 
804
     */
 
805
    return JS_FALSE;
 
806
}
 
807
 
 
808
/*
 
809
 * Execute gen's close hook after the GC detects that the object has become
 
810
 * unreachable.
 
811
 */
 
812
JSBool
 
813
js_CloseGeneratorObject(JSContext *cx, JSGenerator *gen)
 
814
{
 
815
    /* We pass null as rval since SendToGenerator never uses it with CLOSE. */
 
816
    return SendToGenerator(cx, JSGENOP_CLOSE, gen->obj, gen, JSVAL_VOID, NULL);
 
817
}
 
818
 
 
819
/*
 
820
 * Common subroutine of generator_(next|send|throw|close) methods.
 
821
 */
 
822
static JSBool
 
823
generator_op(JSContext *cx, JSGeneratorOp op,
 
824
             JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
825
{
 
826
    JSGenerator *gen;
 
827
    JSString *str;
 
828
    jsval arg;
 
829
 
 
830
    if (!JS_InstanceOf(cx, obj, &js_GeneratorClass, argv))
 
831
        return JS_FALSE;
 
832
 
 
833
    gen = (JSGenerator *) JS_GetPrivate(cx, obj);
 
834
    if (gen == NULL) {
 
835
        /* This happens when obj is the generator prototype. See bug 352885. */
 
836
        goto closed_generator;
 
837
    }
 
838
 
 
839
    switch (gen->state) {
 
840
      case JSGEN_NEWBORN:
 
841
        switch (op) {
 
842
          case JSGENOP_NEXT:
 
843
          case JSGENOP_THROW:
 
844
            break;
 
845
 
 
846
          case JSGENOP_SEND:
 
847
            if (!JSVAL_IS_VOID(argv[0])) {
 
848
                str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
 
849
                                                 argv[0], NULL);
 
850
                if (str) {
 
851
                    JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
 
852
                                           JSMSG_BAD_GENERATOR_SEND,
 
853
                                           JSSTRING_CHARS(str));
 
854
                }
 
855
                return JS_FALSE;
 
856
            }
 
857
            break;
 
858
 
 
859
          default:
 
860
            JS_ASSERT(op == JSGENOP_CLOSE);
 
861
            gen->state = JSGEN_CLOSED;
 
862
            return JS_TRUE;
 
863
        }
 
864
        break;
 
865
 
 
866
      case JSGEN_OPEN:
 
867
        break;
 
868
 
 
869
      case JSGEN_RUNNING:
 
870
      case JSGEN_CLOSING:
 
871
        str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, argv[-1],
 
872
                                         JS_GetFunctionId(gen->frame.fun));
 
873
        if (str) {
 
874
            JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
 
875
                                   JSMSG_NESTING_GENERATOR,
 
876
                                   JSSTRING_CHARS(str));
 
877
        }
 
878
        return JS_FALSE;
 
879
 
 
880
      default:
 
881
        JS_ASSERT(gen->state == JSGEN_CLOSED);
 
882
 
 
883
      closed_generator:
 
884
        switch (op) {
 
885
          case JSGENOP_NEXT:
 
886
          case JSGENOP_SEND:
 
887
            return js_ThrowStopIteration(cx, obj);
 
888
          case JSGENOP_THROW:
 
889
            JS_SetPendingException(cx, argv[0]);
 
890
            return JS_FALSE;
 
891
          default:
 
892
            JS_ASSERT(op == JSGENOP_CLOSE);
 
893
            return JS_TRUE;
 
894
        }
 
895
    }
 
896
 
 
897
    arg = (op == JSGENOP_SEND || op == JSGENOP_THROW)
 
898
          ? argv[0]
 
899
          : JSVAL_VOID;
 
900
    if (!SendToGenerator(cx, op, obj, gen, arg, rval))
 
901
        return JS_FALSE;
814
902
    return JS_TRUE;
815
903
}
816
904
 
817
905
static JSBool
 
906
generator_send(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 
907
               jsval *rval)
 
908
{
 
909
    return generator_op(cx, JSGENOP_SEND, obj, argc, argv, rval);
 
910
}
 
911
 
 
912
static JSBool
818
913
generator_next(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
819
914
               jsval *rval)
820
915
{
821
 
    return generator_send(cx, obj, 0, argv, rval);
 
916
    return generator_op(cx, JSGENOP_NEXT, obj, argc, argv, rval);
822
917
}
823
918
 
824
919
static JSBool
825
920
generator_throw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
826
921
                jsval *rval)
827
922
{
828
 
    JS_SetPendingException(cx, argv[0]);
829
 
    return generator_send(cx, obj, 0, argv, rval);
 
923
    return generator_op(cx, JSGENOP_THROW, obj, argc, argv, rval);
830
924
}
831
925
 
832
926
static JSBool
833
927
generator_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
834
928
                jsval *rval)
835
929
{
836
 
    jsval genexit, exn;
837
 
    JSClass *clasp;
838
 
    JSString *str;
839
 
 
840
 
    if (!js_FindClassObject(cx, NULL, INT_TO_JSID(JSProto_GeneratorExit),
841
 
                            &genexit)) {
842
 
        return JS_FALSE;
843
 
    }
844
 
 
845
 
    JS_SetPendingException(cx, genexit);
846
 
    if (generator_send(cx, obj, 0, argv, rval))
847
 
        return JS_TRUE;
848
 
 
849
 
    if (cx->throwing) {
850
 
        exn = cx->exception;
851
 
        if (!JSVAL_IS_PRIMITIVE(exn)) {
852
 
            clasp = OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(exn));
853
 
            if (clasp == &js_GeneratorExitClass ||
854
 
                clasp == &js_StopIterationClass) {
855
 
                JS_ClearPendingException(cx);
856
 
                return JS_TRUE;
857
 
            }
858
 
        }
859
 
    }
860
 
 
861
 
    str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, argv[-1], NULL);
862
 
    if (str) {
863
 
        JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
864
 
                               JSMSG_BAD_GENERATOR_EXIT,
865
 
                               JSSTRING_CHARS(str));
866
 
    }
867
 
    return JS_FALSE;
 
930
    return generator_op(cx, JSGENOP_CLOSE, obj, argc, argv, rval);
868
931
}
869
932
 
870
933
static JSFunctionSpec generator_methods[] = {
871
 
    {js_iterator_str, iterator_self,   0,0,0},
872
 
    {js_next_str,     generator_next,  0,0,0},
873
 
    {js_send_str,     generator_send,  1,0,0},
874
 
    {js_throw_str,    generator_throw, 1,0,0},
875
 
    {js_close_str,    generator_close, 0,JSPROP_READONLY|JSPROP_PERMANENT,0},
 
934
    {js_iterator_str, iterator_self,     0,JSPROP_READONLY|JSPROP_PERMANENT,0},
 
935
    {js_next_str,     generator_next,    0,JSPROP_READONLY|JSPROP_PERMANENT,0},
 
936
    {js_send_str,     generator_send,    1,JSPROP_READONLY|JSPROP_PERMANENT,0},
 
937
    {js_throw_str,    generator_throw,   1,JSPROP_READONLY|JSPROP_PERMANENT,0},
 
938
    {js_close_str,    generator_close,   0,JSPROP_READONLY|JSPROP_PERMANENT,0},
876
939
    {0,0,0,0,0}
877
940
};
878
941
 
903
966
    }
904
967
#endif
905
968
 
906
 
#if JS_HAS_GENERATORS
907
 
    if (!JS_InitClass(cx, obj, NULL, &js_GeneratorExitClass, NULL, 0,
908
 
                      NULL, NULL, NULL, NULL)) {
909
 
        return NULL;
910
 
    }
911
 
#endif
912
 
 
913
969
    return JS_InitClass(cx, obj, NULL, &js_StopIterationClass, NULL, 0,
914
970
                        NULL, NULL, NULL, NULL);
915
971
}