| Index: src/builtins/builtins-regexp.cc
|
| diff --git a/src/builtins/builtins-regexp.cc b/src/builtins/builtins-regexp.cc
|
| index 2191268441c92687715ff86cbfecd9774b770ebc..ea1a73ea5e1e29f288a38ceb98462fdb7a1241c3 100644
|
| --- a/src/builtins/builtins-regexp.cc
|
| +++ b/src/builtins/builtins-regexp.cc
|
| @@ -33,8 +33,9 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
|
| void StoreLastIndex(Node* context, Node* regexp, Node* value,
|
| bool is_fastpath);
|
|
|
| - Node* ConstructNewResultFromMatchInfo(Node* context, Node* match_info,
|
| - Node* string);
|
| + Node* ConstructNewResultFromMatchInfo(Node* const context, Node* const regexp,
|
| + Node* const match_info,
|
| + Node* const string);
|
|
|
| Node* RegExpPrototypeExecBodyWithoutResult(Node* const context,
|
| Node* const regexp,
|
| @@ -141,10 +142,10 @@ void RegExpBuiltinsAssembler::StoreLastIndex(Node* context, Node* regexp,
|
| }
|
| }
|
|
|
| -Node* RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(Node* context,
|
| - Node* match_info,
|
| - Node* string) {
|
| - Label out(this);
|
| +Node* RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
|
| + Node* const context, Node* const regexp, Node* const match_info,
|
| + Node* const string) {
|
| + Label named_captures(this), out(this);
|
|
|
| Node* const num_indices = SmiUntag(LoadFixedArrayElement(
|
| match_info, RegExpMatchInfo::kNumberOfCapturesIndex));
|
| @@ -164,7 +165,8 @@ Node* RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(Node* context,
|
|
|
| StoreFixedArrayElement(result_elements, 0, first, SKIP_WRITE_BARRIER);
|
|
|
| - GotoIf(SmiEqual(num_results, SmiConstant(Smi::FromInt(1))), &out);
|
| + // If no captures exist we can skip named capture handling as well.
|
| + GotoIf(SmiEqual(num_results, SmiConstant(1)), &out);
|
|
|
| // Store all remaining captures.
|
| Node* const limit = IntPtrAdd(
|
| @@ -187,7 +189,7 @@ Node* RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(Node* context,
|
| Node* const start = LoadFixedArrayElement(match_info, from_cursor);
|
|
|
| Label next_iter(this);
|
| - GotoIf(SmiEqual(start, SmiConstant(Smi::FromInt(-1))), &next_iter);
|
| + GotoIf(SmiEqual(start, SmiConstant(-1)), &next_iter);
|
|
|
| Node* const from_cursor_plus1 = IntPtrAdd(from_cursor, IntPtrConstant(1));
|
| Node* const end = LoadFixedArrayElement(match_info, from_cursor_plus1);
|
| @@ -199,7 +201,83 @@ Node* RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(Node* context,
|
| Bind(&next_iter);
|
| var_from_cursor.Bind(IntPtrAdd(from_cursor, IntPtrConstant(2)));
|
| var_to_cursor.Bind(IntPtrAdd(to_cursor, IntPtrConstant(1)));
|
| - Branch(UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out);
|
| + Branch(UintPtrLessThan(var_from_cursor.value(), limit), &loop,
|
| + &named_captures);
|
| + }
|
| +
|
| + Bind(&named_captures);
|
| + {
|
| + // We reach this point only if captures exist, implying that this is an
|
| + // IRREGEXP JSRegExp.
|
| +
|
| + CSA_ASSERT(this, HasInstanceType(regexp, JS_REGEXP_TYPE));
|
| + CSA_ASSERT(this, SmiGreaterThan(num_results, SmiConstant(1)));
|
| +
|
| + // Preparations for named capture properties. Exit early if the result does
|
| + // not have any named captures to minimize performance impact.
|
| +
|
| + Node* const data = LoadObjectField(regexp, JSRegExp::kDataOffset);
|
| + CSA_ASSERT(this, SmiEqual(LoadFixedArrayElement(data, JSRegExp::kTagIndex),
|
| + SmiConstant(JSRegExp::IRREGEXP)));
|
| +
|
| + // The names fixed array associates names at even indices with a capture
|
| + // index at odd indices.
|
| + Node* const names =
|
| + LoadFixedArrayElement(data, JSRegExp::kIrregexpCaptureNameMapIndex);
|
| + GotoIf(SmiEqual(names, SmiConstant(0)), &out);
|
| +
|
| + // Allocate a new object to store the named capture properties.
|
| + // TODO(jgruber): Could be optimized by adding the object map to the heap
|
| + // root list.
|
| +
|
| + Node* const native_context = LoadNativeContext(context);
|
| + Node* const map = LoadContextElement(
|
| + native_context, Context::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP);
|
| + Node* const properties =
|
| + AllocateNameDictionary(NameDictionary::kInitialCapacity);
|
| +
|
| + Node* const group_object = AllocateJSObjectFromMap(map, properties);
|
| +
|
| + // Store it on the result as a 'group' property.
|
| +
|
| + {
|
| + Node* const name = HeapConstant(isolate()->factory()->group_string());
|
| + CallRuntime(Runtime::kCreateDataProperty, context, result, name,
|
| + group_object);
|
| + }
|
| +
|
| + // One or more named captures exist, add a property for each one.
|
| +
|
| + CSA_ASSERT(this, HasInstanceType(names, FIXED_ARRAY_TYPE));
|
| + Node* const names_length = LoadAndUntagFixedArrayBaseLength(names);
|
| + CSA_ASSERT(this, IntPtrGreaterThan(names_length, IntPtrConstant(0)));
|
| +
|
| + Variable var_i(this, MachineType::PointerRepresentation());
|
| + var_i.Bind(IntPtrConstant(0));
|
| +
|
| + Variable* vars[] = {&var_i};
|
| + const int vars_count = sizeof(vars) / sizeof(vars[0]);
|
| + Label loop(this, vars_count, vars);
|
| +
|
| + Goto(&loop);
|
| + Bind(&loop);
|
| + {
|
| + Node* const i = var_i.value();
|
| + Node* const i_plus_1 = IntPtrAdd(i, IntPtrConstant(1));
|
| + Node* const i_plus_2 = IntPtrAdd(i_plus_1, IntPtrConstant(1));
|
| +
|
| + Node* const name = LoadFixedArrayElement(names, i);
|
| + Node* const index = LoadFixedArrayElement(names, i_plus_1);
|
| + Node* const capture =
|
| + LoadFixedArrayElement(result_elements, SmiUntag(index));
|
| +
|
| + CallRuntime(Runtime::kCreateDataProperty, context, group_object, name,
|
| + capture);
|
| +
|
| + var_i.Bind(i_plus_2);
|
| + Branch(IntPtrGreaterThanOrEqual(var_i.value(), names_length), &out,
|
| + &loop);
|
| + }
|
| }
|
|
|
| Bind(&out);
|
| @@ -352,7 +430,7 @@ Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBody(Node* const context,
|
| {
|
| Node* const match_indices = indices_or_null;
|
| Node* const result =
|
| - ConstructNewResultFromMatchInfo(context, match_indices, string);
|
| + ConstructNewResultFromMatchInfo(context, regexp, match_indices, string);
|
| var_result.Bind(result);
|
| Goto(&out);
|
| }
|
| @@ -2522,7 +2600,7 @@ TF_BUILTIN(RegExpInternalMatch, RegExpBuiltinsAssembler) {
|
| Bind(&if_matched);
|
| {
|
| Node* result =
|
| - ConstructNewResultFromMatchInfo(context, match_indices, string);
|
| + ConstructNewResultFromMatchInfo(context, regexp, match_indices, string);
|
| Return(result);
|
| }
|
| }
|
|
|