Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(453)

Side by Side Diff: src/runtime/runtime-regexp.cc

Issue 1070093002: Eagerly escape RegExp.source. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/objects.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/v8.h" 5 #include "src/v8.h"
6 6
7 #include "src/arguments.h" 7 #include "src/arguments.h"
8 #include "src/jsregexp-inl.h" 8 #include "src/jsregexp-inl.h"
9 #include "src/jsregexp.h" 9 #include "src/jsregexp.h"
10 #include "src/runtime/runtime-utils.h" 10 #include "src/runtime/runtime-utils.h"
(...skipping 826 matching lines...) Expand 10 before | Expand all | Expand 10 after
837 } 837 }
838 // Duplicate flag. 838 // Duplicate flag.
839 if (value & flag) return JSRegExp::Flags(0); 839 if (value & flag) return JSRegExp::Flags(0);
840 value |= flag; 840 value |= flag;
841 } 841 }
842 *success = true; 842 *success = true;
843 return JSRegExp::Flags(value); 843 return JSRegExp::Flags(value);
844 } 844 }
845 845
846 846
847 template <typename Char>
848 inline int CountRequiredEscapes(Handle<String> source) {
849 DisallowHeapAllocation no_gc;
850 int escapes = 0;
851 Vector<const Char> src = source->GetCharVector<Char>();
852 for (int i = 0; i < src.length(); i++) {
853 if (src[i] == '/' && (i == 0 || src[i - 1] != '\\')) escapes++;
854 }
855 return escapes;
856 }
857
858
859 template <typename Char, typename StringType>
860 inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
861 Handle<StringType> result) {
862 DisallowHeapAllocation no_gc;
863 Vector<const Char> src = source->GetCharVector<Char>();
864 Vector<Char> dst(result->GetChars(), result->length());
865 int s = 0;
866 int d = 0;
867 while (s < src.length()) {
868 if (src[s] == '/' && (s == 0 || src[s - 1] != '\\')) dst[d++] = '\\';
869 dst[d++] = src[s++];
870 }
871 DCHECK_EQ(result->length(), d);
872 return result;
873 }
874
875
876 MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
877 Handle<String> source) {
878 String::Flatten(source);
879 if (source->length() == 0) return isolate->factory()->query_colon_string();
880 bool one_byte = source->IsOneByteRepresentationUnderneath();
881 int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
882 : CountRequiredEscapes<uc16>(source);
883 if (escapes == 0) return source;
884 int length = source->length() + escapes;
885 if (one_byte) {
886 Handle<SeqOneByteString> result;
887 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
888 isolate->factory()->NewRawOneByteString(length),
889 String);
890 return WriteEscapedRegExpSource<uint8_t>(source, result);
891 } else {
892 Handle<SeqTwoByteString> result;
893 ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
894 isolate->factory()->NewRawTwoByteString(length),
895 String);
896 return WriteEscapedRegExpSource<uc16>(source, result);
897 }
898 }
899
900
847 RUNTIME_FUNCTION(Runtime_RegExpInitializeAndCompile) { 901 RUNTIME_FUNCTION(Runtime_RegExpInitializeAndCompile) {
848 HandleScope scope(isolate); 902 HandleScope scope(isolate);
849 DCHECK(args.length() == 3); 903 DCHECK(args.length() == 3);
850 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); 904 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
851 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 905 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
852 CONVERT_ARG_HANDLE_CHECKED(String, flags_string, 2); 906 CONVERT_ARG_HANDLE_CHECKED(String, flags_string, 2);
853 Factory* factory = isolate->factory(); 907 Factory* factory = isolate->factory();
854 // If source is the empty string we set it to "(?:)" instead as 908 // If source is the empty string we set it to "(?:)" instead as
855 // suggested by ECMA-262, 5th, section 15.10.4.1. 909 // suggested by ECMA-262, 5th, section 15.10.4.1.
856 if (source->length() == 0) source = factory->query_colon_string(); 910 if (source->length() == 0) source = factory->query_colon_string();
857 911
858 bool success = false; 912 bool success = false;
859 JSRegExp::Flags flags = RegExpFlagsFromString(flags_string, &success); 913 JSRegExp::Flags flags = RegExpFlagsFromString(flags_string, &success);
860 if (!success) { 914 if (!success) {
861 Handle<FixedArray> element = factory->NewFixedArray(1); 915 Handle<FixedArray> element = factory->NewFixedArray(1);
862 element->set(0, *flags_string); 916 element->set(0, *flags_string);
863 Handle<JSArray> args = factory->NewJSArrayWithElements(element); 917 Handle<JSArray> args = factory->NewJSArrayWithElements(element);
864 THROW_NEW_ERROR_RETURN_FAILURE( 918 THROW_NEW_ERROR_RETURN_FAILURE(
865 isolate, NewSyntaxError("invalid_regexp_flags", args)); 919 isolate, NewSyntaxError("invalid_regexp_flags", args));
866 } 920 }
867 921
922 Handle<String> escaped_source;
923 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, escaped_source,
924 EscapeRegExpSource(isolate, source));
925
868 Handle<Object> global = factory->ToBoolean(flags.is_global()); 926 Handle<Object> global = factory->ToBoolean(flags.is_global());
869 Handle<Object> ignore_case = factory->ToBoolean(flags.is_ignore_case()); 927 Handle<Object> ignore_case = factory->ToBoolean(flags.is_ignore_case());
870 Handle<Object> multiline = factory->ToBoolean(flags.is_multiline()); 928 Handle<Object> multiline = factory->ToBoolean(flags.is_multiline());
871 Handle<Object> sticky = factory->ToBoolean(flags.is_sticky()); 929 Handle<Object> sticky = factory->ToBoolean(flags.is_sticky());
872 Handle<Object> unicode = factory->ToBoolean(flags.is_unicode()); 930 Handle<Object> unicode = factory->ToBoolean(flags.is_unicode());
873 931
874 Map* map = regexp->map(); 932 Map* map = regexp->map();
875 Object* constructor = map->GetConstructor(); 933 Object* constructor = map->GetConstructor();
876 if (!FLAG_harmony_regexps && !FLAG_harmony_unicode_regexps && 934 if (!FLAG_harmony_regexps && !FLAG_harmony_unicode_regexps &&
877 constructor->IsJSFunction() && 935 constructor->IsJSFunction() &&
878 JSFunction::cast(constructor)->initial_map() == map) { 936 JSFunction::cast(constructor)->initial_map() == map) {
879 // If we still have the original map, set in-object properties directly. 937 // If we still have the original map, set in-object properties directly.
938 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, *escaped_source);
880 // Both true and false are immovable immortal objects so no need for write 939 // Both true and false are immovable immortal objects so no need for write
881 // barrier. 940 // barrier.
882 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, *global, 941 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, *global,
883 SKIP_WRITE_BARRIER); 942 SKIP_WRITE_BARRIER);
884 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, *ignore_case, 943 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, *ignore_case,
885 SKIP_WRITE_BARRIER); 944 SKIP_WRITE_BARRIER);
886 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, *multiline, 945 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, *multiline,
887 SKIP_WRITE_BARRIER); 946 SKIP_WRITE_BARRIER);
888 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, 947 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
889 Smi::FromInt(0), SKIP_WRITE_BARRIER); 948 Smi::FromInt(0), SKIP_WRITE_BARRIER);
890 } else { 949 } else {
891 // Map has changed, so use generic, but slower, method. We also end here if 950 // Map has changed, so use generic, but slower, method. We also end here if
892 // the --harmony-regexp flag is set, because the initial map does not have 951 // the --harmony-regexp flag is set, because the initial map does not have
893 // space for the 'sticky' flag, since it is from the snapshot, but must work 952 // space for the 'sticky' flag, since it is from the snapshot, but must work
894 // both with and without --harmony-regexp. When sticky comes out from under 953 // both with and without --harmony-regexp. When sticky comes out from under
895 // the flag, we will be able to use the fast initial map. 954 // the flag, we will be able to use the fast initial map.
896 PropertyAttributes final = 955 PropertyAttributes final =
897 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE); 956 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
898 PropertyAttributes writable = 957 PropertyAttributes writable =
899 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); 958 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
900 Handle<Object> zero(Smi::FromInt(0), isolate); 959 Handle<Object> zero(Smi::FromInt(0), isolate);
960 JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->source_string(),
961 escaped_source, final).Check();
901 JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->global_string(), 962 JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->global_string(),
902 global, final).Check(); 963 global, final).Check();
903 JSObject::SetOwnPropertyIgnoreAttributes( 964 JSObject::SetOwnPropertyIgnoreAttributes(
904 regexp, factory->ignore_case_string(), ignore_case, final).Check(); 965 regexp, factory->ignore_case_string(), ignore_case, final).Check();
905 JSObject::SetOwnPropertyIgnoreAttributes( 966 JSObject::SetOwnPropertyIgnoreAttributes(
906 regexp, factory->multiline_string(), multiline, final).Check(); 967 regexp, factory->multiline_string(), multiline, final).Check();
907 if (FLAG_harmony_regexps) { 968 if (FLAG_harmony_regexps) {
908 JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->sticky_string(), 969 JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->sticky_string(),
909 sticky, final).Check(); 970 sticky, final).Check();
910 } 971 }
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
1120 1181
1121 1182
1122 RUNTIME_FUNCTION(Runtime_IsRegExp) { 1183 RUNTIME_FUNCTION(Runtime_IsRegExp) {
1123 SealHandleScope shs(isolate); 1184 SealHandleScope shs(isolate);
1124 DCHECK(args.length() == 1); 1185 DCHECK(args.length() == 1);
1125 CONVERT_ARG_CHECKED(Object, obj, 0); 1186 CONVERT_ARG_CHECKED(Object, obj, 0);
1126 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); 1187 return isolate->heap()->ToBoolean(obj->IsJSRegExp());
1127 } 1188 }
1128 } 1189 }
1129 } // namespace v8::internal 1190 } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698