mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 21:35:39 +00:00
Bug 932276 - Bytecode emitter records static scope extents. r=jorendorff
This commit is contained in:
parent
380ff683ba
commit
ffb3919733
@ -59,6 +59,7 @@ struct frontend::StmtInfoBCE : public StmtInfoBase
|
||||
ptrdiff_t update; /* loop update offset (top if none) */
|
||||
ptrdiff_t breaks; /* offset of last break in loop */
|
||||
ptrdiff_t continues; /* offset of last continue in loop */
|
||||
uint32_t blockScopeIndex; /* index of scope in BlockScopeArray */
|
||||
|
||||
StmtInfoBCE(ExclusiveContext *cx) : StmtInfoBase(cx) {}
|
||||
|
||||
@ -100,10 +101,11 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent,
|
||||
atomIndices(sc->context),
|
||||
firstLine(lineNum),
|
||||
stackDepth(0), maxStackDepth(0),
|
||||
tryNoteList(sc->context),
|
||||
arrayCompDepth(0),
|
||||
emitLevel(0),
|
||||
constList(sc->context),
|
||||
tryNoteList(sc->context),
|
||||
blockScopeList(sc->context),
|
||||
typesetCount(0),
|
||||
hasSingletons(false),
|
||||
emittingForInit(false),
|
||||
@ -686,13 +688,23 @@ EnclosingStaticScope(BytecodeEmitter *bce)
|
||||
}
|
||||
|
||||
// Push a block scope statement and link blockObj into bce->blockChain.
|
||||
static void
|
||||
PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, StaticBlockObject &blockObj,
|
||||
static bool
|
||||
PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, ObjectBox *objbox,
|
||||
ptrdiff_t top)
|
||||
{
|
||||
StaticBlockObject &blockObj = objbox->object->as<StaticBlockObject>();
|
||||
|
||||
PushStatementBCE(bce, stmt, STMT_BLOCK, top);
|
||||
|
||||
unsigned scopeObjectIndex = bce->objectList.add(objbox);
|
||||
stmt->blockScopeIndex = bce->blockScopeList.length();
|
||||
if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset()))
|
||||
return false;
|
||||
|
||||
blockObj.initEnclosingStaticScope(EnclosingStaticScope(bce));
|
||||
FinishPushBlockScope(bce, stmt, blockObj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Patches |breaks| and |continues| unless the top statement info record
|
||||
@ -707,6 +719,10 @@ PopStatementBCE(ExclusiveContext *cx, BytecodeEmitter *bce)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stmt->isBlockScope)
|
||||
bce->blockScopeList.recordEnd(stmt->blockScopeIndex, bce->offset());
|
||||
|
||||
FinishPopStatement(bce);
|
||||
return true;
|
||||
}
|
||||
@ -770,10 +786,16 @@ EmitAtomOp(ExclusiveContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitObjectOp(ExclusiveContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce)
|
||||
EmitInternedObjectOp(ExclusiveContext *cx, uint32_t index, JSOp op, BytecodeEmitter *bce)
|
||||
{
|
||||
JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
|
||||
return EmitIndex32(cx, op, bce->objectList.add(objbox), bce);
|
||||
return EmitIndex32(cx, op, index, bce);
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitObjectOp(ExclusiveContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce)
|
||||
{
|
||||
return EmitInternedObjectOp(cx, bce->objectList.add(objbox), op, bce);
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1061,7 +1083,14 @@ static bool
|
||||
EmitEnterBlock(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op)
|
||||
{
|
||||
JS_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
|
||||
if (!EmitObjectOp(cx, pn->pn_objbox, op, bce))
|
||||
StmtInfoBCE *stmt = bce->topStmt;
|
||||
JS_ASSERT(stmt->type == STMT_BLOCK || stmt->type == STMT_SWITCH);
|
||||
JS_ASSERT(stmt->isBlockScope);
|
||||
JS_ASSERT(stmt->blockScopeIndex == bce->blockScopeList.length() - 1);
|
||||
JS_ASSERT(bce->blockScopeList.list[stmt->blockScopeIndex].length == 0);
|
||||
uint32_t scopeObjectIndex = bce->blockScopeList.list[stmt->blockScopeIndex].index;
|
||||
JS_ASSERT(scopeObjectIndex == bce->objectList.length - 1);
|
||||
if (!EmitInternedObjectOp(cx, scopeObjectIndex, op, bce))
|
||||
return false;
|
||||
|
||||
Rooted<StaticBlockObject*> blockObj(cx, &pn->pn_objbox->object->as<StaticBlockObject>());
|
||||
@ -2305,7 +2334,8 @@ EmitSwitch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
return false;
|
||||
|
||||
if (pn2->isKind(PNK_LEXICALSCOPE)) {
|
||||
PushBlockScopeBCE(bce, &stmtInfo, pn2->pn_objbox->object->as<StaticBlockObject>(), -1);
|
||||
if (!PushBlockScopeBCE(bce, &stmtInfo, pn2->pn_objbox, -1))
|
||||
return false;
|
||||
stmtInfo.type = STMT_SWITCH;
|
||||
if (!EmitEnterBlock(cx, bce, pn2, JSOP_ENTERLET1))
|
||||
return false;
|
||||
@ -4193,7 +4223,8 @@ EmitLet(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pnLet)
|
||||
}
|
||||
|
||||
StmtInfoBCE stmtInfo(cx);
|
||||
PushBlockScopeBCE(bce, &stmtInfo, *blockObj, bce->offset());
|
||||
if (!PushBlockScopeBCE(bce, &stmtInfo, letBody->pn_objbox, bce->offset()))
|
||||
return false;
|
||||
|
||||
DebugOnly<ptrdiff_t> bodyBegin = bce->offset();
|
||||
if (!EmitEnterBlock(cx, bce, letBody, JSOP_ENTERLET0))
|
||||
@ -4226,7 +4257,8 @@ EmitLexicalScope(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
ObjectBox *objbox = pn->pn_objbox;
|
||||
StaticBlockObject &blockObj = objbox->object->as<StaticBlockObject>();
|
||||
size_t slots = blockObj.slotCount();
|
||||
PushBlockScopeBCE(bce, &stmtInfo, blockObj, bce->offset());
|
||||
if (!PushBlockScopeBCE(bce, &stmtInfo, objbox, bce->offset()))
|
||||
return false;
|
||||
|
||||
if (!EmitEnterBlock(cx, bce, pn, JSOP_ENTERBLOCK))
|
||||
return false;
|
||||
@ -4316,7 +4348,8 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
// Enter the block before the loop body, after evaluating the obj.
|
||||
StmtInfoBCE letStmt(cx);
|
||||
if (letDecl) {
|
||||
PushBlockScopeBCE(bce, &letStmt, *blockObj, bce->offset());
|
||||
if (!PushBlockScopeBCE(bce, &letStmt, pn1->pn_objbox, bce->offset()))
|
||||
return false;
|
||||
letStmt.isForLetBlock = true;
|
||||
if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET2))
|
||||
return false;
|
||||
@ -4492,7 +4525,8 @@ EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
/* Enter the block before the loop body, after evaluating the obj. */
|
||||
StmtInfoBCE letStmt(cx);
|
||||
if (letDecl) {
|
||||
PushBlockScopeBCE(bce, &letStmt, *blockObj, bce->offset());
|
||||
if (!PushBlockScopeBCE(bce, &letStmt, pn1->pn_objbox, bce->offset()))
|
||||
return false;
|
||||
letStmt.isForLetBlock = true;
|
||||
if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET1))
|
||||
return false;
|
||||
@ -6775,25 +6809,8 @@ frontend::FinishTakingSrcNotes(ExclusiveContext *cx, BytecodeEmitter *bce, jssrc
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CGTryNoteList::append(JSTryNoteKind kind, unsigned stackDepth, size_t start, size_t end)
|
||||
{
|
||||
JS_ASSERT(unsigned(uint16_t(stackDepth)) == stackDepth);
|
||||
JS_ASSERT(start <= end);
|
||||
JS_ASSERT(size_t(uint32_t(start)) == start);
|
||||
JS_ASSERT(size_t(uint32_t(end)) == end);
|
||||
|
||||
JSTryNote note;
|
||||
note.kind = kind;
|
||||
note.stackDepth = uint16_t(stackDepth);
|
||||
note.start = uint32_t(start);
|
||||
note.length = uint32_t(end - start);
|
||||
|
||||
return list.append(note);
|
||||
}
|
||||
|
||||
void
|
||||
CGTryNoteList::finish(TryNoteArray *array)
|
||||
CGConstList::finish(ConstArray *array)
|
||||
{
|
||||
JS_ASSERT(length() == array->length);
|
||||
|
||||
@ -6878,8 +6895,56 @@ CGObjectList::finish(ObjectArray *array)
|
||||
JS_ASSERT(cursor == array->vector);
|
||||
}
|
||||
|
||||
bool
|
||||
CGTryNoteList::append(JSTryNoteKind kind, unsigned stackDepth, size_t start, size_t end)
|
||||
{
|
||||
JS_ASSERT(unsigned(uint16_t(stackDepth)) == stackDepth);
|
||||
JS_ASSERT(start <= end);
|
||||
JS_ASSERT(size_t(uint32_t(start)) == start);
|
||||
JS_ASSERT(size_t(uint32_t(end)) == end);
|
||||
|
||||
JSTryNote note;
|
||||
note.kind = kind;
|
||||
note.stackDepth = uint16_t(stackDepth);
|
||||
note.start = uint32_t(start);
|
||||
note.length = uint32_t(end - start);
|
||||
|
||||
return list.append(note);
|
||||
}
|
||||
|
||||
void
|
||||
CGConstList::finish(ConstArray *array)
|
||||
CGTryNoteList::finish(TryNoteArray *array)
|
||||
{
|
||||
JS_ASSERT(length() == array->length);
|
||||
|
||||
for (unsigned i = 0; i < length(); i++)
|
||||
array->vector[i] = list[i];
|
||||
}
|
||||
|
||||
bool
|
||||
CGBlockScopeList::append(uint32_t scopeObject, uint32_t offset)
|
||||
{
|
||||
BlockScopeNote note;
|
||||
mozilla::PodZero(¬e);
|
||||
|
||||
note.index = scopeObject;
|
||||
note.start = offset;
|
||||
|
||||
return list.append(note);
|
||||
}
|
||||
|
||||
void
|
||||
CGBlockScopeList::recordEnd(uint32_t index, uint32_t offset)
|
||||
{
|
||||
JS_ASSERT(index < length());
|
||||
JS_ASSERT(offset >= list[index].start);
|
||||
JS_ASSERT(list[index].length == 0);
|
||||
|
||||
list[index].length = offset - list[index].start;
|
||||
}
|
||||
|
||||
void
|
||||
CGBlockScopeList::finish(BlockScopeArray *array)
|
||||
{
|
||||
JS_ASSERT(length() == array->length);
|
||||
|
||||
|
@ -28,13 +28,13 @@ template <typename ParseHandler> class Parser;
|
||||
class SharedContext;
|
||||
class TokenStream;
|
||||
|
||||
struct CGTryNoteList {
|
||||
Vector<JSTryNote> list;
|
||||
CGTryNoteList(ExclusiveContext *cx) : list(cx) {}
|
||||
|
||||
bool append(JSTryNoteKind kind, unsigned stackDepth, size_t start, size_t end);
|
||||
class CGConstList {
|
||||
Vector<Value> list;
|
||||
public:
|
||||
CGConstList(ExclusiveContext *cx) : list(cx) {}
|
||||
bool append(Value v) { JS_ASSERT_IF(v.isString(), v.toString()->isAtom()); return list.append(v); }
|
||||
size_t length() const { return list.length(); }
|
||||
void finish(TryNoteArray *array);
|
||||
void finish(ConstArray *array);
|
||||
};
|
||||
|
||||
struct CGObjectList {
|
||||
@ -48,13 +48,23 @@ struct CGObjectList {
|
||||
void finish(ObjectArray *array);
|
||||
};
|
||||
|
||||
class CGConstList {
|
||||
Vector<Value> list;
|
||||
public:
|
||||
CGConstList(ExclusiveContext *cx) : list(cx) {}
|
||||
bool append(Value v) { JS_ASSERT_IF(v.isString(), v.toString()->isAtom()); return list.append(v); }
|
||||
struct CGTryNoteList {
|
||||
Vector<JSTryNote> list;
|
||||
CGTryNoteList(ExclusiveContext *cx) : list(cx) {}
|
||||
|
||||
bool append(JSTryNoteKind kind, unsigned stackDepth, size_t start, size_t end);
|
||||
size_t length() const { return list.length(); }
|
||||
void finish(ConstArray *array);
|
||||
void finish(TryNoteArray *array);
|
||||
};
|
||||
|
||||
struct CGBlockScopeList {
|
||||
Vector<BlockScopeNote> list;
|
||||
CGBlockScopeList(ExclusiveContext *cx) : list(cx) {}
|
||||
|
||||
bool append(uint32_t scopeObject, uint32_t offset);
|
||||
void recordEnd(uint32_t index, uint32_t offset);
|
||||
size_t length() const { return list.length(); }
|
||||
void finish(BlockScopeArray *array);
|
||||
};
|
||||
|
||||
struct StmtInfoBCE;
|
||||
@ -104,8 +114,6 @@ struct BytecodeEmitter
|
||||
int stackDepth; /* current stack depth in script frame */
|
||||
unsigned maxStackDepth; /* maximum stack depth so far */
|
||||
|
||||
CGTryNoteList tryNoteList; /* list of emitted try notes */
|
||||
|
||||
unsigned arrayCompDepth; /* stack depth of array in comprehension */
|
||||
|
||||
unsigned emitLevel; /* js::frontend::EmitTree recursion level */
|
||||
@ -115,6 +123,8 @@ struct BytecodeEmitter
|
||||
CGObjectList objectList; /* list of emitted objects */
|
||||
CGObjectList regexpList; /* list of emitted regexp that will be
|
||||
cloned during execution */
|
||||
CGTryNoteList tryNoteList; /* list of emitted try notes */
|
||||
CGBlockScopeList blockScopeList;/* list of emitted block scope notes */
|
||||
|
||||
uint16_t typesetCount; /* Number of JOF_TYPESET opcodes generated */
|
||||
|
||||
|
@ -1878,10 +1878,9 @@ JSScript::fullyInitFromEmitter(ExclusiveContext *cx, HandleScript script, Byteco
|
||||
uint32_t prologLength = bce->prologOffset();
|
||||
uint32_t nsrcnotes = uint32_t(bce->countFinalSourceNotes());
|
||||
uint32_t natoms = bce->atomIndices->count();
|
||||
uint32_t nblockscopes = 0;
|
||||
if (!partiallyInit(cx, script,
|
||||
bce->constList.length(), bce->objectList.length, bce->regexpList.length,
|
||||
bce->tryNoteList.length(), nblockscopes, bce->typesetCount))
|
||||
bce->tryNoteList.length(), bce->blockScopeList.length(), bce->typesetCount))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -1918,15 +1917,16 @@ JSScript::fullyInitFromEmitter(ExclusiveContext *cx, HandleScript script, Byteco
|
||||
|
||||
FunctionBox *funbox = bce->sc->isFunctionBox() ? bce->sc->asFunctionBox() : nullptr;
|
||||
|
||||
// FIXME: Initialize blockScopes here.
|
||||
if (bce->tryNoteList.length() != 0)
|
||||
bce->tryNoteList.finish(script->trynotes());
|
||||
if (bce->constList.length() != 0)
|
||||
bce->constList.finish(script->consts());
|
||||
if (bce->objectList.length != 0)
|
||||
bce->objectList.finish(script->objects());
|
||||
if (bce->regexpList.length != 0)
|
||||
bce->regexpList.finish(script->regexps());
|
||||
if (bce->constList.length() != 0)
|
||||
bce->constList.finish(script->consts());
|
||||
if (bce->tryNoteList.length() != 0)
|
||||
bce->tryNoteList.finish(script->trynotes());
|
||||
if (bce->blockScopeList.length() != 0)
|
||||
bce->blockScopeList.finish(script->blockScopes());
|
||||
script->strict = bce->sc->strict;
|
||||
script->explicitUseStrict = bce->sc->hasExplicitUseStrict();
|
||||
script->bindingsAccessedDynamically = bce->sc->bindingsAccessedDynamically();
|
||||
|
Loading…
Reference in New Issue
Block a user