Bug 659577 - Embed blockChain information in ALIASEDVAR ops (r=waldo)

--HG--
extra : rebase_source : ea0deae107902520b392ed1eeddcd8c6420945ee
This commit is contained in:
Luke Wagner 2012-05-10 11:24:20 -07:00
parent da494c3aae
commit 304ebf5156
9 changed files with 98 additions and 35 deletions

View File

@ -806,7 +806,7 @@ static bool
EmitObjectOp(JSContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce) EmitObjectOp(JSContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce)
{ {
JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT); JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
return EmitIndex32(cx, op, bce->objectList.index(objbox), bce); return EmitIndex32(cx, op, bce->objectList.add(objbox), bce);
} }
static bool static bool
@ -834,13 +834,13 @@ EmitUnaliasedVarOp(JSContext *cx, JSOp op, uint16_t slot, BytecodeEmitter *bce)
} }
static bool static bool
EmitAliasedVarOp(JSContext *cx, JSOp op, ScopeCoordinate sc, JSAtom *atom, BytecodeEmitter *bce) EmitAliasedVarOp(JSContext *cx, JSOp op, ScopeCoordinate sc, BytecodeEmitter *bce)
{ {
JS_ASSERT(JOF_OPTYPE(op) == JOF_SCOPECOORD); JS_ASSERT(JOF_OPTYPE(op) == JOF_SCOPECOORD);
jsatomid atomIndex; uint32_t maybeBlockIndex = UINT32_MAX;
if (!bce->makeAtomIndex(atom, &atomIndex)) if (bce->sc->blockChain)
return false; maybeBlockIndex = bce->objectList.indexOf(bce->sc->blockChain);
bool decomposed = js_CodeSpec[op].format & JOF_DECOMPOSE; bool decomposed = js_CodeSpec[op].format & JOF_DECOMPOSE;
unsigned n = 2 * sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint16_t) + (decomposed ? 1 : 0); unsigned n = 2 * sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint16_t) + (decomposed ? 1 : 0);
@ -855,7 +855,7 @@ EmitAliasedVarOp(JSContext *cx, JSOp op, ScopeCoordinate sc, JSAtom *atom, Bytec
pc += sizeof(uint16_t); pc += sizeof(uint16_t);
SET_UINT16(pc, sc.binding); SET_UINT16(pc, sc.binding);
pc += sizeof(uint16_t); pc += sizeof(uint16_t);
SET_UINT32_INDEX(pc, atomIndex); SET_UINT32_INDEX(pc, maybeBlockIndex);
pc += sizeof(uint32_t); pc += sizeof(uint32_t);
SET_UINT16(pc, sc.frameBinding); SET_UINT16(pc, sc.frameBinding);
return true; return true;
@ -911,7 +911,7 @@ EmitAliasedVarOp(JSContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *bce)
} }
} }
return EmitAliasedVarOp(cx, op, sc, pn->atom(), bce); return EmitAliasedVarOp(cx, op, sc, bce);
} }
static bool static bool
@ -2639,8 +2639,7 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
sc.hops = 0; sc.hops = 0;
sc.binding = bce->sc->bindings.localToBinding(bce->sc->argumentsLocalSlot()); sc.binding = bce->sc->bindings.localToBinding(bce->sc->argumentsLocalSlot());
sc.frameBinding = sc.binding; sc.frameBinding = sc.binding;
JSAtom *atom = cx->runtime->atomState.argumentsAtom; if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, bce))
if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, atom, bce))
return false; return false;
} else { } else {
if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, bce->sc->argumentsLocalSlot(), bce)) if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, bce->sc->argumentsLocalSlot(), bce))
@ -4877,7 +4876,7 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
} }
/* Make the function object a literal in the outer script's pool. */ /* Make the function object a literal in the outer script's pool. */
unsigned index = bce->objectList.index(pn->pn_funbox); unsigned index = bce->objectList.add(pn->pn_funbox);
/* Emit a bytecode pointing to the closure object in its immediate. */ /* Emit a bytecode pointing to the closure object in its immediate. */
if (pn->getOp() != JSOP_NOP) { if (pn->getOp() != JSOP_NOP) {
@ -5766,7 +5765,7 @@ EmitObject(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
ObjectBox *objbox = bce->parser->newObjectBox(obj); ObjectBox *objbox = bce->parser->newObjectBox(obj);
if (!objbox) if (!objbox)
return false; return false;
unsigned index = bce->objectList.index(objbox); unsigned index = bce->objectList.add(objbox);
MOZ_STATIC_ASSERT(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH, MOZ_STATIC_ASSERT(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH,
"newinit and newobject must have equal length to edit in-place"); "newinit and newobject must have equal length to edit in-place");
EMIT_UINT32_IN_PLACE(offset, JSOP_NEWOBJECT, uint32_t(index)); EMIT_UINT32_IN_PLACE(offset, JSOP_NEWOBJECT, uint32_t(index));
@ -6454,7 +6453,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
case PNK_REGEXP: case PNK_REGEXP:
JS_ASSERT(pn->isOp(JSOP_REGEXP)); JS_ASSERT(pn->isOp(JSOP_REGEXP));
ok = EmitRegExp(cx, bce->regexpList.index(pn->pn_objbox), bce); ok = EmitRegExp(cx, bce->regexpList.add(pn->pn_objbox), bce);
break; break;
#if JS_HAS_XML_SUPPORT #if JS_HAS_XML_SUPPORT
@ -6954,7 +6953,7 @@ frontend::FinishTakingTryNotes(BytecodeEmitter *bce, TryNoteArray *array)
* the pre-compilation prototype, a pigeon-hole problem for instanceof tests. * the pre-compilation prototype, a pigeon-hole problem for instanceof tests.
*/ */
unsigned unsigned
CGObjectList::index(ObjectBox *objbox) CGObjectList::add(ObjectBox *objbox)
{ {
JS_ASSERT(!objbox->emitLink); JS_ASSERT(!objbox->emitLink);
objbox->emitLink = lastbox; objbox->emitLink = lastbox;
@ -6962,6 +6961,16 @@ CGObjectList::index(ObjectBox *objbox)
return length++; return length++;
} }
unsigned
CGObjectList::indexOf(JSObject *obj)
{
JS_ASSERT(length > 0);
unsigned index = length - 1;
for (ObjectBox *box = lastbox; box->object != obj; box = box->emitLink)
index--;
return index;
}
void void
CGObjectList::finish(ObjectArray *array) CGObjectList::finish(ObjectArray *array)
{ {

View File

@ -49,7 +49,8 @@ struct CGObjectList {
CGObjectList() : length(0), lastbox(NULL) {} CGObjectList() : length(0), lastbox(NULL) {}
unsigned index(ObjectBox *objbox); unsigned add(ObjectBox *objbox);
unsigned indexOf(JSObject *obj);
void finish(ObjectArray *array); void finish(ObjectArray *array);
}; };

View File

@ -136,9 +136,7 @@ struct SharedContext {
StmtInfo *topStmt; /* top of statement info stack */ StmtInfo *topStmt; /* top of statement info stack */
StmtInfo *topScopeStmt; /* top lexical scope statement */ StmtInfo *topScopeStmt; /* top lexical scope statement */
Rooted<StaticBlockObject *> blockChain; Rooted<StaticBlockObject *> blockChain;
/* compile time block scope chain (NB: one /* compile time block scope chain */
deeper than the topScopeStmt/downScope
chain when in head of let block/expr) */
private: private:
const RootedFunction fun_; /* function to store argument and variable const RootedFunction fun_; /* function to store argument and variable

View File

@ -514,14 +514,15 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
} }
case JOF_SCOPECOORD: { case JOF_SCOPECOORD: {
unsigned i = GET_UINT16(pc); Value v = StringValue(ScopeCoordinateName(script, pc));
Sprint(sp, " %u", i); JSAutoByteString bytes;
pc += sizeof(uint16_t); if (!ToDisassemblySource(cx, v, &bytes))
i = GET_UINT16(pc); return 0;
Sprint(sp, " %u", i); ScopeCoordinate sc(pc);
pc += sizeof(uint16_t); Sprint(sp, " %s (hops = %u, slot = %u)", bytes.ptr(), sc.hops, sc.binding);
/* FALL THROUGH */ break;
} }
case JOF_ATOM: { case JOF_ATOM: {
Value v = StringValue(script->getAtom(GET_UINT32_INDEX(pc))); Value v = StringValue(script->getAtom(GET_UINT32_INDEX(pc)));
JSAutoByteString bytes; JSAutoByteString bytes;
@ -1843,7 +1844,7 @@ static bool
IsVarSlot(JSPrinter *jp, jsbytecode *pc, JSAtom **varAtom, int *localSlot) IsVarSlot(JSPrinter *jp, jsbytecode *pc, JSAtom **varAtom, int *localSlot)
{ {
if (JOF_OPTYPE(*pc) == JOF_SCOPECOORD) { if (JOF_OPTYPE(*pc) == JOF_SCOPECOORD) {
*varAtom = ScopeCoordinateAtom(jp->script, pc); *varAtom = ScopeCoordinateName(jp->script, pc);
LOCAL_ASSERT_RV(*varAtom, NULL); LOCAL_ASSERT_RV(*varAtom, NULL);
return true; return true;
} }

View File

@ -60,7 +60,7 @@ typedef enum JSOp {
#define JOF_INT8 18 /* int8_t immediate operand */ #define JOF_INT8 18 /* int8_t immediate operand */
#define JOF_ATOMOBJECT 19 /* uint16_t constant index + object index */ #define JOF_ATOMOBJECT 19 /* uint16_t constant index + object index */
#define JOF_UINT16PAIR 20 /* pair of uint16_t immediates */ #define JOF_UINT16PAIR 20 /* pair of uint16_t immediates */
#define JOF_SCOPECOORD 21 /* pair of uint16_t immediates followed by atom index */ #define JOF_SCOPECOORD 21 /* pair of uint16_t immediates followed by block index */
#define JOF_TYPEMASK 0x001f /* mask for above immediate types */ #define JOF_TYPEMASK 0x001f /* mask for above immediate types */
#define JOF_NAME (1U<<5) /* name operation */ #define JOF_NAME (1U<<5) /* name operation */

View File

@ -334,6 +334,14 @@ OPDEF(JSOP_FINALLY, 135,"finally", NULL, 1, 0, 2, 0, JOF_BYTE)
* 'with', 'arguments' and E4X filters. All of these cases require creating a * 'with', 'arguments' and E4X filters. All of these cases require creating a
* CallObject to own the aliased variable. * CallObject to own the aliased variable.
* *
* An ALIASEDVAR opcode contains the following immediates:
* uint16 hops: the number of scope objects to skip to find the ScopeObject
* containing the variable being accessed
* uint16 slot: the slot containing the variable in the ScopeObject (this
* 'slot' does not include RESERVED_SLOTS).
* uint32 block: the index (into the script object table) of the block chain
* at the point of the variable access.
*
* XXX: there is also a temporary 2-byte index (indicating the frame slot * XXX: there is also a temporary 2-byte index (indicating the frame slot
* aliased by the scope chain) which will be removed with the last patch of bug * aliased by the scope chain) which will be removed with the last patch of bug
* 659577. * 659577.

View File

@ -20,13 +20,6 @@ ScopeCoordinate::ScopeCoordinate(jsbytecode *pc)
JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD); JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD);
} }
inline JSAtom *
ScopeCoordinateAtom(JSScript *script, jsbytecode *pc)
{
JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD);
return script->getAtom(GET_UINT32_INDEX(pc + 2 * sizeof(uint16_t)));
}
inline JSObject & inline JSObject &
ScopeObject::enclosingScope() const ScopeObject::enclosingScope() const
{ {

View File

@ -23,6 +23,51 @@ using namespace js::types;
/*****************************************************************************/ /*****************************************************************************/
StaticBlockObject *
js::ScopeCoordinateBlockChain(JSScript *script, jsbytecode *pc)
{
ScopeCoordinate sc(pc);
uint32_t blockIndex = GET_UINT32_INDEX(pc + 2 * sizeof(uint16_t));
if (blockIndex == UINT32_MAX)
return NULL;
StaticBlockObject *block = &script->getObject(blockIndex)->asStaticBlock();
unsigned i = 0;
while (true) {
while (block && !block->needsClone())
block = block->enclosingBlock();
if (i++ == sc.hops)
break;
block = block->enclosingBlock();
}
return block;
}
PropertyName *
js::ScopeCoordinateName(JSScript *script, jsbytecode *pc)
{
StaticBlockObject *maybeBlock = ScopeCoordinateBlockChain(script, pc);
ScopeCoordinate sc(pc);
uint32_t targetSlot;
Shape *shape;
if (maybeBlock) {
targetSlot = BlockObject::RESERVED_SLOTS + sc.binding;
shape = maybeBlock->lastProperty();
} else {
targetSlot = CallObject::RESERVED_SLOTS + sc.binding;
shape = script->bindings.lastShape();
}
Shape::Range r = shape->all();
while (r.front().slot() != targetSlot)
r.popFront();
return JSID_TO_ATOM(r.front().propid())->asPropertyName();
}
/*****************************************************************************/
void void
js_PutCallObject(StackFrame *fp, CallObject &callobj) js_PutCallObject(StackFrame *fp, CallObject &callobj)
{ {

View File

@ -22,6 +22,9 @@ namespace js {
* given lexically-enclosing variable. A scope coordinate has two dimensions: * given lexically-enclosing variable. A scope coordinate has two dimensions:
* - hops: the number of scope objects on the scope chain to skip * - hops: the number of scope objects on the scope chain to skip
* - binding: which binding on the scope object * - binding: which binding on the scope object
* Additionally (as described in jsopcode.tbl) there is a 'block' index, but
* this is only needed for decompilation/inference so it is not included in the
* main ScopeCoordinate struct: use ScopeCoordinate{BlockChain,Atom} instead.
*/ */
struct ScopeCoordinate struct ScopeCoordinate
{ {
@ -35,8 +38,13 @@ struct ScopeCoordinate
inline ScopeCoordinate() {} inline ScopeCoordinate() {}
}; };
inline JSAtom * /* Return the static block chain (or null) accessed by *pc. */
ScopeCoordinateAtom(JSScript *script, jsbytecode *pc); extern StaticBlockObject *
ScopeCoordinateBlockChain(JSScript *script, jsbytecode *pc);
/* Return the name being accessed by the given ALIASEDVAR op. */
extern PropertyName *
ScopeCoordinateName(JSScript *script, jsbytecode *pc);
/*****************************************************************************/ /*****************************************************************************/