OLD | NEW |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |