| Index: src/runtime/runtime-regexp.cc
|
| diff --git a/src/runtime/runtime-regexp.cc b/src/runtime/runtime-regexp.cc
|
| index 5846881f90ad5b68505a000753d8fd2f7324ce5f..d3212f464ff9839b13a8cb4ab107c8145561ecfa 100644
|
| --- a/src/runtime/runtime-regexp.cc
|
| +++ b/src/runtime/runtime-regexp.cc
|
| @@ -844,6 +844,60 @@ static JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags,
|
| }
|
|
|
|
|
| +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);
|
| + }
|
| +}
|
| +
|
| +
|
| RUNTIME_FUNCTION(Runtime_RegExpInitializeAndCompile) {
|
| HandleScope scope(isolate);
|
| DCHECK(args.length() == 3);
|
| @@ -865,6 +919,10 @@ RUNTIME_FUNCTION(Runtime_RegExpInitializeAndCompile) {
|
| isolate, NewSyntaxError("invalid_regexp_flags", args));
|
| }
|
|
|
| + Handle<String> escaped_source;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, escaped_source,
|
| + EscapeRegExpSource(isolate, source));
|
| +
|
| Handle<Object> global = factory->ToBoolean(flags.is_global());
|
| Handle<Object> ignore_case = factory->ToBoolean(flags.is_ignore_case());
|
| Handle<Object> multiline = factory->ToBoolean(flags.is_multiline());
|
| @@ -877,6 +935,7 @@ RUNTIME_FUNCTION(Runtime_RegExpInitializeAndCompile) {
|
| constructor->IsJSFunction() &&
|
| JSFunction::cast(constructor)->initial_map() == map) {
|
| // If we still have the original map, set in-object properties directly.
|
| + regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, *escaped_source);
|
| // Both true and false are immovable immortal objects so no need for write
|
| // barrier.
|
| regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, *global,
|
| @@ -898,6 +957,8 @@ RUNTIME_FUNCTION(Runtime_RegExpInitializeAndCompile) {
|
| PropertyAttributes writable =
|
| static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
|
| Handle<Object> zero(Smi::FromInt(0), isolate);
|
| + JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->source_string(),
|
| + escaped_source, final).Check();
|
| JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->global_string(),
|
| global, final).Check();
|
| JSObject::SetOwnPropertyIgnoreAttributes(
|
|
|