Handle JSOP_DEFVAR, JSOP_DEFCONST. (Bug 725532, r=dvander)

This commit is contained in:
Sean Stangl 2012-02-17 10:42:31 -08:00
parent a4fa17e0cb
commit 22ab59f33c
14 changed files with 146 additions and 1 deletions

View File

@ -824,6 +824,28 @@ CodeGenerator::visitCheckOverRecursed(LCheckOverRecursed *lir)
return true;
}
bool
CodeGenerator::visitDefVar(LDefVar *lir)
{
Register scopeChain = ToRegister(lir->getScopeChain());
Register nameTemp = ToRegister(lir->nameTemp());
typedef bool (*pf)(JSContext *, PropertyName *, uintN, JSObject *);
static const VMFunction DefVarOrConstInfo =
FunctionInfo<pf>(DefVarOrConst);
masm.movePtr(ImmWord(lir->mir()->name()), nameTemp);
pushArg(scopeChain); // JSObject *
pushArg(Imm32(lir->mir()->attrs())); // uintN
pushArg(nameTemp); // PropertyName *
if (!callVM(DefVarOrConstInfo, lir))
return false;
return true;
}
bool
CodeGenerator::visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool)
{

View File

@ -80,6 +80,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitCallee(LCallee *lir);
bool visitStart(LStart *lir);
bool visitReturn(LReturn *ret);
bool visitDefVar(LDefVar *lir);
bool visitOsrEntry(LOsrEntry *lir);
bool visitOsrScopeChain(LOsrScopeChain *lir);
bool visitStackArg(LStackArg *lir);

View File

@ -773,6 +773,7 @@ CheckFrame(StackFrame *fp)
if (fp->isEvalFrame()) {
// Eval frames are not yet supported. Supporting this will require new
// logic in pushBailoutFrame to deal with linking prev.
// Additionally, JSOP_DEFVAR support will require baking in isEvalFrame().
IonSpew(IonSpew_Abort, "eval frame");
return false;
}

View File

@ -640,6 +640,10 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_OR:
return jsop_andor(op);
case JSOP_DEFVAR:
case JSOP_DEFCONST:
return jsop_defvar(GET_SLOTNO(pc));
case JSOP_LOCALINC:
case JSOP_INCLOCAL:
case JSOP_LOCALDEC:
@ -3668,6 +3672,31 @@ IonBuilder::jsop_deflocalfun(uint32 local, JSFunction *fun)
return resumeAfter(ins);
}
bool
IonBuilder::jsop_defvar(uint32 index)
{
JS_ASSERT(JSOp(*pc) == JSOP_DEFVAR || JSOp(*pc) == JSOP_DEFCONST);
PropertyName *name = script->getName(index);
// Bake in attrs.
uintN attrs = JSPROP_ENUMERATE;
// isEvalFrame() requires attrs |= JSPROP_PERMANENT.
if (JSOp(*pc) == JSOP_DEFCONST)
attrs |= JSPROP_READONLY;
// Pass the ScopeChain.
JS_ASSERT(script->analysis()->usesScopeChain());
MDefinition *scopeChain = current->getSlot(info().scopeChainSlot());
JS_ASSERT(scopeChain->type() == MIRType_Object);
// Bake the name pointer into the MDefVar.
MDefVar *defvar = MDefVar::New(name, attrs, scopeChain);
current->add(defvar);
return resumeAfter(defvar);
}
bool
IonBuilder::jsop_this()
{

View File

@ -285,6 +285,7 @@ class IonBuilder : public MIRGenerator
bool jsop_binary(JSOp op, MDefinition *left, MDefinition *right);
bool jsop_pos();
bool jsop_neg();
bool jsop_defvar(uint32 index);
bool jsop_notearg();
bool jsop_call(uint32 argc, bool constructing);
bool jsop_ifeq(JSOp op);

View File

@ -250,6 +250,28 @@ class LCheckOverRecursed : public LInstructionHelper<0, 0, 1>
}
};
class LDefVar : public LInstructionHelper<0, 1, 1>
{
public:
LIR_HEADER(DefVar);
LDefVar(const LAllocation &scopeChain, const LDefinition &namereg)
{
setOperand(0, scopeChain);
setTemp(0, namereg);
}
const LAllocation *getScopeChain() {
return getOperand(0);
}
const LAllocation *nameTemp() {
return getTemp(0)->output();
}
MDefVar *mir() const {
return mir_->toDefVar();
}
};
class LTypeOfV : public LInstructionHelper<1, BOX_PIECES, 0>
{
public:

View File

@ -58,6 +58,7 @@
_(NewArray) \
_(CheckOverRecursed) \
_(RecompileCheck) \
_(DefVar) \
_(CallGeneric) \
_(CallNative) \
_(StackArg) \

View File

@ -106,9 +106,28 @@ LIRGenerator::visitCheckOverRecursed(MCheckOverRecursed *ins)
{
LCheckOverRecursed *lir = new LCheckOverRecursed(temp(LDefinition::GENERAL));
if (!add(lir))
return false;
if (!assignSafepoint(lir, ins))
return false;
return add(lir);
return true;
}
bool
LIRGenerator::visitDefVar(MDefVar *ins)
{
LAllocation scopeChain = useRegister(ins->scopeChain());
LDefVar *lir = new LDefVar(scopeChain, temp(LDefinition::GENERAL));
lir->setMir(ins);
if (!add(lir))
return false;
if (!assignSafepoint(lir, ins))
return false;
return true;
}
bool

View File

@ -116,6 +116,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitGoto(MGoto *ins);
bool visitNewArray(MNewArray *ins);
bool visitCheckOverRecursed(MCheckOverRecursed *ins);
bool visitDefVar(MDefVar *ins);
bool visitPrepareCall(MPrepareCall *ins);
bool visitPassArg(MPassArg *arg);
bool visitCall(MCall *call);

View File

@ -2139,6 +2139,39 @@ class MRecompileCheck : public MNullaryInstruction
}
};
// If not defined, set a global variable to |undefined|.
class MDefVar : public MUnaryInstruction
{
PropertyName *name_; // Target name to be defined.
uintN attrs_; // Attributes to be set.
private:
MDefVar(PropertyName *name, uintN attrs, MDefinition *scopeChain)
: MUnaryInstruction(scopeChain),
name_(name),
attrs_(attrs)
{
}
public:
INSTRUCTION_HEADER(DefVar);
static MDefVar *New(PropertyName *name, uintN attrs, MDefinition *scopeChain) {
return new MDefVar(name, attrs, scopeChain);
}
PropertyName *name() const {
return name_;
}
uintN attrs() const {
return attrs_;
}
MDefinition *scopeChain() const {
return getOperand(0);
}
};
class MRegExp : public MNullaryInstruction
{
public:

View File

@ -59,6 +59,7 @@ namespace ion {
_(OsrScopeChain) \
_(CheckOverRecursed) \
_(RecompileCheck) \
_(DefVar) \
_(PrepareCall) \
_(PassArg) \
_(Call) \

View File

@ -87,6 +87,17 @@ ReportOverRecursed(JSContext *cx)
return false;
}
bool
DefVarOrConst(JSContext *cx, PropertyName *dn, uintN attrs, JSObject *scopeChain)
{
// Given the ScopeChain, extract the VarObj.
JSObject *obj = scopeChain;
while (!obj->isVarObj())
obj = obj->enclosingScope();
return DefVarOrConstOperation(cx, *obj, dn, attrs);
}
template<bool Equal>
bool
LooselyEqual(JSContext *cx, const Value &lhs, const Value &rhs, JSBool *res)

View File

@ -293,6 +293,8 @@ bool InvokeFunction(JSContext *cx, JSFunction *fun, uint32 argc, Value *argv, Va
bool InvokeConstructorFunction(JSContext *cx, JSFunction *fun, uint32 argc, Value *argv, Value *rval);
bool ReportOverRecursed(JSContext *cx);
bool DefVarOrConst(JSContext *cx, PropertyName *dn, uintN attrs, JSObject *scopeChain);
template<bool Equal>
bool LooselyEqual(JSContext *cx, const Value &lhs, const Value &rhs, JSBool *res);

View File

@ -354,6 +354,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
case JSOP_SETCONST:
checkAliasedName(cx, pc);
extendsScope_ = true;
usesScopeChain_ = true; // Requires access to VarObj via ScopeChain.
isInlineable = canTrackVars = false;
break;