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