Bug 838813 part 12 - Remove SRC_DESTRUCTLET. r=njn.

--HG--
extra : rebase_source : d488c8834a0a0c45b688e2f3aefbcef7e108aa45
This commit is contained in:
Jason Orendorff 2013-02-08 17:21:51 -06:00
parent 13aa192cc9
commit 561c40e9d6
2 changed files with 15 additions and 137 deletions

View File

@ -2918,107 +2918,14 @@ EmitDestructuringOpsHelper(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn,
return true;
}
static ptrdiff_t
OpToDeclType(JSOp op)
{
switch (op) {
case JSOP_NOP:
return SRC_DECL_LET;
case JSOP_DEFCONST:
return SRC_DECL_CONST;
case JSOP_DEFVAR:
return SRC_DECL_VAR;
default:
return SRC_DECL_NONE;
}
}
/*
* This utility accumulates a set of SRC_DESTRUCTLET notes which need to be
* backpatched with the offset from JSOP_DUP to JSOP_LET0.
*
* Also record whether the let head was a group assignment ([x,y] = [a,b])
* (which implies no SRC_DESTRUCTLET notes).
*/
class LetNotes
{
struct Pair {
ptrdiff_t dup;
unsigned index;
Pair(ptrdiff_t dup, unsigned index) : dup(dup), index(index) {}
};
Vector<Pair> notes;
bool groupAssign;
DebugOnly<bool> updateCalled;
public:
LetNotes(JSContext *cx) : notes(cx), groupAssign(false), updateCalled(false) {}
~LetNotes() {
JS_ASSERT_IF(!notes.allocPolicy().context()->isExceptionPending(), updateCalled);
}
void setGroupAssign() {
JS_ASSERT(notes.empty());
groupAssign = true;
}
bool isGroupAssign() const {
return groupAssign;
}
bool append(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t dup, unsigned index) {
JS_ASSERT(!groupAssign);
JS_ASSERT(SN_TYPE(bce->notes() + index) == SRC_DESTRUCTLET);
if (!notes.append(Pair(dup, index)))
return false;
/*
* Pessimistically inflate each srcnote. That way, there is no danger
* of inflation during update() (which would invalidate all indices).
*/
if (!SetSrcNoteOffset(cx, bce, index, 0, SN_MAX_OFFSET))
return false;
JS_ASSERT(bce->notes()[index + 1] & SN_3BYTE_OFFSET_FLAG);
return true;
}
/* This should be called exactly once, right before JSOP_ENTERLET0. */
bool update(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t offset) {
JS_ASSERT(!updateCalled);
for (size_t i = 0; i < notes.length(); ++i) {
JS_ASSERT(offset > notes[i].dup);
JS_ASSERT(*bce->code(notes[i].dup) == JSOP_DUP);
JS_ASSERT(bce->notes()[notes[i].index + 1] & SN_3BYTE_OFFSET_FLAG);
if (!SetSrcNoteOffset(cx, bce, notes[i].index, 0, offset - notes[i].dup))
return false;
}
updateCalled = true;
return true;
}
};
static bool
EmitDestructuringOps(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t declType, ParseNode *pn,
LetNotes *letNotes = NULL)
EmitDestructuringOps(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool isLet = false)
{
/*
* If we're called from a variable declaration, help the decompiler by
* annotating the first JSOP_DUP that EmitDestructuringOpsHelper emits.
* If the destructuring initialiser is empty, our helper will emit a
* JSOP_DUP followed by a JSOP_POP for the decompiler.
*/
if (letNotes) {
ptrdiff_t index = NewSrcNote2(cx, bce, SRC_DESTRUCTLET, 0);
if (index < 0 || !letNotes->append(cx, bce, bce->offset(), (unsigned)index))
return false;
}
/*
* Call our recursive helper to emit the destructuring assignments and
* related stack manipulations.
*/
VarEmitOption emitOption = letNotes ? PushInitialValues : InitializeVars;
VarEmitOption emitOption = isLet ? PushInitialValues : InitializeVars;
return EmitDestructuringOpsHelper(cx, bce, pn, emitOption);
}
@ -3110,8 +3017,7 @@ MaybeEmitGroupAssignment(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, Par
* 1:1 correspondence and lhs elements are simple names.
*/
static bool
MaybeEmitLetGroupDecl(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn,
LetNotes *letNotes, JSOp *pop)
MaybeEmitLetGroupDecl(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp *pop)
{
JS_ASSERT(pn->isKind(PNK_ASSIGN));
JS_ASSERT(pn->isOp(JSOP_NOP));
@ -3134,7 +3040,6 @@ MaybeEmitLetGroupDecl(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn,
return false;
}
letNotes->setGroupAssign();
*pop = JSOP_NOP;
}
return true;
@ -3144,10 +3049,10 @@ MaybeEmitLetGroupDecl(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn,
static bool
EmitVariables(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption emitOption,
LetNotes *letNotes = NULL)
bool isLet = false)
{
JS_ASSERT(pn->isArity(PN_LIST));
JS_ASSERT(!!letNotes == (emitOption == PushInitialValues));
JS_ASSERT(isLet == (emitOption == PushInitialValues));
ptrdiff_t off = -1, noteIndex = -1;
ParseNode *next;
@ -3211,8 +3116,8 @@ EmitVariables(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption
* in pn->pn_op, to suppress a second (and misplaced) 'let'.
*/
JS_ASSERT(noteIndex < 0 && !pn2->pn_next);
if (letNotes) {
if (!MaybeEmitLetGroupDecl(cx, bce, pn2, letNotes, &op))
if (isLet) {
if (!MaybeEmitLetGroupDecl(cx, bce, pn2, &op))
return false;
} else {
if (!MaybeEmitGroupAssignment(cx, bce, pn->getOp(), pn2, GroupIsDecl, &op))
@ -3229,19 +3134,14 @@ EmitVariables(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption
if (!EmitTree(cx, bce, pn2->pn_right))
return false;
/* Only the first list element should print 'let' or 'var'. */
ptrdiff_t declType = pn2 == pn->pn_head
? OpToDeclType(pn->getOp())
: SRC_DECL_NONE;
if (!EmitDestructuringOps(cx, bce, declType, pn3, letNotes))
if (!EmitDestructuringOps(cx, bce, pn3, isLet))
return false;
}
ptrdiff_t stackDepthAfter = bce->stackDepth;
/* Give let ([] = x) a slot (see CheckDestructuring). */
JS_ASSERT(stackDepthBefore <= stackDepthAfter);
if (letNotes && stackDepthBefore == stackDepthAfter) {
if (isLet && stackDepthBefore == stackDepthAfter) {
if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
return false;
}
@ -3298,7 +3198,7 @@ EmitVariables(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption
if (!EmitTree(cx, bce, pn3))
return false;
bce->emittingForInit = oldEmittingForInit;
} else if (letNotes) {
} else if (isLet) {
/* JSOP_ENTERLETx expects at least 1 slot to have been pushed. */
if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
return false;
@ -3520,7 +3420,7 @@ EmitAssignment(JSContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp op, Par
#if JS_HAS_DESTRUCTURING
case PNK_ARRAY:
case PNK_OBJECT:
if (!EmitDestructuringOps(cx, bce, SRC_DECL_NONE, lhs))
if (!EmitDestructuringOps(cx, bce, lhs))
return false;
break;
#endif
@ -3699,7 +3599,7 @@ EmitCatch(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
#if JS_HAS_DESTRUCTURING
case PNK_ARRAY:
case PNK_OBJECT:
if (!EmitDestructuringOps(cx, bce, SRC_DECL_NONE, pn2))
if (!EmitDestructuringOps(cx, bce, pn2))
return false;
if (Emit1(cx, bce, JSOP_POP) < 0)
return false;
@ -4088,10 +3988,10 @@ EmitIf(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
* bytecode stackDepth srcnotes
* evaluate a +1
* evaluate b +1
* dup +1 SRC_DESTRUCTLET + offset to enterlet0
* dup +1
* destructure y
* pick 1
* dup +1 SRC_DESTRUCTLET + offset to enterlet0
* dup +1
* destructure z
* pick 1
* pop -1
@ -4102,11 +4002,6 @@ EmitIf(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
* Note that, since enterlet0 simply changes fp->blockChain and does not
* otherwise touch the stack, evaluation of the let-var initializers must leave
* the initial value in the let-var's future slot.
*
* The SRC_DESTRUCTLET distinguish JSOP_DUP as the beginning of a destructuring
* let initialization and the offset allows the decompiler to find the block
* object from which to find let var names. These forward offsets require
* backpatching, which is handled by LetNotes.
*/
/*
* Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
@ -4124,8 +4019,7 @@ EmitLet(JSContext *cx, BytecodeEmitter *bce, ParseNode *pnLet)
int letHeadDepth = bce->stackDepth;
LetNotes letNotes(cx);
if (!EmitVariables(cx, bce, varList, PushInitialValues, &letNotes))
if (!EmitVariables(cx, bce, varList, PushInitialValues, true))
return false;
/* Push storage for hoisted let decls (e.g. 'let (x) { let y }'). */
@ -4142,9 +4036,6 @@ EmitLet(JSContext *cx, BytecodeEmitter *bce, ParseNode *pnLet)
StmtInfoBCE stmtInfo(cx);
PushBlockScopeBCE(bce, &stmtInfo, *blockObj, bce->offset());
if (!letNotes.update(cx, bce, bce->offset()))
return false;
ptrdiff_t bodyBegin = bce->offset();
if (!EmitEnterBlock(cx, bce, letBody, JSOP_ENTERLET0))
return false;

View File

@ -274,8 +274,6 @@ enum SrcNoteType {
SRC_PCDELTA = 7, /* distance forward from comma-operator to
next POP, or from CONDSWITCH to first CASE
opcode, etc. -- always a forward delta */
SRC_DESTRUCTLET = 7, /* JSOP_DUP starting a destructuring let
operation, with offset to JSOP_ENTERLET0 */
SRC_ASSIGNOP = 8, /* += or another assign-op follows */
SRC_COND = 9, /* JSOP_IFEQ is from conditional ?: operator */
SRC_HIDDEN = 11, /* opcode shouldn't be decompiled */
@ -291,17 +289,6 @@ enum SrcNoteType {
SRC_XDELTA = 24 /* 24-31 are for extended delta notes */
};
/*
* Constants for the SRC_DESTRUCTLET source note.
*
* NB: the var_prefix array in jsopcode.c depends on these dense indexes from
* SRC_DECL_VAR through SRC_DECL_LET.
*/
#define SRC_DECL_VAR 0
#define SRC_DECL_CONST 1
#define SRC_DECL_LET 2
#define SRC_DECL_NONE 3
#define SN_TYPE_BITS 5
#define SN_DELTA_BITS 3
#define SN_XDELTA_BITS 6