Attachment #627405: address review comments, ban yield for bug #757676

View | Details | Raw Unified | Return to bug 757676
Collapse All | Expand All

(-)a/js/src/frontend/BytecodeEmitter.cpp (-3 / +96 lines)
Line     Link Here 
 Lines 5096-5125   EmitStatementList(JSContext *cx, Bytecod Link Here 
5096
        if (noteIndex < 0 || Emit1(cx, bce, JSOP_NOP) < 0)
5096
        if (noteIndex < 0 || Emit1(cx, bce, JSOP_NOP) < 0)
5097
            return false;
5097
            return false;
5098
    }
5098
    }
5099
5099
5100
    StmtInfo stmtInfo(cx);
5100
    StmtInfo stmtInfo(cx);
5101
    PushStatement(bce->sc, &stmtInfo, STMT_BLOCK, top);
5101
    PushStatement(bce->sc, &stmtInfo, STMT_BLOCK, top);
5102
5102
5103
    ParseNode *pnchild = pn->pn_head;
5103
    ParseNode *pnchild = pn->pn_head;
5104
5105
    // Destructuring is handled in args body for functions with default
5106
    // arguments.
5107
    if (pn->pn_xflags & PNX_DESTRUCT && bce->sc->fun()->hasDefaults())
5108
        pnchild = pnchild->pn_next;
5104
    if (pn->pn_xflags & PNX_FUNCDEFS) {
5109
    if (pn->pn_xflags & PNX_FUNCDEFS) {
5105
        /*
5110
        /*
5106
         * This block contains top-level function definitions. To ensure
5111
         * This block contains top-level function definitions. To ensure
5107
         * that we emit the bytecode defining them before the rest of code
5112
         * that we emit the bytecode defining them before the rest of code
5108
         * in the block we use a separate pass over functions. During the
5113
         * in the block we use a separate pass over functions. During the
5109
         * main pass later the emitter will add JSOP_NOP with source notes
5114
         * main pass later the emitter will add JSOP_NOP with source notes
5110
         * for the function to preserve the original functions position
5115
         * for the function to preserve the original functions position
5111
         * when decompiling.
5116
         * when decompiling.
5112
         *
5117
         *
5113
         * Currently this is used only for functions, as compile-as-we go
5118
         * Currently this is used only for functions, as compile-as-we go
5114
         * mode for scripts does not allow separate emitter passes.
5119
         * mode for scripts does not allow separate emitter passes.
5115
         */
5120
         */
5116
        JS_ASSERT(bce->sc->inFunction);
5121
        JS_ASSERT(bce->sc->inFunction);
5117
        if (pn->pn_xflags & PNX_DESTRUCT) {
5122
        if (pn->pn_xflags & PNX_DESTRUCT && !bce->sc->fun()->hasDefaults()) {
5118
            /*
5123
            /*
5119
             * Assign the destructuring arguments before defining any
5124
             * Assign the destructuring arguments before defining any
5120
             * functions, see bug 419662.
5125
             * functions, see bug 419662.
5121
             */
5126
             */
5122
            JS_ASSERT(pnchild->isKind(PNK_SEMI));
5127
            JS_ASSERT(pnchild->isKind(PNK_SEMI));
5123
            JS_ASSERT(pnchild->pn_kid->isKind(PNK_VAR) || pnchild->pn_kid->isKind(PNK_CONST));
5128
            JS_ASSERT(pnchild->pn_kid->isKind(PNK_VAR) || pnchild->pn_kid->isKind(PNK_CONST));
5124
            if (!EmitTree(cx, bce, pnchild))
5129
            if (!EmitTree(cx, bce, pnchild))
5125
                return false;
5130
                return false;
 Lines 5854-5869   EmitUnary(JSContext *cx, BytecodeEmitter Link Here 
5854
    bce->sc->inForInit = false;
5859
    bce->sc->inForInit = false;
5855
    if (!EmitTree(cx, bce, pn2))
5860
    if (!EmitTree(cx, bce, pn2))
5856
        return false;
5861
        return false;
5857
5862
5858
    bce->sc->inForInit = oldInForInit;
5863
    bce->sc->inForInit = oldInForInit;
5859
    return Emit1(cx, bce, op) >= 0;
5864
    return Emit1(cx, bce, op) >= 0;
5860
}
5865
}
5861
5866
5867
static bool
5868
EmitDefaults(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
5869
{
5870
    JS_ASSERT(pn->isKind(PNK_ARGSBODY));
5871
    ParseNode *pnlast = pn->last();
5872
    unsigned ndefaults = 0;
5873
    for (ParseNode *arg = pn->pn_head; arg != pnlast; arg = arg->pn_next) {
5874
        if (arg->pn_expr)
5875
            ndefaults++;
5876
    }
5877
    JSFunction *fun = bce->sc->fun();
5878
    unsigned nformal = fun->nargs - fun->hasRest();
5879
    EMIT_UINT16_IMM_OP(JSOP_ACTUALSFILLED, nformal - ndefaults);
5880
    ptrdiff_t top = bce->offset();
5881
    size_t tableSize = (size_t)(JUMP_OFFSET_LEN * (3 + ndefaults));
5882
    if (EmitN(cx, bce, JSOP_TABLESWITCH, tableSize) < 0)
5883
        return false;
5884
    jsbytecode *pc = bce->code(top + JUMP_OFFSET_LEN);
5885
    JS_ASSERT(nformal >= ndefaults);
5886
    SET_JUMP_OFFSET(pc, nformal - ndefaults);
5887
    pc += JUMP_OFFSET_LEN;
5888
    SET_JUMP_OFFSET(pc, nformal - 1);
5889
    pc += JUMP_OFFSET_LEN;
5890
5891
    // Fill body of switch, which sets defaults where needed.
5892
    for (ParseNode *arg = pn->pn_head; arg != pnlast; arg = arg->pn_next) {
5893
        if (!arg->pn_expr)
5894
            continue;
5895
        SET_JUMP_OFFSET(pc, bce->offset() - top);
5896
        pc += JUMP_OFFSET_LEN;
5897
        if (!EmitTree(cx, bce, arg->pn_expr))
5898
            return false;
5899
        if (!BindNameToSlot(cx, bce, arg))
5900
            return false;
5901
        if (!EmitVarOp(cx, arg, JSOP_SETARG, bce))
5902
            return false;
5903
        if (Emit1(cx, bce, JSOP_POP) < 0)
5904
            return false;
5905
    }
5906
    JS_ASSERT(pc == bce->code(top + tableSize));
5907
    SET_JUMP_OFFSET(bce->code(top), bce->offset() - top);
5908
    return true;
5909
}
5910
5862
JSBool
5911
JSBool
5863
frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
5912
frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
5864
{
5913
{
5865
    JS_CHECK_RECURSION(cx, return JS_FALSE);
5914
    JS_CHECK_RECURSION(cx, return JS_FALSE);
5866
5915
5867
    EmitLevelManager elm(bce);
5916
    EmitLevelManager elm(bce);
5868
5917
5869
    JSBool ok = true;
5918
    JSBool ok = true;
 Lines 5875-5902   frontend::EmitTree(JSContext *cx, Byteco Link Here 
5875
5924
5876
    switch (pn->getKind()) {
5925
    switch (pn->getKind()) {
5877
      case PNK_FUNCTION:
5926
      case PNK_FUNCTION:
5878
        ok = EmitFunc(cx, bce, pn);
5927
        ok = EmitFunc(cx, bce, pn);
5879
        break;
5928
        break;
5880
5929
5881
      case PNK_ARGSBODY:
5930
      case PNK_ARGSBODY:
5882
      {
5931
      {
5932
        JSFunction *fun = bce->sc->fun();
5883
        ParseNode *pnlast = pn->last();
5933
        ParseNode *pnlast = pn->last();
5934
        if (fun->hasDefaults()) {
5935
            if (pnlast->pn_xflags & PNX_DESTRUCT) {
5936
                JS_ASSERT(pnlast->pn_head->isKind(PNK_SEMI));
5937
5938
                // Defaults must be able to access destructured arguments, so do
5939
                // that now.
5940
                if (!EmitTree(cx, bce, pnlast->pn_head))
5941
                    return false;
5942
            }
5943
5944
            ParseNode *rest = NULL;
5945
            if (fun->hasRest()) {
5946
                JS_ASSERT(!bce->sc->funArgumentsHasLocalBinding());
5947
5948
                // Defaults and rest also need special handling. The rest
5949
                // parameter needs to be undefined while defaults are being
5950
                // processed. To do this, we create the rest argument and let it
5951
                // sit on the stack while processing defaults. The rest
5952
                // parameter's slot is set to undefined for the course of
5953
                // default processing.
5954
                rest = pn->pn_head;
5955
                while (rest->pn_next != pnlast)
5956
                    rest = rest->pn_next;
5957
                if (Emit1(cx, bce, JSOP_REST) < 0)
5958
                    return false;
5959
                CheckTypeSet(cx, bce, JSOP_REST);
5960
                if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
5961
                    return false;
5962
                if (!EmitVarOp(cx, rest, JSOP_SETARG, bce))
5963
                    return false;
5964
                if (Emit1(cx, bce, JSOP_POP) < 0)
5965
                    return false;
5966
            }
5967
            if (!EmitDefaults(cx, bce, pn))
5968
                return false;
5969
            if (fun->hasRest()) {
5970
                if (!EmitVarOp(cx, rest, JSOP_SETARG, bce))
5971
                    return false;
5972
                if (Emit1(cx, bce, JSOP_POP) < 0)
5973
                    return false;
5974
            }
5975
        }
5884
        for (ParseNode *pn2 = pn->pn_head; pn2 != pnlast; pn2 = pn2->pn_next) {
5976
        for (ParseNode *pn2 = pn->pn_head; pn2 != pnlast; pn2 = pn2->pn_next) {
5885
            if (!pn2->isDefn())
5977
            if (!pn2->isDefn())
5886
                continue;
5978
                continue;
5887
            if (!BindNameToSlot(cx, bce, pn2))
5979
            if (!BindNameToSlot(cx, bce, pn2))
5888
                return JS_FALSE;
5980
                return JS_FALSE;
5889
            if (JOF_OPTYPE(pn2->getOp()) == JOF_QARG && bce->shouldNoteClosedName(pn2)) {
5981
            if (JOF_OPTYPE(pn2->getOp()) == JOF_QARG && bce->shouldNoteClosedName(pn2)) {
5890
                if (!bce->noteClosedArg(pn2))
5982
                if (!bce->noteClosedArg(pn2))
5891
                    return JS_FALSE;
5983
                    return JS_FALSE;
5892
            }
5984
            }
5893
            if (pn2->pn_next == pnlast && bce->sc->fun()->hasRest()) {
5985
            if (pn2->pn_next == pnlast && fun->hasRest() && !fun->hasDefaults()) {
5894
                /* Fill rest parameter. */
5986
5987
                // Fill rest parameter. We handled the case with defaults above.
5895
                JS_ASSERT(!bce->sc->funArgumentsHasLocalBinding());
5988
                JS_ASSERT(!bce->sc->funArgumentsHasLocalBinding());
5896
                bce->switchToProlog();
5989
                bce->switchToProlog();
5897
                if (Emit1(cx, bce, JSOP_REST) < 0)
5990
                if (Emit1(cx, bce, JSOP_REST) < 0)
5898
                    return false;
5991
                    return false;
5899
                CheckTypeSet(cx, bce, JSOP_REST);
5992
                CheckTypeSet(cx, bce, JSOP_REST);
5900
                if (!EmitVarOp(cx, pn2, JSOP_SETARG, bce))
5993
                if (!EmitVarOp(cx, pn2, JSOP_SETARG, bce))
5901
                    return false;
5994
                    return false;
5902
                if (Emit1(cx, bce, JSOP_POP) < 0)
5995
                if (Emit1(cx, bce, JSOP_POP) < 0)
(-)a/js/src/frontend/ParseNode.h (-2 / +2 lines)
Line     Link Here 
 Lines 609-626   struct ParseNode { Link Here 
609
        } unary;
609
        } unary;
610
        struct {                        /* name, labeled statement, etc. */
610
        struct {                        /* name, labeled statement, etc. */
611
            union {
611
            union {
612
                JSAtom        *atom;    /* lexical name or label atom */
612
                JSAtom        *atom;    /* lexical name or label atom */
613
                FunctionBox   *funbox;  /* function object */
613
                FunctionBox   *funbox;  /* function object */
614
                ObjectBox     *objbox;  /* block or regexp object */
614
                ObjectBox     *objbox;  /* block or regexp object */
615
            };
615
            };
616
            union {
616
            union {
617
                ParseNode    *expr;     /* function body, var initializer, or
617
                ParseNode    *expr;     /* function body, var initializer, argument default,
618
                                           base object of PNK_DOT */
618
                                           or base object of PNK_DOT */
619
                Definition   *lexdef;   /* lexical definition for this use */
619
                Definition   *lexdef;   /* lexical definition for this use */
620
            };
620
            };
621
            UpvarCookie cookie;         /* upvar cookie with absolute frame
621
            UpvarCookie cookie;         /* upvar cookie with absolute frame
622
                                           level (not relative skip), possibly
622
                                           level (not relative skip), possibly
623
                                           in current frame */
623
                                           in current frame */
624
            uint32_t    dflags:12,      /* definition/use flags, see below */
624
            uint32_t    dflags:12,      /* definition/use flags, see below */
625
                        blockid:20;     /* block number, for subset dominance
625
                        blockid:20;     /* block number, for subset dominance
626
                                           computation */
626
                                           computation */
(-)a/js/src/frontend/Parser.cpp (-6 / +48 lines)
Line     Link Here 
 Lines 1274-1296   LeaveFunction(ParseNode *fn, Parser *par Link Here 
1274
    }
1274
    }
1275
1275
1276
    funbox->bindings.transfer(funtc->sc->context, &funtc->sc->bindings);
1276
    funbox->bindings.transfer(funtc->sc->context, &funtc->sc->bindings);
1277
1277
1278
    return true;
1278
    return true;
1279
}
1279
}
1280
1280
1281
bool
1281
bool
1282
Parser::functionArguments(ParseNode **listp, bool &hasRest)
1282
Parser::functionArguments(ParseNode **listp, bool &hasDefaults, bool &hasRest)
1283
{
1283
{
1284
    if (tokenStream.getToken() != TOK_LP) {
1284
    if (tokenStream.getToken() != TOK_LP) {
1285
        reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_PAREN_BEFORE_FORMAL);
1285
        reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_PAREN_BEFORE_FORMAL);
1286
        return false;
1286
        return false;
1287
    }
1287
    }
1288
1288
1289
    hasDefaults = false;
1289
    hasRest = false;
1290
    hasRest = false;
1290
1291
1291
    if (!tokenStream.matchToken(TOK_RP)) {
1292
    if (!tokenStream.matchToken(TOK_RP)) {
1292
#if JS_HAS_DESTRUCTURING
1293
#if JS_HAS_DESTRUCTURING
1293
        JSAtom *duplicatedArg = NULL;
1294
        JSAtom *duplicatedArg = NULL;
1294
        bool destructuringArg = false;
1295
        bool destructuringArg = false;
1295
        ParseNode *list = NULL;
1296
        ParseNode *list = NULL;
1296
#endif
1297
#endif
 Lines 1303-1318   Parser::functionArguments(ParseNode **li Link Here 
1303
            switch (TokenKind tt = tokenStream.getToken()) {
1304
            switch (TokenKind tt = tokenStream.getToken()) {
1304
#if JS_HAS_DESTRUCTURING
1305
#if JS_HAS_DESTRUCTURING
1305
              case TOK_LB:
1306
              case TOK_LB:
1306
              case TOK_LC:
1307
              case TOK_LC:
1307
              {
1308
              {
1308
                /* See comment below in the TOK_NAME case. */
1309
                /* See comment below in the TOK_NAME case. */
1309
                if (duplicatedArg)
1310
                if (duplicatedArg)
1310
                    goto report_dup_and_destructuring;
1311
                    goto report_dup_and_destructuring;
1312
                if (hasDefaults) {
1313
                    reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT);
1314
                    return false;
1315
                }
1316
1311
                destructuringArg = true;
1317
                destructuringArg = true;
1312
1318
1313
                /*
1319
                /*
1314
                 * A destructuring formal parameter turns into one or more
1320
                 * A destructuring formal parameter turns into one or more
1315
                 * local variables initialized from properties of a single
1321
                 * local variables initialized from properties of a single
1316
                 * anonymous positional parameter, so here we must tweak our
1322
                 * anonymous positional parameter, so here we must tweak our
1317
                 * binder and its data.
1323
                 * binder and its data.
1318
                 */
1324
                 */
 Lines 1402-1417   Parser::functionArguments(ParseNode **li Link Here 
1402
                }
1408
                }
1403
#endif
1409
#endif
1404
1410
1405
                uint16_t slot;
1411
                uint16_t slot;
1406
                if (!tc->sc->bindings.addArgument(context, name, &slot))
1412
                if (!tc->sc->bindings.addArgument(context, name, &slot))
1407
                    return false;
1413
                    return false;
1408
                if (!DefineArg(tc->sc->funbox->node, name, slot, this))
1414
                if (!DefineArg(tc->sc->funbox->node, name, slot, this))
1409
                    return false;
1415
                    return false;
1416
1417
                if (tokenStream.matchToken(TOK_ASSIGN)) {
1418
                    if (hasRest) {
1419
                        reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_REST_WITH_DEFAULT);
1420
                        return false;
1421
                    }
1422
                    hasDefaults = true;
1423
                    ParseNode *def_expr = assignExprWithoutYield(JSMSG_YIELD_IN_DEFAULT);
1424
                    if (!def_expr)
1425
                        return false;
1426
                    tc->sc->funbox->node->pn_body->last()->pn_expr = def_expr;
1427
                } else if (!hasRest && hasDefaults) {
1428
                    reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT);
1429
                    return false;
1430
                }
1431
1410
                break;
1432
                break;
1411
              }
1433
              }
1412
1434
1413
              default:
1435
              default:
1414
                reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_MISSING_FORMAL);
1436
                reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_MISSING_FORMAL);
1415
                /* FALL THROUGH */
1437
                /* FALL THROUGH */
1416
              case TOK_ERROR:
1438
              case TOK_ERROR:
1417
                return false;
1439
                return false;
 Lines 1561-1581   Parser::functionDef(HandlePropertyName f Link Here 
1561
1583
1562
    if (outertc->sc->inStrictMode())
1584
    if (outertc->sc->inStrictMode())
1563
        funsc.setInStrictMode();    // inherit strict mode from parent
1585
        funsc.setInStrictMode();    // inherit strict mode from parent
1564
1586
1565
    RootedFunction fun(context, funbox->function());
1587
    RootedFunction fun(context, funbox->function());
1566
1588
1567
    /* Now parse formal argument list and compute fun->nargs. */
1589
    /* Now parse formal argument list and compute fun->nargs. */
1568
    ParseNode *prelude = NULL;
1590
    ParseNode *prelude = NULL;
1569
    bool hasRest;
1591
    bool hasRest, hasDefaults;
1570
    if (!functionArguments(&prelude, hasRest))
1592
    if (!functionArguments(&prelude, hasDefaults, hasRest))
1571
        return NULL;
1593
        return NULL;
1572
1594
1573
    fun->setArgCount(funsc.bindings.numArgs());
1595
    fun->setArgCount(funsc.bindings.numArgs());
1596
    if (hasDefaults)
1597
        fun->setHasDefaults();
1574
    if (hasRest)
1598
    if (hasRest)
1575
        fun->setHasRest();
1599
        fun->setHasRest();
1576
1600
1577
#if JS_HAS_DESTRUCTURING
1601
#if JS_HAS_DESTRUCTURING
1578
    /*
1602
    /*
1579
     * If there were destructuring formal parameters, bind the destructured-to
1603
     * If there were destructuring formal parameters, bind the destructured-to
1580
     * local variables now that we've parsed all the regular and destructuring
1604
     * local variables now that we've parsed all the regular and destructuring
1581
     * formal parameters. Because js::Bindings::add must be called first for
1605
     * formal parameters. Because js::Bindings::add must be called first for
 Lines 4934-4950   class GenexpGuard { Link Here 
4934
            tc->yieldCount = 0;
4958
            tc->yieldCount = 0;
4935
            tc->yieldNode = NULL;
4959
            tc->yieldNode = NULL;
4936
        }
4960
        }
4937
        startYieldCount = tc->yieldCount;
4961
        startYieldCount = tc->yieldCount;
4938
        tc->parenDepth++;
4962
        tc->parenDepth++;
4939
    }
4963
    }
4940
4964
4941
    void endBody();
4965
    void endBody();
4942
    bool checkValidBody(ParseNode *pn);
4966
    bool checkValidBody(ParseNode *pn, unsigned err);
4943
    bool maybeNoteGenerator(ParseNode *pn);
4967
    bool maybeNoteGenerator(ParseNode *pn);
4944
};
4968
};
4945
4969
4946
void
4970
void
4947
GenexpGuard::endBody()
4971
GenexpGuard::endBody()
4948
{
4972
{
4949
    parser->tc->parenDepth--;
4973
    parser->tc->parenDepth--;
4950
}
4974
}
 Lines 4952-4975   GenexpGuard::endBody() Link Here 
4952
/*
4976
/*
4953
 * Check whether a |yield| or |arguments| token has been encountered in the
4977
 * Check whether a |yield| or |arguments| token has been encountered in the
4954
 * body expression, and if so, report an error.
4978
 * body expression, and if so, report an error.
4955
 *
4979
 *
4956
 * Call this after endBody() when determining that the body *was* in a
4980
 * Call this after endBody() when determining that the body *was* in a
4957
 * generator expression.
4981
 * generator expression.
4958
 */
4982
 */
4959
bool
4983
bool
4960
GenexpGuard::checkValidBody(ParseNode *pn)
4984
GenexpGuard::checkValidBody(ParseNode *pn, unsigned err = JSMSG_BAD_GENEXP_BODY)
4961
{
4985
{
4962
    TreeContext *tc = parser->tc;
4986
    TreeContext *tc = parser->tc;
4963
    if (tc->yieldCount > startYieldCount) {
4987
    if (tc->yieldCount > startYieldCount) {
4964
        ParseNode *errorNode = tc->yieldNode;
4988
        ParseNode *errorNode = tc->yieldNode;
4965
        if (!errorNode)
4989
        if (!errorNode)
4966
            errorNode = pn;
4990
            errorNode = pn;
4967
        parser->reportErrorNumber(errorNode, JSREPORT_ERROR, JSMSG_BAD_GENEXP_BODY, js_yield_str);
4991
        parser->reportErrorNumber(errorNode, JSREPORT_ERROR, err, js_yield_str);
4968
        return false;
4992
        return false;
4969
    }
4993
    }
4970
4994
4971
    return true;
4995
    return true;
4972
}
4996
}
4973
4997
4974
/*
4998
/*
4975
 * Check whether a |yield| token has been encountered in the body expression,
4999
 * Check whether a |yield| token has been encountered in the body expression,
 Lines 5531-5546   Parser::generatorExpr(ParseNode *kid) Link Here 
5531
    return result;
5555
    return result;
5532
}
5556
}
5533
5557
5534
static const char js_generator_str[] = "generator";
5558
static const char js_generator_str[] = "generator";
5535
5559
5536
#endif /* JS_HAS_GENERATOR_EXPRS */
5560
#endif /* JS_HAS_GENERATOR_EXPRS */
5537
#endif /* JS_HAS_GENERATORS */
5561
#endif /* JS_HAS_GENERATORS */
5538
5562
5563
ParseNode *
5564
Parser::assignExprWithoutYield(unsigned msg)
5565
{
5566
#ifdef JS_HAS_GENERATORS
5567
    GenexpGuard yieldGuard(this);
5568
#endif
5569
    ParseNode *res = assignExpr();
5570
    if (res) {
5571
#ifdef JS_HAS_GENERATORS
5572
        if (!yieldGuard.checkValidBody(res, msg)) {
5573
            freeTree(res);
5574
            res = NULL;
5575
        }
5576
#endif
5577
    }
5578
    return res;
5579
}
5580
5539
JSBool
5581
JSBool
5540
Parser::argumentList(ParseNode *listNode)
5582
Parser::argumentList(ParseNode *listNode)
5541
{
5583
{
5542
    if (tokenStream.matchToken(TOK_RP, TSF_OPERAND))
5584
    if (tokenStream.matchToken(TOK_RP, TSF_OPERAND))
5543
        return JS_TRUE;
5585
        return JS_TRUE;
5544
5586
5545
    GenexpGuard guard(this);
5587
    GenexpGuard guard(this);
5546
    bool arg0 = true;
5588
    bool arg0 = true;
(-)a/js/src/frontend/Parser.h (-1 / +2 lines)
Line     Link Here 
 Lines 175-190   struct Parser : private AutoGCRooter Link Here 
175
#if JS_HAS_BLOCK_SCOPE
175
#if JS_HAS_BLOCK_SCOPE
176
    ParseNode *letStatement();
176
    ParseNode *letStatement();
177
#endif
177
#endif
178
    ParseNode *expressionStatement();
178
    ParseNode *expressionStatement();
179
    ParseNode *variables(ParseNodeKind kind, StaticBlockObject *blockObj = NULL,
179
    ParseNode *variables(ParseNodeKind kind, StaticBlockObject *blockObj = NULL,
180
                         VarContext varContext = HoistVars);
180
                         VarContext varContext = HoistVars);
181
    ParseNode *expr();
181
    ParseNode *expr();
182
    ParseNode *assignExpr();
182
    ParseNode *assignExpr();
183
    ParseNode *assignExprWithoutYield(unsigned err);
183
    ParseNode *condExpr1();
184
    ParseNode *condExpr1();
184
    ParseNode *orExpr1();
185
    ParseNode *orExpr1();
185
    ParseNode *andExpr1i();
186
    ParseNode *andExpr1i();
186
    ParseNode *andExpr1n();
187
    ParseNode *andExpr1n();
187
    ParseNode *bitOrExpr1i();
188
    ParseNode *bitOrExpr1i();
188
    ParseNode *bitOrExpr1n();
189
    ParseNode *bitOrExpr1n();
189
    ParseNode *bitXorExpr1i();
190
    ParseNode *bitXorExpr1i();
190
    ParseNode *bitXorExpr1n();
191
    ParseNode *bitXorExpr1n();
 Lines 204-220   struct Parser : private AutoGCRooter Link Here 
204
    ParseNode *memberExpr(JSBool allowCallSyntax);
205
    ParseNode *memberExpr(JSBool allowCallSyntax);
205
    ParseNode *primaryExpr(TokenKind tt, bool afterDoubleDot);
206
    ParseNode *primaryExpr(TokenKind tt, bool afterDoubleDot);
206
    ParseNode *parenExpr(JSBool *genexp = NULL);
207
    ParseNode *parenExpr(JSBool *genexp = NULL);
207
208
208
    /*
209
    /*
209
     * Additional JS parsers.
210
     * Additional JS parsers.
210
     */
211
     */
211
    enum FunctionType { Getter, Setter, Normal };
212
    enum FunctionType { Getter, Setter, Normal };
212
    bool functionArguments(ParseNode **list, bool &hasRest);
213
    bool functionArguments(ParseNode **list, bool &hasDefaults, bool &hasRest);
213
214
214
    ParseNode *functionDef(HandlePropertyName name, FunctionType type, FunctionSyntaxKind kind);
215
    ParseNode *functionDef(HandlePropertyName name, FunctionType type, FunctionSyntaxKind kind);
215
216
216
    ParseNode *unaryOpExpr(ParseNodeKind kind, JSOp op);
217
    ParseNode *unaryOpExpr(ParseNodeKind kind, JSOp op);
217
218
218
    ParseNode *condition();
219
    ParseNode *condition();
219
    ParseNode *comprehensionTail(ParseNode *kid, unsigned blockid, bool isGenexp,
220
    ParseNode *comprehensionTail(ParseNode *kid, unsigned blockid, bool isGenexp,
220
                                 ParseNodeKind kind = PNK_SEMI, JSOp op = JSOP_NOP);
221
                                 ParseNodeKind kind = PNK_SEMI, JSOp op = JSOP_NOP);
(-)a/js/src/jit-test/tests/arguments/defaults-basic.js (+22 lines)
Line     Link Here 
Line 0    Link Here 
1
function f1(a, bIs, b=3) {
2
    assertEq(a, 1);
3
    assertEq(b, bIs);
4
}
5
assertEq(f1.length, 3);
6
f1(1, 3);
7
f1(1, 42, 42);
8
function f2(a, bIs, cIs, b=3, c=4) {
9
    assertEq(a, 1);
10
    assertEq(b, bIs);
11
    assertEq(c, cIs);
12
}
13
assertEq(f2.length, 5);
14
f2(1, 3, 4);
15
f2(1, 42, 4, 42);
16
f2(1, 42, 43, 42, 43);
17
function f3(a, b, c=4) {
18
    assertEq(a, 1);
19
    assertEq(b, undefined);
20
    assertEq(c, 4);
21
}
22
f3(1);
(-)a/js/src/jit-test/tests/arguments/defaults-decompile.js (+34 lines)
Line     Link Here 
Line 0    Link Here 
1
function f1(a=1) {}
2
assertEq(f1.toString(), "function f1(a = 1) {\n}");
3
function f2(a=1, b=2, c=3) {}
4
assertEq(f2.toString(), "function f2(a = 1, b = 2, c = 3) {\n}");
5
function f3(a, b, c=1, d=2) {}
6
assertEq(f3.toString(), "function f3(a, b, c = 1, d = 2) {\n}");
7
function f4(a, [b], c=1) {}
8
assertEq(f4.toString(), "function f4(a, [b], c = 1) {\n}");
9
function f5(a, b, c=1, ...rest) {}
10
assertEq(f5.toString(), "function f5(a, b, c = 1, ...rest) {\n}");
11
function f6(a, [b], c=1, ...rest) {}
12
assertEq(f6.toString(), "function f6(a, [b], c = 1, ...rest) {\n}");
13
function f7(a, c=d = 190) {}
14
assertEq(f7.toString(), "function f7(a, c = d = 190) {\n}");
15
function f8(a=(b = 8)) {
16
    function nested() {
17
        return a + b;
18
    }
19
    return nested;
20
}
21
assertEq(f8.toString(), "function f8(a = b = 8) {\n\n\
22
    function nested() {\n\
23
        return a + b;\n\
24
    }\n\n\
25
    return nested;\n\
26
}");
27
function f9(a, b, c={complexity : .5, is : 40 + great.prop}, d=[42], ...rest) {}
28
assertEq(f9.toString(), "function f9(a, b, c = {complexity: 0.5, is: 40 + great.prop}, d = [42], ...rest) {\n}");
29
function f10(a=12) { return arguments; }
30
assertEq(f10.toString(), "function f10(a = 12) {\n    return arguments;\n}");
31
function f11(a=(0, c=1)) {}
32
assertEq(f11.length, 1);
33
var g = eval("(" + f11 + ")");
34
assertEq(g.length, 1);
(-)a/js/src/jit-test/tests/arguments/defaults-evaluation-order.js (+27 lines)
Line     Link Here 
Line 0    Link Here 
1
function f1(a, bIs, cIs, dIs, b=a, c=d, d=5) {
2
    assertEq(a, 1);
3
    assertEq(b, bIs);
4
    assertEq(c, cIs);
5
    assertEq(d, dIs);
6
}
7
f1(1, 1, undefined, 5);
8
f1(1, 42, undefined, 5, 42);
9
f1(1, 42, 43, 5, 42, 43);
10
f1(1, 42, 43, 44, 42, 43, 44);
11
function f2(a=[]) { return a; }
12
assertEq(f2() !== f2(), true);
13
function f3(a=function () {}) { return a; }
14
assertEq(f3() !== f3(), true);
15
function f4(a=Date) { return a; }
16
assertEq(f4(), Date);
17
Date = 0;
18
assertEq(f4(), 0);
19
function f5(x=FAIL()) {};  // don't throw
20
var n = 0;
21
function f6(a=n++) {}
22
assertEq(n, 0);
23
function f7([a, b], A=a, B=b) {
24
    assertEq(A, a);
25
    assertEq(B, b);
26
}
27
f7([0, 1]);
(-)a/js/src/jit-test/tests/arguments/defaults-exceptions.js (+6 lines)
Line     Link Here 
Line 0    Link Here 
1
load(libdir + "asserts.js");
2
3
function die() { throw "x"; }
4
var ok = true;
5
function f(a = die()) { ok = false; }
6
assertThrowsValue(f, "x");
(-)a/js/src/jit-test/tests/arguments/defaults-invalid-syntax.js (+21 lines)
Line     Link Here 
Line 0    Link Here 
1
load(libdir + "asserts.js");
2
3
assertThrowsInstanceOf(function () {
4
    eval("function f(...rest=23) {}");
5
}, SyntaxError);
6
assertThrowsInstanceOf(function () {
7
    eval("function f(a=16, b) {}");
8
}, SyntaxError);
9
assertThrowsInstanceOf(function () {
10
    eval("function f([a]=4) {}");
11
}, SyntaxError);
12
assertThrowsInstanceOf(function () {
13
    eval("function f(a=4, [b]) {}");
14
}, SyntaxError);
15
assertThrowsInstanceOf(function () {
16
    eval("function f(a=yield 24) {}");
17
}, SyntaxError);
18
assertThrowsInstanceOf(function () {
19
    eval("function f(a={a : 19 + (yield 24).prop}) {}");
20
}, SyntaxError);
21
function silly_but_okay(a=(function () { yield 97; })) {}
(-)a/js/src/jit-test/tests/arguments/defaults-scoping.js (+33 lines)
Line     Link Here 
Line 0    Link Here 
1
var x = 'global';
2
function f(a=x) {  // local variable x
3
    var x = 'local';
4
    return a;
5
}
6
assertEq(f(), undefined);
7
8
function g(f=function () { return ++x; }) {  // closes on local variable x
9
    var x = 0;
10
    return f;
11
}
12
var gf = g();
13
assertEq(gf(), 1);
14
assertEq(gf(), 2);
15
gf = g();
16
assertEq(gf(), 1);
17
18
function h(f=function (s) { return eval(s); }) {  // closes on local scope
19
    var x = 'hlocal';
20
    return f;
21
}
22
var hf = h();
23
assertEq(hf('x'), 'hlocal');
24
assertEq(hf('f'), hf);
25
assertEq(hf('var x = 3; x'), 3);
26
27
function j(expr, v=eval(expr)) {
28
    return v;
29
}
30
assertEq(j("expr"), "expr");
31
assertEq(j("v"), undefined);
32
assertEq(j("Array"), Array);
33
assertEq(j("arguments").length, 1);
(-)a/js/src/jit-test/tests/arguments/defaults-with-arguments.js (+10 lines)
Line     Link Here 
Line 0    Link Here 
1
function f(a=1, b=2, c=3) { return arguments; }
2
var args = f();
3
assertEq(args.length, 0);
4
assertEq("0" in args, false);
5
args = f(5, 6);
6
assertEq(args.length, 2);
7
assertEq(args[1], 6);
8
args = f(9, 8, 7, 6, 5);
9
assertEq(args.length, 5);
10
assertEq(args[4], 5);
(-)a/js/src/jit-test/tests/arguments/defaults-with-rest.js (+19 lines)
Line     Link Here 
Line 0    Link Here 
1
load(libdir + "eqArrayHelper.js");
2
3
function f1(a, bIs, b=3, ...rest) {
4
    assertEq(a, 1);
5
    assertEq(bIs, b);
6
    assertEqArray(rest, []);
7
}
8
assertEq(f1.length, 3);
9
f1(1, 3);
10
f1(1, 42, 42);
11
function f2(a=rest, ...rest) {
12
    assertEq(a, undefined);
13
}
14
f2();
15
function f3(a=rest, ...rest) {
16
    assertEq(a, 1);
17
    assertEqArray(rest, [2, 3, 4]);
18
}
19
f3(1, 2, 3, 4);
(-)a/js/src/js.msg (+3 lines)
Line     Link Here 
 Lines 344-351   MSG_DEF(JSMSG_EMPTY_CONSEQUENT, 29 Link Here 
344
MSG_DEF(JSMSG_NOT_ITERABLE,           291, 1, JSEXN_TYPEERR, "{0} is not iterable")
344
MSG_DEF(JSMSG_NOT_ITERABLE,           291, 1, JSEXN_TYPEERR, "{0} is not iterable")
345
MSG_DEF(JSMSG_QUERY_LINE_WITHOUT_URL, 292, 0, JSEXN_TYPEERR, "findScripts query object has 'line' property, but no 'url' property")
345
MSG_DEF(JSMSG_QUERY_LINE_WITHOUT_URL, 292, 0, JSEXN_TYPEERR, "findScripts query object has 'line' property, but no 'url' property")
346
MSG_DEF(JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL, 293, 0, JSEXN_TYPEERR, "findScripts query object has 'innermost' property without both 'url' and 'line' properties")
346
MSG_DEF(JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL, 293, 0, JSEXN_TYPEERR, "findScripts query object has 'innermost' property without both 'url' and 'line' properties")
347
MSG_DEF(JSMSG_DEBUG_VARIABLE_NOT_FOUND, 294, 0, JSEXN_TYPEERR, "variable not found in environment")
347
MSG_DEF(JSMSG_DEBUG_VARIABLE_NOT_FOUND, 294, 0, JSEXN_TYPEERR, "variable not found in environment")
348
MSG_DEF(JSMSG_PARAMETER_AFTER_REST,   295, 0, JSEXN_SYNTAXERR, "parameter after rest parameter")
348
MSG_DEF(JSMSG_PARAMETER_AFTER_REST,   295, 0, JSEXN_SYNTAXERR, "parameter after rest parameter")
349
MSG_DEF(JSMSG_NO_REST_NAME,           296, 0, JSEXN_SYNTAXERR, "no parameter name after ...")
349
MSG_DEF(JSMSG_NO_REST_NAME,           296, 0, JSEXN_SYNTAXERR, "no parameter name after ...")
350
MSG_DEF(JSMSG_ARGUMENTS_AND_REST,     297, 0, JSEXN_SYNTAXERR, "'arguments' object may not be used in conjunction with a rest parameter")
350
MSG_DEF(JSMSG_ARGUMENTS_AND_REST,     297, 0, JSEXN_SYNTAXERR, "'arguments' object may not be used in conjunction with a rest parameter")
351
MSG_DEF(JSMSG_FUNCTION_ARGUMENTS_AND_REST, 298, 0, JSEXN_ERR, "the 'arguments' property of a function with a rest parameter may not be used")
351
MSG_DEF(JSMSG_FUNCTION_ARGUMENTS_AND_REST, 298, 0, JSEXN_ERR, "the 'arguments' property of a function with a rest parameter may not be used")
352
MSG_DEF(JSMSG_REST_WITH_DEFAULT,      299, 0, JSEXN_SYNTAXERR, "rest parameter may not have a default")
353
MSG_DEF(JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT, 300, 0, JSEXN_SYNTAXERR, "parameter(s) with default followed by parameter without default")
354
MSG_DEF(JSMSG_YIELD_IN_DEFAULT,       301, 0, JSEXN_SYNTAXERR, "yield in default expression")
(-)a/js/src/jsapi.h (-1 / +3 lines)
Line     Link Here 
 Lines 2195-2212   class AutoIdRooter : private AutoGCRoote Link Here 
2195
2195
2196
/* Function flags, internal use only, returned by JS_GetFunctionFlags. */
2196
/* Function flags, internal use only, returned by JS_GetFunctionFlags. */
2197
#define JSFUN_LAMBDA            0x08    /* expressed, not declared, function */
2197
#define JSFUN_LAMBDA            0x08    /* expressed, not declared, function */
2198
#define JSFUN_HEAVYWEIGHT       0x80    /* activation requires a Call object */
2198
#define JSFUN_HEAVYWEIGHT       0x80    /* activation requires a Call object */
2199
2199
2200
#define JSFUN_HEAVYWEIGHT_TEST(f)  ((f) & JSFUN_HEAVYWEIGHT)
2200
#define JSFUN_HEAVYWEIGHT_TEST(f)  ((f) & JSFUN_HEAVYWEIGHT)
2201
2201
2202
#define JSFUN_HAS_REST          0x0100  /* function has a rest (...) parameter */
2202
#define JSFUN_HAS_REST          0x0100  /* function has a rest (...) parameter */
2203
#define JSFUN_CONSTRUCTOR     0x0200    /* native that can be called as a ctor
2203
#define JSFUN_CONSTRUCTOR       0x0200  /* native that can be called as a ctor
2204
                                           without creating a this object */
2204
                                           without creating a this object */
2205
#define JSFUN_HAS_DEFAULTS      0x0400  /* function has at least one default
2206
                                           parameter */
2205
2207
2206
#define JSFUN_FLAGS_MASK      0x07f8    /* overlay JSFUN_* attributes --
2208
#define JSFUN_FLAGS_MASK      0x07f8    /* overlay JSFUN_* attributes --
2207
                                           bits 12-15 are used internally to
2209
                                           bits 12-15 are used internally to
2208
                                           flag interpreted functions */
2210
                                           flag interpreted functions */
2209
2211
2210
#define JSFUN_STUB_GSOPS      0x1000    /* use JS_PropertyStub getter/setter
2212
#define JSFUN_STUB_GSOPS      0x1000    /* use JS_PropertyStub getter/setter
2211
                                           instead of defaulting to class gsops
2213
                                           instead of defaulting to class gsops
2212
                                           for property holding function */
2214
                                           for property holding function */
(-)a/js/src/jsfun.h (+6 lines)
Line     Link Here 
 Lines 58-73   struct JSFunction : public JSObject Link Here 
58
                                     use the accessor! */
58
                                     use the accessor! */
59
            JSObject    *env_;    /* environment for new activations;
59
            JSObject    *env_;    /* environment for new activations;
60
                                     use the accessor! */
60
                                     use the accessor! */
61
        } i;
61
        } i;
62
        void            *nativeOrScript;
62
        void            *nativeOrScript;
63
    } u;
63
    } u;
64
    js::HeapPtrAtom  atom;        /* name for diagnostics and decompiling */
64
    js::HeapPtrAtom  atom;        /* name for diagnostics and decompiling */
65
65
66
    bool hasDefaults()       const { return flags & JSFUN_HAS_DEFAULTS; }
66
    bool hasRest()           const { return flags & JSFUN_HAS_REST; }
67
    bool hasRest()           const { return flags & JSFUN_HAS_REST; }
67
    bool isInterpreted()     const { return kind() >= JSFUN_INTERPRETED; }
68
    bool isInterpreted()     const { return kind() >= JSFUN_INTERPRETED; }
68
    bool isNative()          const { return !isInterpreted(); }
69
    bool isNative()          const { return !isInterpreted(); }
69
    bool isNativeConstructor() const { return flags & JSFUN_CONSTRUCTOR; }
70
    bool isNativeConstructor() const { return flags & JSFUN_CONSTRUCTOR; }
70
    bool isHeavyweight()     const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
71
    bool isHeavyweight()     const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
71
    bool isNullClosure()     const { return kind() == JSFUN_NULL_CLOSURE; }
72
    bool isNullClosure()     const { return kind() == JSFUN_NULL_CLOSURE; }
72
    bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
73
    bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
73
    bool isInterpretedConstructor() const { return isInterpreted() && !isFunctionPrototype(); }
74
    bool isInterpretedConstructor() const { return isInterpreted() && !isFunctionPrototype(); }
 Lines 86-101   struct JSFunction : public JSObject Link Here 
86
        this->nargs = nargs;
87
        this->nargs = nargs;
87
    }
88
    }
88
89
89
    void setHasRest() {
90
    void setHasRest() {
90
        JS_ASSERT(!hasRest());
91
        JS_ASSERT(!hasRest());
91
        this->flags |= JSFUN_HAS_REST;
92
        this->flags |= JSFUN_HAS_REST;
92
    }
93
    }
93
94
95
    void setHasDefaults() {
96
        JS_ASSERT(!hasDefaults());
97
        this->flags |= JSFUN_HAS_DEFAULTS;
98
    }
99
94
    /* uint16_t representation bounds number of call object dynamic slots. */
100
    /* uint16_t representation bounds number of call object dynamic slots. */
95
    enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
101
    enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
96
102
97
    /*
103
    /*
98
     * For an interpreted function, accessors for the initial scope object of
104
     * For an interpreted function, accessors for the initial scope object of
99
     * activations (stack frames) of the function.
105
     * activations (stack frames) of the function.
100
     */
106
     */
101
    inline JSObject *environment() const;
107
    inline JSObject *environment() const;
(-)a/js/src/jsinfer.cpp (+1 lines)
Line     Link Here 
 Lines 3384-3399   ScriptAnalysis::analyzeTypesBytecode(JSC Link Here 
3384
      case JSOP_UINT24:
3384
      case JSOP_UINT24:
3385
      case JSOP_BITAND:
3385
      case JSOP_BITAND:
3386
      case JSOP_BITOR:
3386
      case JSOP_BITOR:
3387
      case JSOP_BITXOR:
3387
      case JSOP_BITXOR:
3388
      case JSOP_BITNOT:
3388
      case JSOP_BITNOT:
3389
      case JSOP_RSH:
3389
      case JSOP_RSH:
3390
      case JSOP_LSH:
3390
      case JSOP_LSH:
3391
      case JSOP_URSH:
3391
      case JSOP_URSH:
3392
      case JSOP_ACTUALSFILLED:
3392
        pushed[0].addType(cx, Type::Int32Type());
3393
        pushed[0].addType(cx, Type::Int32Type());
3393
        break;
3394
        break;
3394
      case JSOP_FALSE:
3395
      case JSOP_FALSE:
3395
      case JSOP_TRUE:
3396
      case JSOP_TRUE:
3396
      case JSOP_EQ:
3397
      case JSOP_EQ:
3397
      case JSOP_NE:
3398
      case JSOP_NE:
3398
      case JSOP_LT:
3399
      case JSOP_LT:
3399
      case JSOP_LE:
3400
      case JSOP_LE:
(-)a/js/src/jsinterp.cpp (+6 lines)
Line     Link Here 
 Lines 2807-2822   BEGIN_CASE(JSOP_LOOKUPSWITCH) Link Here 
2807
#undef SEARCH_PAIRS
2807
#undef SEARCH_PAIRS
2808
2808
2809
  end_lookup_switch:
2809
  end_lookup_switch:
2810
    len = GET_JUMP_OFFSET(pc2);
2810
    len = GET_JUMP_OFFSET(pc2);
2811
}
2811
}
2812
END_VARLEN_CASE
2812
END_VARLEN_CASE
2813
}
2813
}
2814
2814
2815
BEGIN_CASE(JSOP_ACTUALSFILLED)
2816
{
2817
    PUSH_INT32(JS_MAX(regs.fp()->numActualArgs(), GET_UINT16(regs.pc)));
2818
}
2819
END_CASE(JSOP_ACTUALSFILLED)
2820
2815
BEGIN_CASE(JSOP_ARGUMENTS)
2821
BEGIN_CASE(JSOP_ARGUMENTS)
2816
    JS_ASSERT(!regs.fp()->fun()->hasRest());
2822
    JS_ASSERT(!regs.fp()->fun()->hasRest());
2817
    if (script->needsArgsObj()) {
2823
    if (script->needsArgsObj()) {
2818
        ArgumentsObject *obj = ArgumentsObject::create(cx, regs.fp());
2824
        ArgumentsObject *obj = ArgumentsObject::create(cx, regs.fp());
2819
        if (!obj)
2825
        if (!obj)
2820
            goto error;
2826
            goto error;
2821
        PUSH_COPY(ObjectValue(*obj));
2827
        PUSH_COPY(ObjectValue(*obj));
2822
    } else {
2828
    } else {
(-)a/js/src/jsopcode.cpp (-4 / +51 lines)
Line     Link Here 
 Lines 5527-5558   js_DecompileFunction(JSPrinter *jp) Link Here 
5527
        jsbytecode *pc = script->main();
5527
        jsbytecode *pc = script->main();
5528
        jsbytecode *endpc = pc + script->length;
5528
        jsbytecode *endpc = pc + script->length;
5529
        JSBool ok = JS_TRUE;
5529
        JSBool ok = JS_TRUE;
5530
5530
5531
#if JS_HAS_DESTRUCTURING
5531
#if JS_HAS_DESTRUCTURING
5532
        ss.printer = NULL;
5532
        ss.printer = NULL;
5533
        jp->script = script;
5533
        jp->script = script;
5534
#endif
5534
#endif
5535
        
5536
        jsbytecode *deftable = NULL;
5537
        jsbytecode *defbegin = NULL;
5538
        int32_t deflen = 0;
5539
        uint16_t defstart = 0;
5540
        unsigned nformal = fun->nargs - fun->hasRest();
5535
5541
5536
        for (unsigned i = 0; i < fun->nargs; i++) {
5542
        for (unsigned i = 0; i < fun->nargs; i++) {
5537
            if (i > 0)
5543
            if (i > 0)
5538
                js_puts(jp, ", ");
5544
                js_puts(jp, ", ");
5539
5545
5540
            if (i == unsigned(fun->nargs) - 1 && fun->hasRest())
5546
            bool isRest = fun->hasRest() && i == unsigned(fun->nargs) - 1;
5547
            if (isRest)
5541
                js_puts(jp, "...");
5548
                js_puts(jp, "...");
5542
            JSAtom *param = GetArgOrVarAtom(jp, i);
5549
            JSAtom *param = GetArgOrVarAtom(jp, i);
5543
5550
5544
#if JS_HAS_DESTRUCTURING
5551
#if JS_HAS_DESTRUCTURING
5545
#define LOCAL_ASSERT(expr)      LOCAL_ASSERT_RV(expr, JS_FALSE)
5552
#define LOCAL_ASSERT(expr)      LOCAL_ASSERT_RV(expr, JS_FALSE)
5546
5553
5547
            if (!param) {
5554
            if (!param) {
5548
                ptrdiff_t todo;
5555
                ptrdiff_t todo;
5549
                const char *lval;
5556
                const char *lval;
5550
5557
5558
                JS_ASSERT(deflen == 0);
5551
                LOCAL_ASSERT(*pc == JSOP_GETARG || *pc == JSOP_GETALIASEDVAR);
5559
                LOCAL_ASSERT(*pc == JSOP_GETARG || *pc == JSOP_GETALIASEDVAR);
5552
                pc += js_CodeSpec[*pc].length;
5560
                pc += js_CodeSpec[*pc].length;
5553
                LOCAL_ASSERT(*pc == JSOP_DUP);
5561
                LOCAL_ASSERT(*pc == JSOP_DUP);
5554
                if (!ss.printer) {
5562
                if (!ss.printer) {
5555
                    ok = InitSprintStack(cx, &ss, jp, StackDepth(script));
5563
                    ok = InitSprintStack(cx, &ss, jp, StackDepth(script));
5556
                    if (!ok)
5564
                    if (!ok)
5557
                        break;
5565
                        break;
5558
                }
5566
                }
 Lines 5567-5586   js_DecompileFunction(JSPrinter *jp) Link Here 
5567
                todo = jp->sprinter.put(lval);
5575
                todo = jp->sprinter.put(lval);
5568
                if (todo < 0) {
5576
                if (todo < 0) {
5569
                    ok = JS_FALSE;
5577
                    ok = JS_FALSE;
5570
                    break;
5578
                    break;
5571
                }
5579
                }
5572
                continue;
5580
                continue;
5573
            }
5581
            }
5574
5582
5583
#endif
5584
5585
            // Compute default parameters.
5586
            if ((*pc == JSOP_REST && pc[1] == JSOP_UNDEFINED) ||
5587
                *pc == JSOP_ACTUALSFILLED) {
5588
#define SKIP(pc, op) LOCAL_ASSERT(*pc == op); pc += js_CodeSpec[op].length;
5589
                JS_ASSERT(fun->hasDefaults());
5590
                JS_ASSERT(deflen == 0);
5591
                if (fun->hasRest()) {
5592
                    SKIP(pc, JSOP_REST);
5593
                    SKIP(pc, JSOP_UNDEFINED);
5594
                    JS_ASSERT(*pc == JSOP_SETARG || *pc == JSOP_SETALIASEDVAR);
5595
                    pc += js_CodeSpec[*pc].length;
5596
                    SKIP(pc, JSOP_POP);
5597
                }
5598
                SKIP(pc, JSOP_ACTUALSFILLED);
5599
                JS_ASSERT(*pc == JSOP_TABLESWITCH);
5600
                defbegin = pc;
5601
                deflen = GET_JUMP_OFFSET(pc);
5602
                pc += JUMP_OFFSET_LEN;
5603
                defstart = GET_JUMP_OFFSET(pc);
5604
                pc += JUMP_OFFSET_LEN;
5605
                pc += JUMP_OFFSET_LEN; // Skip high
5606
                deftable = pc;
5607
                pc = defbegin + deflen;
5608
                if (fun->hasRest()) {
5609
                    SKIP(pc, JSOP_SETARG);
5610
                    SKIP(pc, JSOP_POP);
5611
                }
5612
#undef SKIP
5613
            }
5614
5575
#undef LOCAL_ASSERT
5615
#undef LOCAL_ASSERT
5576
#endif
5616
5577
5617
            if (fun->hasDefaults() && deflen && i >= defstart && !isRest) {
5578
            if (!QuoteString(&jp->sprinter, param, 0)) {
5618
#define TABLE_OFF(off) GET_JUMP_OFFSET(&deftable[(off)*JUMP_OFFSET_LEN])
5619
                jsbytecode *casestart = defbegin + TABLE_OFF(i - defstart);
5620
                jsbytecode *caseend = defbegin + ((i < nformal - 1) ? TABLE_OFF(i - defstart + 1) : deflen);
5621
#undef TABLE_OFF
5622
                unsigned exprlength = caseend - casestart - js_CodeSpec[JSOP_POP].length;
5623
                if (!DecompileCode(jp, script, casestart, exprlength, 0))
5624
                    return JS_FALSE;
5625
            } else if (!QuoteString(&jp->sprinter, param, 0)) {
5579
                ok = JS_FALSE;
5626
                ok = JS_FALSE;
5580
                break;
5627
                break;
5581
            }
5628
            }
5582
        }
5629
        }
5583
5630
5584
#if JS_HAS_DESTRUCTURING
5631
#if JS_HAS_DESTRUCTURING
5585
        jp->script = NULL;
5632
        jp->script = NULL;
5586
#endif
5633
#endif
(-)a/js/src/jsopcode.tbl (+2 lines)
Line     Link Here 
 Lines 512-519   OPDEF(JSOP_REST, 224, "rest", Link Here 
512
/* Pop the stack, convert to a jsid (int or string), and push back. */
512
/* Pop the stack, convert to a jsid (int or string), and push back. */
513
OPDEF(JSOP_TOID,          225, "toid",         NULL,  1,  1,  1,  0,  JOF_BYTE)
513
OPDEF(JSOP_TOID,          225, "toid",         NULL,  1,  1,  1,  0,  JOF_BYTE)
514
514
515
/* Push the implicit 'this' value for calls to the associated name. */
515
/* Push the implicit 'this' value for calls to the associated name. */
516
OPDEF(JSOP_IMPLICITTHIS,  226, "implicitthis", "",    5,  0,  1,  0,  JOF_ATOM)
516
OPDEF(JSOP_IMPLICITTHIS,  226, "implicitthis", "",    5,  0,  1,  0,  JOF_ATOM)
517
517
518
/* This opcode is the target of the entry jump for some loop. */
518
/* This opcode is the target of the entry jump for some loop. */
519
OPDEF(JSOP_LOOPENTRY,     227, "loopentry",    NULL,  1,  0,  0,  0,  JOF_BYTE)
519
OPDEF(JSOP_LOOPENTRY,     227, "loopentry",    NULL,  1,  0,  0,  0,  JOF_BYTE)
520
521
OPDEF(JSOP_ACTUALSFILLED, 228, "actualsfilled", NULL,  3,  0,  1,  0,  JOF_UINT16)
(-)a/js/src/vm/Xdr.h (-1 / +1 lines)
Line     Link Here 
 Lines 20-36   namespace js { Link Here 
20
 * Bytecode version number. Increment the subtrahend whenever JS bytecode
20
 * Bytecode version number. Increment the subtrahend whenever JS bytecode
21
 * changes incompatibly.
21
 * changes incompatibly.
22
 *
22
 *
23
 * This version number is XDR'd near the front of xdr bytecode and
23
 * This version number is XDR'd near the front of xdr bytecode and
24
 * aborts deserialization if there is a mismatch between the current
24
 * aborts deserialization if there is a mismatch between the current
25
 * and saved versions. If deserialization fails, the data should be
25
 * and saved versions. If deserialization fails, the data should be
26
 * invalidated if possible.
26
 * invalidated if possible.
27
 */
27
 */
28
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 115);
28
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 116);
29
29
30
class XDRBuffer {
30
class XDRBuffer {
31
  public:
31
  public:
32
    XDRBuffer(JSContext *cx)
32
    XDRBuffer(JSContext *cx)
33
      : context(cx), base(NULL), cursor(NULL), limit(NULL) { }
33
      : context(cx), base(NULL), cursor(NULL), limit(NULL) { }
34
34
35
    JSContext *cx() const {
35
    JSContext *cx() const {
36
        return context;
36
        return context;

Return to bug 757676