| 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/regexp/regexp-utils.h" | 10 #include "src/regexp/regexp-utils.h" |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags)); | 163 isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags)); |
| 164 | 164 |
| 165 // Return undefined for compatibility with JSC. | 165 // Return undefined for compatibility with JSC. |
| 166 // See http://crbug.com/585775 for web compat details. | 166 // See http://crbug.com/585775 for web compat details. |
| 167 | 167 |
| 168 return isolate->heap()->undefined_value(); | 168 return isolate->heap()->undefined_value(); |
| 169 } | 169 } |
| 170 | 170 |
| 171 namespace { | 171 namespace { |
| 172 | 172 |
| 173 compiler::Node* FastLoadLastIndex(CodeStubAssembler* a, compiler::Node* context, |
| 174 compiler::Node* regexp) { |
| 175 // Load the in-object field. |
| 176 static const int field_offset = |
| 177 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; |
| 178 return a->LoadObjectField(regexp, field_offset); |
| 179 } |
| 180 |
| 181 compiler::Node* SlowLoadLastIndex(CodeStubAssembler* a, compiler::Node* context, |
| 182 compiler::Node* regexp) { |
| 183 // Load through the GetProperty stub. |
| 184 typedef compiler::Node Node; |
| 185 |
| 186 Node* const name = |
| 187 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); |
| 188 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
| 189 return a->CallStub(getproperty_callable, context, regexp, name); |
| 190 } |
| 191 |
| 173 compiler::Node* LoadLastIndex(CodeStubAssembler* a, compiler::Node* context, | 192 compiler::Node* LoadLastIndex(CodeStubAssembler* a, compiler::Node* context, |
| 174 compiler::Node* has_initialmap, | 193 compiler::Node* has_initialmap, |
| 175 compiler::Node* regexp) { | 194 compiler::Node* regexp) { |
| 176 typedef CodeStubAssembler::Variable Variable; | 195 typedef CodeStubAssembler::Variable Variable; |
| 177 typedef CodeStubAssembler::Label Label; | 196 typedef CodeStubAssembler::Label Label; |
| 178 typedef compiler::Node Node; | |
| 179 | 197 |
| 180 Variable var_value(a, MachineRepresentation::kTagged); | 198 Variable var_value(a, MachineRepresentation::kTagged); |
| 181 | 199 |
| 182 Label out(a), if_unmodified(a), if_modified(a, Label::kDeferred); | 200 Label out(a), if_unmodified(a), if_modified(a); |
| 183 a->Branch(has_initialmap, &if_unmodified, &if_modified); | 201 a->Branch(has_initialmap, &if_unmodified, &if_modified); |
| 184 | 202 |
| 185 a->Bind(&if_unmodified); | 203 a->Bind(&if_unmodified); |
| 186 { | 204 { |
| 187 // Load the in-object field. | 205 var_value.Bind(FastLoadLastIndex(a, context, regexp)); |
| 188 static const int field_offset = | |
| 189 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; | |
| 190 var_value.Bind(a->LoadObjectField(regexp, field_offset)); | |
| 191 a->Goto(&out); | 206 a->Goto(&out); |
| 192 } | 207 } |
| 193 | 208 |
| 194 a->Bind(&if_modified); | 209 a->Bind(&if_modified); |
| 195 { | 210 { |
| 196 // Load through the GetProperty stub. | 211 var_value.Bind(SlowLoadLastIndex(a, context, regexp)); |
| 197 Node* const name = | |
| 198 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); | |
| 199 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | |
| 200 var_value.Bind(a->CallStub(getproperty_callable, context, regexp, name)); | |
| 201 a->Goto(&out); | 212 a->Goto(&out); |
| 202 } | 213 } |
| 203 | 214 |
| 204 a->Bind(&out); | 215 a->Bind(&out); |
| 205 return var_value.value(); | 216 return var_value.value(); |
| 206 } | 217 } |
| 207 | 218 |
| 208 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified | 219 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified |
| 209 // JSRegExp instance. | 220 // JSRegExp instance. |
| 210 void FastStoreLastIndex(CodeStubAssembler* a, compiler::Node* context, | 221 void FastStoreLastIndex(CodeStubAssembler* a, compiler::Node* context, |
| 211 compiler::Node* regexp, compiler::Node* value) { | 222 compiler::Node* regexp, compiler::Node* value) { |
| 212 // Store the in-object field. | 223 // Store the in-object field. |
| 213 static const int field_offset = | 224 static const int field_offset = |
| 214 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; | 225 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; |
| 215 a->StoreObjectField(regexp, field_offset, value); | 226 a->StoreObjectField(regexp, field_offset, value); |
| 216 } | 227 } |
| 217 | 228 |
| 229 void SlowStoreLastIndex(CodeStubAssembler* a, compiler::Node* context, |
| 230 compiler::Node* regexp, compiler::Node* value) { |
| 231 // Store through runtime. |
| 232 // TODO(ishell): Use SetPropertyStub here once available. |
| 233 typedef compiler::Node Node; |
| 234 |
| 235 Node* const name = |
| 236 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); |
| 237 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); |
| 238 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value, |
| 239 language_mode); |
| 240 } |
| 241 |
| 218 void StoreLastIndex(CodeStubAssembler* a, compiler::Node* context, | 242 void StoreLastIndex(CodeStubAssembler* a, compiler::Node* context, |
| 219 compiler::Node* has_initialmap, compiler::Node* regexp, | 243 compiler::Node* has_initialmap, compiler::Node* regexp, |
| 220 compiler::Node* value) { | 244 compiler::Node* value) { |
| 221 typedef CodeStubAssembler::Label Label; | 245 typedef CodeStubAssembler::Label Label; |
| 222 typedef compiler::Node Node; | |
| 223 | 246 |
| 224 Label out(a), if_unmodified(a), if_modified(a, Label::kDeferred); | 247 Label out(a), if_unmodified(a), if_modified(a); |
| 225 a->Branch(has_initialmap, &if_unmodified, &if_modified); | 248 a->Branch(has_initialmap, &if_unmodified, &if_modified); |
| 226 | 249 |
| 227 a->Bind(&if_unmodified); | 250 a->Bind(&if_unmodified); |
| 228 { | 251 { |
| 229 FastStoreLastIndex(a, context, regexp, value); | 252 FastStoreLastIndex(a, context, regexp, value); |
| 230 a->Goto(&out); | 253 a->Goto(&out); |
| 231 } | 254 } |
| 232 | 255 |
| 233 a->Bind(&if_modified); | 256 a->Bind(&if_modified); |
| 234 { | 257 { |
| 235 // Store through runtime. | 258 SlowStoreLastIndex(a, context, regexp, value); |
| 236 // TODO(ishell): Use SetPropertyStub here once available. | |
| 237 Node* const name = | |
| 238 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); | |
| 239 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); | |
| 240 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value, | |
| 241 language_mode); | |
| 242 a->Goto(&out); | 259 a->Goto(&out); |
| 243 } | 260 } |
| 244 | 261 |
| 245 a->Bind(&out); | 262 a->Bind(&out); |
| 246 } | 263 } |
| 247 | 264 |
| 248 compiler::Node* ConstructNewResultFromMatchInfo(Isolate* isolate, | 265 compiler::Node* ConstructNewResultFromMatchInfo(Isolate* isolate, |
| 249 CodeStubAssembler* a, | 266 CodeStubAssembler* a, |
| 250 compiler::Node* context, | 267 compiler::Node* context, |
| 251 compiler::Node* match_info, | 268 compiler::Node* match_info, |
| (...skipping 885 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1137 isolate, recv, string, unicode)); | 1154 isolate, recv, string, unicode)); |
| 1138 } | 1155 } |
| 1139 } | 1156 } |
| 1140 | 1157 |
| 1141 elems->Shrink(n); | 1158 elems->Shrink(n); |
| 1142 return *isolate->factory()->NewJSArrayWithElements(elems); | 1159 return *isolate->factory()->NewJSArrayWithElements(elems); |
| 1143 } | 1160 } |
| 1144 | 1161 |
| 1145 // ES#sec-regexp.prototype-@@search | 1162 // ES#sec-regexp.prototype-@@search |
| 1146 // RegExp.prototype [ @@search ] ( string ) | 1163 // RegExp.prototype [ @@search ] ( string ) |
| 1147 BUILTIN(RegExpPrototypeSearch) { | 1164 void Builtins::Generate_RegExpPrototypeSearch(CodeStubAssembler* a) { |
| 1148 HandleScope scope(isolate); | 1165 typedef CodeStubAssembler::Label Label; |
| 1149 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.@@search"); | 1166 typedef compiler::Node Node; |
| 1150 | 1167 |
| 1151 Handle<Object> string_obj = args.atOrUndefined(isolate, 1); | 1168 Isolate* const isolate = a->isolate(); |
| 1152 | 1169 |
| 1153 Handle<String> string; | 1170 Node* const maybe_receiver = a->Parameter(0); |
| 1154 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, | 1171 Node* const maybe_string = a->Parameter(1); |
| 1155 Object::ToString(isolate, string_obj)); | 1172 Node* const context = a->Parameter(4); |
| 1156 | 1173 |
| 1157 Handle<Object> previous_last_index_obj; | 1174 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
| 1158 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, previous_last_index_obj, | |
| 1159 RegExpUtils::GetLastIndex(isolate, recv)); | |
| 1160 | 1175 |
| 1161 if (!previous_last_index_obj->SameValue(Smi::kZero)) { | 1176 // Ensure {maybe_receiver} is a JSReceiver. |
| 1162 RETURN_FAILURE_ON_EXCEPTION(isolate, | 1177 Node* const map = |
| 1163 RegExpUtils::SetLastIndex(isolate, recv, 0)); | 1178 ThrowIfNotJSReceiver(a, isolate, context, maybe_receiver, |
| 1164 } | 1179 MessageTemplate::kIncompatibleMethodReceiver, |
| 1180 "RegExp.prototype.@@search"); |
| 1181 Node* const receiver = maybe_receiver; |
| 1165 | 1182 |
| 1166 Handle<Object> result; | 1183 // Convert {maybe_string} to a String. |
| 1167 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 1184 Node* const string = a->ToString(context, maybe_string); |
| 1168 isolate, result, | |
| 1169 RegExpUtils::RegExpExec(isolate, recv, string, | |
| 1170 isolate->factory()->undefined_value())); | |
| 1171 | 1185 |
| 1172 Handle<Object> current_last_index_obj; | 1186 Label fast_path(a), slow_path(a); |
| 1173 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, current_last_index_obj, | 1187 BranchIfFastPath(a, context, map, &fast_path, &slow_path); |
| 1174 RegExpUtils::GetLastIndex(isolate, recv)); | |
| 1175 | 1188 |
| 1176 const bool is_last_index_unchanged = | 1189 a->Bind(&fast_path); |
| 1177 current_last_index_obj->SameValue(*previous_last_index_obj); | 1190 { |
| 1178 if (!is_last_index_unchanged) { | 1191 // Grab the initial value of last index. |
| 1179 if (previous_last_index_obj->IsSmi()) { | 1192 Node* const previous_last_index = FastLoadLastIndex(a, context, receiver); |
| 1180 RETURN_FAILURE_ON_EXCEPTION( | 1193 |
| 1181 isolate, | 1194 // Ensure last index is 0. |
| 1182 RegExpUtils::SetLastIndex( | 1195 { |
| 1183 isolate, recv, Smi::cast(*previous_last_index_obj)->value())); | 1196 Label next(a); |
| 1184 } else { | 1197 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); |
| 1185 RETURN_FAILURE_ON_EXCEPTION( | 1198 |
| 1186 isolate, | 1199 FastStoreLastIndex(a, context, receiver, smi_zero); |
| 1187 Object::SetProperty(recv, isolate->factory()->lastIndex_string(), | 1200 a->Goto(&next); |
| 1188 previous_last_index_obj, STRICT)); | 1201 |
| 1202 a->Bind(&next); |
| 1203 } |
| 1204 |
| 1205 // Call exec. |
| 1206 Node* const match_indices = RegExpExec(a, context, receiver, string); |
| 1207 |
| 1208 // Reset last index if necessary. |
| 1209 { |
| 1210 Label next(a); |
| 1211 |
| 1212 Node* const current_last_index = FastLoadLastIndex(a, context, receiver); |
| 1213 |
| 1214 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), |
| 1215 &next); |
| 1216 |
| 1217 FastStoreLastIndex(a, context, receiver, previous_last_index); |
| 1218 a->Goto(&next); |
| 1219 |
| 1220 a->Bind(&next); |
| 1221 } |
| 1222 |
| 1223 // Return -1 if no match was found. |
| 1224 { |
| 1225 Label next(a); |
| 1226 a->GotoUnless(a->WordEqual(match_indices, a->NullConstant()), &next); |
| 1227 a->Return(a->SmiConstant(Smi::FromInt(-1))); |
| 1228 a->Bind(&next); |
| 1229 } |
| 1230 |
| 1231 // Return the index of the match. |
| 1232 { |
| 1233 Label fast_result(a), slow_result(a, Label::kDeferred); |
| 1234 |
| 1235 Node* const native_context = a->LoadNativeContext(context); |
| 1236 Node* const initial_regexp_result_map = a->LoadContextElement( |
| 1237 native_context, Context::REGEXP_RESULT_MAP_INDEX); |
| 1238 Node* const match_indices_map = a->LoadMap(match_indices); |
| 1239 |
| 1240 a->Branch(a->WordEqual(match_indices_map, initial_regexp_result_map), |
| 1241 &fast_result, &slow_result); |
| 1242 |
| 1243 a->Bind(&fast_result); |
| 1244 { |
| 1245 Node* const index = |
| 1246 a->LoadObjectField(match_indices, JSRegExpResult::kIndexOffset, |
| 1247 MachineType::AnyTagged()); |
| 1248 a->Return(index); |
| 1249 } |
| 1250 |
| 1251 a->Bind(&slow_result); |
| 1252 { |
| 1253 Node* const name = a->HeapConstant(isolate->factory()->index_string()); |
| 1254 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
| 1255 Node* const index = |
| 1256 a->CallStub(getproperty_callable, context, match_indices, name); |
| 1257 a->Return(index); |
| 1258 } |
| 1189 } | 1259 } |
| 1190 } | 1260 } |
| 1191 | 1261 |
| 1192 if (result->IsNull(isolate)) return Smi::FromInt(-1); | 1262 a->Bind(&slow_path); |
| 1263 { |
| 1264 // Grab the initial value of last index. |
| 1265 Node* const previous_last_index = SlowLoadLastIndex(a, context, receiver); |
| 1193 | 1266 |
| 1194 RETURN_RESULT_OR_FAILURE( | 1267 // Ensure last index is 0. |
| 1195 isolate, Object::GetProperty(result, isolate->factory()->index_string())); | 1268 { |
| 1269 Label next(a); |
| 1270 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); |
| 1271 |
| 1272 SlowStoreLastIndex(a, context, receiver, smi_zero); |
| 1273 a->Goto(&next); |
| 1274 |
| 1275 a->Bind(&next); |
| 1276 } |
| 1277 |
| 1278 // Call exec. |
| 1279 Node* const match_indices = RegExpExec(a, context, receiver, string); |
| 1280 |
| 1281 // Reset last index if necessary. |
| 1282 { |
| 1283 Label next(a); |
| 1284 |
| 1285 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); |
| 1286 |
| 1287 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), |
| 1288 &next); |
| 1289 |
| 1290 SlowStoreLastIndex(a, context, receiver, previous_last_index); |
| 1291 a->Goto(&next); |
| 1292 |
| 1293 a->Bind(&next); |
| 1294 } |
| 1295 |
| 1296 // Return -1 if no match was found. |
| 1297 { |
| 1298 Label next(a); |
| 1299 a->GotoUnless(a->WordEqual(match_indices, a->NullConstant()), &next); |
| 1300 a->Return(a->SmiConstant(Smi::FromInt(-1))); |
| 1301 a->Bind(&next); |
| 1302 } |
| 1303 |
| 1304 // Return the index of the match. |
| 1305 { |
| 1306 Node* const name = a->HeapConstant(isolate->factory()->index_string()); |
| 1307 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
| 1308 Node* const index = |
| 1309 a->CallStub(getproperty_callable, context, match_indices, name); |
| 1310 a->Return(index); |
| 1311 } |
| 1312 } |
| 1196 } | 1313 } |
| 1197 | 1314 |
| 1198 namespace { | 1315 namespace { |
| 1199 | 1316 |
| 1200 MUST_USE_RESULT MaybeHandle<Object> ToUint32(Isolate* isolate, | 1317 MUST_USE_RESULT MaybeHandle<Object> ToUint32(Isolate* isolate, |
| 1201 Handle<Object> object, | 1318 Handle<Object> object, |
| 1202 uint32_t* out) { | 1319 uint32_t* out) { |
| 1203 if (object->IsUndefined(isolate)) { | 1320 if (object->IsUndefined(isolate)) { |
| 1204 *out = kMaxUInt32; | 1321 *out = kMaxUInt32; |
| 1205 return object; | 1322 return object; |
| (...skipping 802 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2008 a->Bind(&if_matched); | 2125 a->Bind(&if_matched); |
| 2009 { | 2126 { |
| 2010 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, | 2127 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, |
| 2011 match_indices, string); | 2128 match_indices, string); |
| 2012 a->Return(result); | 2129 a->Return(result); |
| 2013 } | 2130 } |
| 2014 } | 2131 } |
| 2015 | 2132 |
| 2016 } // namespace internal | 2133 } // namespace internal |
| 2017 } // namespace v8 | 2134 } // namespace v8 |
| OLD | NEW |