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 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stub-assembler.h" | 8 #include "src/code-stub-assembler.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 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 var_to_cursor.Bind(IntPtrConstant(1)); | 176 var_to_cursor.Bind(IntPtrConstant(1)); |
177 | 177 |
178 Variable* vars[] = {&var_from_cursor, &var_to_cursor}; | 178 Variable* vars[] = {&var_from_cursor, &var_to_cursor}; |
179 Label loop(this, 2, vars); | 179 Label loop(this, 2, vars); |
180 | 180 |
181 Goto(&loop); | 181 Goto(&loop); |
182 Bind(&loop); | 182 Bind(&loop); |
183 { | 183 { |
184 Node* const from_cursor = var_from_cursor.value(); | 184 Node* const from_cursor = var_from_cursor.value(); |
185 Node* const to_cursor = var_to_cursor.value(); | 185 Node* const to_cursor = var_to_cursor.value(); |
186 Node* const start = LoadFixedArrayElement(match_info, from_cursor); | 186 Node* const start = |
| 187 LoadFixedArrayElement(match_info, from_cursor, 0, INTPTR_PARAMETERS); |
187 | 188 |
188 Label next_iter(this); | 189 Label next_iter(this); |
189 GotoIf(SmiEqual(start, SmiConstant(Smi::FromInt(-1))), &next_iter); | 190 GotoIf(SmiEqual(start, SmiConstant(Smi::FromInt(-1))), &next_iter); |
190 | 191 |
191 Node* const from_cursor_plus1 = IntPtrAdd(from_cursor, IntPtrConstant(1)); | 192 Node* const from_cursor_plus1 = IntPtrAdd(from_cursor, IntPtrConstant(1)); |
192 Node* const end = LoadFixedArrayElement(match_info, from_cursor_plus1); | 193 Node* const end = LoadFixedArrayElement(match_info, from_cursor_plus1, 0, |
| 194 INTPTR_PARAMETERS); |
193 | 195 |
194 Node* const capture = SubString(context, string, start, end); | 196 Node* const capture = SubString(context, string, start, end); |
195 StoreFixedArrayElement(result_elements, to_cursor, capture); | 197 StoreFixedArrayElement(result_elements, to_cursor, capture, |
| 198 UPDATE_WRITE_BARRIER, 0, INTPTR_PARAMETERS); |
196 Goto(&next_iter); | 199 Goto(&next_iter); |
197 | 200 |
198 Bind(&next_iter); | 201 Bind(&next_iter); |
199 var_from_cursor.Bind(IntPtrAdd(from_cursor, IntPtrConstant(2))); | 202 var_from_cursor.Bind(IntPtrAdd(from_cursor, IntPtrConstant(2))); |
200 var_to_cursor.Bind(IntPtrAdd(to_cursor, IntPtrConstant(1))); | 203 var_to_cursor.Bind(IntPtrAdd(to_cursor, IntPtrConstant(1))); |
201 Branch(UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out); | 204 Branch(UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out); |
202 } | 205 } |
203 | 206 |
204 Bind(&out); | 207 Bind(&out); |
205 return result; | 208 return result; |
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
559 Node* const flags_intptr = var_flags.value(); | 562 Node* const flags_intptr = var_flags.value(); |
560 | 563 |
561 Variable var_offset(this, MachineType::PointerRepresentation()); | 564 Variable var_offset(this, MachineType::PointerRepresentation()); |
562 var_offset.Bind( | 565 var_offset.Bind( |
563 IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 566 IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
564 | 567 |
565 #define CASE_FOR_FLAG(FLAG, CHAR) \ | 568 #define CASE_FOR_FLAG(FLAG, CHAR) \ |
566 do { \ | 569 do { \ |
567 Label next(this); \ | 570 Label next(this); \ |
568 GotoUnless(IsSetWord(flags_intptr, FLAG), &next); \ | 571 GotoUnless(IsSetWord(flags_intptr, FLAG), &next); \ |
569 Node* const value = IntPtrConstant(CHAR); \ | 572 Node* const value = Int32Constant(CHAR); \ |
570 StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \ | 573 StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \ |
571 var_offset.value(), value); \ | 574 var_offset.value(), value); \ |
572 var_offset.Bind(IntPtrAdd(var_offset.value(), int_one)); \ | 575 var_offset.Bind(IntPtrAdd(var_offset.value(), int_one)); \ |
573 Goto(&next); \ | 576 Goto(&next); \ |
574 Bind(&next); \ | 577 Bind(&next); \ |
575 } while (false) | 578 } while (false) |
576 | 579 |
577 CASE_FOR_FLAG(JSRegExp::kGlobal, 'g'); | 580 CASE_FOR_FLAG(JSRegExp::kGlobal, 'g'); |
578 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, 'i'); | 581 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, 'i'); |
579 CASE_FOR_FLAG(JSRegExp::kMultiline, 'm'); | 582 CASE_FOR_FLAG(JSRegExp::kMultiline, 'm'); |
580 CASE_FOR_FLAG(JSRegExp::kUnicode, 'u'); | 583 CASE_FOR_FLAG(JSRegExp::kUnicode, 'u'); |
581 CASE_FOR_FLAG(JSRegExp::kSticky, 'y'); | 584 CASE_FOR_FLAG(JSRegExp::kSticky, 'y'); |
582 #undef CASE_FOR_FLAG | 585 #undef CASE_FOR_FLAG |
583 | 586 |
584 return result; | 587 return result; |
585 } | 588 } |
586 } | 589 } |
587 | 590 |
588 // ES#sec-isregexp IsRegExp ( argument ) | 591 // ES#sec-isregexp IsRegExp ( argument ) |
589 Node* RegExpBuiltinsAssembler::IsRegExp(Node* const context, | 592 Node* RegExpBuiltinsAssembler::IsRegExp(Node* const context, |
590 Node* const maybe_receiver) { | 593 Node* const maybe_receiver) { |
591 Label out(this), if_isregexp(this); | 594 Label out(this), if_isregexp(this); |
592 | 595 |
593 Variable var_result(this, MachineType::PointerRepresentation()); | 596 Variable var_result(this, MachineRepresentation::kWord32); |
594 var_result.Bind(IntPtrConstant(0)); | 597 var_result.Bind(Int32Constant(0)); |
595 | 598 |
596 GotoIf(TaggedIsSmi(maybe_receiver), &out); | 599 GotoIf(TaggedIsSmi(maybe_receiver), &out); |
597 GotoUnless(IsJSReceiver(maybe_receiver), &out); | 600 GotoUnless(IsJSReceiver(maybe_receiver), &out); |
598 | 601 |
599 Node* const receiver = maybe_receiver; | 602 Node* const receiver = maybe_receiver; |
600 | 603 |
601 // Check @@match. | 604 // Check @@match. |
602 { | 605 { |
603 Callable getproperty_callable = CodeFactory::GetProperty(isolate()); | 606 Callable getproperty_callable = CodeFactory::GetProperty(isolate()); |
604 Node* const name = HeapConstant(isolate()->factory()->match_symbol()); | 607 Node* const name = HeapConstant(isolate()->factory()->match_symbol()); |
605 Node* const value = CallStub(getproperty_callable, context, receiver, name); | 608 Node* const value = CallStub(getproperty_callable, context, receiver, name); |
606 | 609 |
607 Label match_isundefined(this), match_isnotundefined(this); | 610 Label match_isundefined(this), match_isnotundefined(this); |
608 Branch(IsUndefined(value), &match_isundefined, &match_isnotundefined); | 611 Branch(IsUndefined(value), &match_isundefined, &match_isnotundefined); |
609 | 612 |
610 Bind(&match_isundefined); | 613 Bind(&match_isundefined); |
611 Branch(HasInstanceType(receiver, JS_REGEXP_TYPE), &if_isregexp, &out); | 614 Branch(HasInstanceType(receiver, JS_REGEXP_TYPE), &if_isregexp, &out); |
612 | 615 |
613 Bind(&match_isnotundefined); | 616 Bind(&match_isnotundefined); |
614 BranchIfToBooleanIsTrue(value, &if_isregexp, &out); | 617 BranchIfToBooleanIsTrue(value, &if_isregexp, &out); |
615 } | 618 } |
616 | 619 |
617 Bind(&if_isregexp); | 620 Bind(&if_isregexp); |
618 var_result.Bind(IntPtrConstant(1)); | 621 var_result.Bind(Int32Constant(1)); |
619 Goto(&out); | 622 Goto(&out); |
620 | 623 |
621 Bind(&out); | 624 Bind(&out); |
622 return var_result.value(); | 625 return var_result.value(); |
623 } | 626 } |
624 | 627 |
625 // ES#sec-regexpinitialize | 628 // ES#sec-regexpinitialize |
626 // Runtime Semantics: RegExpInitialize ( obj, pattern, flags ) | 629 // Runtime Semantics: RegExpInitialize ( obj, pattern, flags ) |
627 Node* RegExpBuiltinsAssembler::RegExpInitialize(Node* const context, | 630 Node* RegExpBuiltinsAssembler::RegExpInitialize(Node* const context, |
628 Node* const regexp, | 631 Node* const regexp, |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
955 Node* const receiver = Parameter(0); | 958 Node* const receiver = Parameter(0); |
956 Return(receiver); | 959 Return(receiver); |
957 } | 960 } |
958 | 961 |
959 // Fast-path implementation for flag checks on an unmodified JSRegExp instance. | 962 // Fast-path implementation for flag checks on an unmodified JSRegExp instance. |
960 Node* RegExpBuiltinsAssembler::FastFlagGetter(Node* const regexp, | 963 Node* RegExpBuiltinsAssembler::FastFlagGetter(Node* const regexp, |
961 JSRegExp::Flag flag) { | 964 JSRegExp::Flag flag) { |
962 Node* const smi_zero = SmiConstant(Smi::kZero); | 965 Node* const smi_zero = SmiConstant(Smi::kZero); |
963 Node* const flags = LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 966 Node* const flags = LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
964 Node* const mask = SmiConstant(Smi::FromInt(flag)); | 967 Node* const mask = SmiConstant(Smi::FromInt(flag)); |
965 Node* const is_flag_set = WordNotEqual(WordAnd(flags, mask), smi_zero); | 968 Node* const is_flag_set = WordNotEqual(SmiAnd(flags, mask), smi_zero); |
966 | 969 |
967 return is_flag_set; | 970 return is_flag_set; |
968 } | 971 } |
969 | 972 |
970 // Load through the GetProperty stub. | 973 // Load through the GetProperty stub. |
971 Node* RegExpBuiltinsAssembler::SlowFlagGetter(Node* const context, | 974 Node* RegExpBuiltinsAssembler::SlowFlagGetter(Node* const context, |
972 Node* const regexp, | 975 Node* const regexp, |
973 JSRegExp::Flag flag) { | 976 JSRegExp::Flag flag) { |
974 Factory* factory = isolate()->factory(); | 977 Factory* factory = isolate()->factory(); |
975 | 978 |
976 Label out(this); | 979 Label out(this); |
977 Variable var_result(this, MachineType::PointerRepresentation()); | 980 Variable var_result(this, MachineRepresentation::kWord32); |
978 | 981 |
979 Node* name; | 982 Node* name; |
980 | 983 |
981 switch (flag) { | 984 switch (flag) { |
982 case JSRegExp::kGlobal: | 985 case JSRegExp::kGlobal: |
983 name = HeapConstant(factory->global_string()); | 986 name = HeapConstant(factory->global_string()); |
984 break; | 987 break; |
985 case JSRegExp::kIgnoreCase: | 988 case JSRegExp::kIgnoreCase: |
986 name = HeapConstant(factory->ignoreCase_string()); | 989 name = HeapConstant(factory->ignoreCase_string()); |
987 break; | 990 break; |
(...skipping 11 matching lines...) Expand all Loading... |
999 } | 1002 } |
1000 | 1003 |
1001 Callable getproperty_callable = CodeFactory::GetProperty(isolate()); | 1004 Callable getproperty_callable = CodeFactory::GetProperty(isolate()); |
1002 Node* const value = CallStub(getproperty_callable, context, regexp, name); | 1005 Node* const value = CallStub(getproperty_callable, context, regexp, name); |
1003 | 1006 |
1004 Label if_true(this), if_false(this); | 1007 Label if_true(this), if_false(this); |
1005 BranchIfToBooleanIsTrue(value, &if_true, &if_false); | 1008 BranchIfToBooleanIsTrue(value, &if_true, &if_false); |
1006 | 1009 |
1007 Bind(&if_true); | 1010 Bind(&if_true); |
1008 { | 1011 { |
1009 var_result.Bind(IntPtrConstant(1)); | 1012 var_result.Bind(Int32Constant(1)); |
1010 Goto(&out); | 1013 Goto(&out); |
1011 } | 1014 } |
1012 | 1015 |
1013 Bind(&if_false); | 1016 Bind(&if_false); |
1014 { | 1017 { |
1015 var_result.Bind(IntPtrConstant(0)); | 1018 var_result.Bind(Int32Constant(0)); |
1016 Goto(&out); | 1019 Goto(&out); |
1017 } | 1020 } |
1018 | 1021 |
1019 Bind(&out); | 1022 Bind(&out); |
1020 return var_result.value(); | 1023 return var_result.value(); |
1021 } | 1024 } |
1022 | 1025 |
1023 Node* RegExpBuiltinsAssembler::FlagGetter(Node* const context, | 1026 Node* RegExpBuiltinsAssembler::FlagGetter(Node* const context, |
1024 Node* const regexp, | 1027 Node* const regexp, |
1025 JSRegExp::Flag flag, | 1028 JSRegExp::Flag flag, |
(...skipping 1216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2242 Bind(&if_isstring); | 2245 Bind(&if_isstring); |
2243 { | 2246 { |
2244 CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(elem))); | 2247 CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(elem))); |
2245 | 2248 |
2246 Callable call_callable = CodeFactory::Call(isolate); | 2249 Callable call_callable = CodeFactory::Call(isolate); |
2247 Node* const replacement_obj = | 2250 Node* const replacement_obj = |
2248 CallJS(call_callable, context, replace_callable, undefined, elem, | 2251 CallJS(call_callable, context, replace_callable, undefined, elem, |
2249 var_match_start.value(), string); | 2252 var_match_start.value(), string); |
2250 | 2253 |
2251 Node* const replacement_str = ToString(context, replacement_obj); | 2254 Node* const replacement_str = ToString(context, replacement_obj); |
2252 StoreFixedArrayElement(res_elems, i, replacement_str); | 2255 StoreFixedArrayElement(res_elems, i, replacement_str, |
| 2256 UPDATE_WRITE_BARRIER, 0, mode); |
2253 | 2257 |
2254 Node* const elem_length = LoadStringLength(elem); | 2258 Node* const elem_length = LoadStringLength(elem); |
2255 Node* const new_match_start = | 2259 Node* const new_match_start = |
2256 SmiAdd(var_match_start.value(), elem_length); | 2260 SmiAdd(var_match_start.value(), elem_length); |
2257 var_match_start.Bind(new_match_start); | 2261 var_match_start.Bind(new_match_start); |
2258 | 2262 |
2259 Goto(&loop_epilogue); | 2263 Goto(&loop_epilogue); |
2260 } | 2264 } |
2261 | 2265 |
2262 Bind(&loop_epilogue); | 2266 Bind(&loop_epilogue); |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2432 } | 2436 } |
2433 | 2437 |
2434 // ES#sec-regexp.prototype-@@replace | 2438 // ES#sec-regexp.prototype-@@replace |
2435 // RegExp.prototype [ @@replace ] ( string, replaceValue ) | 2439 // RegExp.prototype [ @@replace ] ( string, replaceValue ) |
2436 TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) { | 2440 TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) { |
2437 Node* const maybe_receiver = Parameter(0); | 2441 Node* const maybe_receiver = Parameter(0); |
2438 Node* const maybe_string = Parameter(1); | 2442 Node* const maybe_string = Parameter(1); |
2439 Node* const replace_value = Parameter(2); | 2443 Node* const replace_value = Parameter(2); |
2440 Node* const context = Parameter(5); | 2444 Node* const context = Parameter(5); |
2441 | 2445 |
2442 Node* const int_zero = IntPtrConstant(0); | |
2443 | |
2444 // Ensure {maybe_receiver} is a JSReceiver. | 2446 // Ensure {maybe_receiver} is a JSReceiver. |
2445 Node* const map = ThrowIfNotJSReceiver( | 2447 Node* const map = ThrowIfNotJSReceiver( |
2446 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, | 2448 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, |
2447 "RegExp.prototype.@@replace"); | 2449 "RegExp.prototype.@@replace"); |
2448 Node* const receiver = maybe_receiver; | 2450 Node* const receiver = maybe_receiver; |
2449 | 2451 |
2450 // Convert {maybe_string} to a String. | 2452 // Convert {maybe_string} to a String. |
2451 Callable tostring_callable = CodeFactory::ToString(isolate()); | 2453 Callable tostring_callable = CodeFactory::ToString(isolate()); |
2452 Node* const string = CallStub(tostring_callable, context, maybe_string); | 2454 Node* const string = CallStub(tostring_callable, context, maybe_string); |
2453 | 2455 |
(...skipping 11 matching lines...) Expand all Loading... |
2465 | 2467 |
2466 Node* const replace_value_map = LoadMap(replace_value); | 2468 Node* const replace_value_map = LoadMap(replace_value); |
2467 Branch(IsCallableMap(replace_value_map), &if_iscallable, &checkreplacestring); | 2469 Branch(IsCallableMap(replace_value_map), &if_iscallable, &checkreplacestring); |
2468 | 2470 |
2469 // 3. Does ToString({replace_value}) contain '$'? | 2471 // 3. Does ToString({replace_value}) contain '$'? |
2470 Bind(&checkreplacestring); | 2472 Bind(&checkreplacestring); |
2471 { | 2473 { |
2472 Node* const replace_string = | 2474 Node* const replace_string = |
2473 CallStub(tostring_callable, context, replace_value); | 2475 CallStub(tostring_callable, context, replace_value); |
2474 | 2476 |
2475 Node* const dollar_char = IntPtrConstant('$'); | 2477 Node* const dollar_char = Int32Constant('$'); |
2476 Node* const smi_minusone = SmiConstant(Smi::FromInt(-1)); | 2478 Node* const smi_minusone = SmiConstant(Smi::FromInt(-1)); |
2477 GotoUnless(SmiEqual(StringIndexOfChar(context, replace_string, dollar_char, | 2479 GotoUnless(SmiEqual(StringIndexOfChar(context, replace_string, dollar_char, |
2478 int_zero), | 2480 SmiConstant(0)), |
2479 smi_minusone), | 2481 smi_minusone), |
2480 &runtime); | 2482 &runtime); |
2481 | 2483 |
2482 Return( | 2484 Return( |
2483 ReplaceSimpleStringFastPath(context, regexp, string, replace_string)); | 2485 ReplaceSimpleStringFastPath(context, regexp, string, replace_string)); |
2484 } | 2486 } |
2485 | 2487 |
2486 // {regexp} is unmodified and {replace_value} is callable. | 2488 // {regexp} is unmodified and {replace_value} is callable. |
2487 Bind(&if_iscallable); | 2489 Bind(&if_iscallable); |
2488 { | 2490 { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2544 Bind(&if_matched); | 2546 Bind(&if_matched); |
2545 { | 2547 { |
2546 Node* result = | 2548 Node* result = |
2547 ConstructNewResultFromMatchInfo(context, match_indices, string); | 2549 ConstructNewResultFromMatchInfo(context, match_indices, string); |
2548 Return(result); | 2550 Return(result); |
2549 } | 2551 } |
2550 } | 2552 } |
2551 | 2553 |
2552 } // namespace internal | 2554 } // namespace internal |
2553 } // namespace v8 | 2555 } // namespace v8 |
OLD | NEW |