|
|
|
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) |