OLD | NEW |
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/runtime/runtime-utils.h" | 5 #include "src/runtime/runtime-utils.h" |
6 | 6 |
7 #include "src/arguments.h" | 7 #include "src/arguments.h" |
8 #include "src/conversions-inl.h" | 8 #include "src/conversions-inl.h" |
9 #include "src/isolate-inl.h" | 9 #include "src/isolate-inl.h" |
10 #include "src/messages.h" | 10 #include "src/messages.h" |
(...skipping 807 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
818 Handle<JSArray> array = Handle<JSArray>::cast(object); | 818 Handle<JSArray> array = Handle<JSArray>::cast(object); |
819 array->set_elements(*elements); | 819 array->set_elements(*elements); |
820 array->set_length(Smi::FromInt(size)); | 820 array->set_length(Smi::FromInt(size)); |
821 // Write in-object properties after the length of the array. | 821 // Write in-object properties after the length of the array. |
822 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, *index); | 822 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, *index); |
823 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, *input); | 823 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, *input); |
824 return *array; | 824 return *array; |
825 } | 825 } |
826 | 826 |
827 | 827 |
828 static JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, | |
829 bool* success) { | |
830 uint32_t value = JSRegExp::NONE; | |
831 int length = flags->length(); | |
832 // A longer flags string cannot be valid. | |
833 if (length > 5) return JSRegExp::Flags(0); | |
834 for (int i = 0; i < length; i++) { | |
835 uint32_t flag = JSRegExp::NONE; | |
836 switch (flags->Get(i)) { | |
837 case 'g': | |
838 flag = JSRegExp::GLOBAL; | |
839 break; | |
840 case 'i': | |
841 flag = JSRegExp::IGNORE_CASE; | |
842 break; | |
843 case 'm': | |
844 flag = JSRegExp::MULTILINE; | |
845 break; | |
846 case 'u': | |
847 if (!FLAG_harmony_unicode_regexps) return JSRegExp::Flags(0); | |
848 flag = JSRegExp::UNICODE_ESCAPES; | |
849 break; | |
850 case 'y': | |
851 if (!FLAG_harmony_regexps) return JSRegExp::Flags(0); | |
852 flag = JSRegExp::STICKY; | |
853 break; | |
854 default: | |
855 return JSRegExp::Flags(0); | |
856 } | |
857 // Duplicate flag. | |
858 if (value & flag) return JSRegExp::Flags(0); | |
859 value |= flag; | |
860 } | |
861 *success = true; | |
862 return JSRegExp::Flags(value); | |
863 } | |
864 | |
865 | |
866 template <typename Char> | |
867 inline int CountRequiredEscapes(Handle<String> source) { | |
868 DisallowHeapAllocation no_gc; | |
869 int escapes = 0; | |
870 Vector<const Char> src = source->GetCharVector<Char>(); | |
871 for (int i = 0; i < src.length(); i++) { | |
872 if (src[i] == '/' && (i == 0 || src[i - 1] != '\\')) escapes++; | |
873 } | |
874 return escapes; | |
875 } | |
876 | |
877 | |
878 template <typename Char, typename StringType> | |
879 inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source, | |
880 Handle<StringType> result) { | |
881 DisallowHeapAllocation no_gc; | |
882 Vector<const Char> src = source->GetCharVector<Char>(); | |
883 Vector<Char> dst(result->GetChars(), result->length()); | |
884 int s = 0; | |
885 int d = 0; | |
886 while (s < src.length()) { | |
887 if (src[s] == '/' && (s == 0 || src[s - 1] != '\\')) dst[d++] = '\\'; | |
888 dst[d++] = src[s++]; | |
889 } | |
890 DCHECK_EQ(result->length(), d); | |
891 return result; | |
892 } | |
893 | |
894 | |
895 MaybeHandle<String> EscapeRegExpSource(Isolate* isolate, | |
896 Handle<String> source) { | |
897 String::Flatten(source); | |
898 if (source->length() == 0) return isolate->factory()->query_colon_string(); | |
899 bool one_byte = source->IsOneByteRepresentationUnderneath(); | |
900 int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source) | |
901 : CountRequiredEscapes<uc16>(source); | |
902 if (escapes == 0) return source; | |
903 int length = source->length() + escapes; | |
904 if (one_byte) { | |
905 Handle<SeqOneByteString> result; | |
906 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, | |
907 isolate->factory()->NewRawOneByteString(length), | |
908 String); | |
909 return WriteEscapedRegExpSource<uint8_t>(source, result); | |
910 } else { | |
911 Handle<SeqTwoByteString> result; | |
912 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, | |
913 isolate->factory()->NewRawTwoByteString(length), | |
914 String); | |
915 return WriteEscapedRegExpSource<uc16>(source, result); | |
916 } | |
917 } | |
918 | |
919 | |
920 RUNTIME_FUNCTION(Runtime_RegExpInitializeAndCompile) { | 828 RUNTIME_FUNCTION(Runtime_RegExpInitializeAndCompile) { |
921 HandleScope scope(isolate); | 829 HandleScope scope(isolate); |
922 DCHECK(args.length() == 3); | 830 DCHECK(args.length() == 3); |
923 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); | 831 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); |
924 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); | 832 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); |
925 CONVERT_ARG_HANDLE_CHECKED(String, flags_string, 2); | 833 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2); |
926 Factory* factory = isolate->factory(); | |
927 // If source is the empty string we set it to "(?:)" instead as | |
928 // suggested by ECMA-262, 5th, section 15.10.4.1. | |
929 if (source->length() == 0) source = factory->query_colon_string(); | |
930 | 834 |
931 bool success = false; | 835 RETURN_FAILURE_ON_EXCEPTION(isolate, |
932 JSRegExp::Flags flags = RegExpFlagsFromString(flags_string, &success); | 836 JSRegExp::Initialize(regexp, source, flags)); |
933 if (!success) { | |
934 THROW_NEW_ERROR_RETURN_FAILURE( | |
935 isolate, | |
936 NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string)); | |
937 } | |
938 | 837 |
939 Handle<String> escaped_source; | 838 return *regexp; |
940 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, escaped_source, | |
941 EscapeRegExpSource(isolate, source)); | |
942 | |
943 regexp->set_source(*escaped_source); | |
944 regexp->set_flags(Smi::FromInt(flags.value())); | |
945 | |
946 Map* map = regexp->map(); | |
947 Object* constructor = map->GetConstructor(); | |
948 if (constructor->IsJSFunction() && | |
949 JSFunction::cast(constructor)->initial_map() == map) { | |
950 // If we still have the original map, set in-object properties directly. | |
951 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, | |
952 Smi::FromInt(0), SKIP_WRITE_BARRIER); | |
953 } else { | |
954 // Map has changed, so use generic, but slower, method. | |
955 PropertyAttributes writable = | |
956 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); | |
957 JSObject::SetOwnPropertyIgnoreAttributes( | |
958 regexp, factory->last_index_string(), | |
959 Handle<Smi>(Smi::FromInt(0), isolate), writable) | |
960 .Check(); | |
961 } | |
962 | |
963 Handle<Object> result; | |
964 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
965 isolate, result, RegExpImpl::Compile(regexp, source, flags)); | |
966 return *result; | |
967 } | 839 } |
968 | 840 |
969 | 841 |
970 RUNTIME_FUNCTION(Runtime_MaterializeRegExpLiteral) { | 842 RUNTIME_FUNCTION(Runtime_MaterializeRegExpLiteral) { |
971 HandleScope scope(isolate); | 843 HandleScope scope(isolate); |
972 DCHECK(args.length() == 4); | 844 DCHECK(args.length() == 4); |
973 CONVERT_ARG_HANDLE_CHECKED(LiteralsArray, literals, 0); | 845 CONVERT_ARG_HANDLE_CHECKED(LiteralsArray, literals, 0); |
974 CONVERT_SMI_ARG_CHECKED(index, 1); | 846 CONVERT_SMI_ARG_CHECKED(index, 1); |
975 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2); | 847 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2); |
976 CONVERT_ARG_HANDLE_CHECKED(String, flags, 3); | 848 CONVERT_ARG_HANDLE_CHECKED(String, flags, 3); |
977 | 849 |
978 Handle<JSFunction> constructor = isolate->regexp_function(); | 850 Handle<JSRegExp> regexp; |
979 // Compute the regular expression literal. | 851 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, regexp, |
980 Handle<Object> regexp; | 852 JSRegExp::New(pattern, flags)); |
981 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
982 isolate, regexp, | |
983 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags)); | |
984 literals->set_literal(index, *regexp); | 853 literals->set_literal(index, *regexp); |
985 return *regexp; | 854 return *regexp; |
986 } | 855 } |
987 | 856 |
988 | 857 |
989 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain | 858 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain |
990 // separate last match info. See comment on that function. | 859 // separate last match info. See comment on that function. |
991 template <bool has_capture> | 860 template <bool has_capture> |
992 static Object* SearchRegExpMultiple(Isolate* isolate, Handle<String> subject, | 861 static Object* SearchRegExpMultiple(Isolate* isolate, Handle<String> subject, |
993 Handle<JSRegExp> regexp, | 862 Handle<JSRegExp> regexp, |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1169 | 1038 |
1170 | 1039 |
1171 RUNTIME_FUNCTION(Runtime_IsRegExp) { | 1040 RUNTIME_FUNCTION(Runtime_IsRegExp) { |
1172 SealHandleScope shs(isolate); | 1041 SealHandleScope shs(isolate); |
1173 DCHECK(args.length() == 1); | 1042 DCHECK(args.length() == 1); |
1174 CONVERT_ARG_CHECKED(Object, obj, 0); | 1043 CONVERT_ARG_CHECKED(Object, obj, 0); |
1175 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); | 1044 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); |
1176 } | 1045 } |
1177 } // namespace internal | 1046 } // namespace internal |
1178 } // namespace v8 | 1047 } // namespace v8 |
OLD | NEW |