mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-12 21:05:36 +00:00
Bug 838813 part 12 - Remove SRC_DESTRUCTLET. r=njn.
--HG-- extra : rebase_source : d488c8834a0a0c45b688e2f3aefbcef7e108aa45
This commit is contained in:
parent
13aa192cc9
commit
561c40e9d6
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user