Bug 753158 - emit ALIASEDVAR ops for upvars (r=bhackett)

--HG--
extra : rebase_source : 1e868b37de87f94799500019cc13e7b8abe3c0f3
This commit is contained in:
Luke Wagner 2012-07-05 20:35:08 -07:00
parent 852895f9c2
commit 062bdf6738
15 changed files with 183 additions and 198 deletions

View File

@ -873,6 +873,7 @@ EmitAliasedVarOp(JSContext *cx, JSOp op, ScopeCoordinate sc, BytecodeEmitter *bc
SET_UINT16(pc, sc.slot);
pc += sizeof(uint16_t);
SET_UINT32_INDEX(pc, maybeBlockIndex);
CheckTypeSet(cx, bce, op);
return true;
}
@ -891,40 +892,48 @@ ClonedBlockDepth(BytecodeEmitter *bce)
static bool
EmitAliasedVarOp(JSContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *bce)
{
/* This restriction will be removed shortly by bug 753158. */
JS_ASSERT(pn->isUsed() || pn->isDefn());
JS_ASSERT_IF(pn->isUsed(), pn->pn_cookie.level() == 0);
JS_ASSERT_IF(pn->isDefn(), pn->pn_cookie.level() == bce->script->staticLevel);
unsigned skippedScopes = 0;
BytecodeEmitter *bceOfDef = bce;
if (pn->isUsed()) {
/*
* As explained in BindNameToSlot, the 'level' of a use indicates how
* many function scopes (i.e., BytecodeEmitters) to skip to find the
* enclosing function scope of the definition being accessed.
*/
for (unsigned i = pn->pn_cookie.level(); i; i--) {
skippedScopes += ClonedBlockDepth(bceOfDef);
if (bceOfDef->sc->funIsHeavyweight()) {
skippedScopes++;
if (bceOfDef->sc->fun()->isNamedLambda())
skippedScopes++;
}
bceOfDef = bceOfDef->parent;
}
} else {
JS_ASSERT(pn->isDefn());
JS_ASSERT(pn->pn_cookie.level() == bce->script->staticLevel);
}
/*
* The contents of the dynamic scope chain (fp->scopeChain) exactly reflect
* the needsClone-subset of the block chain. Use this to determine the
* number of ClonedBlockObjects on fp->scopeChain to skip to find the scope
* object containing the var to which pn is bound. ALIASEDVAR ops cannot
* reach across with scopes so ClonedBlockObjects is the only NestedScope
* on the scope chain.
*/
ScopeCoordinate sc;
if (JOF_OPTYPE(pn->getOp()) == JOF_QARG) {
sc.hops = ClonedBlockDepth(bce);
sc.slot = bce->sc->bindings.formalIndexToSlot(pn->pn_cookie.slot());
sc.hops = skippedScopes + ClonedBlockDepth(bceOfDef);
sc.slot = bceOfDef->sc->bindings.formalIndexToSlot(pn->pn_cookie.slot());
} else {
JS_ASSERT(JOF_OPTYPE(pn->getOp()) == JOF_LOCAL || pn->isKind(PNK_FUNCTION));
unsigned local = pn->pn_cookie.slot();
if (local < bce->sc->bindings.numVars()) {
sc.hops = ClonedBlockDepth(bce);
sc.slot = bce->sc->bindings.varIndexToSlot(local);
if (local < bceOfDef->sc->bindings.numVars()) {
sc.hops = skippedScopes + ClonedBlockDepth(bceOfDef);
sc.slot = bceOfDef->sc->bindings.varIndexToSlot(local);
} else {
unsigned depth = local - bce->sc->bindings.numVars();
unsigned hops = 0;
StaticBlockObject *b = bce->blockChain;
unsigned depth = local - bceOfDef->sc->bindings.numVars();
StaticBlockObject *b = bceOfDef->blockChain;
while (!b->containsVarAtDepth(depth)) {
if (b->needsClone())
hops++;
skippedScopes++;
b = b->enclosingBlock();
}
sc.hops = hops;
sc.slot = b->localIndexToSlot(bce->sc->bindings, local);
sc.hops = skippedScopes;
sc.slot = b->localIndexToSlot(bceOfDef->sc->bindings, local);
}
}
@ -1325,12 +1334,6 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
JS_ASSERT(pn->pn_lexdef);
JS_ASSERT(pn->pn_cookie.isFree());
/* TODO: actually the comment lies; until bug 753158, y will stay a NAME. */
if (dn->pn_cookie.level() != bce->script->staticLevel) {
JS_ASSERT(dn->isClosed());
return true;
}
/*
* We are compiling a function body and may be able to optimize name
* to stack slot. Look for an argument or variable in the function and
@ -1356,6 +1359,14 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
case Definition::VAR:
if (dn->isOp(JSOP_CALLEE)) {
JS_ASSERT(op != JSOP_CALLEE);
/*
* Currently, the ALIASEDVAR ops do not support accessing the
* callee of a DeclEnvObject, so use NAME.
*/
if (dn->pn_cookie.level() != bce->script->staticLevel)
return true;
JS_ASSERT(bce->sc->fun()->flags & JSFUN_LAMBDA);
JS_ASSERT(pn->pn_atom == bce->sc->fun()->atom);
@ -1414,9 +1425,34 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
JS_NOT_REACHED("unexpected dn->kind()");
}
/*
* The difference between the current static level and the static level of
* the definition is the number of function scopes between the current
* scope and dn's scope.
*/
unsigned skip = bce->script->staticLevel - dn->pn_cookie.level();
JS_ASSERT_IF(skip, dn->isClosed());
/*
* Explicitly disallow accessing var/let bindings in global scope from
* nested functions. The reason for this limitation is that, since the
* global script is not included in the static scope chain (1. because it
* has no object to stand in the static scope chain, 2. to minimize memory
* bloat where a single live function keeps its whole global script
* alive.), ScopeCoordinateToTypeSet is not able to find the var/let's
* associated types::TypeSet.
*/
if (skip) {
BytecodeEmitter *bceSkipped = bce;
for (unsigned i = 0; i < skip; i++)
bceSkipped = bceSkipped->parent;
if (!bceSkipped->sc->inFunction())
return true;
}
JS_ASSERT(!pn->isOp(op));
pn->setOp(op);
if (!pn->pn_cookie.set(bce->sc->context, 0, dn->pn_cookie.slot()))
if (!pn->pn_cookie.set(bce->sc->context, skip, dn->pn_cookie.slot()))
return false;
pn->pn_dflags |= PND_BOUND;

View File

@ -314,18 +314,13 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
case JSOP_BINDNAME:
case JSOP_SETNAME:
case JSOP_DELNAME:
case JSOP_GETALIASEDVAR:
case JSOP_CALLALIASEDVAR:
case JSOP_SETALIASEDVAR:
usesScopeChain_ = true;
isInlineable = false;
break;
case JSOP_GETALIASEDVAR:
case JSOP_CALLALIASEDVAR:
case JSOP_SETALIASEDVAR: {
JS_ASSERT(!isInlineable);
usesScopeChain_ = true;
break;
}
case JSOP_DEFFUN:
case JSOP_DEFVAR:
case JSOP_DEFCONST:

View File

@ -359,16 +359,6 @@ static inline uint32_t GetBytecodeSlot(JSScript *script, jsbytecode *pc)
case JSOP_LOCALDEC:
return LocalSlot(script, GET_SLOTNO(pc));
case JSOP_GETALIASEDVAR:
case JSOP_CALLALIASEDVAR:
case JSOP_SETALIASEDVAR:
{
unsigned index;
return ScopeCoordinateToFrameIndex(script, pc, &index) == FrameIndex_Local
? LocalSlot(script, index)
: ArgSlot(index);
}
case JSOP_THIS:
return ThisSlot();

View File

@ -3418,8 +3418,6 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
break;
}
case JSOP_GETALIASEDVAR:
case JSOP_CALLALIASEDVAR:
case JSOP_GETARG:
case JSOP_CALLARG:
case JSOP_GETLOCAL:
@ -3439,12 +3437,11 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
/* Local 'let' variable. Punt on types for these, for now. */
pushed[0].addType(cx, Type::UnknownType());
}
if (op == JSOP_CALLARG || op == JSOP_CALLLOCAL || op == JSOP_CALLALIASEDVAR)
if (op == JSOP_CALLARG || op == JSOP_CALLLOCAL)
pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType());
break;
}
case JSOP_SETALIASEDVAR:
case JSOP_SETARG:
case JSOP_SETLOCAL: {
uint32_t slot = GetBytecodeSlot(script, pc);
@ -3462,6 +3459,24 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
break;
}
case JSOP_GETALIASEDVAR:
case JSOP_CALLALIASEDVAR:
/*
* Every aliased variable will contain 'undefined' in addition to the
* type of whatever value is written to it. Thus, a dynamic barrier is
* necessary. Since we don't expect the to observe more than 1 type,
* there is little benefit to maintaining a TypeSet for the aliased
* variable. Instead, we monitor/barrier all reads unconditionally.
*/
bytecodeTypes(pc)->addSubset(cx, &pushed[0]);
if (op == JSOP_CALLALIASEDVAR)
pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
break;
case JSOP_SETALIASEDVAR:
poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
break;
case JSOP_INCARG:
case JSOP_DECARG:
case JSOP_ARGINC:

View File

@ -2765,6 +2765,7 @@ BEGIN_CASE(JSOP_GETALIASEDVAR)
{
ScopeCoordinate sc = ScopeCoordinate(regs.pc);
PUSH_COPY(regs.fp()->aliasedVarScope(sc).aliasedVar(sc));
TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
}
END_CASE(JSOP_GETALIASEDVAR)

View File

@ -342,8 +342,8 @@ OPDEF(JSOP_FINALLY, 135,"finally", NULL, 1, 0, 2, 0, JOF_BYTE)
* 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, 19, JOF_SCOPECOORD|JOF_NAME)
OPDEF(JSOP_CALLALIASEDVAR,137,"callaliasedvar",NULL, 9, 0, 1, 19, JOF_SCOPECOORD|JOF_NAME)
OPDEF(JSOP_GETALIASEDVAR, 136,"getaliasedvar",NULL, 9, 0, 1, 19, JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET)
OPDEF(JSOP_CALLALIASEDVAR,137,"callaliasedvar",NULL, 9, 0, 1, 19, JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET)
OPDEF(JSOP_SETALIASEDVAR, 138,"setaliasedvar",NULL, 9, 1, 1, 3, JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING)
OPDEF(JSOP_INCALIASEDVAR, 139,"incaliasedvar",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_DECOMPOSE)
OPDEF(JSOP_DECALIASEDVAR, 140,"decaliasedvar",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_DECOMPOSE)

View File

@ -103,6 +103,9 @@ class Bindings
uint16_t numVars() const { return nvars; }
unsigned count() const { return nargs + nvars; }
/* Convert a CallObject slot to either a formal or local variable index. */
inline BindingKind slotToFrameIndex(unsigned slot, unsigned *index);
/*
* The VM's StackFrame allocates a Value for each formal and variable.
* A (formal|var)Index is the index passed to fp->unaliasedFormal/Var to

View File

@ -15,7 +15,6 @@
#include "jsscript.h"
#include "jsscope.h"
#include "vm/ScopeObject.h"
#include "vm/GlobalObject.h"
#include "vm/RegExpObject.h"
@ -28,6 +27,20 @@ Bindings::Bindings()
: lastBinding(NULL), nargs(0), nvars(0), hasDup_(false)
{}
inline BindingKind
Bindings::slotToFrameIndex(unsigned slot, unsigned *index)
{
slot -= CallObject::RESERVED_SLOTS;
if (slot < numArgs()) {
*index = slot;
return ARGUMENT;
}
*index = slot - numArgs();
JS_ASSERT(*index < numVars());
return VARIABLE;
}
inline void
Bindings::transfer(Bindings *bindings)
{

View File

@ -2832,8 +2832,6 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_GETLOCAL)
BEGIN_CASE(JSOP_CALLLOCAL)
BEGIN_CASE(JSOP_GETALIASEDVAR)
BEGIN_CASE(JSOP_CALLALIASEDVAR)
{
/*
* Update the var type unless we are about to pop the variable.
@ -2845,26 +2843,27 @@ mjit::Compiler::generateMethod()
restoreVarType();
if (JSObject *singleton = pushedSingleton(0))
frame.push(ObjectValue(*singleton));
else if (JOF_OPTYPE(*PC) == JOF_SCOPECOORD)
jsop_aliasedVar(ScopeCoordinate(PC), /* get = */ true);
else
frame.pushLocal(GET_SLOTNO(PC));
PC += GetBytecodeLength(PC);
break;
}
END_CASE(JSOP_GETLOCAL)
BEGIN_CASE(JSOP_GETALIASEDVAR)
BEGIN_CASE(JSOP_CALLALIASEDVAR)
jsop_aliasedVar(ScopeCoordinate(PC), /* get = */ true);
END_CASE(JSOP_GETALIASEDVAR);
BEGIN_CASE(JSOP_SETLOCAL)
BEGIN_CASE(JSOP_SETALIASEDVAR)
{
jsbytecode *next = &PC[GetBytecodeLength(PC)];
bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next);
if (JOF_OPTYPE(*PC) == JOF_SCOPECOORD)
if (JOF_OPTYPE(*PC) == JOF_SCOPECOORD) {
jsop_aliasedVar(ScopeCoordinate(PC), /* get = */ false, pop);
else
} else {
frame.storeLocal(GET_SLOTNO(PC), pop);
updateVarType();
updateVarType();
}
if (pop) {
frame.pop();
@ -5804,12 +5803,7 @@ mjit::Compiler::jsop_aliasedVar(ScopeCoordinate sc, bool get, bool poppedAfter)
for (unsigned i = 0; i < sc.hops; i++)
masm.loadPayload(Address(reg, ScopeObject::offsetOfEnclosingScope()), reg);
Shape *shape;
if (StaticBlockObject *block = ScopeCoordinateBlockChain(script, PC))
shape = block->lastProperty();
else
shape = script->bindings.lastShape();
Shape *shape = ScopeCoordinateToStaticScope(script, PC).scopeShape();
Address addr;
if (shape->numFixedSlots() <= sc.slot) {
masm.loadPtr(Address(reg, JSObject::offsetOfSlots()), reg);
@ -5819,12 +5813,15 @@ mjit::Compiler::jsop_aliasedVar(ScopeCoordinate sc, bool get, bool poppedAfter)
}
if (get) {
unsigned index;
FrameEntry *fe = ScopeCoordinateToFrameIndex(script, PC, &index) == FrameIndex_Local
? frame.getLocal(index)
: frame.getArg(index);
JSValueType type = fe->isTypeKnown() ? fe->getKnownType() : JSVAL_TYPE_UNKNOWN;
frame.push(addr, type, true /* = reuseBase */);
JSValueType type = knownPushedType(0);
RegisterID typeReg, dataReg;
frame.loadIntoRegisters(addr, /* reuseBase = */ true, &typeReg, &dataReg);
frame.pushRegs(typeReg, dataReg, type);
BarrierState barrier = testBarrier(typeReg, dataReg,
/* testUndefined = */ false,
/* testReturn */ false,
/* force */ true);
finishBarrier(barrier, REJOIN_FALLTHROUGH, 0);
} else {
#ifdef JSGC_INCREMENTAL_MJ
if (cx->compartment->needsBarrier()) {

View File

@ -1,33 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 452498;
var summary = 'TM: upvar2 regression tests';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
// ------- Comment #108 From Jesse Ruderman
function p(){p}
expect = 'function p(){p;}';
actual = p + '';
compareSource(expect, actual, summary);
exitFunc ('test');
}

View File

@ -72,7 +72,7 @@ ArgumentsObject::element(uint32_t i) const
JS_ASSERT(!isElementDeleted(i));
const Value &v = data()->args[i];
if (v.isMagic(JS_FORWARD_TO_CALL_OBJECT))
return getFixedSlot(MAYBE_CALL_SLOT).toObject().asCall().arg(i);
return getFixedSlot(MAYBE_CALL_SLOT).toObject().asCall().formal(i);
return v;
}
@ -82,7 +82,7 @@ ArgumentsObject::setElement(uint32_t i, const Value &v)
JS_ASSERT(!isElementDeleted(i));
HeapValue &lhs = data()->args[i];
if (lhs.isMagic(JS_FORWARD_TO_CALL_OBJECT))
getFixedSlot(MAYBE_CALL_SLOT).toObject().asCall().setArg(i, v);
getFixedSlot(MAYBE_CALL_SLOT).toObject().asCall().setFormal(i, v);
else
lhs = v;
}

View File

@ -3177,7 +3177,7 @@ DebuggerArguments_getArg(JSContext *cx, unsigned argc, Value *vp)
Value arg;
if (unsigned(i) < fp->numActualArgs()) {
if (unsigned(i) < fp->numFormalArgs() && fp->script()->formalLivesInCallObject(i))
arg = fp->callObj().arg(i);
arg = fp->callObj().formal(i);
else if (fp->script()->argsObjAliasesFormals() && fp->hasArgsObj())
arg = fp->argsObj().arg(i);
else

View File

@ -10,6 +10,8 @@
#include "ScopeObject.h"
#include "jsscriptinlines.h"
namespace js {
inline
@ -72,14 +74,14 @@ CallObject::callee() const
}
inline const Value &
CallObject::arg(unsigned i, MaybeCheckAliasing checkAliasing) const
CallObject::formal(unsigned i, MaybeCheckAliasing checkAliasing) const
{
JS_ASSERT_IF(checkAliasing, callee().script()->formalLivesInCallObject(i));
return getSlot(RESERVED_SLOTS + i);
}
inline void
CallObject::setArg(unsigned i, const Value &v, MaybeCheckAliasing checkAliasing)
CallObject::setFormal(unsigned i, const Value &v, MaybeCheckAliasing checkAliasing)
{
JS_ASSERT_IF(checkAliasing, callee().script()->formalLivesInCallObject(i));
setSlot(RESERVED_SLOTS + i, v);

View File

@ -58,6 +58,14 @@ StaticScopeIter::hasDynamicScopeObject() const
: obj->toFunction()->isHeavyweight();
}
Shape *
StaticScopeIter::scopeShape() const
{
JS_ASSERT(hasDynamicScopeObject());
JS_ASSERT(type() != NAMED_LAMBDA);
return type() == BLOCK ? block().lastProperty() : funScript()->bindings.lastShape();
}
StaticScopeIter::Type
StaticScopeIter::type() const
{
@ -82,63 +90,47 @@ StaticScopeIter::funScript() const
/*****************************************************************************/
StaticBlockObject *
js::ScopeCoordinateBlockChain(JSScript *script, jsbytecode *pc)
StaticScopeIter
js::ScopeCoordinateToStaticScope(JSScript *script, jsbytecode *pc)
{
ScopeCoordinate sc(pc);
JS_ASSERT(pc >= script->code && pc < script->code + script->length);
JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD);
uint32_t blockIndex = GET_UINT32_INDEX(pc + 2 * sizeof(uint16_t));
JSObject *innermostStaticScope;
if (blockIndex == UINT32_MAX)
return NULL;
innermostStaticScope = script->function();
else
innermostStaticScope = &script->getObject(blockIndex)->asStaticBlock();
StaticBlockObject *block = &script->getObject(blockIndex)->asStaticBlock();
unsigned i = 0;
StaticScopeIter ssi(innermostStaticScope);
ScopeCoordinate sc(pc);
while (true) {
while (block && !block->needsClone())
block = block->enclosingBlock();
if (i++ == sc.hops)
break;
block = block->enclosingBlock();
if (ssi.hasDynamicScopeObject()) {
if (!sc.hops)
break;
sc.hops--;
}
ssi++;
}
return block;
return ssi;
}
PropertyName *
js::ScopeCoordinateName(JSRuntime *rt, JSScript *script, jsbytecode *pc)
{
StaticBlockObject *maybeBlock = ScopeCoordinateBlockChain(script, pc);
Shape::Range r = ScopeCoordinateToStaticScope(script, pc).scopeShape()->all();
ScopeCoordinate sc(pc);
Shape *shape = maybeBlock ? maybeBlock->lastProperty() : script->bindings.lastShape();
Shape::Range r = shape->all();
while (r.front().slot() != sc.slot)
r.popFront();
jsid id = r.front().propid();
/* Beware nameless destructuring formal. */
if (!JSID_IS_ATOM(id))
return rt->atomState.emptyAtom;
return JSID_TO_ATOM(id)->asPropertyName();
}
FrameIndexType
js::ScopeCoordinateToFrameIndex(JSScript *script, jsbytecode *pc, unsigned *index)
{
ScopeCoordinate sc(pc);
if (StaticBlockObject *block = ScopeCoordinateBlockChain(script, pc)) {
*index = block->slotToLocalIndex(script->bindings, sc.slot);
return FrameIndex_Local;
}
unsigned i = sc.slot - CallObject::RESERVED_SLOTS;
if (i < script->bindings.numArgs()) {
*index = i;
return FrameIndex_Arg;
}
*index = i - script->bindings.numArgs();
JS_ASSERT(*index < script->bindings.numVars());
return FrameIndex_Local;
}
/*****************************************************************************/
/*
@ -215,12 +207,12 @@ CallObject::createForFunction(JSContext *cx, StackFrame *fp)
if (script->bindingsAccessedDynamically) {
Value *formals = fp->formals();
for (unsigned slot = 0, n = fp->fun()->nargs; slot < n; ++slot)
callobj->setArg(slot, formals[slot]);
callobj->setFormal(slot, formals[slot]);
} else if (unsigned n = script->numClosedArgs()) {
Value *formals = fp->formals();
for (unsigned i = 0; i < n; ++i) {
uint32_t slot = script->getClosedArg(i);
callobj->setArg(slot, formals[slot]);
callobj->setFormal(slot, formals[slot]);
}
}
@ -241,9 +233,9 @@ CallObject::copyUnaliasedValues(StackFrame *fp)
for (unsigned i = 0; i < script->bindings.numArgs(); ++i) {
if (!script->formalLivesInCallObject(i)) {
if (script->argsObjAliasesFormals() && fp->hasArgsObj())
setArg(i, fp->argsObj().arg(i), DONT_CHECK_ALIASING);
setFormal(i, fp->argsObj().arg(i), DONT_CHECK_ALIASING);
else
setArg(i, fp->unaliasedFormal(i, DONT_CHECK_ALIASING), DONT_CHECK_ALIASING);
setFormal(i, fp->unaliasedFormal(i, DONT_CHECK_ALIASING), DONT_CHECK_ALIASING);
}
}
@ -268,40 +260,20 @@ CallObject::createForStrictEval(JSContext *cx, StackFrame *fp)
JSBool
CallObject::setArgOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp)
{
CallObject &callobj = obj->asCall();
/* TODO: this can totally be a data property now. */
JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
unsigned i = (uint16_t) JSID_TO_INT(id);
JSScript *script = callobj.callee().script();
JS_ASSERT(script->formalLivesInCallObject(i));
callobj.setArg(i, *vp);
if (!script->ensureHasTypes(cx))
return false;
TypeScript::SetArgument(cx, script, i, *vp);
obj->asCall().setFormal(i, *vp);
return true;
}
JSBool
CallObject::setVarOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp)
{
CallObject &callobj = obj->asCall();
/* TODO: this can totally be a data property now. */
JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
unsigned i = (uint16_t) JSID_TO_INT(id);
JSScript *script = callobj.callee().script();
JS_ASSERT(script->varIsAliased(i));
callobj.setVar(i, *vp);
if (!script->ensureHasTypes(cx))
return false;
TypeScript::SetLocal(cx, script, i, *vp);
obj->asCall().setVar(i, *vp);
return true;
}
@ -1193,9 +1165,9 @@ class DebugScopeProxy : public BaseProxyHandler
}
} else {
if (action == GET)
*vp = callobj.arg(i, DONT_CHECK_ALIASING);
*vp = callobj.formal(i, DONT_CHECK_ALIASING);
else
callobj.setArg(i, *vp, DONT_CHECK_ALIASING);
callobj.setFormal(i, *vp, DONT_CHECK_ALIASING);
}
if (action == SET)

View File

@ -65,6 +65,7 @@ class StaticScopeIter
/* Return whether this static scope will be on the dynamic scope chain. */
bool hasDynamicScopeObject() const;
Shape *scopeShape() const;
enum Type { BLOCK, FUNCTION, NAMED_LAMBDA };
Type type() const;
@ -93,25 +94,17 @@ struct ScopeCoordinate
inline ScopeCoordinate() {}
};
/* Return the static block chain (or null) accessed by *pc. */
extern StaticBlockObject *
ScopeCoordinateBlockChain(JSScript *script, jsbytecode *pc);
/*
* Return a scope iterator pointing at the static scope containing the variable
* accessed by the ALIASEDVAR op at 'pc'.
*/
extern StaticScopeIter
ScopeCoordinateToStaticScope(JSScript *script, jsbytecode *pc);
/* Return the name being accessed by the given ALIASEDVAR op. */
extern PropertyName *
ScopeCoordinateName(JSRuntime *rt, JSScript *script, jsbytecode *pc);
/*
* The 'slot' of a ScopeCoordinate is relative to the scope object. Type
* inference and jit compilation are instead relative to frame values (even if
* these values are aliased and thus never accessed, the the index of the
* variable is used to refer to the jit/inference information). This function
* maps from the ScopeCoordinate space to the StackFrame variable space.
*/
enum FrameIndexType { FrameIndex_Local, FrameIndex_Arg };
extern FrameIndexType
ScopeCoordinateToFrameIndex(JSScript *script, jsbytecode *pc, unsigned *index);
/*****************************************************************************/
/*
@ -201,14 +194,15 @@ class CallObject : public ScopeObject
*/
inline JSFunction &callee() const;
/* Returns the formal argument at the given index. */
inline const Value &arg(unsigned i, MaybeCheckAliasing = CHECK_ALIASING) const;
inline void setArg(unsigned i, const Value &v, MaybeCheckAliasing = CHECK_ALIASING);
/* Get/set the formal argument at the given index. */
inline const Value &formal(unsigned i, MaybeCheckAliasing = CHECK_ALIASING) const;
inline void setFormal(unsigned i, const Value &v, MaybeCheckAliasing = CHECK_ALIASING);
/* Returns the variable at the given index. */
/* Get/set the variable at the given index. */
inline const Value &var(unsigned i, MaybeCheckAliasing = CHECK_ALIASING) const;
inline void setVar(unsigned i, const Value &v, MaybeCheckAliasing = CHECK_ALIASING);
/* Internal property ops for CallObject dynamic access via scope chain. */
static JSBool setArgOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp);
static JSBool setVarOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp);