[regexp] Update lastIndex semantics in RegExpBuiltinExec
Updated according to the recent spec change at https://github.com/tc39/ecma262/pull/798. BUG=v8:5949 Review-Url: https://codereview.chromium.org/2681323002 Cr-Commit-Position: refs/heads/master@{#43062}
This commit is contained in:
parent
93c1e73d06
commit
b798b5212a
@ -241,6 +241,27 @@ Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult(
|
||||
Node* const native_context = LoadNativeContext(context);
|
||||
Node* const string_length = LoadStringLength(string);
|
||||
|
||||
// Load lastIndex.
|
||||
Variable var_lastindex(this, MachineRepresentation::kTagged);
|
||||
{
|
||||
Node* const regexp_lastindex = LoadLastIndex(context, regexp, is_fastpath);
|
||||
var_lastindex.Bind(regexp_lastindex);
|
||||
|
||||
// Omit ToLength if lastindex is a non-negative smi.
|
||||
Label call_tolength(this, Label::kDeferred), next(this);
|
||||
Branch(TaggedIsPositiveSmi(regexp_lastindex), &next, &call_tolength);
|
||||
|
||||
Bind(&call_tolength);
|
||||
{
|
||||
Callable tolength_callable = CodeFactory::ToLength(isolate);
|
||||
var_lastindex.Bind(
|
||||
CallStub(tolength_callable, context, regexp_lastindex));
|
||||
Goto(&next);
|
||||
}
|
||||
|
||||
Bind(&next);
|
||||
}
|
||||
|
||||
// Check whether the regexp is global or sticky, which determines whether we
|
||||
// update last index later on.
|
||||
Node* const flags = LoadObjectField(regexp, JSRegExp::kFlagsOffset);
|
||||
@ -251,33 +272,12 @@ Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult(
|
||||
|
||||
// Grab and possibly update last index.
|
||||
Label run_exec(this);
|
||||
Variable var_lastindex(this, MachineRepresentation::kTagged);
|
||||
{
|
||||
Label if_doupdate(this), if_dontupdate(this);
|
||||
Branch(should_update_last_index, &if_doupdate, &if_dontupdate);
|
||||
|
||||
Bind(&if_doupdate);
|
||||
{
|
||||
Node* const regexp_lastindex =
|
||||
LoadLastIndex(context, regexp, is_fastpath);
|
||||
var_lastindex.Bind(regexp_lastindex);
|
||||
|
||||
// Omit ToLength if lastindex is a non-negative smi.
|
||||
{
|
||||
Label call_tolength(this, Label::kDeferred), next(this);
|
||||
Branch(TaggedIsPositiveSmi(regexp_lastindex), &next, &call_tolength);
|
||||
|
||||
Bind(&call_tolength);
|
||||
{
|
||||
Callable tolength_callable = CodeFactory::ToLength(isolate);
|
||||
var_lastindex.Bind(
|
||||
CallStub(tolength_callable, context, regexp_lastindex));
|
||||
Goto(&next);
|
||||
}
|
||||
|
||||
Bind(&next);
|
||||
}
|
||||
|
||||
Node* const lastindex = var_lastindex.value();
|
||||
|
||||
Label if_isoob(this, Label::kDeferred);
|
||||
|
@ -564,21 +564,21 @@ log = [];
|
||||
re.lastIndex = fakeLastIndex;
|
||||
var result = re.exec(fakeString);
|
||||
assertEquals(["str"], result);
|
||||
assertEquals(["ts"], log);
|
||||
assertEquals(["ts", "li"], log);
|
||||
|
||||
// Again, to check if caching interferes.
|
||||
log = [];
|
||||
re.lastIndex = fakeLastIndex;
|
||||
result = re.exec(fakeString);
|
||||
assertEquals(["str"], result);
|
||||
assertEquals(["ts"], log);
|
||||
assertEquals(["ts", "li"], log);
|
||||
|
||||
// And one more time, just to be certain.
|
||||
log = [];
|
||||
re.lastIndex = fakeLastIndex;
|
||||
result = re.exec(fakeString);
|
||||
assertEquals(["str"], result);
|
||||
assertEquals(["ts"], log);
|
||||
assertEquals(["ts", "li"], log);
|
||||
|
||||
// Now with a global regexp, where lastIndex is actually used.
|
||||
re = /str/g;
|
||||
|
@ -27,20 +27,16 @@
|
||||
|
||||
function testSideEffects(subject, re) {
|
||||
var counter = 0;
|
||||
var expected_counter = 0;
|
||||
const accesses_lastindex = (re.global || re.sticky);
|
||||
var side_effect_object = { valueOf: function() { return counter++; } };
|
||||
re.lastIndex = side_effect_object;
|
||||
re.exec(subject);
|
||||
|
||||
if (accesses_lastindex) expected_counter++;
|
||||
assertEquals(expected_counter, counter);
|
||||
assertEquals(1, counter);
|
||||
|
||||
re.lastIndex = side_effect_object;
|
||||
re.test(subject);
|
||||
|
||||
if (accesses_lastindex) expected_counter++;
|
||||
assertEquals(expected_counter, counter);
|
||||
assertEquals(2, counter);
|
||||
}
|
||||
|
||||
testSideEffects("zzzz", /a/);
|
||||
|
@ -91,6 +91,10 @@
|
||||
'built-ins/RegExp/prototype/Symbol.replace/y-init-lastindex': [FAIL],
|
||||
'built-ins/RegExp/prototype/Symbol.replace/y-set-lastindex': [FAIL],
|
||||
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=5949
|
||||
'built-ins/RegExp/prototype/exec/failure-lastindex-no-access': [FAIL],
|
||||
'built-ins/RegExp/prototype/exec/success-lastindex-no-access': [FAIL],
|
||||
|
||||
###### END REGEXP SUBCLASSING SECTION ######
|
||||
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=4895
|
||||
|
Loading…
Reference in New Issue
Block a user