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); |
Igor Sheludko
2016/11/11 16:13:21
Given that the only difference between fast and sl
jgruber
2016/11/13 13:00:09
That helper function exists and is used elsewhere
Igor Sheludko
2016/11/13 18:27:59
I meant something like this:
BranchIfFastPath(..
jgruber
2016/11/15 10:02:29
Done.
| |
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); |
Igor Sheludko
2016/11/11 16:13:20
According to my understanding of a spec we must al
jgruber
2016/11/13 13:00:09
Changes to @@search are about to be merged into th
Igor Sheludko
2016/11/13 18:27:59
Ah. Sorry, I didn't notice that.
But still the id
jgruber
2016/11/15 10:02:29
Done.
Yang
2016/11/15 13:03:43
Yeah. I agree. Always writing zero avoids the comp
| |
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), | |
Igor Sheludko
2016/11/11 16:13:20
Same here.
jgruber
2016/11/13 13:00:09
See above.
| |
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))); | |
Igor Sheludko
2016/11/11 16:13:20
SmiConstant(-1)
jgruber
2016/11/13 13:00:09
Nice, is this a recent change? Will fix.
Igor Sheludko
2016/11/13 18:27:59
Yes.
jgruber
2016/11/15 10:02:29
Done.
| |
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); | |
Igor Sheludko
2016/11/11 16:13:21
According to my understanding of a spec we must al
jgruber
2016/11/13 13:00:09
See above.
| |
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), | |
Igor Sheludko
2016/11/11 16:13:21
Same here.
jgruber
2016/11/13 13:00:09
See above.
| |
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. | |
Igor Sheludko
2016/11/11 16:13:20
I guess in this case the match_indices could still
jgruber
2016/11/13 13:00:09
Yes, but I decided against complicating the implem
Igor Sheludko
2016/11/13 18:27:59
Maybe if you follow the GenerateXYZBody idea menti
jgruber
2016/11/15 10:02:29
Done.
| |
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 |