Issue #2305 Part 3b: Create .indices and .indices.groups

This commit is contained in:
Martok 2024-11-10 17:05:24 +01:00 committed by roytam1
commit 6dbe2de6db
2 changed files with 109 additions and 18 deletions

View file

@ -31,6 +31,28 @@ using mozilla::Maybe;
using CapturesVector = GCVector<Value, 4>;
// Allocate an object for the |.groups| or |.indices.groups| property
// of a regexp match result.
static PlainObject* CreateGroupsObject(JSContext* cx,
HandlePlainObject groupsTemplate)
{
PlainObject* result = NewObjectWithGivenProto<PlainObject>(cx, nullptr);
result->setGroup(groupsTemplate->group());
return result;
}
// Fetch a group index corresponding to a |key| from the template object
static uint32_t GetNamedCaptureIndex(JSContext* cx, HandlePlainObject groupsTemplate, HandleId key)
{
RootedValue ival(cx);
if (!NativeGetProperty(cx, groupsTemplate, key, &ival))
return -1;
return ival.toInt32();
}
/*
* Implements RegExpBuiltinExec: Steps 18-35
* https://tc39.es/ecma262/#sec-regexpbuiltinexec
@ -64,17 +86,17 @@ js::CreateRegExpMatchResult(JSContext* cx, RegExpShared& re,
if (!templateObject)
return false;
// Step 16
// Steps 18-19
size_t numPairs = matches.length();
MOZ_ASSERT(numPairs > 0);
/* Step 18-19. */
// Steps 20-21: Allocate the match result object.
RootedArrayObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, numPairs, templateObject));
if (!arr)
return false;
/* Steps 22-23 and 27 a-e
* Store a Value for each pair. */
// Steps 28-29 and 33 a-d: Initialize the elements of the match result.
// Store a Value for each match pair.
for (size_t i = 0; i < numPairs; i++) {
const MatchPair& pair = matches[i];
@ -91,15 +113,66 @@ js::CreateRegExpMatchResult(JSContext* cx, RegExpShared& re,
}
}
// Step 24 (reordered)
// Step 34a (reordered): Allocate and initialize the indices object if needed.
// This is an inlined implementation of MakeIndicesArray:
// https://tc39.es/ecma262/#sec-makeindicesarray
RootedArrayObject indices(cx);
RootedPlainObject indicesGroups(cx);
if (hasIndices) {
// MakeIndicesArray: step 8
ArrayObject* indicesTemplate =
cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx, RegExpCompartment::ResultTemplateKind::Indices);
indices = NewDenseFullyAllocatedArrayWithTemplate(cx, numPairs, indicesTemplate);
if (!indices) {
return false;
}
// MakeIndicesArray: steps 10-12
if (re.numNamedCaptures() > 0) {
RootedPlainObject groupsTemplate(cx, re.getGroupsTemplate());
indicesGroups = CreateGroupsObject(cx, groupsTemplate);
if (!indicesGroups) {
return false;
}
indices->setSlot(0, ObjectValue(*indicesGroups));
} else {
indices->setSlot(0, UndefinedValue());
}
// FIXME: can we merge this with step 28-29 and 33 a-d above??
// MakeIndicesArray: step 13 a-d. (Step 13.e is implemented below.)
for (size_t i = 0; i < numPairs; i++) {
const MatchPair& pair = matches[i];
if (pair.isUndefined()) {
// Since we had a match, first pair must be present.
MOZ_ASSERT(i != 0);
indices->setDenseInitializedLength(i + 1);
indices->initDenseElement(i, UndefinedValue());
} else {
RootedArrayObject indexPair(cx, NewDenseFullyAllocatedArray(cx, 2));
if (!indexPair) {
return false;
}
indexPair->setDenseInitializedLength(2);
indexPair->initDenseElement(0, Int32Value(pair.start));
indexPair->initDenseElement(1, Int32Value(pair.limit));
indices->setDenseInitializedLength(i + 1);
indices->initDenseElement(i, ObjectValue(*indexPair));
}
}
// /FIXME
}
// Steps 30-31 (reordered): Allocate the groups object (if needed).
RootedPlainObject groups(cx);
if (re.numNamedCaptures() > 0) {
// construct a new object from the template saved on RegExpShared
RootedPlainObject groupsTemplate(cx, re.getGroupsTemplate());
groups = NewObjectWithGivenProto<PlainObject>(cx, nullptr);
groups->setGroup(groupsTemplate->group());
groups = CreateGroupsObject(cx, groupsTemplate);
// Step 27 f.
// Step 33 e-f
// The groups template object stores the names of the named captures in the
// the order in which they are defined.
// Grab the index into the match vector from the template object and define the
@ -110,33 +183,46 @@ js::CreateRegExpMatchResult(JSContext* cx, RegExpShared& re,
}
MOZ_ASSERT(keys.length() == re.numNamedCaptures());
RootedId key(cx);
RootedValue ival(cx);
RootedValue val(cx);
for (size_t i = 0; i < keys.length(); i++) {
key = keys[i];
// fetch the group's match index...
if (!NativeGetProperty(cx, groupsTemplate, key, &ival))
return false;
// ... and set it on groups
val = arr->getDenseElement(ival.toInt32());
uint32_t idx = GetNamedCaptureIndex(cx, groupsTemplate, key);
MOZ_ASSERT(idx >= 0);
// Copy the matched string to |.groups|
val = arr->getDenseElement(idx);
if (!NativeDefineProperty(cx, groups, key, val, nullptr, nullptr, JSPROP_ENUMERATE)) {
return false;
}
// MakeIndicesArray: Step 13.e (reordered)
// If we have an |.indices|, copy the information to |.indices.groups|
if (hasIndices) {
val = indices->getDenseElement(idx);
if (!NativeDefineDataProperty(cx, indicesGroups, key, val,
JSPROP_ENUMERATE)) {
return false;
}
}
}
}
/* Step 20 (reordered).
/* Step 22 (reordered).
* Set the |index| property. (TemplateObject positions it in slot 0) */
arr->setSlot(0, Int32Value(matches[0].start));
/* Step 21 (reordered).
/* Step 23 (reordered).
* Set the |input| property. (TemplateObject positions it in slot 1) */
arr->setSlot(1, StringValue(input));
// Steps 25-26 (reordered)
// Step 32 (reordered)
// Set the |groups| property.
arr->setSlot(2, groups ? ObjectValue(*groups) : UndefinedValue());
// Step 34b (reordered)
// Set the |indices| property.
if (hasIndices) {
arr->setSlot(3, ObjectValue(*indices));
}
#ifdef DEBUG
RootedValue test(cx);
RootedId id(cx, NameToId(cx->names().index));
@ -149,7 +235,7 @@ js::CreateRegExpMatchResult(JSContext* cx, RegExpShared& re,
MOZ_ASSERT(test == arr->getSlot(1));
#endif
/* Step 25. */
/* Step 35. */
rval.setObject(*arr);
return true;
}

View file

@ -1545,6 +1545,11 @@ JitCompartment::generateRegExpMatcherStub(JSContext* cx)
ImmWord(0),
&oolEntry);
// Similarly, if the |hasIndices| flag is set, fall back to the OOL stub.
masm.branchTest32(Assembler::NonZero,
Address(shared, RegExpShared::offsetOfFlags()),
Imm32(int32_t(HasIndicesFlag)), &oolEntry);
// Construct the result.
Register object = temp1;
Label matchResultFallback, matchResultJoin;