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 |