Bug 716068 - de-OptimizeSpanDeps (r=waldo)

--HG--
extra : rebase_source : 4dd2b3c08f792ceb86c3824b953e88a08f3968cc
This commit is contained in:
Luke Wagner 2012-01-09 11:05:06 -08:00
parent c83e247b29
commit daf1801ebe
18 changed files with 257 additions and 1542 deletions

File diff suppressed because it is too large Load Diff

View File

@ -491,66 +491,6 @@ GenerateBlockId(TreeContext *tc, uint32_t &blockid);
} /* namespace frontend */
struct JumpTarget;
/*
* Span-dependent instructions are jumps whose span (from the jump bytecode to
* the jump target) may require 2 or 4 bytes of immediate operand.
*/
struct SpanDep {
ptrdiff_t top; /* offset of first bytecode in an opcode */
ptrdiff_t offset; /* offset - 1 within opcode of jump operand */
ptrdiff_t before; /* original offset - 1 of jump operand */
JumpTarget *target; /* tagged target pointer or backpatch delta */
};
/*
* Jump targets are stored in an AVL tree, for O(log(n)) lookup with targets
* sorted by offset from left to right, so that targets after a span-dependent
* instruction whose jump offset operand must be extended can be found quickly
* and adjusted upward (toward higher offsets).
*/
struct JumpTarget {
ptrdiff_t offset; /* offset of span-dependent jump target */
int balance; /* AVL tree balance number */
JumpTarget *kids[2]; /* left and right AVL tree child pointers */
};
#define JT_LEFT 0
#define JT_RIGHT 1
#define JT_OTHER_DIR(dir) (1 - (dir))
#define JT_IMBALANCE(dir) (((dir) << 1) - 1)
#define JT_DIR(imbalance) (((imbalance) + 1) >> 1)
/*
* Backpatch deltas are encoded in js::SpanDep::target if JT_TAG_BIT is clear,
* so we can maintain backpatch chains when using span dependency records to
* hold jump offsets that overflow 16 bits.
*/
#define JT_TAG_BIT ((jsword) 1)
#define JT_UNTAG_SHIFT 1
#define JT_SET_TAG(jt) ((JumpTarget *)((jsword)(jt) | JT_TAG_BIT))
#define JT_CLR_TAG(jt) ((JumpTarget *)((jsword)(jt) & ~JT_TAG_BIT))
#define JT_HAS_TAG(jt) ((jsword)(jt) & JT_TAG_BIT)
#define BITS_PER_PTRDIFF (sizeof(ptrdiff_t) * JS_BITS_PER_BYTE)
#define BITS_PER_BPDELTA (BITS_PER_PTRDIFF - 1 - JT_UNTAG_SHIFT)
#define BPDELTA_MAX (((ptrdiff_t)1 << BITS_PER_BPDELTA) - 1)
#define BPDELTA_TO_JT(bp) ((JumpTarget *)((bp) << JT_UNTAG_SHIFT))
#define JT_TO_BPDELTA(jt) ((ptrdiff_t)((jsword)(jt) >> JT_UNTAG_SHIFT))
#define SD_SET_TARGET(sd,jt) ((sd)->target = JT_SET_TAG(jt))
#define SD_GET_TARGET(sd) (JS_ASSERT(JT_HAS_TAG((sd)->target)), \
JT_CLR_TAG((sd)->target))
#define SD_SET_BPDELTA(sd,bp) ((sd)->target = BPDELTA_TO_JT(bp))
#define SD_GET_BPDELTA(sd) (JS_ASSERT(!JT_HAS_TAG((sd)->target)), \
JT_TO_BPDELTA((sd)->target))
/* Avoid asserting twice by expanding SD_GET_TARGET in the "then" clause. */
#define SD_SPAN(sd,pivot) (SD_GET_TARGET(sd) \
? JT_CLR_TAG((sd)->target)->offset - (pivot) \
: 0)
struct TryNode {
JSTryNote note;
TryNode *prev;
@ -629,14 +569,6 @@ struct BytecodeEmitter : public TreeContext
uintN ntrynotes; /* number of allocated so far try notes */
TryNode *lastTryNode; /* the last allocated try node */
SpanDep *spanDeps; /* span dependent instruction records */
JumpTarget *jumpTargets; /* AVL tree of jump target offsets */
JumpTarget *jtFreeList; /* JT_LEFT-linked list of free structs */
uintN numSpanDeps; /* number of span dependencies */
uintN numJumpTargets; /* number of jump targets */
ptrdiff_t spanDepTodo; /* offset from main.base of potentially
unoptimized spandeps */
uintN arrayCompDepth; /* stack depth of array in comprehension */
uintN emitLevel; /* js::frontend::EmitTree recursion level */
@ -801,29 +733,6 @@ Emit3(JSContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1, jsbytecode o
ptrdiff_t
EmitN(JSContext *cx, BytecodeEmitter *bce, JSOp op, size_t extra);
/*
* Unsafe macro to call SetJumpOffset and return false if it does.
*/
#define CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx,bce,pc,off,BAD_EXIT) \
JS_BEGIN_MACRO \
if (!SetJumpOffset(cx, bce, pc, off)) { \
BAD_EXIT; \
} \
JS_END_MACRO
#define CHECK_AND_SET_JUMP_OFFSET(cx,bce,pc,off) \
CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx,bce,pc,off,return JS_FALSE)
#define CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx,bce,off,BAD_EXIT) \
CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx, bce, (bce)->code(off), \
bce->offset() - (off), BAD_EXIT)
#define CHECK_AND_SET_JUMP_OFFSET_AT(cx,bce,off) \
CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx, bce, off, return JS_FALSE)
JSBool
SetJumpOffset(JSContext *cx, BytecodeEmitter *bce, jsbytecode *pc, ptrdiff_t off);
/*
* Push the C-stack-allocated struct at stmt onto the stmtInfo stack.
*/
@ -921,8 +830,8 @@ EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *body);
* Note on adding new source notes: every pair of bytecodes (A, B) where A and
* B have disjoint sets of source notes that could apply to each bytecode may
* reuse the same note type value for two notes (snA, snB) that have the same
* arity, offsetBias, and isSpanDep initializers in JSSrcNoteSpec. This is
* why SRC_IF and SRC_INITPROP have the same value below.
* arity in JSSrcNoteSpec. This is why SRC_IF and SRC_INITPROP have the same
* value below.
*
* Don't forget to update JSXDR_BYTECODE_VERSION in jsxdrapi.h for all such
* incompatible source note or other bytecode changes.
@ -981,11 +890,7 @@ enum SrcNoteType {
};
/*
* Constants for the SRC_DECL source note. Note that span-dependent bytecode
* selection means that any SRC_DECL offset greater than SRC_DECL_LET may need
* to be adjusted, but these "offsets" are too small to span a span-dependent
* instruction, so can be used to denote distinct declaration syntaxes to the
* decompiler.
* Constants for the SRC_DECL source note.
*
* NB: the var_prefix array in jsopcode.c depends on these dense indexes from
* SRC_DECL_VAR through SRC_DECL_LET.
@ -1135,9 +1040,6 @@ inline bool LetDataToGroupAssign(ptrdiff_t w)
struct JSSrcNoteSpec {
const char *name; /* name for disassembly/debugging output */
int8_t arity; /* number of offset operands */
uint8_t offsetBias; /* bias of offset(s) from annotated pc */
int8_t isSpanDep; /* 1 or -1 if offsets could span extended ops,
0 otherwise; sign tells span direction */
};
extern JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[];

View File

@ -7,14 +7,14 @@ function doNothing() { }
function myparent(nested) {
if (nested) {
/* JSOP_CALL to doNothing in myparent with nested = true. */
trap(myparent, 26, "success()");
trap(myparent, 28, "success()");
doNothing();
} else {
doNothing();
}
}
/* JSOP_CALL to doNothing in myparent with nested = false. */
trap(myparent, 37, "myparent(true)");
trap(myparent, 41, "myparent(true)");
function success() {
x = "success";

View File

@ -141,21 +141,16 @@ BytecodeNoFallThrough(JSOp op)
{
switch (op) {
case JSOP_GOTO:
case JSOP_GOTOX:
case JSOP_DEFAULT:
case JSOP_DEFAULTX:
case JSOP_RETURN:
case JSOP_STOP:
case JSOP_RETRVAL:
case JSOP_THROW:
case JSOP_TABLESWITCH:
case JSOP_TABLESWITCHX:
case JSOP_LOOKUPSWITCH:
case JSOP_LOOKUPSWITCHX:
case JSOP_FILTER:
return true;
case JSOP_GOSUB:
case JSOP_GOSUBX:
// these fall through indirectly, after executing a 'finally'.
return false;
default:
@ -407,13 +402,10 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
hasFunctionCalls_ = true;
break;
case JSOP_TABLESWITCH:
case JSOP_TABLESWITCHX: {
case JSOP_TABLESWITCH: {
isInlineable = false;
jsbytecode *pc2 = pc;
unsigned jmplen = (op == JSOP_TABLESWITCH) ? JUMP_OFFSET_LEN : JUMPX_OFFSET_LEN;
unsigned defaultOffset = offset + GetJumpOffset(pc, pc2);
pc2 += jmplen;
unsigned defaultOffset = offset + GET_JUMP_OFFSET(pc);
jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
jsint low = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
jsint high = GET_JUMP_OFFSET(pc2);
@ -425,25 +417,22 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
getCode(defaultOffset).safePoint = true;
for (jsint i = low; i <= high; i++) {
unsigned targetOffset = offset + GetJumpOffset(pc, pc2);
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2);
if (targetOffset != offset) {
if (!addJump(cx, targetOffset, &nextOffset, &forwardJump, stackDepth))
return;
}
getCode(targetOffset).switchTarget = true;
getCode(targetOffset).safePoint = true;
pc2 += jmplen;
pc2 += JUMP_OFFSET_LEN;
}
break;
}
case JSOP_LOOKUPSWITCH:
case JSOP_LOOKUPSWITCHX: {
case JSOP_LOOKUPSWITCH: {
isInlineable = false;
jsbytecode *pc2 = pc;
unsigned jmplen = (op == JSOP_LOOKUPSWITCH) ? JUMP_OFFSET_LEN : JUMPX_OFFSET_LEN;
unsigned defaultOffset = offset + GetJumpOffset(pc, pc2);
pc2 += jmplen;
unsigned defaultOffset = offset + GET_JUMP_OFFSET(pc);
jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
unsigned npairs = GET_UINT16(pc2);
pc2 += UINT16_LEN;
@ -454,12 +443,12 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
while (npairs) {
pc2 += INDEX_LEN;
unsigned targetOffset = offset + GetJumpOffset(pc, pc2);
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2);
if (!addJump(cx, targetOffset, &nextOffset, &forwardJump, stackDepth))
return;
getCode(targetOffset).switchTarget = true;
getCode(targetOffset).safePoint = true;
pc2 += jmplen;
pc2 += JUMP_OFFSET_LEN;
npairs--;
}
break;
@ -558,13 +547,12 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
uint32_t type = JOF_TYPE(js_CodeSpec[op].format);
/* Check basic jump opcodes, which may or may not have a fallthrough. */
if (type == JOF_JUMP || type == JOF_JUMPX) {
if (type == JOF_JUMP) {
/* Some opcodes behave differently on their branching path. */
unsigned newStackDepth = stackDepth;
switch (op) {
case JSOP_CASE:
case JSOP_CASEX:
/* Case instructions do not push the lvalue back when branching. */
newStackDepth--;
break;
@ -572,7 +560,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
default:;
}
unsigned targetOffset = offset + GetJumpOffset(pc, pc);
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc);
if (!addJump(cx, targetOffset, &nextOffset, &forwardJump, newStackDepth))
return;
}
@ -593,11 +581,11 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
}
JS_ASSERT(nextcode->stackDepth == stackDepth);
if (type == JOF_JUMP || type == JOF_JUMPX)
if (type == JOF_JUMP)
nextcode->jumpFallthrough = true;
/* Treat the fallthrough of a branch instruction as a jump target. */
if (type == JOF_JUMP || type == JOF_JUMPX)
if (type == JOF_JUMP)
nextcode->jumpTarget = true;
else
nextcode->fallthrough = true;
@ -748,9 +736,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
}
case JSOP_LOOKUPSWITCH:
case JSOP_LOOKUPSWITCHX:
case JSOP_TABLESWITCH:
case JSOP_TABLESWITCHX:
/* Restore all saved variables. :FIXME: maybe do this precisely. */
for (unsigned i = 0; i < savedCount; i++) {
LifetimeVariable &var = *saved[i];
@ -790,7 +776,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
}
uint32_t type = JOF_TYPE(js_CodeSpec[op].format);
if (type == JOF_JUMP || type == JOF_JUMPX) {
if (type == JOF_JUMP) {
/*
* Forward jumps need to pull in all variables which are live at
* their target offset --- the variables live before the jump are
@ -852,8 +838,8 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
jsbytecode *entrypc = script->code + entry;
if (JSOp(*entrypc) == JSOP_GOTO || JSOp(*entrypc) == JSOP_GOTOX)
loop->entry = entry + GetJumpOffset(entrypc, entrypc);
if (JSOp(*entrypc) == JSOP_GOTO)
loop->entry = entry + GET_JUMP_OFFSET(entrypc);
else
loop->entry = targetOffset;
} else {
@ -1431,12 +1417,9 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
* and all case statements or exception/finally handlers.
*/
case JSOP_TABLESWITCH:
case JSOP_TABLESWITCHX: {
jsbytecode *pc2 = pc;
unsigned jmplen = (op == JSOP_TABLESWITCH) ? JUMP_OFFSET_LEN : JUMPX_OFFSET_LEN;
unsigned defaultOffset = offset + GetJumpOffset(pc, pc2);
pc2 += jmplen;
case JSOP_TABLESWITCH: {
unsigned defaultOffset = offset + GET_JUMP_OFFSET(pc);
jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
jsint low = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
jsint high = GET_JUMP_OFFSET(pc2);
@ -1445,20 +1428,17 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
checkBranchTarget(cx, defaultOffset, branchTargets, values, stackDepth);
for (jsint i = low; i <= high; i++) {
unsigned targetOffset = offset + GetJumpOffset(pc, pc2);
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2);
if (targetOffset != offset)
checkBranchTarget(cx, targetOffset, branchTargets, values, stackDepth);
pc2 += jmplen;
pc2 += JUMP_OFFSET_LEN;
}
break;
}
case JSOP_LOOKUPSWITCH:
case JSOP_LOOKUPSWITCHX: {
jsbytecode *pc2 = pc;
unsigned jmplen = (op == JSOP_LOOKUPSWITCH) ? JUMP_OFFSET_LEN : JUMPX_OFFSET_LEN;
unsigned defaultOffset = offset + GetJumpOffset(pc, pc2);
pc2 += jmplen;
case JSOP_LOOKUPSWITCH: {
unsigned defaultOffset = offset + GET_JUMP_OFFSET(pc);
jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
unsigned npairs = GET_UINT16(pc2);
pc2 += UINT16_LEN;
@ -1466,9 +1446,9 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
while (npairs) {
pc2 += INDEX_LEN;
unsigned targetOffset = offset + GetJumpOffset(pc, pc2);
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2);
checkBranchTarget(cx, targetOffset, branchTargets, values, stackDepth);
pc2 += jmplen;
pc2 += JUMP_OFFSET_LEN;
npairs--;
}
break;
@ -1495,7 +1475,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
}
uint32_t type = JOF_TYPE(js_CodeSpec[op].format);
if (type == JOF_JUMP || type == JOF_JUMPX) {
if (type == JOF_JUMP) {
unsigned targetOffset = FollowBranch(cx, script, offset);
checkBranchTarget(cx, targetOffset, branchTargets, values, stackDepth);

View File

@ -209,9 +209,7 @@ GetDefCount(JSScript *script, unsigned offset)
*/
switch (JSOp(*pc)) {
case JSOP_OR:
case JSOP_ORX:
case JSOP_AND:
case JSOP_ANDX:
return 1;
case JSOP_FILTER:
return 2;
@ -288,15 +286,6 @@ ExtendedUse(jsbytecode *pc)
}
}
static inline ptrdiff_t
GetJumpOffset(jsbytecode *pc, jsbytecode *pc2)
{
uint32_t type = JOF_OPTYPE(*pc);
if (JOF_TYPE_IS_EXTENDED_JUMP(type))
return GET_JUMPX_OFFSET(pc2);
return GET_JUMP_OFFSET(pc2);
}
static inline JSOp
ReverseCompareOp(JSOp op)
{
@ -324,12 +313,12 @@ FollowBranch(JSContext *cx, JSScript *script, unsigned offset)
* inserted by the emitter.
*/
jsbytecode *pc = script->code + offset;
unsigned targetOffset = offset + GetJumpOffset(pc, pc);
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc);
if (targetOffset < offset) {
jsbytecode *target = script->code + targetOffset;
JSOp nop = JSOp(*target);
if (nop == JSOP_GOTO || nop == JSOP_GOTOX)
return targetOffset + GetJumpOffset(target, target);
if (nop == JSOP_GOTO)
return targetOffset + GET_JUMP_OFFSET(target);
}
return targetOffset;
}

View File

@ -3207,9 +3207,7 @@ CheckNextTest(jsbytecode *pc)
case JSOP_IFNE:
case JSOP_NOT:
case JSOP_OR:
case JSOP_ORX:
case JSOP_AND:
case JSOP_ANDX:
case JSOP_TYPEOF:
case JSOP_TYPEOFEXPR:
return true;
@ -3402,11 +3400,8 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_NOP:
case JSOP_LOOPHEAD:
case JSOP_GOTO:
case JSOP_GOTOX:
case JSOP_IFEQ:
case JSOP_IFEQX:
case JSOP_IFNE:
case JSOP_IFNEX:
case JSOP_LINENO:
case JSOP_DEFCONST:
case JSOP_LEAVEWITH:
@ -3415,11 +3410,9 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_ENDITER:
case JSOP_THROWING:
case JSOP_GOSUB:
case JSOP_GOSUBX:
case JSOP_RETSUB:
case JSOP_CONDSWITCH:
case JSOP_DEFAULT:
case JSOP_DEFAULTX:
case JSOP_POPN:
case JSOP_STARTXML:
case JSOP_STARTXMLEXPR:
@ -3435,12 +3428,9 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_DEBUGGER:
case JSOP_SETCALL:
case JSOP_TABLESWITCH:
case JSOP_TABLESWITCHX:
case JSOP_LOOKUPSWITCH:
case JSOP_LOOKUPSWITCHX:
case JSOP_TRY:
case JSOP_LABEL:
case JSOP_LABELX:
break;
/* Bytecodes pushing values of known type. */
@ -3521,9 +3511,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
break;
case JSOP_OR:
case JSOP_ORX:
case JSOP_AND:
case JSOP_ANDX:
/* OR/AND push whichever operand determined the result. */
poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
break;
@ -4053,7 +4041,6 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
break;
case JSOP_CASE:
case JSOP_CASEX:
poppedTypes(pc, 1)->addSubset(cx, &pushed[0]);
break;
@ -5440,9 +5427,7 @@ IgnorePushed(const jsbytecode *pc, unsigned index)
/* Value not determining result is not pushed by OR/AND. */
case JSOP_OR:
case JSOP_ORX:
case JSOP_AND:
case JSOP_ANDX:
return (index == 0);
/* Holes tracked separately. */

View File

@ -1794,6 +1794,17 @@ ADD_EMPTY_CASE(JSOP_NOP)
ADD_EMPTY_CASE(JSOP_UNUSED0)
ADD_EMPTY_CASE(JSOP_UNUSED1)
ADD_EMPTY_CASE(JSOP_UNUSED2)
ADD_EMPTY_CASE(JSOP_UNUSED3)
ADD_EMPTY_CASE(JSOP_UNUSED4)
ADD_EMPTY_CASE(JSOP_UNUSED5)
ADD_EMPTY_CASE(JSOP_UNUSED6)
ADD_EMPTY_CASE(JSOP_UNUSED7)
ADD_EMPTY_CASE(JSOP_UNUSED8)
ADD_EMPTY_CASE(JSOP_UNUSED9)
ADD_EMPTY_CASE(JSOP_UNUSED10)
ADD_EMPTY_CASE(JSOP_UNUSED11)
ADD_EMPTY_CASE(JSOP_UNUSED12)
ADD_EMPTY_CASE(JSOP_UNUSED13)
ADD_EMPTY_CASE(JSOP_CONDSWITCH)
ADD_EMPTY_CASE(JSOP_TRY)
#if JS_HAS_XML_SUPPORT
@ -1806,9 +1817,6 @@ END_EMPTY_CASES
BEGIN_CASE(JSOP_LABEL)
END_CASE(JSOP_LABEL)
BEGIN_CASE(JSOP_LABELX)
END_CASE(JSOP_LABELX)
check_backedge:
{
CHECK_BRANCH();
@ -2024,64 +2032,6 @@ BEGIN_CASE(JSOP_AND)
}
END_CASE(JSOP_AND)
BEGIN_CASE(JSOP_DEFAULTX)
regs.sp--;
/* FALL THROUGH */
BEGIN_CASE(JSOP_GOTOX)
{
len = GET_JUMPX_OFFSET(regs.pc);
BRANCH(len);
}
END_CASE(JSOP_GOTOX);
BEGIN_CASE(JSOP_IFEQX)
{
bool cond;
Value *_;
POP_BOOLEAN(cx, _, cond);
if (cond == false) {
len = GET_JUMPX_OFFSET(regs.pc);
BRANCH(len);
}
}
END_CASE(JSOP_IFEQX)
BEGIN_CASE(JSOP_IFNEX)
{
bool cond;
Value *_;
POP_BOOLEAN(cx, _, cond);
if (cond != false) {
len = GET_JUMPX_OFFSET(regs.pc);
BRANCH(len);
}
}
END_CASE(JSOP_IFNEX)
BEGIN_CASE(JSOP_ORX)
{
bool cond;
Value *_;
VALUE_TO_BOOLEAN(cx, _, cond);
if (cond == true) {
len = GET_JUMPX_OFFSET(regs.pc);
DO_NEXT_OP(len);
}
}
END_CASE(JSOP_ORX)
BEGIN_CASE(JSOP_ANDX)
{
bool cond;
Value *_;
VALUE_TO_BOOLEAN(cx, _, cond);
if (cond == JS_FALSE) {
len = GET_JUMPX_OFFSET(regs.pc);
DO_NEXT_OP(len);
}
}
END_CASE(JSOP_ANDX)
/*
* If the index value at sp[n] is not an int that fits in a jsval, it could
* be an object (an XML QName, AttributeName, or AnyName), but only if we are
@ -2378,18 +2328,6 @@ BEGIN_CASE(JSOP_CASE)
}
END_CASE(JSOP_CASE)
BEGIN_CASE(JSOP_CASEX)
{
bool cond;
STRICT_EQUALITY_OP(==, cond);
if (cond) {
regs.sp--;
len = GET_JUMPX_OFFSET(regs.pc);
BRANCH(len);
}
}
END_CASE(JSOP_CASEX)
#undef STRICT_EQUALITY_OP
#define RELATIONAL_OP(OP) \
@ -3316,57 +3254,14 @@ END_VARLEN_CASE
}
{
BEGIN_CASE(JSOP_TABLESWITCHX)
{
jsbytecode *pc2 = regs.pc;
len = GET_JUMPX_OFFSET(pc2);
/*
* ECMAv2+ forbids conversion of discriminant, so we will skip to the
* default case if the discriminant isn't already an int jsval. (This
* opcode is emitted only for dense jsint-domain switches.)
*/
const Value &rref = *--regs.sp;
int32_t i;
if (rref.isInt32()) {
i = rref.toInt32();
} else if (rref.isDouble() && rref.toDouble() == 0) {
/* Treat -0 (double) as 0. */
i = 0;
} else {
DO_NEXT_OP(len);
}
pc2 += JUMPX_OFFSET_LEN;
jsint low = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
jsint high = GET_JUMP_OFFSET(pc2);
i -= low;
if ((jsuint)i < (jsuint)(high - low + 1)) {
pc2 += JUMP_OFFSET_LEN + JUMPX_OFFSET_LEN * i;
jsint off = (jsint) GET_JUMPX_OFFSET(pc2);
if (off)
len = off;
}
}
END_VARLEN_CASE
}
{
BEGIN_CASE(JSOP_LOOKUPSWITCHX)
BEGIN_CASE(JSOP_LOOKUPSWITCH)
{
jsint off;
off = JUMPX_OFFSET_LEN;
goto do_lookup_switch;
BEGIN_CASE(JSOP_LOOKUPSWITCH)
off = JUMP_OFFSET_LEN;
do_lookup_switch:
/*
* JSOP_LOOKUPSWITCH and JSOP_LOOKUPSWITCHX are never used if any atom
* index in it would exceed 64K limit.
* JSOP_LOOKUPSWITCH are never used if any atom index in it would exceed
* 64K limit.
*/
JS_ASSERT(atoms == script->atoms);
jsbytecode *pc2 = regs.pc;
@ -3421,9 +3316,7 @@ BEGIN_CASE(JSOP_LOOKUPSWITCH)
#undef SEARCH_PAIRS
end_lookup_switch:
len = (op == JSOP_LOOKUPSWITCH)
? GET_JUMP_OFFSET(pc2)
: GET_JUMPX_OFFSET(pc2);
len = GET_JUMP_OFFSET(pc2);
}
END_VARLEN_CASE
}
@ -4199,16 +4092,7 @@ END_CASE(JSOP_SHARPINIT)
BEGIN_CASE(JSOP_GOSUB)
PUSH_BOOLEAN(false);
jsint i = (regs.pc - script->code) + JSOP_GOSUB_LENGTH;
PUSH_INT32(i);
len = GET_JUMP_OFFSET(regs.pc);
END_VARLEN_CASE
}
{
BEGIN_CASE(JSOP_GOSUBX)
PUSH_BOOLEAN(false);
jsint i = (regs.pc - script->code) + JSOP_GOSUBX_LENGTH;
len = GET_JUMPX_OFFSET(regs.pc);
PUSH_INT32(i);
END_VARLEN_CASE
}

View File

@ -145,17 +145,6 @@ Dup(const char *chars, DupBuffer *cb)
return cb->append(chars, strlen(chars) + 1);
}
static ptrdiff_t
GetJumpOffset(jsbytecode *pc, jsbytecode *pc2)
{
uint32_t type;
type = JOF_OPTYPE(*pc);
if (JOF_TYPE_IS_EXTENDED_JUMP(type))
return GET_JUMPX_OFFSET(pc2);
return GET_JUMP_OFFSET(pc2);
}
uintN
js_GetIndexFromBytecode(JSScript *script, jsbytecode *pc, ptrdiff_t pcoff)
{
@ -185,37 +174,27 @@ js_GetIndexFromBytecode(JSScript *script, jsbytecode *pc, ptrdiff_t pcoff)
size_t
js_GetVariableBytecodeLength(jsbytecode *pc)
{
uintN jmplen, ncases;
uintN ncases;
jsint low, high;
JSOp op = JSOp(*pc);
JS_ASSERT(js_CodeSpec[op].length == -1);
switch (op) {
case JSOP_TABLESWITCHX:
jmplen = JUMPX_OFFSET_LEN;
goto do_table;
case JSOP_TABLESWITCH:
jmplen = JUMP_OFFSET_LEN;
do_table:
/* Structure: default-jump case-low case-high case1-jump ... */
pc += jmplen;
pc += JUMP_OFFSET_LEN;
low = GET_JUMP_OFFSET(pc);
pc += JUMP_OFFSET_LEN;
high = GET_JUMP_OFFSET(pc);
ncases = (uintN)(high - low + 1);
return 1 + jmplen + INDEX_LEN + INDEX_LEN + ncases * jmplen;
return 1 + 3 * JUMP_OFFSET_LEN + ncases * JUMP_OFFSET_LEN;
case JSOP_LOOKUPSWITCHX:
jmplen = JUMPX_OFFSET_LEN;
goto do_lookup;
default:
JS_ASSERT(op == JSOP_LOOKUPSWITCH);
jmplen = JUMP_OFFSET_LEN;
do_lookup:
/* Structure: default-jump case-count (case1-value case1-jump) ... */
pc += jmplen;
JS_ASSERT(op == JSOP_LOOKUPSWITCH);
pc += JUMP_OFFSET_LEN;
ncases = GET_UINT16(pc);
return 1 + jmplen + INDEX_LEN + ncases * (INDEX_LEN + jmplen);
return 1 + JUMP_OFFSET_LEN + INDEX_LEN + ncases * (INDEX_LEN + JUMP_OFFSET_LEN);
}
}
@ -585,9 +564,8 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
}
break;
case JOF_JUMP:
case JOF_JUMPX: {
ptrdiff_t off = GetJumpOffset(pc, pc);
case JOF_JUMP: {
ptrdiff_t off = GET_JUMP_OFFSET(pc);
Sprint(sp, " %u (%+d)", loc + (intN) off, (intN) off);
break;
}
@ -628,47 +606,39 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
}
case JOF_TABLESWITCH:
case JOF_TABLESWITCHX:
{
jsbytecode *pc2;
jsint i, low, high;
ptrdiff_t jmplen = (type == JOF_TABLESWITCH) ? JUMP_OFFSET_LEN : JUMPX_OFFSET_LEN;
pc2 = pc;
ptrdiff_t off = GetJumpOffset(pc, pc2);
pc2 += jmplen;
ptrdiff_t off = GET_JUMP_OFFSET(pc);
jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
low = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
high = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
Sprint(sp, " defaultOffset %d low %d high %d", intN(off), low, high);
for (i = low; i <= high; i++) {
off = GetJumpOffset(pc, pc2);
off = GET_JUMP_OFFSET(pc2);
Sprint(sp, "\n\t%d: %d", i, intN(off));
pc2 += jmplen;
pc2 += JUMP_OFFSET_LEN;
}
len = 1 + pc2 - pc;
break;
}
case JOF_LOOKUPSWITCH:
case JOF_LOOKUPSWITCHX:
{
jsbytecode *pc2;
jsatomid npairs;
ptrdiff_t jmplen = (type == JOF_LOOKUPSWITCH) ? JUMP_OFFSET_LEN : JUMPX_OFFSET_LEN;
pc2 = pc;
ptrdiff_t off = GetJumpOffset(pc, pc2);
pc2 += jmplen;
ptrdiff_t off = GET_JUMP_OFFSET(pc);
jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
npairs = GET_UINT16(pc2);
pc2 += UINT16_LEN;
Sprint(sp, " offset %d npairs %u", intN(off), uintN(npairs));
while (npairs) {
uint16_t constIndex = GET_INDEX(pc2);
pc2 += INDEX_LEN;
off = GetJumpOffset(pc, pc2);
pc2 += jmplen;
off = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
JSAutoByteString bytes;
if (!ToDisassemblySource(cx, script->getConst(constIndex), &bytes))
@ -2386,10 +2356,10 @@ SprintNormalFor(JSContext *cx, JSPrinter *jp, SprintStack *ss, const char *initP
*/
jsbytecode *pc2 = pc;
if (cond != tail) {
LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX);
pc2 += (*pc == JSOP_GOTO) ? JSOP_GOTO_LENGTH : JSOP_GOTOX_LENGTH;
LOCAL_ASSERT(*pc == JSOP_GOTO);
pc2 += JSOP_GOTO_LENGTH;
}
LOCAL_ASSERT(tail + GetJumpOffset(pc+tail, pc+tail) == pc2 - pc);
LOCAL_ASSERT(tail + GET_JUMP_OFFSET(pc + tail) == pc2 - pc);
if (cond != tail) {
/* Decompile the loop condition. */
@ -2823,8 +2793,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
/* Second instruction (TRACE) contains offset to JSOP_IFNE */
sn = js_GetSrcNote(jp->script, pc);
tail = js_GetSrcNoteOffset(sn, 0);
LOCAL_ASSERT(pc[tail] == JSOP_IFNE ||
pc[tail] == JSOP_IFNEX);
LOCAL_ASSERT(pc[tail] == JSOP_IFNE);
js_printf(jp, "\tdo {\n");
jp->indent += 4;
DECOMPILE_CODE(pc, tail);
@ -2880,7 +2849,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
break;
case JSOP_LABEL:
case JSOP_LABELX:
sn = js_GetSrcNote(jp->script, pc);
todo = -2;
switch (sn ? SN_TYPE(sn) : SRC_NULL) {
@ -2947,11 +2915,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
break;
case JSOP_GOSUB:
case JSOP_GOSUBX:
/*
* JSOP_GOSUB and GOSUBX have no effect on the decompiler's
* string stack because the next op in bytecode order finds
* the stack balanced by a JSOP_RETSUB executed elsewhere.
* JSOP_GOSUB has no effect on the decompiler's string stack
* because the next op in bytecode order finds the stack
* balanced by a JSOP_RETSUB executed elsewhere.
*/
todo = -2;
break;
@ -3276,7 +3243,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
return NULL;
js_printf(jp, "%s", POP_STR());
pc += len;
LOCAL_ASSERT(*pc == JSOP_IFEQ || *pc == JSOP_IFEQX);
LOCAL_ASSERT(*pc == JSOP_IFEQ);
pc += js_CodeSpec[*pc].length;
}
@ -3466,12 +3433,12 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
LOCAL_ASSERT(js_GetSrcNote(jp->script, pc) == NULL);
LOCAL_ASSERT(ss->top - 1 == blockObj.stackDepth() + blockObj.slotCount());
jsbytecode *nextpc = pc + JSOP_ENTERLET1_LENGTH;
if (*nextpc == JSOP_GOTO || *nextpc == JSOP_GOTOX) {
if (*nextpc == JSOP_GOTO) {
LOCAL_ASSERT(SN_TYPE(js_GetSrcNote(jp->script, nextpc)) == SRC_FOR_IN);
} else {
LOCAL_ASSERT(*nextpc == JSOP_CONDSWITCH ||
*nextpc == JSOP_TABLESWITCH || *nextpc == JSOP_TABLESWITCHX ||
*nextpc == JSOP_LOOKUPSWITCH || *nextpc == JSOP_LOOKUPSWITCHX);
*nextpc == JSOP_TABLESWITCH ||
*nextpc == JSOP_LOOKUPSWITCH);
}
DupBuffer rhs(cx);
@ -3781,7 +3748,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
break;
case JSOP_GOTO:
case JSOP_GOTOX:
sn = js_GetSrcNote(jp->script, pc);
switch (sn ? SN_TYPE(sn) : SRC_NULL) {
case SRC_FOR_IN:
@ -3813,7 +3779,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
* JSOP_MOREITER or JSOP_IFNE, though we do quick asserts
* to check that they are there.
*/
cond = GetJumpOffset(pc, pc);
cond = GET_JUMP_OFFSET(pc);
next = js_GetSrcNoteOffset(sn, 0);
tail = js_GetSrcNoteOffset(sn, 1);
JS_ASSERT(pc[next] == JSOP_POP);
@ -3871,12 +3837,12 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
}
pc += tail;
LOCAL_ASSERT(*pc == JSOP_IFNE || *pc == JSOP_IFNEX);
LOCAL_ASSERT(*pc == JSOP_IFNE);
len = js_CodeSpec[*pc].length;
break;
case SRC_WHILE:
cond = GetJumpOffset(pc, pc);
cond = GET_JUMP_OFFSET(pc);
tail = js_GetSrcNoteOffset(sn, 0);
DECOMPILE_CODE(pc + cond, tail - cond);
js_printf(jp, "\twhile (");
@ -3888,7 +3854,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
jp->indent -= 4;
js_printf(jp, "\t}\n");
pc += tail;
LOCAL_ASSERT(*pc == JSOP_IFNE || *pc == JSOP_IFNEX);
LOCAL_ASSERT(*pc == JSOP_IFNE);
len = js_CodeSpec[*pc].length;
todo = -2;
break;
@ -3926,12 +3892,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
break;
case JSOP_IFEQ:
case JSOP_IFEQX:
{
JSBool elseif = JS_FALSE;
if_again:
len = GetJumpOffset(pc, pc);
len = GET_JUMP_OFFSET(pc);
sn = js_GetSrcNote(jp->script, pc);
switch (sn ? SN_TYPE(sn) : SRC_NULL) {
@ -3959,9 +3924,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
DECOMPILE_CODE(pc + oplen, tail - oplen);
jp->indent -= 4;
pc += tail;
LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX);
LOCAL_ASSERT(*pc == JSOP_GOTO);
oplen = js_CodeSpec[*pc].length;
len = GetJumpOffset(pc, pc);
len = GET_JUMP_OFFSET(pc);
js_printf(jp, "\t} else");
/*
@ -4001,9 +3966,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
lval = PopStrDupe(ss, op, &lvalpc);
pushpc = pc;
pc += len;
LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX);
LOCAL_ASSERT(*pc == JSOP_GOTO);
oplen = js_CodeSpec[*pc].length;
len = GetJumpOffset(pc, pc);
len = GET_JUMP_OFFSET(pc);
DECOMPILE_CODE(pc + oplen, len - oplen);
rval = PopStrDupe(ss, op, &rvalpc);
todo = ss->sprinter.offset;
@ -4021,18 +3986,16 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
}
case JSOP_IFNE:
case JSOP_IFNEX:
LOCAL_ASSERT(0);
break;
case JSOP_OR:
case JSOP_ORX:
xval = "||";
do_logical_connective:
/* Top of stack is the first clause in a disjunction (||). */
lval = PopStrDupe(ss, op, &lvalpc);
done = pc + GetJumpOffset(pc, pc);
done = pc + GET_JUMP_OFFSET(pc);
pushpc = pc;
pc += len;
JS_ASSERT(*pc == JSOP_POP);
@ -4056,7 +4019,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
break;
case JSOP_AND:
case JSOP_ANDX:
xval = "&&";
goto do_logical_connective;
@ -4847,19 +4809,16 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
goto sprint_string;
case JSOP_TABLESWITCH:
case JSOP_TABLESWITCHX:
{
ptrdiff_t jmplen, off, off2;
ptrdiff_t off, off2;
jsint j, n, low, high;
TableEntry *table, *tmp;
sn = js_GetSrcNote(jp->script, pc);
LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH);
len = js_GetSrcNoteOffset(sn, 0);
jmplen = (op == JSOP_TABLESWITCH) ? JUMP_OFFSET_LEN : JUMPX_OFFSET_LEN;
pc2 = pc;
off = GetJumpOffset(pc, pc2);
pc2 += jmplen;
off = GET_JUMP_OFFSET(pc);
pc2 = pc + JUMP_OFFSET_LEN;
low = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
high = GET_JUMP_OFFSET(pc2);
@ -4877,7 +4836,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
return NULL;
for (i = j = 0; i < n; i++) {
table[j].label = NULL;
off2 = GetJumpOffset(pc, pc2);
off2 = GET_JUMP_OFFSET(pc2);
if (off2) {
sn = js_GetSrcNote(jp->script, pc2);
if (sn) {
@ -4889,7 +4848,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
table[j].order = j;
j++;
}
pc2 += jmplen;
pc2 += JUMP_OFFSET_LEN;
}
tmp = (TableEntry *)
cx->malloc_((size_t)j * sizeof *table);
@ -4912,20 +4871,16 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
}
case JSOP_LOOKUPSWITCH:
case JSOP_LOOKUPSWITCHX:
{
ptrdiff_t jmplen, off, off2;
ptrdiff_t off, off2;
jsatomid npairs, k;
TableEntry *table;
sn = js_GetSrcNote(jp->script, pc);
LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH);
len = js_GetSrcNoteOffset(sn, 0);
jmplen = (op == JSOP_LOOKUPSWITCH) ? JUMP_OFFSET_LEN
: JUMPX_OFFSET_LEN;
pc2 = pc;
off = GetJumpOffset(pc, pc2);
pc2 += jmplen;
off = GET_JUMP_OFFSET(pc);
pc2 = pc + JUMP_OFFSET_LEN;
npairs = GET_UINT16(pc2);
pc2 += UINT16_LEN;
@ -4943,8 +4898,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
}
uint16_t constIndex = GET_INDEX(pc2);
pc2 += INDEX_LEN;
off2 = GetJumpOffset(pc, pc2);
pc2 += jmplen;
off2 = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
table[k].key = jp->script->getConst(constIndex);
table[k].offset = off2;
}
@ -4977,9 +4932,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
off2 = off;
for (ncases = 0; off2 != 0; ncases++) {
pc2 += off2;
LOCAL_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT ||
*pc2 == JSOP_CASEX || *pc2 == JSOP_DEFAULTX);
if (*pc2 == JSOP_DEFAULT || *pc2 == JSOP_DEFAULTX) {
LOCAL_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT);
if (*pc2 == JSOP_DEFAULT) {
/* End of cases, but count default as a case. */
off2 = 0;
} else {
@ -5002,12 +4956,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
off2 = off;
for (i = 0; i < ncases; i++) {
pc2 += off2;
LOCAL_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT ||
*pc2 == JSOP_CASEX || *pc2 == JSOP_DEFAULTX);
LOCAL_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT);
caseOff = pc2 - pc;
table[i].key = INT_TO_JSVAL((jsint) caseOff);
table[i].offset = caseOff + GetJumpOffset(pc2, pc2);
if (*pc2 == JSOP_CASE || *pc2 == JSOP_CASEX) {
table[i].offset = caseOff + GET_JUMP_OFFSET(pc2);
if (*pc2 == JSOP_CASE) {
sn = js_GetSrcNote(jp->script, pc2);
LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_PCDELTA);
off2 = js_GetSrcNoteOffset(sn, 0);
@ -5021,7 +4974,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
*/
off = JSVAL_TO_INT(table[ncases-1].key);
pc2 = pc + off;
off += GetJumpOffset(pc2, pc2);
off += GET_JUMP_OFFSET(pc2);
ok = DecompileSwitch(ss, table, (uintN)ncases, pc, len, off,
JS_TRUE);
@ -5033,7 +4986,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
}
case JSOP_CASE:
case JSOP_CASEX:
{
lval = PopStr(ss, op, &lvalpc);
if (!lval)
@ -5773,8 +5725,7 @@ DecompileExpression(JSContext *cx, JSScript *script, JSFunction *fun,
JSOp op = (JSOp) *pc;
/* None of these stack-writing ops generates novel values. */
JS_ASSERT(op != JSOP_CASE && op != JSOP_CASEX &&
op != JSOP_DUP && op != JSOP_DUP2);
JS_ASSERT(op != JSOP_CASE && op != JSOP_DUP && op != JSOP_DUP2);
/*
* |this| could convert to a very long object initialiser, so cite it by
@ -5897,7 +5848,6 @@ SimulateOp(JSContext *cx, JSScript *script, JSOp op, const JSCodeSpec *cs,
break;
case JSOP_CASE:
case JSOP_CASEX:
/* Keep the switch value. */
JS_ASSERT(ndefs == 1);
break;
@ -5961,9 +5911,9 @@ ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target,
/*
* A (C ? T : E) expression requires skipping either T (if target is in
* E) or both T and E (if target is after the whole expression) before
* adjusting pcdepth based on the JSOP_IFEQ or JSOP_IFEQX at pc that
* tests condition C. We know that the stack depth can't change from
* what it was with C on top of stack.
* adjusting pcdepth based on the JSOP_IFEQ at pc that tests condition
* C. We know that the stack depth can't change from what it was with
* C on top of stack.
*/
jssrcnote *sn = js_GetSrcNote(script, pc);
if (sn && SN_TYPE(sn) == SRC_COND) {
@ -5971,11 +5921,11 @@ ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target,
if (pc + jmpoff < target) {
pc += jmpoff;
op = JSOp(*pc);
JS_ASSERT(op == JSOP_GOTO || op == JSOP_GOTOX);
JS_ASSERT(op == JSOP_GOTO);
cs = &js_CodeSpec[op];
oplen = cs->length;
JS_ASSERT(oplen > 0);
ptrdiff_t jmplen = GetJumpOffset(pc, pc);
ptrdiff_t jmplen = GET_JUMP_OFFSET(pc);
if (pc + jmplen < target) {
oplen = (uintN) jmplen;
continue;

View File

@ -83,9 +83,6 @@ typedef enum JSOp {
#define JOF_QARG 6 /* quickened get/set function argument ops */
#define JOF_LOCAL 7 /* var or block-local variable */
#define JOF_SLOTATOM 8 /* uint16_t slot + constant index */
#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_UINT24 12 /* extended unsigned 24-bit literal (index) */
#define JOF_UINT8 13 /* uint8_t immediate, e.g. top 8 bits of 24-bit
atom index */
@ -148,7 +145,7 @@ typedef enum JSOp {
#define JOF_OPMODE(op) JOF_MODE(js_CodeSpec[op].format)
#define JOF_TYPE_IS_EXTENDED_JUMP(t) \
((unsigned)((t) - JOF_JUMPX) <= (unsigned)(JOF_LOOKUPSWITCHX - JOF_JUMPX))
((unsigned)((t) - JOF_JUMP) <= (unsigned)(JOF_LOOKUPSWITCH - JOF_JUMP))
/*
* Immediate operand getters, setters, and bounds.
@ -162,48 +159,25 @@ typedef enum JSOp {
#define SET_UINT16(pc,i) ((pc)[1] = UINT16_HI(i), (pc)[2] = UINT16_LO(i))
#define UINT16_LIMIT ((uintN)1 << 16)
/* Short (2-byte signed offset) relative jump macros. */
#define JUMP_OFFSET_LEN 2
#define JUMP_OFFSET_HI(off) ((jsbytecode)((off) >> 8))
#define JUMP_OFFSET_LO(off) ((jsbytecode)(off))
#define GET_JUMP_OFFSET(pc) (int16_t(GET_UINT16(pc)))
#define SET_JUMP_OFFSET(pc,off) ((pc)[1] = JUMP_OFFSET_HI(off), \
(pc)[2] = JUMP_OFFSET_LO(off))
#define JUMP_OFFSET_MIN ((int16_t)0x8000)
#define JUMP_OFFSET_MAX ((int16_t)0x7fff)
/* Helpers for accessing the offsets of jump opcodes. */
#define JUMP_OFFSET_LEN 4
#define JUMP_OFFSET_MIN INT32_MIN
#define JUMP_OFFSET_MAX INT32_MAX
/*
* When a short jump won't hold a relative offset, its 2-byte immediate offset
* operand is an unsigned index of a span-dependency record, maintained until
* code generation finishes -- after which some (but we hope not nearly all)
* span-dependent jumps must be extended (see js::frontend::OptimizeSpanDeps in
* frontend/BytecodeEmitter.cpp).
*
* If the span-dependency record index overflows SPANDEP_INDEX_MAX, the jump
* offset will contain SPANDEP_INDEX_HUGE, indicating that the record must be
* found (via binary search) by its "before span-dependency optimization" pc
* offset (from script main entry point).
*/
#define GET_SPANDEP_INDEX(pc) (uint16_t(GET_UINT16(pc)))
#define SET_SPANDEP_INDEX(pc,i) ((pc)[1] = JUMP_OFFSET_HI(i), \
(pc)[2] = JUMP_OFFSET_LO(i))
#define SPANDEP_INDEX_MAX ((uint16_t)0xfffe)
#define SPANDEP_INDEX_HUGE ((uint16_t)0xffff)
static JS_ALWAYS_INLINE int32_t
GET_JUMP_OFFSET(jsbytecode *pc)
{
return (pc[1] << 24) | (pc[2] << 16) | (pc[3] << 8) | pc[4];
}
/* Ultimately, if short jumps won't do, emit long (4-byte signed) offsets. */
#define JUMPX_OFFSET_LEN 4
#define JUMPX_OFFSET_B3(off) ((jsbytecode)((off) >> 24))
#define JUMPX_OFFSET_B2(off) ((jsbytecode)((off) >> 16))
#define JUMPX_OFFSET_B1(off) ((jsbytecode)((off) >> 8))
#define JUMPX_OFFSET_B0(off) ((jsbytecode)(off))
#define GET_JUMPX_OFFSET(pc) (int32_t(((pc)[1] << 24) | ((pc)[2] << 16) \
| ((pc)[3] << 8) | (pc)[4]))
#define SET_JUMPX_OFFSET(pc,off)((pc)[1] = JUMPX_OFFSET_B3(off), \
(pc)[2] = JUMPX_OFFSET_B2(off), \
(pc)[3] = JUMPX_OFFSET_B1(off), \
(pc)[4] = JUMPX_OFFSET_B0(off))
#define JUMPX_OFFSET_MIN (int32_t(0x80000000))
#define JUMPX_OFFSET_MAX (int32_t(0x7fffffff))
static JS_ALWAYS_INLINE void
SET_JUMP_OFFSET(jsbytecode *pc, int32_t off)
{
pc[1] = (jsbytecode)(off >> 24);
pc[2] = (jsbytecode)(off >> 16);
pc[3] = (jsbytecode)(off >> 8);
pc[4] = (jsbytecode)off;
}
/*
* A literal is indexed by a per-script atom or object maps. Most scripts
@ -532,7 +506,7 @@ FlowsIntoNext(JSOp op)
{
/* JSOP_YIELD is considered to flow into the next instruction, like JSOP_CALL. */
return op != JSOP_STOP && op != JSOP_RETURN && op != JSOP_RETRVAL && op != JSOP_THROW &&
op != JSOP_GOTO && op != JSOP_GOTOX && op != JSOP_RETSUB;
op != JSOP_GOTO && op != JSOP_RETSUB;
}
/*

View File

@ -70,9 +70,9 @@
* 2 , JSOP_POP with SRC_PCDELTA, JSOP_RETURN
* 3 =, +=, etc. JSOP_SETNAME, etc. (all JOF_SET);
* let (...) ... and JSOP_LEAVEBLOCKEXPR
* 4 ?: JSOP_IFEQ, JSOP_IFEQX
* 5 || JSOP_OR, JSOP_ORX
* 6 && JSOP_AND, JSOP_ANDX
* 4 ?: JSOP_IFEQ
* 5 || JSOP_OR
* 6 && JSOP_AND
* 7 | JSOP_BITOR
* 8 ^ JSOP_BITXOR
* 9 & JSOP_BITAND
@ -118,9 +118,9 @@ OPDEF(JSOP_POPV, 2, "popv", NULL, 1, 1, 0, 2, JOF_BYTE)
OPDEF(JSOP_ENTERWITH, 3, "enterwith", NULL, 1, 1, 1, 0, JOF_BYTE|JOF_PARENHEAD)
OPDEF(JSOP_LEAVEWITH, 4, "leavewith", NULL, 1, 1, 0, 0, JOF_BYTE)
OPDEF(JSOP_RETURN, 5, "return", NULL, 1, 1, 0, 2, JOF_BYTE)
OPDEF(JSOP_GOTO, 6, "goto", NULL, 3, 0, 0, 0, JOF_JUMP)
OPDEF(JSOP_IFEQ, 7, "ifeq", NULL, 3, 1, 0, 4, JOF_JUMP|JOF_DETECTING)
OPDEF(JSOP_IFNE, 8, "ifne", NULL, 3, 1, 0, 0, JOF_JUMP|JOF_PARENHEAD)
OPDEF(JSOP_GOTO, 6, "goto", NULL, 5, 0, 0, 0, JOF_JUMP)
OPDEF(JSOP_IFEQ, 7, "ifeq", NULL, 5, 1, 0, 4, JOF_JUMP|JOF_DETECTING)
OPDEF(JSOP_IFNE, 8, "ifne", NULL, 5, 1, 0, 0, JOF_JUMP|JOF_PARENHEAD)
/* Get the arguments object for the current, lightweight function activation. */
OPDEF(JSOP_ARGUMENTS, 9, js_arguments_str, js_arguments_str, 1, 0, 1, 18, JOF_BYTE)
@ -187,11 +187,11 @@ OPDEF(JSOP_NULL, 64, js_null_str, js_null_str, 1, 0, 1, 19, JOF_BYTE)
OPDEF(JSOP_THIS, 65, js_this_str, js_this_str, 1, 0, 1, 19, JOF_BYTE)
OPDEF(JSOP_FALSE, 66, js_false_str, js_false_str, 1, 0, 1, 19, JOF_BYTE)
OPDEF(JSOP_TRUE, 67, js_true_str, js_true_str, 1, 0, 1, 19, JOF_BYTE)
OPDEF(JSOP_OR, 68, "or", NULL, 3, 1, 1, 5, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC)
OPDEF(JSOP_AND, 69, "and", NULL, 3, 1, 1, 6, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC)
OPDEF(JSOP_OR, 68, "or", NULL, 5, 1, 1, 5, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC)
OPDEF(JSOP_AND, 69, "and", NULL, 5, 1, 1, 6, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC)
/* The switch bytecodes have variable length. */
OPDEF(JSOP_TABLESWITCH, 70, "tableswitch", NULL, -1, 1, 0, 0, JOF_TABLESWITCH|JOF_DETECTING|JOF_PARENHEAD)
OPDEF(JSOP_TABLESWITCH, 70, "tableswitch", NULL, -1, 1, 0, 0, JOF_TABLESWITCH|JOF_DETECTING|JOF_PARENHEAD)
OPDEF(JSOP_LOOKUPSWITCH, 71, "lookupswitch", NULL, -1, 1, 0, 0, JOF_LOOKUPSWITCH|JOF_DETECTING|JOF_PARENHEAD)
/* New, infallible/transitive identity ops. */
@ -211,7 +211,7 @@ OPDEF(JSOP_SETCALL, 74, "setcall", NULL, 1, 1, 2, 18, JOF_BYTE)
*
* JSOP_MOREITER stores the next iterated value into cx->iterValue and pushes
* true if another value is available, and false otherwise. It is followed
* immediately by JSOP_IFNE{,X}.
* immediately by JSOP_IFNE.
*
* JSOP_ENDITER cleans up after the loop. It uses the slot above the iterator
* for temporary GC rooting.
@ -275,8 +275,8 @@ OPDEF(JSOP_LOCALDEC, 104,"localdec", NULL, 3, 0, 1, 15, JOF_LOCAL|
OPDEF(JSOP_LEAVEFORLETIN, 105,"leaveforletin",NULL, 1, 0, 0, 0, JOF_BYTE)
/* The argument is the offset to the next statement and is used by IonMonkey. */
OPDEF(JSOP_LABEL, 106,"label", NULL, 3, 0, 0, 0, JOF_JUMP)
OPDEF(JSOP_LABELX, 107,"labelx", NULL, 5, 0, 0, 0, JOF_JUMPX)
OPDEF(JSOP_LABEL, 106,"label", NULL, 5, 0, 0, 0, JOF_JUMP)
OPDEF(JSOP_UNUSED3, 107,"unused3", NULL, 1, 0, 0, 0, JOF_BYTE)
/* Like JSOP_FUNAPPLY but for f.call instead of f.apply. */
OPDEF(JSOP_FUNCALL, 108,"funcall", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
@ -299,7 +299,7 @@ OPDEF(JSOP_INSTANCEOF,114,js_instanceof_str,js_instanceof_str,1,2,1,11,JOF_BYTE|
OPDEF(JSOP_DEBUGGER, 115,"debugger", NULL, 1, 0, 0, 0, JOF_BYTE)
/* gosub/retsub for finally handling */
OPDEF(JSOP_GOSUB, 116,"gosub", NULL, 3, 0, 0, 0, JOF_JUMP)
OPDEF(JSOP_GOSUB, 116,"gosub", NULL, 5, 0, 0, 0, JOF_JUMP)
OPDEF(JSOP_RETSUB, 117,"retsub", NULL, 1, 2, 0, 0, JOF_BYTE)
/* More exception handling ops. */
@ -314,8 +314,8 @@ OPDEF(JSOP_LINENO, 119,"lineno", NULL, 3, 0, 0, 0, JOF_UINT16
* lval if false; and DEFAULT is POP lval and GOTO.
*/
OPDEF(JSOP_CONDSWITCH,120,"condswitch", NULL, 1, 0, 0, 0, JOF_BYTE|JOF_PARENHEAD)
OPDEF(JSOP_CASE, 121,"case", NULL, 3, 2, 1, 0, JOF_JUMP|JOF_TMPSLOT2)
OPDEF(JSOP_DEFAULT, 122,"default", NULL, 3, 1, 0, 0, JOF_JUMP)
OPDEF(JSOP_CASE, 121,"case", NULL, 5, 2, 1, 0, JOF_JUMP)
OPDEF(JSOP_DEFAULT, 122,"default", NULL, 5, 1, 0, 0, JOF_JUMP)
/*
* ECMA-compliant call to eval op
@ -380,20 +380,20 @@ OPDEF(JSOP_CALLFCSLOT, 137,"callfcslot", NULL, 3, 0, 1, 19, JOF_UINT16
OPDEF(JSOP_DEFLOCALFUN, 138,"deflocalfun",NULL, 5, 0, 0, 0, JOF_SLOTOBJECT|JOF_DECLARING|JOF_TMPSLOT)
/* Extended jumps. */
OPDEF(JSOP_GOTOX, 139,"gotox", NULL, 5, 0, 0, 0, JOF_JUMPX)
OPDEF(JSOP_IFEQX, 140,"ifeqx", NULL, 5, 1, 0, 4, JOF_JUMPX|JOF_DETECTING)
OPDEF(JSOP_IFNEX, 141,"ifnex", NULL, 5, 1, 0, 0, JOF_JUMPX|JOF_PARENHEAD)
OPDEF(JSOP_ORX, 142,"orx", NULL, 5, 1, 1, 5, JOF_JUMPX|JOF_DETECTING)
OPDEF(JSOP_ANDX, 143,"andx", NULL, 5, 1, 1, 6, JOF_JUMPX|JOF_DETECTING)
OPDEF(JSOP_GOSUBX, 144,"gosubx", NULL, 5, 0, 0, 0, JOF_JUMPX)
OPDEF(JSOP_CASEX, 145,"casex", NULL, 5, 2, 1, 0, JOF_JUMPX)
OPDEF(JSOP_DEFAULTX, 146,"defaultx", NULL, 5, 1, 0, 0, JOF_JUMPX)
OPDEF(JSOP_TABLESWITCHX, 147,"tableswitchx",NULL, -1, 1, 0, 0, JOF_TABLESWITCHX|JOF_DETECTING|JOF_PARENHEAD)
OPDEF(JSOP_LOOKUPSWITCHX, 148,"lookupswitchx",NULL, -1, 1, 0, 0, JOF_LOOKUPSWITCHX|JOF_DETECTING|JOF_PARENHEAD)
OPDEF(JSOP_UNUSED4, 139,"unused4", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED5, 140,"unused5", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED6, 141,"unused6", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED7, 142,"unused7", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED8, 143,"unused8", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED9, 144,"unused9", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED10, 145,"unused10", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED11, 146,"unused11", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED12, 147,"unused12", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED13, 148,"unused13", NULL, 1, 0, 0, 0, JOF_BYTE)
/* Placeholders for a real jump opcode set during backpatch chain fixup. */
OPDEF(JSOP_BACKPATCH, 149,"backpatch",NULL, 3, 0, 0, 0, JOF_JUMP|JOF_BACKPATCH)
OPDEF(JSOP_BACKPATCH_POP, 150,"backpatch_pop",NULL, 3, 1, 0, 0, JOF_JUMP|JOF_BACKPATCH)
OPDEF(JSOP_BACKPATCH, 149,"backpatch",NULL, 5, 0, 0, 0, JOF_JUMP|JOF_BACKPATCH)
OPDEF(JSOP_BACKPATCH_POP, 150,"backpatch_pop",NULL, 5, 1, 0, 0, JOF_JUMP|JOF_BACKPATCH)
/* Set pending exception from the stack, to trigger rethrow. */
OPDEF(JSOP_THROWING, 151,"throwing", NULL, 1, 1, 0, 0, JOF_BYTE)
@ -427,8 +427,8 @@ OPDEF(JSOP_BINDXMLNAME, 170,"bindxmlname",NULL, 1, 1, 2, 3, JOF_BYTE|J
OPDEF(JSOP_SETXMLNAME, 171,"setxmlname", NULL, 1, 3, 1, 3, JOF_BYTE|JOF_SET|JOF_DETECTING)
OPDEF(JSOP_XMLNAME, 172,"xmlname", NULL, 1, 1, 1, 19, JOF_BYTE)
OPDEF(JSOP_DESCENDANTS, 173,"descendants",NULL, 1, 2, 1, 18, JOF_BYTE)
OPDEF(JSOP_FILTER, 174,"filter", NULL, 3, 1, 1, 0, JOF_JUMP)
OPDEF(JSOP_ENDFILTER, 175,"endfilter", NULL, 3, 2, 1, 18, JOF_JUMP)
OPDEF(JSOP_FILTER, 174,"filter", NULL, 5, 1, 1, 0, JOF_JUMP)
OPDEF(JSOP_ENDFILTER, 175,"endfilter", NULL, 5, 2, 1, 18, JOF_JUMP)
OPDEF(JSOP_TOXML, 176,"toxml", NULL, 1, 1, 1, 19, JOF_BYTE)
OPDEF(JSOP_TOXMLLIST, 177,"toxmllist", NULL, 1, 1, 1, 19, JOF_BYTE)
OPDEF(JSOP_XMLTAGEXPR, 178,"xmltagexpr", NULL, 1, 1, 1, 0, JOF_BYTE)

View File

@ -1646,7 +1646,6 @@ mjit::Compiler::generateMethod()
END_CASE(JSOP_RETURN)
BEGIN_CASE(JSOP_GOTO)
BEGIN_CASE(JSOP_GOTOX)
BEGIN_CASE(JSOP_DEFAULT)
{
unsigned targetOffset = FollowBranch(cx, script, PC - script->code);
@ -1681,10 +1680,8 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_IFEQ)
BEGIN_CASE(JSOP_IFNE)
BEGIN_CASE(JSOP_IFEQX)
BEGIN_CASE(JSOP_IFNEX)
{
jsbytecode *target = PC + GetJumpOffset(PC, PC);
jsbytecode *target = PC + GET_JUMP_OFFSET(PC);
fixDoubleTypes(target);
if (!jsop_ifneq(op, target))
return Compile_Error;
@ -2148,7 +2145,6 @@ mjit::Compiler::generateMethod()
END_CASE(JSOP_AND)
BEGIN_CASE(JSOP_TABLESWITCH)
BEGIN_CASE(JSOP_TABLESWITCHX)
/*
* Note: there is no need to syncForBranch for the various targets of
* switch statement. The liveness analysis has already marked these as
@ -2224,11 +2220,9 @@ mjit::Compiler::generateMethod()
updatePCCounters(PC, &codeStart, &countersUpdated);
jsbytecode *target = &PC[JSOP_MOREITER_LENGTH];
JSOp next = JSOp(*target);
JS_ASSERT(next == JSOP_IFNE || next == JSOP_IFNEX);
JS_ASSERT(next == JSOP_IFNE);
target += (next == JSOP_IFNE)
? GET_JUMP_OFFSET(target)
: GET_JUMPX_OFFSET(target);
target += GET_JUMP_OFFSET(target);
fixDoubleTypes(target);
if (!iterMore(target))
@ -2487,9 +2481,6 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_LABEL)
END_CASE(JSOP_LABEL)
BEGIN_CASE(JSOP_LABELX)
END_CASE(JSOP_LABELX)
BEGIN_CASE(JSOP_DEFFUN)
{
uint32_t index = fullAtomIndex(PC);
@ -6795,11 +6786,10 @@ mjit::Compiler::jsop_tableswitch(jsbytecode *pc)
#else
jsbytecode *originalPC = pc;
JSOp op = JSOp(*originalPC);
JS_ASSERT(op == JSOP_TABLESWITCH || op == JSOP_TABLESWITCHX);
JS_ASSERT(op == JSOP_TABLESWITCH);
uint32_t defaultTarget = GetJumpOffset(pc, pc);
unsigned jumpLength = (op == JSOP_TABLESWITCHX) ? JUMPX_OFFSET_LEN : JUMP_OFFSET_LEN;
pc += jumpLength;
uint32_t defaultTarget = GET_JUMP_OFFSET(pc);
pc += JUMP_OFFSET_LEN;
jsint low = GET_JUMP_OFFSET(pc);
pc += JUMP_OFFSET_LEN;
@ -6851,12 +6841,12 @@ mjit::Compiler::jsop_tableswitch(jsbytecode *pc)
jumpTables.append(jt);
for (int i = 0; i < numJumps; i++) {
uint32_t target = GetJumpOffset(originalPC, pc);
uint32_t target = GET_JUMP_OFFSET(pc);
if (!target)
target = defaultTarget;
uint32_t offset = (originalPC + target) - script->code;
jumpTableOffsets.append(offset);
pc += jumpLength;
pc += JUMP_OFFSET_LEN;
}
if (low != 0)
masm.sub32(Imm32(low), dataReg);

View File

@ -729,7 +729,7 @@ private:
static inline Assembler::Condition
GetStubCompareCondition(JSOp fused)
{
return (fused == JSOP_IFEQ) ? Assembler::Zero : Assembler::NonZero;
return fused == JSOP_IFEQ ? Assembler::Zero : Assembler::NonZero;
}
/* Fast builtins. */

View File

@ -789,13 +789,12 @@ mjit::Compiler::booleanJumpScript(JSOp op, jsbytecode *target)
if (op == JSOP_AND || op == JSOP_OR) {
frame.syncForBranch(target, Uses(0));
} else {
JS_ASSERT(op == JSOP_IFEQ || op == JSOP_IFEQX ||
op == JSOP_IFNE || op == JSOP_IFNEX);
JS_ASSERT(op == JSOP_IFEQ || op == JSOP_IFNE);
frame.syncForBranch(target, Uses(1));
}
FrameEntry *fe = frame.peek(-1);
Assembler::Condition cond = (op == JSOP_IFNE || op == JSOP_IFNEX || op == JSOP_OR)
Assembler::Condition cond = (op == JSOP_IFNE || op == JSOP_OR)
? Assembler::NonZero
: Assembler::Zero;
@ -859,7 +858,7 @@ mjit::Compiler::jsop_ifneq(JSOp op, jsbytecode *target)
frame.pop();
if (op == JSOP_IFEQ || op == JSOP_IFEQX)
if (op == JSOP_IFEQ)
b = !b;
if (b) {
if (!frame.syncForBranch(target, Uses(0)))

View File

@ -1054,18 +1054,16 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
bool takeBranch = false;
switch (JSOp(*nextpc)) {
case JSOP_IFNE:
case JSOP_IFNEX:
takeBranch = returnReg != NULL;
break;
case JSOP_IFEQ:
case JSOP_IFEQX:
takeBranch = returnReg == NULL;
break;
default:
JS_NOT_REACHED("Bad branch op");
}
if (takeBranch)
f.regs.pc = nextpc + analyze::GetJumpOffset(nextpc, nextpc);
f.regs.pc = nextpc + GET_JUMP_OFFSET(nextpc);
else
f.regs.pc = nextpc + GetBytecodeLength(nextpc);
break;

View File

@ -1921,15 +1921,10 @@ LoopState::analyzeLoopBody(unsigned frame)
case JSOP_LOCALINC:
case JSOP_LOCALDEC:
case JSOP_IFEQ:
case JSOP_IFEQX:
case JSOP_IFNE:
case JSOP_IFNEX:
case JSOP_AND:
case JSOP_ANDX:
case JSOP_OR:
case JSOP_ORX:
case JSOP_GOTO:
case JSOP_GOTOX:
break;
case JSOP_ADD:

View File

@ -1555,15 +1555,13 @@ void * JS_FASTCALL
stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
{
jsbytecode * const originalPC = origPc;
jsbytecode *pc = originalPC;
JSOp op = JSOp(*originalPC);
JS_ASSERT(op == JSOP_TABLESWITCH || op == JSOP_TABLESWITCHX);
uint32_t jumpOffset = js::analyze::GetJumpOffset(originalPC, pc);
unsigned jumpLength = (op == JSOP_TABLESWITCHX) ? JUMPX_OFFSET_LEN : JUMP_OFFSET_LEN;
pc += jumpLength;
JS_ASSERT(op == JSOP_TABLESWITCH);
uint32_t jumpOffset = GET_JUMP_OFFSET(originalPC);
jsbytecode *pc = originalPC + JUMP_OFFSET_LEN;
/* Note: compiler adjusts the stack beforehand. */
Value rval = f.regs.sp[-1];
@ -1590,9 +1588,8 @@ stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
tableIdx -= low;
if ((jsuint) tableIdx < (jsuint)(high - low + 1)) {
pc += jumpLength * tableIdx;
uint32_t candidateOffset = js::analyze::GetJumpOffset(originalPC, pc);
if (candidateOffset)
pc += JUMP_OFFSET_LEN * tableIdx;
if (uint32_t candidateOffset = GET_JUMP_OFFSET(pc))
jumpOffset = candidateOffset;
}
}

View File

@ -1827,12 +1827,8 @@ UpdateSwitchTableBounds(JSContext *cx, JSScript *script, uintN offset,
pc = script->code + offset;
op = JSOp(*pc);
switch (op) {
case JSOP_TABLESWITCHX:
jmplen = JUMPX_OFFSET_LEN;
goto jump_table;
case JSOP_TABLESWITCH:
jmplen = JUMP_OFFSET_LEN;
jump_table:
pc += jmplen;
low = GET_JUMP_OFFSET(pc);
pc += JUMP_OFFSET_LEN;
@ -1841,12 +1837,8 @@ UpdateSwitchTableBounds(JSContext *cx, JSScript *script, uintN offset,
n = high - low + 1;
break;
case JSOP_LOOKUPSWITCHX:
jmplen = JUMPX_OFFSET_LEN;
goto lookup_table;
case JSOP_LOOKUPSWITCH:
jmplen = JUMP_OFFSET_LEN;
lookup_table:
pc += jmplen;
n = GET_INDEX(pc);
pc += INDEX_LEN;
@ -1885,7 +1877,7 @@ SrcNotes(JSContext *cx, JSScript *script, Sprinter *sp)
name = "case";
} else {
JSOp op = JSOp(script->code[offset]);
JS_ASSERT(op == JSOP_LABEL || op == JSOP_LABELX);
JS_ASSERT(op == JSOP_LABEL);
}
}
Sprint(sp, "%3u: %4u %5u [%4u] %-8s", uintN(sn - notes), lineno, offset, delta, name);
@ -1944,7 +1936,7 @@ SrcNotes(JSContext *cx, JSScript *script, Sprinter *sp)
}
case SRC_SWITCH: {
JSOp op = JSOp(script->code[offset]);
if (op == JSOP_GOTO || op == JSOP_GOTOX)
if (op == JSOP_GOTO)
break;
Sprint(sp, " length %u", uintN(js_GetSrcNoteOffset(sn, 0)));
uintN caseOff = (uintN) js_GetSrcNoteOffset(sn, 1);

View File

@ -2129,22 +2129,16 @@ class FlowGraphSummary : public Vector<size_t> {
if (js_CodeSpec[op].type() == JOF_JUMP) {
addEdge(lineno, r.frontOffset() + GET_JUMP_OFFSET(r.frontPC()));
} else if (js_CodeSpec[op].type() == JOF_JUMPX) {
addEdge(lineno, r.frontOffset() + GET_JUMPX_OFFSET(r.frontPC()));
} else if (op == JSOP_TABLESWITCH || op == JSOP_TABLESWITCHX ||
op == JSOP_LOOKUPSWITCH || op == JSOP_LOOKUPSWITCHX) {
bool table = op == JSOP_TABLESWITCH || op == JSOP_TABLESWITCHX;
bool big = op == JSOP_TABLESWITCHX || op == JSOP_LOOKUPSWITCHX;
} else if (op == JSOP_TABLESWITCH || op == JSOP_LOOKUPSWITCH) {
jsbytecode *pc = r.frontPC();
size_t offset = r.frontOffset();
ptrdiff_t step = big ? JUMPX_OFFSET_LEN : JUMP_OFFSET_LEN;
size_t defaultOffset = offset + (big ? GET_JUMPX_OFFSET(pc) : GET_JUMP_OFFSET(pc));
ptrdiff_t step = JUMP_OFFSET_LEN;
size_t defaultOffset = offset + GET_JUMP_OFFSET(pc);
pc += step;
addEdge(lineno, defaultOffset);
jsint ncases;
if (table) {
if (op == JSOP_TABLESWITCH) {
jsint low = GET_JUMP_OFFSET(pc);
pc += JUMP_OFFSET_LEN;
ncases = GET_JUMP_OFFSET(pc) - low + 1;
@ -2156,9 +2150,9 @@ class FlowGraphSummary : public Vector<size_t> {
}
for (jsint i = 0; i < ncases; i++) {
if (!table)
if (op == JSOP_LOOKUPSWITCH)
pc += INDEX_LEN;
size_t target = offset + (big ? GET_JUMPX_OFFSET(pc) : GET_JUMP_OFFSET(pc));
size_t target = offset + GET_JUMP_OFFSET(pc);
addEdge(lineno, target);
pc += step;
}