Index: src/runtime/runtime-regexp.cc |
diff --git a/src/runtime/runtime-regexp.cc b/src/runtime/runtime-regexp.cc |
index ccdbea4b96f67ae41aa880f7b3da9932200f364d..ae8564e6fe1a091cbce5cbaba3e778a9670500af 100644 |
--- a/src/runtime/runtime-regexp.cc |
+++ b/src/runtime/runtime-regexp.cc |
@@ -1269,6 +1269,223 @@ RUNTIME_FUNCTION(Runtime_StringReplaceNonGlobalRegExpWithFunction) { |
isolate, subject, regexp, replace)); |
} |
+namespace { |
+ |
+// ES##sec-speciesconstructor |
+// SpeciesConstructor ( O, defaultConstructor ) |
+MUST_USE_RESULT MaybeHandle<Object> SpeciesConstructor( |
+ Isolate* isolate, Handle<JSReceiver> recv, |
+ Handle<JSFunction> default_ctor) { |
+ Handle<Object> ctor_obj; |
+ ASSIGN_RETURN_ON_EXCEPTION( |
+ isolate, ctor_obj, |
+ JSObject::GetProperty(recv, isolate->factory()->constructor_string()), |
+ Object); |
+ |
+ if (ctor_obj->IsUndefined(isolate)) return default_ctor; |
+ |
+ if (!ctor_obj->IsJSReceiver()) { |
+ THROW_NEW_ERROR(isolate, |
+ NewTypeError(MessageTemplate::kConstructorNotReceiver), |
+ Object); |
+ } |
+ |
+ Handle<JSReceiver> ctor = Handle<JSReceiver>::cast(ctor_obj); |
+ |
+ Handle<Object> species; |
+ ASSIGN_RETURN_ON_EXCEPTION( |
+ isolate, species, |
+ JSObject::GetProperty(ctor, isolate->factory()->species_symbol()), |
+ Object); |
+ |
+ if (species->IsNull(isolate) || species->IsUndefined(isolate)) { |
+ return default_ctor; |
+ } |
+ |
+ if (species->IsConstructor()) return species; |
+ |
+ THROW_NEW_ERROR( |
+ isolate, NewTypeError(MessageTemplate::kSpeciesNotConstructor), Object); |
+} |
+ |
+MUST_USE_RESULT MaybeHandle<Object> ToUint32(Isolate* isolate, |
+ Handle<Object> object, |
+ uint32_t* out) { |
+ if (object->IsUndefined(isolate)) { |
+ *out = kMaxUInt32; |
+ return object; |
+ } |
+ |
+ Handle<Object> number; |
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, number, Object::ToNumber(object), Object); |
+ *out = NumberToUint32(*number); |
+ return object; |
+} |
+ |
+Handle<JSArray> NewJSArrayWithElements(Isolate* isolate, |
+ Handle<FixedArray> elems, |
+ int num_elems) { |
+ elems->Shrink(num_elems); |
+ return isolate->factory()->NewJSArrayWithElements(elems); |
+} |
+ |
+} // namespace |
+ |
+// Slow path for: |
+// ES#sec-regexp.prototype-@@replace |
+// RegExp.prototype [ @@split ] ( string, limit ) |
+RUNTIME_FUNCTION(Runtime_RegExpSplit) { |
+ HandleScope scope(isolate); |
+ DCHECK(args.length() == 3); |
+ |
+ DCHECK(args[1]->IsString()); |
+ |
+ CONVERT_ARG_HANDLE_CHECKED(JSReceiver, recv, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(String, string, 1); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, limit_obj, 2); |
+ |
+ Factory* factory = isolate->factory(); |
+ |
+ Handle<JSFunction> regexp_fun = isolate->regexp_function(); |
+ Handle<Object> ctor; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, ctor, SpeciesConstructor(isolate, recv, regexp_fun)); |
+ |
+ Handle<Object> flags_obj; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, flags_obj, JSObject::GetProperty(recv, factory->flags_string())); |
+ |
+ Handle<String> flags; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, flags, |
+ Object::ToString(isolate, flags_obj)); |
+ |
+ Handle<String> u_str = factory->LookupSingleCharacterStringFromCode('u'); |
+ const bool unicode = (String::IndexOf(isolate, flags, u_str, 0) >= 0); |
+ |
+ Handle<String> y_str = factory->LookupSingleCharacterStringFromCode('y'); |
+ const bool sticky = (String::IndexOf(isolate, flags, y_str, 0) >= 0); |
+ |
+ Handle<String> new_flags = flags; |
+ if (!sticky) { |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, new_flags, |
+ factory->NewConsString(flags, y_str)); |
+ } |
+ |
+ Handle<JSReceiver> splitter; |
+ { |
+ const int argc = 2; |
+ |
+ ScopedVector<Handle<Object>> argv(argc); |
+ argv[0] = recv; |
+ argv[1] = new_flags; |
+ |
+ Handle<JSFunction> ctor_fun = Handle<JSFunction>::cast(ctor); |
+ Handle<Object> splitter_obj; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, splitter_obj, Execution::New(ctor_fun, argc, argv.start())); |
+ |
+ splitter = Handle<JSReceiver>::cast(splitter_obj); |
+ } |
+ |
+ uint32_t limit; |
+ RETURN_FAILURE_ON_EXCEPTION(isolate, ToUint32(isolate, limit_obj, &limit)); |
+ |
+ const int length = string->length(); |
+ |
+ if (limit == 0) return *factory->NewJSArray(0); |
+ |
+ if (length == 0) { |
+ Handle<Object> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, result, RegExpUtils::RegExpExec(isolate, splitter, string, |
+ factory->undefined_value())); |
+ |
+ if (!result->IsNull(isolate)) return *factory->NewJSArray(0); |
+ |
+ Handle<FixedArray> elems = factory->NewUninitializedFixedArray(1); |
+ elems->set(0, *string); |
+ return *factory->NewJSArrayWithElements(elems); |
+ } |
+ |
+ static const int kInitialArraySize = 8; |
+ Handle<FixedArray> elems = factory->NewFixedArrayWithHoles(kInitialArraySize); |
+ int num_elems = 0; |
+ |
+ int string_index = 0; |
+ int prev_string_index = 0; |
+ while (string_index < length) { |
+ RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, RegExpUtils::SetLastIndex(isolate, splitter, string_index)); |
+ |
+ Handle<Object> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, result, RegExpUtils::RegExpExec(isolate, splitter, string, |
+ factory->undefined_value())); |
+ |
+ if (result->IsNull(isolate)) { |
+ string_index = RegExpUtils::AdvanceStringIndex(isolate, string, |
+ string_index, unicode); |
+ continue; |
+ } |
+ |
+ Handle<Object> last_index_obj; |
+ 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)); |
+ const int last_index = Handle<Smi>::cast(last_index_obj)->value(); |
+ |
+ const int end = std::min(last_index, length); |
+ if (end == prev_string_index) { |
+ string_index = RegExpUtils::AdvanceStringIndex(isolate, string, |
+ string_index, unicode); |
+ continue; |
+ } |
+ |
+ { |
+ Handle<String> substr = |
+ factory->NewSubString(string, prev_string_index, string_index); |
+ elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
+ if (static_cast<uint32_t>(num_elems) == limit) { |
+ return *NewJSArrayWithElements(isolate, elems, num_elems); |
+ } |
+ } |
+ |
+ prev_string_index = end; |
+ |
+ Handle<Object> num_captures_obj; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, num_captures_obj, |
+ Object::GetProperty(result, isolate->factory()->length_string())); |
+ |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, num_captures_obj, Object::ToLength(isolate, num_captures_obj)); |
+ const int num_captures = |
+ std::max(Handle<Smi>::cast(num_captures_obj)->value(), 0); |
+ |
+ for (int i = 1; i < num_captures; i++) { |
+ Handle<Object> capture; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, capture, Object::GetElement(isolate, result, i)); |
+ elems = FixedArray::SetAndGrow(elems, num_elems++, capture); |
+ if (static_cast<uint32_t>(num_elems) == limit) { |
+ return *NewJSArrayWithElements(isolate, elems, num_elems); |
+ } |
+ } |
+ |
+ string_index = prev_string_index; |
+ } |
+ |
+ { |
+ Handle<String> substr = |
+ factory->NewSubString(string, prev_string_index, length); |
+ elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
+ } |
+ |
+ return *NewJSArrayWithElements(isolate, elems, num_elems); |
+} |
+ |
// Slow path for: |
// ES#sec-regexp.prototype-@@replace |
// RegExp.prototype [ @@replace ] ( string, replaceValue ) |