зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 0f963fbdc918 (bug 1141865)
This commit is contained in:
Родитель
e1180d592e
Коммит
3a80a55abd
|
@ -5452,19 +5452,6 @@ BytecodeEmitter::emitFor(ParseNode* pn, ptrdiff_t top)
|
|||
return emitNormalFor(pn, top);
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::arrowNeedsNewTarget()
|
||||
{
|
||||
for (BytecodeEmitter* bce = this; bce; bce = bce->parent) {
|
||||
SharedContext *sc = bce->sc;
|
||||
if (sc->isFunctionBox() && sc->asFunctionBox()->function()->isArrow())
|
||||
continue;
|
||||
|
||||
return sc->allowSyntax(SharedContext::AllowedSyntax::NewTarget);
|
||||
}
|
||||
MOZ_CRASH("impossible parent chain");
|
||||
}
|
||||
|
||||
MOZ_NEVER_INLINE bool
|
||||
BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
|
||||
{
|
||||
|
@ -5556,21 +5543,10 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
|
|||
|
||||
/* Non-hoisted functions simply emit their respective op. */
|
||||
if (!pn->functionIsHoisted()) {
|
||||
/* JSOP_LAMBDA_ARROW is always preceded by JSOP_THIS and a new.target */
|
||||
/* JSOP_LAMBDA_ARROW is always preceded by JSOP_THIS. */
|
||||
MOZ_ASSERT(fun->isArrow() == (pn->getOp() == JSOP_LAMBDA_ARROW));
|
||||
if (fun->isArrow()) {
|
||||
if (!emit1(JSOP_THIS))
|
||||
return false;
|
||||
|
||||
if (arrowNeedsNewTarget()) {
|
||||
if (!emit1(JSOP_NEWTARGET))
|
||||
return false;
|
||||
} else {
|
||||
if (!emit1(JSOP_NULL))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fun->isArrow() && !emit1(JSOP_THIS))
|
||||
return false;
|
||||
if (needsProto) {
|
||||
MOZ_ASSERT(pn->getOp() == JSOP_LAMBDA);
|
||||
pn->setOp(JSOP_FUNWITHPROTO);
|
||||
|
|
|
@ -432,7 +432,6 @@ struct BytecodeEmitter
|
|||
bool emitObjectPairOp(ObjectBox* objbox1, ObjectBox* objbox2, JSOp op);
|
||||
bool emitRegExp(uint32_t index);
|
||||
|
||||
bool arrowNeedsNewTarget();
|
||||
MOZ_NEVER_INLINE bool emitFunction(ParseNode* pn, bool needsProto = false);
|
||||
MOZ_NEVER_INLINE bool emitObject(ParseNode* pn);
|
||||
|
||||
|
|
|
@ -7844,8 +7844,13 @@ Parser<ParseHandler>::checkAllowedNestedSyntax(SharedContext::AllowedSyntax allo
|
|||
|
||||
// Arrow functions don't help decide whether we should allow nested
|
||||
// syntax, as they don't store any of the necessary state for themselves.
|
||||
if (sc->isFunctionBox() && sc->asFunctionBox()->function()->isArrow())
|
||||
if (sc->isFunctionBox() && sc->asFunctionBox()->function()->isArrow()) {
|
||||
// For now (!), disallow new.target in arrow functions. This will
|
||||
// change later in this bug!
|
||||
if (allowed == SharedContext::AllowedSyntax::NewTarget)
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sc->allowSyntax(allowed))
|
||||
return false;
|
||||
|
|
|
@ -272,9 +272,13 @@ class GlobalSharedContext : public SharedContext
|
|||
bool allowSyntax(AllowedSyntax allowed) const {
|
||||
StaticScopeIter<CanGC> it(context, staticEvalScope_);
|
||||
for (; !it.done(); it++) {
|
||||
if (it.type() == StaticScopeIter<CanGC>::Function &&
|
||||
!it.fun().isArrow())
|
||||
{
|
||||
if (it.type() == StaticScopeIter<CanGC>::Function) {
|
||||
if (it.fun().isArrow()) {
|
||||
// For the moment, disallow new.target inside arrow functions
|
||||
if (allowed == AllowedSyntax::NewTarget)
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
return FunctionAllowsSyntax(&it.fun(), allowed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
// Test that new.target is acceptably usable in RematerializedFrames.
|
||||
|
||||
load(libdir + "jitopts.js");
|
||||
|
||||
if (!jitTogglesMatch(Opts_Ion2NoOffthreadCompilation))
|
||||
quit();
|
||||
|
||||
withJitOptions(Opts_Ion2NoOffthreadCompilation, function () {
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger;
|
||||
|
||||
g.toggle = function toggle(d, expected) {
|
||||
if (d) {
|
||||
dbg.addDebuggee(g);
|
||||
|
||||
var frame = dbg.getNewestFrame();
|
||||
assertEq(frame.implementation, "ion");
|
||||
|
||||
// the arrow function will not be constructing, even though it has a
|
||||
// new.target value.
|
||||
assertEq(frame.constructing, false);
|
||||
|
||||
// CONGRATS IF THIS FAILS! You, proud saviour, have made new.target parse
|
||||
// in debug frame evals (presumably by hooking up static scope walks).
|
||||
// Uncomment the assert below for efaust's undying gratitude.
|
||||
// Note that we use .name here because of CCW nonsense.
|
||||
assertEq(frame.eval('new.target').throw.unsafeDereference().name, "SyntaxError");
|
||||
// assertEq(frame.eval('new.target').return.unsafeDereference(), expected);
|
||||
}
|
||||
};
|
||||
|
||||
g.eval("" + function f(d) { new g(d, g, 15); });
|
||||
|
||||
g.eval("" + function g(d, expected) { (() => toggle(d, expected))(); });
|
||||
|
||||
g.eval("(" + function test() {
|
||||
for (var i = 0; i < 5; i++)
|
||||
f(false);
|
||||
f(true);
|
||||
} + ")();");
|
||||
});
|
|
@ -1463,24 +1463,22 @@ BaselineCompiler::emit_JSOP_LAMBDA()
|
|||
return true;
|
||||
}
|
||||
|
||||
typedef JSObject* (*LambdaArrowFn)(JSContext*, HandleFunction, HandleObject,
|
||||
HandleValue, HandleValue);
|
||||
typedef JSObject* (*LambdaArrowFn)(JSContext*, HandleFunction, HandleObject, HandleValue);
|
||||
static const VMFunction LambdaArrowInfo = FunctionInfo<LambdaArrowFn>(js::LambdaArrow);
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_LAMBDA_ARROW()
|
||||
{
|
||||
// Keep pushed |this| in R0, and newTarget in R1.
|
||||
frame.popRegsAndSync(2);
|
||||
// Keep pushed |this| in R0.
|
||||
frame.popRegsAndSync(1);
|
||||
|
||||
RootedFunction fun(cx, script->getFunction(GET_UINT32_INDEX(pc)));
|
||||
|
||||
prepareVMCall();
|
||||
masm.loadPtr(frame.addressOfScopeChain(), R2.scratchReg());
|
||||
masm.loadPtr(frame.addressOfScopeChain(), R1.scratchReg());
|
||||
|
||||
pushArg(R1);
|
||||
pushArg(R0);
|
||||
pushArg(R2.scratchReg());
|
||||
pushArg(R1.scratchReg());
|
||||
pushArg(ImmGCPtr(fun));
|
||||
|
||||
if (!callVM(LambdaArrowInfo))
|
||||
|
@ -2696,16 +2694,6 @@ BaselineCompiler::emit_JSOP_NEWTARGET()
|
|||
MOZ_ASSERT(function());
|
||||
frame.syncStack(0);
|
||||
|
||||
if (function()->isArrow()) {
|
||||
// Arrow functions store their |new.target| value in an
|
||||
// extended slot.
|
||||
Register scratch = R0.scratchReg();
|
||||
masm.loadFunctionFromCalleeToken(frame.addressOfCalleeToken(), scratch);
|
||||
masm.loadValue(Address(scratch, FunctionExtended::offsetOfArrowNewTargetSlot()), R0);
|
||||
frame.push(R0);
|
||||
return true;
|
||||
}
|
||||
|
||||
// if (!isConstructing()) push(undefined)
|
||||
Label constructing, done;
|
||||
masm.branchTestPtr(Assembler::NonZero, frame.addressOfCalleeToken(),
|
||||
|
|
|
@ -227,11 +227,8 @@ class BaselineFrame
|
|||
|
||||
public:
|
||||
Value newTarget() const {
|
||||
MOZ_ASSERT(isFunctionFrame());
|
||||
if (isEvalFrame())
|
||||
return *evalNewTargetAddress();
|
||||
if (fun()->isArrow())
|
||||
return fun()->getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);
|
||||
if (isConstructing())
|
||||
return *(Value*)(reinterpret_cast<const uint8_t*>(this) +
|
||||
BaselineFrame::Size() +
|
||||
|
|
|
@ -1720,100 +1720,42 @@ CodeGenerator::visitLambda(LLambda* lir)
|
|||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
class OutOfLineLambdaArrow : public OutOfLineCodeBase<CodeGenerator>
|
||||
{
|
||||
public:
|
||||
LLambdaArrow* lir;
|
||||
Label entryNoPop_;
|
||||
|
||||
explicit OutOfLineLambdaArrow(LLambdaArrow* lir)
|
||||
: lir(lir)
|
||||
{ }
|
||||
|
||||
void accept(CodeGenerator* codegen) {
|
||||
codegen->visitOutOfLineLambdaArrow(this);
|
||||
}
|
||||
|
||||
Label* entryNoPop() {
|
||||
return &entryNoPop_;
|
||||
}
|
||||
};
|
||||
|
||||
typedef JSObject* (*LambdaArrowFn)(JSContext*, HandleFunction, HandleObject, HandleValue, HandleValue);
|
||||
typedef JSObject* (*LambdaArrowFn)(JSContext*, HandleFunction, HandleObject, HandleValue);
|
||||
static const VMFunction LambdaArrowInfo = FunctionInfo<LambdaArrowFn>(js::LambdaArrow);
|
||||
|
||||
void
|
||||
CodeGenerator::visitOutOfLineLambdaArrow(OutOfLineLambdaArrow* ool)
|
||||
{
|
||||
Register scopeChain = ToRegister(ool->lir->scopeChain());
|
||||
ValueOperand thisv = ToValue(ool->lir, LLambdaArrow::ThisValue);
|
||||
ValueOperand newTarget = ToValue(ool->lir, LLambdaArrow::NewTargetValue);
|
||||
Register output = ToRegister(ool->lir->output());
|
||||
const LambdaFunctionInfo& info = ool->lir->mir()->info();
|
||||
|
||||
// When we get here, we may need to restore part of the newTarget,
|
||||
// which has been conscripted into service as a temp register.
|
||||
masm.pop(newTarget.scratchReg());
|
||||
|
||||
masm.bind(ool->entryNoPop());
|
||||
|
||||
saveLive(ool->lir);
|
||||
|
||||
pushArg(newTarget);
|
||||
pushArg(thisv);
|
||||
pushArg(scopeChain);
|
||||
pushArg(ImmGCPtr(info.fun));
|
||||
|
||||
callVM(LambdaArrowInfo, ool->lir);
|
||||
StoreRegisterTo(output).generate(this);
|
||||
|
||||
restoreLiveIgnore(ool->lir, StoreRegisterTo(output).clobbered());
|
||||
|
||||
masm.jump(ool->rejoin());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitLambdaArrow(LLambdaArrow* lir)
|
||||
{
|
||||
Register scopeChain = ToRegister(lir->scopeChain());
|
||||
ValueOperand thisv = ToValue(lir, LLambdaArrow::ThisValue);
|
||||
ValueOperand newTarget = ToValue(lir, LLambdaArrow::NewTargetValue);
|
||||
Register output = ToRegister(lir->output());
|
||||
Register tempReg = ToRegister(lir->temp());
|
||||
const LambdaFunctionInfo& info = lir->mir()->info();
|
||||
|
||||
OutOfLineLambdaArrow* ool = new (alloc()) OutOfLineLambdaArrow(lir);
|
||||
addOutOfLineCode(ool, lir->mir());
|
||||
OutOfLineCode* ool = oolCallVM(LambdaArrowInfo, lir,
|
||||
(ArgList(), ImmGCPtr(info.fun), scopeChain, thisv),
|
||||
StoreRegisterTo(output));
|
||||
|
||||
MOZ_ASSERT(!info.useSingletonForClone);
|
||||
|
||||
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->entryNoPop());
|
||||
masm.jump(ool->entry());
|
||||
masm.bind(ool->rejoin());
|
||||
return;
|
||||
}
|
||||
|
||||
// There's not enough registers on x86 with the profiler enabled to request
|
||||
// a temp. Instead, spill part of one of the values, being prepared to
|
||||
// restore it if necessary on the out of line path.
|
||||
Register tempReg = newTarget.scratchReg();
|
||||
masm.push(newTarget.scratchReg());
|
||||
|
||||
masm.createGCObject(output, tempReg, info.fun, gc::DefaultHeap, ool->entry());
|
||||
|
||||
masm.pop(newTarget.scratchReg());
|
||||
|
||||
emitLambdaInit(output, scopeChain, info);
|
||||
|
||||
// Initialize extended slots. Lexical |this| is stored in the first one.
|
||||
MOZ_ASSERT(info.flags & JSFunction::EXTENDED);
|
||||
static_assert(FunctionExtended::NUM_EXTENDED_SLOTS == 2, "All slots must be initialized");
|
||||
static_assert(FunctionExtended::ARROW_THIS_SLOT == 0, "|this| must be stored in first slot");
|
||||
static_assert(FunctionExtended::ARROW_NEWTARGET_SLOT == 1,
|
||||
"|new.target| must be stored in second slot");
|
||||
masm.storeValue(thisv, Address(output, FunctionExtended::offsetOfExtendedSlot(0)));
|
||||
masm.storeValue(newTarget, Address(output, FunctionExtended::offsetOfExtendedSlot(1)));
|
||||
masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(1)));
|
||||
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
@ -5023,14 +4965,6 @@ CodeGenerator::visitLoadArrowThis(LLoadArrowThis* lir)
|
|||
masm.loadValue(Address(callee, FunctionExtended::offsetOfArrowThisSlot()), output);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitArrowNewTarget(LArrowNewTarget* lir)
|
||||
{
|
||||
Register callee = ToRegister(lir->callee());
|
||||
ValueOperand output = ToOutValue(lir);
|
||||
masm.loadValue(Address(callee, FunctionExtended::offsetOfArrowNewTargetSlot()), output);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitArrayLength(LArrayLength* lir)
|
||||
{
|
||||
|
|
|
@ -42,7 +42,6 @@ class OutOfLineCallPostWriteBarrier;
|
|||
class OutOfLineIsCallable;
|
||||
class OutOfLineRegExpExec;
|
||||
class OutOfLineRegExpTest;
|
||||
class OutOfLineLambdaArrow;
|
||||
|
||||
class CodeGenerator : public CodeGeneratorSpecific
|
||||
{
|
||||
|
@ -105,7 +104,6 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||
void visitRegExpReplace(LRegExpReplace* lir);
|
||||
void visitStringReplace(LStringReplace* lir);
|
||||
void visitLambda(LLambda* lir);
|
||||
void visitOutOfLineLambdaArrow(OutOfLineLambdaArrow* ool);
|
||||
void visitLambdaArrow(LLambdaArrow* lir);
|
||||
void visitLambdaForSingleton(LLambdaForSingleton* lir);
|
||||
void visitPointer(LPointer* lir);
|
||||
|
@ -326,7 +324,6 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||
void visitThrowUninitializedLexical(LThrowUninitializedLexical* ins);
|
||||
void visitDebugger(LDebugger* ins);
|
||||
void visitNewTarget(LNewTarget* ins);
|
||||
void visitArrowNewTarget(LArrowNewTarget* ins);
|
||||
|
||||
void visitCheckOverRecursed(LCheckOverRecursed* lir);
|
||||
void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool);
|
||||
|
|
|
@ -9443,14 +9443,6 @@ IonBuilder::jsop_newtarget()
|
|||
}
|
||||
|
||||
MOZ_ASSERT(info().funMaybeLazy());
|
||||
|
||||
if (info().funMaybeLazy()->isArrow()) {
|
||||
MArrowNewTarget* arrowNewTarget = MArrowNewTarget::New(alloc(), getCallee());
|
||||
current->add(arrowNewTarget);
|
||||
current->push(arrowNewTarget);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inliningDepth_ == 0) {
|
||||
MNewTarget* newTarget = MNewTarget::New(alloc());
|
||||
current->add(newTarget);
|
||||
|
@ -11887,11 +11879,10 @@ IonBuilder::jsop_lambda_arrow(JSFunction* fun)
|
|||
MOZ_ASSERT(fun->isArrow());
|
||||
MOZ_ASSERT(!fun->isNative());
|
||||
|
||||
MDefinition* newTargetDef = current->pop();
|
||||
MDefinition* thisDef = current->pop();
|
||||
|
||||
MLambdaArrow* ins = MLambdaArrow::New(alloc(), constraints(), current->scopeChain(),
|
||||
thisDef, newTargetDef, fun);
|
||||
thisDef, fun);
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
||||
|
|
|
@ -3990,20 +3990,23 @@ class LLambda : public LInstructionHelper<1, 1, 1>
|
|||
}
|
||||
};
|
||||
|
||||
class LLambdaArrow : public LInstructionHelper<1, 1 + (2 * BOX_PIECES), 0>
|
||||
class LLambdaArrow : public LInstructionHelper<1, 1 + BOX_PIECES, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(LambdaArrow)
|
||||
|
||||
static const size_t ThisValue = 1;
|
||||
static const size_t NewTargetValue = ThisValue + BOX_PIECES;
|
||||
|
||||
explicit LLambdaArrow(const LAllocation& scopeChain) {
|
||||
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();
|
||||
}
|
||||
|
@ -7018,20 +7021,6 @@ class LNewTarget : public LInstructionHelper<BOX_PIECES, 0, 0>
|
|||
LIR_HEADER(NewTarget)
|
||||
};
|
||||
|
||||
class LArrowNewTarget : public LInstructionHelper<BOX_PIECES, 1, 0>
|
||||
{
|
||||
public:
|
||||
explicit LArrowNewTarget(const LAllocation& callee) {
|
||||
setOperand(0, callee);
|
||||
}
|
||||
|
||||
LIR_HEADER(ArrowNewTarget)
|
||||
|
||||
const LAllocation* callee() {
|
||||
return getOperand(0);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -350,8 +350,7 @@
|
|||
_(ThrowUninitializedLexical) \
|
||||
_(NurseryObject) \
|
||||
_(Debugger) \
|
||||
_(NewTarget) \
|
||||
_(ArrowNewTarget)
|
||||
_(NewTarget)
|
||||
|
||||
#if defined(JS_CODEGEN_X86)
|
||||
# include "jit/x86/LOpcodes-x86.h"
|
||||
|
|
|
@ -385,16 +385,6 @@ LIRGenerator::visitLoadArrowThis(MLoadArrowThis* ins)
|
|||
defineBox(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitArrowNewTarget(MArrowNewTarget* ins)
|
||||
{
|
||||
MOZ_ASSERT(ins->type() == MIRType_Value);
|
||||
MOZ_ASSERT(ins->callee()->type() == MIRType_Object);
|
||||
|
||||
LArrowNewTarget* lir = new(alloc()) LArrowNewTarget(useRegister(ins->callee()));
|
||||
defineBox(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::lowerCallArguments(MCall* call)
|
||||
{
|
||||
|
@ -2158,11 +2148,9 @@ LIRGenerator::visitLambdaArrow(MLambdaArrow* ins)
|
|||
{
|
||||
MOZ_ASSERT(ins->scopeChain()->type() == MIRType_Object);
|
||||
MOZ_ASSERT(ins->thisDef()->type() == MIRType_Value);
|
||||
MOZ_ASSERT(ins->newTargetDef()->type() == MIRType_Value);
|
||||
|
||||
LLambdaArrow* lir = new(alloc()) LLambdaArrow(useRegister(ins->scopeChain()));
|
||||
LLambdaArrow* lir = new(alloc()) LLambdaArrow(useRegister(ins->scopeChain()), temp());
|
||||
useBox(lir, LLambdaArrow::ThisValue, ins->thisDef());
|
||||
useBox(lir, LLambdaArrow::NewTargetValue, ins->newTargetDef());
|
||||
define(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
|
|
@ -297,7 +297,6 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
void visitDebugger(MDebugger* ins);
|
||||
void visitNurseryObject(MNurseryObject* ins);
|
||||
void visitNewTarget(MNewTarget* ins);
|
||||
void visitArrowNewTarget(MArrowNewTarget* ins);
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
|
|
@ -6707,36 +6707,6 @@ class MLoadArrowThis
|
|||
}
|
||||
};
|
||||
|
||||
// Load an arrow function's |new.target| value.
|
||||
class MArrowNewTarget
|
||||
: public MUnaryInstruction,
|
||||
public SingleObjectPolicy::Data
|
||||
{
|
||||
explicit MArrowNewTarget(MDefinition* callee)
|
||||
: MUnaryInstruction(callee)
|
||||
{
|
||||
setResultType(MIRType_Value);
|
||||
setMovable();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(ArrowNewTarget)
|
||||
|
||||
static MArrowNewTarget* New(TempAllocator& alloc, MDefinition* callee) {
|
||||
return new(alloc) MArrowNewTarget(callee);
|
||||
}
|
||||
MDefinition* callee() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
bool congruentTo(const MDefinition* ins) const override {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
AliasSet getAliasSet() const override {
|
||||
// An arrow function's lexical |this| value is immutable.
|
||||
return AliasSet::None();
|
||||
}
|
||||
};
|
||||
|
||||
class MPhi final
|
||||
: public MDefinition,
|
||||
public InlineListNode<MPhi>,
|
||||
|
@ -7569,14 +7539,14 @@ class MLambda
|
|||
};
|
||||
|
||||
class MLambdaArrow
|
||||
: public MTernaryInstruction,
|
||||
public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >::Data
|
||||
: public MBinaryInstruction,
|
||||
public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
|
||||
{
|
||||
const LambdaFunctionInfo info_;
|
||||
|
||||
MLambdaArrow(CompilerConstraintList* constraints, MDefinition* scopeChain,
|
||||
MDefinition* this_, MDefinition* newTarget_, JSFunction* fun)
|
||||
: MTernaryInstruction(scopeChain, this_, newTarget_), info_(fun)
|
||||
MDefinition* this_, JSFunction* fun)
|
||||
: MBinaryInstruction(scopeChain, this_), info_(fun)
|
||||
{
|
||||
setResultType(MIRType_Object);
|
||||
MOZ_ASSERT(!ObjectGroup::useSingletonForClone(fun));
|
||||
|
@ -7588,10 +7558,9 @@ class MLambdaArrow
|
|||
INSTRUCTION_HEADER(LambdaArrow)
|
||||
|
||||
static MLambdaArrow* New(TempAllocator& alloc, CompilerConstraintList* constraints,
|
||||
MDefinition* scopeChain, MDefinition* this_, MDefinition* newTarget_,
|
||||
JSFunction* fun)
|
||||
MDefinition* scopeChain, MDefinition* this_, JSFunction* fun)
|
||||
{
|
||||
return new(alloc) MLambdaArrow(constraints, scopeChain, this_, newTarget_, fun);
|
||||
return new(alloc) MLambdaArrow(constraints, scopeChain, this_, fun);
|
||||
}
|
||||
MDefinition* scopeChain() const {
|
||||
return getOperand(0);
|
||||
|
@ -7599,9 +7568,6 @@ class MLambdaArrow
|
|||
MDefinition* thisDef() const {
|
||||
return getOperand(1);
|
||||
}
|
||||
MDefinition* newTargetDef() const {
|
||||
return getOperand(2);
|
||||
}
|
||||
const LambdaFunctionInfo& info() const {
|
||||
return info_;
|
||||
}
|
||||
|
|
|
@ -269,8 +269,7 @@ namespace jit {
|
|||
_(LexicalCheck) \
|
||||
_(ThrowUninitializedLexical) \
|
||||
_(Debugger) \
|
||||
_(NewTarget) \
|
||||
_(ArrowNewTarget)
|
||||
_(NewTarget)
|
||||
|
||||
// Forward declarations of MIR types.
|
||||
#define FORWARD_DECLARE(op) class M##op;
|
||||
|
|
|
@ -202,8 +202,6 @@ class RematerializedFrame
|
|||
|
||||
Value newTarget() {
|
||||
MOZ_ASSERT(isFunctionFrame());
|
||||
if (callee()->isArrow())
|
||||
return callee()->getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);
|
||||
if (isConstructing())
|
||||
return argv()[numActualArgs()];
|
||||
return UndefinedValue();
|
||||
|
|
|
@ -609,7 +609,6 @@ class FunctionExtended : public JSFunction
|
|||
|
||||
/* Arrow functions store their lexical |this| in the first extended slot. */
|
||||
static const unsigned ARROW_THIS_SLOT = 0;
|
||||
static const unsigned ARROW_NEWTARGET_SLOT = 1;
|
||||
|
||||
static const unsigned METHOD_HOMEOBJECT_SLOT = 0;
|
||||
|
||||
|
@ -620,9 +619,6 @@ class FunctionExtended : public JSFunction
|
|||
static inline size_t offsetOfArrowThisSlot() {
|
||||
return offsetOfExtendedSlot(ARROW_THIS_SLOT);
|
||||
}
|
||||
static inline size_t offsetOfArrowNewTargetSlot() {
|
||||
return offsetOfExtendedSlot(ARROW_NEWTARGET_SLOT);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class JSFunction;
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
// new.target is valid in any arrow function not in a global context.
|
||||
new Function('(() => new.target)()');
|
||||
|
||||
// It's also good inside eval, but not global eval
|
||||
assertThrowsInstanceOf(() => eval('() => new.target'), SyntaxError);
|
||||
|
||||
function assertNewTarget(expected) {
|
||||
assertEq((()=>new.target)(), expected);
|
||||
assertEq(eval('()=>new.target')(), expected);
|
||||
|
||||
// Make sure that arrow functions can escape their original context and
|
||||
// still get the right answer.
|
||||
return (() => new.target);
|
||||
}
|
||||
|
||||
const ITERATIONS = 550;
|
||||
for (let i = 0; i < ITERATIONS; i++)
|
||||
assertEq(assertNewTarget(undefined)(), undefined);
|
||||
|
||||
for (let i = 0; i < ITERATIONS; i++)
|
||||
assertEq(new assertNewTarget(assertNewTarget)(), assertNewTarget);
|
||||
|
||||
if (typeof reportCompare === 'function')
|
||||
reportCompare(0,0,"OK");
|
|
@ -4,7 +4,8 @@ try {
|
|||
assertEq(false, true);
|
||||
} catch (e if e instanceof SyntaxError) { }
|
||||
|
||||
// new.target is invalid inside eval inside top-level arrow functions
|
||||
// new.target is (for now!) invalid inside arrow functions, or eval inside arrow
|
||||
// functions.
|
||||
assertThrowsInstanceOf(() => eval('new.target'), SyntaxError);
|
||||
|
||||
// new.target is invalid inside indirect eval.
|
||||
|
@ -16,7 +17,6 @@ try {
|
|||
|
||||
function assertNewTarget(expected) {
|
||||
assertEq(eval('new.target'), expected);
|
||||
assertEq((()=>eval('new.target'))(), expected);
|
||||
|
||||
// Also test nestings "by induction"
|
||||
assertEq(eval('eval("new.target")'), expected);
|
||||
|
|
|
@ -11,8 +11,8 @@ function testNewTarget() {
|
|||
// invalid in top-level scripts
|
||||
assertError("new.target", SyntaxError);
|
||||
|
||||
// valid in arrow functions inside functions
|
||||
assertInFunctionExpr("()=>new.target", arrowExpr([], newTarget()));
|
||||
// invalid (for now!) in any arrow function
|
||||
assertError("function foo() { (() => new.target) }", SyntaxError);
|
||||
assertError("(() => new.target))", SyntaxError);
|
||||
|
||||
// invalid (for now!) in generators
|
||||
|
|
|
@ -3420,14 +3420,12 @@ CASE(JSOP_LAMBDA_ARROW)
|
|||
{
|
||||
/* Load the specified function object literal. */
|
||||
ReservedRooted<JSFunction*> fun(&rootFunction0, script->getFunction(GET_UINT32_INDEX(REGS.pc)));
|
||||
ReservedRooted<Value> thisv(&rootValue0, REGS.sp[-2]);
|
||||
ReservedRooted<Value> newTarget(&rootValue1, REGS.sp[-1]);
|
||||
JSObject* obj = LambdaArrow(cx, fun, REGS.fp()->scopeChain(), thisv, newTarget);
|
||||
ReservedRooted<Value> thisv(&rootValue0, REGS.sp[-1]);
|
||||
JSObject* obj = LambdaArrow(cx, fun, REGS.fp()->scopeChain(), thisv);
|
||||
if (!obj)
|
||||
goto error;
|
||||
MOZ_ASSERT(obj->getProto());
|
||||
REGS.sp[-2].setObject(*obj);
|
||||
REGS.sp--;
|
||||
REGS.sp[-1].setObject(*obj);
|
||||
}
|
||||
END_CASE(JSOP_LAMBDA_ARROW)
|
||||
|
||||
|
@ -3967,7 +3965,6 @@ END_CASE(JSOP_SUPERBASE)
|
|||
|
||||
CASE(JSOP_NEWTARGET)
|
||||
PUSH_COPY(REGS.fp()->newTarget());
|
||||
MOZ_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined());
|
||||
END_CASE(JSOP_NEWTARGET)
|
||||
|
||||
DEFAULT()
|
||||
|
@ -4169,8 +4166,7 @@ js::Lambda(JSContext* cx, HandleFunction fun, HandleObject parent)
|
|||
}
|
||||
|
||||
JSObject*
|
||||
js::LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent, HandleValue thisv,
|
||||
HandleValue newTargetv)
|
||||
js::LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent, HandleValue thisv)
|
||||
{
|
||||
MOZ_ASSERT(fun->isArrow());
|
||||
|
||||
|
@ -4181,7 +4177,6 @@ js::LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent, HandleVa
|
|||
|
||||
MOZ_ASSERT(clone->as<JSFunction>().isArrow());
|
||||
clone->as<JSFunction>().setExtendedSlot(0, thisv);
|
||||
clone->as<JSFunction>().setExtendedSlot(1, newTargetv);
|
||||
|
||||
MOZ_ASSERT(fun->global() == clone->global());
|
||||
return clone;
|
||||
|
|
|
@ -356,8 +356,7 @@ JSObject*
|
|||
Lambda(JSContext* cx, HandleFunction fun, HandleObject parent);
|
||||
|
||||
JSObject*
|
||||
LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent, HandleValue thisv,
|
||||
HandleValue newTargetv);
|
||||
LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent, HandleValue thisv);
|
||||
|
||||
bool
|
||||
GetElement(JSContext* cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res);
|
||||
|
|
|
@ -1340,7 +1340,7 @@
|
|||
* Operands: uint32_t funcIndex
|
||||
* Stack: this => obj
|
||||
*/ \
|
||||
macro(JSOP_LAMBDA_ARROW, 131, "lambda_arrow", NULL, 5, 2, 1, JOF_OBJECT) \
|
||||
macro(JSOP_LAMBDA_ARROW, 131, "lambda_arrow", NULL, 5, 1, 1, JOF_OBJECT) \
|
||||
\
|
||||
/*
|
||||
* Pushes current callee onto the stack.
|
||||
|
|
|
@ -44,9 +44,6 @@ InterpreterFrame::initExecuteFrame(JSContext* cx, HandleScript script, AbstractF
|
|||
flags_ = type | HAS_SCOPECHAIN;
|
||||
|
||||
JSObject* callee = nullptr;
|
||||
|
||||
// newTarget = NullValue is an initial sentinel for "please fill me in from the stack".
|
||||
// It should never be passed from Ion code.
|
||||
RootedValue newTarget(cx, newTargetValue);
|
||||
if (!(flags_ & (GLOBAL))) {
|
||||
if (evalInFramePrev) {
|
||||
|
@ -73,6 +70,9 @@ InterpreterFrame::initExecuteFrame(JSContext* cx, HandleScript script, AbstractF
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Null is just a sentinel value. We should have figured it out by now.
|
||||
MOZ_ASSERT_IF(isFunctionFrame(), newTarget.isObject() || newTarget.isUndefined());
|
||||
|
||||
Value* dstvp = (Value*)this - 3;
|
||||
dstvp[2] = thisv;
|
||||
|
|
|
@ -755,9 +755,6 @@ class InterpreterFrame
|
|||
if (isEvalFrame())
|
||||
return ((Value*)this)[-3];
|
||||
|
||||
if (callee().isArrow())
|
||||
return callee().getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);
|
||||
|
||||
if (isConstructing()) {
|
||||
unsigned pushedArgs = Max(numFormalArgs(), numActualArgs());
|
||||
return argv()[pushedArgs];
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace js {
|
|||
*
|
||||
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
|
||||
*/
|
||||
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 291;
|
||||
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 290;
|
||||
static const uint32_t XDR_BYTECODE_VERSION =
|
||||
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче