| Index: src/runtime/runtime-regexp.cc | 
| diff --git a/src/runtime/runtime-regexp.cc b/src/runtime/runtime-regexp.cc | 
| index 986c7365ef46692b035b64bb3ecc6fa813346778..865f85a73fa0fd6a0876b42764280c6a782f525a 100644 | 
| --- a/src/runtime/runtime-regexp.cc | 
| +++ b/src/runtime/runtime-regexp.cc | 
| @@ -401,7 +401,7 @@ void TruncateRegexpIndicesList(Isolate* isolate) { | 
| template <typename ResultSeqString> | 
| MUST_USE_RESULT static Object* StringReplaceGlobalAtomRegExpWithString( | 
| Isolate* isolate, Handle<String> subject, Handle<JSRegExp> pattern_regexp, | 
| -    Handle<String> replacement, Handle<JSObject> last_match_info) { | 
| +    Handle<String> replacement, Handle<RegExpMatchInfo> last_match_info) { | 
| DCHECK(subject->IsFlat()); | 
| DCHECK(replacement->IsFlat()); | 
|  | 
| @@ -479,7 +479,7 @@ MUST_USE_RESULT static Object* StringReplaceGlobalAtomRegExpWithString( | 
|  | 
| MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithString( | 
| Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, | 
| -    Handle<String> replacement, Handle<JSObject> last_match_info) { | 
| +    Handle<String> replacement, Handle<RegExpMatchInfo> last_match_info) { | 
| DCHECK(subject->IsFlat()); | 
| DCHECK(replacement->IsFlat()); | 
|  | 
| @@ -561,7 +561,7 @@ MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithString( | 
| template <typename ResultSeqString> | 
| MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithEmptyString( | 
| Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, | 
| -    Handle<JSObject> last_match_info) { | 
| +    Handle<RegExpMatchInfo> last_match_info) { | 
| DCHECK(subject->IsFlat()); | 
|  | 
| // Shortcut for simple non-regexp global replacements | 
| @@ -660,9 +660,8 @@ namespace { | 
|  | 
| Object* StringReplaceGlobalRegExpWithStringHelper( | 
| Isolate* isolate, Handle<JSRegExp> regexp, Handle<String> subject, | 
| -    Handle<String> replacement, Handle<JSObject> last_match_info) { | 
| +    Handle<String> replacement, Handle<RegExpMatchInfo> last_match_info) { | 
| CHECK(regexp->GetFlags() & JSRegExp::kGlobal); | 
| -  CHECK(last_match_info->HasFastObjectElements()); | 
|  | 
| subject = String::Flatten(subject); | 
|  | 
| @@ -691,7 +690,7 @@ RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) { | 
| CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | 
| CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2); | 
| CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); | 
| -  CONVERT_ARG_HANDLE_CHECKED(JSObject, last_match_info, 3); | 
| +  CONVERT_ARG_HANDLE_CHECKED(RegExpMatchInfo, last_match_info, 3); | 
|  | 
| return StringReplaceGlobalRegExpWithStringHelper( | 
| isolate, regexp, subject, replacement, last_match_info); | 
| @@ -811,7 +810,7 @@ RUNTIME_FUNCTION(Runtime_RegExpExec) { | 
| CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); | 
| CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); | 
| CONVERT_INT32_ARG_CHECKED(index, 2); | 
| -  CONVERT_ARG_HANDLE_CHECKED(JSObject, last_match_info, 3); | 
| +  CONVERT_ARG_HANDLE_CHECKED(RegExpMatchInfo, last_match_info, 3); | 
| // Due to the way the JS calls are constructed this must be less than the | 
| // length of a string, i.e. it is always a Smi.  We check anyway for security. | 
| CHECK(index >= 0); | 
| @@ -877,10 +876,8 @@ RUNTIME_FUNCTION(Runtime_RegExpInternalReplace) { | 
| CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); | 
| CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2); | 
|  | 
| -  static const int kInitialMatchSlots = 2; | 
| -  Handle<JSArray> internal_match_info = isolate->factory()->NewJSArray( | 
| -      FAST_ELEMENTS, 0, RegExpImpl::kLastMatchOverhead + kInitialMatchSlots, | 
| -      INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); | 
| +  Handle<RegExpMatchInfo> internal_match_info = | 
| +      isolate->regexp_internal_match_info(); | 
|  | 
| return StringReplaceGlobalRegExpWithStringHelper( | 
| isolate, regexp, subject, replacement, internal_match_info); | 
| @@ -891,7 +888,7 @@ namespace { | 
| class MatchInfoBackedMatch : public String::Match { | 
| public: | 
| MatchInfoBackedMatch(Isolate* isolate, Handle<String> subject, | 
| -                       Handle<JSObject> match_info) | 
| +                       Handle<RegExpMatchInfo> match_info) | 
| : isolate_(isolate), match_info_(match_info) { | 
| subject_ = String::Flatten(subject); | 
| } | 
| @@ -912,20 +909,18 @@ class MatchInfoBackedMatch : public String::Match { | 
| } | 
|  | 
| Handle<String> GetPrefix() override { | 
| -    const int match_start = | 
| -        RegExpUtils::GetLastMatchCapture(isolate_, match_info_, 0); | 
| +    const int match_start = match_info_->Capture(0); | 
| return isolate_->factory()->NewSubString(subject_, 0, match_start); | 
| } | 
|  | 
| Handle<String> GetSuffix() override { | 
| -    const int match_end = | 
| -        RegExpUtils::GetLastMatchCapture(isolate_, match_info_, 1); | 
| +    const int match_end = match_info_->Capture(1); | 
| return isolate_->factory()->NewSubString(subject_, match_end, | 
| subject_->length()); | 
| } | 
|  | 
| int CaptureCount() override { | 
| -    return RegExpUtils::GetLastMatchNumberOfCaptures(isolate_, match_info_) / 2; | 
| +    return match_info_->NumberOfCaptureRegisters() / 2; | 
| } | 
|  | 
| virtual ~MatchInfoBackedMatch() {} | 
| @@ -933,7 +928,7 @@ class MatchInfoBackedMatch : public String::Match { | 
| private: | 
| Isolate* isolate_; | 
| Handle<String> subject_; | 
| -  Handle<JSObject> match_info_; | 
| +  Handle<RegExpMatchInfo> match_info_; | 
| }; | 
|  | 
| class VectorBackedMatch : public String::Match { | 
| @@ -985,11 +980,10 @@ class VectorBackedMatch : public String::Match { | 
| // Only called from RegExpExecMultiple so it doesn't need to maintain | 
| // separate last match info.  See comment on that function. | 
| template <bool has_capture> | 
| -MaybeHandle<Object> SearchRegExpMultiple(Isolate* isolate, | 
| -                                         Handle<String> subject, | 
| -                                         Handle<JSRegExp> regexp, | 
| -                                         Handle<JSObject> last_match_array, | 
| -                                         Handle<FixedArray> result_elements) { | 
| +MaybeHandle<Object> SearchRegExpMultiple( | 
| +    Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, | 
| +    Handle<RegExpMatchInfo> last_match_array, | 
| +    Handle<FixedArray> result_elements) { | 
| DCHECK(subject->IsFlat()); | 
| DCHECK_NE(has_capture, regexp->CaptureCount() == 0); | 
|  | 
| @@ -1133,10 +1127,8 @@ MaybeHandle<Object> SearchRegExpMultiple(Isolate* isolate, | 
| MaybeHandle<Object> RegExpExecMultiple(Isolate* isolate, | 
| Handle<JSRegExp> regexp, | 
| Handle<String> subject, | 
| -                                       Handle<JSObject> last_match_info, | 
| +                                       Handle<RegExpMatchInfo> last_match_info, | 
| Handle<FixedArray> result_array) { | 
| -  CHECK(last_match_info->HasFastObjectElements()); | 
| - | 
| subject = String::Flatten(subject); | 
| CHECK(regexp->GetFlags() & JSRegExp::kGlobal); | 
|  | 
| @@ -1158,7 +1150,7 @@ MaybeHandle<String> StringReplaceGlobalRegExpWithFunction( | 
|  | 
| // TODO(jgruber): Convert result_array into a List<Handle<Object>> (or | 
| // similar) and adapt / remove FixedArrayBuilder. | 
| -  Handle<JSObject> last_match_info = isolate->regexp_last_match_info(); | 
| +  Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); | 
| Handle<FixedArray> result_array = factory->NewFixedArrayWithHoles(16); | 
|  | 
| Handle<Object> res; | 
| @@ -1175,8 +1167,7 @@ MaybeHandle<String> StringReplaceGlobalRegExpWithFunction( | 
| result_array = Handle<FixedArray>::cast(res); | 
| const int result_length = result_array->length(); | 
|  | 
| -  const int num_captures = | 
| -      RegExpUtils::GetLastMatchNumberOfCaptures(isolate, last_match_info) / 2; | 
| +  const int num_captures = last_match_info->NumberOfCaptureRegisters() / 2; | 
| if (num_captures == 1) { | 
| // If the number of captures is one then there are no explicit captures in | 
| // the regexp, just the implicit capture that captures the whole match.  In | 
| @@ -1309,7 +1300,7 @@ MaybeHandle<String> StringReplaceNonGlobalRegExpWithFunction( | 
| Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, | 
| Handle<Object> replace_obj) { | 
| Factory* factory = isolate->factory(); | 
| -  Handle<JSObject> last_match_info = isolate->regexp_last_match_info(); | 
| +  Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); | 
|  | 
| // TODO(jgruber): This is a pattern we could refactor. | 
| Handle<Object> match_indices_obj; | 
| @@ -1323,11 +1314,11 @@ MaybeHandle<String> StringReplaceNonGlobalRegExpWithFunction( | 
| return subject; | 
| } | 
|  | 
| -  Handle<JSObject> match_indices = Handle<JSObject>::cast(match_indices_obj); | 
| +  Handle<RegExpMatchInfo> match_indices = | 
| +      Handle<RegExpMatchInfo>::cast(match_indices_obj); | 
|  | 
| -  const int index = RegExpUtils::GetLastMatchCapture(isolate, match_indices, 0); | 
| -  const int end_of_match = | 
| -      RegExpUtils::GetLastMatchCapture(isolate, match_indices, 1); | 
| +  const int index = match_indices->Capture(0); | 
| +  const int end_of_match = match_indices->Capture(1); | 
|  | 
| IncrementalStringBuilder builder(isolate); | 
| builder.AppendString(factory->NewSubString(subject, 0, index)); | 
| @@ -1335,8 +1326,7 @@ MaybeHandle<String> StringReplaceNonGlobalRegExpWithFunction( | 
| // Compute the parameter list consisting of the match, captures, index, | 
| // and subject for the replace function invocation. | 
| // The number of captures plus one for the match. | 
| -  const int m = | 
| -      RegExpUtils::GetLastMatchNumberOfCaptures(isolate, match_indices) / 2; | 
| +  const int m = match_indices->NumberOfCaptureRegisters() / 2; | 
|  | 
| const int argc = m + 2; | 
| ScopedVector<Handle<Object>> argv(argc); | 
| @@ -1392,7 +1382,7 @@ MaybeHandle<String> RegExpReplace(Isolate* isolate, Handle<JSRegExp> regexp, | 
| Object::ToString(isolate, replace_obj), String); | 
| replace = String::Flatten(replace); | 
|  | 
| -    Handle<JSObject> last_match_info = isolate->regexp_last_match_info(); | 
| +    Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); | 
|  | 
| if (!global) { | 
| // Non-global regexp search, string replace. | 
| @@ -1408,25 +1398,16 @@ MaybeHandle<String> RegExpReplace(Isolate* isolate, Handle<JSRegExp> regexp, | 
| return string; | 
| } | 
|  | 
| -      auto match_indices = Handle<JSReceiver>::cast(match_indices_obj); | 
| - | 
| -      Handle<Object> start_index_obj = | 
| -          JSReceiver::GetElement(isolate, match_indices, | 
| -                                 RegExpImpl::kFirstCapture) | 
| -              .ToHandleChecked(); | 
| -      const int start_index = Handle<Smi>::cast(start_index_obj)->value(); | 
| +      auto match_indices = Handle<RegExpMatchInfo>::cast(match_indices_obj); | 
|  | 
| -      Handle<Object> end_index_obj = | 
| -          JSReceiver::GetElement(isolate, match_indices, | 
| -                                 RegExpImpl::kFirstCapture + 1) | 
| -              .ToHandleChecked(); | 
| -      const int end_index = Handle<Smi>::cast(end_index_obj)->value(); | 
| +      const int start_index = match_indices->Capture(0); | 
| +      const int end_index = match_indices->Capture(1); | 
|  | 
| IncrementalStringBuilder builder(isolate); | 
| builder.AppendString(factory->NewSubString(string, 0, start_index)); | 
|  | 
| if (replace->length() > 0) { | 
| -        MatchInfoBackedMatch m(isolate, string, last_match_info); | 
| +        MatchInfoBackedMatch m(isolate, string, match_indices); | 
| Handle<String> replacement; | 
| ASSIGN_RETURN_ON_EXCEPTION( | 
| isolate, replacement, String::GetSubstitution(isolate, &m, replace), | 
|  |