| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/builtins/builtins-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
| 6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
| 7 | 7 |
| 8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
| 9 #include "src/regexp/jsregexp.h" | 9 #include "src/regexp/jsregexp.h" |
| 10 #include "src/string-builder.h" | 10 #include "src/string-builder.h" |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 static const int field_offset = | 209 static const int field_offset = |
| 210 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; | 210 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; |
| 211 var_value.Bind(a->LoadObjectField(regexp, field_offset)); | 211 var_value.Bind(a->LoadObjectField(regexp, field_offset)); |
| 212 a->Goto(&out); | 212 a->Goto(&out); |
| 213 } | 213 } |
| 214 | 214 |
| 215 a->Bind(&if_modified); | 215 a->Bind(&if_modified); |
| 216 { | 216 { |
| 217 // Load through the GetProperty stub. | 217 // Load through the GetProperty stub. |
| 218 Node* const name = | 218 Node* const name = |
| 219 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); | 219 a->HeapConstant(a->isolate()->factory()->last_index_string()); |
| 220 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | 220 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
| 221 var_value.Bind(a->CallStub(getproperty_callable, context, regexp, name)); | 221 var_value.Bind(a->CallStub(getproperty_callable, context, regexp, name)); |
| 222 a->Goto(&out); | 222 a->Goto(&out); |
| 223 } | 223 } |
| 224 | 224 |
| 225 a->Bind(&out); | 225 a->Bind(&out); |
| 226 return var_value.value(); | 226 return var_value.value(); |
| 227 } | 227 } |
| 228 | 228 |
| 229 void StoreLastIndex(CodeStubAssembler* a, compiler::Node* context, | 229 void StoreLastIndex(CodeStubAssembler* a, compiler::Node* context, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 242 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; | 242 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; |
| 243 a->StoreObjectField(regexp, field_offset, value); | 243 a->StoreObjectField(regexp, field_offset, value); |
| 244 a->Goto(&out); | 244 a->Goto(&out); |
| 245 } | 245 } |
| 246 | 246 |
| 247 a->Bind(&if_modified); | 247 a->Bind(&if_modified); |
| 248 { | 248 { |
| 249 // Store through runtime. | 249 // Store through runtime. |
| 250 // TODO(ishell): Use SetPropertyStub here once available. | 250 // TODO(ishell): Use SetPropertyStub here once available. |
| 251 Node* const name = | 251 Node* const name = |
| 252 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); | 252 a->HeapConstant(a->isolate()->factory()->last_index_string()); |
| 253 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); | 253 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); |
| 254 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value, | 254 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value, |
| 255 language_mode); | 255 language_mode); |
| 256 a->Goto(&out); | 256 a->Goto(&out); |
| 257 } | 257 } |
| 258 | 258 |
| 259 a->Bind(&out); | 259 a->Bind(&out); |
| 260 } | 260 } |
| 261 | 261 |
| 262 compiler::Node* ConstructNewResultFromMatchInfo(Isolate* isolate, | 262 compiler::Node* ConstructNewResultFromMatchInfo(Isolate* isolate, |
| (...skipping 706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 969 } | 969 } |
| 970 | 970 |
| 971 BUILTIN(RegExpRightContextGetter) { | 971 BUILTIN(RegExpRightContextGetter) { |
| 972 HandleScope scope(isolate); | 972 HandleScope scope(isolate); |
| 973 const int start_index = GetLastMatchCapture(isolate, 1); | 973 const int start_index = GetLastMatchCapture(isolate, 1); |
| 974 Handle<String> last_subject = GetLastMatchSubject(isolate); | 974 Handle<String> last_subject = GetLastMatchSubject(isolate); |
| 975 const int len = last_subject->length(); | 975 const int len = last_subject->length(); |
| 976 return *isolate->factory()->NewSubString(last_subject, start_index, len); | 976 return *isolate->factory()->NewSubString(last_subject, start_index, len); |
| 977 } | 977 } |
| 978 | 978 |
| 979 namespace { | |
| 980 | |
| 981 V8_INLINE bool HasInitialRegExpMap(Isolate* isolate, Handle<JSReceiver> recv) { | |
| 982 return recv->map() == isolate->regexp_function()->initial_map(); | |
| 983 } | |
| 984 | |
| 985 } // namespace | |
| 986 | |
| 987 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) | |
| 988 // Also takes an optional exec method in case our caller | |
| 989 // has already fetched exec. | |
| 990 MaybeHandle<Object> RegExpExec(Isolate* isolate, Handle<JSReceiver> regexp, | |
| 991 Handle<String> string, Handle<Object> exec) { | |
| 992 if (exec->IsUndefined(isolate)) { | |
| 993 ASSIGN_RETURN_ON_EXCEPTION( | |
| 994 isolate, exec, | |
| 995 Object::GetProperty( | |
| 996 regexp, isolate->factory()->NewStringFromAsciiChecked("exec")), | |
| 997 Object); | |
| 998 } | |
| 999 | |
| 1000 if (exec->IsCallable()) { | |
| 1001 const int argc = 1; | |
| 1002 ScopedVector<Handle<Object>> argv(argc); | |
| 1003 argv[0] = string; | |
| 1004 | |
| 1005 Handle<Object> result; | |
| 1006 ASSIGN_RETURN_ON_EXCEPTION( | |
| 1007 isolate, result, | |
| 1008 Execution::Call(isolate, exec, regexp, argc, argv.start()), Object); | |
| 1009 | |
| 1010 if (!result->IsJSReceiver() && !result->IsNull(isolate)) { | |
| 1011 THROW_NEW_ERROR(isolate, | |
| 1012 NewTypeError(MessageTemplate::kInvalidRegExpExecResult), | |
| 1013 Object); | |
| 1014 } | |
| 1015 return result; | |
| 1016 } | |
| 1017 | |
| 1018 if (!regexp->IsJSRegExp()) { | |
| 1019 THROW_NEW_ERROR(isolate, | |
| 1020 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, | |
| 1021 isolate->factory()->NewStringFromAsciiChecked( | |
| 1022 "RegExp.prototype.exec"), | |
| 1023 regexp), | |
| 1024 Object); | |
| 1025 } | |
| 1026 | |
| 1027 { | |
| 1028 Handle<JSFunction> regexp_exec = isolate->regexp_exec_function(); | |
| 1029 | |
| 1030 const int argc = 1; | |
| 1031 ScopedVector<Handle<Object>> argv(argc); | |
| 1032 argv[0] = string; | |
| 1033 | |
| 1034 return Execution::Call(isolate, exec, regexp_exec, argc, argv.start()); | |
| 1035 } | |
| 1036 } | |
| 1037 | |
| 1038 // ES#sec-regexp.prototype.test | |
| 1039 // RegExp.prototype.test ( S ) | |
| 1040 BUILTIN(RegExpPrototypeTest) { | |
| 1041 HandleScope scope(isolate); | |
| 1042 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.test"); | |
| 1043 | |
| 1044 Handle<Object> string_obj = args.atOrUndefined(isolate, 1); | |
| 1045 | |
| 1046 Handle<String> string; | |
| 1047 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, | |
| 1048 Object::ToString(isolate, string_obj)); | |
| 1049 | |
| 1050 Handle<Object> result; | |
| 1051 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 1052 isolate, result, | |
| 1053 RegExpExec(isolate, recv, string, isolate->factory()->undefined_value())); | |
| 1054 | |
| 1055 return isolate->heap()->ToBoolean(!result->IsNull(isolate)); | |
| 1056 } | |
| 1057 | |
| 1058 namespace { | |
| 1059 | |
| 1060 // ES#sec-advancestringindex | |
| 1061 // AdvanceStringIndex ( S, index, unicode ) | |
| 1062 int AdvanceStringIndex(Isolate* isolate, Handle<String> string, int index, | |
| 1063 bool unicode) { | |
| 1064 int increment = 1; | |
| 1065 | |
| 1066 if (unicode && index < string->length()) { | |
| 1067 const uint16_t first = string->Get(index); | |
| 1068 if (first >= 0xD800 && first <= 0xDBFF && string->length() > index + 1) { | |
| 1069 const uint16_t second = string->Get(index + 1); | |
| 1070 if (second >= 0xDC00 && second <= 0xDFFF) { | |
| 1071 increment = 2; | |
| 1072 } | |
| 1073 } | |
| 1074 } | |
| 1075 | |
| 1076 return increment; | |
| 1077 } | |
| 1078 | |
| 1079 MaybeHandle<Object> SetLastIndex(Isolate* isolate, Handle<JSReceiver> recv, | |
| 1080 int value) { | |
| 1081 if (HasInitialRegExpMap(isolate, recv)) { | |
| 1082 JSRegExp::cast(*recv)->SetLastIndex(value); | |
| 1083 return recv; | |
| 1084 } else { | |
| 1085 return Object::SetProperty(recv, isolate->factory()->lastIndex_string(), | |
| 1086 handle(Smi::FromInt(value), isolate), STRICT); | |
| 1087 } | |
| 1088 } | |
| 1089 | |
| 1090 MaybeHandle<Object> GetLastIndex(Isolate* isolate, Handle<JSReceiver> recv) { | |
| 1091 if (HasInitialRegExpMap(isolate, recv)) { | |
| 1092 return handle(JSRegExp::cast(*recv)->LastIndex(), isolate); | |
| 1093 } else { | |
| 1094 return Object::GetProperty(recv, isolate->factory()->lastIndex_string()); | |
| 1095 } | |
| 1096 } | |
| 1097 | |
| 1098 MaybeHandle<Object> SetAdvancedStringIndex(Isolate* isolate, | |
| 1099 Handle<JSReceiver> regexp, | |
| 1100 Handle<String> string, | |
| 1101 bool unicode) { | |
| 1102 Handle<Object> last_index_obj; | |
| 1103 ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj, | |
| 1104 GetLastIndex(isolate, regexp), Object); | |
| 1105 | |
| 1106 ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj, | |
| 1107 Object::ToLength(isolate, last_index_obj), Object); | |
| 1108 | |
| 1109 const int last_index = Handle<Smi>::cast(last_index_obj)->value(); | |
| 1110 const int new_last_index = | |
| 1111 last_index + AdvanceStringIndex(isolate, string, last_index, unicode); | |
| 1112 | |
| 1113 return SetLastIndex(isolate, regexp, new_last_index); | |
| 1114 } | |
| 1115 | |
| 1116 } // namespace | |
| 1117 | |
| 1118 // ES#sec-regexp.prototype-@@match | |
| 1119 // RegExp.prototype [ @@match ] ( string ) | |
| 1120 BUILTIN(RegExpPrototypeMatch) { | |
| 1121 HandleScope scope(isolate); | |
| 1122 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.@@match"); | |
| 1123 | |
| 1124 Handle<Object> string_obj = args.atOrUndefined(isolate, 1); | |
| 1125 | |
| 1126 Handle<String> string; | |
| 1127 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, | |
| 1128 Object::ToString(isolate, string_obj)); | |
| 1129 | |
| 1130 Handle<Object> global_obj; | |
| 1131 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 1132 isolate, global_obj, | |
| 1133 JSReceiver::GetProperty(recv, isolate->factory()->global_string())); | |
| 1134 const bool global = global_obj->BooleanValue(); | |
| 1135 | |
| 1136 if (!global) { | |
| 1137 RETURN_RESULT_OR_FAILURE(isolate, | |
| 1138 RegExpExec(isolate, recv, string, | |
| 1139 isolate->factory()->undefined_value())); | |
| 1140 } | |
| 1141 | |
| 1142 Handle<Object> unicode_obj; | |
| 1143 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 1144 isolate, unicode_obj, | |
| 1145 JSReceiver::GetProperty(recv, isolate->factory()->unicode_string())); | |
| 1146 const bool unicode = unicode_obj->BooleanValue(); | |
| 1147 | |
| 1148 RETURN_FAILURE_ON_EXCEPTION(isolate, SetLastIndex(isolate, recv, 0)); | |
| 1149 | |
| 1150 static const int kInitialArraySize = 8; | |
| 1151 Handle<FixedArray> elems = | |
| 1152 isolate->factory()->NewFixedArrayWithHoles(kInitialArraySize); | |
| 1153 | |
| 1154 int n = 0; | |
| 1155 for (;; n++) { | |
| 1156 Handle<Object> result; | |
| 1157 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 1158 isolate, result, RegExpExec(isolate, recv, string, | |
| 1159 isolate->factory()->undefined_value())); | |
| 1160 | |
| 1161 if (result->IsNull(isolate)) { | |
| 1162 if (n == 0) return isolate->heap()->null_value(); | |
| 1163 break; | |
| 1164 } | |
| 1165 | |
| 1166 Handle<Object> match_obj; | |
| 1167 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, match_obj, | |
| 1168 Object::GetElement(isolate, result, 0)); | |
| 1169 | |
| 1170 Handle<String> match; | |
| 1171 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, match, | |
| 1172 Object::ToString(isolate, match_obj)); | |
| 1173 | |
| 1174 elems = FixedArray::SetAndGrow(elems, n, match); | |
| 1175 | |
| 1176 if (match->length() == 0) { | |
| 1177 RETURN_FAILURE_ON_EXCEPTION( | |
| 1178 isolate, SetAdvancedStringIndex(isolate, recv, string, unicode)); | |
| 1179 } | |
| 1180 } | |
| 1181 | |
| 1182 elems->Shrink(n); | |
| 1183 return *isolate->factory()->NewJSArrayWithElements(elems); | |
| 1184 } | |
| 1185 | |
| 1186 // ES#sec-regexp.prototype-@@search | |
| 1187 // RegExp.prototype [ @@search ] ( string ) | |
| 1188 BUILTIN(RegExpPrototypeSearch) { | |
| 1189 HandleScope scope(isolate); | |
| 1190 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.@@search"); | |
| 1191 | |
| 1192 Handle<Object> string_obj = args.atOrUndefined(isolate, 1); | |
| 1193 | |
| 1194 Handle<String> string; | |
| 1195 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, | |
| 1196 Object::ToString(isolate, string_obj)); | |
| 1197 | |
| 1198 Handle<Object> previous_last_index_obj; | |
| 1199 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, previous_last_index_obj, | |
| 1200 GetLastIndex(isolate, recv)); | |
| 1201 | |
| 1202 if (!previous_last_index_obj->IsSmi() || | |
| 1203 Smi::cast(*previous_last_index_obj)->value() != 0) { | |
| 1204 RETURN_FAILURE_ON_EXCEPTION(isolate, SetLastIndex(isolate, recv, 0)); | |
| 1205 } | |
| 1206 | |
| 1207 Handle<Object> result; | |
| 1208 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 1209 isolate, result, | |
| 1210 RegExpExec(isolate, recv, string, isolate->factory()->undefined_value())); | |
| 1211 | |
| 1212 Handle<Object> current_last_index_obj; | |
| 1213 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, current_last_index_obj, | |
| 1214 GetLastIndex(isolate, recv)); | |
| 1215 | |
| 1216 Maybe<bool> is_last_index_unchanged = | |
| 1217 Object::Equals(current_last_index_obj, previous_last_index_obj); | |
| 1218 if (is_last_index_unchanged.IsNothing()) return isolate->pending_exception(); | |
| 1219 if (!is_last_index_unchanged.FromJust()) { | |
| 1220 if (previous_last_index_obj->IsSmi()) { | |
| 1221 RETURN_FAILURE_ON_EXCEPTION( | |
| 1222 isolate, SetLastIndex(isolate, recv, | |
| 1223 Smi::cast(*previous_last_index_obj)->value())); | |
| 1224 } else { | |
| 1225 RETURN_FAILURE_ON_EXCEPTION( | |
| 1226 isolate, | |
| 1227 Object::SetProperty(recv, isolate->factory()->lastIndex_string(), | |
| 1228 previous_last_index_obj, STRICT)); | |
| 1229 } | |
| 1230 } | |
| 1231 | |
| 1232 if (result->IsNull(isolate)) return Smi::FromInt(-1); | |
| 1233 | |
| 1234 RETURN_RESULT_OR_FAILURE( | |
| 1235 isolate, Object::GetProperty(result, isolate->factory()->index_string())); | |
| 1236 } | |
| 1237 | |
| 1238 } // namespace internal | 979 } // namespace internal |
| 1239 } // namespace v8 | 980 } // namespace v8 |
| OLD | NEW |