Bug 988993 - Ion-compile scripts with arrow functions. r=bhackett

This commit is contained in:
Jan de Mooij 2014-04-09 13:57:32 +02:00
parent 59e1c9cc53
commit 02406ce983
13 changed files with 149 additions and 6 deletions

View File

@ -156,6 +156,7 @@ BytecodeAnalysis::init(TempAllocator &alloc, GSNCache &gsn)
case JSOP_CALLALIASEDVAR:
case JSOP_SETALIASEDVAR:
case JSOP_LAMBDA:
case JSOP_LAMBDA_ARROW:
case JSOP_DEFFUN:
case JSOP_DEFVAR:
case JSOP_DEFCONST:

View File

@ -941,8 +941,7 @@ CodeGenerator::visitStringReplace(LStringReplace *lir)
typedef JSObject *(*LambdaFn)(JSContext *, HandleFunction, HandleObject);
static const VMFunction LambdaInfo =
FunctionInfo<LambdaFn>(js::Lambda);
static const VMFunction LambdaInfo = FunctionInfo<LambdaFn>(js::Lambda);
bool
CodeGenerator::visitLambdaForSingleton(LLambdaForSingleton *lir)
@ -976,10 +975,53 @@ CodeGenerator::visitLambda(LLambda *lir)
return true;
}
typedef JSObject *(*LambdaArrowFn)(JSContext *, HandleFunction, HandleObject, HandleValue);
static const VMFunction LambdaArrowInfo = FunctionInfo<LambdaArrowFn>(js::LambdaArrow);
bool
CodeGenerator::visitLambdaArrow(LLambdaArrow *lir)
{
Register scopeChain = ToRegister(lir->scopeChain());
ValueOperand thisv = ToValue(lir, LLambdaArrow::ThisValue);
Register output = ToRegister(lir->output());
Register tempReg = ToRegister(lir->temp());
const LambdaFunctionInfo &info = lir->mir()->info();
OutOfLineCode *ool = oolCallVM(LambdaArrowInfo, lir,
(ArgList(), ImmGCPtr(info.fun), scopeChain, thisv),
StoreRegisterTo(output));
if (!ool)
return false;
MOZ_ASSERT(!info.useNewTypeForClone);
if (info.singletonType) {
// If the function has a singleton type, this instruction will only be
// executed once so we don't bother inlining it.
masm.jump(ool->entry());
masm.bind(ool->rejoin());
return true;
}
masm.newGCThing(output, tempReg, info.fun, ool->entry(), gc::DefaultHeap);
masm.initGCThing(output, tempReg, info.fun);
emitLambdaInit(output, scopeChain, info);
// Store the lexical |this| value.
MOZ_ASSERT(info.flags & JSFunction::EXTENDED);
masm.storeValue(thisv, Address(output, FunctionExtended::offsetOfArrowThisSlot()));
masm.bind(ool->rejoin());
return true;
}
void
CodeGenerator::emitLambdaInit(Register output, Register scopeChain,
const LambdaFunctionInfo &info)
{
MOZ_ASSERT(!!(info.flags & JSFunction::ARROW) == !!(info.flags & JSFunction::EXTENDED));
// Initialize nargs and flags. We do this with a single uint32 to avoid
// 16-bit writes.
union {
@ -990,7 +1032,7 @@ CodeGenerator::emitLambdaInit(Register output, Register scopeChain,
uint32_t word;
} u;
u.s.nargs = info.fun->nargs();
u.s.flags = info.flags & ~JSFunction::EXTENDED;
u.s.flags = info.flags;
JS_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2);
masm.store32(Imm32(u.word), Address(output, JSFunction::offsetOfNargs()));

View File

@ -99,6 +99,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitRegExpReplace(LRegExpReplace *lir);
bool visitStringReplace(LStringReplace *lir);
bool visitLambda(LLambda *lir);
bool visitLambdaArrow(LLambdaArrow *lir);
bool visitLambdaForSingleton(LLambdaForSingleton *lir);
bool visitLambdaPar(LLambdaPar *lir);
bool visitPointer(LPointer *lir);

View File

@ -1711,6 +1711,9 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_LAMBDA:
return jsop_lambda(info().getFunction(pc));
case JSOP_LAMBDA_ARROW:
return jsop_lambda_arrow(info().getFunction(pc));
case JSOP_ITER:
return jsop_iter(GET_INT8(pc));
@ -9420,9 +9423,9 @@ IonBuilder::jsop_object(JSObject *obj)
bool
IonBuilder::jsop_lambda(JSFunction *fun)
{
JS_ASSERT(analysis().usesScopeChain());
if (fun->isArrow())
return abort("bound arrow function");
MOZ_ASSERT(analysis().usesScopeChain());
MOZ_ASSERT(!fun->isArrow());
if (fun->isNative() && IsAsmJSModuleNative(fun->native()))
return abort("asm.js module function");
@ -9433,6 +9436,23 @@ IonBuilder::jsop_lambda(JSFunction *fun)
return resumeAfter(ins);
}
bool
IonBuilder::jsop_lambda_arrow(JSFunction *fun)
{
MOZ_ASSERT(analysis().usesScopeChain());
MOZ_ASSERT(fun->isArrow());
MOZ_ASSERT(!fun->isNative());
MDefinition *thisDef = current->pop();
MLambdaArrow *ins = MLambdaArrow::New(alloc(), constraints(), current->scopeChain(),
thisDef, fun);
current->add(ins);
current->push(ins);
return resumeAfter(ins);
}
bool
IonBuilder::jsop_setarg(uint32_t arg)
{

View File

@ -602,6 +602,7 @@ class IonBuilder : public MIRGenerator
bool jsop_regexp(RegExpObject *reobj);
bool jsop_object(JSObject *obj);
bool jsop_lambda(JSFunction *fun);
bool jsop_lambda_arrow(JSFunction *fun);
bool jsop_this();
bool jsop_typeof();
bool jsop_toid();

View File

@ -3487,6 +3487,28 @@ class LLambda : public LInstructionHelper<1, 1, 1>
}
};
class LLambdaArrow : public LInstructionHelper<1, 1 + BOX_PIECES, 1>
{
public:
LIR_HEADER(LambdaArrow)
static const size_t ThisValue = 1;
LLambdaArrow(const LAllocation &scopeChain, const LDefinition &temp) {
setOperand(0, scopeChain);
setTemp(0, temp);
}
const LAllocation *scopeChain() {
return getOperand(0);
}
const LDefinition *temp() {
return getTemp(0);
}
const MLambdaArrow *mir() const {
return mir_->toLambdaArrow();
}
};
class LLambdaPar : public LInstructionHelper<1, 2, 2>
{
public:

View File

@ -160,6 +160,7 @@
_(RegExpReplace) \
_(StringReplace) \
_(Lambda) \
_(LambdaArrow) \
_(LambdaForSingleton) \
_(LambdaPar) \
_(ImplicitThis) \

View File

@ -2068,6 +2068,18 @@ LIRGenerator::visitLambda(MLambda *ins)
return define(lir, ins) && assignSafepoint(lir, ins);
}
bool
LIRGenerator::visitLambdaArrow(MLambdaArrow *ins)
{
MOZ_ASSERT(ins->scopeChain()->type() == MIRType_Object);
MOZ_ASSERT(ins->thisDef()->type() == MIRType_Value);
LLambdaArrow *lir = new(alloc()) LLambdaArrow(useRegister(ins->scopeChain()), temp());
if (!useBox(lir, LLambdaArrow::ThisValue, ins->thisDef()))
return false;
return define(lir, ins) && assignSafepoint(lir, ins);
}
bool
LIRGenerator::visitLambdaPar(MLambdaPar *ins)
{

View File

@ -154,6 +154,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitRegExpReplace(MRegExpReplace *ins);
bool visitStringReplace(MStringReplace *ins);
bool visitLambda(MLambda *ins);
bool visitLambdaArrow(MLambdaArrow *ins);
bool visitLambdaPar(MLambdaPar *ins);
bool visitImplicitThis(MImplicitThis *ins);
bool visitSlots(MSlots *ins);

View File

@ -5085,6 +5085,44 @@ class MLambda
}
};
class MLambdaArrow
: public MBinaryInstruction,
public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
{
LambdaFunctionInfo info_;
MLambdaArrow(types::CompilerConstraintList *constraints, MDefinition *scopeChain,
MDefinition *this_, JSFunction *fun)
: MBinaryInstruction(scopeChain, this_), info_(fun)
{
setResultType(MIRType_Object);
MOZ_ASSERT(!types::UseNewTypeForClone(fun));
if (!fun->hasSingletonType())
setResultTypeSet(MakeSingletonTypeSet(constraints, fun));
}
public:
INSTRUCTION_HEADER(LambdaArrow)
static MLambdaArrow *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
MDefinition *scopeChain, MDefinition *this_, JSFunction *fun)
{
return new(alloc) MLambdaArrow(constraints, scopeChain, this_, fun);
}
MDefinition *scopeChain() const {
return getOperand(0);
}
MDefinition *thisDef() const {
return getOperand(1);
}
const LambdaFunctionInfo &info() const {
return info_;
}
TypePolicy *typePolicy() {
return this;
}
};
class MLambdaPar
: public MBinaryInstruction,
public SingleObjectPolicy

View File

@ -107,6 +107,7 @@ namespace jit {
_(RegExpReplace) \
_(StringReplace) \
_(Lambda) \
_(LambdaArrow) \
_(ImplicitThis) \
_(Slots) \
_(Elements) \

View File

@ -196,6 +196,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
SAFE_OP(Nop)
UNSAFE_OP(RegExp)
CUSTOM_OP(Lambda)
UNSAFE_OP(LambdaArrow)
UNSAFE_OP(ImplicitThis)
SAFE_OP(Slots)
SAFE_OP(Elements)

View File

@ -1063,6 +1063,8 @@ CloneObject(JSContext *cx, HandleObject selfHostedObject)
if (selfHostedObject->is<JSFunction>()) {
RootedFunction selfHostedFunction(cx, &selfHostedObject->as<JSFunction>());
bool hasName = selfHostedFunction->atom() != nullptr;
// Arrow functions use the first extended slot for their lexical |this| value.
JS_ASSERT(!selfHostedFunction->isArrow());
js::gc::AllocKind kind = hasName
? JSFunction::ExtendedFinalizeKind
: selfHostedFunction->getAllocKind();