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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 // ES#sec-regexp.prototype.exec |
330 // RegExp.prototype.exec ( string ) | 301 // RegExp.prototype.exec ( string ) |
331 Node* RegExpPrototypeExecInternal(CodeStubAssembler* a, Node* context, | 302 // Implements the core of RegExp.prototype.exec but without actually |
332 Node* maybe_receiver, Node* maybe_string) { | 303 // constructing the JSRegExpResult. Returns either null (if the RegExp did not |
| 304 // match) or a fixed array containing match indices as returned by |
| 305 // RegExpExecStub. |
| 306 Node* RegExpPrototypeExecBodyWithoutResult( |
| 307 CodeStubAssembler* a, Node* const context, Node* const regexp, |
| 308 Node* const string, CLabel* if_didnotmatch, const bool is_fastpath) { |
333 Isolate* const isolate = a->isolate(); | 309 Isolate* const isolate = a->isolate(); |
334 | 310 |
335 Node* const null = a->NullConstant(); | 311 Node* const null = a->NullConstant(); |
336 Node* const int_zero = a->IntPtrConstant(0); | 312 Node* const int_zero = a->IntPtrConstant(0); |
337 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 313 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
338 | 314 |
| 315 if (!is_fastpath) { |
| 316 a->ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, |
| 317 "RegExp.prototype.exec"); |
| 318 } |
| 319 |
| 320 CSA_ASSERT(a, a->IsStringInstanceType(a->LoadInstanceType(string))); |
| 321 CSA_ASSERT(a, a->HasInstanceType(regexp, JS_REGEXP_TYPE)); |
| 322 |
339 CVariable var_result(a, MachineRepresentation::kTagged); | 323 CVariable var_result(a, MachineRepresentation::kTagged); |
340 CLabel out(a); | 324 CLabel out(a); |
341 | 325 |
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); | 326 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); | 327 Node* const string_length = a->LoadStringLength(string); |
359 | 328 |
360 // Check whether the regexp is global or sticky, which determines whether we | 329 // Check whether the regexp is global or sticky, which determines whether we |
361 // update last index later on. | 330 // update last index later on. |
362 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 331 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
363 Node* const is_global_or_sticky = | 332 Node* const is_global_or_sticky = |
364 a->WordAnd(a->SmiUntag(flags), | 333 a->WordAnd(a->SmiUntag(flags), |
365 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); | 334 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); |
366 Node* const should_update_last_index = | 335 Node* const should_update_last_index = |
367 a->WordNotEqual(is_global_or_sticky, int_zero); | 336 a->WordNotEqual(is_global_or_sticky, int_zero); |
368 | 337 |
369 // Grab and possibly update last index. | 338 // Grab and possibly update last index. |
370 CLabel run_exec(a); | 339 CLabel run_exec(a); |
371 CVariable var_lastindex(a, MachineRepresentation::kTagged); | 340 CVariable var_lastindex(a, MachineRepresentation::kTagged); |
372 { | 341 { |
373 CLabel if_doupdate(a), if_dontupdate(a); | 342 CLabel if_doupdate(a), if_dontupdate(a); |
374 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate); | 343 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate); |
375 | 344 |
376 a->Bind(&if_doupdate); | 345 a->Bind(&if_doupdate); |
377 { | 346 { |
378 Node* const regexp_lastindex = | 347 Node* const regexp_lastindex = |
379 LoadLastIndex(a, context, has_initialmap, regexp); | 348 LoadLastIndex(a, context, regexp, is_fastpath); |
| 349 var_lastindex.Bind(regexp_lastindex); |
380 | 350 |
381 Callable tolength_callable = CodeFactory::ToLength(isolate); | 351 // Omit ToLength if lastindex is a non-negative smi. |
382 Node* const lastindex = | 352 { |
383 a->CallStub(tolength_callable, context, regexp_lastindex); | 353 CLabel call_tolength(a, CLabel::kDeferred), next(a); |
384 var_lastindex.Bind(lastindex); | 354 a->Branch(a->WordIsPositiveSmi(regexp_lastindex), &next, |
| 355 &call_tolength); |
| 356 |
| 357 a->Bind(&call_tolength); |
| 358 { |
| 359 Callable tolength_callable = CodeFactory::ToLength(isolate); |
| 360 var_lastindex.Bind( |
| 361 a->CallStub(tolength_callable, context, regexp_lastindex)); |
| 362 a->Goto(&next); |
| 363 } |
| 364 |
| 365 a->Bind(&next); |
| 366 } |
| 367 |
| 368 Node* const lastindex = var_lastindex.value(); |
385 | 369 |
386 CLabel if_isoob(a, CLabel::kDeferred); | 370 CLabel if_isoob(a, CLabel::kDeferred); |
387 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob); | 371 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob); |
388 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob); | 372 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob); |
389 a->Goto(&run_exec); | 373 a->Goto(&run_exec); |
390 | 374 |
391 a->Bind(&if_isoob); | 375 a->Bind(&if_isoob); |
392 { | 376 { |
393 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); | 377 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); |
394 var_result.Bind(null); | 378 var_result.Bind(null); |
395 a->Goto(&out); | 379 a->Goto(if_didnotmatch); |
396 } | 380 } |
397 } | 381 } |
398 | 382 |
399 a->Bind(&if_dontupdate); | 383 a->Bind(&if_dontupdate); |
400 { | 384 { |
401 var_lastindex.Bind(smi_zero); | 385 var_lastindex.Bind(smi_zero); |
402 a->Goto(&run_exec); | 386 a->Goto(&run_exec); |
403 } | 387 } |
404 } | 388 } |
405 | 389 |
406 Node* match_indices; | 390 Node* match_indices; |
407 CLabel successful_match(a); | 391 CLabel successful_match(a); |
408 a->Bind(&run_exec); | 392 a->Bind(&run_exec); |
409 { | 393 { |
410 // Get last match info from the context. | 394 // Get last match info from the context. |
411 Node* const last_match_info = a->LoadContextElement( | 395 Node* const last_match_info = a->LoadContextElement( |
412 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 396 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
413 | 397 |
414 // Call the exec stub. | 398 // Call the exec stub. |
415 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 399 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
416 match_indices = a->CallStub(exec_callable, context, regexp, string, | 400 match_indices = a->CallStub(exec_callable, context, regexp, string, |
417 var_lastindex.value(), last_match_info); | 401 var_lastindex.value(), last_match_info); |
| 402 var_result.Bind(match_indices); |
418 | 403 |
419 // {match_indices} is either null or the RegExpMatchInfo array. | 404 // {match_indices} is either null or the RegExpMatchInfo array. |
420 // Return early if exec failed, possibly updating last index. | 405 // Return early if exec failed, possibly updating last index. |
421 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); | 406 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); |
422 | 407 |
423 CLabel return_null(a); | 408 a->GotoUnless(should_update_last_index, if_didnotmatch); |
424 a->GotoUnless(should_update_last_index, &return_null); | |
425 | 409 |
426 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); | 410 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); |
427 a->Goto(&return_null); | 411 a->Goto(if_didnotmatch); |
428 | |
429 a->Bind(&return_null); | |
430 var_result.Bind(null); | |
431 a->Goto(&out); | |
432 } | 412 } |
433 | 413 |
434 CLabel construct_result(a); | |
435 a->Bind(&successful_match); | 414 a->Bind(&successful_match); |
436 { | 415 { |
437 a->GotoUnless(should_update_last_index, &construct_result); | 416 a->GotoUnless(should_update_last_index, &out); |
438 | 417 |
439 // Update the new last index from {match_indices}. | 418 // Update the new last index from {match_indices}. |
440 Node* const new_lastindex = a->LoadFixedArrayElement( | 419 Node* const new_lastindex = a->LoadFixedArrayElement( |
441 match_indices, | 420 match_indices, |
442 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); | 421 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); |
443 | 422 |
444 StoreLastIndex(a, context, has_initialmap, regexp, new_lastindex); | 423 StoreLastIndex(a, context, regexp, new_lastindex, is_fastpath); |
445 a->Goto(&construct_result); | 424 a->Goto(&out); |
| 425 } |
446 | 426 |
447 a->Bind(&construct_result); | 427 a->Bind(&out); |
448 { | 428 return var_result.value(); |
449 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, | 429 } |
450 match_indices, string); | 430 |
451 var_result.Bind(result); | 431 // ES#sec-regexp.prototype.exec |
452 a->Goto(&out); | 432 // RegExp.prototype.exec ( string ) |
453 } | 433 Node* RegExpPrototypeExecBody(CodeStubAssembler* a, Node* const context, |
| 434 Node* const regexp, Node* const string, |
| 435 const bool is_fastpath) { |
| 436 Isolate* const isolate = a->isolate(); |
| 437 Node* const null = a->NullConstant(); |
| 438 |
| 439 CVariable var_result(a, MachineRepresentation::kTagged); |
| 440 |
| 441 CLabel if_didnotmatch(a), out(a); |
| 442 Node* const indices_or_null = RegExpPrototypeExecBodyWithoutResult( |
| 443 a, context, regexp, string, &if_didnotmatch, is_fastpath); |
| 444 |
| 445 // Successful match. |
| 446 { |
| 447 Node* const match_indices = indices_or_null; |
| 448 Node* const result = ConstructNewResultFromMatchInfo(isolate, a, context, |
| 449 match_indices, string); |
| 450 var_result.Bind(result); |
| 451 a->Goto(&out); |
| 452 } |
| 453 |
| 454 a->Bind(&if_didnotmatch); |
| 455 { |
| 456 var_result.Bind(null); |
| 457 a->Goto(&out); |
454 } | 458 } |
455 | 459 |
456 a->Bind(&out); | 460 a->Bind(&out); |
457 return var_result.value(); | 461 return var_result.value(); |
458 } | 462 } |
459 | 463 |
460 } // namespace | 464 } // namespace |
461 | 465 |
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 { | 466 namespace { |
477 | 467 |
478 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, | 468 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, |
479 Node* context, Node* value, | 469 Node* context, Node* value, |
480 MessageTemplate::Template msg_template, | 470 MessageTemplate::Template msg_template, |
481 char const* method_name) { | 471 char const* method_name) { |
482 CLabel out(a), throw_exception(a, CLabel::kDeferred); | 472 CLabel out(a), throw_exception(a, CLabel::kDeferred); |
483 CVariable var_value_map(a, MachineRepresentation::kTagged); | 473 CVariable var_value_map(a, MachineRepresentation::kTagged); |
484 | 474 |
485 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); | 475 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); | 545 Node* const native_context = a->LoadNativeContext(context); |
556 Node* const initial_regexp_result_map = | 546 Node* const initial_regexp_result_map = |
557 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); | 547 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); |
558 | 548 |
559 a->Branch(a->WordEqual(map, initial_regexp_result_map), if_isunmodified, | 549 a->Branch(a->WordEqual(map, initial_regexp_result_map), if_isunmodified, |
560 if_ismodified); | 550 if_ismodified); |
561 } | 551 } |
562 | 552 |
563 } // namespace | 553 } // namespace |
564 | 554 |
| 555 // ES#sec-regexp.prototype.exec |
| 556 // RegExp.prototype.exec ( string ) |
| 557 void Builtins::Generate_RegExpPrototypeExec(CodeAssemblerState* state) { |
| 558 CodeStubAssembler a(state); |
| 559 |
| 560 Node* const maybe_receiver = a.Parameter(0); |
| 561 Node* const maybe_string = a.Parameter(1); |
| 562 Node* const context = a.Parameter(4); |
| 563 |
| 564 // Ensure {maybe_receiver} is a JSRegExp. |
| 565 Node* const regexp_map = a.ThrowIfNotInstanceType( |
| 566 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); |
| 567 Node* const receiver = maybe_receiver; |
| 568 |
| 569 // Convert {maybe_string} to a String. |
| 570 Node* const string = a.ToString(context, maybe_string); |
| 571 |
| 572 CLabel if_isfastpath(&a), if_isslowpath(&a); |
| 573 a.Branch(IsInitialRegExpMap(&a, context, regexp_map), &if_isfastpath, |
| 574 &if_isslowpath); |
| 575 |
| 576 a.Bind(&if_isfastpath); |
| 577 { |
| 578 Node* const result = |
| 579 RegExpPrototypeExecBody(&a, context, receiver, string, true); |
| 580 a.Return(result); |
| 581 } |
| 582 |
| 583 a.Bind(&if_isslowpath); |
| 584 { |
| 585 Node* const result = |
| 586 RegExpPrototypeExecBody(&a, context, receiver, string, false); |
| 587 a.Return(result); |
| 588 } |
| 589 } |
| 590 |
565 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { | 591 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { |
566 CodeStubAssembler a(state); | 592 CodeStubAssembler a(state); |
567 | 593 |
568 Node* const receiver = a.Parameter(0); | 594 Node* const receiver = a.Parameter(0); |
569 Node* const context = a.Parameter(3); | 595 Node* const context = a.Parameter(3); |
570 | 596 |
571 Isolate* isolate = a.isolate(); | 597 Isolate* isolate = a.isolate(); |
572 Node* const int_zero = a.IntPtrConstant(0); | 598 Node* const int_zero = a.IntPtrConstant(0); |
573 Node* const int_one = a.IntPtrConstant(1); | 599 Node* const int_one = a.IntPtrConstant(1); |
574 | 600 |
(...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1026 namespace { | 1052 namespace { |
1027 | 1053 |
1028 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) | 1054 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) |
1029 Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv, | 1055 Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv, |
1030 Node* string) { | 1056 Node* string) { |
1031 Isolate* isolate = a->isolate(); | 1057 Isolate* isolate = a->isolate(); |
1032 | 1058 |
1033 Node* const null = a->NullConstant(); | 1059 Node* const null = a->NullConstant(); |
1034 | 1060 |
1035 CVariable var_result(a, MachineRepresentation::kTagged); | 1061 CVariable var_result(a, MachineRepresentation::kTagged); |
1036 CLabel out(a), call_builtin_exec(a), slow_path(a, CLabel::kDeferred); | 1062 CLabel out(a), if_isfastpath(a), if_isslowpath(a); |
1037 | 1063 |
1038 Node* const map = a->LoadMap(recv); | 1064 Node* const map = a->LoadMap(recv); |
1039 BranchIfFastPath(a, context, map, &call_builtin_exec, &slow_path); | 1065 BranchIfFastPath(a, context, map, &if_isfastpath, &if_isslowpath); |
1040 | 1066 |
1041 a->Bind(&call_builtin_exec); | 1067 a->Bind(&if_isfastpath); |
1042 { | 1068 { |
1043 Node* const result = RegExpPrototypeExecInternal(a, context, recv, string); | 1069 Node* const result = |
| 1070 RegExpPrototypeExecBody(a, context, recv, string, true); |
1044 var_result.Bind(result); | 1071 var_result.Bind(result); |
1045 a->Goto(&out); | 1072 a->Goto(&out); |
1046 } | 1073 } |
1047 | 1074 |
1048 a->Bind(&slow_path); | 1075 a->Bind(&if_isslowpath); |
1049 { | 1076 { |
1050 // Take the slow path of fetching the exec property, calling it, and | 1077 // Take the slow path of fetching the exec property, calling it, and |
1051 // verifying its return value. | 1078 // verifying its return value. |
1052 | 1079 |
1053 // Get the exec property. | 1080 // Get the exec property. |
1054 Node* const name = a->HeapConstant(isolate->factory()->exec_string()); | 1081 Node* const name = a->HeapConstant(isolate->factory()->exec_string()); |
1055 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | 1082 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
1056 Node* const exec = a->CallStub(getproperty_callable, context, recv, name); | 1083 Node* const exec = a->CallStub(getproperty_callable, context, recv, name); |
1057 | 1084 |
1058 // Is {exec} callable? | 1085 // Is {exec} callable? |
(...skipping 16 matching lines...) Expand all Loading... |
1075 ThrowIfNotJSReceiver(a, isolate, context, result, | 1102 ThrowIfNotJSReceiver(a, isolate, context, result, |
1076 MessageTemplate::kInvalidRegExpExecResult, "unused"); | 1103 MessageTemplate::kInvalidRegExpExecResult, "unused"); |
1077 | 1104 |
1078 a->Goto(&out); | 1105 a->Goto(&out); |
1079 } | 1106 } |
1080 | 1107 |
1081 a->Bind(&if_isnotcallable); | 1108 a->Bind(&if_isnotcallable); |
1082 { | 1109 { |
1083 a->ThrowIfNotInstanceType(context, recv, JS_REGEXP_TYPE, | 1110 a->ThrowIfNotInstanceType(context, recv, JS_REGEXP_TYPE, |
1084 "RegExp.prototype.exec"); | 1111 "RegExp.prototype.exec"); |
1085 a->Goto(&call_builtin_exec); | 1112 |
| 1113 Node* const result = |
| 1114 RegExpPrototypeExecBody(a, context, recv, string, false); |
| 1115 var_result.Bind(result); |
| 1116 a->Goto(&out); |
1086 } | 1117 } |
1087 } | 1118 } |
1088 | 1119 |
1089 a->Bind(&out); | 1120 a->Bind(&out); |
1090 return var_result.value(); | 1121 return var_result.value(); |
1091 } | 1122 } |
1092 | 1123 |
1093 } // namespace | 1124 } // namespace |
1094 | 1125 |
1095 // ES#sec-regexp.prototype.test | 1126 // ES#sec-regexp.prototype.test |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1301 Node* const regexp = receiver; | 1332 Node* const regexp = receiver; |
1302 Node* const is_global = | 1333 Node* const is_global = |
1303 FlagGetter(a, context, regexp, JSRegExp::kGlobal, is_fastpath); | 1334 FlagGetter(a, context, regexp, JSRegExp::kGlobal, is_fastpath); |
1304 | 1335 |
1305 CLabel if_isglobal(a), if_isnotglobal(a); | 1336 CLabel if_isglobal(a), if_isnotglobal(a); |
1306 a->Branch(is_global, &if_isglobal, &if_isnotglobal); | 1337 a->Branch(is_global, &if_isglobal, &if_isnotglobal); |
1307 | 1338 |
1308 a->Bind(&if_isnotglobal); | 1339 a->Bind(&if_isnotglobal); |
1309 { | 1340 { |
1310 Node* const result = | 1341 Node* const result = |
1311 is_fastpath ? RegExpPrototypeExecInternal(a, context, regexp, string) | 1342 is_fastpath ? RegExpPrototypeExecBody(a, context, regexp, string, true) |
1312 : RegExpExec(a, context, regexp, string); | 1343 : RegExpExec(a, context, regexp, string); |
1313 a->Return(result); | 1344 a->Return(result); |
1314 } | 1345 } |
1315 | 1346 |
1316 a->Bind(&if_isglobal); | 1347 a->Bind(&if_isglobal); |
1317 { | 1348 { |
1318 Node* const is_unicode = | 1349 Node* const is_unicode = |
1319 FlagGetter(a, context, regexp, JSRegExp::kUnicode, is_fastpath); | 1350 FlagGetter(a, context, regexp, JSRegExp::kUnicode, is_fastpath); |
1320 | 1351 |
1321 if (is_fastpath) { | 1352 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 | 1353 |
1327 // Allocate an array to store the resulting match strings. | 1354 // Allocate an array to store the resulting match strings. |
1328 | 1355 |
1329 GrowableFixedArray array(a); | 1356 GrowableFixedArray array(a); |
1330 | 1357 |
1331 // Loop preparations. Within the loop, collect results from RegExpExec | 1358 // Loop preparations. Within the loop, collect results from RegExpExec |
1332 // and store match strings in the array. | 1359 // and store match strings in the array. |
1333 | 1360 |
1334 CVariable* vars[] = {array.var_array(), array.var_length(), | 1361 CVariable* vars[] = {array.var_array(), array.var_length(), |
1335 array.var_capacity()}; | 1362 array.var_capacity()}; |
1336 CLabel loop(a, 3, vars), out(a); | 1363 CLabel loop(a, 3, vars), out(a); |
1337 a->Goto(&loop); | 1364 a->Goto(&loop); |
1338 | 1365 |
1339 a->Bind(&loop); | 1366 a->Bind(&loop); |
1340 { | 1367 { |
1341 Node* const result = | 1368 Node* const result = is_fastpath ? RegExpPrototypeExecBody( |
1342 is_fastpath ? RegExpPrototypeExecInternal(a, context, regexp, string) | 1369 a, context, regexp, string, true) |
1343 : RegExpExec(a, context, regexp, string); | 1370 : RegExpExec(a, context, regexp, string); |
1344 | 1371 |
1345 CLabel if_didmatch(a), if_didnotmatch(a); | 1372 CLabel if_didmatch(a), if_didnotmatch(a); |
1346 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &if_didmatch); | 1373 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &if_didmatch); |
1347 | 1374 |
1348 a->Bind(&if_didnotmatch); | 1375 a->Bind(&if_didnotmatch); |
1349 { | 1376 { |
1350 // Return null if there were no matches, otherwise just exit the loop. | 1377 // Return null if there were no matches, otherwise just exit the loop. |
1351 a->GotoUnless(a->IntPtrEqual(array.length(), int_zero), &out); | 1378 a->GotoUnless(a->IntPtrEqual(array.length(), int_zero), &out); |
1352 a->Return(null); | 1379 a->Return(null); |
1353 } | 1380 } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1408 | 1435 |
1409 // Store the match, growing the fixed array if needed. | 1436 // Store the match, growing the fixed array if needed. |
1410 | 1437 |
1411 array.Push(match); | 1438 array.Push(match); |
1412 | 1439 |
1413 // Advance last index if the match is the empty string. | 1440 // Advance last index if the match is the empty string. |
1414 | 1441 |
1415 Node* const match_length = a->LoadStringLength(match); | 1442 Node* const match_length = a->LoadStringLength(match); |
1416 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop); | 1443 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop); |
1417 | 1444 |
1418 Node* last_index = is_fastpath ? FastLoadLastIndex(a, context, regexp) | 1445 Node* last_index = LoadLastIndex(a, context, regexp, is_fastpath); |
1419 : SlowLoadLastIndex(a, context, regexp); | |
1420 | 1446 |
1421 Callable tolength_callable = CodeFactory::ToLength(isolate); | 1447 Callable tolength_callable = CodeFactory::ToLength(isolate); |
1422 last_index = a->CallStub(tolength_callable, context, last_index); | 1448 last_index = a->CallStub(tolength_callable, context, last_index); |
1423 | 1449 |
1424 Node* const new_last_index = | 1450 Node* const new_last_index = |
1425 AdvanceStringIndex(a, string, last_index, is_unicode); | 1451 AdvanceStringIndex(a, string, last_index, is_unicode); |
1426 | 1452 |
1427 if (is_fastpath) { | 1453 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 | 1454 |
1433 a->Goto(&loop); | 1455 a->Goto(&loop); |
1434 } | 1456 } |
1435 } | 1457 } |
1436 | 1458 |
1437 a->Bind(&out); | 1459 a->Bind(&out); |
1438 { | 1460 { |
1439 // Wrap the match in a JSArray. | 1461 // Wrap the match in a JSArray. |
1440 | 1462 |
1441 Node* const result = array.ToJSArray(context); | 1463 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, | 1501 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, |
1480 Node* const receiver, | 1502 Node* const receiver, |
1481 Node* const string, Node* const context, | 1503 Node* const string, Node* const context, |
1482 bool is_fastpath) { | 1504 bool is_fastpath) { |
1483 Isolate* const isolate = a->isolate(); | 1505 Isolate* const isolate = a->isolate(); |
1484 | 1506 |
1485 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1507 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
1486 | 1508 |
1487 // Grab the initial value of last index. | 1509 // Grab the initial value of last index. |
1488 Node* const previous_last_index = | 1510 Node* const previous_last_index = |
1489 is_fastpath ? FastLoadLastIndex(a, context, receiver) | 1511 LoadLastIndex(a, context, receiver, is_fastpath); |
1490 : SlowLoadLastIndex(a, context, receiver); | |
1491 | 1512 |
1492 // Ensure last index is 0. | 1513 // Ensure last index is 0. |
1493 if (is_fastpath) { | 1514 if (is_fastpath) { |
1494 FastStoreLastIndex(a, context, receiver, smi_zero); | 1515 FastStoreLastIndex(a, receiver, smi_zero); |
1495 } else { | 1516 } else { |
1496 CLabel next(a); | 1517 CLabel next(a); |
1497 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); | 1518 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); |
1498 | 1519 |
1499 SlowStoreLastIndex(a, context, receiver, smi_zero); | 1520 SlowStoreLastIndex(a, context, receiver, smi_zero); |
1500 a->Goto(&next); | 1521 a->Goto(&next); |
1501 a->Bind(&next); | 1522 a->Bind(&next); |
1502 } | 1523 } |
1503 | 1524 |
1504 // Call exec. | 1525 // Call exec. |
1505 Node* const match_indices = | 1526 Node* const match_indices = |
1506 is_fastpath ? RegExpPrototypeExecInternal(a, context, receiver, string) | 1527 is_fastpath ? RegExpPrototypeExecBody(a, context, receiver, string, true) |
1507 : RegExpExec(a, context, receiver, string); | 1528 : RegExpExec(a, context, receiver, string); |
1508 | 1529 |
1509 // Reset last index if necessary. | 1530 // Reset last index if necessary. |
1510 if (is_fastpath) { | 1531 if (is_fastpath) { |
1511 FastStoreLastIndex(a, context, receiver, previous_last_index); | 1532 FastStoreLastIndex(a, receiver, previous_last_index); |
1512 } else { | 1533 } else { |
1513 CLabel next(a); | 1534 CLabel next(a); |
1514 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); | 1535 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); |
1515 | 1536 |
1516 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), | 1537 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), |
1517 &next); | 1538 &next); |
1518 | 1539 |
1519 SlowStoreLastIndex(a, context, receiver, previous_last_index); | 1540 SlowStoreLastIndex(a, context, receiver, previous_last_index); |
1520 a->Goto(&next); | 1541 a->Goto(&next); |
1521 a->Bind(&next); | 1542 a->Bind(&next); |
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1928 Node* const int_zero = a->IntPtrConstant(0); | 1949 Node* const int_zero = a->IntPtrConstant(0); |
1929 Node* const int_one = a->IntPtrConstant(1); | 1950 Node* const int_one = a->IntPtrConstant(1); |
1930 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1951 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
1931 | 1952 |
1932 Node* const native_context = a->LoadNativeContext(context); | 1953 Node* const native_context = a->LoadNativeContext(context); |
1933 | 1954 |
1934 CLabel out(a); | 1955 CLabel out(a); |
1935 CVariable var_result(a, MachineRepresentation::kTagged); | 1956 CVariable var_result(a, MachineRepresentation::kTagged); |
1936 | 1957 |
1937 // Set last index to 0. | 1958 // Set last index to 0. |
1938 FastStoreLastIndex(a, context, regexp, smi_zero); | 1959 FastStoreLastIndex(a, regexp, smi_zero); |
1939 | 1960 |
1940 // Allocate {result_array}. | 1961 // Allocate {result_array}. |
1941 Node* result_array; | 1962 Node* result_array; |
1942 { | 1963 { |
1943 ElementsKind kind = FAST_ELEMENTS; | 1964 ElementsKind kind = FAST_ELEMENTS; |
1944 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); | 1965 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); |
1945 Node* const capacity = a->IntPtrConstant(16); | 1966 Node* const capacity = a->IntPtrConstant(16); |
1946 Node* const length = smi_zero; | 1967 Node* const length = smi_zero; |
1947 Node* const allocation_site = nullptr; | 1968 Node* const allocation_site = nullptr; |
1948 ParameterMode capacity_mode = CodeStubAssembler::INTPTR_PARAMETERS; | 1969 ParameterMode capacity_mode = CodeStubAssembler::INTPTR_PARAMETERS; |
1949 | 1970 |
1950 result_array = a->AllocateJSArray(kind, array_map, capacity, length, | 1971 result_array = a->AllocateJSArray(kind, array_map, capacity, length, |
1951 allocation_site, capacity_mode); | 1972 allocation_site, capacity_mode); |
1952 } | 1973 } |
1953 | 1974 |
1954 // Call into runtime for RegExpExecMultiple. | 1975 // Call into runtime for RegExpExecMultiple. |
1955 Node* last_match_info = a->LoadContextElement( | 1976 Node* last_match_info = a->LoadContextElement( |
1956 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 1977 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
1957 Node* const res = | 1978 Node* const res = |
1958 a->CallRuntime(Runtime::kRegExpExecMultiple, context, regexp, | 1979 a->CallRuntime(Runtime::kRegExpExecMultiple, context, regexp, |
1959 subject_string, last_match_info, result_array); | 1980 subject_string, last_match_info, result_array); |
1960 | 1981 |
1961 // Reset last index to 0. | 1982 // Reset last index to 0. |
1962 FastStoreLastIndex(a, context, regexp, smi_zero); | 1983 FastStoreLastIndex(a, regexp, smi_zero); |
1963 | 1984 |
1964 // If no matches, return the subject string. | 1985 // If no matches, return the subject string. |
1965 var_result.Bind(subject_string); | 1986 var_result.Bind(subject_string); |
1966 a->GotoIf(a->WordEqual(res, null), &out); | 1987 a->GotoIf(a->WordEqual(res, null), &out); |
1967 | 1988 |
1968 // Reload last match info since it might have changed. | 1989 // Reload last match info since it might have changed. |
1969 last_match_info = a->LoadContextElement( | 1990 last_match_info = a->LoadContextElement( |
1970 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 1991 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
1971 | 1992 |
1972 Node* const res_length = a->LoadJSArrayLength(res); | 1993 Node* const res_length = a->LoadJSArrayLength(res); |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2155 // Is {regexp} global? | 2176 // Is {regexp} global? |
2156 CLabel if_isglobal(a), if_isnonglobal(a); | 2177 CLabel if_isglobal(a), if_isnonglobal(a); |
2157 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 2178 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
2158 Node* const is_global = | 2179 Node* const is_global = |
2159 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal)); | 2180 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal)); |
2160 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal); | 2181 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal); |
2161 | 2182 |
2162 a->Bind(&if_isglobal); | 2183 a->Bind(&if_isglobal); |
2163 { | 2184 { |
2164 // Hand off global regexps to runtime. | 2185 // Hand off global regexps to runtime. |
2165 FastStoreLastIndex(a, context, regexp, smi_zero); | 2186 FastStoreLastIndex(a, regexp, smi_zero); |
2166 Node* const result = | 2187 Node* const result = |
2167 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, | 2188 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, |
2168 subject_string, regexp, replace_string, last_match_info); | 2189 subject_string, regexp, replace_string, last_match_info); |
2169 var_result.Bind(result); | 2190 var_result.Bind(result); |
2170 a->Goto(&out); | 2191 a->Goto(&out); |
2171 } | 2192 } |
2172 | 2193 |
2173 a->Bind(&if_isnonglobal); | 2194 a->Bind(&if_isnonglobal); |
2174 { | 2195 { |
2175 // Run exec, then manually construct the resulting string. | 2196 // Run exec, then manually construct the resulting string. |
2176 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 2197 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
2177 Node* const match_indices = | 2198 Node* const match_indices = |
2178 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero, | 2199 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero, |
2179 last_match_info); | 2200 last_match_info); |
2180 | 2201 |
2181 CLabel if_matched(a), if_didnotmatch(a); | 2202 CLabel if_matched(a), if_didnotmatch(a); |
2182 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); | 2203 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); |
2183 | 2204 |
2184 a->Bind(&if_didnotmatch); | 2205 a->Bind(&if_didnotmatch); |
2185 { | 2206 { |
2186 FastStoreLastIndex(a, context, regexp, smi_zero); | 2207 FastStoreLastIndex(a, regexp, smi_zero); |
2187 var_result.Bind(subject_string); | 2208 var_result.Bind(subject_string); |
2188 a->Goto(&out); | 2209 a->Goto(&out); |
2189 } | 2210 } |
2190 | 2211 |
2191 a->Bind(&if_matched); | 2212 a->Bind(&if_matched); |
2192 { | 2213 { |
2193 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 2214 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; |
2194 | 2215 |
2195 Node* const subject_start = smi_zero; | 2216 Node* const subject_start = smi_zero; |
2196 Node* const match_start = a->LoadFixedArrayElement( | 2217 Node* const match_start = a->LoadFixedArrayElement( |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2366 a.Bind(&if_matched); | 2387 a.Bind(&if_matched); |
2367 { | 2388 { |
2368 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, | 2389 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, |
2369 match_indices, string); | 2390 match_indices, string); |
2370 a.Return(result); | 2391 a.Return(result); |
2371 } | 2392 } |
2372 } | 2393 } |
2373 | 2394 |
2374 } // namespace internal | 2395 } // namespace internal |
2375 } // namespace v8 | 2396 } // namespace v8 |
OLD | NEW |