mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 723640 - Don't clone regexps in Ion code if cloning is not observable. r=bhackett
This commit is contained in:
parent
27586aa6a7
commit
d55f9aed12
8
js/src/jit-test/tests/ion/regexp-clone.js
Normal file
8
js/src/jit-test/tests/ion/regexp-clone.js
Normal file
@ -0,0 +1,8 @@
|
||||
var i=0;
|
||||
function f() {
|
||||
assertEq(/^[a-z0-9\.]+$/gi.test("Foo.Bar"), true);
|
||||
i++;
|
||||
if (i < 100)
|
||||
f();
|
||||
}
|
||||
f();
|
@ -23,6 +23,7 @@
|
||||
#include "jit/MIRGraph.h"
|
||||
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/RegExpStatics.h"
|
||||
|
||||
#include "jsinferinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
@ -8873,7 +8874,31 @@ IonBuilder::jsop_regexp(RegExpObject *reobj)
|
||||
if (!prototype)
|
||||
return false;
|
||||
|
||||
MRegExp *regexp = MRegExp::New(reobj, prototype);
|
||||
JS_ASSERT(&reobj->JSObject::global() == &script()->global());
|
||||
|
||||
// JS semantics require regular expression literals to create different
|
||||
// objects every time they execute. We only need to do this cloning if the
|
||||
// script could actually observe the effect of such cloning, for instance
|
||||
// by getting or setting properties on it.
|
||||
//
|
||||
// First, make sure the regex is one we can safely optimize. Lowering can
|
||||
// then check if this regex object only flows into known natives and can
|
||||
// avoid cloning in this case.
|
||||
|
||||
bool mustClone = true;
|
||||
types::TypeObjectKey *typeObj = types::TypeObjectKey::get(&script()->global());
|
||||
if (!typeObj->hasFlags(constraints(), types::OBJECT_FLAG_REGEXP_FLAGS_SET)) {
|
||||
RegExpStatics *res = script()->global().getRegExpStatics();
|
||||
|
||||
DebugOnly<uint32_t> origFlags = reobj->getFlags();
|
||||
DebugOnly<uint32_t> staticsFlags = res->getFlags();
|
||||
JS_ASSERT((origFlags & staticsFlags) == staticsFlags);
|
||||
|
||||
if (!reobj->global() && !reobj->sticky())
|
||||
mustClone = false;
|
||||
}
|
||||
|
||||
MRegExp *regexp = MRegExp::New(reobj, prototype, mustClone);
|
||||
current->add(regexp);
|
||||
current->push(regexp);
|
||||
|
||||
@ -8883,6 +8908,7 @@ IonBuilder::jsop_regexp(RegExpObject *reobj)
|
||||
// That would be incorrect for global/sticky, because lastIndex could be wrong.
|
||||
// Therefore setting the lastIndex to 0. That is faster than removing the movable flag.
|
||||
if (reobj->sticky() || reobj->global()) {
|
||||
JS_ASSERT(mustClone);
|
||||
MConstant *zero = MConstant::New(Int32Value(0));
|
||||
current->add(zero);
|
||||
|
||||
|
@ -1776,9 +1776,87 @@ LIRGenerator::visitToString(MToString *ins)
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
MustCloneRegExpForCall(MPassArg *arg)
|
||||
{
|
||||
// |arg| is a regex literal flowing into a call. Return |false| iff
|
||||
// this is a native call that does not let the regex escape.
|
||||
|
||||
JS_ASSERT(arg->getArgument()->isRegExp());
|
||||
|
||||
for (MUseIterator iter(arg->usesBegin()); iter != arg->usesEnd(); iter++) {
|
||||
MNode *node = iter->consumer();
|
||||
if (!node->isDefinition())
|
||||
return true;
|
||||
|
||||
MDefinition *def = node->toDefinition();
|
||||
if (!def->isCall())
|
||||
return true;
|
||||
|
||||
MCall *call = def->toCall();
|
||||
JSFunction *target = call->getSingleTarget();
|
||||
if (!target || !target->isNative())
|
||||
return true;
|
||||
|
||||
if (iter->index() == MCall::IndexOfThis() &&
|
||||
(target->native() == regexp_exec || target->native() == regexp_test))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iter->index() == MCall::IndexOfArgument(0) &&
|
||||
(target->native() == str_split ||
|
||||
target->native() == str_replace ||
|
||||
target->native() == str_match ||
|
||||
target->native() == str_search))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
MustCloneRegExp(MRegExp *regexp)
|
||||
{
|
||||
if (regexp->mustClone())
|
||||
return true;
|
||||
|
||||
// If this regex literal only flows into known natives that don't let
|
||||
// it escape, we don't have to clone it.
|
||||
|
||||
for (MUseIterator iter(regexp->usesBegin()); iter != regexp->usesEnd(); iter++) {
|
||||
MNode *node = iter->consumer();
|
||||
if (!node->isDefinition())
|
||||
return true;
|
||||
|
||||
MDefinition *def = node->toDefinition();
|
||||
if (def->isRegExpTest() && iter->index() == 1) {
|
||||
// Optimized RegExp.prototype.test.
|
||||
JS_ASSERT(def->toRegExpTest()->regexp() == regexp);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (def->isPassArg() && !MustCloneRegExpForCall(def->toPassArg()))
|
||||
continue;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitRegExp(MRegExp *ins)
|
||||
{
|
||||
if (!MustCloneRegExp(ins)) {
|
||||
RegExpObject *source = ins->source();
|
||||
return define(new LPointer(source), ins);
|
||||
}
|
||||
|
||||
LRegExp *lir = new LRegExp();
|
||||
return defineReturn(lir, ins) && assignSafepoint(lir, ins);
|
||||
}
|
||||
|
@ -1832,6 +1832,13 @@ class MCall
|
||||
replaceOperand(NumNonArgumentOperands + index, def);
|
||||
}
|
||||
|
||||
static size_t IndexOfThis() {
|
||||
return NumNonArgumentOperands;
|
||||
}
|
||||
static size_t IndexOfArgument(size_t index) {
|
||||
return NumNonArgumentOperands + index + 1; // +1 to skip |this|.
|
||||
}
|
||||
|
||||
// For TI-informed monomorphic callsites.
|
||||
JSFunction *getSingleTarget() const {
|
||||
return target_;
|
||||
@ -4481,10 +4488,12 @@ class MRegExp : public MNullaryInstruction
|
||||
{
|
||||
CompilerRoot<RegExpObject *> source_;
|
||||
CompilerRootObject prototype_;
|
||||
bool mustClone_;
|
||||
|
||||
MRegExp(RegExpObject *source, JSObject *prototype)
|
||||
MRegExp(RegExpObject *source, JSObject *prototype, bool mustClone)
|
||||
: source_(source),
|
||||
prototype_(prototype)
|
||||
prototype_(prototype),
|
||||
mustClone_(mustClone)
|
||||
{
|
||||
setResultType(MIRType_Object);
|
||||
|
||||
@ -4495,10 +4504,13 @@ class MRegExp : public MNullaryInstruction
|
||||
public:
|
||||
INSTRUCTION_HEADER(RegExp)
|
||||
|
||||
static MRegExp *New(RegExpObject *source, JSObject *prototype) {
|
||||
return new MRegExp(source, prototype);
|
||||
static MRegExp *New(RegExpObject *source, JSObject *prototype, bool mustClone) {
|
||||
return new MRegExp(source, prototype, mustClone);
|
||||
}
|
||||
|
||||
bool mustClone() const {
|
||||
return mustClone_;
|
||||
}
|
||||
RegExpObject *source() const {
|
||||
return source_;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user