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 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
169 isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags)); | 169 isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags)); |
170 | 170 |
171 // Return undefined for compatibility with JSC. | 171 // Return undefined for compatibility with JSC. |
172 // See http://crbug.com/585775 for web compat details. | 172 // See http://crbug.com/585775 for web compat details. |
173 | 173 |
174 return isolate->heap()->undefined_value(); | 174 return isolate->heap()->undefined_value(); |
175 } | 175 } |
176 | 176 |
177 namespace { | 177 namespace { |
178 | 178 |
179 Node* FastLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) { | 179 Node* FastLoadLastIndex(CodeStubAssembler* a, Node* regexp) { |
180 // Load the in-object field. | 180 // Load the in-object field. |
181 static const int field_offset = | 181 static const int field_offset = |
182 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; | 182 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; |
183 return a->LoadObjectField(regexp, field_offset); | 183 return a->LoadObjectField(regexp, field_offset); |
184 } | 184 } |
185 | 185 |
186 Node* SlowLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) { | 186 Node* SlowLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) { |
187 // Load through the GetProperty stub. | 187 // Load through the GetProperty stub. |
188 Node* const name = | 188 Node* const name = |
189 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); | 189 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); |
190 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | 190 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
191 return a->CallStub(getproperty_callable, context, regexp, name); | 191 return a->CallStub(getproperty_callable, context, regexp, name); |
192 } | 192 } |
193 | 193 |
194 Node* LoadLastIndex(CodeStubAssembler* a, Node* context, Node* has_initialmap, | 194 Node* LoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, |
195 Node* regexp) { | 195 bool is_fastpath) { |
196 CVariable var_value(a, MachineRepresentation::kTagged); | 196 return is_fastpath ? FastLoadLastIndex(a, regexp) |
197 | 197 : SlowLoadLastIndex(a, context, regexp); |
198 CLabel out(a), if_unmodified(a), if_modified(a); | |
199 a->Branch(has_initialmap, &if_unmodified, &if_modified); | |
200 | |
201 a->Bind(&if_unmodified); | |
202 { | |
203 var_value.Bind(FastLoadLastIndex(a, context, regexp)); | |
204 a->Goto(&out); | |
205 } | |
206 | |
207 a->Bind(&if_modified); | |
208 { | |
209 var_value.Bind(SlowLoadLastIndex(a, context, regexp)); | |
210 a->Goto(&out); | |
211 } | |
212 | |
213 a->Bind(&out); | |
214 return var_value.value(); | |
215 } | 198 } |
216 | 199 |
217 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified | 200 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified |
218 // JSRegExp instance. | 201 // JSRegExp instance. |
219 void FastStoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, | 202 void FastStoreLastIndex(CodeStubAssembler* a, Node* regexp, Node* value) { |
220 Node* value) { | |
221 // Store the in-object field. | 203 // Store the in-object field. |
222 static const int field_offset = | 204 static const int field_offset = |
223 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; | 205 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; |
224 a->StoreObjectField(regexp, field_offset, value); | 206 a->StoreObjectField(regexp, field_offset, value); |
225 } | 207 } |
226 | 208 |
227 void SlowStoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, | 209 void SlowStoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, |
228 Node* value) { | 210 Node* value) { |
229 // Store through runtime. | 211 // Store through runtime. |
230 // TODO(ishell): Use SetPropertyStub here once available. | 212 // TODO(ishell): Use SetPropertyStub here once available. |
231 Node* const name = | 213 Node* const name = |
232 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); | 214 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); |
233 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); | 215 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); |
234 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value, | 216 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value, |
235 language_mode); | 217 language_mode); |
236 } | 218 } |
237 | 219 |
238 void StoreLastIndex(CodeStubAssembler* a, Node* context, Node* has_initialmap, | 220 void StoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, |
239 Node* regexp, Node* value) { | 221 Node* value, bool is_fastpath) { |
240 CLabel out(a), if_unmodified(a), if_modified(a); | 222 if (is_fastpath) { |
241 a->Branch(has_initialmap, &if_unmodified, &if_modified); | 223 FastStoreLastIndex(a, regexp, value); |
242 | 224 } else { |
243 a->Bind(&if_unmodified); | 225 SlowStoreLastIndex(a, context, regexp, value); |
244 { | |
245 FastStoreLastIndex(a, context, regexp, value); | |
246 a->Goto(&out); | |
247 } | 226 } |
248 | |
249 a->Bind(&if_modified); | |
250 { | |
251 SlowStoreLastIndex(a, context, regexp, value); | |
252 a->Goto(&out); | |
253 } | |
254 | |
255 a->Bind(&out); | |
256 } | 227 } |
257 | 228 |
258 Node* ConstructNewResultFromMatchInfo(Isolate* isolate, CodeStubAssembler* a, | 229 Node* ConstructNewResultFromMatchInfo(Isolate* isolate, CodeStubAssembler* a, |
259 Node* context, Node* match_info, | 230 Node* context, Node* match_info, |
260 Node* string) { | 231 Node* string) { |
261 CLabel out(a); | 232 CLabel out(a); |
262 | 233 |
263 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 234 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; |
264 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement( | 235 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement( |
265 match_info, a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, | 236 match_info, a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
319 a->Bind(&next_iter); | 290 a->Bind(&next_iter); |
320 var_from_cursor.Bind(a->IntPtrAdd(from_cursor, a->IntPtrConstant(2))); | 291 var_from_cursor.Bind(a->IntPtrAdd(from_cursor, a->IntPtrConstant(2))); |
321 var_to_cursor.Bind(a->IntPtrAdd(to_cursor, a->IntPtrConstant(1))); | 292 var_to_cursor.Bind(a->IntPtrAdd(to_cursor, a->IntPtrConstant(1))); |
322 a->Branch(a->UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out); | 293 a->Branch(a->UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out); |
323 } | 294 } |
324 | 295 |
325 a->Bind(&out); | 296 a->Bind(&out); |
326 return result; | 297 return result; |
327 } | 298 } |
328 | 299 |
329 // ES#sec-regexp.prototype.exec | 300 Node* Generate_RegExpPrototypeExecBodyWithoutResult( |
Igor Sheludko
2016/11/30 22:04:21
Please add a comment (especially about what does t
jgruber
2016/12/01 09:09:09
Done.
| |
330 // RegExp.prototype.exec ( string ) | 301 CodeStubAssembler* a, Node* const context, Node* const regexp, |
331 Node* RegExpPrototypeExecInternal(CodeStubAssembler* a, Node* context, | 302 Node* const string, CLabel* if_didnotmatch, const bool is_fastpath) { |
332 Node* maybe_receiver, Node* maybe_string) { | |
333 Isolate* const isolate = a->isolate(); | 303 Isolate* const isolate = a->isolate(); |
334 | 304 |
335 Node* const null = a->NullConstant(); | 305 Node* const null = a->NullConstant(); |
336 Node* const int_zero = a->IntPtrConstant(0); | 306 Node* const int_zero = a->IntPtrConstant(0); |
337 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 307 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
338 | 308 |
309 if (!is_fastpath) { | |
310 a->ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, | |
311 "RegExp.prototype.exec"); | |
312 } | |
313 | |
314 CSA_ASSERT(a, a->IsStringInstanceType(a->LoadInstanceType(string))); | |
315 CSA_ASSERT(a, a->HasInstanceType(regexp, JS_REGEXP_TYPE)); | |
316 | |
339 CVariable var_result(a, MachineRepresentation::kTagged); | 317 CVariable var_result(a, MachineRepresentation::kTagged); |
340 CLabel out(a); | 318 CLabel out(a); |
341 | 319 |
342 // Ensure {maybe_receiver} is a JSRegExp. | |
343 Node* const regexp_map = a->ThrowIfNotInstanceType( | |
344 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); | |
345 Node* const regexp = maybe_receiver; | |
346 | |
347 // Check whether the regexp instance is unmodified. | |
348 Node* const native_context = a->LoadNativeContext(context); | 320 Node* const native_context = a->LoadNativeContext(context); |
349 Node* const regexp_fun = | |
350 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); | |
351 Node* const initial_map = | |
352 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); | |
353 Node* const has_initialmap = a->WordEqual(regexp_map, initial_map); | |
354 | |
355 // Convert {maybe_string} to a string. | |
356 Callable tostring_callable = CodeFactory::ToString(isolate); | |
357 Node* const string = a->CallStub(tostring_callable, context, maybe_string); | |
358 Node* const string_length = a->LoadStringLength(string); | 321 Node* const string_length = a->LoadStringLength(string); |
359 | 322 |
360 // Check whether the regexp is global or sticky, which determines whether we | 323 // Check whether the regexp is global or sticky, which determines whether we |
361 // update last index later on. | 324 // update last index later on. |
362 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 325 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
363 Node* const is_global_or_sticky = | 326 Node* const is_global_or_sticky = |
364 a->WordAnd(a->SmiUntag(flags), | 327 a->WordAnd(a->SmiUntag(flags), |
365 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); | 328 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); |
366 Node* const should_update_last_index = | 329 Node* const should_update_last_index = |
367 a->WordNotEqual(is_global_or_sticky, int_zero); | 330 a->WordNotEqual(is_global_or_sticky, int_zero); |
368 | 331 |
369 // Grab and possibly update last index. | 332 // Grab and possibly update last index. |
370 CLabel run_exec(a); | 333 CLabel run_exec(a); |
371 CVariable var_lastindex(a, MachineRepresentation::kTagged); | 334 CVariable var_lastindex(a, MachineRepresentation::kTagged); |
372 { | 335 { |
373 CLabel if_doupdate(a), if_dontupdate(a); | 336 CLabel if_doupdate(a), if_dontupdate(a); |
374 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate); | 337 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate); |
375 | 338 |
376 a->Bind(&if_doupdate); | 339 a->Bind(&if_doupdate); |
377 { | 340 { |
378 Node* const regexp_lastindex = | 341 Node* const regexp_lastindex = |
379 LoadLastIndex(a, context, has_initialmap, regexp); | 342 LoadLastIndex(a, context, regexp, is_fastpath); |
343 var_lastindex.Bind(regexp_lastindex); | |
380 | 344 |
381 Callable tolength_callable = CodeFactory::ToLength(isolate); | 345 // Omit ToLength if lastindex is a non-negative smi. |
382 Node* const lastindex = | 346 { |
383 a->CallStub(tolength_callable, context, regexp_lastindex); | 347 CLabel call_tolength(a, CLabel::kDeferred), next(a); |
384 var_lastindex.Bind(lastindex); | 348 a->Branch(a->WordIsPositiveSmi(regexp_lastindex), &next, |
349 &call_tolength); | |
350 | |
351 a->Bind(&call_tolength); | |
352 { | |
353 Callable tolength_callable = CodeFactory::ToLength(isolate); | |
354 var_lastindex.Bind( | |
355 a->CallStub(tolength_callable, context, regexp_lastindex)); | |
356 a->Goto(&next); | |
357 } | |
358 | |
359 a->Bind(&next); | |
360 } | |
361 | |
362 Node* const lastindex = var_lastindex.value(); | |
385 | 363 |
386 CLabel if_isoob(a, CLabel::kDeferred); | 364 CLabel if_isoob(a, CLabel::kDeferred); |
387 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob); | 365 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob); |
388 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob); | 366 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob); |
389 a->Goto(&run_exec); | 367 a->Goto(&run_exec); |
390 | 368 |
391 a->Bind(&if_isoob); | 369 a->Bind(&if_isoob); |
392 { | 370 { |
393 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); | 371 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); |
394 var_result.Bind(null); | 372 var_result.Bind(null); |
395 a->Goto(&out); | 373 a->Goto(if_didnotmatch); |
396 } | 374 } |
397 } | 375 } |
398 | 376 |
399 a->Bind(&if_dontupdate); | 377 a->Bind(&if_dontupdate); |
400 { | 378 { |
401 var_lastindex.Bind(smi_zero); | 379 var_lastindex.Bind(smi_zero); |
402 a->Goto(&run_exec); | 380 a->Goto(&run_exec); |
403 } | 381 } |
404 } | 382 } |
405 | 383 |
406 Node* match_indices; | 384 Node* match_indices; |
407 CLabel successful_match(a); | 385 CLabel successful_match(a); |
408 a->Bind(&run_exec); | 386 a->Bind(&run_exec); |
409 { | 387 { |
410 // Get last match info from the context. | 388 // Get last match info from the context. |
411 Node* const last_match_info = a->LoadContextElement( | 389 Node* const last_match_info = a->LoadContextElement( |
412 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 390 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
413 | 391 |
414 // Call the exec stub. | 392 // Call the exec stub. |
415 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 393 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
416 match_indices = a->CallStub(exec_callable, context, regexp, string, | 394 match_indices = a->CallStub(exec_callable, context, regexp, string, |
417 var_lastindex.value(), last_match_info); | 395 var_lastindex.value(), last_match_info); |
396 var_result.Bind(match_indices); | |
418 | 397 |
419 // {match_indices} is either null or the RegExpMatchInfo array. | 398 // {match_indices} is either null or the RegExpMatchInfo array. |
420 // Return early if exec failed, possibly updating last index. | 399 // Return early if exec failed, possibly updating last index. |
421 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); | 400 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); |
422 | 401 |
423 CLabel return_null(a); | 402 a->GotoUnless(should_update_last_index, if_didnotmatch); |
424 a->GotoUnless(should_update_last_index, &return_null); | |
425 | 403 |
426 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); | 404 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); |
427 a->Goto(&return_null); | 405 a->Goto(if_didnotmatch); |
428 | |
429 a->Bind(&return_null); | |
430 var_result.Bind(null); | |
431 a->Goto(&out); | |
432 } | 406 } |
433 | 407 |
434 CLabel construct_result(a); | |
435 a->Bind(&successful_match); | 408 a->Bind(&successful_match); |
436 { | 409 { |
437 a->GotoUnless(should_update_last_index, &construct_result); | 410 a->GotoUnless(should_update_last_index, &out); |
438 | 411 |
439 // Update the new last index from {match_indices}. | 412 // Update the new last index from {match_indices}. |
440 Node* const new_lastindex = a->LoadFixedArrayElement( | 413 Node* const new_lastindex = a->LoadFixedArrayElement( |
441 match_indices, | 414 match_indices, |
442 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); | 415 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); |
443 | 416 |
444 StoreLastIndex(a, context, has_initialmap, regexp, new_lastindex); | 417 StoreLastIndex(a, context, regexp, new_lastindex, is_fastpath); |
445 a->Goto(&construct_result); | 418 a->Goto(&out); |
419 } | |
446 | 420 |
447 a->Bind(&construct_result); | 421 a->Bind(&out); |
448 { | 422 return var_result.value(); |
449 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, | 423 } |
450 match_indices, string); | 424 |
451 var_result.Bind(result); | 425 // ES#sec-regexp.prototype.exec |
452 a->Goto(&out); | 426 // RegExp.prototype.exec ( string ) |
453 } | 427 Node* Generate_RegExpPrototypeExecBody(CodeStubAssembler* a, |
Igor Sheludko
2016/11/30 22:12:08
I think you can drop the Generate_ prefix for read
jgruber
2016/12/01 09:09:09
Done.
| |
428 Node* const context, Node* const regexp, | |
429 Node* const string, | |
430 const bool is_fastpath) { | |
431 Isolate* const isolate = a->isolate(); | |
432 Node* const null = a->NullConstant(); | |
433 | |
434 CVariable var_result(a, MachineRepresentation::kTagged); | |
435 | |
436 CLabel if_didnotmatch(a), out(a); | |
437 Node* const indices_or_null = Generate_RegExpPrototypeExecBodyWithoutResult( | |
438 a, context, regexp, string, &if_didnotmatch, is_fastpath); | |
439 | |
440 // Successful match. | |
441 { | |
442 Node* const match_indices = indices_or_null; | |
443 Node* const result = ConstructNewResultFromMatchInfo(isolate, a, context, | |
444 match_indices, string); | |
445 var_result.Bind(result); | |
446 a->Goto(&out); | |
447 } | |
448 | |
449 a->Bind(&if_didnotmatch); | |
450 { | |
451 var_result.Bind(null); | |
452 a->Goto(&out); | |
454 } | 453 } |
455 | 454 |
456 a->Bind(&out); | 455 a->Bind(&out); |
457 return var_result.value(); | 456 return var_result.value(); |
458 } | 457 } |
459 | 458 |
460 } // namespace | 459 } // namespace |
461 | 460 |
462 // ES#sec-regexp.prototype.exec | |
463 // RegExp.prototype.exec ( string ) | |
464 void Builtins::Generate_RegExpPrototypeExec(CodeAssemblerState* state) { | |
465 CodeStubAssembler a(state); | |
466 | |
467 Node* const maybe_receiver = a.Parameter(0); | |
468 Node* const maybe_string = a.Parameter(1); | |
469 Node* const context = a.Parameter(4); | |
470 | |
471 Node* const result = | |
472 RegExpPrototypeExecInternal(&a, context, maybe_receiver, maybe_string); | |
473 a.Return(result); | |
474 } | |
475 | |
476 namespace { | 461 namespace { |
477 | 462 |
478 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, | 463 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, |
479 Node* context, Node* value, | 464 Node* context, Node* value, |
480 MessageTemplate::Template msg_template, | 465 MessageTemplate::Template msg_template, |
481 char const* method_name) { | 466 char const* method_name) { |
482 CLabel out(a), throw_exception(a, CLabel::kDeferred); | 467 CLabel out(a), throw_exception(a, CLabel::kDeferred); |
483 CVariable var_value_map(a, MachineRepresentation::kTagged); | 468 CVariable var_value_map(a, MachineRepresentation::kTagged); |
484 | 469 |
485 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); | 470 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
555 Node* const native_context = a->LoadNativeContext(context); | 540 Node* const native_context = a->LoadNativeContext(context); |
556 Node* const initial_regexp_result_map = | 541 Node* const initial_regexp_result_map = |
557 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); | 542 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); |
558 | 543 |
559 a->Branch(a->WordEqual(map, initial_regexp_result_map), if_isunmodified, | 544 a->Branch(a->WordEqual(map, initial_regexp_result_map), if_isunmodified, |
560 if_ismodified); | 545 if_ismodified); |
561 } | 546 } |
562 | 547 |
563 } // namespace | 548 } // namespace |
564 | 549 |
550 // ES#sec-regexp.prototype.exec | |
551 // RegExp.prototype.exec ( string ) | |
552 void Builtins::Generate_RegExpPrototypeExec(CodeAssemblerState* state) { | |
553 CodeStubAssembler a(state); | |
554 | |
555 Node* const maybe_receiver = a.Parameter(0); | |
556 Node* const maybe_string = a.Parameter(1); | |
557 Node* const context = a.Parameter(4); | |
558 | |
559 // Ensure {maybe_receiver} is a JSRegExp. | |
560 Node* const regexp_map = a.ThrowIfNotInstanceType( | |
561 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); | |
562 Node* const receiver = maybe_receiver; | |
563 | |
564 // Convert {maybe_string} to a String. | |
565 Node* const string = a.ToString(context, maybe_string); | |
566 | |
567 CLabel if_isfastpath(&a), if_isslowpath(&a); | |
568 a.Branch(IsInitialRegExpMap(&a, context, regexp_map), &if_isfastpath, | |
569 &if_isslowpath); | |
570 | |
571 a.Bind(&if_isfastpath); | |
572 { | |
573 Node* const result = | |
574 Generate_RegExpPrototypeExecBody(&a, context, receiver, string, true); | |
575 a.Return(result); | |
576 } | |
577 | |
578 a.Bind(&if_isslowpath); | |
579 { | |
580 Node* const result = | |
581 Generate_RegExpPrototypeExecBody(&a, context, receiver, string, false); | |
582 a.Return(result); | |
583 } | |
584 } | |
585 | |
565 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { | 586 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { |
566 CodeStubAssembler a(state); | 587 CodeStubAssembler a(state); |
567 | 588 |
568 Node* const receiver = a.Parameter(0); | 589 Node* const receiver = a.Parameter(0); |
569 Node* const context = a.Parameter(3); | 590 Node* const context = a.Parameter(3); |
570 | 591 |
571 Isolate* isolate = a.isolate(); | 592 Isolate* isolate = a.isolate(); |
572 Node* const int_zero = a.IntPtrConstant(0); | 593 Node* const int_zero = a.IntPtrConstant(0); |
573 Node* const int_one = a.IntPtrConstant(1); | 594 Node* const int_one = a.IntPtrConstant(1); |
574 | 595 |
(...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1026 namespace { | 1047 namespace { |
1027 | 1048 |
1028 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) | 1049 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) |
1029 Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv, | 1050 Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv, |
1030 Node* string) { | 1051 Node* string) { |
1031 Isolate* isolate = a->isolate(); | 1052 Isolate* isolate = a->isolate(); |
1032 | 1053 |
1033 Node* const null = a->NullConstant(); | 1054 Node* const null = a->NullConstant(); |
1034 | 1055 |
1035 CVariable var_result(a, MachineRepresentation::kTagged); | 1056 CVariable var_result(a, MachineRepresentation::kTagged); |
1036 CLabel out(a), call_builtin_exec(a), slow_path(a, CLabel::kDeferred); | 1057 CLabel out(a), if_isfastpath(a), if_isslowpath(a); |
1037 | 1058 |
1038 Node* const map = a->LoadMap(recv); | 1059 Node* const map = a->LoadMap(recv); |
1039 BranchIfFastPath(a, context, map, &call_builtin_exec, &slow_path); | 1060 BranchIfFastPath(a, context, map, &if_isfastpath, &if_isslowpath); |
1040 | 1061 |
1041 a->Bind(&call_builtin_exec); | 1062 a->Bind(&if_isfastpath); |
1042 { | 1063 { |
1043 Node* const result = RegExpPrototypeExecInternal(a, context, recv, string); | 1064 Node* const result = |
1065 Generate_RegExpPrototypeExecBody(a, context, recv, string, true); | |
1044 var_result.Bind(result); | 1066 var_result.Bind(result); |
1045 a->Goto(&out); | 1067 a->Goto(&out); |
1046 } | 1068 } |
1047 | 1069 |
1048 a->Bind(&slow_path); | 1070 a->Bind(&if_isslowpath); |
1049 { | 1071 { |
1050 // Take the slow path of fetching the exec property, calling it, and | 1072 // Take the slow path of fetching the exec property, calling it, and |
1051 // verifying its return value. | 1073 // verifying its return value. |
1052 | 1074 |
1053 // Get the exec property. | 1075 // Get the exec property. |
1054 Node* const name = a->HeapConstant(isolate->factory()->exec_string()); | 1076 Node* const name = a->HeapConstant(isolate->factory()->exec_string()); |
1055 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | 1077 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
1056 Node* const exec = a->CallStub(getproperty_callable, context, recv, name); | 1078 Node* const exec = a->CallStub(getproperty_callable, context, recv, name); |
1057 | 1079 |
1058 // Is {exec} callable? | 1080 // Is {exec} callable? |
(...skipping 16 matching lines...) Expand all Loading... | |
1075 ThrowIfNotJSReceiver(a, isolate, context, result, | 1097 ThrowIfNotJSReceiver(a, isolate, context, result, |
1076 MessageTemplate::kInvalidRegExpExecResult, "unused"); | 1098 MessageTemplate::kInvalidRegExpExecResult, "unused"); |
1077 | 1099 |
1078 a->Goto(&out); | 1100 a->Goto(&out); |
1079 } | 1101 } |
1080 | 1102 |
1081 a->Bind(&if_isnotcallable); | 1103 a->Bind(&if_isnotcallable); |
1082 { | 1104 { |
1083 a->ThrowIfNotInstanceType(context, recv, JS_REGEXP_TYPE, | 1105 a->ThrowIfNotInstanceType(context, recv, JS_REGEXP_TYPE, |
1084 "RegExp.prototype.exec"); | 1106 "RegExp.prototype.exec"); |
1085 a->Goto(&call_builtin_exec); | 1107 |
1108 Node* const result = | |
1109 Generate_RegExpPrototypeExecBody(a, context, recv, string, false); | |
1110 var_result.Bind(result); | |
1111 a->Goto(&out); | |
1086 } | 1112 } |
1087 } | 1113 } |
1088 | 1114 |
1089 a->Bind(&out); | 1115 a->Bind(&out); |
1090 return var_result.value(); | 1116 return var_result.value(); |
1091 } | 1117 } |
1092 | 1118 |
1093 } // namespace | 1119 } // namespace |
1094 | 1120 |
1095 // ES#sec-regexp.prototype.test | 1121 // ES#sec-regexp.prototype.test |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1300 | 1326 |
1301 Node* const regexp = receiver; | 1327 Node* const regexp = receiver; |
1302 Node* const is_global = | 1328 Node* const is_global = |
1303 FlagGetter(a, context, regexp, JSRegExp::kGlobal, is_fastpath); | 1329 FlagGetter(a, context, regexp, JSRegExp::kGlobal, is_fastpath); |
1304 | 1330 |
1305 CLabel if_isglobal(a), if_isnotglobal(a); | 1331 CLabel if_isglobal(a), if_isnotglobal(a); |
1306 a->Branch(is_global, &if_isglobal, &if_isnotglobal); | 1332 a->Branch(is_global, &if_isglobal, &if_isnotglobal); |
1307 | 1333 |
1308 a->Bind(&if_isnotglobal); | 1334 a->Bind(&if_isnotglobal); |
1309 { | 1335 { |
1310 Node* const result = | 1336 Node* const result = is_fastpath ? Generate_RegExpPrototypeExecBody( |
1311 is_fastpath ? RegExpPrototypeExecInternal(a, context, regexp, string) | 1337 a, context, regexp, string, true) |
1312 : RegExpExec(a, context, regexp, string); | 1338 : RegExpExec(a, context, regexp, string); |
1313 a->Return(result); | 1339 a->Return(result); |
1314 } | 1340 } |
1315 | 1341 |
1316 a->Bind(&if_isglobal); | 1342 a->Bind(&if_isglobal); |
1317 { | 1343 { |
1318 Node* const is_unicode = | 1344 Node* const is_unicode = |
1319 FlagGetter(a, context, regexp, JSRegExp::kUnicode, is_fastpath); | 1345 FlagGetter(a, context, regexp, JSRegExp::kUnicode, is_fastpath); |
1320 | 1346 |
1321 if (is_fastpath) { | 1347 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); |
1322 FastStoreLastIndex(a, context, regexp, smi_zero); | |
1323 } else { | |
1324 SlowStoreLastIndex(a, context, regexp, smi_zero); | |
1325 } | |
1326 | 1348 |
1327 // Allocate an array to store the resulting match strings. | 1349 // Allocate an array to store the resulting match strings. |
1328 | 1350 |
1329 GrowableFixedArray array(a); | 1351 GrowableFixedArray array(a); |
1330 | 1352 |
1331 // Loop preparations. Within the loop, collect results from RegExpExec | 1353 // Loop preparations. Within the loop, collect results from RegExpExec |
1332 // and store match strings in the array. | 1354 // and store match strings in the array. |
1333 | 1355 |
1334 CVariable* vars[] = {array.var_array(), array.var_length(), | 1356 CVariable* vars[] = {array.var_array(), array.var_length(), |
1335 array.var_capacity()}; | 1357 array.var_capacity()}; |
1336 CLabel loop(a, 3, vars), out(a); | 1358 CLabel loop(a, 3, vars), out(a); |
1337 a->Goto(&loop); | 1359 a->Goto(&loop); |
1338 | 1360 |
1339 a->Bind(&loop); | 1361 a->Bind(&loop); |
1340 { | 1362 { |
1341 Node* const result = | 1363 Node* const result = is_fastpath ? Generate_RegExpPrototypeExecBody( |
1342 is_fastpath ? RegExpPrototypeExecInternal(a, context, regexp, string) | 1364 a, context, regexp, string, true) |
1343 : RegExpExec(a, context, regexp, string); | 1365 : RegExpExec(a, context, regexp, string); |
1344 | 1366 |
1345 CLabel if_didmatch(a), if_didnotmatch(a); | 1367 CLabel if_didmatch(a), if_didnotmatch(a); |
1346 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &if_didmatch); | 1368 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &if_didmatch); |
1347 | 1369 |
1348 a->Bind(&if_didnotmatch); | 1370 a->Bind(&if_didnotmatch); |
1349 { | 1371 { |
1350 // Return null if there were no matches, otherwise just exit the loop. | 1372 // Return null if there were no matches, otherwise just exit the loop. |
1351 a->GotoUnless(a->IntPtrEqual(array.length(), int_zero), &out); | 1373 a->GotoUnless(a->IntPtrEqual(array.length(), int_zero), &out); |
1352 a->Return(null); | 1374 a->Return(null); |
1353 } | 1375 } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1408 | 1430 |
1409 // Store the match, growing the fixed array if needed. | 1431 // Store the match, growing the fixed array if needed. |
1410 | 1432 |
1411 array.Push(match); | 1433 array.Push(match); |
1412 | 1434 |
1413 // Advance last index if the match is the empty string. | 1435 // Advance last index if the match is the empty string. |
1414 | 1436 |
1415 Node* const match_length = a->LoadStringLength(match); | 1437 Node* const match_length = a->LoadStringLength(match); |
1416 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop); | 1438 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop); |
1417 | 1439 |
1418 Node* last_index = is_fastpath ? FastLoadLastIndex(a, context, regexp) | 1440 Node* last_index = LoadLastIndex(a, context, regexp, is_fastpath); |
1419 : SlowLoadLastIndex(a, context, regexp); | |
1420 | 1441 |
1421 Callable tolength_callable = CodeFactory::ToLength(isolate); | 1442 Callable tolength_callable = CodeFactory::ToLength(isolate); |
1422 last_index = a->CallStub(tolength_callable, context, last_index); | 1443 last_index = a->CallStub(tolength_callable, context, last_index); |
1423 | 1444 |
1424 Node* const new_last_index = | 1445 Node* const new_last_index = |
1425 AdvanceStringIndex(a, string, last_index, is_unicode); | 1446 AdvanceStringIndex(a, string, last_index, is_unicode); |
1426 | 1447 |
1427 if (is_fastpath) { | 1448 StoreLastIndex(a, context, regexp, new_last_index, is_fastpath); |
1428 FastStoreLastIndex(a, context, regexp, new_last_index); | |
1429 } else { | |
1430 SlowStoreLastIndex(a, context, regexp, new_last_index); | |
1431 } | |
1432 | 1449 |
1433 a->Goto(&loop); | 1450 a->Goto(&loop); |
1434 } | 1451 } |
1435 } | 1452 } |
1436 | 1453 |
1437 a->Bind(&out); | 1454 a->Bind(&out); |
1438 { | 1455 { |
1439 // Wrap the match in a JSArray. | 1456 // Wrap the match in a JSArray. |
1440 | 1457 |
1441 Node* const result = array.ToJSArray(context); | 1458 Node* const result = array.ToJSArray(context); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1479 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, | 1496 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, |
1480 Node* const receiver, | 1497 Node* const receiver, |
1481 Node* const string, Node* const context, | 1498 Node* const string, Node* const context, |
1482 bool is_fastpath) { | 1499 bool is_fastpath) { |
1483 Isolate* const isolate = a->isolate(); | 1500 Isolate* const isolate = a->isolate(); |
1484 | 1501 |
1485 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1502 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
1486 | 1503 |
1487 // Grab the initial value of last index. | 1504 // Grab the initial value of last index. |
1488 Node* const previous_last_index = | 1505 Node* const previous_last_index = |
1489 is_fastpath ? FastLoadLastIndex(a, context, receiver) | 1506 LoadLastIndex(a, context, receiver, is_fastpath); |
1490 : SlowLoadLastIndex(a, context, receiver); | |
1491 | 1507 |
1492 // Ensure last index is 0. | 1508 // Ensure last index is 0. |
1493 if (is_fastpath) { | 1509 if (is_fastpath) { |
1494 FastStoreLastIndex(a, context, receiver, smi_zero); | 1510 FastStoreLastIndex(a, receiver, smi_zero); |
1495 } else { | 1511 } else { |
1496 CLabel next(a); | 1512 CLabel next(a); |
1497 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); | 1513 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); |
1498 | 1514 |
1499 SlowStoreLastIndex(a, context, receiver, smi_zero); | 1515 SlowStoreLastIndex(a, context, receiver, smi_zero); |
1500 a->Goto(&next); | 1516 a->Goto(&next); |
1501 a->Bind(&next); | 1517 a->Bind(&next); |
1502 } | 1518 } |
1503 | 1519 |
1504 // Call exec. | 1520 // Call exec. |
1505 Node* const match_indices = | 1521 Node* const match_indices = |
1506 is_fastpath ? RegExpPrototypeExecInternal(a, context, receiver, string) | 1522 is_fastpath |
1507 : RegExpExec(a, context, receiver, string); | 1523 ? Generate_RegExpPrototypeExecBody(a, context, receiver, string, true) |
1524 : RegExpExec(a, context, receiver, string); | |
1508 | 1525 |
1509 // Reset last index if necessary. | 1526 // Reset last index if necessary. |
1510 if (is_fastpath) { | 1527 if (is_fastpath) { |
1511 FastStoreLastIndex(a, context, receiver, previous_last_index); | 1528 FastStoreLastIndex(a, receiver, previous_last_index); |
1512 } else { | 1529 } else { |
1513 CLabel next(a); | 1530 CLabel next(a); |
1514 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); | 1531 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); |
1515 | 1532 |
1516 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), | 1533 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), |
1517 &next); | 1534 &next); |
1518 | 1535 |
1519 SlowStoreLastIndex(a, context, receiver, previous_last_index); | 1536 SlowStoreLastIndex(a, context, receiver, previous_last_index); |
1520 a->Goto(&next); | 1537 a->Goto(&next); |
1521 a->Bind(&next); | 1538 a->Bind(&next); |
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1927 Node* const int_zero = a->IntPtrConstant(0); | 1944 Node* const int_zero = a->IntPtrConstant(0); |
1928 Node* const int_one = a->IntPtrConstant(1); | 1945 Node* const int_one = a->IntPtrConstant(1); |
1929 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1946 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
1930 | 1947 |
1931 Node* const native_context = a->LoadNativeContext(context); | 1948 Node* const native_context = a->LoadNativeContext(context); |
1932 | 1949 |
1933 CLabel out(a); | 1950 CLabel out(a); |
1934 CVariable var_result(a, MachineRepresentation::kTagged); | 1951 CVariable var_result(a, MachineRepresentation::kTagged); |
1935 | 1952 |
1936 // Set last index to 0. | 1953 // Set last index to 0. |
1937 FastStoreLastIndex(a, context, regexp, smi_zero); | 1954 FastStoreLastIndex(a, regexp, smi_zero); |
1938 | 1955 |
1939 // Allocate {result_array}. | 1956 // Allocate {result_array}. |
1940 Node* result_array; | 1957 Node* result_array; |
1941 { | 1958 { |
1942 ElementsKind kind = FAST_ELEMENTS; | 1959 ElementsKind kind = FAST_ELEMENTS; |
1943 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); | 1960 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); |
1944 Node* const capacity = a->IntPtrConstant(16); | 1961 Node* const capacity = a->IntPtrConstant(16); |
1945 Node* const length = smi_zero; | 1962 Node* const length = smi_zero; |
1946 Node* const allocation_site = nullptr; | 1963 Node* const allocation_site = nullptr; |
1947 ParameterMode capacity_mode = CodeStubAssembler::INTPTR_PARAMETERS; | 1964 ParameterMode capacity_mode = CodeStubAssembler::INTPTR_PARAMETERS; |
1948 | 1965 |
1949 result_array = a->AllocateJSArray(kind, array_map, capacity, length, | 1966 result_array = a->AllocateJSArray(kind, array_map, capacity, length, |
1950 allocation_site, capacity_mode); | 1967 allocation_site, capacity_mode); |
1951 } | 1968 } |
1952 | 1969 |
1953 // Call into runtime for RegExpExecMultiple. | 1970 // Call into runtime for RegExpExecMultiple. |
1954 Node* last_match_info = a->LoadContextElement( | 1971 Node* last_match_info = a->LoadContextElement( |
1955 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 1972 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
1956 Node* const res = | 1973 Node* const res = |
1957 a->CallRuntime(Runtime::kRegExpExecMultiple, context, regexp, | 1974 a->CallRuntime(Runtime::kRegExpExecMultiple, context, regexp, |
1958 subject_string, last_match_info, result_array); | 1975 subject_string, last_match_info, result_array); |
1959 | 1976 |
1960 // Reset last index to 0. | 1977 // Reset last index to 0. |
1961 FastStoreLastIndex(a, context, regexp, smi_zero); | 1978 FastStoreLastIndex(a, regexp, smi_zero); |
1962 | 1979 |
1963 // If no matches, return the subject string. | 1980 // If no matches, return the subject string. |
1964 var_result.Bind(subject_string); | 1981 var_result.Bind(subject_string); |
1965 a->GotoIf(a->WordEqual(res, null), &out); | 1982 a->GotoIf(a->WordEqual(res, null), &out); |
1966 | 1983 |
1967 // Reload last match info since it might have changed. | 1984 // Reload last match info since it might have changed. |
1968 last_match_info = a->LoadContextElement( | 1985 last_match_info = a->LoadContextElement( |
1969 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 1986 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
1970 | 1987 |
1971 Node* const res_length = a->LoadJSArrayLength(res); | 1988 Node* const res_length = a->LoadJSArrayLength(res); |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2154 // Is {regexp} global? | 2171 // Is {regexp} global? |
2155 CLabel if_isglobal(a), if_isnonglobal(a); | 2172 CLabel if_isglobal(a), if_isnonglobal(a); |
2156 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 2173 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
2157 Node* const is_global = | 2174 Node* const is_global = |
2158 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal)); | 2175 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal)); |
2159 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal); | 2176 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal); |
2160 | 2177 |
2161 a->Bind(&if_isglobal); | 2178 a->Bind(&if_isglobal); |
2162 { | 2179 { |
2163 // Hand off global regexps to runtime. | 2180 // Hand off global regexps to runtime. |
2164 FastStoreLastIndex(a, context, regexp, smi_zero); | 2181 FastStoreLastIndex(a, regexp, smi_zero); |
2165 Node* const result = | 2182 Node* const result = |
2166 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, | 2183 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, |
2167 subject_string, regexp, replace_string, last_match_info); | 2184 subject_string, regexp, replace_string, last_match_info); |
2168 var_result.Bind(result); | 2185 var_result.Bind(result); |
2169 a->Goto(&out); | 2186 a->Goto(&out); |
2170 } | 2187 } |
2171 | 2188 |
2172 a->Bind(&if_isnonglobal); | 2189 a->Bind(&if_isnonglobal); |
2173 { | 2190 { |
2174 // Run exec, then manually construct the resulting string. | 2191 // Run exec, then manually construct the resulting string. |
2175 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 2192 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
2176 Node* const match_indices = | 2193 Node* const match_indices = |
2177 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero, | 2194 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero, |
2178 last_match_info); | 2195 last_match_info); |
2179 | 2196 |
2180 CLabel if_matched(a), if_didnotmatch(a); | 2197 CLabel if_matched(a), if_didnotmatch(a); |
2181 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); | 2198 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); |
2182 | 2199 |
2183 a->Bind(&if_didnotmatch); | 2200 a->Bind(&if_didnotmatch); |
2184 { | 2201 { |
2185 FastStoreLastIndex(a, context, regexp, smi_zero); | 2202 FastStoreLastIndex(a, regexp, smi_zero); |
2186 var_result.Bind(subject_string); | 2203 var_result.Bind(subject_string); |
2187 a->Goto(&out); | 2204 a->Goto(&out); |
2188 } | 2205 } |
2189 | 2206 |
2190 a->Bind(&if_matched); | 2207 a->Bind(&if_matched); |
2191 { | 2208 { |
2192 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 2209 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; |
2193 | 2210 |
2194 Node* const subject_start = smi_zero; | 2211 Node* const subject_start = smi_zero; |
2195 Node* const match_start = a->LoadFixedArrayElement( | 2212 Node* const match_start = a->LoadFixedArrayElement( |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2365 a.Bind(&if_matched); | 2382 a.Bind(&if_matched); |
2366 { | 2383 { |
2367 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, | 2384 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, |
2368 match_indices, string); | 2385 match_indices, string); |
2369 a.Return(result); | 2386 a.Return(result); |
2370 } | 2387 } |
2371 } | 2388 } |
2372 | 2389 |
2373 } // namespace internal | 2390 } // namespace internal |
2374 } // namespace v8 | 2391 } // namespace v8 |
OLD | NEW |