Bug 1700443: Remove argumentsOptimizationFailed r=jandem

Depends on D114032

Differential Revision: https://phabricator.services.mozilla.com/D114033
This commit is contained in:
Iain Ireland 2021-05-04 17:51:24 +00:00
Родитель 68468b3a61
Коммит 613c40a99c
14 изменённых файлов: 8 добавлений и 280 удалений

Просмотреть файл

@ -2094,12 +2094,6 @@ bool jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfoArg) {
saveFailedICHash = true;
break;
case BailoutKind::NotOptimizedArgumentsGuard:
// Optimized-arguments escaped to a slow path. Disable the optimization to
// prevent bailout loops.
JSScript::argumentsOptimizationFailed(cx, innerScript);
break;
case BailoutKind::UninitializedLexical:
HandleLexicalCheckFailure(cx, outerScript, innerScript);
break;

Просмотреть файл

@ -853,23 +853,11 @@ bool DoGetElemFallback(JSContext* cx, BaselineFrame* frame,
MOZ_ASSERT(JSOp(*pc) == JSOp::GetElem);
#endif
// Don't pass lhs directly, we need it when generating stubs.
RootedValue lhsCopy(cx, lhs);
bool isOptimizedArgs = false;
if (lhs.isMagic(JS_OPTIMIZED_ARGUMENTS)) {
// Handle optimized arguments[i] access.
isOptimizedArgs =
MaybeGetElemOptimizedArguments(cx, frame, &lhsCopy, rhs, res);
}
TryAttachStub<GetPropIRGenerator>("GetElem", cx, frame, stub,
CacheKind::GetElem, lhs, rhs);
if (!isOptimizedArgs) {
if (!GetElementOperation(cx, lhsCopy, rhs, res)) {
return false;
}
if (!GetElementOperation(cx, lhs, rhs, res)) {
return false;
}
return true;
@ -1763,12 +1751,6 @@ bool DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub,
RootedValue callee(cx, vp[0]);
RootedValue newTarget(cx, constructing ? callArgs.newTarget() : NullValue());
// Handle funapply with JSOp::Arguments
if (op == JSOp::FunApply && argc == 2 &&
callArgs[1].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
GuardFunApplyArgumentsOptimization(cx, frame, callArgs);
}
// Transition stub state to megamorphic or generic if warranted.
MaybeTransition(cx, frame, stub);

Просмотреть файл

@ -4620,15 +4620,6 @@ void CodeGenerator::visitGuardValue(LGuardValue* lir) {
bailoutFrom(&bail, lir->snapshot());
}
void CodeGenerator::visitGuardNotOptimizedArguments(
LGuardNotOptimizedArguments* lir) {
ValueOperand input = ToValue(lir, LGuardNotOptimizedArguments::Input);
Label bail;
masm.branchTestValue(Assembler::Equal, input,
MagicValue(JS_OPTIMIZED_ARGUMENTS), &bail);
bailoutFrom(&bail, lir->snapshot());
}
void CodeGenerator::visitGuardNullOrUndefined(LGuardNullOrUndefined* lir) {
ValueOperand input = ToValue(lir, LGuardNullOrUndefined::Input);

Просмотреть файл

@ -81,8 +81,7 @@ static const SnapshotOffset INVALID_SNAPSHOT_OFFSET = uint32_t(-1);
*
* 2. If the bailout occurs because an assumption we made in WarpBuilder was
* invalidated, then FinishBailoutToBaseline will set a flag on the script
* to avoid that assumption in the future. Examples include
* NotOptimizedArgumentsGuard and UninitializedLexical.
* to avoid that assumption in the future: for example, UninitializedLexical.
*
* 3. Similarly, if the bailing instruction is generated or modified by a MIR
* optimization, then FinishBailoutToBaseline will set a flag on the script
@ -162,10 +161,6 @@ enum class BailoutKind : uint8_t {
// We hit this code for the first time.
FirstExecution,
// A bailout triggered by MGuardNotOptimizedArguments. We will call
// argumentsOptimizationFailed to invalidate the script.
NotOptimizedArgumentsGuard,
// A lexical check failed. We will set lexical checks as unmovable.
UninitializedLexical,
@ -208,8 +203,6 @@ inline const char* BailoutKindString(BailoutKind kind) {
return "Debugger";
case BailoutKind::FirstExecution:
return "FirstExecution";
case BailoutKind::NotOptimizedArgumentsGuard:
return "NotOptimizedArgumentsGuard";
case BailoutKind::UninitializedLexical:
return "UninitializedLexical";
case BailoutKind::IonExceptionDebugMode:

Просмотреть файл

@ -4214,15 +4214,6 @@ void LIRGenerator::visitGuardValue(MGuardValue* ins) {
redefine(ins, ins->value());
}
void LIRGenerator::visitGuardNotOptimizedArguments(
MGuardNotOptimizedArguments* ins) {
MOZ_ASSERT(ins->value()->type() == MIRType::Value);
auto* lir = new (alloc()) LGuardNotOptimizedArguments(useBox(ins->value()));
assignSnapshot(lir, ins->bailoutKind());
add(lir, ins);
redefine(ins, ins->value());
}
void LIRGenerator::visitGuardNullOrUndefined(MGuardNullOrUndefined* ins) {
MOZ_ASSERT(ins->value()->type() == MIRType::Value);
auto* lir = new (alloc()) LGuardNullOrUndefined(useBox(ins->value()));

Просмотреть файл

@ -5124,31 +5124,6 @@ MDefinition* MGuardValue::foldsTo(TempAllocator& alloc) {
return this;
}
/* static */
bool MGuardNotOptimizedArguments::maybeIsOptimizedArguments(MDefinition* def) {
if (def->isBox()) {
def = def->toBox()->input();
}
if (def->type() != MIRType::Value &&
def->type() != MIRType::MagicOptimizedArguments) {
return false;
}
// Only phis and constants can produce optimized-arguments.
MOZ_ASSERT_IF(def->type() == MIRType::MagicOptimizedArguments,
def->isConstant());
return def->isConstant() || def->isPhi();
}
MDefinition* MGuardNotOptimizedArguments::foldsTo(TempAllocator& alloc) {
if (!maybeIsOptimizedArguments(value())) {
return value();
}
return this;
}
MDefinition* MGuardNullOrUndefined::foldsTo(TempAllocator& alloc) {
MDefinition* input = value();
if (input->isBox()) {

Просмотреть файл

@ -9282,36 +9282,6 @@ class MGuardValue : public MUnaryInstruction, public BoxInputsPolicy::Data {
AliasSet getAliasSet() const override { return AliasSet::None(); }
};
// Guards the value is not MagicValue(JS_OPTIMIZED_ARGUMENTS). If this fails,
// disable lazy arguments for the script.
class MGuardNotOptimizedArguments : public MUnaryInstruction,
public BoxInputsPolicy::Data {
explicit MGuardNotOptimizedArguments(MDefinition* val)
: MUnaryInstruction(classOpcode, val) {
setGuard();
setResultType(MIRType::Value);
// Note: don't setMovable() to not deoptimize lazy arguments unnecessarily.
// If this instruction bails out, we will disable the optimization to
// prevent bailout loops.
setBailoutKind(BailoutKind::NotOptimizedArgumentsGuard);
}
public:
INSTRUCTION_HEADER(GuardNotOptimizedArguments)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, value))
bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins);
}
static bool maybeIsOptimizedArguments(MDefinition* def);
MDefinition* foldsTo(TempAllocator& alloc) override;
AliasSet getAliasSet() const override { return AliasSet::None(); }
};
// Guard on null or undefined values.
class MGuardNullOrUndefined : public MUnaryInstruction,
public BoxInputsPolicy::Data {

Просмотреть файл

@ -1805,11 +1805,6 @@ bool WarpBuilder::buildCallOp(BytecodeLocation loc) {
needsThisCheck = true;
}
if (op == JSOp::FunApply && argc == 2) {
MDefinition* arg = maybeGuardNotOptimizedArguments(callInfo.getArg(1));
callInfo.setArg(1, arg);
}
MCall* call = makeCall(callInfo, needsThisCheck);
if (!call) {
return false;
@ -3191,12 +3186,6 @@ bool WarpBuilder::buildIC(BytecodeLocation loc, CacheKind kind,
PropertyName* name = loc.getPropertyName(script_);
MConstant* id = constant(StringValue(name));
MDefinition* val = getInput(0);
if (info().hasArguments()) {
const JSAtomState& names = mirGen().runtime->names();
if (name == names.length || name == names.callee) {
val = maybeGuardNotOptimizedArguments(val);
}
}
auto* ins = MGetPropertyCache::New(alloc(), val, id);
current->add(ins);
current->push(ins);
@ -3204,7 +3193,7 @@ bool WarpBuilder::buildIC(BytecodeLocation loc, CacheKind kind,
}
case CacheKind::GetElem: {
MOZ_ASSERT(numInputs == 2);
MDefinition* val = maybeGuardNotOptimizedArguments(getInput(0));
MDefinition* val = getInput(0);
auto* ins = MGetPropertyCache::New(alloc(), val, getInput(1));
current->add(ins);
current->push(ins);
@ -3342,31 +3331,6 @@ bool WarpBuilder::buildBailoutForColdIC(BytecodeLocation loc, CacheKind kind) {
return true;
}
MDefinition* WarpBuilder::maybeGuardNotOptimizedArguments(MDefinition* def) {
// The arguments-analysis ensures the optimized-arguments MagicValue can only
// flow into a few allowlisted JSOps, for instance arguments.length or
// arguments[i]. See ArgumentsUseCanBeLazy.
//
// Baseline ICs have fast paths for these optimized-arguments uses and the
// transpiler lets us generate MIR for them. Ion ICs, however, don't support
// optimized-arguments because it's hard/impossible to access frame values
// reliably from Ion ICs, especially in inlined functions. To deal with this,
// we insert MGuardNotOptimizedArguments here if needed. On bailout we
// deoptimize the arguments-analysis.
if (!info().hasArguments() || info().needsArgsObj() || info().isAnalysis()) {
return def;
}
if (!MGuardNotOptimizedArguments::maybeIsOptimizedArguments(def)) {
return def;
}
auto* ins = MGuardNotOptimizedArguments::New(alloc(), def);
current->add(ins);
return ins;
}
class MOZ_RAII AutoAccumulateReturns {
MIRGraph& graph_;
MIRGraphReturns* prev_;

Просмотреть файл

@ -285,8 +285,6 @@ class MOZ_STACK_CLASS WarpBuilder : public WarpBuilderShared {
MConstant* globalLexicalEnvConstant();
MDefinition* getCallee();
MDefinition* maybeGuardNotOptimizedArguments(MDefinition* def);
[[nodiscard]] bool buildUnaryOp(BytecodeLocation loc);
[[nodiscard]] bool buildBinaryOp(BytecodeLocation loc);
[[nodiscard]] bool buildCompareOp(BytecodeLocation loc);

Просмотреть файл

@ -8109,19 +8109,6 @@ class LGuardValue : public LInstructionHelper<0, BOX_PIECES, 0> {
MGuardValue* mir() { return mir_->toGuardValue(); }
};
class LGuardNotOptimizedArguments
: public LInstructionHelper<0, BOX_PIECES, 0> {
public:
LIR_HEADER(GuardNotOptimizedArguments)
explicit LGuardNotOptimizedArguments(const LBoxAllocation& input)
: LInstructionHelper(classOpcode) {
setBoxOperand(Input, input);
}
static const size_t Input = 0;
};
class LGuardNullOrUndefined : public LInstructionHelper<0, BOX_PIECES, 0> {
public:
LIR_HEADER(GuardNullOrUndefined)

Просмотреть файл

@ -47,23 +47,6 @@ static inline bool IsOptimizedArguments(AbstractFramePtr frame,
return vp.isMagic(JS_OPTIMIZED_ARGUMENTS);
}
/*
* One optimized consumer of MagicValue(JS_OPTIMIZED_ARGUMENTS) is f.apply.
* However, this speculation must be guarded before calling 'apply' in case it
* is not the builtin Function.prototype.apply.
*/
static inline void GuardFunApplyArgumentsOptimization(JSContext* cx,
AbstractFramePtr frame,
CallArgs& args) {
if (args.length() == 2 && IsOptimizedArguments(frame, args[1])) {
if (!IsNativeFunction(args.calleev(), js::fun_apply)) {
RootedScript script(cx, frame.script());
JSScript::argumentsOptimizationFailed(cx, script);
args[1].setObject(frame.argsObj());
}
}
}
/*
* Per ES6, lexical declarations may not be accessed in any fashion until they
* are initialized (i.e., until the actual declaring statement is
@ -513,27 +496,6 @@ static MOZ_ALWAYS_INLINE bool GetPrimitiveElementOperation(
return true;
}
static MOZ_ALWAYS_INLINE bool MaybeGetElemOptimizedArguments(
JSContext* cx, AbstractFramePtr frame, MutableHandleValue lref,
HandleValue rref, MutableHandleValue res) {
if (IsOptimizedArguments(frame, lref)) {
if (rref.isInt32()) {
int32_t i = rref.toInt32();
if (i >= 0 && uint32_t(i) < frame.numActualArgs()) {
res.set(frame.unaliasedActual(i));
return true;
}
}
RootedScript script(cx, frame.script());
JSScript::argumentsOptimizationFailed(cx, script);
lref.set(ObjectValue(frame.argsObj()));
}
return false;
}
static MOZ_ALWAYS_INLINE bool GetElementOperationWithStackIndex(
JSContext* cx, HandleValue lref, int lrefIndex, HandleValue rref,
MutableHandleValue res) {

Просмотреть файл

@ -3048,14 +3048,8 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
HandleValue rval = REGS.stackHandleAt(-1);
MutableHandleValue res = REGS.stackHandleAt(-2);
bool done =
MaybeGetElemOptimizedArguments(cx, REGS.fp(), lval, rval, res);
if (!done) {
if (!GetElementOperationWithStackIndex(cx, lval, lvalIndex, rval,
res)) {
goto error;
}
if (!GetElementOperationWithStackIndex(cx, lval, lvalIndex, rval, res)) {
goto error;
}
REGS.sp--;
@ -3186,18 +3180,13 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
}
END_CASE(SpreadCall)
CASE(FunApply) {
CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
GuardFunApplyArgumentsOptimization(cx, REGS.fp(), args);
/* FALL THROUGH */
}
CASE(New)
CASE(Call)
CASE(CallIgnoresRv)
CASE(CallIter)
CASE(SuperCall)
CASE(FunCall) {
CASE(FunCall)
CASE(FunApply) {
static_assert(JSOpLength_Call == JSOpLength_New,
"call and new must be the same size");
static_assert(JSOpLength_Call == JSOpLength_CallIgnoresRv,

Просмотреть файл

@ -4719,72 +4719,6 @@ void js::SetFrameArgumentsObject(JSContext* cx, AbstractFramePtr frame,
}
}
/* static */
void JSScript::argumentsOptimizationFailed(JSContext* cx, HandleScript script) {
MOZ_ASSERT(script->isFunction());
MOZ_ASSERT(script->argumentsHasVarBinding());
/*
* It is possible that the arguments optimization has already failed,
* everything has been fixed up, but there was an outstanding magic value
* on the stack that has just now flowed into an apply. In this case, there
* is nothing to do; GuardFunApplySpeculation will patch in the real
* argsobj.
*/
if (script->needsArgsObj()) {
return;
}
MOZ_ASSERT(!script->isGenerator());
MOZ_ASSERT(!script->isAsync());
script->setFlag(MutableFlags::NeedsArgsObj);
// Warp code depends on the NeedsArgsObj flag so invalidate the script
// (including compilations inlining the script).
{
jit::RecompileInfoVector invalid;
AddPendingInvalidation(invalid, script);
Invalidate(cx, invalid);
}
/*
* By design, the arguments optimization is only made when there are no
* outstanding cases of MagicValue(JS_OPTIMIZED_ARGUMENTS) at any points
* where the optimization could fail, other than an active invocation of
* 'f.apply(x, arguments)'. Thus, there are no outstanding values of
* MagicValue(JS_OPTIMIZED_ARGUMENTS) on the stack. However, there are
* three things that need fixup:
* - there may be any number of activations of this script that don't have
* an argsObj that now need one.
* - jit code compiled (and possible active on the stack) with the static
* assumption of !script->needsArgsObj();
* - type inference data for the script assuming script->needsArgsObj
*/
for (AllScriptFramesIter i(cx); !i.done(); ++i) {
/*
* We cannot reliably create an arguments object for Ion activations of
* this script. To maintain the invariant that "script->needsArgsObj
* implies fp->hasArgsObj", the Ion bail mechanism will create an
* arguments object right after restoring the BaselineFrame and before
* entering Baseline code (in jit::FinishBailoutToBaseline).
*/
if (i.isIon()) {
continue;
}
AbstractFramePtr frame = i.abstractFramePtr();
if (frame.isFunctionFrame() && frame.script() == script) {
/* We crash on OOM since cleaning up here would be complicated. */
AutoEnterOOMUnsafeRegion oomUnsafe;
ArgumentsObject* argsobj = ArgumentsObject::createExpected(cx, frame);
if (!argsobj) {
oomUnsafe.crash("JSScript::argumentsOptimizationFailed");
}
SetFrameArgumentsObject(cx, frame, script, argsobj);
}
}
}
bool JSScript::formalIsAliased(unsigned argSlot) {
if (functionHasParameterExprs()) {
return false;

Просмотреть файл

@ -2020,8 +2020,6 @@ class JSScript : public js::BaseScript {
}
bool needsArgsObj() const { return hasFlag(MutableFlags::NeedsArgsObj); }
static void argumentsOptimizationFailed(JSContext* cx,
js::HandleScript script);
/*
* Arguments access (via JSOp::*Arg* opcodes) must access the canonical