Bug 1185106 - Part 0.1: Refactor JSOP_DEFFUN. r=efaust,jandem,till,h4writer
MozReview-Commit-ID: 8XpAiHEzWVm
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -6937,16 +6937,23 @@ BytecodeEmitter::emitFunction(ParseNode*
return false;
}
}
if (needsProto) {
MOZ_ASSERT(pn->getOp() == JSOP_FUNWITHPROTO || pn->getOp() == JSOP_LAMBDA);
pn->setOp(JSOP_FUNWITHPROTO);
}
+
+ if (pn->getOp() == JSOP_DEFFUN) {
+ if (!emitIndex32(JSOP_LAMBDA, index))
+ return false;
+ return emit1(JSOP_DEFFUN);
+ }
+
return emitIndex32(pn->getOp(), index);
}
MOZ_ASSERT(!needsProto);
bool topLevelFunction;
if (sc->isFunctionBox() || (sc->isEvalContext() && sc->strict())) {
// No nested functions inside other functions are top-level.
@@ -6967,17 +6974,19 @@ BytecodeEmitter::emitFunction(ParseNode*
RootedModuleObject module(cx, sc->asModuleContext()->module());
if (!module->noteFunctionDeclaration(cx, name, fun))
return false;
} else {
MOZ_ASSERT(sc->isGlobalContext() || sc->isEvalContext());
MOZ_ASSERT(pn->getOp() == JSOP_NOP);
switchToPrologue();
- if (!emitIndex32(JSOP_DEFFUN, index))
+ if (!emitIndex32(JSOP_LAMBDA, index))
+ return false;
+ if (!emit1(JSOP_DEFFUN))
return false;
if (!updateSourceCoordNotes(pn->pn_pos.begin))
return false;
switchToMain();
}
} else {
// For functions nested within functions and blocks, make a lambda and
// initialize the binding name of the function in the current scope.
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -2745,25 +2745,24 @@ BaselineCompiler::emit_JSOP_DEFLET()
typedef bool (*DefFunOperationFn)(JSContext*, HandleScript, HandleObject, HandleFunction);
static const VMFunction DefFunOperationInfo =
FunctionInfo<DefFunOperationFn>(DefFunOperation, "DefFunOperation");
bool
BaselineCompiler::emit_JSOP_DEFFUN()
{
- RootedFunction fun(cx, script->getFunction(GET_UINT32_INDEX(pc)));
-
- frame.syncStack(0);
- masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
+ frame.popRegsAndSync(1);
+ masm.unboxObject(R0, R0.scratchReg());
+ masm.loadPtr(frame.addressOfEnvironmentChain(), R1.scratchReg());
prepareVMCall();
- pushArg(ImmGCPtr(fun));
pushArg(R0.scratchReg());
+ pushArg(R1.scratchReg());
pushArg(ImmGCPtr(script));
return callVM(DefFunOperationInfo);
}
typedef bool (*InitPropGetterSetterFn)(JSContext*, jsbytecode*, HandleObject, HandlePropertyName,
HandleObject);
static const VMFunction InitPropGetterSetterInfo =
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4689,17 +4689,18 @@ typedef bool (*DefFunOperationFn)(JSCont
static const VMFunction DefFunOperationInfo =
FunctionInfo<DefFunOperationFn>(DefFunOperation, "DefFunOperation");
void
CodeGenerator::visitDefFun(LDefFun* lir)
{
Register envChain = ToRegister(lir->environmentChain());
- pushArg(ImmGCPtr(lir->mir()->fun()));
+ Register fun = ToRegister(lir->fun());
+ pushArg(fun);
pushArg(envChain);
pushArg(ImmGCPtr(current->mir()->info().script()));
callVM(DefFunOperationInfo, lir);
}
typedef bool (*CheckOverRecursedFn)(JSContext*);
static const VMFunction CheckOverRecursedInfo =
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -13413,23 +13413,19 @@ IonBuilder::jsop_deflexical(uint32_t ind
current->add(deflex);
return resumeAfter(deflex);
}
bool
IonBuilder::jsop_deffun(uint32_t index)
{
- JSFunction* fun = script()->getFunction(index);
- if (IsAsmJSModule(fun))
- return abort("asm.js module function");
-
MOZ_ASSERT(analysis().usesEnvironmentChain());
- MDefFun* deffun = MDefFun::New(alloc(), fun, current->environmentChain());
+ MDefFun* deffun = MDefFun::New(alloc(), current->pop(), current->environmentChain());
current->add(deffun);
return resumeAfter(deffun);
}
bool
IonBuilder::jsop_throwsetconst()
{
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -202,17 +202,21 @@ LIRGenerator::visitDefLexical(MDefLexica
LDefLexical* lir = new(alloc()) LDefLexical();
add(lir, ins);
assignSafepoint(lir, ins);
}
void
LIRGenerator::visitDefFun(MDefFun* ins)
{
- LDefFun* lir = new(alloc()) LDefFun(useRegisterAtStart(ins->environmentChain()));
+ MDefinition* fun = ins->fun();
+ MOZ_ASSERT(fun->type() == MIRType::Object);
+
+ LDefFun* lir = new(alloc()) LDefFun(useRegisterAtStart(fun),
+ useRegisterAtStart(ins->environmentChain()));
add(lir, ins);
assignSafepoint(lir, ins);
}
void
LIRGenerator::visitNewArray(MNewArray* ins)
{
LNewArray* lir = new(alloc()) LNewArray(temp());
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -8101,41 +8101,32 @@ class MDefLexical
return attrs_;
}
bool appendRoots(MRootList& roots) const override {
return roots.append(name_);
}
};
class MDefFun
- : public MUnaryInstruction,
- public NoTypePolicy::Data
-{
- CompilerFunction fun_;
-
+ : public MBinaryInstruction,
+ public ObjectPolicy<0>::Data
+{
private:
- MDefFun(JSFunction* fun, MDefinition* envChain)
- : MUnaryInstruction(envChain),
- fun_(fun)
+ MDefFun(MDefinition* fun, MDefinition* envChain)
+ : MBinaryInstruction(fun, envChain)
{}
public:
INSTRUCTION_HEADER(DefFun)
TRIVIAL_NEW_WRAPPERS
- NAMED_OPERANDS((0, environmentChain))
-
- JSFunction* fun() const {
- return fun_;
- }
+ NAMED_OPERANDS((0, fun), (1, environmentChain))
+
bool possiblyCalls() const override {
return true;
}
- bool appendRoots(MRootList& roots) const override {
- return roots.append(fun_);
- }
};
class MRegExp : public MNullaryInstruction
{
CompilerGCPointer<RegExpObject*> source_;
bool mustClone_;
MRegExp(CompilerConstraintList* constraints, RegExpObject* source)
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -1545,28 +1545,32 @@ class LDefLexical : public LCallInstruct
public:
LIR_HEADER(DefLexical)
MDefLexical* mir() const {
return mir_->toDefLexical();
}
};
-class LDefFun : public LCallInstructionHelper<0, 1, 0>
+class LDefFun : public LCallInstructionHelper<0, 2, 0>
{
public:
LIR_HEADER(DefFun)
- explicit LDefFun(const LAllocation& envChain)
- {
- setOperand(0, envChain);
- }
-
+ LDefFun(const LAllocation& fun, const LAllocation& envChain)
+ {
+ setOperand(0, fun);
+ setOperand(1, envChain);
+ }
+
+ const LAllocation* fun() {
+ return getOperand(0);
+ }
const LAllocation* environmentChain() {
- return getOperand(0);
+ return getOperand(1);
}
MDefFun* mir() const {
return mir_->toDefFun();
}
};
class LTypeOfV : public LInstructionHelper<1, BOX_PIECES, 1>
{
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -3441,19 +3441,20 @@ END_CASE(JSOP_DEFLET)
CASE(JSOP_DEFFUN)
{
/*
* A top-level function defined in Global or Eval code (see ECMA-262
* Ed. 3), or else a SpiderMonkey extension: a named function statement in
* a compound statement (not at the top statement level of global code, or
* at the top level of a function body).
*/
- ReservedRooted<JSFunction*> fun(&rootFunction0, script->getFunction(GET_UINT32_INDEX(REGS.pc)));
+ ReservedRooted<JSFunction*> fun(&rootFunction0, ®S.sp[-1].toObject().as<JSFunction>());
if (!DefFunOperation(cx, script, REGS.fp()->environmentChain(), fun))
goto error;
+ REGS.sp--;
}
END_CASE(JSOP_DEFFUN)
CASE(JSOP_LAMBDA)
{
/* Load the specified function object literal. */
ReservedRooted<JSFunction*> fun(&rootFunction0, script->getFunction(GET_UINT32_INDEX(REGS.pc)));
JSObject* obj = Lambda(cx, fun, REGS.fp()->environmentChain());
@@ -4325,37 +4326,18 @@ js::LambdaArrow(JSContext* cx, HandleFun
clone->as<JSFunction>().setExtendedSlot(0, newTargetv);
MOZ_ASSERT(fun->global() == clone->global());
return clone;
}
bool
js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject envChain,
- HandleFunction funArg)
-{
- /*
- * If static link is not current scope, clone fun's object to link to the
- * current scope via parent. We do this to enable sharing of compiled
- * functions among multiple equivalent scopes, amortizing the cost of
- * compilation over a number of executions. Examples include XUL scripts
- * and event handlers shared among Firefox or other Mozilla app chrome
- * windows, and user-defined JS functions precompiled and then shared among
- * requests in server-side JS.
- */
- RootedFunction fun(cx, funArg);
- if (fun->isNative() || fun->environment() != envChain) {
- fun = CloneFunctionObjectIfNotSingleton(cx, fun, envChain, nullptr, TenuredObject);
- if (!fun)
- return false;
- } else {
- MOZ_ASSERT(script->treatAsRunOnce());
- MOZ_ASSERT(!script->functionNonDelazifying());
- }
-
+ HandleFunction fun)
+{
/*
* We define the function as a property of the variable object and not the
* current scope chain even for the case of function expression statements
* and functions defined by eval inside let or with blocks.
*/
RootedObject parent(cx, envChain);
while (!parent->isQualifiedVarObj())
parent = parent->enclosingEnvironment();
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -1295,20 +1295,20 @@ 1234567890123456789012345678901234567890
\
/*
* Defines the given function on the current scope.
*
* This is used for global scripts and also in some cases for function
* scripts where use of dynamic scoping inhibits optimization.
* Category: Variables and Scopes
* Type: Variables
- * Operands: uint32_t funcIndex
- * Stack: =>
+ * Operands:
+ * Stack: fun =>
*/ \
- macro(JSOP_DEFFUN, 127,"deffun", NULL, 5, 0, 0, JOF_OBJECT) \
+ macro(JSOP_DEFFUN, 127,"deffun", NULL, 1, 1, 0, JOF_BYTE) \
/* Defines the new constant binding on global lexical scope.
*
* Throws if a binding with the same name already exists on the scope, or
* if a var binding with the same name exists on the global.
* Category: Variables and Scopes
* Type: Variables
* Operands: uint32_t nameIndex
* Stack: =>