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 883 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1135 if (match->length() == 0) { | 1152 if (match->length() == 0) { |
1136 RETURN_FAILURE_ON_EXCEPTION(isolate, RegExpUtils::SetAdvancedStringIndex( | 1153 RETURN_FAILURE_ON_EXCEPTION(isolate, RegExpUtils::SetAdvancedStringIndex( |
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 |
| 1162 namespace { |
| 1163 |
| 1164 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, |
| 1165 compiler::Node* const receiver, |
| 1166 compiler::Node* const string, |
| 1167 compiler::Node* const context, |
| 1168 bool is_fastpath) { |
| 1169 typedef CodeStubAssembler::Label Label; |
| 1170 typedef compiler::Node Node; |
| 1171 |
| 1172 Isolate* const isolate = a->isolate(); |
| 1173 |
| 1174 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
| 1175 |
| 1176 // Grab the initial value of last index. |
| 1177 Node* const previous_last_index = |
| 1178 is_fastpath ? FastLoadLastIndex(a, context, receiver) |
| 1179 : SlowLoadLastIndex(a, context, receiver); |
| 1180 |
| 1181 // Ensure last index is 0. |
| 1182 if (is_fastpath) { |
| 1183 FastStoreLastIndex(a, context, receiver, smi_zero); |
| 1184 } else { |
| 1185 Label next(a); |
| 1186 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); |
| 1187 |
| 1188 SlowStoreLastIndex(a, context, receiver, smi_zero); |
| 1189 a->Goto(&next); |
| 1190 a->Bind(&next); |
| 1191 } |
| 1192 |
| 1193 // Call exec. |
| 1194 Node* const match_indices = |
| 1195 is_fastpath ? RegExpPrototypeExecInternal(a, context, receiver, string) |
| 1196 : RegExpExec(a, context, receiver, string); |
| 1197 |
| 1198 // Reset last index if necessary. |
| 1199 if (is_fastpath) { |
| 1200 FastStoreLastIndex(a, context, receiver, previous_last_index); |
| 1201 } else { |
| 1202 Label next(a); |
| 1203 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); |
| 1204 |
| 1205 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), |
| 1206 &next); |
| 1207 |
| 1208 SlowStoreLastIndex(a, context, receiver, previous_last_index); |
| 1209 a->Goto(&next); |
| 1210 a->Bind(&next); |
| 1211 } |
| 1212 |
| 1213 // Return -1 if no match was found. |
| 1214 { |
| 1215 Label next(a); |
| 1216 a->GotoUnless(a->WordEqual(match_indices, a->NullConstant()), &next); |
| 1217 a->Return(a->SmiConstant(-1)); |
| 1218 a->Bind(&next); |
| 1219 } |
| 1220 |
| 1221 // Return the index of the match. |
| 1222 { |
| 1223 Label fast_result(a), slow_result(a, Label::kDeferred); |
| 1224 |
| 1225 Node* const native_context = a->LoadNativeContext(context); |
| 1226 Node* const initial_regexp_result_map = |
| 1227 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); |
| 1228 Node* const match_indices_map = a->LoadMap(match_indices); |
| 1229 |
| 1230 a->Branch(a->WordEqual(match_indices_map, initial_regexp_result_map), |
| 1231 &fast_result, &slow_result); |
| 1232 |
| 1233 a->Bind(&fast_result); |
| 1234 { |
| 1235 Node* const index = |
| 1236 a->LoadObjectField(match_indices, JSRegExpResult::kIndexOffset, |
| 1237 MachineType::AnyTagged()); |
| 1238 a->Return(index); |
| 1239 } |
| 1240 |
| 1241 a->Bind(&slow_result); |
| 1242 { |
| 1243 Node* const name = a->HeapConstant(isolate->factory()->index_string()); |
| 1244 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
| 1245 Node* const index = |
| 1246 a->CallStub(getproperty_callable, context, match_indices, name); |
| 1247 a->Return(index); |
| 1248 } |
| 1249 } |
| 1250 } |
| 1251 |
| 1252 } // namespace |
| 1253 |
1145 // ES#sec-regexp.prototype-@@search | 1254 // ES#sec-regexp.prototype-@@search |
1146 // RegExp.prototype [ @@search ] ( string ) | 1255 // RegExp.prototype [ @@search ] ( string ) |
1147 BUILTIN(RegExpPrototypeSearch) { | 1256 void Builtins::Generate_RegExpPrototypeSearch(CodeStubAssembler* a) { |
1148 HandleScope scope(isolate); | 1257 typedef CodeStubAssembler::Label Label; |
1149 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.@@search"); | 1258 typedef compiler::Node Node; |
1150 | 1259 |
1151 Handle<Object> string_obj = args.atOrUndefined(isolate, 1); | 1260 Isolate* const isolate = a->isolate(); |
1152 | 1261 |
1153 Handle<String> string; | 1262 Node* const maybe_receiver = a->Parameter(0); |
1154 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, | 1263 Node* const maybe_string = a->Parameter(1); |
1155 Object::ToString(isolate, string_obj)); | 1264 Node* const context = a->Parameter(4); |
1156 | 1265 |
1157 Handle<Object> previous_last_index_obj; | 1266 // Ensure {maybe_receiver} is a JSReceiver. |
1158 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, previous_last_index_obj, | 1267 Node* const map = |
1159 RegExpUtils::GetLastIndex(isolate, recv)); | 1268 ThrowIfNotJSReceiver(a, isolate, context, maybe_receiver, |
| 1269 MessageTemplate::kIncompatibleMethodReceiver, |
| 1270 "RegExp.prototype.@@search"); |
| 1271 Node* const receiver = maybe_receiver; |
1160 | 1272 |
1161 if (!previous_last_index_obj->SameValue(Smi::kZero)) { | 1273 // Convert {maybe_string} to a String. |
1162 RETURN_FAILURE_ON_EXCEPTION(isolate, | 1274 Node* const string = a->ToString(context, maybe_string); |
1163 RegExpUtils::SetLastIndex(isolate, recv, 0)); | |
1164 } | |
1165 | 1275 |
1166 Handle<Object> result; | 1276 Label fast_path(a), slow_path(a); |
1167 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 1277 BranchIfFastPath(a, context, map, &fast_path, &slow_path); |
1168 isolate, result, | |
1169 RegExpUtils::RegExpExec(isolate, recv, string, | |
1170 isolate->factory()->undefined_value())); | |
1171 | 1278 |
1172 Handle<Object> current_last_index_obj; | 1279 a->Bind(&fast_path); |
1173 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, current_last_index_obj, | 1280 Generate_RegExpPrototypeSearchBody(a, receiver, string, context, true); |
1174 RegExpUtils::GetLastIndex(isolate, recv)); | |
1175 | 1281 |
1176 const bool is_last_index_unchanged = | 1282 a->Bind(&slow_path); |
1177 current_last_index_obj->SameValue(*previous_last_index_obj); | 1283 Generate_RegExpPrototypeSearchBody(a, receiver, string, context, false); |
1178 if (!is_last_index_unchanged) { | |
1179 if (previous_last_index_obj->IsSmi()) { | |
1180 RETURN_FAILURE_ON_EXCEPTION( | |
1181 isolate, | |
1182 RegExpUtils::SetLastIndex( | |
1183 isolate, recv, Smi::cast(*previous_last_index_obj)->value())); | |
1184 } else { | |
1185 RETURN_FAILURE_ON_EXCEPTION( | |
1186 isolate, | |
1187 Object::SetProperty(recv, isolate->factory()->lastIndex_string(), | |
1188 previous_last_index_obj, STRICT)); | |
1189 } | |
1190 } | |
1191 | |
1192 if (result->IsNull(isolate)) return Smi::FromInt(-1); | |
1193 | |
1194 RETURN_RESULT_OR_FAILURE( | |
1195 isolate, Object::GetProperty(result, isolate->factory()->index_string())); | |
1196 } | 1284 } |
1197 | 1285 |
1198 namespace { | 1286 namespace { |
1199 | 1287 |
1200 MUST_USE_RESULT MaybeHandle<Object> ToUint32(Isolate* isolate, | 1288 MUST_USE_RESULT MaybeHandle<Object> ToUint32(Isolate* isolate, |
1201 Handle<Object> object, | 1289 Handle<Object> object, |
1202 uint32_t* out) { | 1290 uint32_t* out) { |
1203 if (object->IsUndefined(isolate)) { | 1291 if (object->IsUndefined(isolate)) { |
1204 *out = kMaxUInt32; | 1292 *out = kMaxUInt32; |
1205 return object; | 1293 return object; |
(...skipping 802 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2008 a->Bind(&if_matched); | 2096 a->Bind(&if_matched); |
2009 { | 2097 { |
2010 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, | 2098 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, |
2011 match_indices, string); | 2099 match_indices, string); |
2012 a->Return(result); | 2100 a->Return(result); |
2013 } | 2101 } |
2014 } | 2102 } |
2015 | 2103 |
2016 } // namespace internal | 2104 } // namespace internal |
2017 } // namespace v8 | 2105 } // namespace v8 |
OLD | NEW |