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

« back to all changes in this revision

Viewing changes to js/src/jsinterp.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:
463
463
    return JS_TRUE;
464
464
}
465
465
 
466
 
/*
467
 
 * Recursive helper to convert a compile-time block chain to a runtime block
468
 
 * scope chain prefix.  Each cloned block object is safe from GC by virtue of
469
 
 * the object newborn root.  This root cannot be displaced by arbitrary code
470
 
 * called from within js_NewObject, because we pass non-null proto and parent
471
 
 * arguments (so js_NewObject won't call js_GetClassPrototype).
472
 
 */
473
 
static JSObject *
474
 
CloneBlockChain(JSContext *cx, JSStackFrame *fp, JSObject *obj)
475
 
{
476
 
    JSObject *parent;
477
 
 
478
 
    parent = OBJ_GET_PARENT(cx, obj);
479
 
    if (!parent) {
480
 
        parent = fp->scopeChain;
481
 
    } else {
482
 
        parent = CloneBlockChain(cx, fp, parent);
483
 
        if (!parent)
484
 
            return NULL;
485
 
        fp->scopeChain = parent;
486
 
    }
487
 
    return js_CloneBlockObject(cx, obj, parent, fp);
488
 
}
489
 
 
490
466
JSObject *
491
467
js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
492
468
{
493
 
    JSObject *obj;
 
469
    JSObject *obj, *cursor, *clonedChild, *parent;
 
470
    JSTempValueRooter tvr;
494
471
 
495
472
    obj = fp->blockChain;
496
 
    if (obj) {
497
 
        obj = CloneBlockChain(cx, fp, obj);
498
 
        if (!obj)
 
473
    if (!obj) {
 
474
        JS_ASSERT(fp->scopeChain);
 
475
        return fp->scopeChain;
 
476
    }
 
477
 
 
478
    /*
 
479
     * Clone the block chain. To avoid recursive cloning we set the parent of
 
480
     * the cloned child after we clone the parent. In the following loop when
 
481
     * clonedChild is null it indicates the first iteration when no special GC
 
482
     * rooting is necessary. On the second and the following iterations we
 
483
     * have to protect clonedChild against the GC during cloning of the parent.
 
484
     */
 
485
    cursor = obj;
 
486
    clonedChild = NULL;
 
487
    for (;;) {
 
488
        parent = OBJ_GET_PARENT(cx, cursor);
 
489
 
 
490
        /*
 
491
         * We pass fp->scopeChain and not null even if we override the parent
 
492
         * slot later as null triggers useless calculations of slot's value in
 
493
         * js_NewObject that js_CloneBlockObject calls.
 
494
         */
 
495
        cursor = js_CloneBlockObject(cx, cursor, fp->scopeChain, fp);
 
496
        if (!cursor) {
 
497
            if (clonedChild)
 
498
                JS_POP_TEMP_ROOT(cx, &tvr);
499
499
            return NULL;
500
 
        fp->flags |= JSFRAME_POP_BLOCKS;
501
 
        fp->scopeChain = obj;
502
 
        fp->blockChain = NULL;
503
 
        return obj;
 
500
        }
 
501
        if (!clonedChild) {
 
502
            obj = cursor;
 
503
            if (parent)
 
504
                JS_PUSH_SINGLE_TEMP_ROOT(cx, cursor, &tvr);
 
505
        } else {
 
506
            /*
 
507
             * Avoid OBJ_SET_PARENT overhead as clonedChild cannot escape to
 
508
             * other threads.
 
509
             */
 
510
            clonedChild->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(cursor);
 
511
            JS_ASSERT(tvr.u.value == OBJECT_TO_JSVAL(clonedChild));
 
512
            tvr.u.value = OBJECT_TO_JSVAL(cursor);
 
513
        }
 
514
        if (!parent) {
 
515
            if (clonedChild)
 
516
                JS_POP_TEMP_ROOT(cx, &tvr);
 
517
            break;
 
518
        }
 
519
        clonedChild = cursor;
 
520
        cursor = parent;
504
521
    }
505
 
    JS_ASSERT(fp->scopeChain);
506
 
    return fp->scopeChain;
 
522
    fp->flags |= JSFRAME_POP_BLOCKS;
 
523
    fp->scopeChain = obj;
 
524
    fp->blockChain = NULL;
 
525
    return obj;
507
526
}
508
527
 
509
528
/*
518
537
 
519
538
    ok = JS_TRUE;
520
539
    for (obj = fp->scopeChain; obj; obj = OBJ_GET_PARENT(cx, obj)) {
521
 
        if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass)
 
540
        if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) {
 
541
            if (JS_GetPrivate(cx, obj) != fp)
 
542
                break;
522
543
            ok &= js_PutBlockObject(cx, obj);
 
544
        }
523
545
    }
524
546
    return ok;
525
547
}
1261
1283
        /* All arguments must be contiguous, so we may have to copy actuals. */
1262
1284
        nalloc = nslots;
1263
1285
        limit = (jsval *) cx->stackPool.current->limit;
 
1286
        JS_ASSERT((jsval *) cx->stackPool.current->base <= sp && sp <= limit);
1264
1287
        if (sp + nslots > limit) {
1265
1288
            /* Hit end of arena: we have to copy argv[-2..(argc+nslots-1)]. */
1266
1289
            nalloc += 2 + argc;
1380
1403
            hook(cx, &frame, JS_FALSE, &ok, hookData);
1381
1404
    }
1382
1405
 
1383
 
    /* If frame has block objects on its scope chain, cut them loose. */
1384
 
    if (frame.flags & JSFRAME_POP_BLOCKS)
1385
 
        ok &= PutBlockObjects(cx, &frame);
1386
 
 
1387
1406
    /* If frame has a call object, sync values and clear back-pointer. */
1388
1407
    if (frame.callobj)
1389
1408
        ok &= js_PutCallObject(cx, &frame);
1711
1730
            ok = OBJ_SET_PROPERTY(cx, target, id, &value);
1712
1731
        } else {
1713
1732
            ok = OBJ_DEFINE_PROPERTY(cx, target, id, value, NULL, NULL,
1714
 
                                     attrs & ~JSPROP_EXPORTED,
 
1733
                                     attrs & ~(JSPROP_EXPORTED |
 
1734
                                               JSPROP_GETTER |
 
1735
                                               JSPROP_SETTER),
1715
1736
                                     NULL);
1716
1737
        }
1717
1738
        if (prop)
1747
1768
    if (!prop)
1748
1769
        return JS_TRUE;
1749
1770
 
1750
 
    /* From here, return true, or goto bad on failure to drop prop. */
1751
 
    if (!OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &oldAttrs))
 
1771
    /*
 
1772
     * Use prop as a speedup hint to OBJ_GET_ATTRIBUTES, but drop it on error.
 
1773
     * An assertion at label bad: will insist that it is null.
 
1774
     */
 
1775
    if (!OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &oldAttrs)) {
 
1776
        OBJ_DROP_PROPERTY(cx, obj2, prop);
 
1777
#ifdef DEBUG
 
1778
        prop = NULL;
 
1779
#endif
1752
1780
        goto bad;
 
1781
    }
 
1782
 
 
1783
    /*
 
1784
     * From here, return true, or else goto bad on failure to null out params.
 
1785
     * If our caller doesn't want prop, drop it (we don't need it any longer).
 
1786
     */
 
1787
    if (!propp) {
 
1788
        OBJ_DROP_PROPERTY(cx, obj2, prop);
 
1789
        prop = NULL;
 
1790
    }
1753
1791
 
1754
1792
    /* If either property is readonly, we have an error. */
1755
1793
    report = ((oldAttrs | attrs) & JSPROP_READONLY)
1800
1838
        *objp = NULL;
1801
1839
        *propp = NULL;
1802
1840
    }
1803
 
    OBJ_DROP_PROPERTY(cx, obj2, prop);
 
1841
    JS_ASSERT(!prop);
1804
1842
    return JS_FALSE;
1805
1843
}
1806
1844
 
1981
2019
# undef JS_THREADED_INTERP
1982
2020
#endif
1983
2021
 
1984
 
typedef enum JSOpLength {
1985
 
#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
1986
 
    op##_LENGTH = length,
1987
 
#include "jsopcode.tbl"
1988
 
#undef OPDEF
1989
 
    JSOP_LIMIT_LENGTH
1990
 
} JSOpLength;
1991
 
 
1992
2022
JSBool
1993
2023
js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
1994
2024
{
2194
2224
     * jump is distributed throughout interruptJumpTable, and comes back to
2195
2225
     * the interrupt label.  The dispatch on op is through normalJumpTable.
2196
2226
     * The trick is LOAD_INTERRUPT_HANDLER setting jumpTable appropriately.
 
2227
     *
 
2228
     * It is important that "op" be initialized before the interrupt label
 
2229
     * because it is possible for "op" to be specially assigned during the
 
2230
     * normally processing of an opcode while looping (in particular, this
 
2231
     * happens in JSOP_TRAP while debugging).  We rely on DO_NEXT_OP to
 
2232
     * correctly manage "op" in all other cases.
2197
2233
     */
 
2234
    op = (JSOp) *pc;
2198
2235
    if (interruptHandler) {
2199
2236
interrupt:
2200
2237
        SAVE_SP_AND_PC(fp);
2218
2255
        LOAD_INTERRUPT_HANDLER(rt);
2219
2256
    }
2220
2257
 
2221
 
    op = (JSOp) *pc;
 
2258
    JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
2222
2259
    JS_EXTENSION_(goto *normalJumpTable[op]);
2223
2260
 
2224
2261
#else  /* !JS_THREADED_INTERP */
2283
2320
            goto out;
2284
2321
 
2285
2322
          EMPTY_CASE(JSOP_NOP)
2286
 
          EMPTY_CASE(JSOP_GROUP)
 
2323
 
 
2324
          BEGIN_CASE(JSOP_GROUP)
 
2325
            obj = NULL;
 
2326
          END_CASE(JSOP_GROUP)
2287
2327
 
2288
2328
          BEGIN_CASE(JSOP_PUSH)
2289
2329
            PUSH_OPND(JSVAL_VOID);
2298
2338
          END_CASE(JSOP_POP2)
2299
2339
 
2300
2340
          BEGIN_CASE(JSOP_SWAP)
2301
 
            /*
2302
 
             * N.B. JSOP_SWAP doesn't swap the corresponding generating pcs
2303
 
             * for the operands it swaps.
2304
 
             */
2305
 
            ltmp = sp[-1];
 
2341
            vp = sp - depth;    /* swap generating pc's for the decompiler */
 
2342
            ltmp = vp[-1];
 
2343
            vp[-1] = vp[-2];
 
2344
            sp[-2] = ltmp;
 
2345
            rtmp = sp[-1];
2306
2346
            sp[-1] = sp[-2];
2307
 
            sp[-2] = ltmp;
 
2347
            sp[-2] = rtmp;
2308
2348
          END_CASE(JSOP_SWAP)
2309
2349
 
2310
2350
          BEGIN_CASE(JSOP_POPV)
2355
2395
                JSInlineFrame *ifp = (JSInlineFrame *) fp;
2356
2396
                void *hookData = ifp->hookData;
2357
2397
 
 
2398
                /*
 
2399
                 * If fp has blocks on its scope chain, home their locals now,
 
2400
                 * before calling any debugger hook, and before freeing stack.
 
2401
                 * This matches the order of block putting and hook calling in
 
2402
                 * the "out-of-line" return code at the bottom of js_Interpret
 
2403
                 * and in js_Invoke.
 
2404
                 */
 
2405
                if (fp->flags & JSFRAME_POP_BLOCKS) {
 
2406
                    SAVE_SP_AND_PC(fp);
 
2407
                    ok &= PutBlockObjects(cx, fp);
 
2408
                }
 
2409
 
2358
2410
                if (hookData) {
2359
2411
                    JSInterpreterHook hook = cx->runtime->callHook;
2360
2412
                    if (hook) {
2364
2416
                    }
2365
2417
                }
2366
2418
 
2367
 
                /* If fp has blocks on its scope chain, cut them loose. */
2368
 
                if (fp->flags & JSFRAME_POP_BLOCKS) {
2369
 
                    SAVE_SP_AND_PC(fp);
2370
 
                    ok &= PutBlockObjects(cx, fp);
2371
 
                }
2372
 
 
2373
2419
                /*
2374
2420
                 * If fp has a call object, sync values and clear the back-
2375
2421
                 * pointer. This can happen for a lightweight function if it
2573
2619
                OBJ_DROP_PROPERTY(cx, obj2, prop);
2574
2620
          END_CASE(JSOP_IN)
2575
2621
 
 
2622
          BEGIN_CASE(JSOP_FORIN)
 
2623
            flags = 0;
 
2624
          END_CASE(JSOP_FORIN)
 
2625
 
2576
2626
          BEGIN_CASE(JSOP_FOREACH)
2577
2627
            flags = JSITER_FOREACH;
2578
2628
          END_CASE(JSOP_FOREACH)
2617
2667
 
2618
2668
          BEGIN_CASE(JSOP_FORARG)
2619
2669
          BEGIN_CASE(JSOP_FORVAR)
2620
 
#if JS_HAS_BLOCK_SCOPE
2621
2670
          BEGIN_CASE(JSOP_FORLOCAL)
2622
 
#endif
2623
2671
            /*
2624
2672
             * JSOP_FORARG and JSOP_FORVAR don't require any lval computation
2625
2673
             * here, because they address slots on the stack (in fp->args and
2674
2722
 
2675
2723
            /* Is this the first iteration ? */
2676
2724
            if (JSVAL_IS_NULL(rval)) {
2677
 
                /*
2678
 
                 * Yes, and because rval is null we know JSOP_STARTITER stored
2679
 
                 * that slot, and we must use the new iteration protocol.
2680
 
                 */
 
2725
                /* Yes, use the new iteration protocol. */
2681
2726
                fp->pc = (jsbytecode *) sp[i-depth];
2682
2727
                iterobj = js_ValueToIterator(cx, OBJECT_TO_JSVAL(obj), flags);
2683
2728
                fp->pc = pc;
2861
2906
                fp->vars[slot] = rval;
2862
2907
                break;
2863
2908
 
2864
 
#if JS_HAS_BLOCK_SCOPE
2865
2909
              case JSOP_FORLOCAL:
2866
2910
                slot = GET_UINT16(pc);
2867
2911
                JS_ASSERT(slot < (uintN)depth);
2869
2913
                GC_POKE(cx, *vp);
2870
2914
                *vp = rval;
2871
2915
                break;
2872
 
#endif
2873
2916
 
2874
2917
              case JSOP_FORELEM:
2875
2918
                /* FORELEM is not a SET operation, it's more like BINDNAME. */
2903
2946
 
2904
2947
          BEGIN_CASE(JSOP_DUP)
2905
2948
            JS_ASSERT(sp > fp->spbase);
2906
 
            rval = sp[-1];
2907
 
            PUSH_OPND(rval);
 
2949
            vp = sp - 1;                /* address top of stack */
 
2950
            rval = *vp;
 
2951
            vp -= depth;                /* address generating pc */
 
2952
            vp[1] = *vp;
 
2953
            PUSH(rval);
2908
2954
          END_CASE(JSOP_DUP)
2909
2955
 
2910
2956
          BEGIN_CASE(JSOP_DUP2)
2911
 
            JS_ASSERT(sp - 1 > fp->spbase);
2912
 
            lval = FETCH_OPND(-2);
2913
 
            rval = FETCH_OPND(-1);
2914
 
            PUSH_OPND(lval);
2915
 
            PUSH_OPND(rval);
 
2957
            JS_ASSERT(sp - 2 >= fp->spbase);
 
2958
            vp = sp - 1;                /* address top of stack */
 
2959
            lval = vp[-1];
 
2960
            rval = *vp;
 
2961
            vp -= depth;                /* address generating pc */
 
2962
            vp[1] = vp[2] = *vp;
 
2963
            PUSH(lval);
 
2964
            PUSH(rval);
2916
2965
          END_CASE(JSOP_DUP2)
2917
2966
 
2918
2967
#define PROPERTY_OP(n, call)                                                  \
3252
3301
          END_CASE(JSOP_NEW_NE)
3253
3302
 
3254
3303
          BEGIN_CASE(JSOP_CASE)
 
3304
            pc2 = (jsbytecode *) sp[-2-depth];
3255
3305
            NEW_EQUALITY_OP(==);
3256
3306
            (void) POP();
3257
3307
            if (cond) {
3259
3309
                CHECK_BRANCH(len);
3260
3310
                DO_NEXT_OP(len);
3261
3311
            }
 
3312
            sp[-depth] = (jsval)pc2;
3262
3313
            PUSH(lval);
3263
3314
          END_CASE(JSOP_CASE)
3264
3315
 
3265
3316
          BEGIN_CASE(JSOP_CASEX)
 
3317
            pc2 = (jsbytecode *) sp[-2-depth];
3266
3318
            NEW_EQUALITY_OP(==);
3267
3319
            (void) POP();
3268
3320
            if (cond) {
3270
3322
                CHECK_BRANCH(len);
3271
3323
                DO_NEXT_OP(len);
3272
3324
            }
 
3325
            sp[-depth] = (jsval)pc2;
3273
3326
            PUSH(lval);
3274
3327
          END_CASE(JSOP_CASEX)
3275
3328
 
3660
3713
                     * or decrement result, if converted to a jsdouble from
3661
3714
                     * a non-number value, from GC nesting in the setter.
3662
3715
                     */
3663
 
                    vp = sp++;
 
3716
                    vp = sp;
 
3717
                    PUSH(JSVAL_VOID);
3664
3718
                    SAVE_SP(fp);
3665
3719
                    --i;
3666
3720
                }
4256
4310
              case JSOP_GETMETHOD:    goto do_JSOP_GETMETHOD;
4257
4311
              case JSOP_SETMETHOD:    goto do_JSOP_SETMETHOD;
4258
4312
#endif
4259
 
              case JSOP_INITCATCHVAR: goto do_JSOP_INITCATCHVAR;
4260
4313
              case JSOP_NAMEDFUNOBJ:  goto do_JSOP_NAMEDFUNOBJ;
4261
4314
              case JSOP_NUMBER:       goto do_JSOP_NUMBER;
4262
4315
              case JSOP_OBJECT:       goto do_JSOP_OBJECT;
4273
4326
              case JSOP_XMLOBJECT:    goto do_JSOP_XMLOBJECT;
4274
4327
              case JSOP_XMLPI:        goto do_JSOP_XMLPI;
4275
4328
#endif
4276
 
#if JS_HAS_BLOCK_SCOPE
4277
4329
              case JSOP_ENTERBLOCK:   goto do_JSOP_ENTERBLOCK;
4278
 
#endif
4279
4330
              default:                JS_ASSERT(0);
4280
4331
            }
4281
4332
            /* NOTREACHED */
4921
4972
             */
4922
4973
            JS_ASSERT(!fp->blockChain);
4923
4974
            obj2 = fp->scopeChain;
4924
 
            JS_ASSERT(OBJ_GET_CLASS(cx, obj2) != &js_BlockClass);
4925
4975
            if (OBJ_GET_PARENT(cx, obj) != obj2) {
4926
4976
                obj = js_CloneFunctionObject(cx, obj, obj2);
4927
4977
                if (!obj) {
5013
5063
            /* If re-parenting, store a clone of the function object. */
5014
5064
            JS_ASSERT(!fp->blockChain);
5015
5065
            parent = fp->scopeChain;
5016
 
            JS_ASSERT(OBJ_GET_CLASS(cx, parent) != &js_BlockClass);
5017
5066
            if (OBJ_GET_PARENT(cx, obj) != parent) {
5018
5067
                SAVE_SP_AND_PC(fp);
5019
5068
                obj = js_CloneFunctionObject(cx, obj, parent);
5030
5079
            obj = ATOM_TO_OBJECT(atom);
5031
5080
 
5032
5081
            /* If re-parenting, push a clone of the function object. */
 
5082
            SAVE_SP_AND_PC(fp);
5033
5083
            parent = js_GetScopeChain(cx, fp);
5034
5084
            if (!parent) {
5035
5085
                ok = JS_FALSE;
5036
5086
                goto out;
5037
5087
            }
5038
5088
            if (OBJ_GET_PARENT(cx, obj) != parent) {
5039
 
                SAVE_SP_AND_PC(fp);
5040
5089
                obj = js_CloneFunctionObject(cx, obj, parent);
5041
5090
                if (!obj) {
5042
5091
                    ok = JS_FALSE;
5271
5320
            /* Ensure that id has a type suitable for use with obj. */
5272
5321
            CHECK_ELEMENT_ID(obj, id);
5273
5322
 
 
5323
            SAVE_SP_AND_PC(fp);
5274
5324
            if (JS_TypeOfValue(cx, rval) != JSTYPE_FUNCTION) {
5275
5325
                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5276
5326
                                     JSMSG_BAD_GETTER_OR_SETTER,
5285
5335
             * Getters and setters are just like watchpoints from an access
5286
5336
             * control point of view.
5287
5337
             */
5288
 
            SAVE_SP_AND_PC(fp);
5289
5338
            ok = OBJ_CHECK_ACCESS(cx, obj, id, JSACC_WATCH, &rtmp, &attrs);
5290
5339
            if (!ok)
5291
5340
                goto out;
5467
5516
          END_CASE(JSOP_SETSP)
5468
5517
 
5469
5518
          BEGIN_CASE(JSOP_GOSUB)
 
5519
            JS_ASSERT(cx->exception != JSVAL_HOLE);
 
5520
            if (!cx->throwing) {
 
5521
                lval = JSVAL_HOLE;
 
5522
            } else {
 
5523
                lval = cx->exception;
 
5524
                cx->throwing = JS_FALSE;
 
5525
            }
 
5526
            PUSH(lval);
5470
5527
            i = PTRDIFF(pc, script->main, jsbytecode) + JSOP_GOSUB_LENGTH;
5471
5528
            len = GET_JUMP_OFFSET(pc);
5472
5529
            PUSH(INT_TO_JSVAL(i));
5473
5530
          END_VARLEN_CASE
5474
5531
 
5475
5532
          BEGIN_CASE(JSOP_GOSUBX)
 
5533
            JS_ASSERT(cx->exception != JSVAL_HOLE);
 
5534
            lval = cx->throwing ? cx->exception : JSVAL_HOLE;
 
5535
            PUSH(lval);
5476
5536
            i = PTRDIFF(pc, script->main, jsbytecode) + JSOP_GOSUBX_LENGTH;
5477
5537
            len = GET_JUMPX_OFFSET(pc);
5478
5538
            PUSH(INT_TO_JSVAL(i));
5481
5541
          BEGIN_CASE(JSOP_RETSUB)
5482
5542
            rval = POP();
5483
5543
            JS_ASSERT(JSVAL_IS_INT(rval));
 
5544
            lval = POP();
 
5545
            if (lval != JSVAL_HOLE) {
 
5546
                /*
 
5547
                 * Exception was pending during finally, throw it *before* we
 
5548
                 * adjust pc, because pc indexes into script->trynotes.  This
 
5549
                 * turns out not to be necessary, but it seems clearer.  And
 
5550
                 * it points out a FIXME: 350509, due to Igor Bukanov.
 
5551
                 */
 
5552
                cx->throwing = JS_TRUE;
 
5553
                cx->exception = lval;
 
5554
                ok = JS_FALSE;
 
5555
                goto out;
 
5556
            }
5484
5557
            len = JSVAL_TO_INT(rval);
5485
5558
            pc = script->main;
5486
5559
          END_VARLEN_CASE
5490
5563
            cx->throwing = JS_FALSE;
5491
5564
          END_CASE(JSOP_EXCEPTION)
5492
5565
 
 
5566
          BEGIN_CASE(JSOP_THROWING)
 
5567
            JS_ASSERT(!cx->throwing);
 
5568
            cx->throwing = JS_TRUE;
 
5569
          END_CASE(JSOP_THROWING)
 
5570
 
5493
5571
          BEGIN_CASE(JSOP_THROW)
5494
5572
            cx->throwing = JS_TRUE;
5495
5573
            cx->exception = POP_OPND();
5497
5575
            /* let the code at out try to catch the exception. */
5498
5576
            goto out;
5499
5577
 
5500
 
          BEGIN_LITOPX_CASE(JSOP_INITCATCHVAR, 0)
5501
 
            /* Load the value into rval, while keeping it live on stack. */
5502
 
            JS_ASSERT(sp - fp->spbase >= 2);
5503
 
            rval = FETCH_OPND(-1);
5504
 
 
5505
 
            /* Get the immediate catch variable name into id. */
5506
 
            id   = ATOM_TO_JSID(atom);
5507
 
 
5508
 
            /* Find the object being initialized at top of stack. */
5509
 
            lval = FETCH_OPND(-2);
5510
 
            JS_ASSERT(JSVAL_IS_OBJECT(lval));
5511
 
            obj = JSVAL_TO_OBJECT(lval);
5512
 
 
5513
 
            SAVE_SP_AND_PC(fp);
5514
 
 
 
5578
          BEGIN_CASE(JSOP_SETLOCALPOP)
5515
5579
            /*
5516
 
             * It's possible for an evil script to substitute a random object
5517
 
             * for the new object. Check to make sure that we don't override a
5518
 
             * readonly property with the below OBJ_DEFINE_PROPERTY.
 
5580
             * The stack must have a block with at least one local slot below
 
5581
             * the exception object.
5519
5582
             */
5520
 
            ok = OBJ_GET_ATTRIBUTES(cx, obj, id, NULL, &attrs);
5521
 
            if (!ok)
5522
 
                goto out;
5523
 
            if (!(attrs & (JSPROP_READONLY | JSPROP_PERMANENT |
5524
 
                           JSPROP_GETTER | JSPROP_SETTER))) {
5525
 
                /* Define obj[id] to contain rval and to be permanent. */
5526
 
                ok = OBJ_DEFINE_PROPERTY(cx, obj, id, rval, NULL, NULL,
5527
 
                                         JSPROP_PERMANENT, NULL);
5528
 
                if (!ok)
5529
 
                    goto out;
5530
 
            }
5531
 
 
5532
 
            /* Now that we're done with rval, pop it. */
5533
 
            sp--;
5534
 
          END_LITOPX_CASE(JSOP_INITCATCHVAR)
 
5583
            JS_ASSERT(sp - fp->spbase >= 2);
 
5584
            slot = GET_UINT16(pc);
 
5585
            JS_ASSERT(slot + 1 < (uintN)depth);
 
5586
            fp->spbase[slot] = POP_OPND();
 
5587
          END_CASE(JSOP_SETLOCALPOP)
5535
5588
 
5536
5589
          BEGIN_CASE(JSOP_INSTANCEOF)
5537
5590
            SAVE_SP_AND_PC(fp);
5921
5974
          END_CASE(JSOP_GETFUNNS)
5922
5975
#endif /* JS_HAS_XML_SUPPORT */
5923
5976
 
5924
 
#if JS_HAS_BLOCK_SCOPE
5925
5977
          BEGIN_LITOPX_CASE(JSOP_ENTERBLOCK, 0)
5926
5978
            obj = ATOM_TO_OBJECT(atom);
5927
5979
            JS_ASSERT(fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == sp);
5994
6046
            JS_ASSERT(op == JSOP_LEAVEBLOCKEXPR
5995
6047
                      ? fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == sp - 1
5996
6048
                      : fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == sp);
 
6049
 
5997
6050
            *chainp = OBJ_GET_PARENT(cx, obj);
 
6051
            JS_ASSERT(chainp != &fp->blockChain ||
 
6052
                      !*chainp ||
 
6053
                      OBJ_GET_CLASS(cx, *chainp) == &js_BlockClass);
5998
6054
          }
5999
6055
          END_CASE(JSOP_LEAVEBLOCK)
6000
6056
 
6045
6101
 
6046
6102
#undef FAST_LOCAL_INCREMENT_OP
6047
6103
 
6048
 
#endif /* JS_HAS_BLOCK_SCOPE */
6049
 
 
6050
6104
#if JS_HAS_GENERATORS
6051
6105
          BEGIN_CASE(JSOP_STARTITER)
6052
6106
            /*
6053
 
             * Start of a for-in or for-each-in loop: clear flags and push two
6054
 
             * nulls.  If this is a for-each-in loop, JSOP_FOREACH will follow
6055
 
             * and set flags = JSITER_FOREACH.  Push null instead of undefined
6056
 
             * so that code at do_forinloop: can tell that this opcode pushed
6057
 
             * the iterator slot, rather than a backward compatible JSOP_PUSH
6058
 
             * that was emitted prior to the introduction of the new iteration
6059
 
             * protocol.
 
6107
             * Start of a for-in or for-each-in loop: push two nulls.  Push
 
6108
             * null instead of undefined so that code at do_forinloop: can
 
6109
             * tell that this opcode pushed the iterator slot, rather than a
 
6110
             * backward compatible JSOP_PUSH that was emitted prior to the
 
6111
             * introduction of the new iteration protocol.
6060
6112
             */
6061
 
            flags = 0;
6062
6113
            sp[0] = sp[1] = JSVAL_NULL;
6063
6114
            sp += 2;
6064
6115
          END_CASE(JSOP_STARTITER)
6095
6146
 
6096
6147
          BEGIN_CASE(JSOP_YIELD)
6097
6148
            ASSERT_NOT_THROWING(cx);
 
6149
            if (fp->flags & JSFRAME_FILTERING) {
 
6150
                /* FIXME: bug 309894 -- fix to eliminate this error. */
 
6151
                JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
 
6152
                                       JSMSG_YIELD_FROM_FILTER);
 
6153
                ok = JS_FALSE;
 
6154
                goto out;
 
6155
            }
 
6156
            if (FRAME_TO_GENERATOR(fp)->state == JSGEN_CLOSING) {
 
6157
                str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
 
6158
                                                 fp->argv[-2], NULL);
 
6159
                if (str) {
 
6160
                    JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
 
6161
                                           JSMSG_BAD_GENERATOR_YIELD,
 
6162
                                           JSSTRING_CHARS(str));
 
6163
                }
 
6164
                ok = JS_FALSE;
 
6165
                goto out;
 
6166
            }
6098
6167
            fp->rval = FETCH_OPND(-1);
6099
6168
            fp->flags |= JSFRAME_YIELDING;
6100
6169
            pc += JSOP_YIELD_LENGTH;
6121
6190
          END_CASE(JSOP_ARRAYPUSH)
6122
6191
#endif /* JS_HAS_GENERATORS */
6123
6192
 
6124
 
#if !JS_HAS_BLOCK_SCOPE
6125
 
          L_JSOP_ENTERBLOCK:
6126
 
          L_JSOP_LEAVEBLOCK:
6127
 
          L_JSOP_LEAVEBLOCKEXPR:
6128
 
          L_JSOP_GETLOCAL:
6129
 
          L_JSOP_SETLOCAL:
6130
 
          L_JSOP_INCLOCAL:
6131
 
          L_JSOP_DECLOCAL:
6132
 
          L_JSOP_LOCALINC:
6133
 
          L_JSOP_LOCALDEC:
6134
 
          L_JSOP_FORLOCAL:
6135
 
#endif
6136
 
 
6137
6193
#if !JS_HAS_GENERATORS
6138
6194
          L_JSOP_STARTITER:
6139
6195
          L_JSOP_ENDITER:
6149
6205
 
6150
6206
#ifdef JS_THREADED_INTERP
6151
6207
          L_JSOP_BACKPATCH:
6152
 
          L_JSOP_BACKPATCH_PUSH:
6153
6208
          L_JSOP_BACKPATCH_POP:
6154
6209
#else
6155
6210
          default:
6255
6310
            /*
6256
6311
             * Look for a try block in script that can catch this exception.
6257
6312
             */
 
6313
#if JS_HAS_GENERATORS
 
6314
            if (JS_LIKELY(cx->exception != JSVAL_ARETURN)) {
 
6315
                SCRIPT_FIND_CATCH_START(script, pc, pc);
 
6316
                if (!pc)
 
6317
                    goto no_catch;
 
6318
            } else {
 
6319
                pc = js_FindFinallyHandler(script, pc);
 
6320
                if (!pc) {
 
6321
                    cx->throwing = JS_FALSE;
 
6322
                    ok = JS_TRUE;
 
6323
                    fp->rval = JSVAL_VOID;
 
6324
                    goto no_catch;
 
6325
                }
 
6326
            }
 
6327
#else
6258
6328
            SCRIPT_FIND_CATCH_START(script, pc, pc);
6259
 
            if (pc) {
6260
 
                /* Don't clear cx->throwing to save cx->exception from GC. */
6261
 
                len = 0;
6262
 
                ok = JS_TRUE;
6263
 
                DO_NEXT_OP(len);
6264
 
            }
 
6329
            if (!pc)
 
6330
                goto no_catch;
 
6331
#endif
 
6332
 
 
6333
            /* Don't clear cx->throwing to save cx->exception from GC. */
 
6334
            len = 0;
 
6335
            ok = JS_TRUE;
 
6336
            DO_NEXT_OP(len);
6265
6337
        }
6266
6338
no_catch:;
6267
6339
    }
6280
6352
     * Restore the previous frame's execution state.
6281
6353
     */
6282
6354
    if (JS_LIKELY(mark != NULL)) {
 
6355
        /* If fp has blocks on its scope chain, home their locals now. */
 
6356
        if (fp->flags & JSFRAME_POP_BLOCKS) {
 
6357
            SAVE_SP_AND_PC(fp);
 
6358
            ok &= PutBlockObjects(cx, fp);
 
6359
        }
 
6360
 
6283
6361
        fp->sp = fp->spbase;
6284
6362
        fp->spbase = NULL;
6285
6363
        js_FreeRawStack(cx, mark);