| 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:
|
|
|