Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(238)

Side by Side Diff: src/builtins/builtins-regexp.cc

Issue 2398423002: [regexp] Port RegExp.prototype[@@replace] (Closed)
Patch Set: Smi::kZero Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-stub-assembler.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); 200 a->HeapConstant(a->isolate()->factory()->lastIndex_string());
201 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); 201 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
202 var_value.Bind(a->CallStub(getproperty_callable, context, regexp, name)); 202 var_value.Bind(a->CallStub(getproperty_callable, context, regexp, name));
203 a->Goto(&out); 203 a->Goto(&out);
204 } 204 }
205 205
206 a->Bind(&out); 206 a->Bind(&out);
207 return var_value.value(); 207 return var_value.value();
208 } 208 }
209 209
210 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified
211 // JSRegExp instance.
212 void FastStoreLastIndex(CodeStubAssembler* a, compiler::Node* context,
213 compiler::Node* regexp, compiler::Node* value) {
214 // Store the in-object field.
215 static const int field_offset =
216 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize;
217 a->StoreObjectField(regexp, field_offset, value);
218 }
219
210 void StoreLastIndex(CodeStubAssembler* a, compiler::Node* context, 220 void StoreLastIndex(CodeStubAssembler* a, compiler::Node* context,
211 compiler::Node* has_initialmap, compiler::Node* regexp, 221 compiler::Node* has_initialmap, compiler::Node* regexp,
212 compiler::Node* value) { 222 compiler::Node* value) {
213 typedef CodeStubAssembler::Label Label; 223 typedef CodeStubAssembler::Label Label;
214 typedef compiler::Node Node; 224 typedef compiler::Node Node;
215 225
216 Label out(a), if_unmodified(a), if_modified(a, Label::kDeferred); 226 Label out(a), if_unmodified(a), if_modified(a, Label::kDeferred);
217 a->Branch(has_initialmap, &if_unmodified, &if_modified); 227 a->Branch(has_initialmap, &if_unmodified, &if_modified);
218 228
219 a->Bind(&if_unmodified); 229 a->Bind(&if_unmodified);
220 { 230 {
221 // Store the in-object field. 231 FastStoreLastIndex(a, context, regexp, value);
222 static const int field_offset =
223 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize;
224 a->StoreObjectField(regexp, field_offset, value);
225 a->Goto(&out); 232 a->Goto(&out);
226 } 233 }
227 234
228 a->Bind(&if_modified); 235 a->Bind(&if_modified);
229 { 236 {
230 // Store through runtime. 237 // Store through runtime.
231 // TODO(ishell): Use SetPropertyStub here once available. 238 // TODO(ishell): Use SetPropertyStub here once available.
232 Node* const name = 239 Node* const name =
233 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); 240 a->HeapConstant(a->isolate()->factory()->lastIndex_string());
234 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); 241 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT));
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 a->Return(result); 454 a->Return(result);
448 } 455 }
449 } 456 }
450 } 457 }
451 458
452 namespace { 459 namespace {
453 460
454 compiler::Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, 461 compiler::Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate,
455 compiler::Node* context, 462 compiler::Node* context,
456 compiler::Node* value, 463 compiler::Node* value,
464 MessageTemplate::Template msg_template,
457 char const* method_name) { 465 char const* method_name) {
458 typedef compiler::Node Node; 466 typedef compiler::Node Node;
459 typedef CodeStubAssembler::Label Label; 467 typedef CodeStubAssembler::Label Label;
460 typedef CodeStubAssembler::Variable Variable; 468 typedef CodeStubAssembler::Variable Variable;
461 469
462 Label out(a), throw_exception(a, Label::kDeferred); 470 Label out(a), throw_exception(a, Label::kDeferred);
463 Variable var_value_map(a, MachineRepresentation::kTagged); 471 Variable var_value_map(a, MachineRepresentation::kTagged);
464 472
465 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); 473 a->GotoIf(a->TaggedIsSmi(value), &throw_exception);
466 474
467 // Load the instance type of the {value}. 475 // Load the instance type of the {value}.
468 var_value_map.Bind(a->LoadMap(value)); 476 var_value_map.Bind(a->LoadMap(value));
469 Node* const value_instance_type = 477 Node* const value_instance_type =
470 a->LoadMapInstanceType(var_value_map.value()); 478 a->LoadMapInstanceType(var_value_map.value());
471 479
472 a->Branch(a->IsJSReceiverInstanceType(value_instance_type), &out, 480 a->Branch(a->IsJSReceiverInstanceType(value_instance_type), &out,
473 &throw_exception); 481 &throw_exception);
474 482
475 // The {value} is not a compatible receiver for this method. 483 // The {value} is not a compatible receiver for this method.
476 a->Bind(&throw_exception); 484 a->Bind(&throw_exception);
477 { 485 {
478 Node* const message_id = 486 Node* const message_id = a->SmiConstant(Smi::FromInt(msg_template));
479 a->SmiConstant(Smi::FromInt(MessageTemplate::kRegExpNonObject));
480 Node* const method_name_str = a->HeapConstant( 487 Node* const method_name_str = a->HeapConstant(
481 isolate->factory()->NewStringFromAsciiChecked(method_name, TENURED)); 488 isolate->factory()->NewStringFromAsciiChecked(method_name, TENURED));
482 489
483 Callable callable = CodeFactory::ToString(isolate); 490 Callable callable = CodeFactory::ToString(isolate);
484 Node* const value_str = a->CallStub(callable, context, value); 491 Node* const value_str = a->CallStub(callable, context, value);
485 492
486 a->CallRuntime(Runtime::kThrowTypeError, context, message_id, 493 a->CallRuntime(Runtime::kThrowTypeError, context, message_id,
487 method_name_str, value_str); 494 method_name_str, value_str);
488 var_value_map.Bind(a->UndefinedConstant()); 495 var_value_map.Bind(a->UndefinedConstant());
489 a->Goto(&out); // Never reached. 496 a->Goto(&out); // Never reached.
(...skipping 11 matching lines...) Expand all
501 Node* const native_context = a->LoadNativeContext(context); 508 Node* const native_context = a->LoadNativeContext(context);
502 Node* const regexp_fun = 509 Node* const regexp_fun =
503 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); 510 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
504 Node* const initial_map = 511 Node* const initial_map =
505 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); 512 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
506 Node* const has_initialmap = a->WordEqual(map, initial_map); 513 Node* const has_initialmap = a->WordEqual(map, initial_map);
507 514
508 return has_initialmap; 515 return has_initialmap;
509 } 516 }
510 517
518 // RegExp fast path implementations rely on unmodified JSRegExp instances.
519 // We use a fairly coarse granularity for this and simply check whether both
520 // the regexp itself is unmodified (i.e. its map has not changed) and its
521 // prototype is unmodified.
522 void BranchIfFastPath(CodeStubAssembler* a, compiler::Node* context,
523 compiler::Node* map,
524 CodeStubAssembler::Label* if_isunmodified,
525 CodeStubAssembler::Label* if_ismodified) {
526 typedef compiler::Node Node;
527
528 Node* const native_context = a->LoadNativeContext(context);
529 Node* const regexp_fun =
530 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
531 Node* const initial_map =
532 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
533 Node* const has_initialmap = a->WordEqual(map, initial_map);
534
535 a->GotoUnless(has_initialmap, if_ismodified);
536
537 Node* const initial_proto_initial_map = a->LoadContextElement(
538 native_context, Context::REGEXP_PROTOTYPE_MAP_INDEX);
539 Node* const proto_map = a->LoadMap(a->LoadMapPrototype(map));
540 Node* const proto_has_initialmap =
541 a->WordEqual(proto_map, initial_proto_initial_map);
542
543 // TODO(ishell): Update this check once map changes for constant field
544 // tracking are landing.
545
546 a->Branch(proto_has_initialmap, if_isunmodified, if_ismodified);
547 }
548
511 } // namespace 549 } // namespace
512 550
513 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeStubAssembler* a) { 551 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeStubAssembler* a) {
514 typedef CodeStubAssembler::Variable Variable; 552 typedef CodeStubAssembler::Variable Variable;
515 typedef CodeStubAssembler::Label Label; 553 typedef CodeStubAssembler::Label Label;
516 typedef compiler::Node Node; 554 typedef compiler::Node Node;
517 555
518 Node* const receiver = a->Parameter(0); 556 Node* const receiver = a->Parameter(0);
519 Node* const context = a->Parameter(3); 557 Node* const context = a->Parameter(3);
520 558
521 Isolate* isolate = a->isolate(); 559 Isolate* isolate = a->isolate();
522 Node* const int_zero = a->IntPtrConstant(0); 560 Node* const int_zero = a->IntPtrConstant(0);
523 Node* const int_one = a->IntPtrConstant(1); 561 Node* const int_one = a->IntPtrConstant(1);
524 562
525 Node* const map = ThrowIfNotJSReceiver(a, isolate, context, receiver, 563 Node* const map = ThrowIfNotJSReceiver(a, isolate, context, receiver,
564 MessageTemplate::kRegExpNonObject,
526 "RegExp.prototype.flags"); 565 "RegExp.prototype.flags");
527 566
528 Variable var_length(a, MachineType::PointerRepresentation()); 567 Variable var_length(a, MachineType::PointerRepresentation());
529 Variable var_flags(a, MachineType::PointerRepresentation()); 568 Variable var_flags(a, MachineType::PointerRepresentation());
530 569
531 // First, count the number of characters we will need and check which flags 570 // First, count the number of characters we will need and check which flags
532 // are set. 571 // are set.
533 572
534 var_length.Bind(int_zero); 573 var_length.Bind(int_zero);
535 574
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
812 "RegExp.prototype.sticky"); 851 "RegExp.prototype.sticky");
813 } 852 }
814 853
815 // ES6 21.2.5.15. 854 // ES6 21.2.5.15.
816 void Builtins::Generate_RegExpPrototypeUnicodeGetter(CodeStubAssembler* a) { 855 void Builtins::Generate_RegExpPrototypeUnicodeGetter(CodeStubAssembler* a) {
817 Generate_FlagGetter(a, JSRegExp::kUnicode, 856 Generate_FlagGetter(a, JSRegExp::kUnicode,
818 v8::Isolate::kRegExpPrototypeUnicodeGetter, 857 v8::Isolate::kRegExpPrototypeUnicodeGetter,
819 "RegExp.prototype.unicode"); 858 "RegExp.prototype.unicode");
820 } 859 }
821 860
822
823 // The properties $1..$9 are the first nine capturing substrings of the last 861 // The properties $1..$9 are the first nine capturing substrings of the last
824 // successful match, or ''. The function RegExpMakeCaptureGetter will be 862 // successful match, or ''. The function RegExpMakeCaptureGetter will be
825 // called with indices from 1 to 9. 863 // called with indices from 1 to 9.
826 #define DEFINE_CAPTURE_GETTER(i) \ 864 #define DEFINE_CAPTURE_GETTER(i) \
827 BUILTIN(RegExpCapture##i##Getter) { \ 865 BUILTIN(RegExpCapture##i##Getter) { \
828 HandleScope scope(isolate); \ 866 HandleScope scope(isolate); \
829 return *RegExpUtils::GenericCaptureGetter( \ 867 return *RegExpUtils::GenericCaptureGetter( \
830 isolate, isolate->regexp_last_match_info(), i); \ 868 isolate, isolate->regexp_last_match_info(), i); \
831 } 869 }
832 DEFINE_CAPTURE_GETTER(1) 870 DEFINE_CAPTURE_GETTER(1)
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after
1176 } 1214 }
1177 1215
1178 { 1216 {
1179 Handle<String> substr = 1217 Handle<String> substr =
1180 factory->NewSubString(string, current_index, start_match); 1218 factory->NewSubString(string, current_index, start_match);
1181 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); 1219 elems = FixedArray::SetAndGrow(elems, num_elems++, substr);
1182 } 1220 }
1183 1221
1184 if (num_elems == limit) break; 1222 if (num_elems == limit) break;
1185 1223
1186 // TODO(jgruber): Refactor GetLastMatchInfo methods to take an input
1187 // argument.
1188 Handle<Object> num_captures_obj = 1224 Handle<Object> num_captures_obj =
1189 JSReceiver::GetElement(isolate, match_indices, 1225 JSReceiver::GetElement(isolate, match_indices,
1190 RegExpImpl::kLastCaptureCount) 1226 RegExpImpl::kLastCaptureCount)
1191 .ToHandleChecked(); 1227 .ToHandleChecked();
1192 const int match_indices_len = Handle<Smi>::cast(num_captures_obj)->value() + 1228 const int match_indices_len = Handle<Smi>::cast(num_captures_obj)->value() +
1193 RegExpImpl::kFirstCapture; 1229 RegExpImpl::kFirstCapture;
1194 1230
1195 for (int i = RegExpImpl::kFirstCapture + 2; i < match_indices_len;) { 1231 for (int i = RegExpImpl::kFirstCapture + 2; i < match_indices_len;) {
1196 Handle<Object> start_obj = 1232 Handle<Object> start_obj =
1197 JSReceiver::GetElement(isolate, match_indices, i++).ToHandleChecked(); 1233 JSReceiver::GetElement(isolate, match_indices, i++).ToHandleChecked();
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
1421 1457
1422 { 1458 {
1423 Handle<String> substr = 1459 Handle<String> substr =
1424 factory->NewSubString(string, prev_string_index, length); 1460 factory->NewSubString(string, prev_string_index, length);
1425 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); 1461 elems = FixedArray::SetAndGrow(elems, num_elems++, substr);
1426 } 1462 }
1427 1463
1428 return *NewJSArrayWithElements(isolate, elems, num_elems); 1464 return *NewJSArrayWithElements(isolate, elems, num_elems);
1429 } 1465 }
1430 1466
1467 namespace {
1468
1469 compiler::Node* ReplaceFastPath(CodeStubAssembler* a, compiler::Node* context,
1470 compiler::Node* regexp,
1471 compiler::Node* subject_string,
1472 compiler::Node* replace_string) {
1473 // The fast path is reached only if {receiver} is an unmodified
1474 // JSRegExp instance, {replace_value} is non-callable, and
1475 // ToString({replace_value}) does not contain '$', i.e. we're doing a simple
1476 // string replacement.
1477
1478 typedef CodeStubAssembler::Variable Variable;
1479 typedef CodeStubAssembler::Label Label;
1480 typedef compiler::Node Node;
1481
1482 Isolate* const isolate = a->isolate();
1483
1484 Node* const null = a->NullConstant();
1485 Node* const int_zero = a->IntPtrConstant(0);
1486 Node* const smi_zero = a->SmiConstant(Smi::kZero);
1487
1488 Label out(a);
1489 Variable var_result(a, MachineRepresentation::kTagged);
1490
1491 // Load the last match info.
1492 Node* const native_context = a->LoadNativeContext(context);
1493 Node* const last_match_info = a->LoadContextElement(
1494 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
1495
1496 // Is {regexp} global?
1497 Label if_isglobal(a), if_isnonglobal(a);
1498 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset);
1499 Node* const is_global =
1500 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal));
1501 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal);
1502
1503 a->Bind(&if_isglobal);
1504 {
1505 // Hand off global regexps to runtime.
1506 FastStoreLastIndex(a, context, regexp, smi_zero);
1507 Node* const result =
1508 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context,
1509 subject_string, regexp, replace_string, last_match_info);
1510 var_result.Bind(result);
1511 a->Goto(&out);
1512 }
1513
1514 a->Bind(&if_isnonglobal);
1515 {
1516 // Run exec, then manually construct the resulting string.
1517 Callable exec_callable = CodeFactory::RegExpExec(isolate);
1518 Node* const match_indices =
1519 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero,
1520 last_match_info);
1521
1522 Label if_matched(a), if_didnotmatch(a);
1523 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched);
1524
1525 a->Bind(&if_didnotmatch);
1526 {
1527 FastStoreLastIndex(a, context, regexp, smi_zero);
1528 var_result.Bind(subject_string);
1529 a->Goto(&out);
1530 }
1531
1532 a->Bind(&if_matched);
1533 {
1534 Node* const match_elements = a->LoadElements(match_indices);
1535 CodeStubAssembler::ParameterMode mode =
1536 CodeStubAssembler::INTPTR_PARAMETERS;
1537
1538 Node* const subject_start = smi_zero;
1539 Node* const match_start = a->LoadFixedArrayElement(
1540 match_elements, a->IntPtrConstant(RegExpImpl::kFirstCapture), 0,
1541 mode);
1542 Node* const match_end = a->LoadFixedArrayElement(
1543 match_elements, a->IntPtrConstant(RegExpImpl::kFirstCapture + 1), 0,
1544 mode);
1545 Node* const subject_end = a->LoadStringLength(subject_string);
1546
1547 Label if_replaceisempty(a), if_replaceisnotempty(a);
1548 Node* const replace_length = a->LoadStringLength(replace_string);
1549 a->Branch(a->SmiEqual(replace_length, smi_zero), &if_replaceisempty,
1550 &if_replaceisnotempty);
1551
1552 a->Bind(&if_replaceisempty);
1553 {
1554 // TODO(jgruber): We could skip many of the checks that using SubString
1555 // here entails.
1556
1557 Node* const first_part =
1558 a->SubString(context, subject_string, subject_start, match_start);
1559 Node* const second_part =
1560 a->SubString(context, subject_string, match_end, subject_end);
1561
1562 Node* const result = a->StringConcat(context, first_part, second_part);
1563 var_result.Bind(result);
1564 a->Goto(&out);
1565 }
1566
1567 a->Bind(&if_replaceisnotempty);
1568 {
1569 Node* const first_part =
1570 a->SubString(context, subject_string, subject_start, match_start);
1571 Node* const second_part = replace_string;
1572 Node* const third_part =
1573 a->SubString(context, subject_string, match_end, subject_end);
1574
1575 Node* result = a->StringConcat(context, first_part, second_part);
1576 result = a->StringConcat(context, result, third_part);
1577
1578 var_result.Bind(result);
1579 a->Goto(&out);
1580 }
1581 }
1582 }
1583
1584 a->Bind(&out);
1585 return var_result.value();
1586 }
1587
1588 } // namespace
1589
1590 // ES#sec-regexp.prototype-@@replace
1591 // RegExp.prototype [ @@replace ] ( string, replaceValue )
1592 void Builtins::Generate_RegExpPrototypeReplace(CodeStubAssembler* a) {
1593 typedef CodeStubAssembler::Label Label;
1594 typedef compiler::Node Node;
1595
1596 Isolate* const isolate = a->isolate();
1597
1598 Node* const maybe_receiver = a->Parameter(0);
1599 Node* const maybe_string = a->Parameter(1);
1600 Node* const replace_value = a->Parameter(2);
1601 Node* const context = a->Parameter(5);
1602
1603 Node* const int_zero = a->IntPtrConstant(0);
1604
1605 // Ensure {receiver} is a JSReceiver.
1606 Node* const map =
1607 ThrowIfNotJSReceiver(a, isolate, context, maybe_receiver,
1608 MessageTemplate::kIncompatibleMethodReceiver,
1609 "RegExp.prototype.@@replace");
1610 Node* const receiver = maybe_receiver;
1611
1612 // Convert {maybe_string} to a String.
1613 Callable tostring_callable = CodeFactory::ToString(isolate);
1614 Node* const string = a->CallStub(tostring_callable, context, maybe_string);
1615
1616 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance?
1617 Label checkreplacecallable(a), runtime(a, Label::kDeferred), fastpath(a);
1618 BranchIfFastPath(a, context, map, &checkreplacecallable, &runtime);
1619
1620 a->Bind(&checkreplacecallable);
1621 Node* const regexp = receiver;
1622
1623 // 2. Is {replace_value} callable?
1624 Label checkreplacestring(a);
1625 a->GotoIf(a->TaggedIsSmi(replace_value), &checkreplacestring);
1626
1627 Node* const replace_value_map = a->LoadMap(replace_value);
1628 a->Branch(
1629 a->Word32Equal(a->Word32And(a->LoadMapBitField(replace_value_map),
1630 a->Int32Constant(1 << Map::kIsCallable)),
1631 a->Int32Constant(0)),
1632 &checkreplacestring, &runtime);
1633
1634 // 3. Does ToString({replace_value}) contain '$'?
1635 a->Bind(&checkreplacestring);
1636 {
1637 Node* const replace_string =
1638 a->CallStub(tostring_callable, context, replace_value);
1639
1640 Node* const dollar_char = a->IntPtrConstant('$');
1641 Node* const smi_minusone = a->SmiConstant(Smi::FromInt(-1));
1642 a->GotoUnless(a->SmiEqual(a->StringIndexOfChar(context, replace_string,
1643 dollar_char, int_zero),
1644 smi_minusone),
1645 &runtime);
1646
1647 a->Return(ReplaceFastPath(a, context, regexp, string, replace_string));
1648 }
1649
1650 a->Bind(&runtime);
1651 {
1652 Node* const result = a->CallRuntime(Runtime::kRegExpReplace, context,
1653 receiver, string, replace_value);
1654 a->Return(result);
1655 }
1656 }
1657
1431 } // namespace internal 1658 } // namespace internal
1432 } // namespace v8 1659 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-stub-assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698