diff --git a/mozilla/js/src/jsemit.c b/mozilla/js/src/jsemit.c index b25d22df927..d622722439f 100644 --- a/mozilla/js/src/jsemit.c +++ b/mozilla/js/src/jsemit.c @@ -1230,15 +1230,17 @@ js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type, * Emit a backpatch op with offset pointing to the previous jump of this type, * so that we can walk back up the chain fixing up the op and jump offset. */ -#define EMIT_BACKPATCH_OP(cx, cg, last, op, jmp) \ - JS_BEGIN_MACRO \ - ptrdiff_t offset, delta; \ - offset = CG_OFFSET(cg); \ - delta = offset - (last); \ - last = offset; \ - JS_ASSERT(delta > 0); \ - jmp = EmitJump((cx), (cg), (op), (delta)); \ - JS_END_MACRO +static ptrdiff_t +EmitBackPatchOp(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t *lastp) +{ + ptrdiff_t offset, delta; + + offset = CG_OFFSET(cg); + delta = offset - *lastp; + *lastp = offset; + JS_ASSERT(delta > 0); + return EmitJump(cx, cg, op, delta); +} /* Emit additional bytecode(s) for non-local jumps. */ static JSBool @@ -1297,7 +1299,7 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt, case STMT_FINALLY: if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; - EMIT_BACKPATCH_OP(cx, cg, stmt->gosub, JSOP_BACKPATCH_PUSH, jmp); + jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH_PUSH, &stmt->gosub); if (jmp < 0) return JS_FALSE; break; @@ -1338,10 +1340,9 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt, static ptrdiff_t EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt, - ptrdiff_t *last, JSAtomListElement *label, JSSrcNoteType noteType) + ptrdiff_t *lastp, JSAtomListElement *label, JSSrcNoteType noteType) { intN index; - ptrdiff_t jmp; if (!EmitNonLocalJumpFixup(cx, cg, toStmt, NULL)) return -1; @@ -1359,8 +1360,7 @@ EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt, return -1; } - EMIT_BACKPATCH_OP(cx, cg, *last, JSOP_BACKPATCH, jmp); - return jmp; + return EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, lastp); } static JSBool @@ -1590,16 +1590,94 @@ IndexRegExpClone(JSContext *cx, JSParseNode *pn, JSAtomListElement *ale, } /* - * Emit a bytecode and its 2-byte constant (atom) index immediate operand. + * Macro to emit a bytecode followed by a uint16 immediate operand stored in + * big-endian order, used for arg and var numbers as well as for atomIndexes. * NB: We use cx and cg from our caller's lexical environment, and return * false on error. */ +#define EMIT_UINT16_IMM_OP(op, i) \ + JS_BEGIN_MACRO \ + if (js_Emit3(cx, cg, op, ATOM_INDEX_HI(i), ATOM_INDEX_LO(i)) < 0) \ + return JS_FALSE; \ + JS_END_MACRO + +/* + * Emit a bytecode and its 2-byte constant (atom) index immediate operand. + * If the atomIndex requires more than 2 bytes, emit a prefix op whose 24-bit + * immediate operand indexes the atom in script->atomMap. + * + * If op has JOF_NAME mode, emit JSOP_FINDNAME to find and push the object in + * the scope chain in which the literal name was found, followed by the name + * as a string. This enables us to use the JOF_ELEM counterpart to op. + * + * Otherwise, if op has JOF_PROP mode, emit JSOP_LITERAL before op, to push + * the atom's value key. For JOF_PROP ops, the object being operated on has + * already been pushed, and JSOP_LITERAL will push the id, leaving the stack + * in the proper state for a JOF_ELEM counterpart. + * + * Otherwise, emit JSOP_LITOPX to push the atom index, then perform a special + * dispatch on op, but getting op's atom index from the stack instead of from + * an unsigned 16-bit immediate operand. + */ +static JSBool +EmitAtomIndexOp(JSContext *cx, JSOp op, jsatomid atomIndex, JSCodeGenerator *cg) +{ + uint32 mode; + JSOp prefixOp; + ptrdiff_t off; + jsbytecode *pc; + + if (atomIndex >= JS_BIT(16)) { + mode = (js_CodeSpec[op].format & JOF_MODEMASK); + prefixOp = (mode == JOF_NAME) + ? JSOP_FINDNAME + : (mode == JOF_PROP) + ? JSOP_LITERAL + : JSOP_LITOPX; + off = js_EmitN(cx, cg, prefixOp, 3); + if (off < 0) + return JS_FALSE; + pc = CG_CODE(cg, off); + SET_LITERAL_INDEX(pc, atomIndex); + + switch (op) { + case JSOP_DECNAME: op = JSOP_DECELEM; break; + case JSOP_DECPROP: op = JSOP_DECELEM; break; + case JSOP_DELNAME: op = JSOP_DELELEM; break; + case JSOP_DELPROP: op = JSOP_DELELEM; break; + case JSOP_FORNAME: op = JSOP_FORELEM; break; + case JSOP_FORPROP: op = JSOP_FORELEM; break; + case JSOP_GETPROP: op = JSOP_GETELEM; break; + case JSOP_IMPORTPROP: op = JSOP_IMPORTELEM; break; + case JSOP_INCNAME: op = JSOP_INCELEM; break; + case JSOP_INCPROP: op = JSOP_INCELEM; break; + case JSOP_INITPROP: op = JSOP_INITELEM; break; + case JSOP_NAME: op = JSOP_GETELEM; break; + case JSOP_NAMEDEC: op = JSOP_ELEMDEC; break; + case JSOP_NAMEINC: op = JSOP_ELEMINC; break; + case JSOP_PROPDEC: op = JSOP_ELEMDEC; break; + case JSOP_PROPINC: op = JSOP_ELEMINC; break; + case JSOP_SETNAME: op = JSOP_SETELEM; break; + case JSOP_SETPROP: op = JSOP_SETELEM; break; + default: JS_ASSERT(mode == 0); break; + } + + return js_Emit1(cx, cg, op) >= 0; + } + + EMIT_UINT16_IMM_OP(op, atomIndex); + return JS_TRUE; +} + +/* + * Slight sugar for EmitAtomIndexOp, again accessing cx and cg from the macro + * caller's lexical environment, and embedding a false return on error. + * XXXbe hey, who checks for fun->nvars and fun->nargs overflow?! + */ #define EMIT_ATOM_INDEX_OP(op, atomIndex) \ JS_BEGIN_MACRO \ - if (js_Emit3(cx, cg, op, ATOM_INDEX_HI(atomIndex), \ - ATOM_INDEX_LO(atomIndex)) < 0) { \ + if (!EmitAtomIndexOp(cx, op, atomIndex, cg) < 0) \ return JS_FALSE; \ - } \ JS_END_MACRO static JSBool @@ -1612,8 +1690,7 @@ EmitAtomOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) return JS_FALSE; if (op == JSOP_REGEXP && !IndexRegExpClone(cx, pn, ale, cg)) return JS_FALSE; - EMIT_ATOM_INDEX_OP(op, ALE_INDEX(ale)); - return JS_TRUE; + return EmitAtomIndexOp(cx, op, ALE_INDEX(ale), cg); } /* @@ -2059,9 +2136,9 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) return JS_FALSE; if (left->pn_op == JSOP_ARGUMENTS && JSDOUBLE_IS_INT(next->pn_dval, slot) && - (jsuint)slot < ATOM_INDEX_LIMIT) { + (jsuint)slot < JS_BIT(16)) { left->pn_offset = next->pn_offset = top; - EMIT_ATOM_INDEX_OP(JSOP_ARGSUB, (jsatomid)slot); + EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot); left = next; next = left->pn_next; } @@ -2101,9 +2178,9 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) return JS_FALSE; if (left->pn_op == JSOP_ARGUMENTS && JSDOUBLE_IS_INT(right->pn_dval, slot) && - (jsuint)slot < ATOM_INDEX_LIMIT) { + (jsuint)slot < JS_BIT(16)) { left->pn_offset = right->pn_offset = top; - EMIT_ATOM_INDEX_OP(JSOP_ARGSUB, (jsatomid)slot); + EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot); return JS_TRUE; } } @@ -2123,6 +2200,8 @@ EmitNumberOp(JSContext *cx, jsdouble dval, JSCodeGenerator *cg) { jsint ival; jsatomid atomIndex; + ptrdiff_t off; + jsbytecode *pc; JSAtom *atom; JSAtomListElement *ale; @@ -2131,22 +2210,33 @@ EmitNumberOp(JSContext *cx, jsdouble dval, JSCodeGenerator *cg) return js_Emit1(cx, cg, JSOP_ZERO) >= 0; if (ival == 1) return js_Emit1(cx, cg, JSOP_ONE) >= 0; - if ((jsuint)ival < (jsuint)ATOM_INDEX_LIMIT) { - atomIndex = (jsatomid)ival; - EMIT_ATOM_INDEX_OP(JSOP_UINT16, atomIndex); + + atomIndex = (jsatomid)ival; + if (atomIndex < JS_BIT(16)) { + EMIT_UINT16_IMM_OP(JSOP_UINT16, atomIndex); return JS_TRUE; } + + if (atomIndex < JS_BIT(24)) { + off = js_EmitN(cx, cg, JSOP_UINT24, 3); + if (off < 0) + return JS_FALSE; + pc = CG_CODE(cg, off); + SET_LITERAL_INDEX(pc, atomIndex); + return JS_TRUE; + } + atom = js_AtomizeInt(cx, ival, 0); } else { atom = js_AtomizeDouble(cx, dval, 0); } if (!atom) return JS_FALSE; + ale = js_IndexAtom(cx, atom, &cg->atomList); if (!ale) return JS_FALSE; - EMIT_ATOM_INDEX_OP(JSOP_NUMBER, ALE_INDEX(ale)); - return JS_TRUE; + return EmitAtomIndexOp(cx, JSOP_NUMBER, ALE_INDEX(ale), cg); } #if JS_HAS_SWITCH_STATEMENT @@ -2787,14 +2877,28 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) slot = ((JSScopeProperty *) prop)->shortid; OBJ_DROP_PROPERTY(cx, pobj, prop); - /* Emit [JSOP_DEFLOCALFUN, local variable slot, atomIndex]. */ - off = js_EmitN(cx, cg, JSOP_DEFLOCALFUN, VARNO_LEN+ATOM_INDEX_LEN); - if (off < 0) - return JS_FALSE; - pc = CG_CODE(cg, off); - SET_VARNO(pc, slot); - pc += VARNO_LEN; - SET_ATOM_INDEX(pc, atomIndex); + if (atomIndex >= JS_BIT(16)) { + /* + * Lots of literals in the outer function, so we have to emit + * [JSOP_LITOPX, atomIndex, JSOP_DEFLOCALFUN, var slot]. + */ + off = js_EmitN(cx, cg, JSOP_LITOPX, 3); + if (off < 0) + return JS_FALSE; + pc = CG_CODE(cg, off); + SET_LITERAL_INDEX(pc, atomIndex); + EMIT_UINT16_IMM_OP(JSOP_DEFLOCALFUN, slot); + } else { + /* Emit [JSOP_DEFLOCALFUN, var slot, atomIndex]. */ + off = js_EmitN(cx, cg, JSOP_DEFLOCALFUN, + VARNO_LEN + ATOM_INDEX_LEN); + if (off < 0) + return JS_FALSE; + pc = CG_CODE(cg, off); + SET_VARNO(pc, slot); + pc += VARNO_LEN; + SET_ATOM_INDEX(pc, atomIndex); + } } else #endif EMIT_ATOM_INDEX_OP(JSOP_DEFFUN, atomIndex); @@ -3030,7 +3134,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) SET_STATEMENT_TOP(&stmtInfo, top); #if JS_HAS_XML_SUPPORT - /* Emit a for each prefix. */ + /* Emit a prefix opcode if 'for each (... in ...)' was used. */ if (pn->pn_op != JSOP_NOP && js_Emit1(cx, cg, pn->pn_op) < 0) return JS_FALSE; #endif @@ -3065,7 +3169,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (pn3->pn_attrs & JSPROP_READONLY) op = JSOP_GETVAR; atomIndex = (jsatomid) pn3->pn_slot; - EMIT_ATOM_INDEX_OP(op, atomIndex); + EMIT_UINT16_IMM_OP(op, atomIndex); } else { if (!EmitAtomOp(cx, pn3, op, cg)) return JS_FALSE; @@ -3294,14 +3398,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* Quell GCC overwarnings. */ end = catchStart = finallyCatch = catchJump = -1; -/* Emit JSOP_GOTO that points to the first op after the catch/finally blocks */ -#define EMIT_CATCH_GOTO(cx, cg, jmp) \ - EMIT_BACKPATCH_OP(cx, cg, stmtInfo.catchJump, JSOP_BACKPATCH, jmp) - -/* Emit JSOP_GOSUB that points to the finally block. */ -#define EMIT_FINALLY_GOSUB(cx, cg, jmp) \ - EMIT_BACKPATCH_OP(cx, cg, stmtInfo.gosub, JSOP_BACKPATCH_PUSH, jmp) - /* * Push stmtInfo to track jumps-over-catches and gosubs-to-finally * for later fixup. @@ -3309,7 +3405,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * When a finally block is `active' (STMT_FINALLY on the treeContext), * non-local jumps (including jumps-over-catches) result in a GOSUB * being written into the bytecode stream and fixed-up later (c.f. - * EMIT_BACKPATCH_OP and BackPatch). + * EmitBackPatchOp and BackPatch). */ js_PushStatement(&cg->treeContext, &stmtInfo, pn->pn_kid3 ? STMT_FINALLY : STMT_BLOCK, @@ -3339,7 +3435,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (pn->pn_kid3) { if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; - EMIT_FINALLY_GOSUB(cx, cg, jmp); + jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH_PUSH, &stmtInfo.gosub); if (jmp < 0) return JS_FALSE; } @@ -3347,7 +3443,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* Emit (hidden) jump over catch and/or finally. */ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; - EMIT_CATCH_GOTO(cx, cg, jmp); + jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &stmtInfo.catchJump); if (jmp < 0) return JS_FALSE; @@ -3402,7 +3498,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) } } else { /* Set stack to original depth (see SETSP comment above). */ - EMIT_ATOM_INDEX_OP(JSOP_SETSP, (jsatomid)depth); + EMIT_UINT16_IMM_OP(JSOP_SETSP, (jsatomid)depth); cg->stackDepth = depth; } @@ -3475,7 +3571,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* gosub , if required */ if (pn->pn_kid3) { - EMIT_FINALLY_GOSUB(cx, cg, jmp); + jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH_PUSH, + &stmtInfo.gosub); if (jmp < 0) return JS_FALSE; } @@ -3483,7 +3580,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* This will get fixed up to jump to after catch/finally. */ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; - EMIT_CATCH_GOTO(cx, cg, jmp); + jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, + &stmtInfo.catchJump); if (jmp < 0) return JS_FALSE; if (!iter->pn_kid2) /* leave iter at last catch */ @@ -3507,7 +3605,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * stack fixup. */ finallyCatch = CG_OFFSET(cg); - EMIT_ATOM_INDEX_OP(JSOP_SETSP, (jsatomid)depth); + EMIT_UINT16_IMM_OP(JSOP_SETSP, (jsatomid)depth); cg->stackDepth = depth; /* Last discriminant jumps to rethrow if none match. */ @@ -3515,7 +3613,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, catchJump); if (pn->pn_kid3) { - EMIT_FINALLY_GOSUB(cx, cg, jmp); + jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH_PUSH, + &stmtInfo.gosub); if (jmp < 0) return JS_FALSE; cg->stackDepth = depth; @@ -3666,6 +3765,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (op == JSOP_ARGUMENTS) { if (js_Emit1(cx, cg, op) < 0) return JS_FALSE; + } else if (pn2->pn_slot >= 0) { + EMIT_UINT16_IMM_OP(op, atomIndex); } else { EMIT_ATOM_INDEX_OP(op, atomIndex); } @@ -3898,7 +3999,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) switch (pn2->pn_type) { case TOK_NAME: if (pn2->pn_op != JSOP_SETNAME) { - EMIT_ATOM_INDEX_OP((pn2->pn_op == JSOP_SETGVAR) + EMIT_UINT16_IMM_OP((pn2->pn_op == JSOP_SETGVAR) ? JSOP_GETGVAR : (pn2->pn_op == JSOP_SETARG) ? JSOP_GETARG @@ -3951,7 +4052,11 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) case TOK_NAME: if (pn2->pn_slot < 0 || !(pn2->pn_attrs & JSPROP_READONLY)) { case TOK_DOT: - EMIT_ATOM_INDEX_OP(pn2->pn_op, atomIndex); + if (pn2->pn_slot >= 0) { + EMIT_UINT16_IMM_OP(pn2->pn_op, atomIndex); + } else { + EMIT_ATOM_INDEX_OP(pn2->pn_op, atomIndex); + } } break; case TOK_LB: @@ -4149,7 +4254,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) : JSOP_GETVAR; } atomIndex = (jsatomid) pn2->pn_slot; - EMIT_ATOM_INDEX_OP(op, atomIndex); + EMIT_UINT16_IMM_OP(op, atomIndex); } else { if (!EmitAtomOp(cx, pn2, op, cg)) return JS_FALSE; @@ -4351,25 +4456,16 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) pn2 = pn->pn_head; #if JS_HAS_SHARP_VARS if (pn2 && pn2->pn_type == TOK_DEFSHARP) { - EMIT_ATOM_INDEX_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num); + EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num); pn2 = pn2->pn_next; } #endif - for (atomIndex = 0; pn2; pn2 = pn2->pn_next) { - /* PrimaryExpr enforced ATOM_INDEX_LIMIT, so in-line optimize. */ - JS_ASSERT(atomIndex < ATOM_INDEX_LIMIT); - if (atomIndex == 0) { - if (js_Emit1(cx, cg, JSOP_ZERO) < 0) - return JS_FALSE; - } else if (atomIndex == 1) { - if (js_Emit1(cx, cg, JSOP_ONE) < 0) - return JS_FALSE; - } else { - EMIT_ATOM_INDEX_OP(JSOP_UINT16, (jsatomid)atomIndex); - } + for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) { + if (!EmitNumberOp(cx, atomIndex, cg)) + return JS_FALSE; - /* Sub-optimal: holes in a sparse initializer are void-filled. */ + /* FIXME 260106: holes in a sparse initializer are void-filled. */ if (pn2->pn_type == TOK_COMMA) { if (js_Emit1(cx, cg, JSOP_PUSH) < 0) return JS_FALSE; @@ -4377,10 +4473,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (!js_EmitTree(cx, cg, pn2)) return JS_FALSE; } + if (js_Emit1(cx, cg, JSOP_INITELEM) < 0) return JS_FALSE; - - atomIndex++; } if (pn->pn_extra & PNX_ENDCOMMA) { @@ -4415,7 +4510,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) pn2 = pn->pn_head; #if JS_HAS_SHARP_VARS if (pn2 && pn2->pn_type == TOK_DEFSHARP) { - EMIT_ATOM_INDEX_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num); + EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num); pn2 = pn2->pn_next; } #endif @@ -4469,11 +4564,11 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) case TOK_DEFSHARP: if (!js_EmitTree(cx, cg, pn->pn_kid)) return JS_FALSE; - EMIT_ATOM_INDEX_OP(JSOP_DEFSHARP, (jsatomid) pn->pn_num); + EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid) pn->pn_num); break; case TOK_USESHARP: - EMIT_ATOM_INDEX_OP(JSOP_USESHARP, (jsatomid) pn->pn_num); + EMIT_UINT16_IMM_OP(JSOP_USESHARP, (jsatomid) pn->pn_num); break; #endif /* JS_HAS_SHARP_VARS */ #endif /* JS_HAS_INITIALIZERS */ @@ -4501,7 +4596,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) } if (pn->pn_slot >= 0) { atomIndex = (jsatomid) pn->pn_slot; - EMIT_ATOM_INDEX_OP(op, atomIndex); + EMIT_UINT16_IMM_OP(op, atomIndex); break; } /* FALL THROUGH */ @@ -4654,21 +4749,13 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) break; case TOK_XMLPI: - off = js_EmitN(cx, cg, JSOP_XMLPI, 2 * ATOM_INDEX_LEN); - if (off < 0) - return JS_FALSE; - pc = CG_CODE(cg, off); - ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList); - if (!ale) - return JS_FALSE; - atomIndex = ALE_INDEX(ale); - SET_ATOM_INDEX(pc, atomIndex); - pc += ATOM_INDEX_LEN; ale = js_IndexAtom(cx, pn->pn_atom2, &cg->atomList); if (!ale) return JS_FALSE; - atomIndex = ALE_INDEX(ale); - SET_ATOM_INDEX(pc, atomIndex); + if (!EmitAtomIndexOp(cx, JSOP_STRING, ALE_INDEX(ale), cg)) + return JS_FALSE; + if (!EmitAtomOp(cx, pn, JSOP_XMLPI, cg)) + return JS_FALSE; break; #endif /* JS_HAS_XML_SUPPORT */ diff --git a/mozilla/js/src/jsinterp.c b/mozilla/js/src/jsinterp.c index 551b165d7a2..bc0b9b6f4fe 100644 --- a/mozilla/js/src/jsinterp.c +++ b/mozilla/js/src/jsinterp.c @@ -1857,6 +1857,7 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) jsbytecode *endpc, *pc2; JSOp op, op2; const JSCodeSpec *cs; + jsatomid atomIndex; JSAtom *atom; uintN argc, slot, attrs; jsval *vp, lval, rval, ltmp, rtmp; @@ -2682,9 +2683,17 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) } \ JS_END_MACRO - case JSOP_SETCONST: +#define BEGIN_LITOPX_CASE(OP,PCOFF) \ + case OP: \ + atomIndex = GET_ATOM_INDEX(pc + PCOFF); \ + do_##OP: \ + atom = js_GetAtom(cx, &script->atomMap, atomIndex); + +#define END_LITOPX_CASE \ + break; \ + + BEGIN_LITOPX_CASE(JSOP_SETCONST, 0) obj = fp->varobj; - atom = GET_ATOM(cx, script, pc); rval = FETCH_OPND(-1); SAVE_SP(fp); ok = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval, @@ -2695,10 +2704,9 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) if (!ok) goto out; STORE_OPND(-1, rval); - break; + END_LITOPX_CASE - case JSOP_BINDNAME: - atom = GET_ATOM(cx, script, pc); + BEGIN_LITOPX_CASE(JSOP_BINDNAME, 0) SAVE_SP(fp); obj = js_FindIdentifierBase(cx, ATOM_TO_JSID(atom)); if (!obj) { @@ -2706,7 +2714,7 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) goto out; } PUSH_OPND(OBJECT_TO_JSVAL(obj)); - break; + END_LITOPX_CASE case JSOP_SETNAME: atom = GET_ATOM(cx, script, pc); @@ -3708,16 +3716,78 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) PUSH_OPND(rval); obj = NULL; break; + + case JSOP_UINT24: + i = (jsint) GET_LITERAL_INDEX(pc); + rval = INT_TO_JSVAL(i); + PUSH_OPND(rval); + break; - case JSOP_NUMBER: - case JSOP_STRING: - case JSOP_OBJECT: - atom = GET_ATOM(cx, script, pc); + case JSOP_LITERAL: + atomIndex = GET_LITERAL_INDEX(pc); + atom = js_GetAtom(cx, &script->atomMap, atomIndex); PUSH_OPND(ATOM_KEY(atom)); obj = NULL; break; - case JSOP_REGEXP: + case JSOP_FINDNAME: + atomIndex = GET_LITERAL_INDEX(pc); + atom = js_GetAtom(cx, &script->atomMap, atomIndex); + SAVE_SP(fp); + obj = js_FindIdentifierBase(cx, ATOM_TO_JSID(atom)); + if (!obj) { + ok = JS_FALSE; + goto out; + } + PUSH_OPND(OBJECT_TO_JSVAL(obj)); + PUSH_OPND(ATOM_KEY(atom)); + break; + + case JSOP_LITOPX: + atomIndex = GET_LITERAL_INDEX(pc); + op = pc[1 + LITERAL_INDEX_LEN]; + switch (op) { + case JSOP_ANONFUNOBJ: goto do_JSOP_ANONFUNOBJ; + case JSOP_BINDNAME: goto do_JSOP_BINDNAME; + case JSOP_CLOSURE: goto do_JSOP_CLOSURE; + case JSOP_DEFCONST: goto do_JSOP_DEFCONST; + case JSOP_DEFFUN: goto do_JSOP_DEFFUN; + case JSOP_DEFLOCALFUN: goto do_JSOP_DEFLOCALFUN; + case JSOP_DEFVAR: goto do_JSOP_DEFVAR; + case JSOP_EXPORTNAME: goto do_JSOP_EXPORTNAME; + case JSOP_GETMETHOD: goto do_JSOP_GETMETHOD; + case JSOP_INITCATCHVAR: goto do_JSOP_INITCATCHVAR; + case JSOP_NAMEDFUNOBJ: goto do_JSOP_NAMEDFUNOBJ; + case JSOP_NUMBER: goto do_JSOP_NUMBER; + case JSOP_OBJECT: goto do_JSOP_OBJECT; + case JSOP_QNAMECONST: goto do_JSOP_QNAMECONST; + case JSOP_QNAMEPART: goto do_JSOP_QNAMEPART; + case JSOP_REGEXP: goto do_JSOP_REGEXP; + case JSOP_SETCONST: goto do_JSOP_SETCONST; + case JSOP_STRING: goto do_JSOP_STRING; + case JSOP_XMLCDATA: goto do_JSOP_XMLCDATA; + case JSOP_XMLCOMMENT: goto do_JSOP_XMLCOMMENT; + case JSOP_XMLOBJECT: goto do_JSOP_XMLOBJECT; + case JSOP_XMLPI: goto do_JSOP_XMLPI; + default: JS_ASSERT(0); + } + /* NOTREACHED */ + break; + + case JSOP_NUMBER: + case JSOP_STRING: + case JSOP_OBJECT: + atomIndex = GET_ATOM_INDEX(pc); + + do_JSOP_NUMBER: + do_JSOP_STRING: + do_JSOP_OBJECT: + atom = js_GetAtom(cx, &script->atomMap, atomIndex); + PUSH_OPND(ATOM_KEY(atom)); + obj = NULL; + break; + + BEGIN_LITOPX_CASE(JSOP_REGEXP, 0) { JSRegExp *re; JSObject *funobj; @@ -3746,7 +3816,6 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) * need a similar op for other kinds of object literals, we should * push cloning down under JSObjectOps and reuse code here. */ - atom = GET_ATOM(cx, script, pc); JS_ASSERT(ATOM_IS_OBJECT(atom)); obj = ATOM_TO_OBJECT(atom); JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass); @@ -3829,8 +3898,8 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) PUSH_OPND(rval); obj = NULL; - break; } + END_LITOPX_CASE case JSOP_ZERO: PUSH_OPND(JSVAL_ZERO); @@ -4062,8 +4131,7 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) } break; - case JSOP_EXPORTNAME: - atom = GET_ATOM(cx, script, pc); + BEGIN_LITOPX_CASE(JSOP_EXPORTNAME, 0) id = ATOM_TO_JSID(atom); obj = fp->varobj; SAVE_SP(fp); @@ -4083,7 +4151,7 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) } if (!ok) goto out; - break; + END_LITOPX_CASE case JSOP_IMPORTALL: id = (jsid) JSVAL_VOID; @@ -4244,10 +4312,10 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) case JSOP_DEFCONST: case JSOP_DEFVAR: - { - jsatomid atomIndex; - atomIndex = GET_ATOM_INDEX(pc); + + do_JSOP_DEFCONST: + do_JSOP_DEFVAR: atom = js_GetAtom(cx, &script->atomMap, atomIndex); obj = fp->varobj; attrs = JSPROP_ENUMERATE; @@ -4298,11 +4366,9 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) OBJ_DROP_PROPERTY(cx, obj2, prop); break; - } - case JSOP_DEFFUN: + BEGIN_LITOPX_CASE(JSOP_DEFFUN, 0) { - jsatomid atomIndex; uintN flags; atomIndex = GET_ATOM_INDEX(pc); @@ -4416,11 +4482,11 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) } #endif OBJ_DROP_PROPERTY(cx, parent, prop); - break; } + END_LITOPX_CASE #if JS_HAS_LEXICAL_CLOSURE - case JSOP_DEFLOCALFUN: + BEGIN_LITOPX_CASE(JSOP_DEFLOCALFUN, VARNO_LEN) /* * Define a local function (i.e., one nested at the top level of * another function), parented by the current scope chain, and @@ -4428,15 +4494,14 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) * This is an optimization over JSOP_DEFFUN that avoids requiring * a call object for the outer function's activation. */ - pc2 = pc; - slot = GET_VARNO(pc2); - pc2 += VARNO_LEN; - atom = GET_ATOM(cx, script, pc2); + slot = GET_VARNO(pc); + atom = js_GetAtom(cx, &script->atomMap, atomIndex); obj = ATOM_TO_OBJECT(atom); fun = (JSFunction *) JS_GetPrivate(cx, obj); parent = fp->scopeChain; if (OBJ_GET_PARENT(cx, obj) != parent) { + SAVE_SP(fp); obj = js_CloneFunctionObject(cx, obj, parent); if (!obj) { ok = JS_FALSE; @@ -4444,16 +4509,16 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) } } fp->vars[slot] = OBJECT_TO_JSVAL(obj); - break; + END_LITOPX_CASE - case JSOP_ANONFUNOBJ: + BEGIN_LITOPX_CASE(JSOP_ANONFUNOBJ, 0) /* Push the specified function object literal. */ - atom = GET_ATOM(cx, script, pc); obj = ATOM_TO_OBJECT(atom); /* If re-parenting, push a clone of the function object. */ parent = fp->scopeChain; if (OBJ_GET_PARENT(cx, obj) != parent) { + SAVE_SP(fp); obj = js_CloneFunctionObject(cx, obj, parent); if (!obj) { ok = JS_FALSE; @@ -4462,11 +4527,10 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) } PUSH_OPND(OBJECT_TO_JSVAL(obj)); obj = NULL; - break; + END_LITOPX_CASE - case JSOP_NAMEDFUNOBJ: + BEGIN_LITOPX_CASE(JSOP_NAMEDFUNOBJ, 0) /* ECMA ed. 3 FunctionExpression: function Identifier [etc.]. */ - atom = GET_ATOM(cx, script, pc); rval = ATOM_KEY(atom); JS_ASSERT(JSVAL_IS_FUNCTION(cx, rval)); @@ -4552,12 +4616,9 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) */ PUSH_OPND(OBJECT_TO_JSVAL(obj)); obj = NULL; - break; - - case JSOP_CLOSURE: - { - jsatomid atomIndex; + END_LITOPX_CASE + BEGIN_LITOPX_CASE(JSOP_CLOSURE, 0) /* * ECMA ed. 3 extension: a named function expression in a compound * statement (not at the top statement level of global code, or at @@ -4566,8 +4627,6 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) * Get immediate operand atom, which is a function object literal. * From it, get the function to close. */ - atomIndex = GET_ATOM_INDEX(pc); - atom = js_GetAtom(cx, &script->atomMap, atomIndex); JS_ASSERT(JSVAL_IS_FUNCTION(cx, ATOM_KEY(atom))); obj = ATOM_TO_OBJECT(atom); @@ -4638,8 +4697,7 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) } #endif OBJ_DROP_PROPERTY(cx, parent, prop); - break; - } + END_LITOPX_CASE #endif /* JS_HAS_LEXICAL_CLOSURE */ #if JS_HAS_GETTER_SETTER @@ -4898,13 +4956,12 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) /* let the code at out try to catch the exception. */ goto out; - case JSOP_INITCATCHVAR: + BEGIN_LITOPX_CASE(JSOP_INITCATCHVAR, 0) /* Load the value into rval, while keeping it live on stack. */ JS_ASSERT(sp - fp->spbase >= 2); rval = FETCH_OPND(-1); /* Get the immediate catch variable name into id. */ - atom = GET_ATOM(cx, script, pc); id = ATOM_TO_JSID(atom); /* Find the object being initialized at top of stack. */ @@ -4921,7 +4978,7 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) /* Now that we're done with rval, pop it. */ sp--; - break; + END_LITOPX_CASE #endif /* JS_HAS_EXCEPTIONS */ #if JS_HAS_INSTANCEOF @@ -4998,13 +5055,11 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) PUSH_OPND(rval); break; - case JSOP_QNAMEPART: - atom = GET_ATOM(cx, script, pc); + BEGIN_LITOPX_CASE(JSOP_QNAMEPART, 0) PUSH_OPND(ATOM_KEY(atom)); - break; + END_LITOPX_CASE - case JSOP_QNAMECONST: - atom = GET_ATOM(cx, script, pc); + BEGIN_LITOPX_CASE(JSOP_QNAMECONST, 0) rval = ATOM_KEY(atom); lval = FETCH_OPND(-1); SAVE_SP(fp); @@ -5014,7 +5069,7 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) goto out; } STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); - break; + END_LITOPX_CASE case JSOP_QNAME: rval = FETCH_OPND(-1); @@ -5194,8 +5249,7 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) STORE_OPND(-1, STRING_TO_JSVAL(str)); break; - case JSOP_XMLOBJECT: - atom = GET_ATOM(cx, script, pc); + BEGIN_LITOPX_CASE(JSOP_XMLOBJECT, 0) SAVE_SP(fp); obj = js_CloneXMLObject(cx, ATOM_TO_OBJECT(atom)); if (!obj) { @@ -5204,10 +5258,9 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) } PUSH_OPND(OBJECT_TO_JSVAL(obj)); obj = NULL; - break; + END_LITOPX_CASE - case JSOP_XMLCDATA: - atom = GET_ATOM(cx, script, pc); + BEGIN_LITOPX_CASE(JSOP_XMLCDATA, 0) str = ATOM_TO_STRING(atom); obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, str); if (!obj) { @@ -5215,10 +5268,9 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) goto out; } PUSH_OPND(OBJECT_TO_JSVAL(obj)); - break; + END_LITOPX_CASE - case JSOP_XMLCOMMENT: - atom = GET_ATOM(cx, script, pc); + BEGIN_LITOPX_CASE(JSOP_XMLCOMMENT, 0) str = ATOM_TO_STRING(atom); obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, str); if (!obj) { @@ -5226,13 +5278,13 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) goto out; } PUSH_OPND(OBJECT_TO_JSVAL(obj)); - break; + END_LITOPX_CASE - case JSOP_XMLPI: - atom = GET_ATOM(cx, script, pc); + BEGIN_LITOPX_CASE(JSOP_XMLPI, 0) str = ATOM_TO_STRING(atom); - atom = GET_ATOM(cx, script, pc + ATOM_INDEX_LEN); - str2 = ATOM_TO_STRING(atom); + rval = FETCH_OPND(-1); + str2 = JSVAL_TO_STRING(rval); + SAVE_SP(fp); obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_PROCESSING_INSTRUCTION, str, str2); @@ -5240,12 +5292,11 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) ok = JS_FALSE; goto out; } - PUSH_OPND(OBJECT_TO_JSVAL(obj)); - break; + STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); + END_LITOPX_CASE - case JSOP_GETMETHOD: + BEGIN_LITOPX_CASE(JSOP_GETMETHOD, 0) /* Get an immediate atom naming the property. */ - atom = GET_ATOM(cx, script, pc); id = ATOM_TO_JSID(atom); FETCH_OBJECT(cx, -1, lval, obj); SAVE_SP(fp); @@ -5264,7 +5315,7 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result) if (!ok) goto out; STORE_OPND(-1, rval); - break; + END_LITOPX_CASE case JSOP_GETFUNNS: ok = js_GetFunctionNamespace(cx, &rval); diff --git a/mozilla/js/src/jsopcode.c b/mozilla/js/src/jsopcode.c index 98599a70a68..c4b04f20cac 100644 --- a/mozilla/js/src/jsopcode.c +++ b/mozilla/js/src/jsopcode.c @@ -149,7 +149,6 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc, const JSCodeSpec *cs; ptrdiff_t len, off, jmplen; uint32 type; - jsbytecode *stop; JSAtom *atom; JSString *str; @@ -185,16 +184,12 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc, fprintf(fp, " %u (%d)", loc + off, off); break; - case JOF_CONST2: case JOF_CONST: - stop = pc + len - 1; - do { - atom = GET_ATOM(cx, script, pc); - str = js_ValueToSource(cx, ATOM_KEY(atom)); - if (!str) - return 0; - fprintf(fp, " %s", JS_GetStringBytes(str)); - } while ((pc += ATOM_INDEX_LEN) < stop); + atom = GET_ATOM(cx, script, pc); + str = js_ValueToSource(cx, ATOM_KEY(atom)); + if (!str) + return 0; + fprintf(fp, " %s", JS_GetStringBytes(str)); break; case JOF_UINT16: @@ -839,6 +834,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) const char *lval, *rval, *xval, *fmt; jsint i, argc; char **argv; + jsatomid atomIndex; JSAtom *atom; JSObject *obj; JSFunction *fun; @@ -863,13 +859,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) (!ATOM_KEYWORD(atom) && js_IsIdentifier(ATOM_TO_STRING(atom))) /* - * Get atom from script's atom map, quote/escape its string appropriately into - * rval, and select fmt from the quoted and unquoted alternatives. + * Given an atom already fetched from jp->script's atom map, quote/escape its + * string appropriately into rval, and select fmt from the quoted and unquoted + * alternatives. */ -#define GET_ATOM_QUOTE_AND_FMT(qfmt, ufmt, rval) \ +#define GET_QUOTE_AND_FMT(qfmt, ufmt, rval) \ JS_BEGIN_MACRO \ jschar quote_; \ - atom = GET_ATOM(cx, jp->script, pc); \ if (!ATOM_IS_IDENTIFIER(atom)) { \ quote_ = '\''; \ fmt = qfmt; \ @@ -882,6 +878,16 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) return JS_FALSE; \ JS_END_MACRO +/* + * Get atom from jp->script's atom map, quote/escape its string appropriately + * into rval, and select fmt from the quoted and unquoted alternatives. + */ +#define GET_ATOM_QUOTE_AND_FMT(qfmt, ufmt, rval) \ + JS_BEGIN_MACRO \ + atom = GET_ATOM(cx, jp->script, pc); \ + GET_QUOTE_AND_FMT(qfmt, ufmt, rval); \ + JS_END_MACRO + cx = ss->sprinter.context; jp = ss->printer; endpc = pc + nb; @@ -939,6 +945,15 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) } } else { switch (op) { +#define BEGIN_LITOPX_CASE(OP) \ + case OP: \ + atomIndex = GET_ATOM_INDEX(pc); \ + do_##OP: \ + atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); + +#define END_LITOPX_CASE \ + break; + case JSOP_NOP: /* * Check for a do-while loop, a for-loop with an empty @@ -1040,14 +1055,22 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) pc += js_CodeSpec[JSOP_NEWINIT].length; LOCAL_ASSERT(*pc == JSOP_EXCEPTION); pc += js_CodeSpec[JSOP_EXCEPTION].length; - LOCAL_ASSERT(*pc == JSOP_INITCATCHVAR); - atom = GET_ATOM(cx, jp->script, pc); + if (*pc == JSOP_LITOPX) { + atomIndex = GET_LITERAL_INDEX(pc); + pc += 1 + LITERAL_INDEX_LEN; + LOCAL_ASSERT(*pc == JSOP_INITCATCHVAR); + ++pc; + } else { + LOCAL_ASSERT(*pc == JSOP_INITCATCHVAR); + atomIndex = GET_ATOM_INDEX(pc); + pc += js_CodeSpec[JSOP_INITCATCHVAR].length; + } + atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); if (!rval) return JS_FALSE; RETRACT(&ss->sprinter, rval); js_printf(jp, "%s", rval); - pc += js_CodeSpec[JSOP_INITCATCHVAR].length; LOCAL_ASSERT(*pc == JSOP_ENTERWITH); pc += js_CodeSpec[JSOP_ENTERWITH].length; @@ -1108,6 +1131,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case JSOP_PUSH: case JSOP_PUSHOBJ: case JSOP_BINDNAME: + do_JSOP_BINDNAME: todo = Sprint(&ss->sprinter, ""); break; @@ -1588,7 +1612,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case JSOP_SETCONST: case JSOP_SETNAME: case JSOP_SETGVAR: - atom = GET_ATOM(cx, jp->script, pc); + atomIndex = GET_ATOM_INDEX(pc); + + do_JSOP_SETCONST: + atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); + do_setname: lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); if (!lval) @@ -1596,6 +1624,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) rval = POP_STR(); if (op == JSOP_SETNAME) (void) PopOff(ss, op); + do_setlval: sn = js_GetSrcNote(jp->script, pc - 1); if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) { @@ -1829,14 +1858,20 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) /* FALL THROUGH */ case JSOP_GETPROP: -#if JS_HAS_XML_SUPPORT - case JSOP_GETMETHOD: -#endif - GET_ATOM_QUOTE_AND_FMT("%s[%s]", "%s.%s", rval); + atom = GET_ATOM(cx, jp->script, pc); + + do_getprop: + GET_QUOTE_AND_FMT("%s[%s]", "%s.%s", rval); lval = POP_STR(); todo = Sprint(&ss->sprinter, fmt, lval, rval); break; +#if JS_HAS_XML_SUPPORT + BEGIN_LITOPX_CASE(JSOP_GETMETHOD) + goto do_getprop; + END_LITOPX_CASE +#endif + case JSOP_SETPROP: GET_ATOM_QUOTE_AND_FMT("%s[%s] %s= %s", "%s.%s %s= %s", xval); rval = POP_STR(); @@ -1925,11 +1960,53 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case JSOP_UINT16: i = (jsint) GET_ATOM_INDEX(pc); + goto do_sprint_int; + + case JSOP_UINT24: + i = (jsint) GET_LITERAL_INDEX(pc); + do_sprint_int: todo = Sprint(&ss->sprinter, "%u", (unsigned) i); break; - case JSOP_NUMBER: - atom = GET_ATOM(cx, jp->script, pc); + case JSOP_LITERAL: + atomIndex = GET_LITERAL_INDEX(pc); + goto do_JSOP_STRING; + + case JSOP_FINDNAME: + atomIndex = GET_LITERAL_INDEX(pc); + todo = Sprint(&ss->sprinter, ""); + if (todo < 0 || !PushOff(ss, todo, op)) + return JS_FALSE; + atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); + goto do_name; + + case JSOP_LITOPX: + atomIndex = GET_LITERAL_INDEX(pc); + op = pc[1 + LITERAL_INDEX_LEN]; + switch (op) { + case JSOP_ANONFUNOBJ: goto do_JSOP_ANONFUNOBJ; + case JSOP_BINDNAME: goto do_JSOP_BINDNAME; + case JSOP_CLOSURE: goto do_JSOP_CLOSURE; + case JSOP_EXPORTNAME: goto do_JSOP_EXPORTNAME; + case JSOP_GETMETHOD: goto do_JSOP_GETMETHOD; + case JSOP_NAMEDFUNOBJ: goto do_JSOP_NAMEDFUNOBJ; + case JSOP_NUMBER: goto do_JSOP_NUMBER; + case JSOP_OBJECT: goto do_JSOP_OBJECT; + case JSOP_QNAMECONST: goto do_JSOP_QNAMECONST; + case JSOP_QNAMEPART: goto do_JSOP_QNAMEPART; + case JSOP_REGEXP: goto do_JSOP_REGEXP; + case JSOP_SETCONST: goto do_JSOP_SETCONST; + case JSOP_STRING: goto do_JSOP_STRING; + case JSOP_XMLCDATA: goto do_JSOP_XMLCDATA; + case JSOP_XMLCOMMENT: goto do_JSOP_XMLCOMMENT; + case JSOP_XMLOBJECT: goto do_JSOP_XMLOBJECT; + case JSOP_XMLPI: goto do_JSOP_XMLPI; + default: JS_ASSERT(0); + } + /* NOTREACHED */ + break; + + BEGIN_LITOPX_CASE(JSOP_NUMBER) val = ATOM_KEY(atom); if (JSVAL_IS_INT(val)) { long ival = (long)JSVAL_TO_INT(val); @@ -1944,22 +2021,27 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) } todo = Sprint(&ss->sprinter, numStr); } - break; + END_LITOPX_CASE - case JSOP_STRING: - atom = GET_ATOM(cx, jp->script, pc); + BEGIN_LITOPX_CASE(JSOP_STRING) rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), (jschar)'"'); if (!rval) return JS_FALSE; todo = STR2OFF(&ss->sprinter, rval); - break; + END_LITOPX_CASE case JSOP_OBJECT: case JSOP_REGEXP: case JSOP_ANONFUNOBJ: case JSOP_NAMEDFUNOBJ: - atom = GET_ATOM(cx, jp->script, pc); + atomIndex = GET_ATOM_INDEX(pc); + + do_JSOP_OBJECT: + do_JSOP_REGEXP: + do_JSOP_ANONFUNOBJ: + do_JSOP_NAMEDFUNOBJ: + atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); if (op == JSOP_OBJECT || op == JSOP_REGEXP) { if (!js_regexp_toString(cx, ATOM_TO_OBJECT(atom), 0, NULL, &val)) { @@ -2196,14 +2278,14 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) "=", rval); break; -#endif /* !JS_BUG_FALLIBLE_EQOPS */ +#endif #if JS_HAS_LEXICAL_CLOSURE - case JSOP_CLOSURE: - atom = GET_ATOM(cx, jp->script, pc); + BEGIN_LITOPX_CASE(JSOP_CLOSURE) JS_ASSERT(ATOM_IS_OBJECT(atom)); goto do_function; -#endif /* JS_HAS_LEXICAL_CLOSURE */ + END_LITOPX_CASE +#endif #if JS_HAS_EXPORT_IMPORT case JSOP_EXPORTALL: @@ -2211,15 +2293,14 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) todo = -2; break; - case JSOP_EXPORTNAME: - atom = GET_ATOM(cx, jp->script, pc); + BEGIN_LITOPX_CASE(JSOP_EXPORTNAME) rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); if (!rval) return JS_FALSE; RETRACT(&ss->sprinter, rval); js_printf(jp, "\texport %s\n", rval); todo = -2; - break; + END_LITOPX_CASE case JSOP_IMPORTALL: lval = POP_STR(); @@ -2291,7 +2372,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) break; case JSOP_INITPROP: - case JSOP_INITCATCHVAR: atom = GET_ATOM(cx, jp->script, pc); xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), (jschar) @@ -2377,19 +2457,18 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) todo = SprintPut(&ss->sprinter, "*", 1); break; - case JSOP_QNAMEPART: - atom = GET_ATOM(cx, jp->script, pc); + BEGIN_LITOPX_CASE(JSOP_QNAMEPART) goto do_name; + END_LITOPX_CASE - case JSOP_QNAMECONST: - atom = GET_ATOM(cx, jp->script, pc); + BEGIN_LITOPX_CASE(JSOP_QNAMECONST) rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); if (!rval) return JS_FALSE; RETRACT(&ss->sprinter, rval); lval = POP_STR(); todo = Sprint(&ss->sprinter, "%s::%s", lval, rval); - break; + END_LITOPX_CASE case JSOP_QNAME: op = JSOP_NOP; /* turn off parens */ @@ -2453,39 +2532,39 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) todo = Sprint(&ss->sprinter, "%s..%s", lval, rval); break; - case JSOP_XMLOBJECT: + BEGIN_LITOPX_CASE(JSOP_XMLOBJECT) atom = GET_ATOM(cx, jp->script, pc); todo = Sprint(&ss->sprinter, "", ATOM_TO_OBJECT(atom)); - break; + END_LITOPX_CASE - case JSOP_XMLCDATA: + BEGIN_LITOPX_CASE(JSOP_XMLCDATA) todo = SprintPut(&ss->sprinter, "script, pc); if (!QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0)) return JS_FALSE; SprintPut(&ss->sprinter, "]]>", 3); - break; + END_LITOPX_CASE - case JSOP_XMLCOMMENT: + BEGIN_LITOPX_CASE(JSOP_XMLCOMMENT) todo = SprintPut(&ss->sprinter, "", 3); - break; + END_LITOPX_CASE - case JSOP_XMLPI: - todo = SprintPut(&ss->sprinter, "script, pc); - if (!QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0)) + BEGIN_LITOPX_CASE(JSOP_XMLPI) + rval = JS_strdup(cx, POP_STR()); + if (!rval) return JS_FALSE; - SprintPut(&ss->sprinter, " ", 1); - atom = GET_ATOM(cx, jp->script, pc + ATOM_INDEX_LEN); - if (!QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0)) + todo = SprintPut(&ss->sprinter, "sprinter, ATOM_TO_STRING(atom), 0) && + SprintPut(&ss->sprinter, " ", 1) >= 0 && + SprintPut(&ss->sprinter, rval, strlen(rval)); + JS_free(cx, (char *)rval); + if (!ok) return JS_FALSE; SprintPut(&ss->sprinter, "?>", 2); - break; + END_LITOPX_CASE case JSOP_GETFUNNS: todo = SprintPut(&ss->sprinter, js_function_str, 8); @@ -2495,6 +2574,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) default: todo = -2; break; + +#undef BEGIN_LITOPX_CASE +#undef END_LITOPX_CASE } } @@ -2516,6 +2598,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) #undef POP_STR #undef LOCAL_ASSERT #undef ATOM_IS_IDENTIFIER +#undef GET_QUOTE_AND_FMT #undef GET_ATOM_QUOTE_AND_FMT return JS_TRUE; diff --git a/mozilla/js/src/jsopcode.h b/mozilla/js/src/jsopcode.h index 4b9f7835be9..237be8c30af 100644 --- a/mozilla/js/src/jsopcode.h +++ b/mozilla/js/src/jsopcode.h @@ -74,7 +74,10 @@ typedef enum JSOp { #define JOF_JUMPX 9 /* signed 32-bit jump offset immediate */ #define JOF_TABLESWITCHX 10 /* extended (32-bit offset) table switch */ #define JOF_LOOKUPSWITCHX 11 /* extended (32-bit offset) lookup switch */ -#define JOF_CONST2 12 /* 2 unsigned 16-bit constant pool indexes */ +#define JOF_UINT24 12 /* extended unsigned 24-bit literal (index) */ +#define JOF_LITOPX 13 /* JOF_UINT24 followed by op being extended, + where op if JOF_CONST has no unsigned 16- + bit immediate operand */ #define JOF_TYPEMASK 0x000f /* mask for above immediate types */ #define JOF_NAME 0x0010 /* name operation */ #define JOF_PROP 0x0020 /* obj.prop operation */ @@ -145,16 +148,36 @@ typedef enum JSOp { #define JUMPX_OFFSET_MIN ((int32)0x80000000) #define JUMPX_OFFSET_MAX ((int32)0x7fffffff) -/* A literal is indexed by a per-script atom map. */ +/* + * A literal is indexed by a per-script atom map. Most scripts have relatively + * few literals, so the standard JOF_CONST format specifies a fixed 16 bits of + * immediate operand index. A script with more than 64K literals must push all + * high-indexed literals on the stack using JSOP_LITERAL, then use JOF_ELEM ops + * instead of JOF_PROP, etc. + */ #define ATOM_INDEX_LEN 2 -#define ATOM_INDEX_HI(index) ((jsbytecode)((index) >> 8)) -#define ATOM_INDEX_LO(index) ((jsbytecode)(index)) +#define ATOM_INDEX_HI(i) ((jsbytecode)((i) >> 8)) +#define ATOM_INDEX_LO(i) ((jsbytecode)(i)) #define GET_ATOM_INDEX(pc) ((jsatomid)(((pc)[1] << 8) | (pc)[2])) -#define SET_ATOM_INDEX(pc,index)((pc)[1] = ATOM_INDEX_HI(index), \ - (pc)[2] = ATOM_INDEX_LO(index)) +#define SET_ATOM_INDEX(pc,i) ((pc)[1] = ATOM_INDEX_HI(i), \ + (pc)[2] = ATOM_INDEX_LO(i)) #define GET_ATOM(cx,script,pc) js_GetAtom((cx), &(script)->atomMap, \ GET_ATOM_INDEX(pc)) -#define ATOM_INDEX_LIMIT_LOG2 16 + +/* A full atom index for JSOP_LITERAL uses 24 bits of immediate operand. */ +#define LITERAL_INDEX_LEN 3 +#define LITERAL_INDEX_HI(i) ((jsbytecode)((i) >> 16)) +#define LITERAL_INDEX_MID(i) ((jsbytecode)((i) >> 8)) +#define LITERAL_INDEX_LO(i) ((jsbytecode)(i)) +#define GET_LITERAL_INDEX(pc) ((jsatomid)(((pc)[1] << 16) | \ + ((pc)[2] << 8) | \ + (pc)[3])) +#define SET_LITERAL_INDEX(pc,i) ((pc)[1] = LITERAL_INDEX_HI(i), \ + (pc)[2] = LITERAL_INDEX_MID(i), \ + (pc)[3] = LITERAL_INDEX_LO(i)) + +/* Atom index limit is determined by SN_3BYTE_OFFSET_FLAG, see jsemit.h. */ +#define ATOM_INDEX_LIMIT_LOG2 23 #define ATOM_INDEX_LIMIT ((uint32)1 << ATOM_INDEX_LIMIT_LOG2) /* Actual argument count operand format helpers. */ diff --git a/mozilla/js/src/jsopcode.tbl b/mozilla/js/src/jsopcode.tbl index 509b6a2de11..044e42e005b 100644 --- a/mozilla/js/src/jsopcode.tbl +++ b/mozilla/js/src/jsopcode.tbl @@ -272,8 +272,11 @@ OPDEF(JSOP_ANONFUNOBJ, 128, "anonfunobj", NULL, 3, 0, 1, 12, JOF_CONST) /* ECMA ed. 3 named function expression. */ OPDEF(JSOP_NAMEDFUNOBJ, 129, "namedfunobj", NULL, 3, 0, 1, 12, JOF_CONST) -/* Like JSOP_INITPROP, but specialized to make a DontDelete property for ECMA ed. 3 catch variables. */ -OPDEF(JSOP_INITCATCHVAR,130, "initcatchvar",NULL, 3, 1, 0, 0, JOF_CONST|JOF_PROP) +/* + * Like JSOP_INITPROP, but specialized to make a DontDelete property for ECMA + * Edition 3 catch variables. + */ +OPDEF(JSOP_INITCATCHVAR,130, "initcatchvar",NULL, 3, 1, 0, 0, JOF_CONST) /* ECMA-mandated parenthesization opcode, which nulls the reference base register, obj; see jsinterp.c. */ OPDEF(JSOP_GROUP, 131, "group", NULL, 1, 0, 0, 0, JOF_BYTE) @@ -366,8 +369,19 @@ OPDEF(JSOP_XMLELTEXPR, 179,"xmleltexpr", NULL, 1, 1, 1, 12, JOF_BYTE) OPDEF(JSOP_XMLOBJECT, 180,"xmlobject", NULL, 3, 0, 1, 12, JOF_CONST) OPDEF(JSOP_XMLCDATA, 181,"xmlcdata", NULL, 3, 0, 1, 12, JOF_CONST) OPDEF(JSOP_XMLCOMMENT, 182,"xmlcomment", NULL, 3, 0, 1, 12, JOF_CONST) -OPDEF(JSOP_XMLPI, 183,"xmlpi", NULL, 5, 0, 1, 12, JOF_CONST2) +OPDEF(JSOP_XMLPI, 183,"xmlpi", NULL, 3, 1, 1, 12, JOF_CONST) OPDEF(JSOP_GETMETHOD, 184,"getmethod", NULL, 3, 1, 1, 11, JOF_CONST|JOF_PROP) OPDEF(JSOP_GETFUNNS, 185,"getfunns", NULL, 1, 0, 1, 12, JOF_BYTE) OPDEF(JSOP_FOREACH, 186,"foreach", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_DELDESC, 187,"deldesc", NULL, 1, 2, 1, 10, JOF_BYTE |JOF_ELEM|JOF_DEL) + +/* + * Opcodes for extended literal addressing, using unsigned 24-bit immediate + * operands to hold integer operands (JSOP_UINT24), extended atom indexes in + * script->atomMap (JSOP_LITERAL, JSOP_FINDNAME), and ops prefixed by such + * atom index immediates (JSOP_LITOPX). See jsemit.c, EmitAtomIndexOp. + */ +OPDEF(JSOP_UINT24, 188,"uint24", NULL, 4, 0, 1, 12, JOF_UINT24) +OPDEF(JSOP_LITERAL, 189,"literal", NULL, 4, 0, 1, 12, JOF_UINT24) +OPDEF(JSOP_FINDNAME, 190,"findname", NULL, 4, 0, 2, 0, JOF_UINT24) +OPDEF(JSOP_LITOPX, 191,"litopx", NULL, 5, 0, 0, 12, JOF_LITOPX)