[js] Remove pointless MakeMRegExpHoistable optimization.

master
Fedor 2020-04-03 20:55:14 +03:00
parent 4997923cea
commit d29e1bdafc
6 changed files with 4 additions and 302 deletions

View File

@ -1497,14 +1497,6 @@ OptimizeMIR(MIRGenerator* mir)
if (mir->shouldCancel("Start"))
return false;
if (!mir->compilingWasm()) {
if (!MakeMRegExpHoistable(mir, graph))
return false;
if (mir->shouldCancel("Make MRegExp Hoistable"))
return false;
}
gs.spewPass("BuildSSA");
AssertBasicGraphCoherency(graph);

View File

@ -1975,274 +1975,6 @@ jit::ApplyTypeInformation(MIRGenerator* mir, MIRGraph& graph)
return true;
}
// Check if `def` is only the N-th operand of `useDef`.
static inline size_t
IsExclusiveNthOperand(MDefinition* useDef, size_t n, MDefinition* def)
{
uint32_t num = useDef->numOperands();
if (n >= num || useDef->getOperand(n) != def)
return false;
for (uint32_t i = 0; i < num; i++) {
if (i == n)
continue;
if (useDef->getOperand(i) == def)
return false;
}
return true;
}
static size_t
IsExclusiveThisArg(MCall* call, MDefinition* def)
{
return IsExclusiveNthOperand(call, MCall::IndexOfThis(), def);
}
static size_t
IsExclusiveFirstArg(MCall* call, MDefinition* def)
{
return IsExclusiveNthOperand(call, MCall::IndexOfArgument(0), def);
}
static bool
IsRegExpHoistableCall(MCall* call, MDefinition* def)
{
if (call->isConstructing())
return false;
JSAtom* name;
if (WrappedFunction* fun = call->getSingleTarget()) {
if (!fun->isSelfHostedBuiltin())
return false;
name = GetSelfHostedFunctionName(fun->rawJSFunction());
} else {
MDefinition* funDef = call->getFunction();
if (funDef->isDebugCheckSelfHosted())
funDef = funDef->toDebugCheckSelfHosted()->input();
if (funDef->isTypeBarrier())
funDef = funDef->toTypeBarrier()->input();
if (!funDef->isCallGetIntrinsicValue())
return false;
name = funDef->toCallGetIntrinsicValue()->name();
}
// Hoistable only if the RegExp is the first argument of RegExpBuiltinExec.
CompileRuntime* runtime = GetJitContext()->runtime;
if (name == runtime->names().RegExpBuiltinExec ||
name == runtime->names().UnwrapAndCallRegExpBuiltinExec ||
name == runtime->names().RegExpMatcher ||
name == runtime->names().RegExpTester ||
name == runtime->names().RegExpSearcher)
{
return IsExclusiveFirstArg(call, def);
}
if (name == runtime->names().RegExp_prototype_Exec)
return IsExclusiveThisArg(call, def);
return false;
}
static bool
CanCompareRegExp(MCompare* compare, MDefinition* def)
{
MDefinition* value;
if (compare->lhs() == def) {
value = compare->rhs();
} else {
MOZ_ASSERT(compare->rhs() == def);
value = compare->lhs();
}
// Comparing two regexp that weren't cloned will give different result
// than if they were cloned.
if (value->mightBeType(MIRType::Object))
return false;
// Make sure @@toPrimitive is not called which could notice
// the difference between a not cloned/cloned regexp.
JSOp op = compare->jsop();
// Strict equality comparison won't invoke @@toPrimitive.
if (op == JSOP_STRICTEQ || op == JSOP_STRICTNE)
return true;
if (op != JSOP_EQ && op != JSOP_NE) {
// Relational comparison always invoke @@toPrimitive.
MOZ_ASSERT(op == JSOP_GT || op == JSOP_GE || op == JSOP_LT || op == JSOP_LE);
return false;
}
// Loose equality comparison can invoke @@toPrimitive.
if (value->mightBeType(MIRType::Boolean) || value->mightBeType(MIRType::String) ||
value->mightBeType(MIRType::Int32) ||
value->mightBeType(MIRType::Double) || value->mightBeType(MIRType::Float32) ||
value->mightBeType(MIRType::Symbol))
{
return false;
}
return true;
}
static inline void
SetNotInWorklist(MDefinitionVector& worklist)
{
for (size_t i = 0; i < worklist.length(); i++)
worklist[i]->setNotInWorklist();
}
static bool
IsRegExpHoistable(MIRGenerator* mir, MDefinition* regexp, MDefinitionVector& worklist,
bool* hoistable)
{
MOZ_ASSERT(worklist.length() == 0);
if (!worklist.append(regexp))
return false;
regexp->setInWorklist();
for (size_t i = 0; i < worklist.length(); i++) {
MDefinition* def = worklist[i];
if (mir->shouldCancel("IsRegExpHoistable outer loop"))
return false;
for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) {
if (mir->shouldCancel("IsRegExpHoistable inner loop"))
return false;
// Ignore resume points. At this point all uses are listed.
// No DCE or GVN or something has happened.
if (use->consumer()->isResumePoint())
continue;
MDefinition* useDef = use->consumer()->toDefinition();
// Step through a few white-listed ops.
if (useDef->isPhi() || useDef->isFilterTypeSet() || useDef->isGuardShape()) {
if (useDef->isInWorklist())
continue;
if (!worklist.append(useDef))
return false;
useDef->setInWorklist();
continue;
}
// Instructions that doesn't invoke unknown code that may modify
// RegExp instance or pass it to elsewhere.
if (useDef->isRegExpMatcher() || useDef->isRegExpTester() ||
useDef->isRegExpSearcher())
{
if (IsExclusiveNthOperand(useDef, 0, def))
continue;
} else if (useDef->isLoadFixedSlot() || useDef->isTypeOf()) {
continue;
} else if (useDef->isCompare()) {
if (CanCompareRegExp(useDef->toCompare(), def))
continue;
}
// Instructions that modifies `lastIndex` property.
else if (useDef->isStoreFixedSlot()) {
if (IsExclusiveNthOperand(useDef, 0, def)) {
MStoreFixedSlot* store = useDef->toStoreFixedSlot();
if (store->slot() == RegExpObject::lastIndexSlot())
continue;
}
} else if (useDef->isSetPropertyCache()) {
if (IsExclusiveNthOperand(useDef, 0, def)) {
MSetPropertyCache* setProp = useDef->toSetPropertyCache();
if (setProp->idval()->isConstant()) {
Value propIdVal = setProp->idval()->toConstant()->toJSValue();
if (propIdVal.isString()) {
CompileRuntime* runtime = GetJitContext()->runtime;
if (propIdVal.toString() == runtime->names().lastIndex)
continue;
}
}
}
}
// MCall is safe only for some known safe functions.
else if (useDef->isCall()) {
if (IsRegExpHoistableCall(useDef->toCall(), def))
continue;
}
// Everything else is unsafe.
SetNotInWorklist(worklist);
worklist.clear();
*hoistable = false;
return true;
}
}
SetNotInWorklist(worklist);
worklist.clear();
*hoistable = true;
return true;
}
bool
jit::MakeMRegExpHoistable(MIRGenerator* mir, MIRGraph& graph)
{
// If we are compiling try blocks, regular expressions may be observable
// from catch blocks (which Ion does not compile). For now just disable the
// pass in this case.
if (graph.hasTryBlock())
return true;
MDefinitionVector worklist(graph.alloc());
for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
if (mir->shouldCancel("MakeMRegExpHoistable outer loop"))
return false;
for (MDefinitionIterator iter(*block); iter; iter++) {
if (!*iter)
MOZ_CRASH("confirm bug 1263794.");
if (mir->shouldCancel("MakeMRegExpHoistable inner loop"))
return false;
if (!iter->isRegExp())
continue;
MRegExp* regexp = iter->toRegExp();
bool hoistable = false;
if (!IsRegExpHoistable(mir, regexp, worklist, &hoistable))
return false;
if (!hoistable)
continue;
// Make MRegExp hoistable
regexp->setMovable();
regexp->setDoNotClone();
// That would be incorrect for global/sticky, because lastIndex
// could be wrong. Therefore setting the lastIndex to 0. That is
// faster than a not movable regexp.
RegExpObject* source = regexp->source();
if (source->sticky() || source->global()) {
if (!graph.alloc().ensureBallast())
return false;
MConstant* zero = MConstant::New(graph.alloc(), Int32Value(0));
regexp->block()->insertAfter(regexp, zero);
MStoreFixedSlot* lastIndex =
MStoreFixedSlot::New(graph.alloc(), regexp, RegExpObject::lastIndexSlot(), zero);
regexp->block()->insertAfter(zero, lastIndex);
}
}
}
return true;
}
void
jit::RenumberBlocks(MIRGraph& graph)
{

View File

@ -56,9 +56,6 @@ EliminateDeadCode(MIRGenerator* mir, MIRGraph& graph);
MOZ_MUST_USE bool
ApplyTypeInformation(MIRGenerator* mir, MIRGraph& graph);
MOZ_MUST_USE bool
MakeMRegExpHoistable(MIRGenerator* mir, MIRGraph& graph);
void
RenumberBlocks(MIRGraph& graph);

View File

@ -2297,14 +2297,9 @@ LIRGenerator::visitToObjectOrNull(MToObjectOrNull* ins)
void
LIRGenerator::visitRegExp(MRegExp* ins)
{
if (ins->mustClone()) {
LRegExp* lir = new(alloc()) LRegExp();
defineReturn(lir, ins);
assignSafepoint(lir, ins);
} else {
RegExpObject* source = ins->source();
define(new(alloc()) LPointer(source), ins);
}
LRegExp* lir = new(alloc()) LRegExp();
defineReturn(lir, ins);
assignSafepoint(lir, ins);
}
void

View File

@ -8102,11 +8102,9 @@ class MDefFun
class MRegExp : public MNullaryInstruction
{
CompilerGCPointer<RegExpObject*> source_;
bool mustClone_;
MRegExp(CompilerConstraintList* constraints, RegExpObject* source)
: source_(source),
mustClone_(true)
: source_(source)
{
setResultType(MIRType::Object);
setResultTypeSet(MakeSingletonTypeSet(constraints, source));
@ -8116,12 +8114,6 @@ class MRegExp : public MNullaryInstruction
INSTRUCTION_HEADER(RegExp)
TRIVIAL_NEW_WRAPPERS
void setDoNotClone() {
mustClone_ = false;
}
bool mustClone() const {
return mustClone_;
}
RegExpObject* source() const {
return source_;
}

View File

@ -281,13 +281,8 @@
macro(proxy, proxy, "proxy") \
macro(raw, raw, "raw") \
macro(reason, reason, "reason") \
macro(RegExpBuiltinExec, RegExpBuiltinExec, "RegExpBuiltinExec") \
macro(RegExpFlagsGetter, RegExpFlagsGetter, "RegExpFlagsGetter") \
macro(RegExpMatcher, RegExpMatcher, "RegExpMatcher") \
macro(RegExpSearcher, RegExpSearcher, "RegExpSearcher") \
macro(RegExpStringIterator, RegExpStringIterator, "RegExp String Iterator") \
macro(RegExpTester, RegExpTester, "RegExpTester") \
macro(RegExp_prototype_Exec, RegExp_prototype_Exec, "RegExp_prototype_Exec") \
macro(Reify, Reify, "Reify") \
macro(reject, reject, "reject") \
macro(rejected, rejected, "rejected") \
@ -360,7 +355,6 @@
macro(uninitialized, uninitialized, "uninitialized") \
macro(unsized, unsized, "unsized") \
macro(unwatch, unwatch, "unwatch") \
macro(UnwrapAndCallRegExpBuiltinExec, UnwrapAndCallRegExpBuiltinExec, "UnwrapAndCallRegExpBuiltinExec") \
macro(url, url, "url") \
macro(usage, usage, "usage") \
macro(useAsm, useAsm, "use asm") \