Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 6123008afacbb9cd32133dcbfbd6fadd8a20503c..48f966849765c9961c4bd9a056c34bb93842acd2 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -15406,6 +15406,160 @@ class StringSharedKey : public HashTableKey { |
}; |
+// static |
+MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, |
+ Handle<String> flags) { |
+ Isolate* isolate = pattern->GetIsolate(); |
+ Handle<JSFunction> constructor = isolate->regexp_function(); |
+ Handle<JSRegExp> regexp = |
+ Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor)); |
+ |
+ return JSRegExp::Initialize(regexp, pattern, flags); |
+} |
+ |
+ |
+static JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, |
+ bool* success) { |
+ uint32_t value = JSRegExp::NONE; |
+ int length = flags->length(); |
+ // A longer flags string cannot be valid. |
+ if (length > 5) return JSRegExp::Flags(0); |
+ for (int i = 0; i < length; i++) { |
+ uint32_t flag = JSRegExp::NONE; |
+ switch (flags->Get(i)) { |
+ case 'g': |
+ flag = JSRegExp::GLOBAL; |
+ break; |
+ case 'i': |
+ flag = JSRegExp::IGNORE_CASE; |
+ break; |
+ case 'm': |
+ flag = JSRegExp::MULTILINE; |
+ break; |
+ case 'u': |
+ if (!FLAG_harmony_unicode_regexps) return JSRegExp::Flags(0); |
+ flag = JSRegExp::UNICODE_ESCAPES; |
+ break; |
+ case 'y': |
+ if (!FLAG_harmony_regexps) return JSRegExp::Flags(0); |
+ flag = JSRegExp::STICKY; |
+ break; |
+ default: |
+ return JSRegExp::Flags(0); |
+ } |
+ // Duplicate flag. |
+ if (value & flag) return JSRegExp::Flags(0); |
+ value |= flag; |
+ } |
+ *success = true; |
+ return JSRegExp::Flags(value); |
+} |
+ |
+ |
+template <typename Char> |
+inline int CountRequiredEscapes(Handle<String> source) { |
+ DisallowHeapAllocation no_gc; |
+ int escapes = 0; |
+ Vector<const Char> src = source->GetCharVector<Char>(); |
+ for (int i = 0; i < src.length(); i++) { |
+ if (src[i] == '/' && (i == 0 || src[i - 1] != '\\')) escapes++; |
+ } |
+ return escapes; |
+} |
+ |
+ |
+template <typename Char, typename StringType> |
+inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source, |
+ Handle<StringType> result) { |
+ DisallowHeapAllocation no_gc; |
+ Vector<const Char> src = source->GetCharVector<Char>(); |
+ Vector<Char> dst(result->GetChars(), result->length()); |
+ int s = 0; |
+ int d = 0; |
+ while (s < src.length()) { |
+ if (src[s] == '/' && (s == 0 || src[s - 1] != '\\')) dst[d++] = '\\'; |
+ dst[d++] = src[s++]; |
+ } |
+ DCHECK_EQ(result->length(), d); |
+ return result; |
+} |
+ |
+ |
+MaybeHandle<String> EscapeRegExpSource(Isolate* isolate, |
+ Handle<String> source) { |
+ String::Flatten(source); |
+ if (source->length() == 0) return isolate->factory()->query_colon_string(); |
+ bool one_byte = source->IsOneByteRepresentationUnderneath(); |
+ int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source) |
+ : CountRequiredEscapes<uc16>(source); |
+ if (escapes == 0) return source; |
+ int length = source->length() + escapes; |
+ if (one_byte) { |
+ Handle<SeqOneByteString> result; |
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, result, |
+ isolate->factory()->NewRawOneByteString(length), |
+ String); |
+ return WriteEscapedRegExpSource<uint8_t>(source, result); |
+ } else { |
+ Handle<SeqTwoByteString> result; |
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, result, |
+ isolate->factory()->NewRawTwoByteString(length), |
+ String); |
+ return WriteEscapedRegExpSource<uc16>(source, result); |
+ } |
+} |
+ |
+ |
+// static |
+MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp, |
+ Handle<String> source, |
+ Handle<String> flags_string) { |
+ Isolate* isolate = regexp->GetIsolate(); |
+ Factory* factory = isolate->factory(); |
+ // If source is the empty string we set it to "(?:)" instead as |
+ // suggested by ECMA-262, 5th, section 15.10.4.1. |
+ if (source->length() == 0) source = factory->query_colon_string(); |
+ |
+ bool success = false; |
+ JSRegExp::Flags flags = RegExpFlagsFromString(flags_string, &success); |
+ if (!success) { |
+ THROW_NEW_ERROR( |
+ isolate, |
+ NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string), |
+ JSRegExp); |
+ } |
+ |
+ Handle<String> escaped_source; |
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source, |
+ EscapeRegExpSource(isolate, source), JSRegExp); |
+ |
+ regexp->set_source(*escaped_source); |
+ regexp->set_flags(Smi::FromInt(flags.value())); |
+ |
+ Map* map = regexp->map(); |
+ Object* constructor = map->GetConstructor(); |
+ if (constructor->IsJSFunction() && |
+ JSFunction::cast(constructor)->initial_map() == map) { |
+ // If we still have the original map, set in-object properties directly. |
+ regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, |
+ Smi::FromInt(0), SKIP_WRITE_BARRIER); |
+ } else { |
+ // Map has changed, so use generic, but slower, method. |
+ PropertyAttributes writable = |
+ static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); |
+ JSObject::SetOwnPropertyIgnoreAttributes( |
+ regexp, factory->last_index_string(), |
+ Handle<Smi>(Smi::FromInt(0), isolate), writable) |
+ .Check(); |
+ } |
+ |
+ RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags), |
+ JSRegExp); |
+ |
+ return regexp; |
+} |
+ |
+ |
// RegExpKey carries the source and flags of a regular expression as key. |
class RegExpKey : public HashTableKey { |
public: |