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 2267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 | 2287 |
| 2288 template <typename ResultSeqString> |
| 2289 static Object* StringReplaceRegExpWithEmptyString(String* subject, |
| 2290 JSRegExp* regexp, |
| 2291 JSArray* last_match_info) { |
| 2292 ASSERT(subject->IsFlat()); |
| 2293 |
| 2294 HandleScope handles; |
| 2295 |
| 2296 Handle<String> subject_handle(subject); |
| 2297 Handle<JSRegExp> regexp_handle(regexp); |
| 2298 Handle<JSArray> last_match_info_handle(last_match_info); |
| 2299 Handle<Object> match = RegExpImpl::Exec(regexp_handle, |
| 2300 subject_handle, |
| 2301 0, |
| 2302 last_match_info_handle); |
| 2303 if (match.is_null()) return Failure::Exception(); |
| 2304 if (match->IsNull()) return *subject_handle; |
| 2305 |
| 2306 ASSERT(last_match_info_handle->HasFastElements()); |
| 2307 |
| 2308 HandleScope loop_scope; |
| 2309 int start, end; |
| 2310 { |
| 2311 AssertNoAllocation match_info_array_is_not_in_a_handle; |
| 2312 FixedArray* match_info_array = |
| 2313 FixedArray::cast(last_match_info_handle->elements()); |
| 2314 |
| 2315 start = RegExpImpl::GetCapture(match_info_array, 0); |
| 2316 end = RegExpImpl::GetCapture(match_info_array, 1); |
| 2317 } |
| 2318 |
| 2319 int length = subject->length(); |
| 2320 int new_length = length - (end - start); |
| 2321 if (new_length == 0) { |
| 2322 return Heap::empty_string(); |
| 2323 } |
| 2324 Handle<ResultSeqString> answer; |
| 2325 if (ResultSeqString::kHasAsciiEncoding) { |
| 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 |
| 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->HasOnlyAsciiChars()) { |
| 2444 return StringReplaceRegExpWithEmptyString<SeqAsciiString>( |
| 2445 subject, regexp, last_match_info); |
| 2446 } else { |
| 2447 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>( |
| 2448 subject, regexp, last_match_info); |
| 2449 } |
| 2450 } |
| 2451 |
2314 return StringReplaceRegExpWithString(subject, | 2452 return StringReplaceRegExpWithString(subject, |
2315 regexp, | 2453 regexp, |
2316 replacement, | 2454 replacement, |
2317 last_match_info); | 2455 last_match_info); |
2318 } | 2456 } |
2319 | 2457 |
2320 | 2458 |
2321 // Cap on the maximal shift in the Boyer-Moore implementation. By setting a | 2459 // Cap on the maximal shift in the Boyer-Moore implementation. By setting a |
2322 // limit, we can fix the size of tables. | 2460 // limit, we can fix the size of tables. |
2323 static const int kBMMaxShift = 0xff; | 2461 static const int kBMMaxShift = 0xff; |
(...skipping 3106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5430 return Heap::nan_value(); | 5568 return Heap::nan_value(); |
5431 } | 5569 } |
5432 | 5570 |
5433 | 5571 |
5434 static Object* Runtime_NumberAdd(Arguments args) { | 5572 static Object* Runtime_NumberAdd(Arguments args) { |
5435 NoHandleAllocation ha; | 5573 NoHandleAllocation ha; |
5436 ASSERT(args.length() == 2); | 5574 ASSERT(args.length() == 2); |
5437 | 5575 |
5438 CONVERT_DOUBLE_CHECKED(x, args[0]); | 5576 CONVERT_DOUBLE_CHECKED(x, args[0]); |
5439 CONVERT_DOUBLE_CHECKED(y, args[1]); | 5577 CONVERT_DOUBLE_CHECKED(y, args[1]); |
5440 return Heap::AllocateHeapNumber(x + y); | 5578 return Heap::NumberFromDouble(x + y); |
5441 } | 5579 } |
5442 | 5580 |
5443 | 5581 |
5444 static Object* Runtime_NumberSub(Arguments args) { | 5582 static Object* Runtime_NumberSub(Arguments args) { |
5445 NoHandleAllocation ha; | 5583 NoHandleAllocation ha; |
5446 ASSERT(args.length() == 2); | 5584 ASSERT(args.length() == 2); |
5447 | 5585 |
5448 CONVERT_DOUBLE_CHECKED(x, args[0]); | 5586 CONVERT_DOUBLE_CHECKED(x, args[0]); |
5449 CONVERT_DOUBLE_CHECKED(y, args[1]); | 5587 CONVERT_DOUBLE_CHECKED(y, args[1]); |
5450 return Heap::AllocateHeapNumber(x - y); | 5588 return Heap::NumberFromDouble(x - y); |
5451 } | 5589 } |
5452 | 5590 |
5453 | 5591 |
5454 static Object* Runtime_NumberMul(Arguments args) { | 5592 static Object* Runtime_NumberMul(Arguments args) { |
5455 NoHandleAllocation ha; | 5593 NoHandleAllocation ha; |
5456 ASSERT(args.length() == 2); | 5594 ASSERT(args.length() == 2); |
5457 | 5595 |
5458 CONVERT_DOUBLE_CHECKED(x, args[0]); | 5596 CONVERT_DOUBLE_CHECKED(x, args[0]); |
5459 CONVERT_DOUBLE_CHECKED(y, args[1]); | 5597 CONVERT_DOUBLE_CHECKED(y, args[1]); |
5460 return Heap::AllocateHeapNumber(x * y); | 5598 return Heap::NumberFromDouble(x * y); |
5461 } | 5599 } |
5462 | 5600 |
5463 | 5601 |
5464 static Object* Runtime_NumberUnaryMinus(Arguments args) { | 5602 static Object* Runtime_NumberUnaryMinus(Arguments args) { |
5465 NoHandleAllocation ha; | 5603 NoHandleAllocation ha; |
5466 ASSERT(args.length() == 1); | 5604 ASSERT(args.length() == 1); |
5467 | 5605 |
5468 CONVERT_DOUBLE_CHECKED(x, args[0]); | 5606 CONVERT_DOUBLE_CHECKED(x, args[0]); |
5469 return Heap::AllocateHeapNumber(-x); | 5607 return Heap::NumberFromDouble(-x); |
5470 } | 5608 } |
5471 | 5609 |
5472 | 5610 |
5473 static Object* Runtime_NumberDiv(Arguments args) { | 5611 static Object* Runtime_NumberDiv(Arguments args) { |
5474 NoHandleAllocation ha; | 5612 NoHandleAllocation ha; |
5475 ASSERT(args.length() == 2); | 5613 ASSERT(args.length() == 2); |
5476 | 5614 |
5477 CONVERT_DOUBLE_CHECKED(x, args[0]); | 5615 CONVERT_DOUBLE_CHECKED(x, args[0]); |
5478 CONVERT_DOUBLE_CHECKED(y, args[1]); | 5616 CONVERT_DOUBLE_CHECKED(y, args[1]); |
5479 return Heap::NumberFromDouble(x / y); | 5617 return Heap::NumberFromDouble(x / y); |
(...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6061 NoHandleAllocation ha; | 6199 NoHandleAllocation ha; |
6062 ASSERT(args.length() == 2); | 6200 ASSERT(args.length() == 2); |
6063 Counters::math_pow.Increment(); | 6201 Counters::math_pow.Increment(); |
6064 | 6202 |
6065 CONVERT_DOUBLE_CHECKED(x, args[0]); | 6203 CONVERT_DOUBLE_CHECKED(x, args[0]); |
6066 | 6204 |
6067 // If the second argument is a smi, it is much faster to call the | 6205 // If the second argument is a smi, it is much faster to call the |
6068 // custom powi() function than the generic pow(). | 6206 // custom powi() function than the generic pow(). |
6069 if (args[1]->IsSmi()) { | 6207 if (args[1]->IsSmi()) { |
6070 int y = Smi::cast(args[1])->value(); | 6208 int y = Smi::cast(args[1])->value(); |
6071 return Heap::AllocateHeapNumber(powi(x, y)); | 6209 return Heap::NumberFromDouble(powi(x, y)); |
6072 } | 6210 } |
6073 | 6211 |
6074 CONVERT_DOUBLE_CHECKED(y, args[1]); | 6212 CONVERT_DOUBLE_CHECKED(y, args[1]); |
6075 | 6213 |
6076 if (!isinf(x)) { | 6214 if (!isinf(x)) { |
6077 if (y == 0.5) { | 6215 if (y == 0.5) { |
6078 // It's not uncommon to use Math.pow(x, 0.5) to compute the | 6216 // It's not uncommon to use Math.pow(x, 0.5) to compute the |
6079 // square root of a number. To speed up such computations, we | 6217 // square root of a number. To speed up such computations, we |
6080 // explictly check for this case and use the sqrt() function | 6218 // explictly check for this case and use the sqrt() function |
6081 // which is faster than pow(). | 6219 // which is faster than pow(). |
(...skipping 4316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10398 } else { | 10536 } else { |
10399 // Handle last resort GC and make sure to allow future allocations | 10537 // Handle last resort GC and make sure to allow future allocations |
10400 // to grow the heap without causing GCs (if possible). | 10538 // to grow the heap without causing GCs (if possible). |
10401 Counters::gc_last_resort_from_js.Increment(); | 10539 Counters::gc_last_resort_from_js.Increment(); |
10402 Heap::CollectAllGarbage(false); | 10540 Heap::CollectAllGarbage(false); |
10403 } | 10541 } |
10404 } | 10542 } |
10405 | 10543 |
10406 | 10544 |
10407 } } // namespace v8::internal | 10545 } } // namespace v8::internal |
OLD | NEW |