Bug 944930 - Remove block index from aliasedvar ops, use a binary search to find the block chain for a given pc, r=luke.

This commit is contained in:
Brian Hackett 2013-12-07 11:03:07 -08:00
parent 688dd8051e
commit 6ebb9c6ffe
11 changed files with 69 additions and 37 deletions

View File

@ -1135,7 +1135,6 @@ if test "$GNU_CC"; then
#
_WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall -Wpointer-arith -Wdeclaration-after-statement"
MOZ_C_SUPPORTS_WARNING(-W, error=return-type, ac_c_has_werror_return_type)
MOZ_C_SUPPORTS_WARNING(-W, type-limits, ac_c_has_wtype_limits)
MOZ_C_SUPPORTS_WARNING(-W, empty-body, ac_c_has_wempty_body)
MOZ_C_SUPPORTS_WARNING(-W, sign-compare, ac_c_has_sign_compare)

View File

@ -678,13 +678,20 @@ static bool
PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, ObjectBox *objbox,
ptrdiff_t top)
{
uint32_t parent = UINT32_MAX;
if (bce->blockChain) {
StmtInfoBCE *stmt = bce->topScopeStmt;
for (; stmt->blockObj != bce->blockChain; stmt = stmt->down) {}
parent = stmt->blockScopeIndex;
}
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()))
if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset(), parent))
return false;
blockObj.initEnclosingStaticScope(EnclosingStaticScope(bce));
@ -814,11 +821,7 @@ EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ScopeCoordinate sc, BytecodeEmit
{
JS_ASSERT(JOF_OPTYPE(op) == JOF_SCOPECOORD);
uint32_t maybeBlockIndex = UINT32_MAX;
if (bce->blockChain)
maybeBlockIndex = bce->objectList.indexOf(bce->blockChain);
unsigned n = 2 * sizeof(uint16_t) + sizeof(uint32_t);
unsigned n = 2 * sizeof(uint16_t);
JS_ASSERT(int(n) + 1 /* op */ == js_CodeSpec[op].length);
ptrdiff_t off = EmitN(cx, bce, op, n);
@ -830,7 +833,6 @@ EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ScopeCoordinate sc, BytecodeEmit
pc += sizeof(uint16_t);
SET_UINT16(pc, sc.slot);
pc += sizeof(uint16_t);
SET_UINT32_INDEX(pc, maybeBlockIndex);
CheckTypeSet(cx, bce, op);
return true;
}
@ -6879,13 +6881,14 @@ CGTryNoteList::finish(TryNoteArray *array)
}
bool
CGBlockScopeList::append(uint32_t scopeObject, uint32_t offset)
CGBlockScopeList::append(uint32_t scopeObject, uint32_t offset, uint32_t parent)
{
BlockScopeNote note;
mozilla::PodZero(&note);
note.index = scopeObject;
note.start = offset;
note.parent = parent;
return list.append(note);
}

View File

@ -61,7 +61,7 @@ struct CGBlockScopeList {
Vector<BlockScopeNote> list;
CGBlockScopeList(ExclusiveContext *cx) : list(cx) {}
bool append(uint32_t scopeObject, uint32_t offset);
bool append(uint32_t scopeObject, uint32_t offset, uint32_t parent);
void recordEnd(uint32_t index, uint32_t offset);
size_t length() const { return list.length(); }
void finish(BlockScopeArray *array);

View File

@ -3,7 +3,7 @@ setDebug(true);
x = "notset";
function main() {
/* The JSOP_STOP in main. */
a = { valueOf: function () { trap(main, 95, "success()"); } };
a = { valueOf: function () { trap(main, 91, "success()"); } };
b = "";
eval();
a + b;

View File

@ -1432,25 +1432,52 @@ js_QuoteString(ExclusiveContext *cx, JSString *str, jschar quote)
/************************************************************************/
static JSObject *
GetBlockChainAtPC(JSContext *cx, JSScript *script, jsbytecode *pc)
StaticBlockObject *
js::GetBlockChainAtPC(JSScript *script, jsbytecode *pc)
{
JS_ASSERT(script->containsPC(pc));
JS_ASSERT(pc >= script->main());
ptrdiff_t offset = pc - script->main();
if (!script->hasBlockScopes())
return nullptr;
if (pc < script->main())
return nullptr;
ptrdiff_t offset = pc - script->main();
BlockScopeArray *blockScopes = script->blockScopes();
JSObject *blockChain = nullptr;
for (uint32_t n = 0; n < blockScopes->length; n++) {
const BlockScopeNote *note = &blockScopes->vector[n];
if (note->start > offset)
break;
if (offset <= note->start + note->length)
blockChain = script->getObject(note->index);
StaticBlockObject *blockChain = nullptr;
// Find the innermost block chain using a binary search.
size_t bottom = 0;
size_t top = blockScopes->length;
while (bottom < top) {
size_t mid = bottom + (top - bottom) / 2;
const BlockScopeNote *note = &blockScopes->vector[mid];
if (note->start <= offset) {
// Block scopes are ordered in the list by their starting offset, and since
// blocks form a tree ones earlier in the list may cover the pc even if
// later blocks end before the pc. This only happens when the earlier block
// is a parent of the later block, so we need to check parents of |mid| in
// the searched range for coverage.
size_t check = mid;
while (check >= bottom) {
const BlockScopeNote *checkNote = &blockScopes->vector[check];
JS_ASSERT(checkNote->start <= offset);
if (offset <= checkNote->start + checkNote->length) {
// We found a matching block chain but there may be inner ones
// at a higher block chain index than mid. Continue the binary search.
blockChain = &script->getObject(checkNote->index)->as<StaticBlockObject>();
break;
}
if (checkNote->parent == UINT32_MAX)
break;
check = checkNote->parent;
}
bottom = mid + 1;
} else {
top = mid;
}
}
return blockChain;
@ -1716,7 +1743,7 @@ JSAtom *
ExpressionDecompiler::findLetVar(jsbytecode *pc, unsigned depth)
{
if (script->hasObjects()) {
JSObject *chain = GetBlockChainAtPC(cx, script, pc);
JSObject *chain = GetBlockChainAtPC(script, pc);
if (!chain)
return nullptr;
JS_ASSERT(chain->is<BlockObject>());

View File

@ -777,6 +777,11 @@ GetNextPc(jsbytecode *pc)
return pc + GetBytecodeLength(pc);
}
class StaticBlockObject;
StaticBlockObject *
GetBlockChainAtPC(JSScript *script, jsbytecode *pc);
} /* namespace js */
#if defined(DEBUG)

View File

@ -318,12 +318,10 @@ OPDEF(JSOP_FINALLY, 135,"finally", NULL, 1, 0, 2, JOF_BYTE)
* 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.
*/
OPDEF(JSOP_GETALIASEDVAR, 136,"getaliasedvar",NULL, 9, 0, 1, JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET)
OPDEF(JSOP_CALLALIASEDVAR,137,"callaliasedvar",NULL, 9, 0, 1, JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET)
OPDEF(JSOP_SETALIASEDVAR, 138,"setaliasedvar",NULL, 9, 1, 1, JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING)
OPDEF(JSOP_GETALIASEDVAR, 136,"getaliasedvar",NULL, 5, 0, 1, JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET)
OPDEF(JSOP_CALLALIASEDVAR,137,"callaliasedvar",NULL, 5, 0, 1, JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET)
OPDEF(JSOP_SETALIASEDVAR, 138,"setaliasedvar",NULL, 5, 1, 1, JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING)
OPDEF(JSOP_UNUSED139, 139, "unused139", NULL, 1, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED140, 140, "unused140", NULL, 1, 0, 0, JOF_BYTE)

View File

@ -807,7 +807,8 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
BlockScopeNote *note = &script->blockScopes()->vector[i];
if (!xdr->codeUint32(&note->index) ||
!xdr->codeUint32(&note->start) ||
!xdr->codeUint32(&note->length))
!xdr->codeUint32(&note->length) ||
!xdr->codeUint32(&note->parent))
{
return false;
}

View File

@ -85,7 +85,7 @@ struct BlockScopeNote {
uint32_t index; // Index of StaticScopeObject in the object array.
uint32_t start; // Bytecode offset at which this scope starts.
uint32_t length; // Bytecode length of scope.
uint32_t padding; // Pad to 64-bit boundary.
uint32_t parent; // Index of parent block scope in notes, or UINT32_MAX.
};
struct ConstArray {

View File

@ -38,11 +38,10 @@ InnermostStaticScope(JSScript *script, jsbytecode *pc)
JS_ASSERT(script->containsPC(pc));
JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD);
uint32_t blockIndex = GET_UINT32_INDEX(pc + 2 * sizeof(uint16_t));
if (blockIndex == UINT32_MAX)
return script->function();
return &script->getObject(blockIndex)->as<StaticBlockObject>();
StaticBlockObject *block = GetBlockChainAtPC(script, pc);
if (block)
return block;
return script->function();
}
Shape *

View File

@ -22,7 +22,7 @@ namespace js {
* and saved versions. If deserialization fails, the data should be
* invalidated if possible.
*/
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 155);
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 156);
class XDRBuffer {
public: