| Index: src/builtins/builtins-regexp.cc | 
| diff --git a/src/builtins/builtins-regexp.cc b/src/builtins/builtins-regexp.cc | 
| index 05a3cda06d424ff10fb0646bc3c81ca4d7f4940e..17978a33f6a0088b2912f1e462b9c2022d556e13 100644 | 
| --- a/src/builtins/builtins-regexp.cc | 
| +++ b/src/builtins/builtins-regexp.cc | 
| @@ -7,6 +7,7 @@ | 
|  | 
| #include "src/code-factory.h" | 
| #include "src/regexp/jsregexp.h" | 
| +#include "src/regexp/regexp-utils.h" | 
| #include "src/string-builder.h" | 
|  | 
| namespace v8 { | 
| @@ -79,7 +80,8 @@ BUILTIN(RegExpConstructor) { | 
|  | 
| bool pattern_is_regexp; | 
| { | 
| -    Maybe<bool> maybe_pattern_is_regexp = Object::IsRegExp(isolate, pattern); | 
| +    Maybe<bool> maybe_pattern_is_regexp = | 
| +        RegExpUtils::IsRegExp(isolate, pattern); | 
| if (maybe_pattern_is_regexp.IsNothing()) { | 
| DCHECK(isolate->has_pending_exception()); | 
| return isolate->heap()->exception(); | 
| @@ -817,73 +819,15 @@ void Builtins::Generate_RegExpPrototypeUnicodeGetter(CodeStubAssembler* a) { | 
| "RegExp.prototype.unicode"); | 
| } | 
|  | 
| -namespace { | 
| - | 
| -// Constants for accessing RegExpLastMatchInfo. | 
| -// TODO(jgruber): Currently, RegExpLastMatchInfo is still a JSObject maintained | 
| -// and accessed from JS. This is a crutch until all RegExp logic is ported, then | 
| -// we can take care of RegExpLastMatchInfo. | 
| - | 
| -Handle<Object> GetLastMatchField(Isolate* isolate, int index) { | 
| -  Handle<JSObject> last_match_info = isolate->regexp_last_match_info(); | 
| -  return JSReceiver::GetElement(isolate, last_match_info, index) | 
| -      .ToHandleChecked(); | 
| -} | 
| - | 
| -void SetLastMatchField(Isolate* isolate, int index, Handle<Object> value) { | 
| -  Handle<JSObject> last_match_info = isolate->regexp_last_match_info(); | 
| -  JSReceiver::SetElement(isolate, last_match_info, index, value, SLOPPY) | 
| -      .ToHandleChecked(); | 
| -} | 
| - | 
| -int GetLastMatchNumberOfCaptures(Isolate* isolate) { | 
| -  Handle<Object> obj = | 
| -      GetLastMatchField(isolate, RegExpImpl::kLastCaptureCount); | 
| -  return Handle<Smi>::cast(obj)->value(); | 
| -} | 
| - | 
| -Handle<String> GetLastMatchSubject(Isolate* isolate) { | 
| -  return Handle<String>::cast( | 
| -      GetLastMatchField(isolate, RegExpImpl::kLastSubject)); | 
| -} | 
| - | 
| -Handle<Object> GetLastMatchInput(Isolate* isolate) { | 
| -  return GetLastMatchField(isolate, RegExpImpl::kLastInput); | 
| -} | 
| - | 
| -int GetLastMatchCapture(Isolate* isolate, int i) { | 
| -  Handle<Object> obj = | 
| -      GetLastMatchField(isolate, RegExpImpl::kFirstCapture + i); | 
| -  return Handle<Smi>::cast(obj)->value(); | 
| -} | 
| - | 
| -Object* GenericCaptureGetter(Isolate* isolate, int capture) { | 
| -  HandleScope scope(isolate); | 
| -  const int index = capture * 2; | 
| -  if (index >= GetLastMatchNumberOfCaptures(isolate)) { | 
| -    return isolate->heap()->empty_string(); | 
| -  } | 
| - | 
| -  const int match_start = GetLastMatchCapture(isolate, index); | 
| -  const int match_end = GetLastMatchCapture(isolate, index + 1); | 
| -  if (match_start == -1 || match_end == -1) { | 
| -    return isolate->heap()->empty_string(); | 
| -  } | 
| - | 
| -  Handle<String> last_subject = GetLastMatchSubject(isolate); | 
| -  return *isolate->factory()->NewSubString(last_subject, match_start, | 
| -                                           match_end); | 
| -} | 
| - | 
| -}  // namespace | 
|  | 
| // The properties $1..$9 are the first nine capturing substrings of the last | 
| // successful match, or ''.  The function RegExpMakeCaptureGetter will be | 
| // called with indices from 1 to 9. | 
| -#define DEFINE_CAPTURE_GETTER(i)             \ | 
| -  BUILTIN(RegExpCapture##i##Getter) {        \ | 
| -    HandleScope scope(isolate);              \ | 
| -    return GenericCaptureGetter(isolate, i); \ | 
| +#define DEFINE_CAPTURE_GETTER(i)                        \ | 
| +  BUILTIN(RegExpCapture##i##Getter) {                   \ | 
| +    HandleScope scope(isolate);                         \ | 
| +    return *RegExpUtils::GenericCaptureGetter(          \ | 
| +        isolate, isolate->regexp_last_match_info(), i); \ | 
| } | 
| DEFINE_CAPTURE_GETTER(1) | 
| DEFINE_CAPTURE_GETTER(2) | 
| @@ -902,7 +846,8 @@ DEFINE_CAPTURE_GETTER(9) | 
|  | 
| BUILTIN(RegExpInputGetter) { | 
| HandleScope scope(isolate); | 
| -  Handle<Object> obj = GetLastMatchInput(isolate); | 
| +  Handle<Object> obj = RegExpUtils::GetLastMatchInput( | 
| +      isolate, isolate->regexp_last_match_info()); | 
| return obj->IsUndefined(isolate) ? isolate->heap()->empty_string() | 
| : String::cast(*obj); | 
| } | 
| @@ -913,7 +858,8 @@ BUILTIN(RegExpInputSetter) { | 
| Handle<String> str; | 
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str, | 
| Object::ToString(isolate, value)); | 
| -  SetLastMatchField(isolate, RegExpImpl::kLastInput, str); | 
| +  RegExpUtils::SetLastMatchField(isolate, isolate->regexp_last_match_info(), | 
| +                                 RegExpImpl::kLastInput, str); | 
| return isolate->heap()->undefined_value(); | 
| } | 
|  | 
| @@ -923,12 +869,15 @@ BUILTIN(RegExpInputSetter) { | 
| // of the last successful match. | 
| BUILTIN(RegExpLastMatchGetter) { | 
| HandleScope scope(isolate); | 
| -  return GenericCaptureGetter(isolate, 0); | 
| +  return *RegExpUtils::GenericCaptureGetter( | 
| +      isolate, isolate->regexp_last_match_info(), 0); | 
| } | 
|  | 
| BUILTIN(RegExpLastParenGetter) { | 
| HandleScope scope(isolate); | 
| -  const int length = GetLastMatchNumberOfCaptures(isolate); | 
| +  Handle<JSObject> match_info = isolate->regexp_last_match_info(); | 
| +  const int length = | 
| +      RegExpUtils::GetLastMatchNumberOfCaptures(isolate, match_info); | 
| if (length <= 2) return isolate->heap()->empty_string();  // No captures. | 
|  | 
| DCHECK_EQ(0, length % 2); | 
| @@ -937,83 +886,30 @@ BUILTIN(RegExpLastParenGetter) { | 
| // We match the SpiderMonkey behavior: return the substring defined by the | 
| // last pair (after the first pair) of elements of the capture array even if | 
| // it is empty. | 
| -  return GenericCaptureGetter(isolate, last_capture); | 
| +  return *RegExpUtils::GenericCaptureGetter(isolate, match_info, last_capture); | 
| } | 
|  | 
| BUILTIN(RegExpLeftContextGetter) { | 
| HandleScope scope(isolate); | 
| -  const int start_index = GetLastMatchCapture(isolate, 0); | 
| -  Handle<String> last_subject = GetLastMatchSubject(isolate); | 
| +  Handle<JSObject> match_info = isolate->regexp_last_match_info(); | 
| +  const int start_index = | 
| +      RegExpUtils::GetLastMatchCapture(isolate, match_info, 0); | 
| +  Handle<String> last_subject = | 
| +      RegExpUtils::GetLastMatchSubject(isolate, match_info); | 
| return *isolate->factory()->NewSubString(last_subject, 0, start_index); | 
| } | 
|  | 
| BUILTIN(RegExpRightContextGetter) { | 
| HandleScope scope(isolate); | 
| -  const int start_index = GetLastMatchCapture(isolate, 1); | 
| -  Handle<String> last_subject = GetLastMatchSubject(isolate); | 
| +  Handle<JSObject> match_info = isolate->regexp_last_match_info(); | 
| +  const int start_index = | 
| +      RegExpUtils::GetLastMatchCapture(isolate, match_info, 1); | 
| +  Handle<String> last_subject = | 
| +      RegExpUtils::GetLastMatchSubject(isolate, match_info); | 
| const int len = last_subject->length(); | 
| return *isolate->factory()->NewSubString(last_subject, start_index, len); | 
| } | 
|  | 
| -namespace { | 
| - | 
| -V8_INLINE bool HasInitialRegExpMap(Isolate* isolate, Handle<JSReceiver> recv) { | 
| -  return recv->map() == isolate->regexp_function()->initial_map(); | 
| -} | 
| - | 
| -}  // namespace | 
| - | 
| -// ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) | 
| -// Also takes an optional exec method in case our caller | 
| -// has already fetched exec. | 
| -MaybeHandle<Object> RegExpExec(Isolate* isolate, Handle<JSReceiver> regexp, | 
| -                               Handle<String> string, Handle<Object> exec) { | 
| -  if (exec->IsUndefined(isolate)) { | 
| -    ASSIGN_RETURN_ON_EXCEPTION( | 
| -        isolate, exec, | 
| -        Object::GetProperty( | 
| -            regexp, isolate->factory()->NewStringFromAsciiChecked("exec")), | 
| -        Object); | 
| -  } | 
| - | 
| -  if (exec->IsCallable()) { | 
| -    const int argc = 1; | 
| -    ScopedVector<Handle<Object>> argv(argc); | 
| -    argv[0] = string; | 
| - | 
| -    Handle<Object> result; | 
| -    ASSIGN_RETURN_ON_EXCEPTION( | 
| -        isolate, result, | 
| -        Execution::Call(isolate, exec, regexp, argc, argv.start()), Object); | 
| - | 
| -    if (!result->IsJSReceiver() && !result->IsNull(isolate)) { | 
| -      THROW_NEW_ERROR(isolate, | 
| -                      NewTypeError(MessageTemplate::kInvalidRegExpExecResult), | 
| -                      Object); | 
| -    } | 
| -    return result; | 
| -  } | 
| - | 
| -  if (!regexp->IsJSRegExp()) { | 
| -    THROW_NEW_ERROR(isolate, | 
| -                    NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, | 
| -                                 isolate->factory()->NewStringFromAsciiChecked( | 
| -                                     "RegExp.prototype.exec"), | 
| -                                 regexp), | 
| -                    Object); | 
| -  } | 
| - | 
| -  { | 
| -    Handle<JSFunction> regexp_exec = isolate->regexp_exec_function(); | 
| - | 
| -    const int argc = 1; | 
| -    ScopedVector<Handle<Object>> argv(argc); | 
| -    argv[0] = string; | 
| - | 
| -    return Execution::Call(isolate, exec, regexp_exec, argc, argv.start()); | 
| -  } | 
| -} | 
| - | 
| // ES#sec-regexp.prototype.test | 
| // RegExp.prototype.test ( S ) | 
| BUILTIN(RegExpPrototypeTest) { | 
| @@ -1029,71 +925,12 @@ BUILTIN(RegExpPrototypeTest) { | 
| Handle<Object> result; | 
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
| isolate, result, | 
| -      RegExpExec(isolate, recv, string, isolate->factory()->undefined_value())); | 
| +      RegExpUtils::RegExpExec(isolate, recv, string, | 
| +                              isolate->factory()->undefined_value())); | 
|  | 
| return isolate->heap()->ToBoolean(!result->IsNull(isolate)); | 
| } | 
|  | 
| -namespace { | 
| - | 
| -// ES#sec-advancestringindex | 
| -// AdvanceStringIndex ( S, index, unicode ) | 
| -int AdvanceStringIndex(Isolate* isolate, Handle<String> string, int index, | 
| -                       bool unicode) { | 
| -  int increment = 1; | 
| - | 
| -  if (unicode && index < string->length()) { | 
| -    const uint16_t first = string->Get(index); | 
| -    if (first >= 0xD800 && first <= 0xDBFF && string->length() > index + 1) { | 
| -      const uint16_t second = string->Get(index + 1); | 
| -      if (second >= 0xDC00 && second <= 0xDFFF) { | 
| -        increment = 2; | 
| -      } | 
| -    } | 
| -  } | 
| - | 
| -  return increment; | 
| -} | 
| - | 
| -MaybeHandle<Object> SetLastIndex(Isolate* isolate, Handle<JSReceiver> recv, | 
| -                                 int value) { | 
| -  if (HasInitialRegExpMap(isolate, recv)) { | 
| -    JSRegExp::cast(*recv)->SetLastIndex(value); | 
| -    return recv; | 
| -  } else { | 
| -    return Object::SetProperty(recv, isolate->factory()->lastIndex_string(), | 
| -                               handle(Smi::FromInt(value), isolate), STRICT); | 
| -  } | 
| -} | 
| - | 
| -MaybeHandle<Object> GetLastIndex(Isolate* isolate, Handle<JSReceiver> recv) { | 
| -  if (HasInitialRegExpMap(isolate, recv)) { | 
| -    return handle(JSRegExp::cast(*recv)->LastIndex(), isolate); | 
| -  } else { | 
| -    return Object::GetProperty(recv, isolate->factory()->lastIndex_string()); | 
| -  } | 
| -} | 
| - | 
| -MaybeHandle<Object> SetAdvancedStringIndex(Isolate* isolate, | 
| -                                           Handle<JSReceiver> regexp, | 
| -                                           Handle<String> string, | 
| -                                           bool unicode) { | 
| -  Handle<Object> last_index_obj; | 
| -  ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj, | 
| -                             GetLastIndex(isolate, regexp), Object); | 
| - | 
| -  ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj, | 
| -                             Object::ToLength(isolate, last_index_obj), Object); | 
| - | 
| -  const int last_index = Handle<Smi>::cast(last_index_obj)->value(); | 
| -  const int new_last_index = | 
| -      last_index + AdvanceStringIndex(isolate, string, last_index, unicode); | 
| - | 
| -  return SetLastIndex(isolate, regexp, new_last_index); | 
| -} | 
| - | 
| -}  // namespace | 
| - | 
| // ES#sec-regexp.prototype-@@match | 
| // RegExp.prototype [ @@match ] ( string ) | 
| BUILTIN(RegExpPrototypeMatch) { | 
| @@ -1113,9 +950,10 @@ BUILTIN(RegExpPrototypeMatch) { | 
| const bool global = global_obj->BooleanValue(); | 
|  | 
| if (!global) { | 
| -    RETURN_RESULT_OR_FAILURE(isolate, | 
| -                             RegExpExec(isolate, recv, string, | 
| -                                        isolate->factory()->undefined_value())); | 
| +    RETURN_RESULT_OR_FAILURE( | 
| +        isolate, | 
| +        RegExpUtils::RegExpExec(isolate, recv, string, | 
| +                                isolate->factory()->undefined_value())); | 
| } | 
|  | 
| Handle<Object> unicode_obj; | 
| @@ -1124,7 +962,8 @@ BUILTIN(RegExpPrototypeMatch) { | 
| JSReceiver::GetProperty(recv, isolate->factory()->unicode_string())); | 
| const bool unicode = unicode_obj->BooleanValue(); | 
|  | 
| -  RETURN_FAILURE_ON_EXCEPTION(isolate, SetLastIndex(isolate, recv, 0)); | 
| +  RETURN_FAILURE_ON_EXCEPTION(isolate, | 
| +                              RegExpUtils::SetLastIndex(isolate, recv, 0)); | 
|  | 
| static const int kInitialArraySize = 8; | 
| Handle<FixedArray> elems = | 
| @@ -1134,8 +973,9 @@ BUILTIN(RegExpPrototypeMatch) { | 
| for (;; n++) { | 
| Handle<Object> result; | 
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
| -        isolate, result, RegExpExec(isolate, recv, string, | 
| -                                    isolate->factory()->undefined_value())); | 
| +        isolate, result, | 
| +        RegExpUtils::RegExpExec(isolate, recv, string, | 
| +                                isolate->factory()->undefined_value())); | 
|  | 
| if (result->IsNull(isolate)) { | 
| if (n == 0) return isolate->heap()->null_value(); | 
| @@ -1153,8 +993,8 @@ BUILTIN(RegExpPrototypeMatch) { | 
| elems = FixedArray::SetAndGrow(elems, n, match); | 
|  | 
| if (match->length() == 0) { | 
| -      RETURN_FAILURE_ON_EXCEPTION( | 
| -          isolate, SetAdvancedStringIndex(isolate, recv, string, unicode)); | 
| +      RETURN_FAILURE_ON_EXCEPTION(isolate, RegExpUtils::SetAdvancedStringIndex( | 
| +                                               isolate, recv, string, unicode)); | 
| } | 
| } | 
|  | 
| @@ -1176,21 +1016,23 @@ BUILTIN(RegExpPrototypeSearch) { | 
|  | 
| Handle<Object> previous_last_index_obj; | 
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, previous_last_index_obj, | 
| -                                     GetLastIndex(isolate, recv)); | 
| +                                     RegExpUtils::GetLastIndex(isolate, recv)); | 
|  | 
| if (!previous_last_index_obj->IsSmi() || | 
| Smi::cast(*previous_last_index_obj)->value() != 0) { | 
| -    RETURN_FAILURE_ON_EXCEPTION(isolate, SetLastIndex(isolate, recv, 0)); | 
| +    RETURN_FAILURE_ON_EXCEPTION(isolate, | 
| +                                RegExpUtils::SetLastIndex(isolate, recv, 0)); | 
| } | 
|  | 
| Handle<Object> result; | 
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
| isolate, result, | 
| -      RegExpExec(isolate, recv, string, isolate->factory()->undefined_value())); | 
| +      RegExpUtils::RegExpExec(isolate, recv, string, | 
| +                              isolate->factory()->undefined_value())); | 
|  | 
| Handle<Object> current_last_index_obj; | 
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, current_last_index_obj, | 
| -                                     GetLastIndex(isolate, recv)); | 
| +                                     RegExpUtils::GetLastIndex(isolate, recv)); | 
|  | 
| Maybe<bool> is_last_index_unchanged = | 
| Object::Equals(current_last_index_obj, previous_last_index_obj); | 
| @@ -1198,8 +1040,9 @@ BUILTIN(RegExpPrototypeSearch) { | 
| if (!is_last_index_unchanged.FromJust()) { | 
| if (previous_last_index_obj->IsSmi()) { | 
| RETURN_FAILURE_ON_EXCEPTION( | 
| -          isolate, SetLastIndex(isolate, recv, | 
| -                                Smi::cast(*previous_last_index_obj)->value())); | 
| +          isolate, | 
| +          RegExpUtils::SetLastIndex( | 
| +              isolate, recv, Smi::cast(*previous_last_index_obj)->value())); | 
| } else { | 
| RETURN_FAILURE_ON_EXCEPTION( | 
| isolate, | 
| @@ -1414,15 +1257,6 @@ MaybeHandle<Object> SpeciesConstructor(Isolate* isolate, | 
| isolate, NewTypeError(MessageTemplate::kSpeciesNotConstructor), Object); | 
| } | 
|  | 
| -bool IsBuiltinExec(Handle<Object> exec) { | 
| -  if (!exec->IsJSFunction()) return false; | 
| - | 
| -  Code* code = Handle<JSFunction>::cast(exec)->code(); | 
| -  if (code == nullptr) return false; | 
| - | 
| -  return (code->builtin_index() == Builtins::kRegExpPrototypeExec); | 
| -} | 
| - | 
| }  // namespace | 
|  | 
| // ES#sec-regexp.prototype-@@split | 
| @@ -1450,7 +1284,7 @@ BUILTIN(RegExpPrototypeSplit) { | 
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
| isolate, exec, JSObject::GetProperty( | 
| recv, factory->NewStringFromAsciiChecked("exec"))); | 
| -    if (IsBuiltinExec(exec)) { | 
| +    if (RegExpUtils::IsBuiltinExec(exec)) { | 
| RETURN_RESULT_OR_FAILURE( | 
| isolate, RegExpSplit(isolate, Handle<JSRegExp>::cast(recv), string, | 
| limit_obj)); | 
| @@ -1503,8 +1337,8 @@ BUILTIN(RegExpPrototypeSplit) { | 
| if (length == 0) { | 
| Handle<Object> result; | 
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
| -        isolate, result, | 
| -        RegExpExec(isolate, splitter, string, factory->undefined_value())); | 
| +        isolate, result, RegExpUtils::RegExpExec(isolate, splitter, string, | 
| +                                                 factory->undefined_value())); | 
|  | 
| if (!result->IsNull(isolate)) return *factory->NewJSArray(0); | 
|  | 
| @@ -1521,24 +1355,24 @@ BUILTIN(RegExpPrototypeSplit) { | 
| int string_index = 0; | 
| int prev_string_index = 0; | 
| while (string_index < length) { | 
| -    RETURN_FAILURE_ON_EXCEPTION(isolate, | 
| -                                SetLastIndex(isolate, splitter, string_index)); | 
| +    RETURN_FAILURE_ON_EXCEPTION( | 
| +        isolate, RegExpUtils::SetLastIndex(isolate, splitter, string_index)); | 
|  | 
| Handle<Object> result; | 
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
| -        isolate, result, | 
| -        RegExpExec(isolate, splitter, string, factory->undefined_value())); | 
| +        isolate, result, RegExpUtils::RegExpExec(isolate, splitter, string, | 
| +                                                 factory->undefined_value())); | 
|  | 
| if (result->IsNull(isolate)) { | 
| -      string_index += | 
| -          AdvanceStringIndex(isolate, string, string_index, unicode); | 
| +      string_index += RegExpUtils::AdvanceStringIndex(isolate, string, | 
| +                                                      string_index, unicode); | 
| continue; | 
| } | 
|  | 
| // TODO(jgruber): Extract toLength of some property into function. | 
| Handle<Object> last_index_obj; | 
| -    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, last_index_obj, | 
| -                                       GetLastIndex(isolate, splitter)); | 
| +    ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
| +        isolate, last_index_obj, RegExpUtils::GetLastIndex(isolate, splitter)); | 
|  | 
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
| isolate, last_index_obj, Object::ToLength(isolate, last_index_obj)); | 
| @@ -1546,8 +1380,8 @@ BUILTIN(RegExpPrototypeSplit) { | 
|  | 
| const int end = std::min(last_index, length); | 
| if (end == prev_string_index) { | 
| -      string_index += | 
| -          AdvanceStringIndex(isolate, string, string_index, unicode); | 
| +      string_index += RegExpUtils::AdvanceStringIndex(isolate, string, | 
| +                                                      string_index, unicode); | 
| continue; | 
| } | 
|  | 
|  |