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)
{
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
@ -834,13 +834,13 @@ EmitUnaliasedVarOp(JSContext *cx, JSOp op, uint16_t slot, BytecodeEmitter *bce)
}
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);
jsatomid atomIndex;
if (!bce->makeAtomIndex(atom, &atomIndex))
return false;
uint32_t maybeBlockIndex = UINT32_MAX;
if (bce->sc->blockChain)
maybeBlockIndex = bce->objectList.indexOf(bce->sc->blockChain);
bool decomposed = js_CodeSpec[op].format & JOF_DECOMPOSE;
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);
SET_UINT16(pc, sc.binding);
pc += sizeof(uint16_t);
SET_UINT32_INDEX(pc, atomIndex);
SET_UINT32_INDEX(pc, maybeBlockIndex);
pc += sizeof(uint32_t);
SET_UINT16(pc, sc.frameBinding);
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
@ -2639,8 +2639,7 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
sc.hops = 0;
sc.binding = bce->sc->bindings.localToBinding(bce->sc->argumentsLocalSlot());
sc.frameBinding = sc.binding;
JSAtom *atom = cx->runtime->atomState.argumentsAtom;
if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, atom, bce))
if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, bce))
return false;
} else {
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. */
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. */
if (pn->getOp() != JSOP_NOP) {
@ -5766,7 +5765,7 @@ EmitObject(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
ObjectBox *objbox = bce->parser->newObjectBox(obj);
if (!objbox)
return false;
unsigned index = bce->objectList.index(objbox);
unsigned index = bce->objectList.add(objbox);
MOZ_STATIC_ASSERT(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH,
"newinit and newobject must have equal length to edit in-place");
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:
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;
#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.
*/
unsigned
CGObjectList::index(ObjectBox *objbox)
CGObjectList::add(ObjectBox *objbox)
{
JS_ASSERT(!objbox->emitLink);
objbox->emitLink = lastbox;
@ -6962,6 +6961,16 @@ CGObjectList::index(ObjectBox *objbox)
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
CGObjectList::finish(ObjectArray *array)
{

View File

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

View File

@ -136,9 +136,7 @@ struct SharedContext {
StmtInfo *topStmt; /* top of statement info stack */
StmtInfo *topScopeStmt; /* top lexical scope statement */
Rooted<StaticBlockObject *> blockChain;
/* compile time block scope chain (NB: one
deeper than the topScopeStmt/downScope
chain when in head of let block/expr) */
/* compile time block scope chain */
private:
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: {
unsigned i = GET_UINT16(pc);
Sprint(sp, " %u", i);
pc += sizeof(uint16_t);
i = GET_UINT16(pc);
Sprint(sp, " %u", i);
pc += sizeof(uint16_t);
/* FALL THROUGH */
Value v = StringValue(ScopeCoordinateName(script, pc));
JSAutoByteString bytes;
if (!ToDisassemblySource(cx, v, &bytes))
return 0;
ScopeCoordinate sc(pc);
Sprint(sp, " %s (hops = %u, slot = %u)", bytes.ptr(), sc.hops, sc.binding);
break;
}
case JOF_ATOM: {
Value v = StringValue(script->getAtom(GET_UINT32_INDEX(pc)));
JSAutoByteString bytes;
@ -1843,7 +1844,7 @@ static bool
IsVarSlot(JSPrinter *jp, jsbytecode *pc, JSAtom **varAtom, int *localSlot)
{
if (JOF_OPTYPE(*pc) == JOF_SCOPECOORD) {
*varAtom = ScopeCoordinateAtom(jp->script, pc);
*varAtom = ScopeCoordinateName(jp->script, pc);
LOCAL_ASSERT_RV(*varAtom, NULL);
return true;
}

View File

@ -60,7 +60,7 @@ typedef enum JSOp {
#define JOF_INT8 18 /* int8_t immediate operand */
#define JOF_ATOMOBJECT 19 /* uint16_t constant index + object index */
#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_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
* 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
* aliased by the scope chain) which will be removed with the last patch of bug
* 659577.

View File

@ -20,13 +20,6 @@ ScopeCoordinate::ScopeCoordinate(jsbytecode *pc)
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 &
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
js_PutCallObject(StackFrame *fp, CallObject &callobj)
{

View File

@ -22,6 +22,9 @@ namespace js {
* given lexically-enclosing variable. A scope coordinate has two dimensions:
* - hops: the number of scope objects on the scope chain to skip
* - 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
{
@ -35,8 +38,13 @@ struct ScopeCoordinate
inline ScopeCoordinate() {}
};
inline JSAtom *
ScopeCoordinateAtom(JSScript *script, jsbytecode *pc);
/* Return the static block chain (or null) accessed by *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);
/*****************************************************************************/