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

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

Issue 2776293003: Revert of [regexp] Named capture support for string replacements (Closed)
Patch Set: Created 3 years, 8 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/objects.cc ('k') | src/runtime/runtime-strings.cc » ('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 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 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/runtime/runtime-utils.h" 5 #include "src/runtime/runtime-utils.h"
6 6
7 #include <functional> 7 #include <functional>
8 8
9 #include "src/arguments.h" 9 #include "src/arguments.h"
10 #include "src/conversions-inl.h" 10 #include "src/conversions-inl.h"
11 #include "src/isolate-inl.h" 11 #include "src/isolate-inl.h"
12 #include "src/messages.h" 12 #include "src/messages.h"
13 #include "src/regexp/jsregexp-inl.h" 13 #include "src/regexp/jsregexp-inl.h"
14 #include "src/regexp/jsregexp.h" 14 #include "src/regexp/jsregexp.h"
15 #include "src/regexp/regexp-utils.h" 15 #include "src/regexp/regexp-utils.h"
16 #include "src/string-builder.h" 16 #include "src/string-builder.h"
17 #include "src/string-search.h" 17 #include "src/string-search.h"
18 18
19 namespace v8 { 19 namespace v8 {
20 namespace internal { 20 namespace internal {
21 21
22 namespace {
23
24 // Looks up the capture of the given name. Returns the (1-based) numbered
25 // capture index or -1 on failure.
26 int LookupNamedCapture(std::function<bool(String*)> name_matches,
27 FixedArray* capture_name_map) {
28 // TODO(jgruber): Sort capture_name_map and do binary search via
29 // internalized strings.
30
31 int maybe_capture_index = -1;
32 const int named_capture_count = capture_name_map->length() >> 1;
33 for (int j = 0; j < named_capture_count; j++) {
34 // The format of {capture_name_map} is documented at
35 // JSRegExp::kIrregexpCaptureNameMapIndex.
36 const int name_ix = j * 2;
37 const int index_ix = j * 2 + 1;
38
39 String* capture_name = String::cast(capture_name_map->get(name_ix));
40 if (!name_matches(capture_name)) continue;
41
42 maybe_capture_index = Smi::cast(capture_name_map->get(index_ix))->value();
43 break;
44 }
45
46 return maybe_capture_index;
47 }
48
49 } // namespace
50
51 class CompiledReplacement { 22 class CompiledReplacement {
52 public: 23 public:
53 explicit CompiledReplacement(Zone* zone) 24 explicit CompiledReplacement(Zone* zone)
54 : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {} 25 : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {}
55 26
56 // Return whether the replacement is simple. Can also fail and return Nothing 27 // Return whether the replacement is simple.
57 // if the given replacement string is invalid (and requires throwing a 28 bool Compile(Handle<String> replacement, int capture_count,
58 // SyntaxError). 29 int subject_length);
59 Maybe<bool> Compile(Handle<JSRegExp> regexp, Handle<String> replacement,
60 int capture_count, int subject_length);
61 30
62 // Use Apply only if Compile returned false. 31 // Use Apply only if Compile returned false.
63 void Apply(ReplacementStringBuilder* builder, int match_from, int match_to, 32 void Apply(ReplacementStringBuilder* builder, int match_from, int match_to,
64 int32_t* match); 33 int32_t* match);
65 34
66 // Number of distinct parts of the replacement pattern. 35 // Number of distinct parts of the replacement pattern.
67 int parts() { return parts_.length(); } 36 int parts() { return parts_.length(); }
68 37
69 Zone* zone() const { return zone_; } 38 Zone* zone() const { return zone_; }
70 39
71 private: 40 private:
72 enum PartType { 41 enum PartType {
73 SUBJECT_PREFIX = 1, 42 SUBJECT_PREFIX = 1,
74 SUBJECT_SUFFIX, 43 SUBJECT_SUFFIX,
75 SUBJECT_CAPTURE, 44 SUBJECT_CAPTURE,
76 REPLACEMENT_SUBSTRING, 45 REPLACEMENT_SUBSTRING,
77 REPLACEMENT_STRING, 46 REPLACEMENT_STRING,
78 EMPTY,
79 NUMBER_OF_PART_TYPES 47 NUMBER_OF_PART_TYPES
80 }; 48 };
81 49
82 struct ReplacementPart { 50 struct ReplacementPart {
83 static inline ReplacementPart SubjectMatch() { 51 static inline ReplacementPart SubjectMatch() {
84 return ReplacementPart(SUBJECT_CAPTURE, 0); 52 return ReplacementPart(SUBJECT_CAPTURE, 0);
85 } 53 }
86 static inline ReplacementPart SubjectCapture(int capture_index) { 54 static inline ReplacementPart SubjectCapture(int capture_index) {
87 return ReplacementPart(SUBJECT_CAPTURE, capture_index); 55 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
88 } 56 }
89 static inline ReplacementPart SubjectPrefix() { 57 static inline ReplacementPart SubjectPrefix() {
90 return ReplacementPart(SUBJECT_PREFIX, 0); 58 return ReplacementPart(SUBJECT_PREFIX, 0);
91 } 59 }
92 static inline ReplacementPart SubjectSuffix(int subject_length) { 60 static inline ReplacementPart SubjectSuffix(int subject_length) {
93 return ReplacementPart(SUBJECT_SUFFIX, subject_length); 61 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
94 } 62 }
95 static inline ReplacementPart ReplacementString() { 63 static inline ReplacementPart ReplacementString() {
96 return ReplacementPart(REPLACEMENT_STRING, 0); 64 return ReplacementPart(REPLACEMENT_STRING, 0);
97 } 65 }
98 static inline ReplacementPart ReplacementSubString(int from, int to) { 66 static inline ReplacementPart ReplacementSubString(int from, int to) {
99 DCHECK(from >= 0); 67 DCHECK(from >= 0);
100 DCHECK(to > from); 68 DCHECK(to > from);
101 return ReplacementPart(-from, to); 69 return ReplacementPart(-from, to);
102 } 70 }
103 static inline ReplacementPart Empty() { return ReplacementPart(EMPTY, 0); }
104 71
105 // If tag <= 0 then it is the negation of a start index of a substring of 72 // If tag <= 0 then it is the negation of a start index of a substring of
106 // the replacement pattern, otherwise it's a value from PartType. 73 // the replacement pattern, otherwise it's a value from PartType.
107 ReplacementPart(int tag, int data) : tag(tag), data(data) { 74 ReplacementPart(int tag, int data) : tag(tag), data(data) {
108 // Must be non-positive or a PartType value. 75 // Must be non-positive or a PartType value.
109 DCHECK(tag < NUMBER_OF_PART_TYPES); 76 DCHECK(tag < NUMBER_OF_PART_TYPES);
110 } 77 }
111 // Either a value of PartType or a non-positive number that is 78 // Either a value of PartType or a non-positive number that is
112 // the negation of an index into the replacement string. 79 // the negation of an index into the replacement string.
113 int tag; 80 int tag;
114 // The data value's interpretation depends on the value of tag: 81 // The data value's interpretation depends on the value of tag:
115 // tag == SUBJECT_PREFIX || 82 // tag == SUBJECT_PREFIX ||
116 // tag == SUBJECT_SUFFIX || 83 // tag == SUBJECT_SUFFIX: data is unused.
117 // tag == EMPTY: data is unused.
118 // tag == SUBJECT_CAPTURE: data is the number of the capture. 84 // tag == SUBJECT_CAPTURE: data is the number of the capture.
119 // tag == REPLACEMENT_SUBSTRING || 85 // tag == REPLACEMENT_SUBSTRING ||
120 // tag == REPLACEMENT_STRING: data is index into array of substrings 86 // tag == REPLACEMENT_STRING: data is index into array of substrings
121 // of the replacement string. 87 // of the replacement string.
122 // tag <= 0: Temporary representation of the substring of the replacement 88 // tag <= 0: Temporary representation of the substring of the replacement
123 // string ranging over -tag .. data. 89 // string ranging over -tag .. data.
124 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the 90 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
125 // substring objects. 91 // substring objects.
126 int data; 92 int data;
127 }; 93 };
128 94
129 template <typename Char> 95 template <typename Char>
130 Maybe<bool> ParseReplacementPattern(ZoneList<ReplacementPart>* parts, 96 bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
131 Vector<Char> characters, 97 Vector<Char> characters, int capture_count,
132 FixedArray* capture_name_map, 98 int subject_length, Zone* zone) {
133 int capture_count, int subject_length,
134 Zone* zone) {
135 // Equivalent to String::GetSubstitution, except that this method converts
136 // the replacement string into an internal representation that avoids
137 // repeated parsing when used repeatedly.
138 DCHECK_IMPLIES(capture_name_map != nullptr,
139 FLAG_harmony_regexp_named_captures);
140
141 int length = characters.length(); 99 int length = characters.length();
142 int last = 0; 100 int last = 0;
143 for (int i = 0; i < length; i++) { 101 for (int i = 0; i < length; i++) {
144 Char c = characters[i]; 102 Char c = characters[i];
145 if (c == '$') { 103 if (c == '$') {
146 int next_index = i + 1; 104 int next_index = i + 1;
147 if (next_index == length) { // No next character! 105 if (next_index == length) { // No next character!
148 break; 106 break;
149 } 107 }
150 Char c2 = characters[next_index]; 108 Char c2 = characters[next_index];
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 parts->Add(ReplacementPart::ReplacementSubString(last, i), 176 parts->Add(ReplacementPart::ReplacementSubString(last, i),
219 zone); 177 zone);
220 } 178 }
221 DCHECK(capture_ref <= capture_count); 179 DCHECK(capture_ref <= capture_count);
222 parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone); 180 parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone);
223 last = next_index + 1; 181 last = next_index + 1;
224 } 182 }
225 i = next_index; 183 i = next_index;
226 break; 184 break;
227 } 185 }
228 case '<': {
229 if (capture_name_map == nullptr) {
230 i = next_index;
231 break;
232 }
233
234 // Scan until the next '>', throwing a SyntaxError exception if one
235 // is not found, and let the enclosed substring be groupName.
236
237 const int name_start_index = next_index + 1;
238 int closing_bracket_index = -1;
239 for (int j = name_start_index; j < length; j++) {
240 if (characters[j] == '>') {
241 closing_bracket_index = j;
242 break;
243 }
244 }
245
246 // Throw a SyntaxError for invalid replacement strings.
247 if (closing_bracket_index == -1) return Nothing<bool>();
248
249 Vector<Char> requested_name =
250 characters.SubVector(name_start_index, closing_bracket_index);
251
252 // Let capture be ? Get(namedCaptures, groupName).
253
254 int capture_index = LookupNamedCapture(
255 [=](String* capture_name) {
256 return capture_name->IsEqualTo(requested_name);
257 },
258 capture_name_map);
259
260 // If capture is undefined, replace the text through the following
261 // '>' with the empty string.
262 // Otherwise, replace the text through the following '>' with
263 // ? ToString(capture).
264
265 DCHECK_IMPLIES(
266 capture_index != -1,
267 1 <= capture_index && capture_index <= capture_count);
268
269 ReplacementPart replacement =
270 (capture_index == -1)
271 ? ReplacementPart::Empty()
272 : ReplacementPart::SubjectCapture(capture_index);
273
274 if (i > last) {
275 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
276 }
277 parts->Add(replacement, zone);
278 last = closing_bracket_index + 1;
279 i = closing_bracket_index;
280 break;
281 }
282 default: 186 default:
283 i = next_index; 187 i = next_index;
284 break; 188 break;
285 } 189 }
286 } 190 }
287 } 191 }
288 if (length > last) { 192 if (length > last) {
289 if (last == 0) { 193 if (last == 0) {
290 // Replacement is simple. Do not use Apply to do the replacement. 194 // Replacement is simple. Do not use Apply to do the replacement.
291 return Just(true); 195 return true;
292 } else { 196 } else {
293 parts->Add(ReplacementPart::ReplacementSubString(last, length), zone); 197 parts->Add(ReplacementPart::ReplacementSubString(last, length), zone);
294 } 198 }
295 } 199 }
296 return Just(false); 200 return false;
297 } 201 }
298 202
299 ZoneList<ReplacementPart> parts_; 203 ZoneList<ReplacementPart> parts_;
300 ZoneList<Handle<String> > replacement_substrings_; 204 ZoneList<Handle<String> > replacement_substrings_;
301 Zone* zone_; 205 Zone* zone_;
302 }; 206 };
303 207
304 Maybe<bool> CompiledReplacement::Compile(Handle<JSRegExp> regexp, 208
305 Handle<String> replacement, 209 bool CompiledReplacement::Compile(Handle<String> replacement, int capture_count,
306 int capture_count, 210 int subject_length) {
307 int subject_length) {
308 { 211 {
309 DisallowHeapAllocation no_gc; 212 DisallowHeapAllocation no_gc;
310 String::FlatContent content = replacement->GetFlatContent(); 213 String::FlatContent content = replacement->GetFlatContent();
311 DCHECK(content.IsFlat()); 214 DCHECK(content.IsFlat());
312 215 bool simple = false;
313 FixedArray* capture_name_map = nullptr;
314 if (capture_count > 0) {
315 DCHECK_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
316 Object* maybe_capture_name_map = regexp->CaptureNameMap();
317 if (maybe_capture_name_map->IsFixedArray()) {
318 DCHECK(FLAG_harmony_regexp_named_captures);
319 capture_name_map = FixedArray::cast(maybe_capture_name_map);
320 }
321 }
322
323 Maybe<bool> simple = Nothing<bool>();
324 if (content.IsOneByte()) { 216 if (content.IsOneByte()) {
325 simple = ParseReplacementPattern(&parts_, content.ToOneByteVector(), 217 simple = ParseReplacementPattern(&parts_, content.ToOneByteVector(),
326 capture_name_map, capture_count, 218 capture_count, subject_length, zone());
327 subject_length, zone());
328 } else { 219 } else {
329 DCHECK(content.IsTwoByte()); 220 DCHECK(content.IsTwoByte());
330 simple = ParseReplacementPattern(&parts_, content.ToUC16Vector(), 221 simple = ParseReplacementPattern(&parts_, content.ToUC16Vector(),
331 capture_name_map, capture_count, 222 capture_count, subject_length, zone());
332 subject_length, zone());
333 } 223 }
334 if (simple.IsNothing() || simple.FromJust()) return simple; 224 if (simple) return true;
335 } 225 }
336 226
337 Isolate* isolate = replacement->GetIsolate(); 227 Isolate* isolate = replacement->GetIsolate();
338 // Find substrings of replacement string and create them as String objects. 228 // Find substrings of replacement string and create them as String objects.
339 int substring_index = 0; 229 int substring_index = 0;
340 for (int i = 0, n = parts_.length(); i < n; i++) { 230 for (int i = 0, n = parts_.length(); i < n; i++) {
341 int tag = parts_[i].tag; 231 int tag = parts_[i].tag;
342 if (tag <= 0) { // A replacement string slice. 232 if (tag <= 0) { // A replacement string slice.
343 int from = -tag; 233 int from = -tag;
344 int to = parts_[i].data; 234 int to = parts_[i].data;
345 replacement_substrings_.Add( 235 replacement_substrings_.Add(
346 isolate->factory()->NewSubString(replacement, from, to), zone()); 236 isolate->factory()->NewSubString(replacement, from, to), zone());
347 parts_[i].tag = REPLACEMENT_SUBSTRING; 237 parts_[i].tag = REPLACEMENT_SUBSTRING;
348 parts_[i].data = substring_index; 238 parts_[i].data = substring_index;
349 substring_index++; 239 substring_index++;
350 } else if (tag == REPLACEMENT_STRING) { 240 } else if (tag == REPLACEMENT_STRING) {
351 replacement_substrings_.Add(replacement, zone()); 241 replacement_substrings_.Add(replacement, zone());
352 parts_[i].data = substring_index; 242 parts_[i].data = substring_index;
353 substring_index++; 243 substring_index++;
354 } 244 }
355 } 245 }
356 return Just(false); 246 return false;
357 } 247 }
358 248
359 249
360 void CompiledReplacement::Apply(ReplacementStringBuilder* builder, 250 void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
361 int match_from, int match_to, int32_t* match) { 251 int match_from, int match_to, int32_t* match) {
362 DCHECK_LT(0, parts_.length()); 252 DCHECK_LT(0, parts_.length());
363 for (int i = 0, n = parts_.length(); i < n; i++) { 253 for (int i = 0, n = parts_.length(); i < n; i++) {
364 ReplacementPart part = parts_[i]; 254 ReplacementPart part = parts_[i];
365 switch (part.tag) { 255 switch (part.tag) {
366 case SUBJECT_PREFIX: 256 case SUBJECT_PREFIX:
(...skipping 12 matching lines...) Expand all
379 int to = match[capture * 2 + 1]; 269 int to = match[capture * 2 + 1];
380 if (from >= 0 && to > from) { 270 if (from >= 0 && to > from) {
381 builder->AddSubjectSlice(from, to); 271 builder->AddSubjectSlice(from, to);
382 } 272 }
383 break; 273 break;
384 } 274 }
385 case REPLACEMENT_SUBSTRING: 275 case REPLACEMENT_SUBSTRING:
386 case REPLACEMENT_STRING: 276 case REPLACEMENT_STRING:
387 builder->AddString(replacement_substrings_[part.data]); 277 builder->AddString(replacement_substrings_[part.data]);
388 break; 278 break;
389 case EMPTY:
390 break;
391 default: 279 default:
392 UNREACHABLE(); 280 UNREACHABLE();
393 } 281 }
394 } 282 }
395 } 283 }
396 284
397 void FindOneByteStringIndices(Vector<const uint8_t> subject, uint8_t pattern, 285 void FindOneByteStringIndices(Vector<const uint8_t> subject, uint8_t pattern,
398 List<int>* indices, unsigned int limit) { 286 List<int>* indices, unsigned int limit) {
399 DCHECK(limit > 0); 287 DCHECK(limit > 0);
400 // Collect indices of pattern in subject using memchr. 288 // Collect indices of pattern in subject using memchr.
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 484
597 MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithString( 485 MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithString(
598 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, 486 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp,
599 Handle<String> replacement, Handle<RegExpMatchInfo> last_match_info) { 487 Handle<String> replacement, Handle<RegExpMatchInfo> last_match_info) {
600 DCHECK(subject->IsFlat()); 488 DCHECK(subject->IsFlat());
601 DCHECK(replacement->IsFlat()); 489 DCHECK(replacement->IsFlat());
602 490
603 int capture_count = regexp->CaptureCount(); 491 int capture_count = regexp->CaptureCount();
604 int subject_length = subject->length(); 492 int subject_length = subject->length();
605 493
606 JSRegExp::Type typeTag = regexp->TypeTag();
607 if (typeTag == JSRegExp::IRREGEXP) {
608 // Ensure the RegExp is compiled so we can access the capture-name map.
609 RegExpImpl::IrregexpPrepare(regexp, subject);
610 }
611
612 // CompiledReplacement uses zone allocation. 494 // CompiledReplacement uses zone allocation.
613 Zone zone(isolate->allocator(), ZONE_NAME); 495 Zone zone(isolate->allocator(), ZONE_NAME);
614 CompiledReplacement compiled_replacement(&zone); 496 CompiledReplacement compiled_replacement(&zone);
615 Maybe<bool> maybe_simple_replace = compiled_replacement.Compile( 497 bool simple_replace =
616 regexp, replacement, capture_count, subject_length); 498 compiled_replacement.Compile(replacement, capture_count, subject_length);
617 if (maybe_simple_replace.IsNothing()) {
618 THROW_NEW_ERROR_RETURN_FAILURE(
619 isolate, NewSyntaxError(MessageTemplate::kRegExpInvalidReplaceString,
620 replacement));
621 }
622
623 const bool simple_replace = maybe_simple_replace.FromJust();
624 499
625 // Shortcut for simple non-regexp global replacements 500 // Shortcut for simple non-regexp global replacements
626 if (typeTag == JSRegExp::ATOM && simple_replace) { 501 if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) {
627 if (subject->HasOnlyOneByteChars() && replacement->HasOnlyOneByteChars()) { 502 if (subject->HasOnlyOneByteChars() && replacement->HasOnlyOneByteChars()) {
628 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>( 503 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
629 isolate, subject, regexp, replacement, last_match_info); 504 isolate, subject, regexp, replacement, last_match_info);
630 } else { 505 } else {
631 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>( 506 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
632 isolate, subject, regexp, replacement, last_match_info); 507 isolate, subject, regexp, replacement, last_match_info);
633 } 508 }
634 } 509 }
635 510
636 RegExpImpl::GlobalCache global_cache(regexp, subject, isolate); 511 RegExpImpl::GlobalCache global_cache(regexp, subject, isolate);
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
767 int allocated_string_size = ResultSeqString::SizeFor(new_length); 642 int allocated_string_size = ResultSeqString::SizeFor(new_length);
768 int delta = allocated_string_size - string_size; 643 int delta = allocated_string_size - string_size;
769 644
770 answer->set_length(position); 645 answer->set_length(position);
771 if (delta == 0) return *answer; 646 if (delta == 0) return *answer;
772 647
773 Address end_of_string = answer->address() + string_size; 648 Address end_of_string = answer->address() + string_size;
774 Heap* heap = isolate->heap(); 649 Heap* heap = isolate->heap();
775 650
776 // The trimming is performed on a newly allocated object, which is on a 651 // The trimming is performed on a newly allocated object, which is on a
777 // freshly allocated page or on an already swept page. Hence, the sweeper 652 // fresly allocated page or on an already swept page. Hence, the sweeper
778 // thread can not get confused with the filler creation. No synchronization 653 // thread can not get confused with the filler creation. No synchronization
779 // needed. 654 // needed.
780 // TODO(hpayer): We should shrink the large object page if the size 655 // TODO(hpayer): We should shrink the large object page if the size
781 // of the object changed significantly. 656 // of the object changed significantly.
782 if (!heap->lo_space()->Contains(*answer)) { 657 if (!heap->lo_space()->Contains(*answer)) {
783 heap->CreateFillerObjectAt(end_of_string, delta, ClearRecordedSlots::kNo); 658 heap->CreateFillerObjectAt(end_of_string, delta, ClearRecordedSlots::kNo);
784 } 659 }
785 heap->AdjustLiveBytes(*answer, -delta); 660 heap->AdjustLiveBytes(*answer, -delta);
786 return *answer; 661 return *answer;
787 } 662 }
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
961 isolate->regexp_internal_match_info(); 836 isolate->regexp_internal_match_info();
962 837
963 return StringReplaceGlobalRegExpWithStringHelper( 838 return StringReplaceGlobalRegExpWithStringHelper(
964 isolate, regexp, subject, replacement, internal_match_info); 839 isolate, regexp, subject, replacement, internal_match_info);
965 } 840 }
966 841
967 namespace { 842 namespace {
968 843
969 class MatchInfoBackedMatch : public String::Match { 844 class MatchInfoBackedMatch : public String::Match {
970 public: 845 public:
971 MatchInfoBackedMatch(Isolate* isolate, Handle<JSRegExp> regexp, 846 MatchInfoBackedMatch(Isolate* isolate, Handle<String> subject,
972 Handle<String> subject,
973 Handle<RegExpMatchInfo> match_info) 847 Handle<RegExpMatchInfo> match_info)
974 : isolate_(isolate), match_info_(match_info) { 848 : isolate_(isolate), match_info_(match_info) {
975 subject_ = String::Flatten(subject); 849 subject_ = String::Flatten(subject);
976
977 if (regexp->TypeTag() == JSRegExp::IRREGEXP) {
978 Object* o = regexp->CaptureNameMap();
979 has_named_captures_ = o->IsFixedArray();
980 if (has_named_captures_) {
981 DCHECK(FLAG_harmony_regexp_named_captures);
982 capture_name_map_ = handle(FixedArray::cast(o));
983 }
984 } else {
985 has_named_captures_ = false;
986 }
987 } 850 }
988 851
989 Handle<String> GetMatch() override { 852 Handle<String> GetMatch() override {
990 return RegExpUtils::GenericCaptureGetter(isolate_, match_info_, 0, nullptr); 853 return RegExpUtils::GenericCaptureGetter(isolate_, match_info_, 0, nullptr);
991 } 854 }
992 855
993 Handle<String> GetPrefix() override {
994 const int match_start = match_info_->Capture(0);
995 return isolate_->factory()->NewSubString(subject_, 0, match_start);
996 }
997
998 Handle<String> GetSuffix() override {
999 const int match_end = match_info_->Capture(1);
1000 return isolate_->factory()->NewSubString(subject_, match_end,
1001 subject_->length());
1002 }
1003
1004 bool HasNamedCaptures() override { return has_named_captures_; }
1005
1006 int CaptureCount() override {
1007 return match_info_->NumberOfCaptureRegisters() / 2;
1008 }
1009
1010 MaybeHandle<String> GetCapture(int i, bool* capture_exists) override { 856 MaybeHandle<String> GetCapture(int i, bool* capture_exists) override {
1011 Handle<Object> capture_obj = RegExpUtils::GenericCaptureGetter( 857 Handle<Object> capture_obj = RegExpUtils::GenericCaptureGetter(
1012 isolate_, match_info_, i, capture_exists); 858 isolate_, match_info_, i, capture_exists);
1013 return (*capture_exists) ? Object::ToString(isolate_, capture_obj) 859 return (*capture_exists) ? Object::ToString(isolate_, capture_obj)
1014 : isolate_->factory()->empty_string(); 860 : isolate_->factory()->empty_string();
1015 } 861 }
1016 862
1017 MaybeHandle<String> GetNamedCapture(Handle<String> name, 863 Handle<String> GetPrefix() override {
1018 bool* capture_exists) override { 864 const int match_start = match_info_->Capture(0);
1019 DCHECK(has_named_captures_); 865 return isolate_->factory()->NewSubString(subject_, 0, match_start);
1020 const int capture_index = LookupNamedCapture( 866 }
1021 [=](String* capture_name) { return capture_name->Equals(*name); },
1022 *capture_name_map_);
1023 867
1024 if (capture_index == -1) { 868 Handle<String> GetSuffix() override {
1025 *capture_exists = false; 869 const int match_end = match_info_->Capture(1);
1026 return name; // Arbitrary string handle. 870 return isolate_->factory()->NewSubString(subject_, match_end,
1027 } 871 subject_->length());
872 }
1028 873
1029 DCHECK(1 <= capture_index && capture_index <= CaptureCount()); 874 int CaptureCount() override {
1030 return GetCapture(capture_index, capture_exists); 875 return match_info_->NumberOfCaptureRegisters() / 2;
1031 } 876 }
1032 877
878 virtual ~MatchInfoBackedMatch() {}
879
1033 private: 880 private:
1034 Isolate* isolate_; 881 Isolate* isolate_;
1035 Handle<String> subject_; 882 Handle<String> subject_;
1036 Handle<RegExpMatchInfo> match_info_; 883 Handle<RegExpMatchInfo> match_info_;
1037
1038 bool has_named_captures_;
1039 Handle<FixedArray> capture_name_map_;
1040 }; 884 };
1041 885
1042 class VectorBackedMatch : public String::Match { 886 class VectorBackedMatch : public String::Match {
1043 public: 887 public:
1044 VectorBackedMatch(Isolate* isolate, Handle<String> subject, 888 VectorBackedMatch(Isolate* isolate, Handle<String> subject,
1045 Handle<String> match, int match_position, 889 Handle<String> match, int match_position,
1046 std::vector<Handle<Object>>* captures, 890 std::vector<Handle<Object>>* captures)
1047 Handle<Object> groups_obj)
1048 : isolate_(isolate), 891 : isolate_(isolate),
1049 match_(match), 892 match_(match),
1050 match_position_(match_position), 893 match_position_(match_position),
1051 captures_(captures) { 894 captures_(captures) {
1052 subject_ = String::Flatten(subject); 895 subject_ = String::Flatten(subject);
1053
1054 DCHECK(groups_obj->IsUndefined(isolate) || groups_obj->IsJSReceiver());
1055 has_named_captures_ = !groups_obj->IsUndefined(isolate);
1056 if (has_named_captures_) groups_obj_ = Handle<JSReceiver>::cast(groups_obj);
1057 } 896 }
1058 897
1059 Handle<String> GetMatch() override { return match_; } 898 Handle<String> GetMatch() override { return match_; }
1060 899
1061 Handle<String> GetPrefix() override {
1062 return isolate_->factory()->NewSubString(subject_, 0, match_position_);
1063 }
1064
1065 Handle<String> GetSuffix() override {
1066 const int match_end_position = match_position_ + match_->length();
1067 return isolate_->factory()->NewSubString(subject_, match_end_position,
1068 subject_->length());
1069 }
1070
1071 bool HasNamedCaptures() override { return has_named_captures_; }
1072
1073 int CaptureCount() override { return static_cast<int>(captures_->size()); }
1074
1075 MaybeHandle<String> GetCapture(int i, bool* capture_exists) override { 900 MaybeHandle<String> GetCapture(int i, bool* capture_exists) override {
1076 Handle<Object> capture_obj = captures_->at(i); 901 Handle<Object> capture_obj = captures_->at(i);
1077 if (capture_obj->IsUndefined(isolate_)) { 902 if (capture_obj->IsUndefined(isolate_)) {
1078 *capture_exists = false; 903 *capture_exists = false;
1079 return isolate_->factory()->empty_string(); 904 return isolate_->factory()->empty_string();
1080 } 905 }
1081 *capture_exists = true; 906 *capture_exists = true;
1082 return Object::ToString(isolate_, capture_obj); 907 return Object::ToString(isolate_, capture_obj);
1083 } 908 }
1084 909
1085 MaybeHandle<String> GetNamedCapture(Handle<String> name, 910 Handle<String> GetPrefix() override {
1086 bool* capture_exists) override { 911 return isolate_->factory()->NewSubString(subject_, 0, match_position_);
1087 DCHECK(has_named_captures_);
1088 Handle<Object> capture_obj;
1089 ASSIGN_RETURN_ON_EXCEPTION(isolate_, capture_obj,
1090 Object::GetProperty(groups_obj_, name), String);
1091 if (capture_obj->IsUndefined(isolate_)) {
1092 *capture_exists = false;
1093 return name;
1094 } else {
1095 *capture_exists = true;
1096 return Object::ToString(isolate_, capture_obj);
1097 }
1098 } 912 }
1099 913
914 Handle<String> GetSuffix() override {
915 const int match_end_position = match_position_ + match_->length();
916 return isolate_->factory()->NewSubString(subject_, match_end_position,
917 subject_->length());
918 }
919
920 int CaptureCount() override { return static_cast<int>(captures_->size()); }
921
922 virtual ~VectorBackedMatch() {}
923
1100 private: 924 private:
1101 Isolate* isolate_; 925 Isolate* isolate_;
1102 Handle<String> subject_; 926 Handle<String> subject_;
1103 Handle<String> match_; 927 Handle<String> match_;
1104 const int match_position_; 928 const int match_position_;
1105 std::vector<Handle<Object>>* captures_; 929 std::vector<Handle<Object>>* captures_;
1106
1107 bool has_named_captures_;
1108 Handle<JSReceiver> groups_obj_;
1109 }; 930 };
1110 931
1111 // Create the groups object (see also the RegExp result creation in 932 // Create the groups object (see also the RegExp result creation in
1112 // RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo). 933 // RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo).
1113 Handle<JSObject> ConstructNamedCaptureGroupsObject( 934 Handle<JSObject> ConstructNamedCaptureGroupsObject(
1114 Isolate* isolate, Handle<FixedArray> capture_map, 935 Isolate* isolate, Handle<FixedArray> capture_map,
1115 std::function<Object*(int)> f_get_capture) { 936 std::function<Object*(int)> f_get_capture) {
1116 Handle<JSObject> groups = isolate->factory()->NewJSObjectWithNullProto(); 937 Handle<JSObject> groups = isolate->factory()->NewJSObjectWithNullProto();
1117 938
1118 const int capture_count = capture_map->length() >> 1; 939 const int capture_count = capture_map->length() >> 1;
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
1244 } else { 1065 } else {
1245 DCHECK(current_match[i * 2 + 1] < 0); 1066 DCHECK(current_match[i * 2 + 1] < 0);
1246 elements->set(cursor++, isolate->heap()->undefined_value()); 1067 elements->set(cursor++, isolate->heap()->undefined_value());
1247 } 1068 }
1248 } 1069 }
1249 1070
1250 elements->set(cursor++, Smi::FromInt(match_start)); 1071 elements->set(cursor++, Smi::FromInt(match_start));
1251 elements->set(cursor++, *subject); 1072 elements->set(cursor++, *subject);
1252 1073
1253 if (has_named_captures) { 1074 if (has_named_captures) {
1254 DCHECK(FLAG_harmony_regexp_named_captures);
1255 Handle<FixedArray> capture_map = 1075 Handle<FixedArray> capture_map =
1256 Handle<FixedArray>::cast(maybe_capture_map); 1076 Handle<FixedArray>::cast(maybe_capture_map);
1257 Handle<JSObject> groups = ConstructNamedCaptureGroupsObject( 1077 Handle<JSObject> groups = ConstructNamedCaptureGroupsObject(
1258 isolate, capture_map, [=](int ix) { return elements->get(ix); }); 1078 isolate, capture_map, [=](int ix) { return elements->get(ix); });
1259 elements->set(cursor++, *groups); 1079 elements->set(cursor++, *groups);
1260 } 1080 }
1261 1081
1262 DCHECK_EQ(cursor, argc); 1082 DCHECK_EQ(cursor, argc);
1263 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements)); 1083 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements));
1264 } else { 1084 } else {
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
1356 1176
1357 const int start_index = match_indices->Capture(0); 1177 const int start_index = match_indices->Capture(0);
1358 const int end_index = match_indices->Capture(1); 1178 const int end_index = match_indices->Capture(1);
1359 1179
1360 if (sticky) regexp->SetLastIndex(end_index); 1180 if (sticky) regexp->SetLastIndex(end_index);
1361 1181
1362 IncrementalStringBuilder builder(isolate); 1182 IncrementalStringBuilder builder(isolate);
1363 builder.AppendString(factory->NewSubString(string, 0, start_index)); 1183 builder.AppendString(factory->NewSubString(string, 0, start_index));
1364 1184
1365 if (replace->length() > 0) { 1185 if (replace->length() > 0) {
1366 MatchInfoBackedMatch m(isolate, regexp, string, match_indices); 1186 MatchInfoBackedMatch m(isolate, string, match_indices);
1367 Handle<String> replacement; 1187 Handle<String> replacement;
1368 ASSIGN_RETURN_ON_EXCEPTION(isolate, replacement, 1188 ASSIGN_RETURN_ON_EXCEPTION(isolate, replacement,
1369 String::GetSubstitution(isolate, &m, replace), 1189 String::GetSubstitution(isolate, &m, replace),
1370 String); 1190 String);
1371 builder.AppendString(replacement); 1191 builder.AppendString(replacement);
1372 } 1192 }
1373 1193
1374 builder.AppendString( 1194 builder.AppendString(
1375 factory->NewSubString(string, end_index, string->length())); 1195 factory->NewSubString(string, end_index, string->length()));
1376 return builder.Finish(); 1196 return builder.Finish();
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
1489 const int m = match_indices->NumberOfCaptureRegisters() / 2; 1309 const int m = match_indices->NumberOfCaptureRegisters() / 2;
1490 1310
1491 bool has_named_captures = false; 1311 bool has_named_captures = false;
1492 Handle<FixedArray> capture_map; 1312 Handle<FixedArray> capture_map;
1493 if (m > 1) { 1313 if (m > 1) {
1494 // The existence of capture groups implies IRREGEXP kind. 1314 // The existence of capture groups implies IRREGEXP kind.
1495 DCHECK_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP); 1315 DCHECK_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
1496 1316
1497 Object* maybe_capture_map = regexp->CaptureNameMap(); 1317 Object* maybe_capture_map = regexp->CaptureNameMap();
1498 if (maybe_capture_map->IsFixedArray()) { 1318 if (maybe_capture_map->IsFixedArray()) {
1499 DCHECK(FLAG_harmony_regexp_named_captures);
1500 has_named_captures = true; 1319 has_named_captures = true;
1501 capture_map = handle(FixedArray::cast(maybe_capture_map)); 1320 capture_map = handle(FixedArray::cast(maybe_capture_map));
1502 } 1321 }
1503 } 1322 }
1504 1323
1505 const int argc = has_named_captures ? m + 3 : m + 2; 1324 const int argc = has_named_captures ? m + 3 : m + 2;
1506 ScopedVector<Handle<Object>> argv(argc); 1325 ScopedVector<Handle<Object>> argv(argc);
1507 1326
1508 int cursor = 0; 1327 int cursor = 0;
1509 for (int j = 0; j < m; j++) { 1328 for (int j = 0; j < m; j++) {
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after
1877 Handle<Object> replacement_obj; 1696 Handle<Object> replacement_obj;
1878 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1697 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1879 isolate, replacement_obj, 1698 isolate, replacement_obj,
1880 Execution::Call(isolate, replace_obj, factory->undefined_value(), 1699 Execution::Call(isolate, replace_obj, factory->undefined_value(),
1881 argc, argv.start())); 1700 argc, argv.start()));
1882 1701
1883 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1702 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1884 isolate, replacement, Object::ToString(isolate, replacement_obj)); 1703 isolate, replacement, Object::ToString(isolate, replacement_obj));
1885 } else { 1704 } else {
1886 DCHECK(!functional_replace); 1705 DCHECK(!functional_replace);
1887 if (!groups_obj->IsUndefined(isolate)) { 1706 VectorBackedMatch m(isolate, string, match, position, &captures);
1888 // TODO(jgruber): Behavior in this case is not yet specced.
1889 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1890 isolate, groups_obj, JSReceiver::ToObject(isolate, groups_obj));
1891 }
1892 VectorBackedMatch m(isolate, string, match, position, &captures,
1893 groups_obj);
1894 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1707 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1895 isolate, replacement, String::GetSubstitution(isolate, &m, replace)); 1708 isolate, replacement, String::GetSubstitution(isolate, &m, replace));
1896 } 1709 }
1897 1710
1898 if (position >= next_source_position) { 1711 if (position >= next_source_position) {
1899 builder.AppendString( 1712 builder.AppendString(
1900 factory->NewSubString(string, next_source_position, position)); 1713 factory->NewSubString(string, next_source_position, position));
1901 builder.AppendString(replacement); 1714 builder.AppendString(replacement);
1902 1715
1903 next_source_position = position + match_length; 1716 next_source_position = position + match_length;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1935 1748
1936 RUNTIME_FUNCTION(Runtime_IsRegExp) { 1749 RUNTIME_FUNCTION(Runtime_IsRegExp) {
1937 SealHandleScope shs(isolate); 1750 SealHandleScope shs(isolate);
1938 DCHECK_EQ(1, args.length()); 1751 DCHECK_EQ(1, args.length());
1939 CONVERT_ARG_CHECKED(Object, obj, 0); 1752 CONVERT_ARG_CHECKED(Object, obj, 0);
1940 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); 1753 return isolate->heap()->ToBoolean(obj->IsJSRegExp());
1941 } 1754 }
1942 1755
1943 } // namespace internal 1756 } // namespace internal
1944 } // namespace v8 1757 } // namespace v8
OLDNEW
« no previous file with comments | « src/objects.cc ('k') | src/runtime/runtime-strings.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698