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

Side by Side Diff: src/runtime.cc

Issue 2809048: RegExp replace with empty string optimization by Sandholm. (Closed)
Patch Set: Addressed review comments. Created 10 years, 5 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/factory.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 2266 matching lines...) Expand 10 before | Expand all | Expand 10 after
2277 matched = !match->IsNull(); 2277 matched = !match->IsNull();
2278 } while (matched); 2278 } while (matched);
2279 2279
2280 if (prev < length) { 2280 if (prev < length) {
2281 builder.AddSubjectSlice(prev, length); 2281 builder.AddSubjectSlice(prev, length);
2282 } 2282 }
2283 2283
2284 return *(builder.ToString()); 2284 return *(builder.ToString());
2285 } 2285 }
2286 2286
2287 template <typename ResultSeqString>
2288 static Object* StringReplaceRegExpWithEmptyString(ResultSeqString* subject,
2289 JSRegExp* regexp,
2290 JSArray* last_match_info) {
2291 ASSERT(subject->IsFlat());
2292
2293 HandleScope handles;
2294
2295 Handle<String> subject_handle(subject);
2296 Handle<JSRegExp> regexp_handle(regexp);
2297 Handle<JSArray> last_match_info_handle(last_match_info);
2298 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2299 subject_handle,
2300 0,
2301 last_match_info_handle);
2302 if (match.is_null()) return Failure::Exception();
2303 if (match->IsNull()) return *subject_handle;
2304
2305 ASSERT(last_match_info_handle->HasFastElements());
2306
2307 HandleScope loop_scope;
2308 int start, end;
2309 {
2310 AssertNoAllocation match_info_array_is_not_in_a_handle;
2311 FixedArray* match_info_array =
2312 FixedArray::cast(last_match_info_handle->elements());
2313
2314 start = RegExpImpl::GetCapture(match_info_array, 0);
2315 end = RegExpImpl::GetCapture(match_info_array, 1);
2316 }
2317
2318 int length = subject->length();
2319 int new_length = length - (end - start);
2320 if (new_length == 0) {
2321 return Heap::empty_string();
2322 }
2323 // TODO(sandholm) try to use types statically to determine this.
2324 Handle<ResultSeqString> answer;
2325 if (subject_handle->IsAsciiRepresentation()) {
2326 answer =
2327 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2328 } else {
2329 answer =
2330 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2331 }
2332
2333 // If the regexp isn't global, only match once.
2334 if (!regexp_handle->GetFlags().is_global()) {
2335 if (start > 0) {
2336 String::WriteToFlat(*subject_handle,
2337 answer->GetChars(),
2338 0,
2339 start);
2340 }
2341 if (end < length) {
2342 String::WriteToFlat(*subject_handle,
2343 answer->GetChars() + start,
2344 end,
2345 length);
2346 }
2347 return *answer;
2348 }
2349
2350 int prev = 0; // Index of end of last match.
2351 int next = 0; // Start of next search (prev unless last match was empty).
2352 int position = 0;
2353
2354 do {
2355 if (prev < start) {
2356 // Add substring subject[prev;start] to answer string.
2357 String::WriteToFlat(*subject_handle,
2358 answer->GetChars() + position,
2359 prev,
2360 start);
2361 position += start - prev;
2362 }
2363 prev = end;
2364 next = end;
2365 // Continue from where the match ended, unless it was an empty match.
2366 if (start == end) {
2367 next++;
2368 if (next > length) break;
2369 }
2370 match = RegExpImpl::Exec(regexp_handle,
2371 subject_handle,
2372 next,
2373 last_match_info_handle);
2374 if (match.is_null()) return Failure::Exception();
2375 if (match->IsNull()) break;
2376
2377 ASSERT(last_match_info_handle->HasFastElements());
2378 HandleScope loop_scope;
2379 {
2380 AssertNoAllocation match_info_array_is_not_in_a_handle;
2381 FixedArray* match_info_array =
2382 FixedArray::cast(last_match_info_handle->elements());
2383 start = RegExpImpl::GetCapture(match_info_array, 0);
2384 end = RegExpImpl::GetCapture(match_info_array, 1);
2385 }
2386 } while (true);
2387
2388 if (prev < length) {
2389 // Add substring subject[prev;length] to answer string.
2390 String::WriteToFlat(*subject_handle,
2391 answer->GetChars() + position,
2392 prev,
2393 length);
2394 position += length - prev;
2395 }
2396
2397 if (position == 0) {
2398 return Heap::empty_string();
2399 }
2400
2401 // Shorten string and fill
2402 int string_size = ResultSeqString::SizeFor(position);
2403 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2404 int delta = allocated_string_size - string_size;
2405
2406 answer->set_length(position);
2407 if (delta == 0) return *answer;
2408
2409 Address end_of_string = answer->address() + string_size;
2410 Heap::CreateFillerObjectAt(end_of_string, delta);
2411
2412 return *answer;
2413 }
2414
2287 2415
2288 static Object* Runtime_StringReplaceRegExpWithString(Arguments args) { 2416 static Object* Runtime_StringReplaceRegExpWithString(Arguments args) {
2289 ASSERT(args.length() == 4); 2417 ASSERT(args.length() == 4);
2290 2418
2291 CONVERT_CHECKED(String, subject, args[0]); 2419 CONVERT_CHECKED(String, subject, args[0]);
2292 if (!subject->IsFlat()) { 2420 if (!subject->IsFlat()) {
2293 Object* flat_subject = subject->TryFlatten(); 2421 Object* flat_subject = subject->TryFlatten();
2294 if (flat_subject->IsFailure()) { 2422 if (flat_subject->IsFailure()) {
2295 return flat_subject; 2423 return flat_subject;
2296 } 2424 }
2297 subject = String::cast(flat_subject); 2425 subject = String::cast(flat_subject);
2298 } 2426 }
2299 2427
2300 CONVERT_CHECKED(String, replacement, args[2]); 2428 CONVERT_CHECKED(String, replacement, args[2]);
2301 if (!replacement->IsFlat()) { 2429 if (!replacement->IsFlat()) {
2302 Object* flat_replacement = replacement->TryFlatten(); 2430 Object* flat_replacement = replacement->TryFlatten();
2303 if (flat_replacement->IsFailure()) { 2431 if (flat_replacement->IsFailure()) {
2304 return flat_replacement; 2432 return flat_replacement;
2305 } 2433 }
2306 replacement = String::cast(flat_replacement); 2434 replacement = String::cast(flat_replacement);
2307 } 2435 }
2308 2436
2309 CONVERT_CHECKED(JSRegExp, regexp, args[1]); 2437 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2310 CONVERT_CHECKED(JSArray, last_match_info, args[3]); 2438 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2311 2439
2312 ASSERT(last_match_info->HasFastElements()); 2440 ASSERT(last_match_info->HasFastElements());
2313 2441
2442 if (replacement->length() == 0) {
2443 if (subject->IsAsciiRepresentation()) {
2444 return StringReplaceRegExpWithEmptyString(SeqAsciiString::cast(subject),
2445 regexp,
2446 last_match_info);
2447 } else {
2448 return StringReplaceRegExpWithEmptyString(SeqTwoByteString::cast(subject),
2449 regexp,
2450 last_match_info);
2451 }
2452 }
2453
2314 return StringReplaceRegExpWithString(subject, 2454 return StringReplaceRegExpWithString(subject,
2315 regexp, 2455 regexp,
2316 replacement, 2456 replacement,
2317 last_match_info); 2457 last_match_info);
2318 } 2458 }
2319 2459
2320 2460
2321 // Cap on the maximal shift in the Boyer-Moore implementation. By setting a 2461 // Cap on the maximal shift in the Boyer-Moore implementation. By setting a
2322 // limit, we can fix the size of tables. 2462 // limit, we can fix the size of tables.
2323 static const int kBMMaxShift = 0xff; 2463 static const int kBMMaxShift = 0xff;
(...skipping 8074 matching lines...) Expand 10 before | Expand all | Expand 10 after
10398 } else { 10538 } else {
10399 // Handle last resort GC and make sure to allow future allocations 10539 // Handle last resort GC and make sure to allow future allocations
10400 // to grow the heap without causing GCs (if possible). 10540 // to grow the heap without causing GCs (if possible).
10401 Counters::gc_last_resort_from_js.Increment(); 10541 Counters::gc_last_resort_from_js.Increment();
10402 Heap::CollectAllGarbage(false); 10542 Heap::CollectAllGarbage(false);
10403 } 10543 }
10404 } 10544 }
10405 10545
10406 10546
10407 } } // namespace v8::internal 10547 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/factory.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698