mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 966912 - Part 2: Add StaticWithObject to the static scope chain r=luke
--HG-- extra : rebase_source : c0ccbca2166c953dcac37e32aba9b30175399d25
This commit is contained in:
parent
10a99f426e
commit
17707f6384
@ -497,7 +497,7 @@ class NonLocalExitScope {
|
||||
StmtInfoBCE *stmt = bce->topStmt;
|
||||
while (1) {
|
||||
JS_ASSERT(stmt);
|
||||
if (stmt->isBlockScope) {
|
||||
if (stmt->isNestedScope) {
|
||||
openScopeIndex = stmt->blockScopeIndex;
|
||||
break;
|
||||
}
|
||||
@ -512,18 +512,12 @@ class NonLocalExitScope {
|
||||
bce->stackDepth = savedDepth;
|
||||
}
|
||||
|
||||
bool popScopeForNonLocalExit(StaticBlockObject &blockObj, uint32_t blockScopeIndex) {
|
||||
bool popScopeForNonLocalExit(uint32_t blockScopeIndex) {
|
||||
uint32_t scopeObjectIndex = bce->blockScopeList.findEnclosingScope(blockScopeIndex);
|
||||
uint32_t parent = openScopeIndex;
|
||||
|
||||
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
|
||||
return false;
|
||||
if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset(), parent))
|
||||
return false;
|
||||
if (blockObj.needsClone()) {
|
||||
if (Emit1(cx, bce, JSOP_POPBLOCKSCOPE) < 0)
|
||||
return false;
|
||||
}
|
||||
openScopeIndex = bce->blockScopeList.length() - 1;
|
||||
return true;
|
||||
}
|
||||
@ -554,6 +548,9 @@ NonLocalExitScope::prepareForNonLocalJump(StmtInfoBCE *toStmt)
|
||||
FLUSH_POPS();
|
||||
if (Emit1(cx, bce, JSOP_LEAVEWITH) < 0)
|
||||
return false;
|
||||
JS_ASSERT(stmt->isNestedScope);
|
||||
if (!popScopeForNonLocalExit(stmt->blockScopeIndex))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case STMT_FOR_OF_LOOP:
|
||||
@ -578,9 +575,16 @@ NonLocalExitScope::prepareForNonLocalJump(StmtInfoBCE *toStmt)
|
||||
}
|
||||
|
||||
if (stmt->isBlockScope) {
|
||||
JS_ASSERT(stmt->isNestedScope);
|
||||
StaticBlockObject &blockObj = stmt->staticBlock();
|
||||
if (!popScopeForNonLocalExit(blockObj, stmt->blockScopeIndex))
|
||||
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
|
||||
return false;
|
||||
if (!popScopeForNonLocalExit(stmt->blockScopeIndex))
|
||||
return false;
|
||||
if (blockObj.needsClone()) {
|
||||
if (Emit1(cx, bce, JSOP_POPBLOCKSCOPE) < 0)
|
||||
return false;
|
||||
}
|
||||
npops += blockObj.slotCount();
|
||||
}
|
||||
}
|
||||
@ -728,6 +732,55 @@ ComputeAliasedSlots(ExclusiveContext *cx, BytecodeEmitter *bce, Handle<StaticBlo
|
||||
static bool
|
||||
EmitInternedObjectOp(ExclusiveContext *cx, uint32_t index, JSOp op, BytecodeEmitter *bce);
|
||||
|
||||
static bool
|
||||
EnterNestedScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmt, ObjectBox *objbox,
|
||||
StmtType stmtType)
|
||||
{
|
||||
Rooted<NestedScopeObject *> scopeObj(cx, &objbox->object->as<NestedScopeObject>());
|
||||
uint32_t scopeObjectIndex = bce->objectList.add(objbox);
|
||||
|
||||
switch (stmtType) {
|
||||
case STMT_BLOCK: {
|
||||
Rooted<StaticBlockObject *> blockObj(cx, &scopeObj->as<StaticBlockObject>());
|
||||
|
||||
if (!ComputeAliasedSlots(cx, bce, blockObj))
|
||||
return false;
|
||||
|
||||
if (blockObj->needsClone()) {
|
||||
if (!EmitInternedObjectOp(cx, scopeObjectIndex, JSOP_PUSHBLOCKSCOPE, bce))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STMT_WITH:
|
||||
JS_ASSERT(scopeObj->is<StaticWithObject>());
|
||||
if (!EmitInternedObjectOp(cx, scopeObjectIndex, JSOP_ENTERWITH, bce))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE();
|
||||
}
|
||||
|
||||
uint32_t parent = BlockScopeNote::NoBlockScopeIndex;
|
||||
if (bce->staticScope) {
|
||||
StmtInfoBCE *stmt = bce->topScopeStmt;
|
||||
for (; stmt->staticScope != bce->staticScope; stmt = stmt->down) {}
|
||||
parent = stmt->blockScopeIndex;
|
||||
}
|
||||
|
||||
stmt->blockScopeIndex = bce->blockScopeList.length();
|
||||
if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset(), parent))
|
||||
return false;
|
||||
|
||||
PushStatementBCE(bce, stmt, stmtType, bce->offset());
|
||||
scopeObj->initEnclosingNestedScope(EnclosingStaticScope(bce));
|
||||
FinishPushNestedScope(bce, stmt, *scopeObj);
|
||||
JS_ASSERT(stmt->isNestedScope);
|
||||
stmt->isBlockScope = (stmtType == STMT_BLOCK);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ~ Block Scopes ~
|
||||
//
|
||||
// A block scope is a region of a script with an additional set of named
|
||||
@ -771,50 +824,26 @@ EmitInternedObjectOp(ExclusiveContext *cx, uint32_t index, JSOp op, BytecodeEmit
|
||||
// for-in loops.
|
||||
//
|
||||
// Summary: Enter block scopes with EnterBlockScope. It will emit
|
||||
// PUSHBLOCKSCOPE if needed. Leave them with LeaveBlockScope, which will emit
|
||||
// PUSHBLOCKSCOPE if needed. Leave them with LeaveNestedScope, which will emit
|
||||
// DEBUGLEAVEBLOCK and may emit POPBLOCKSCOPE. Pass EnterBlockScope a fresh
|
||||
// StmtInfoBCE object, and pass that same object to the corresponding
|
||||
// LeaveBlockScope. Push locals before entering a scope, and pop them
|
||||
// LeaveNestedScope. Push locals before entering a scope, and pop them
|
||||
// afterwards. Brush your teeth, and clean behind your ears!
|
||||
//
|
||||
static bool
|
||||
EnterBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmt, ObjectBox *objbox,
|
||||
unsigned extraSlots)
|
||||
{
|
||||
uint32_t parent = BlockScopeNote::NoBlockScopeIndex;
|
||||
if (bce->staticScope) {
|
||||
StmtInfoBCE *stmt = bce->topScopeStmt;
|
||||
for (; stmt->staticScope != bce->staticScope; stmt = stmt->down) {}
|
||||
parent = stmt->blockScopeIndex;
|
||||
}
|
||||
|
||||
Rooted<StaticBlockObject *> blockObj(cx, &objbox->object->as<StaticBlockObject>());
|
||||
|
||||
uint32_t scopeObjectIndex = bce->objectList.add(objbox);
|
||||
|
||||
// FIXME: Once bug 962599 lands, we won't care about the stack depth, so we
|
||||
// won't have extraSlots and thus invocations of EnterBlockScope can become
|
||||
// invocations of EnterNestedScope.
|
||||
int depth = bce->stackDepth - (blockObj->slotCount() + extraSlots);
|
||||
JS_ASSERT(depth >= 0);
|
||||
blockObj->setStackDepth(depth);
|
||||
|
||||
if (!ComputeAliasedSlots(cx, bce, blockObj))
|
||||
return false;
|
||||
|
||||
if (blockObj->needsClone()) {
|
||||
if (!EmitInternedObjectOp(cx, scopeObjectIndex, JSOP_PUSHBLOCKSCOPE, bce))
|
||||
return false;
|
||||
}
|
||||
|
||||
stmt->blockScopeIndex = bce->blockScopeList.length();
|
||||
if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset(), parent))
|
||||
return false;
|
||||
|
||||
PushStatementBCE(bce, stmt, STMT_BLOCK, bce->offset());
|
||||
blockObj->initEnclosingNestedScope(EnclosingStaticScope(bce));
|
||||
FinishPushBlockScope(bce, stmt, *blockObj);
|
||||
|
||||
JS_ASSERT(stmt->isBlockScope);
|
||||
|
||||
return true;
|
||||
return EnterNestedScope(cx, bce, stmt, objbox, STMT_BLOCK);
|
||||
}
|
||||
|
||||
// Patches |breaks| and |continues| unless the top statement info record
|
||||
@ -835,10 +864,11 @@ PopStatementBCE(ExclusiveContext *cx, BytecodeEmitter *bce)
|
||||
}
|
||||
|
||||
static bool
|
||||
LeaveBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce)
|
||||
LeaveNestedScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmt)
|
||||
{
|
||||
StmtInfoBCE *stmt = bce->topStmt;
|
||||
JS_ASSERT(stmt->isBlockScope);
|
||||
JS_ASSERT(stmt == bce->topStmt);
|
||||
JS_ASSERT(stmt->isNestedScope);
|
||||
JS_ASSERT(stmt->isBlockScope == !(stmt->type == STMT_WITH));
|
||||
uint32_t blockScopeIndex = stmt->blockScopeIndex;
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -848,20 +878,18 @@ LeaveBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce)
|
||||
NestedScopeObject *staticScope = &blockObjBox->object->as<NestedScopeObject>();
|
||||
JS_ASSERT(stmt->staticScope == staticScope);
|
||||
JS_ASSERT(staticScope == bce->staticScope);
|
||||
JS_ASSERT_IF(!stmt->isBlockScope, staticScope->is<StaticWithObject>());
|
||||
#endif
|
||||
|
||||
JS_ASSERT(bce->staticScope->is<StaticBlockObject>());
|
||||
bool blockOnChain = bce->staticScope->as<StaticBlockObject>().needsClone();
|
||||
|
||||
if (!PopStatementBCE(cx, bce))
|
||||
return false;
|
||||
|
||||
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
|
||||
if (Emit1(cx, bce, stmt->isBlockScope ? JSOP_DEBUGLEAVEBLOCK : JSOP_LEAVEWITH) < 0)
|
||||
return false;
|
||||
|
||||
bce->blockScopeList.recordEnd(blockScopeIndex, bce->offset());
|
||||
|
||||
if (blockOnChain) {
|
||||
if (stmt->isBlockScope && stmt->staticScope->as<StaticBlockObject>().needsClone()) {
|
||||
if (Emit1(cx, bce, JSOP_POPBLOCKSCOPE) < 0)
|
||||
return false;
|
||||
}
|
||||
@ -1120,8 +1148,7 @@ EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *
|
||||
while (!b->containsVarAtDepth(depth)) {
|
||||
if (b->needsClone())
|
||||
skippedScopes++;
|
||||
b = b->enclosingBlock();
|
||||
JS_ASSERT(b);
|
||||
b = &b->enclosingNestedScope()->as<StaticBlockObject>();
|
||||
}
|
||||
if (!AssignHops(bce, pn, skippedScopes, &sc))
|
||||
return false;
|
||||
@ -1736,6 +1763,7 @@ CheckSideEffects(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool
|
||||
CheckSideEffects(cx, bce, pn->pn_kid3, answer);
|
||||
|
||||
case PN_BINARY:
|
||||
case PN_BINARY_OBJ:
|
||||
if (pn->isAssignment()) {
|
||||
/*
|
||||
* Assignment is presumed to be useful, even if the next operation
|
||||
@ -1888,7 +1916,7 @@ BytecodeEmitter::needsImplicitThis()
|
||||
} else {
|
||||
JSObject *scope = sc->asGlobalSharedContext()->scopeChain();
|
||||
while (scope) {
|
||||
if (scope->is<WithObject>())
|
||||
if (scope->is<DynamicWithObject>())
|
||||
return true;
|
||||
scope = scope->enclosingScope();
|
||||
}
|
||||
@ -2719,7 +2747,7 @@ EmitSwitch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
}
|
||||
|
||||
if (pn->pn_right->isKind(PNK_LEXICALSCOPE)) {
|
||||
if (!LeaveBlockScope(cx, bce))
|
||||
if (!LeaveNestedScope(cx, bce, &stmtInfo))
|
||||
return false;
|
||||
EMIT_UINT16_IMM_OP(JSOP_POPN, blockObj->slotCount());
|
||||
} else {
|
||||
@ -4269,7 +4297,7 @@ EmitLet(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pnLet)
|
||||
if (!EmitTree(cx, bce, letBody->pn_expr))
|
||||
return false;
|
||||
|
||||
if (!LeaveBlockScope(cx, bce))
|
||||
if (!LeaveNestedScope(cx, bce, &stmtInfo))
|
||||
return false;
|
||||
|
||||
JSOp leaveOp = letBody->getOp();
|
||||
@ -4305,7 +4333,7 @@ EmitLexicalScope(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
if (!EmitTree(cx, bce, pn->pn_expr))
|
||||
return false;
|
||||
|
||||
if (!LeaveBlockScope(cx, bce))
|
||||
if (!LeaveNestedScope(cx, bce, &stmtInfo))
|
||||
return false;
|
||||
|
||||
EMIT_UINT16_IMM_OP(JSOP_POPN, slots);
|
||||
@ -4319,15 +4347,13 @@ EmitWith(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
StmtInfoBCE stmtInfo(cx);
|
||||
if (!EmitTree(cx, bce, pn->pn_left))
|
||||
return false;
|
||||
PushStatementBCE(bce, &stmtInfo, STMT_WITH, bce->offset());
|
||||
if (Emit1(cx, bce, JSOP_ENTERWITH) < 0)
|
||||
if (!EnterNestedScope(cx, bce, &stmtInfo, pn->pn_binary_obj, STMT_WITH))
|
||||
return false;
|
||||
|
||||
if (!EmitTree(cx, bce, pn->pn_right))
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_LEAVEWITH) < 0)
|
||||
if (!LeaveNestedScope(cx, bce, &stmtInfo))
|
||||
return false;
|
||||
return PopStatementBCE(cx, bce);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -4474,7 +4500,7 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
return false;
|
||||
|
||||
if (letDecl) {
|
||||
if (!LeaveBlockScope(cx, bce))
|
||||
if (!LeaveNestedScope(cx, bce, &letStmt))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -4637,7 +4663,7 @@ EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
return false;
|
||||
|
||||
if (letDecl) {
|
||||
if (!LeaveBlockScope(cx, bce))
|
||||
if (!LeaveNestedScope(cx, bce, &letStmt))
|
||||
return false;
|
||||
EMIT_UINT16_IMM_OP(JSOP_POPN, blockObjCount);
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ ContainsVarOrConst(ParseNode *pn)
|
||||
return pnt;
|
||||
return ContainsVarOrConst(pn->pn_kid3);
|
||||
case PN_BINARY:
|
||||
case PN_BINARY_OBJ:
|
||||
/*
|
||||
* Limit recursion if pn is a binary expression, which can't contain a
|
||||
* var statement.
|
||||
@ -327,6 +328,7 @@ Fold(ExclusiveContext *cx, ParseNode **pnp,
|
||||
break;
|
||||
|
||||
case PN_BINARY:
|
||||
case PN_BINARY_OBJ:
|
||||
if (pn->isKind(PNK_OR) || pn->isKind(PNK_AND)) {
|
||||
// Propagate Condition context through logical connectives.
|
||||
SyntacticContext kidsc = SyntacticContext::Other;
|
||||
|
@ -385,8 +385,10 @@ class FullParseHandler
|
||||
return new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, pos, expr);
|
||||
}
|
||||
|
||||
ParseNode *newWithStatement(uint32_t begin, ParseNode *expr, ParseNode *body) {
|
||||
return new_<BinaryNode>(PNK_WITH, JSOP_NOP, TokenPos(begin, body->pn_pos.end), expr, body);
|
||||
ParseNode *newWithStatement(uint32_t begin, ParseNode *expr, ParseNode *body,
|
||||
ObjectBox *staticWith) {
|
||||
return new_<BinaryObjNode>(PNK_WITH, JSOP_NOP, TokenPos(begin, body->pn_pos.end),
|
||||
expr, body, staticWith);
|
||||
}
|
||||
|
||||
ParseNode *newLabeledStatement(PropertyName *label, ParseNode *stmt, uint32_t begin) {
|
||||
|
@ -310,6 +310,7 @@ class NameResolver
|
||||
return false;
|
||||
break;
|
||||
case PN_BINARY:
|
||||
case PN_BINARY_OBJ:
|
||||
if (!resolve(cur->pn_left, prefix))
|
||||
return false;
|
||||
|
||||
|
@ -170,6 +170,7 @@ PushNodeChildren(ParseNode *pn, NodeStack *stack)
|
||||
stack->pushUnlessNull(pn->pn_kid3);
|
||||
break;
|
||||
case PN_BINARY:
|
||||
case PN_BINARY_OBJ:
|
||||
if (pn->pn_left != pn->pn_right)
|
||||
stack->pushUnlessNull(pn->pn_left);
|
||||
stack->pushUnlessNull(pn->pn_right);
|
||||
@ -382,6 +383,15 @@ Parser<FullParseHandler>::cloneParseTree(ParseNode *opn)
|
||||
pn->pn_iflags = opn->pn_iflags;
|
||||
break;
|
||||
|
||||
case PN_BINARY_OBJ:
|
||||
NULLCHECK(pn->pn_left = cloneParseTree(opn->pn_left));
|
||||
if (opn->pn_right != opn->pn_left)
|
||||
NULLCHECK(pn->pn_right = cloneParseTree(opn->pn_right));
|
||||
else
|
||||
pn->pn_right = pn->pn_left;
|
||||
pn->pn_binary_obj = opn->pn_binary_obj;
|
||||
break;
|
||||
|
||||
case PN_UNARY:
|
||||
NULLCHECK(pn->pn_kid = cloneParseTree(opn->pn_kid));
|
||||
break;
|
||||
@ -548,6 +558,9 @@ ParseNode::dump(int indent)
|
||||
case PN_BINARY:
|
||||
((BinaryNode *) this)->dump(indent);
|
||||
break;
|
||||
case PN_BINARY_OBJ:
|
||||
((BinaryObjNode *) this)->dump(indent);
|
||||
break;
|
||||
case PN_TERNARY:
|
||||
((TernaryNode *) this)->dump(indent);
|
||||
break;
|
||||
@ -618,6 +631,18 @@ BinaryNode::dump(int indent)
|
||||
fprintf(stderr, ")");
|
||||
}
|
||||
|
||||
void
|
||||
BinaryObjNode::dump(int indent)
|
||||
{
|
||||
const char *name = parseNodeNames[getKind()];
|
||||
fprintf(stderr, "(%s ", name);
|
||||
indent += strlen(name) + 2;
|
||||
DumpParseTree(pn_left, indent);
|
||||
IndentNewLine(indent);
|
||||
DumpParseTree(pn_right, indent);
|
||||
fprintf(stderr, ")");
|
||||
}
|
||||
|
||||
void
|
||||
TernaryNode::dump(int indent)
|
||||
{
|
||||
|
@ -288,7 +288,7 @@ enum ParseNodeKind
|
||||
* pn_kid3: catch block statements
|
||||
* PNK_BREAK name pn_atom: label or null
|
||||
* PNK_CONTINUE name pn_atom: label or null
|
||||
* PNK_WITH binary pn_left: head expr, pn_right: body
|
||||
* PNK_WITH binary-obj pn_left: head expr; pn_right: body; pn_binary_obj: StaticWithObject
|
||||
* PNK_VAR, list pn_head: list of PNK_NAME or PNK_ASSIGN nodes
|
||||
* PNK_CONST each name node has either
|
||||
* pn_used: false
|
||||
@ -420,6 +420,7 @@ enum ParseNodeArity
|
||||
PN_NULLARY, /* 0 kids, only pn_atom/pn_dval/etc. */
|
||||
PN_UNARY, /* one kid, plus a couple of scalars */
|
||||
PN_BINARY, /* two kids, plus a couple of scalars */
|
||||
PN_BINARY_OBJ, /* two kids, plus an objbox */
|
||||
PN_TERNARY, /* three kids */
|
||||
PN_CODE, /* module or function definition node */
|
||||
PN_LIST, /* generic singly linked list */
|
||||
@ -516,7 +517,10 @@ class ParseNode
|
||||
struct { /* two kids if binary */
|
||||
ParseNode *left;
|
||||
ParseNode *right;
|
||||
unsigned iflags; /* JSITER_* flags for PNK_FOR node */
|
||||
union {
|
||||
unsigned iflags; /* JSITER_* flags for PNK_FOR node */
|
||||
ObjectBox *objbox; /* Only for PN_BINARY_OBJ */
|
||||
};
|
||||
} binary;
|
||||
struct { /* one kid if unary */
|
||||
ParseNode *kid;
|
||||
@ -570,6 +574,7 @@ class ParseNode
|
||||
#define pn_right pn_u.binary.right
|
||||
#define pn_pval pn_u.binary.pval
|
||||
#define pn_iflags pn_u.binary.iflags
|
||||
#define pn_binary_obj pn_u.binary.objbox
|
||||
#define pn_kid pn_u.unary.kid
|
||||
#define pn_prologue pn_u.unary.prologue
|
||||
#define pn_atom pn_u.name.atom
|
||||
@ -905,6 +910,30 @@ struct BinaryNode : public ParseNode
|
||||
#endif
|
||||
};
|
||||
|
||||
struct BinaryObjNode : public ParseNode
|
||||
{
|
||||
BinaryObjNode(ParseNodeKind kind, JSOp op, const TokenPos &pos, ParseNode *left, ParseNode *right,
|
||||
ObjectBox *objbox)
|
||||
: ParseNode(kind, op, PN_BINARY_OBJ, pos)
|
||||
{
|
||||
pn_left = left;
|
||||
pn_right = right;
|
||||
pn_binary_obj = objbox;
|
||||
}
|
||||
|
||||
static inline BinaryObjNode *create(ParseNodeKind kind, FullParseHandler *handler) {
|
||||
return (BinaryObjNode *) ParseNode::create(kind, PN_BINARY_OBJ, handler);
|
||||
}
|
||||
|
||||
static bool test(const ParseNode &node) {
|
||||
return node.isArity(PN_BINARY_OBJ);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void dump(int indent);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct TernaryNode : public ParseNode
|
||||
{
|
||||
TernaryNode(ParseNodeKind kind, JSOp op, ParseNode *kid1, ParseNode *kid2, ParseNode *kid3)
|
||||
|
@ -535,7 +535,7 @@ FunctionBox::FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunct
|
||||
//
|
||||
JSObject *scope = outerpc->sc->asGlobalSharedContext()->scopeChain();
|
||||
while (scope) {
|
||||
if (scope->is<WithObject>())
|
||||
if (scope->is<DynamicWithObject>())
|
||||
inWith = true;
|
||||
scope = scope->enclosingScope();
|
||||
}
|
||||
@ -2774,7 +2774,7 @@ static void
|
||||
PopStatementPC(TokenStream &ts, ParseContext<ParseHandler> *pc)
|
||||
{
|
||||
RootedNestedScopeObject scopeObj(ts.context(), pc->topStmt->staticScope);
|
||||
JS_ASSERT(!!scopeObj == (pc->topStmt->isBlockScope));
|
||||
JS_ASSERT(!!scopeObj == pc->topStmt->isNestedScope);
|
||||
|
||||
FinishPopStatement(pc);
|
||||
|
||||
@ -3196,7 +3196,8 @@ Parser<ParseHandler>::pushLexicalScope(HandleStaticBlockObject blockObj, StmtInf
|
||||
|
||||
PushStatementPC(pc, stmt, STMT_BLOCK);
|
||||
blockObj->initEnclosingNestedScopeFromParser(pc->staticScope);
|
||||
FinishPushBlockScope(pc, stmt, *blockObj.get());
|
||||
FinishPushNestedScope(pc, stmt, *blockObj.get());
|
||||
stmt->isBlockScope = true;
|
||||
|
||||
Node pn = handler.newLexicalScope(blockbox);
|
||||
if (!pn)
|
||||
@ -3593,7 +3594,7 @@ Parser<FullParseHandler>::letDeclaration()
|
||||
* lacks the SIF_SCOPE flag, it must be a try, catch, or finally
|
||||
* block.
|
||||
*/
|
||||
stmt->isBlockScope = true;
|
||||
stmt->isBlockScope = stmt->isNestedScope = true;
|
||||
stmt->downScope = pc->topScopeStmt;
|
||||
pc->topScopeStmt = stmt;
|
||||
|
||||
@ -4896,9 +4897,16 @@ Parser<FullParseHandler>::withStatement()
|
||||
|
||||
StmtInfoPC stmtInfo(context);
|
||||
PushStatementPC(pc, &stmtInfo, STMT_WITH);
|
||||
Rooted<StaticWithObject *> staticWith(context, StaticWithObject::create(context));
|
||||
if (!staticWith)
|
||||
return null();
|
||||
staticWith->initEnclosingNestedScopeFromParser(pc->staticScope);
|
||||
FinishPushNestedScope(pc, &stmtInfo, *staticWith);
|
||||
|
||||
Node innerBlock = statement();
|
||||
if (!innerBlock)
|
||||
return null();
|
||||
|
||||
PopStatementPC(tokenStream, pc);
|
||||
|
||||
pc->sc->setBindingsAccessedDynamically();
|
||||
@ -4914,7 +4922,10 @@ Parser<FullParseHandler>::withStatement()
|
||||
handler.deoptimizeUsesWithin(lexdep, TokenPos(begin, pos().begin));
|
||||
}
|
||||
|
||||
return handler.newWithStatement(begin, objectExpr, innerBlock);
|
||||
ObjectBox *staticWithBox = newObjectBox(staticWith);
|
||||
if (!staticWithBox)
|
||||
return null();
|
||||
return handler.newWithStatement(begin, objectExpr, innerBlock, staticWithBox);
|
||||
}
|
||||
|
||||
template <>
|
||||
@ -5860,6 +5871,7 @@ CompExprTransplanter::transplant(ParseNode *pn)
|
||||
break;
|
||||
|
||||
case PN_BINARY:
|
||||
case PN_BINARY_OBJ:
|
||||
if (!transplant(pn->pn_left))
|
||||
return false;
|
||||
|
||||
|
@ -389,22 +389,30 @@ enum StmtType {
|
||||
// work with both types.
|
||||
|
||||
struct StmtInfoBase {
|
||||
uint16_t type; /* statement type */
|
||||
// Statement type (StmtType).
|
||||
uint16_t type;
|
||||
|
||||
/*
|
||||
* True if type is STMT_BLOCK, STMT_TRY, STMT_SWITCH, or
|
||||
* STMT_FINALLY and the block contains at least one let-declaration.
|
||||
*/
|
||||
// True if type is STMT_BLOCK, STMT_TRY, STMT_SWITCH, or STMT_FINALLY and
|
||||
// the block contains at least one let-declaration, or if type is
|
||||
// STMT_CATCH.
|
||||
bool isBlockScope:1;
|
||||
|
||||
/* for (let ...) induced block scope */
|
||||
// True if isBlockScope or type == STMT_WITH.
|
||||
bool isNestedScope:1;
|
||||
|
||||
// for (let ...) induced block scope
|
||||
bool isForLetBlock:1;
|
||||
|
||||
RootedAtom label; /* name of LABEL */
|
||||
Rooted<NestedScopeObject *> staticScope; /* scope object */
|
||||
// Block label.
|
||||
RootedAtom label;
|
||||
|
||||
// Compile-time scope chain node for this scope. Only set if
|
||||
// isNestedScope.
|
||||
Rooted<NestedScopeObject *> staticScope;
|
||||
|
||||
StmtInfoBase(ExclusiveContext *cx)
|
||||
: isBlockScope(false), isForLetBlock(false), label(cx), staticScope(cx)
|
||||
: isBlockScope(false), isNestedScope(false), isForLetBlock(false),
|
||||
label(cx), staticScope(cx)
|
||||
{}
|
||||
|
||||
bool maybeScope() const {
|
||||
@ -412,12 +420,12 @@ struct StmtInfoBase {
|
||||
}
|
||||
|
||||
bool linksScope() const {
|
||||
return (STMT_WITH <= type && type <= STMT_CATCH) || isBlockScope;
|
||||
return isNestedScope;
|
||||
}
|
||||
|
||||
StaticBlockObject& staticBlock() const {
|
||||
JS_ASSERT(isNestedScope);
|
||||
JS_ASSERT(isBlockScope);
|
||||
JS_ASSERT(staticScope);
|
||||
return staticScope->as<StaticBlockObject>();
|
||||
}
|
||||
|
||||
@ -437,6 +445,7 @@ PushStatement(ContextT *ct, typename ContextT::StmtInfo *stmt, StmtType type)
|
||||
{
|
||||
stmt->type = type;
|
||||
stmt->isBlockScope = false;
|
||||
stmt->isNestedScope = false;
|
||||
stmt->isForLetBlock = false;
|
||||
stmt->label = nullptr;
|
||||
stmt->staticScope = nullptr;
|
||||
@ -452,9 +461,9 @@ PushStatement(ContextT *ct, typename ContextT::StmtInfo *stmt, StmtType type)
|
||||
|
||||
template <class ContextT>
|
||||
void
|
||||
FinishPushBlockScope(ContextT *ct, typename ContextT::StmtInfo *stmt, NestedScopeObject &staticScope)
|
||||
FinishPushNestedScope(ContextT *ct, typename ContextT::StmtInfo *stmt, NestedScopeObject &staticScope)
|
||||
{
|
||||
stmt->isBlockScope = true;
|
||||
stmt->isNestedScope = true;
|
||||
stmt->downScope = ct->topScopeStmt;
|
||||
ct->topScopeStmt = stmt;
|
||||
ct->staticScope = &staticScope;
|
||||
@ -472,8 +481,10 @@ FinishPopStatement(ContextT *ct)
|
||||
ct->topStmt = stmt->down;
|
||||
if (stmt->linksScope()) {
|
||||
ct->topScopeStmt = stmt->downScope;
|
||||
if (stmt->isBlockScope)
|
||||
ct->staticScope = stmt->staticBlock().enclosingBlock();
|
||||
if (stmt->isNestedScope) {
|
||||
JS_ASSERT(stmt->staticScope);
|
||||
ct->staticScope = stmt->staticScope->enclosingNestedScope();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5663,7 +5663,7 @@ TryAttachScopeNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *s
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!scopeChain->is<ScopeObject>() || scopeChain->is<WithObject>())
|
||||
if (!scopeChain->is<ScopeObject>() || scopeChain->is<DynamicWithObject>())
|
||||
return true;
|
||||
|
||||
// Check for an 'own' property on the scope. There is no need to
|
||||
|
@ -5952,4 +5952,3 @@ JSObject::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Objects
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -433,8 +433,9 @@ SaveSharedScriptData(ExclusiveContext *, Handle<JSScript *>, SharedScriptData *,
|
||||
|
||||
enum XDRClassKind {
|
||||
CK_BlockObject = 0,
|
||||
CK_JSFunction = 1,
|
||||
CK_JSObject = 2
|
||||
CK_WithObject = 1,
|
||||
CK_JSFunction = 2,
|
||||
CK_JSObject = 3
|
||||
};
|
||||
|
||||
template<XDRMode mode>
|
||||
@ -766,6 +767,8 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
|
||||
JSObject *obj = *objp;
|
||||
if (obj->is<BlockObject>())
|
||||
classk = CK_BlockObject;
|
||||
else if (obj->is<StaticWithObject>())
|
||||
classk = CK_WithObject;
|
||||
else if (obj->is<JSFunction>())
|
||||
classk = CK_JSFunction;
|
||||
else if (obj->is<JSObject>() || obj->is<ArrayObject>())
|
||||
@ -778,32 +781,40 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
|
||||
return false;
|
||||
|
||||
switch (classk) {
|
||||
case CK_BlockObject: {
|
||||
case CK_BlockObject:
|
||||
case CK_WithObject: {
|
||||
/* Code the nested block's enclosing scope. */
|
||||
uint32_t blockEnclosingScopeIndex = 0;
|
||||
uint32_t enclosingStaticScopeIndex = 0;
|
||||
if (mode == XDR_ENCODE) {
|
||||
NestedScopeObject &scope = (*objp)->as<NestedScopeObject>();
|
||||
if (NestedScopeObject *enclosing = scope.enclosingNestedScope())
|
||||
blockEnclosingScopeIndex = FindScopeObjectIndex(script, *enclosing);
|
||||
enclosingStaticScopeIndex = FindScopeObjectIndex(script, *enclosing);
|
||||
else
|
||||
blockEnclosingScopeIndex = UINT32_MAX;
|
||||
enclosingStaticScopeIndex = UINT32_MAX;
|
||||
}
|
||||
if (!xdr->codeUint32(&blockEnclosingScopeIndex))
|
||||
if (!xdr->codeUint32(&enclosingStaticScopeIndex))
|
||||
return false;
|
||||
Rooted<JSObject*> blockEnclosingScope(cx);
|
||||
Rooted<JSObject*> enclosingStaticScope(cx);
|
||||
if (mode == XDR_DECODE) {
|
||||
if (blockEnclosingScopeIndex != UINT32_MAX) {
|
||||
JS_ASSERT(blockEnclosingScopeIndex < i);
|
||||
blockEnclosingScope = script->objects()->vector[blockEnclosingScopeIndex];
|
||||
if (enclosingStaticScopeIndex != UINT32_MAX) {
|
||||
JS_ASSERT(enclosingStaticScopeIndex < i);
|
||||
enclosingStaticScope = script->objects()->vector[enclosingStaticScopeIndex];
|
||||
} else {
|
||||
blockEnclosingScope = fun;
|
||||
enclosingStaticScope = fun;
|
||||
}
|
||||
}
|
||||
|
||||
Rooted<StaticBlockObject*> tmp(cx, static_cast<StaticBlockObject *>(objp->get()));
|
||||
if (!XDRStaticBlockObject(xdr, blockEnclosingScope, tmp.address()))
|
||||
return false;
|
||||
*objp = tmp;
|
||||
if (classk == CK_BlockObject) {
|
||||
Rooted<StaticBlockObject*> tmp(cx, static_cast<StaticBlockObject *>(objp->get()));
|
||||
if (!XDRStaticBlockObject(xdr, enclosingStaticScope, tmp.address()))
|
||||
return false;
|
||||
*objp = tmp;
|
||||
} else {
|
||||
Rooted<StaticWithObject*> tmp(cx, static_cast<StaticWithObject *>(objp->get()));
|
||||
if (!XDRStaticWithObject(xdr, enclosingStaticScope, tmp.address()))
|
||||
return false;
|
||||
*objp = tmp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -396,7 +396,8 @@ class ReferenceFinder {
|
||||
/* Certain classes of object are for internal use only. */
|
||||
if (object->is<BlockObject>() ||
|
||||
object->is<CallObject>() ||
|
||||
object->is<WithObject>() ||
|
||||
object->is<StaticWithObject>() ||
|
||||
object->is<DynamicWithObject>() ||
|
||||
object->is<DeclEnvObject>()) {
|
||||
return JSVAL_VOID;
|
||||
}
|
||||
|
@ -5591,7 +5591,8 @@ IsDeclarative(Env *env)
|
||||
static bool
|
||||
IsWith(Env *env)
|
||||
{
|
||||
return env->is<DebugScopeObject>() && env->as<DebugScopeObject>().scope().is<WithObject>();
|
||||
return env->is<DebugScopeObject>() &&
|
||||
env->as<DebugScopeObject>().scope().is<DynamicWithObject>();
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -5641,7 +5642,7 @@ DebuggerEnv_getObject(JSContext *cx, unsigned argc, Value *vp)
|
||||
|
||||
JSObject *obj;
|
||||
if (IsWith(env)) {
|
||||
obj = &env->as<DebugScopeObject>().scope().as<WithObject>().object();
|
||||
obj = &env->as<DebugScopeObject>().scope().as<DynamicWithObject>().object();
|
||||
} else {
|
||||
obj = env;
|
||||
JS_ASSERT(!obj->is<DebugScopeObject>());
|
||||
|
@ -183,8 +183,8 @@ FetchName(JSContext *cx, HandleObject obj, HandleObject obj2, HandlePropertyName
|
||||
return false;
|
||||
} else {
|
||||
Rooted<JSObject*> normalized(cx, obj);
|
||||
if (normalized->getClass() == &WithObject::class_ && !shape->hasDefaultGetter())
|
||||
normalized = &normalized->as<WithObject>().object();
|
||||
if (normalized->is<DynamicWithObject>() && !shape->hasDefaultGetter())
|
||||
normalized = &normalized->as<DynamicWithObject>().object();
|
||||
if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {
|
||||
/* Fast path for Object instance properties. */
|
||||
JS_ASSERT(shape->hasSlot());
|
||||
|
@ -832,8 +832,10 @@ js::TypeOfValue(const Value &v)
|
||||
* of the with block with sp + stackIndex.
|
||||
*/
|
||||
static bool
|
||||
EnterWith(JSContext *cx, AbstractFramePtr frame, HandleValue val, uint32_t stackDepth)
|
||||
EnterWith(JSContext *cx, AbstractFramePtr frame, HandleValue val, uint32_t stackDepth,
|
||||
HandleObject staticWith)
|
||||
{
|
||||
JS_ASSERT(staticWith->is<StaticWithObject>());
|
||||
RootedObject obj(cx);
|
||||
if (val.isObject()) {
|
||||
obj = &val.toObject();
|
||||
@ -844,7 +846,8 @@ EnterWith(JSContext *cx, AbstractFramePtr frame, HandleValue val, uint32_t stack
|
||||
}
|
||||
|
||||
RootedObject scopeChain(cx, frame.scopeChain());
|
||||
WithObject *withobj = WithObject::create(cx, obj, scopeChain, stackDepth);
|
||||
DynamicWithObject *withobj = DynamicWithObject::create(cx, obj, scopeChain, stackDepth,
|
||||
staticWith);
|
||||
if (!withobj)
|
||||
return false;
|
||||
|
||||
@ -867,7 +870,7 @@ js::UnwindScope(JSContext *cx, ScopeIter &si, uint32_t stackDepth)
|
||||
si.frame().popBlock(cx);
|
||||
break;
|
||||
case ScopeIter::With:
|
||||
if (si.scope().as<WithObject>().stackDepth() < stackDepth)
|
||||
if (si.scope().as<DynamicWithObject>().stackDepth() < stackDepth)
|
||||
return;
|
||||
si.frame().popWith(cx);
|
||||
break;
|
||||
@ -1727,13 +1730,6 @@ END_CASE(JSOP_POP)
|
||||
CASE(JSOP_POPN)
|
||||
JS_ASSERT(GET_UINT16(REGS.pc) <= REGS.stackDepth());
|
||||
REGS.sp -= GET_UINT16(REGS.pc);
|
||||
#ifdef DEBUG
|
||||
if (NestedScopeObject *scope = script->getStaticScope(REGS.pc + JSOP_POPN_LENGTH)) {
|
||||
JS_ASSERT(scope->is<StaticBlockObject>());
|
||||
StaticBlockObject &blockObj = scope->as<StaticBlockObject>();
|
||||
JS_ASSERT(REGS.stackDepth() >= blockObj.stackDepth() + blockObj.slotCount());
|
||||
}
|
||||
#endif
|
||||
END_CASE(JSOP_POPN)
|
||||
|
||||
CASE(JSOP_POPNV)
|
||||
@ -1742,13 +1738,6 @@ CASE(JSOP_POPNV)
|
||||
Value val = REGS.sp[-1];
|
||||
REGS.sp -= GET_UINT16(REGS.pc);
|
||||
REGS.sp[-1] = val;
|
||||
#ifdef DEBUG
|
||||
if (NestedScopeObject *scope = script->getStaticScope(REGS.pc + JSOP_POPNV_LENGTH)) {
|
||||
JS_ASSERT(scope->is<StaticBlockObject>());
|
||||
StaticBlockObject &blockObj = scope->as<StaticBlockObject>();
|
||||
JS_ASSERT(REGS.stackDepth() >= blockObj.stackDepth() + blockObj.slotCount());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
END_CASE(JSOP_POPNV)
|
||||
|
||||
@ -1759,9 +1748,11 @@ END_CASE(JSOP_SETRVAL)
|
||||
CASE(JSOP_ENTERWITH)
|
||||
{
|
||||
RootedValue &val = rootValue0;
|
||||
RootedObject &staticWith = rootObject0;
|
||||
val = REGS.sp[-1];
|
||||
staticWith = script->getObject(REGS.pc);
|
||||
|
||||
if (!EnterWith(cx, REGS.fp(), val, REGS.stackDepth() - 1))
|
||||
if (!EnterWith(cx, REGS.fp(), val, REGS.stackDepth() - 1, staticWith))
|
||||
goto error;
|
||||
|
||||
/*
|
||||
|
@ -49,7 +49,7 @@
|
||||
/* Long-standing JavaScript bytecodes. */ \
|
||||
macro(JSOP_UNDEFINED, 1, js_undefined_str, "", 1, 0, 1, JOF_BYTE) \
|
||||
macro(JSOP_UNUSED2, 2, "unused2", NULL, 1, 1, 0, JOF_BYTE) \
|
||||
macro(JSOP_ENTERWITH, 3, "enterwith", NULL, 1, 1, 1, JOF_BYTE) \
|
||||
macro(JSOP_ENTERWITH, 3, "enterwith", NULL, 5, 1, 1, JOF_OBJECT) \
|
||||
macro(JSOP_LEAVEWITH, 4, "leavewith", NULL, 1, 1, 0, JOF_BYTE) \
|
||||
macro(JSOP_RETURN, 5, "return", NULL, 1, 1, 0, JOF_BYTE) \
|
||||
macro(JSOP_GOTO, 6, "goto", NULL, 5, 0, 0, JOF_JUMP) \
|
||||
|
@ -56,7 +56,7 @@ StaticScopeIter<allowGC>::operator++(int)
|
||||
} else {
|
||||
onNamedLambda = true;
|
||||
}
|
||||
JS_ASSERT_IF(obj, obj->template is<StaticBlockObject>() || obj->template is<JSFunction>());
|
||||
JS_ASSERT_IF(obj, obj->template is<NestedScopeObject>() || obj->template is<JSFunction>());
|
||||
JS_ASSERT_IF(onNamedLambda, obj->template is<JSFunction>());
|
||||
}
|
||||
|
||||
@ -66,7 +66,8 @@ StaticScopeIter<allowGC>::hasDynamicScopeObject() const
|
||||
{
|
||||
return obj->template is<StaticBlockObject>()
|
||||
? obj->template as<StaticBlockObject>().needsClone()
|
||||
: obj->template as<JSFunction>().isHeavyweight();
|
||||
: (obj->template is<StaticWithObject>() ||
|
||||
obj->template as<JSFunction>().isHeavyweight());
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
@ -88,7 +89,9 @@ StaticScopeIter<allowGC>::type() const
|
||||
{
|
||||
if (onNamedLambda)
|
||||
return NAMED_LAMBDA;
|
||||
return obj->template is<StaticBlockObject>() ? BLOCK : FUNCTION;
|
||||
return obj->template is<StaticBlockObject>()
|
||||
? BLOCK
|
||||
: (obj->template is<StaticWithObject>() ? WITH : FUNCTION);
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
@ -99,6 +102,14 @@ StaticScopeIter<allowGC>::block() const
|
||||
return obj->template as<StaticBlockObject>();
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
inline StaticWithObject &
|
||||
StaticScopeIter<allowGC>::staticWith() const
|
||||
{
|
||||
JS_ASSERT(type() == WITH);
|
||||
return obj->template as<StaticWithObject>();
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
inline JSScript *
|
||||
StaticScopeIter<allowGC>::funScript() const
|
||||
|
@ -346,14 +346,72 @@ DeclEnvObject::create(JSContext *cx, HandleObject enclosing, HandleFunction call
|
||||
return &obj->as<DeclEnvObject>();
|
||||
}
|
||||
|
||||
WithObject *
|
||||
WithObject::create(JSContext *cx, HandleObject proto, HandleObject enclosing, uint32_t depth)
|
||||
template<XDRMode mode>
|
||||
bool
|
||||
js::XDRStaticWithObject(XDRState<mode> *xdr, HandleObject enclosingScope, StaticWithObject **objp)
|
||||
{
|
||||
RootedTypeObject type(cx, cx->getNewType(&class_, proto.get()));
|
||||
if (mode == XDR_DECODE) {
|
||||
JSContext *cx = xdr->cx();
|
||||
Rooted<StaticWithObject*> obj(cx, StaticWithObject::create(cx));
|
||||
if (!obj)
|
||||
return false;
|
||||
obj->initEnclosingNestedScope(enclosingScope);
|
||||
*objp = obj;
|
||||
}
|
||||
// For encoding, there is nothing to do. The only information that is
|
||||
// encoded by a StaticWithObject is its presence on the scope chain, and the
|
||||
// script XDR handler already takes care of that.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template bool
|
||||
js::XDRStaticWithObject(XDRState<XDR_ENCODE> *, HandleObject, StaticWithObject **);
|
||||
|
||||
template bool
|
||||
js::XDRStaticWithObject(XDRState<XDR_DECODE> *, HandleObject, StaticWithObject **);
|
||||
|
||||
StaticWithObject *
|
||||
StaticWithObject::create(ExclusiveContext *cx)
|
||||
{
|
||||
RootedTypeObject type(cx, cx->getNewType(&class_, nullptr));
|
||||
if (!type)
|
||||
return nullptr;
|
||||
|
||||
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &class_, TaggedProto(proto),
|
||||
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &class_, TaggedProto(nullptr),
|
||||
nullptr, nullptr, FINALIZE_KIND));
|
||||
if (!shape)
|
||||
return nullptr;
|
||||
|
||||
RootedObject obj(cx, JSObject::create(cx, FINALIZE_KIND, gc::DefaultHeap, shape, type));
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
return &obj->as<StaticWithObject>();
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
CloneStaticWithObject(JSContext *cx, HandleObject enclosingScope, Handle<StaticWithObject*> srcWith)
|
||||
{
|
||||
Rooted<StaticWithObject*> clone(cx, StaticWithObject::create(cx));
|
||||
if (!clone)
|
||||
return nullptr;
|
||||
|
||||
clone->initEnclosingNestedScope(enclosingScope);
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
DynamicWithObject *
|
||||
DynamicWithObject::create(JSContext *cx, HandleObject object, HandleObject enclosing, uint32_t depth,
|
||||
HandleObject staticWith)
|
||||
{
|
||||
JS_ASSERT(staticWith->is<StaticWithObject>());
|
||||
RootedTypeObject type(cx, cx->getNewType(&class_, staticWith.get()));
|
||||
if (!type)
|
||||
return nullptr;
|
||||
|
||||
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &class_, TaggedProto(staticWith),
|
||||
&enclosing->global(), nullptr,
|
||||
FINALIZE_KIND));
|
||||
if (!shape)
|
||||
@ -363,23 +421,23 @@ WithObject::create(JSContext *cx, HandleObject proto, HandleObject enclosing, ui
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
obj->as<ScopeObject>().setEnclosingScope(enclosing);
|
||||
obj->setReservedSlot(DEPTH_SLOT, PrivateUint32Value(depth));
|
||||
|
||||
JSObject *thisp = JSObject::thisObject(cx, proto);
|
||||
JSObject *thisp = JSObject::thisObject(cx, object);
|
||||
if (!thisp)
|
||||
return nullptr;
|
||||
|
||||
obj->as<ScopeObject>().setEnclosingScope(enclosing);
|
||||
obj->setReservedSlot(DEPTH_SLOT, PrivateUint32Value(depth));
|
||||
obj->setFixedSlot(OBJECT_SLOT, ObjectValue(*object));
|
||||
obj->setFixedSlot(THIS_SLOT, ObjectValue(*thisp));
|
||||
|
||||
return &obj->as<WithObject>();
|
||||
return &obj->as<DynamicWithObject>();
|
||||
}
|
||||
|
||||
static bool
|
||||
with_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
|
||||
MutableHandleObject objp, MutableHandleShape propp)
|
||||
{
|
||||
RootedObject actual(cx, &obj->as<WithObject>().object());
|
||||
RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
|
||||
return JSObject::lookupGeneric(cx, actual, id, objp, propp);
|
||||
}
|
||||
|
||||
@ -413,7 +471,7 @@ static bool
|
||||
with_GetGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
|
||||
MutableHandleValue vp)
|
||||
{
|
||||
RootedObject actual(cx, &obj->as<WithObject>().object());
|
||||
RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
|
||||
return JSObject::getGeneric(cx, actual, actual, id, vp);
|
||||
}
|
||||
|
||||
@ -447,7 +505,7 @@ static bool
|
||||
with_SetGeneric(JSContext *cx, HandleObject obj, HandleId id,
|
||||
MutableHandleValue vp, bool strict)
|
||||
{
|
||||
RootedObject actual(cx, &obj->as<WithObject>().object());
|
||||
RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
|
||||
return JSObject::setGeneric(cx, actual, actual, id, vp, strict);
|
||||
}
|
||||
|
||||
@ -455,7 +513,7 @@ static bool
|
||||
with_SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
|
||||
MutableHandleValue vp, bool strict)
|
||||
{
|
||||
RootedObject actual(cx, &obj->as<WithObject>().object());
|
||||
RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
|
||||
return JSObject::setProperty(cx, actual, actual, name, vp, strict);
|
||||
}
|
||||
|
||||
@ -463,7 +521,7 @@ static bool
|
||||
with_SetElement(JSContext *cx, HandleObject obj, uint32_t index,
|
||||
MutableHandleValue vp, bool strict)
|
||||
{
|
||||
RootedObject actual(cx, &obj->as<WithObject>().object());
|
||||
RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
|
||||
return JSObject::setElement(cx, actual, actual, index, vp, strict);
|
||||
}
|
||||
|
||||
@ -471,21 +529,21 @@ static bool
|
||||
with_SetSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
|
||||
MutableHandleValue vp, bool strict)
|
||||
{
|
||||
RootedObject actual(cx, &obj->as<WithObject>().object());
|
||||
RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
|
||||
return JSObject::setSpecial(cx, actual, actual, sid, vp, strict);
|
||||
}
|
||||
|
||||
static bool
|
||||
with_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
|
||||
{
|
||||
RootedObject actual(cx, &obj->as<WithObject>().object());
|
||||
RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
|
||||
return JSObject::getGenericAttributes(cx, actual, id, attrsp);
|
||||
}
|
||||
|
||||
static bool
|
||||
with_SetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
|
||||
{
|
||||
RootedObject actual(cx, &obj->as<WithObject>().object());
|
||||
RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
|
||||
return JSObject::setGenericAttributes(cx, actual, id, attrsp);
|
||||
}
|
||||
|
||||
@ -493,7 +551,7 @@ static bool
|
||||
with_DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
|
||||
bool *succeeded)
|
||||
{
|
||||
RootedObject actual(cx, &obj->as<WithObject>().object());
|
||||
RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
|
||||
return JSObject::deleteProperty(cx, actual, name, succeeded);
|
||||
}
|
||||
|
||||
@ -501,7 +559,7 @@ static bool
|
||||
with_DeleteElement(JSContext *cx, HandleObject obj, uint32_t index,
|
||||
bool *succeeded)
|
||||
{
|
||||
RootedObject actual(cx, &obj->as<WithObject>().object());
|
||||
RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
|
||||
return JSObject::deleteElement(cx, actual, index, succeeded);
|
||||
}
|
||||
|
||||
@ -509,27 +567,33 @@ static bool
|
||||
with_DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
|
||||
bool *succeeded)
|
||||
{
|
||||
RootedObject actual(cx, &obj->as<WithObject>().object());
|
||||
RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
|
||||
return JSObject::deleteSpecial(cx, actual, sid, succeeded);
|
||||
}
|
||||
|
||||
static bool
|
||||
with_Enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
|
||||
MutableHandleValue statep, MutableHandleId idp)
|
||||
{
|
||||
RootedObject actual(cx, &obj->as<WithObject>().object());
|
||||
return JSObject::enumerate(cx, actual, enum_op, statep, idp);
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
with_ThisObject(JSContext *cx, HandleObject obj)
|
||||
{
|
||||
return &obj->as<WithObject>().withThis();
|
||||
return &obj->as<DynamicWithObject>().withThis();
|
||||
}
|
||||
|
||||
const Class WithObject::class_ = {
|
||||
const Class StaticWithObject::class_ = {
|
||||
"WithTemplate",
|
||||
JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(StaticWithObject::RESERVED_SLOTS) |
|
||||
JSCLASS_IS_ANONYMOUS,
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_DeletePropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub
|
||||
};
|
||||
|
||||
const Class DynamicWithObject::class_ = {
|
||||
"With",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(WithObject::RESERVED_SLOTS) |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(DynamicWithObject::RESERVED_SLOTS) |
|
||||
JSCLASS_IS_ANONYMOUS,
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_DeletePropertyStub, /* delProperty */
|
||||
@ -569,7 +633,7 @@ const Class WithObject::class_ = {
|
||||
with_DeleteSpecial,
|
||||
nullptr, nullptr, /* watch/unwatch */
|
||||
nullptr, /* slice */
|
||||
with_Enumerate,
|
||||
nullptr, /* enumerate (native enumeration of target doesn't work) */
|
||||
with_ThisObject,
|
||||
}
|
||||
};
|
||||
@ -845,9 +909,13 @@ CloneStaticBlockObject(JSContext *cx, HandleObject enclosingScope, Handle<Static
|
||||
JSObject *
|
||||
js::CloneNestedScopeObject(JSContext *cx, HandleObject enclosingScope, Handle<NestedScopeObject*> srcBlock)
|
||||
{
|
||||
JS_ASSERT(srcBlock->is<StaticBlockObject>());
|
||||
Rooted<StaticBlockObject *> blockObj(cx, &srcBlock->as<StaticBlockObject>());
|
||||
return CloneStaticBlockObject(cx, enclosingScope, blockObj);
|
||||
if (srcBlock->is<StaticBlockObject>()) {
|
||||
Rooted<StaticBlockObject *> blockObj(cx, &srcBlock->as<StaticBlockObject>());
|
||||
return CloneStaticBlockObject(cx, enclosingScope, blockObj);
|
||||
} else {
|
||||
Rooted<StaticWithObject *> withObj(cx, &srcBlock->as<StaticWithObject>());
|
||||
return CloneStaticWithObject(cx, enclosingScope, withObj);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -929,14 +997,17 @@ ScopeIter::operator++()
|
||||
frame_ = NullFramePtr();
|
||||
break;
|
||||
case Block:
|
||||
staticScope_ = staticScope_->as<StaticBlockObject>().enclosingBlock();
|
||||
JS_ASSERT(staticScope_ && staticScope_->is<StaticBlockObject>());
|
||||
staticScope_ = staticScope_->as<StaticBlockObject>().enclosingNestedScope();
|
||||
if (hasScopeObject_)
|
||||
cur_ = &cur_->as<ClonedBlockObject>().enclosingScope();
|
||||
settle();
|
||||
break;
|
||||
case With:
|
||||
JS_ASSERT(staticScope_ && staticScope_->is<StaticWithObject>());
|
||||
JS_ASSERT(hasScopeObject_);
|
||||
cur_ = &cur_->as<WithObject>().enclosingScope();
|
||||
staticScope_ = staticScope_->as<StaticWithObject>().enclosingNestedScope();
|
||||
cur_ = &cur_->as<DynamicWithObject>().enclosingScope();
|
||||
settle();
|
||||
break;
|
||||
case StrictEvalScope:
|
||||
@ -976,6 +1047,8 @@ ScopeIter::settle()
|
||||
*/
|
||||
if (frame_.isNonEvalFunctionFrame() && !frame_.fun()->isHeavyweight()) {
|
||||
if (staticScope_) {
|
||||
// If staticScope_ were a StaticWithObject, the function would be
|
||||
// heavyweight.
|
||||
JS_ASSERT(staticScope_->is<StaticBlockObject>());
|
||||
type_ = Block;
|
||||
hasScopeObject_ = staticScope_->as<StaticBlockObject>().needsClone();
|
||||
@ -998,18 +1071,18 @@ ScopeIter::settle()
|
||||
} else if (frame_.isStrictEvalFrame() && !frame_.hasCallObj()) {
|
||||
JS_ASSERT(cur_ == frame_.evalPrevScopeChain(cx));
|
||||
frame_ = NullFramePtr();
|
||||
} else if (cur_->is<WithObject>()) {
|
||||
JS_ASSERT_IF(frame_.isFunctionFrame(), frame_.fun()->isHeavyweight());
|
||||
JS_ASSERT_IF(staticScope_, staticScope_->as<StaticBlockObject>().needsClone());
|
||||
JS_ASSERT_IF(staticScope_,
|
||||
staticScope_->as<StaticBlockObject>().stackDepth() <
|
||||
cur_->as<WithObject>().stackDepth());
|
||||
type_ = With;
|
||||
hasScopeObject_ = true;
|
||||
} else if (staticScope_) {
|
||||
type_ = Block;
|
||||
hasScopeObject_ = staticScope_->as<StaticBlockObject>().needsClone();
|
||||
JS_ASSERT_IF(hasScopeObject_, cur_->as<ClonedBlockObject>().staticBlock() == *staticScope_);
|
||||
if (staticScope_->is<StaticWithObject>()) {
|
||||
JS_ASSERT(cur_);
|
||||
JS_ASSERT(cur_->as<DynamicWithObject>().staticScope() == staticScope_);
|
||||
type_ = With;
|
||||
hasScopeObject_ = true;
|
||||
} else {
|
||||
type_ = Block;
|
||||
hasScopeObject_ = staticScope_->as<StaticBlockObject>().needsClone();
|
||||
JS_ASSERT_IF(hasScopeObject_,
|
||||
cur_->as<ClonedBlockObject>().staticBlock() == *staticScope_);
|
||||
}
|
||||
} else if (cur_->is<CallObject>()) {
|
||||
CallObject &callobj = cur_->as<CallObject>();
|
||||
type_ = callobj.isForEval() ? StrictEvalScope : Call;
|
||||
@ -1211,7 +1284,7 @@ class DebugScopeProxy : public BaseProxyHandler
|
||||
}
|
||||
|
||||
/* The rest of the internal scopes do not have unaliased vars. */
|
||||
JS_ASSERT(scope->is<DeclEnvObject>() || scope->is<WithObject>() ||
|
||||
JS_ASSERT(scope->is<DeclEnvObject>() || scope->is<DynamicWithObject>() ||
|
||||
scope->as<CallObject>().isForEval());
|
||||
return false;
|
||||
}
|
||||
@ -1385,7 +1458,15 @@ class DebugScopeProxy : public BaseProxyHandler
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GetPropertyNames(cx, scope, flags, &props))
|
||||
// DynamicWithObject isn't a very good proxy. It doesn't have a
|
||||
// JSNewEnumerateOp implementation, because if it just delegated to the
|
||||
// target object, the object would indicate that native enumeration is
|
||||
// the thing to do, but native enumeration over the DynamicWithObject
|
||||
// wrapper yields no properties. So instead here we hack around the
|
||||
// issue, and punch a hole through to the with object target.
|
||||
Rooted<JSObject*> target(cx, (scope->is<DynamicWithObject>()
|
||||
? &scope->as<DynamicWithObject>().object() : scope));
|
||||
if (!GetPropertyNames(cx, target, flags, &props))
|
||||
return false;
|
||||
|
||||
/*
|
||||
@ -1928,7 +2009,7 @@ DebugScopes::onPopWith(AbstractFramePtr frame)
|
||||
{
|
||||
DebugScopes *scopes = frame.compartment()->debugScopes;
|
||||
if (scopes)
|
||||
scopes->liveScopes.remove(&frame.scopeChain()->as<WithObject>());
|
||||
scopes->liveScopes.remove(&frame.scopeChain()->as<DynamicWithObject>());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -18,6 +18,8 @@ namespace js {
|
||||
|
||||
namespace frontend { struct Definition; }
|
||||
|
||||
class StaticWithObject;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
@ -65,14 +67,16 @@ class StaticScopeIter
|
||||
: obj(cx, obj), onNamedLambda(false)
|
||||
{
|
||||
JS_STATIC_ASSERT(allowGC == CanGC);
|
||||
JS_ASSERT_IF(obj, obj->is<StaticBlockObject>() || obj->is<JSFunction>());
|
||||
JS_ASSERT_IF(obj, obj->is<StaticBlockObject>() || obj->is<StaticWithObject>() ||
|
||||
obj->is<JSFunction>());
|
||||
}
|
||||
|
||||
StaticScopeIter(JSObject *obj)
|
||||
: obj((ExclusiveContext *) nullptr, obj), onNamedLambda(false)
|
||||
{
|
||||
JS_STATIC_ASSERT(allowGC == NoGC);
|
||||
JS_ASSERT_IF(obj, obj->is<StaticBlockObject>() || obj->is<JSFunction>());
|
||||
JS_ASSERT_IF(obj, obj->is<StaticBlockObject>() || obj->is<StaticWithObject>() ||
|
||||
obj->is<JSFunction>());
|
||||
}
|
||||
|
||||
bool done() const;
|
||||
@ -82,10 +86,11 @@ class StaticScopeIter
|
||||
bool hasDynamicScopeObject() const;
|
||||
Shape *scopeShape() const;
|
||||
|
||||
enum Type { BLOCK, FUNCTION, NAMED_LAMBDA };
|
||||
enum Type { WITH, BLOCK, FUNCTION, NAMED_LAMBDA };
|
||||
Type type() const;
|
||||
|
||||
StaticBlockObject &block() const;
|
||||
StaticWithObject &staticWith() const;
|
||||
JSScript *funScript() const;
|
||||
};
|
||||
|
||||
@ -159,9 +164,11 @@ ScopeCoordinateFunctionScript(JSScript *script, jsbytecode *pc);
|
||||
* \ CallObject Scope of entire function or strict eval
|
||||
* \
|
||||
* NestedScopeObject Scope created for a statement
|
||||
* \ \
|
||||
* \ WithObject with
|
||||
* \
|
||||
* \ \ \
|
||||
* \ \ StaticWithObject Template for "with" object in static scope chain
|
||||
* \ \
|
||||
* \ DynamicWithObject Run-time "with" object on scope chain
|
||||
* \
|
||||
* BlockObject Shared interface of cloned/static block objects
|
||||
* \ \
|
||||
* \ ClonedBlockObject let, switch, catch, for
|
||||
@ -316,6 +323,15 @@ class NestedScopeObject : public ScopeObject
|
||||
*/
|
||||
inline NestedScopeObject *enclosingNestedScope() const;
|
||||
|
||||
// Return true if this object is a compile-time scope template.
|
||||
inline bool isStatic() { return !getProto(); }
|
||||
|
||||
// Return the static scope corresponding to this scope chain object.
|
||||
inline NestedScopeObject* staticScope() {
|
||||
JS_ASSERT(!isStatic());
|
||||
return &getProto()->as<NestedScopeObject>();
|
||||
}
|
||||
|
||||
// At compile-time it's possible for the scope chain to be null.
|
||||
JSObject *enclosingScopeForStaticScopeIter() {
|
||||
return getReservedSlot(SCOPE_CHAIN_SLOT).toObjectOrNull();
|
||||
@ -342,30 +358,46 @@ class NestedScopeObject : public ScopeObject
|
||||
}
|
||||
};
|
||||
|
||||
class WithObject : public NestedScopeObject
|
||||
// With scope template objects on the static scope chain.
|
||||
class StaticWithObject : public NestedScopeObject
|
||||
{
|
||||
static const unsigned THIS_SLOT = 2;
|
||||
public:
|
||||
static const unsigned RESERVED_SLOTS = 2;
|
||||
static const gc::AllocKind FINALIZE_KIND = gc::FINALIZE_OBJECT2_BACKGROUND;
|
||||
|
||||
/* Use WithObject::object() instead. */
|
||||
JSObject *getProto() const;
|
||||
static const Class class_;
|
||||
|
||||
static StaticWithObject *create(ExclusiveContext *cx);
|
||||
};
|
||||
|
||||
// With scope objects on the run-time scope chain.
|
||||
class DynamicWithObject : public NestedScopeObject
|
||||
{
|
||||
static const unsigned OBJECT_SLOT = 2;
|
||||
static const unsigned THIS_SLOT = 3;
|
||||
|
||||
public:
|
||||
static const unsigned RESERVED_SLOTS = 3;
|
||||
static const unsigned RESERVED_SLOTS = 4;
|
||||
static const gc::AllocKind FINALIZE_KIND = gc::FINALIZE_OBJECT4_BACKGROUND;
|
||||
|
||||
static const Class class_;
|
||||
|
||||
static WithObject *
|
||||
create(JSContext *cx, HandleObject proto, HandleObject enclosing, uint32_t depth);
|
||||
static DynamicWithObject *
|
||||
create(JSContext *cx, HandleObject object, HandleObject enclosing, uint32_t depth,
|
||||
HandleObject staticWith);
|
||||
|
||||
/* Return object for the 'this' class hook. */
|
||||
JSObject &withThis() const {
|
||||
return getReservedSlot(THIS_SLOT).toObject();
|
||||
StaticWithObject& staticWith() const {
|
||||
return getProto()->as<StaticWithObject>();
|
||||
}
|
||||
|
||||
/* Return the 'o' in 'with (o)'. */
|
||||
JSObject &object() const {
|
||||
return *JSObject::getProto();
|
||||
return getReservedSlot(OBJECT_SLOT).toObject();
|
||||
}
|
||||
|
||||
/* Return object for the 'this' class hook. */
|
||||
JSObject &withThis() const {
|
||||
return getReservedSlot(THIS_SLOT).toObject();
|
||||
}
|
||||
};
|
||||
|
||||
@ -412,12 +444,6 @@ class StaticBlockObject : public BlockObject
|
||||
public:
|
||||
static StaticBlockObject *create(ExclusiveContext *cx);
|
||||
|
||||
/*
|
||||
* A refinement of enclosingScope that returns nullptr if the enclosing
|
||||
* static scope is a JSFunction.
|
||||
*/
|
||||
inline StaticBlockObject *enclosingBlock() const;
|
||||
|
||||
/*
|
||||
* Return whether this StaticBlockObject contains a variable stored at
|
||||
* the given stack depth (i.e., fp->base()[depth]).
|
||||
@ -520,6 +546,11 @@ bool
|
||||
XDRStaticBlockObject(XDRState<mode> *xdr, HandleObject enclosingScope,
|
||||
StaticBlockObject **objp);
|
||||
|
||||
template<XDRMode mode>
|
||||
bool
|
||||
XDRStaticWithObject(XDRState<mode> *xdr, HandleObject enclosingScope,
|
||||
StaticWithObject **objp);
|
||||
|
||||
extern JSObject *
|
||||
CloneNestedScopeObject(JSContext *cx, HandleObject enclosingScope, Handle<NestedScopeObject*> src);
|
||||
|
||||
@ -806,7 +837,7 @@ template<>
|
||||
inline bool
|
||||
JSObject::is<js::NestedScopeObject>() const
|
||||
{
|
||||
return is<js::BlockObject>() || is<js::WithObject>();
|
||||
return is<js::BlockObject>() || is<js::StaticWithObject>() || is<js::DynamicWithObject>();
|
||||
}
|
||||
|
||||
template<>
|
||||
@ -867,13 +898,6 @@ NestedScopeObject::enclosingNestedScope() const
|
||||
return obj && obj->is<NestedScopeObject>() ? &obj->as<NestedScopeObject>() : nullptr;
|
||||
}
|
||||
|
||||
inline StaticBlockObject *
|
||||
StaticBlockObject::enclosingBlock() const
|
||||
{
|
||||
JSObject *obj = getReservedSlot(SCOPE_CHAIN_SLOT).toObjectOrNull();
|
||||
return obj && obj->is<StaticBlockObject>() ? &obj->as<StaticBlockObject>() : nullptr;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
AnalyzeEntrainedVariables(JSContext *cx, HandleScript script);
|
||||
|
@ -133,8 +133,8 @@ Shape::set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict,
|
||||
* |with (it) color='red';| ends up here.
|
||||
* Avoid exposing the With object to native setters.
|
||||
*/
|
||||
if (obj->is<WithObject>()) {
|
||||
RootedObject nobj(cx, &obj->as<WithObject>().object());
|
||||
if (obj->is<DynamicWithObject>()) {
|
||||
RootedObject nobj(cx, &obj->as<DynamicWithObject>().object());
|
||||
return CallJSPropertyOpSetter(cx, self->setterOp(), nobj, id, strict, vp);
|
||||
}
|
||||
|
||||
|
@ -182,18 +182,15 @@ AssertDynamicScopeMatchesStaticScope(JSContext *cx, JSScript *script, JSObject *
|
||||
RootedObject enclosingScope(cx, script->enclosingStaticScope());
|
||||
for (StaticScopeIter<NoGC> i(enclosingScope); !i.done(); i++) {
|
||||
if (i.hasDynamicScopeObject()) {
|
||||
/*
|
||||
* 'with' does not participate in the static scope of the script,
|
||||
* but it does in the dynamic scope, so skip them here.
|
||||
*/
|
||||
while (scope->is<WithObject>())
|
||||
scope = &scope->as<WithObject>().enclosingScope();
|
||||
|
||||
switch (i.type()) {
|
||||
case StaticScopeIter<NoGC>::BLOCK:
|
||||
JS_ASSERT(i.block() == scope->as<ClonedBlockObject>().staticBlock());
|
||||
JS_ASSERT(&i.block() == scope->as<ClonedBlockObject>().staticScope());
|
||||
scope = &scope->as<ClonedBlockObject>().enclosingScope();
|
||||
break;
|
||||
case StaticScopeIter<NoGC>::WITH:
|
||||
JS_ASSERT(&i.staticWith() == scope->as<DynamicWithObject>().staticScope());
|
||||
scope = &scope->as<DynamicWithObject>().enclosingScope();
|
||||
break;
|
||||
case StaticScopeIter<NoGC>::FUNCTION:
|
||||
JS_ASSERT(scope->as<CallObject>().callee().nonLazyScript() == i.funScript());
|
||||
scope = &scope->as<CallObject>().enclosingScope();
|
||||
@ -350,7 +347,7 @@ StackFrame::popWith(JSContext *cx)
|
||||
if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
|
||||
DebugScopes::onPopWith(this);
|
||||
|
||||
JS_ASSERT(scopeChain()->is<WithObject>());
|
||||
JS_ASSERT(scopeChain()->is<DynamicWithObject>());
|
||||
popOffScopeChain();
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,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 - 165);
|
||||
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 166);
|
||||
|
||||
class XDRBuffer {
|
||||
public:
|
||||
|
Loading…
Reference in New Issue
Block a user