OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 | 44 |
45 #ifdef ARM | 45 #ifdef ARM |
46 #include "regexp-macro-assembler-arm.h" | 46 #include "regexp-macro-assembler-arm.h" |
47 #else // IA32 | 47 #else // IA32 |
48 #include "macro-assembler-ia32.h" | 48 #include "macro-assembler-ia32.h" |
49 #include "regexp-macro-assembler-ia32.h" | 49 #include "regexp-macro-assembler-ia32.h" |
50 #endif | 50 #endif |
51 | 51 |
52 #include "interpreter-irregexp.h" | 52 #include "interpreter-irregexp.h" |
53 | 53 |
54 // Including pcre.h undefines DEBUG to avoid getting debug output from | |
55 // the JSCRE implementation. Make sure to redefine it in debug mode | |
56 // after having included the header file. | |
57 #ifdef DEBUG | |
58 #include "third_party/jscre/pcre.h" | |
59 #define DEBUG | |
60 #else | |
61 #include "third_party/jscre/pcre.h" | |
62 #endif | |
63 | |
64 | 54 |
65 namespace v8 { namespace internal { | 55 namespace v8 { namespace internal { |
66 | 56 |
67 | 57 |
68 static Failure* malloc_failure; | |
69 | |
70 static void* JSREMalloc(size_t size) { | |
71 Object* obj = Heap::AllocateByteArray(size); | |
72 | |
73 // If allocation failed, return a NULL pointer to JSRE, and jsRegExpCompile | |
74 // will return NULL to the caller, performs GC there. | |
75 // Also pass failure information to the caller. | |
76 if (obj->IsFailure()) { | |
77 malloc_failure = Failure::cast(obj); | |
78 return NULL; | |
79 } | |
80 | |
81 // Note: object is unrooted, the caller of jsRegExpCompile must | |
82 // create a handle for the return value before doing heap allocation. | |
83 return reinterpret_cast<void*>(ByteArray::cast(obj)->GetDataStartAddress()); | |
84 } | |
85 | |
86 | |
87 static void JSREFree(void* p) { | |
88 USE(p); // Do nothing, memory is garbage collected. | |
89 } | |
90 | |
91 | |
92 String* RegExpImpl::last_ascii_string_ = NULL; | 58 String* RegExpImpl::last_ascii_string_ = NULL; |
93 String* RegExpImpl::two_byte_cached_string_ = NULL; | 59 String* RegExpImpl::two_byte_cached_string_ = NULL; |
94 | 60 |
95 | 61 |
96 void RegExpImpl::NewSpaceCollectionPrologue() { | 62 void RegExpImpl::NewSpaceCollectionPrologue() { |
97 // The two byte string is always in the old space. The Ascii string may be | 63 // The two byte string is always in the old space. The Ascii string may be |
98 // in either place. If it is in the old space we don't need to do anything. | 64 // in either place. If it is in the old space we don't need to do anything. |
99 if (Heap::InNewSpace(last_ascii_string_)) { | 65 if (Heap::InNewSpace(last_ascii_string_)) { |
100 // Invalidate the cache. | 66 // Invalidate the cache. |
101 last_ascii_string_ = NULL; | 67 last_ascii_string_ = NULL; |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 if (parse_result.simple && !flags.is_ignore_case()) { | 231 if (parse_result.simple && !flags.is_ignore_case()) { |
266 // Parse-tree is a single atom that is equal to the pattern. | 232 // Parse-tree is a single atom that is equal to the pattern. |
267 result = AtomCompile(re, pattern, flags, pattern); | 233 result = AtomCompile(re, pattern, flags, pattern); |
268 } else if (parse_result.tree->IsAtom() && | 234 } else if (parse_result.tree->IsAtom() && |
269 !flags.is_ignore_case() && | 235 !flags.is_ignore_case() && |
270 parse_result.capture_count == 0) { | 236 parse_result.capture_count == 0) { |
271 RegExpAtom* atom = parse_result.tree->AsAtom(); | 237 RegExpAtom* atom = parse_result.tree->AsAtom(); |
272 Vector<const uc16> atom_pattern = atom->data(); | 238 Vector<const uc16> atom_pattern = atom->data(); |
273 Handle<String> atom_string = Factory::NewStringFromTwoByte(atom_pattern); | 239 Handle<String> atom_string = Factory::NewStringFromTwoByte(atom_pattern); |
274 result = AtomCompile(re, pattern, flags, atom_string); | 240 result = AtomCompile(re, pattern, flags, atom_string); |
275 } else if (FLAG_irregexp) { | 241 } else { |
276 result = IrregexpPrepare(re, pattern, flags); | 242 result = IrregexpPrepare(re, pattern, flags); |
277 } else { | |
278 result = JscrePrepare(re, pattern, flags); | |
279 } | 243 } |
280 Object* data = re->data(); | 244 Object* data = re->data(); |
281 if (data->IsFixedArray()) { | 245 if (data->IsFixedArray()) { |
282 // If compilation succeeded then the data is set on the regexp | 246 // If compilation succeeded then the data is set on the regexp |
283 // and we can store it in the cache. | 247 // and we can store it in the cache. |
284 Handle<FixedArray> data(FixedArray::cast(re->data())); | 248 Handle<FixedArray> data(FixedArray::cast(re->data())); |
285 CompilationCache::PutRegExp(pattern, flags, data); | 249 CompilationCache::PutRegExp(pattern, flags, data); |
286 } | 250 } |
287 } | 251 } |
288 | 252 |
289 return result; | 253 return result; |
290 } | 254 } |
291 | 255 |
292 | 256 |
293 Handle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp, | 257 Handle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp, |
294 Handle<String> subject, | 258 Handle<String> subject, |
295 Handle<Object> index) { | 259 Handle<Object> index) { |
296 switch (regexp->TypeTag()) { | 260 switch (regexp->TypeTag()) { |
297 case JSRegExp::ATOM: | 261 case JSRegExp::ATOM: |
298 return AtomExec(regexp, subject, index); | 262 return AtomExec(regexp, subject, index); |
299 case JSRegExp::IRREGEXP: { | 263 case JSRegExp::IRREGEXP: { |
300 Handle<Object> result = IrregexpExec(regexp, subject, index); | 264 Handle<Object> result = IrregexpExec(regexp, subject, index); |
301 ASSERT(!result.is_null() || Top::has_pending_exception()); | 265 ASSERT(!result.is_null() || Top::has_pending_exception()); |
302 return result; | 266 return result; |
303 } | 267 } |
304 case JSRegExp::JSCRE: | |
305 return JscreExec(regexp, subject, index); | |
306 default: | 268 default: |
307 UNREACHABLE(); | 269 UNREACHABLE(); |
308 return Handle<Object>::null(); | 270 return Handle<Object>::null(); |
309 } | 271 } |
310 } | 272 } |
311 | 273 |
312 | 274 |
313 Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp, | 275 Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp, |
314 Handle<String> subject) { | 276 Handle<String> subject) { |
315 switch (regexp->TypeTag()) { | 277 switch (regexp->TypeTag()) { |
316 case JSRegExp::ATOM: | 278 case JSRegExp::ATOM: |
317 return AtomExecGlobal(regexp, subject); | 279 return AtomExecGlobal(regexp, subject); |
318 case JSRegExp::IRREGEXP: { | 280 case JSRegExp::IRREGEXP: { |
319 Handle<Object> result = IrregexpExecGlobal(regexp, subject); | 281 Handle<Object> result = IrregexpExecGlobal(regexp, subject); |
320 ASSERT(!result.is_null() || Top::has_pending_exception()); | 282 ASSERT(!result.is_null() || Top::has_pending_exception()); |
321 return result; | 283 return result; |
322 } | 284 } |
323 case JSRegExp::JSCRE: | |
324 return JscreExecGlobal(regexp, subject); | |
325 default: | 285 default: |
326 UNREACHABLE(); | 286 UNREACHABLE(); |
327 return Handle<Object>::null(); | 287 return Handle<Object>::null(); |
328 } | 288 } |
329 } | 289 } |
330 | 290 |
331 | 291 |
332 // RegExp Atom implementation: Simple string search using indexOf. | 292 // RegExp Atom implementation: Simple string search using indexOf. |
333 | 293 |
334 | 294 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
384 Handle<JSArray> pair = Factory::NewJSArrayWithElements(array); | 344 Handle<JSArray> pair = Factory::NewJSArrayWithElements(array); |
385 SetElement(result, match_count, pair); | 345 SetElement(result, match_count, pair); |
386 match_count++; | 346 match_count++; |
387 index = end; | 347 index = end; |
388 if (needle_length == 0) index++; | 348 if (needle_length == 0) index++; |
389 } | 349 } |
390 return result; | 350 return result; |
391 } | 351 } |
392 | 352 |
393 | 353 |
394 // JSCRE implementation. | |
395 | |
396 | |
397 int RegExpImpl::JscreNumberOfCaptures(Handle<JSRegExp> re) { | |
398 FixedArray* value = FixedArray::cast(re->DataAt(JSRegExp::kJscreDataIndex)); | |
399 return Smi::cast(value->get(kJscreNumberOfCapturesIndex))->value(); | |
400 } | |
401 | |
402 | |
403 ByteArray* RegExpImpl::JscreInternal(Handle<JSRegExp> re) { | |
404 FixedArray* value = FixedArray::cast(re->DataAt(JSRegExp::kJscreDataIndex)); | |
405 return ByteArray::cast(value->get(kJscreInternalIndex)); | |
406 } | |
407 | |
408 | |
409 Handle<Object>RegExpImpl::JscrePrepare(Handle<JSRegExp> re, | |
410 Handle<String> pattern, | |
411 JSRegExp::Flags flags) { | |
412 Handle<Object> value(Heap::undefined_value()); | |
413 Factory::SetRegExpData(re, JSRegExp::JSCRE, pattern, flags, value); | |
414 return re; | |
415 } | |
416 | |
417 | |
418 static inline Object* JscreDoCompile(String* pattern, | |
419 JSRegExp::Flags flags, | |
420 unsigned* number_of_captures, | |
421 const char** error_message, | |
422 v8::jscre::JscreRegExp** code) { | |
423 v8::jscre::JSRegExpIgnoreCaseOption case_option = flags.is_ignore_case() | |
424 ? v8::jscre::JSRegExpIgnoreCase | |
425 : v8::jscre::JSRegExpDoNotIgnoreCase; | |
426 v8::jscre::JSRegExpMultilineOption multiline_option = flags.is_multiline() | |
427 ? v8::jscre::JSRegExpMultiline | |
428 : v8::jscre::JSRegExpSingleLine; | |
429 *error_message = NULL; | |
430 malloc_failure = Failure::Exception(); | |
431 *code = v8::jscre::jsRegExpCompile(pattern->GetTwoByteData(), | |
432 pattern->length(), | |
433 case_option, | |
434 multiline_option, | |
435 number_of_captures, | |
436 error_message, | |
437 &JSREMalloc, | |
438 &JSREFree); | |
439 if (*code == NULL && (malloc_failure->IsRetryAfterGC() || | |
440 malloc_failure->IsOutOfMemoryFailure())) { | |
441 return malloc_failure; | |
442 } else { | |
443 // It doesn't matter which object we return here, we just need to return | |
444 // a non-failure to indicate to the GC-retry code that there was no | |
445 // allocation failure. | |
446 return pattern; | |
447 } | |
448 } | |
449 | |
450 | |
451 static void JscreCompileWithRetryAfterGC(Handle<String> pattern, | |
452 JSRegExp::Flags flags, | |
453 unsigned* number_of_captures, | |
454 const char** error_message, | |
455 v8::jscre::JscreRegExp** code) { | |
456 CALL_HEAP_FUNCTION_VOID(JscreDoCompile(*pattern, | |
457 flags, | |
458 number_of_captures, | |
459 error_message, | |
460 code)); | |
461 } | |
462 | |
463 | |
464 Handle<Object> RegExpImpl::JscreCompile(Handle<JSRegExp> re) { | |
465 ASSERT_EQ(re->TypeTag(), JSRegExp::JSCRE); | |
466 ASSERT(re->DataAt(JSRegExp::kJscreDataIndex)->IsUndefined()); | |
467 | |
468 Handle<String> pattern(re->Pattern()); | |
469 JSRegExp::Flags flags = re->GetFlags(); | |
470 | |
471 Handle<String> two_byte_pattern = StringToTwoByte(pattern); | |
472 | |
473 unsigned number_of_captures; | |
474 const char* error_message = NULL; | |
475 | |
476 v8::jscre::JscreRegExp* code = NULL; | |
477 FlattenString(pattern); | |
478 | |
479 JscreCompileWithRetryAfterGC(two_byte_pattern, | |
480 flags, | |
481 &number_of_captures, | |
482 &error_message, | |
483 &code); | |
484 | |
485 if (code == NULL) { | |
486 // Throw an exception. | |
487 Handle<JSArray> array = Factory::NewJSArray(2); | |
488 SetElement(array, 0, pattern); | |
489 const char* message = | |
490 (error_message == NULL) ? "Unknown regexp error" : error_message; | |
491 SetElement(array, 1, Factory::NewStringFromUtf8(CStrVector(message))); | |
492 Handle<Object> regexp_err = | |
493 Factory::NewSyntaxError("malformed_regexp", array); | |
494 Top::Throw(*regexp_err); | |
495 return Handle<Object>(); | |
496 } | |
497 | |
498 // Convert the return address to a ByteArray pointer. | |
499 Handle<ByteArray> internal( | |
500 ByteArray::FromDataStartAddress(reinterpret_cast<Address>(code))); | |
501 | |
502 Handle<FixedArray> value = Factory::NewFixedArray(kJscreDataLength); | |
503 value->set(kJscreNumberOfCapturesIndex, Smi::FromInt(number_of_captures)); | |
504 value->set(kJscreInternalIndex, *internal); | |
505 Factory::SetRegExpData(re, JSRegExp::JSCRE, pattern, flags, value); | |
506 | |
507 return re; | |
508 } | |
509 | |
510 | |
511 Handle<Object> RegExpImpl::JscreExec(Handle<JSRegExp> regexp, | |
512 Handle<String> subject, | |
513 Handle<Object> index) { | |
514 ASSERT_EQ(regexp->TypeTag(), JSRegExp::JSCRE); | |
515 if (regexp->DataAt(JSRegExp::kJscreDataIndex)->IsUndefined()) { | |
516 Handle<Object> compile_result = JscreCompile(regexp); | |
517 if (compile_result.is_null()) return compile_result; | |
518 } | |
519 ASSERT(regexp->DataAt(JSRegExp::kJscreDataIndex)->IsFixedArray()); | |
520 | |
521 int num_captures = JscreNumberOfCaptures(regexp); | |
522 | |
523 OffsetsVector offsets((num_captures + 1) * 3); | |
524 | |
525 int previous_index = static_cast<int>(DoubleToInteger(index->Number())); | |
526 | |
527 Handle<String> subject16 = CachedStringToTwoByte(subject); | |
528 | |
529 return JscreExecOnce(regexp, | |
530 num_captures, | |
531 subject, | |
532 previous_index, | |
533 subject16->GetTwoByteData(), | |
534 offsets.vector(), | |
535 offsets.length()); | |
536 } | |
537 | |
538 | |
539 Handle<Object> RegExpImpl::JscreExecOnce(Handle<JSRegExp> regexp, | |
540 int num_captures, | |
541 Handle<String> subject, | |
542 int previous_index, | |
543 const uc16* two_byte_subject, | |
544 int* offsets_vector, | |
545 int offsets_vector_length) { | |
546 int rc; | |
547 { | |
548 AssertNoAllocation a; | |
549 ByteArray* internal = JscreInternal(regexp); | |
550 const v8::jscre::JscreRegExp* js_regexp = | |
551 reinterpret_cast<v8::jscre::JscreRegExp*>( | |
552 internal->GetDataStartAddress()); | |
553 | |
554 rc = v8::jscre::jsRegExpExecute(js_regexp, | |
555 two_byte_subject, | |
556 subject->length(), | |
557 previous_index, | |
558 offsets_vector, | |
559 offsets_vector_length); | |
560 } | |
561 | |
562 // The KJS JavaScript engine returns null (ie, a failed match) when | |
563 // JSRE's internal match limit is exceeded. We duplicate that behavior here. | |
564 if (rc == v8::jscre::JSRegExpErrorNoMatch | |
565 || rc == v8::jscre::JSRegExpErrorHitLimit) { | |
566 return Factory::null_value(); | |
567 } | |
568 | |
569 // Other JSRE errors: | |
570 if (rc < 0) { | |
571 // Throw an exception. | |
572 Handle<Object> code(Smi::FromInt(rc)); | |
573 Handle<Object> args[2] = { Factory::LookupAsciiSymbol("jsre_exec"), code }; | |
574 Handle<Object> regexp_err( | |
575 Factory::NewTypeError("jsre_error", HandleVector(args, 2))); | |
576 return Handle<Object>(Top::Throw(*regexp_err)); | |
577 } | |
578 | |
579 Handle<FixedArray> array = Factory::NewFixedArray(2 * (num_captures+1)); | |
580 // The captures come in (start, end+1) pairs. | |
581 for (int i = 0; i < 2 * (num_captures+1); i += 2) { | |
582 array->set(i, Smi::FromInt(offsets_vector[i])); | |
583 array->set(i+1, Smi::FromInt(offsets_vector[i+1])); | |
584 } | |
585 return Factory::NewJSArrayWithElements(array); | |
586 } | |
587 | |
588 | |
589 Handle<Object> RegExpImpl::JscreExecGlobal(Handle<JSRegExp> regexp, | |
590 Handle<String> subject) { | |
591 ASSERT_EQ(regexp->TypeTag(), JSRegExp::JSCRE); | |
592 if (regexp->DataAt(JSRegExp::kJscreDataIndex)->IsUndefined()) { | |
593 Handle<Object> compile_result = JscreCompile(regexp); | |
594 if (compile_result.is_null()) return compile_result; | |
595 } | |
596 ASSERT(regexp->DataAt(JSRegExp::kJscreDataIndex)->IsFixedArray()); | |
597 | |
598 // Prepare space for the return values. | |
599 int num_captures = JscreNumberOfCaptures(regexp); | |
600 | |
601 OffsetsVector offsets((num_captures + 1) * 3); | |
602 | |
603 int previous_index = 0; | |
604 | |
605 Handle<JSArray> result = Factory::NewJSArray(0); | |
606 int i = 0; | |
607 Handle<Object> matches; | |
608 | |
609 Handle<String> subject16 = CachedStringToTwoByte(subject); | |
610 | |
611 do { | |
612 if (previous_index > subject->length() || previous_index < 0) { | |
613 // Per ECMA-262 15.10.6.2, if the previous index is greater than the | |
614 // string length, there is no match. | |
615 matches = Factory::null_value(); | |
616 } else { | |
617 matches = JscreExecOnce(regexp, | |
618 num_captures, | |
619 subject, | |
620 previous_index, | |
621 subject16->GetTwoByteData(), | |
622 offsets.vector(), | |
623 offsets.length()); | |
624 | |
625 if (matches->IsJSArray()) { | |
626 SetElement(result, i, matches); | |
627 i++; | |
628 previous_index = offsets.vector()[1]; | |
629 if (offsets.vector()[0] == offsets.vector()[1]) { | |
630 previous_index++; | |
631 } | |
632 } | |
633 } | |
634 } while (matches->IsJSArray()); | |
635 | |
636 // If we exited the loop with an exception, throw it. | |
637 if (matches->IsNull()) { | |
638 // Exited loop normally. | |
639 return result; | |
640 } else { | |
641 // Exited loop with the exception in matches. | |
642 return matches; | |
643 } | |
644 } | |
645 | |
646 | |
647 // Irregexp implementation. | 354 // Irregexp implementation. |
648 | 355 |
649 | 356 |
650 // Retrieves a compiled version of the regexp for either ASCII or non-ASCII | 357 // Retrieves a compiled version of the regexp for either ASCII or non-ASCII |
651 // strings. If the compiled version doesn't already exist, it is compiled | 358 // strings. If the compiled version doesn't already exist, it is compiled |
652 // from the source pattern. | 359 // from the source pattern. |
653 // Irregexp is not feature complete yet. If there is something in the | 360 // Irregexp is not feature complete yet. If there is something in the |
654 // regexp that the compiler cannot currently handle, an empty | 361 // regexp that the compiler cannot currently handle, an empty |
655 // handle is returned, but no exception is thrown. | 362 // handle is returned, but no exception is thrown. |
656 static Handle<FixedArray> GetCompiledIrregexp(Handle<JSRegExp> re, | 363 static Handle<FixedArray> GetCompiledIrregexp(Handle<JSRegExp> re, |
(...skipping 1406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2063 return DONE; | 1770 return DONE; |
2064 } | 1771 } |
2065 // Generate generic version of the node and bind the label for later use. | 1772 // Generate generic version of the node and bind the label for later use. |
2066 macro_assembler->Bind(&label_); | 1773 macro_assembler->Bind(&label_); |
2067 return CONTINUE; | 1774 return CONTINUE; |
2068 } | 1775 } |
2069 | 1776 |
2070 // We are being asked to make a non-generic version. Keep track of how many | 1777 // We are being asked to make a non-generic version. Keep track of how many |
2071 // non-generic versions we generate so as not to overdo it. | 1778 // non-generic versions we generate so as not to overdo it. |
2072 trace_count_++; | 1779 trace_count_++; |
2073 if (FLAG_irregexp_optimization && | 1780 if (FLAG_regexp_optimization && |
2074 trace_count_ < kMaxCopiesCodeGenerated && | 1781 trace_count_ < kMaxCopiesCodeGenerated && |
2075 compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) { | 1782 compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) { |
2076 return CONTINUE; | 1783 return CONTINUE; |
2077 } | 1784 } |
2078 | 1785 |
2079 // If we get here code has been generated for this node too many times or | 1786 // If we get here code has been generated for this node too many times or |
2080 // recursion is too deep. Time to switch to a generic version. The code for | 1787 // recursion is too deep. Time to switch to a generic version. The code for |
2081 // generic versions above can handle deep recursion properly. | 1788 // generic versions above can handle deep recursion properly. |
2082 trace->Flush(compiler, this); | 1789 trace->Flush(compiler, this); |
2083 return DONE; | 1790 return DONE; |
(...skipping 1146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3230 new_trace.set_characters_preloaded(preload_is_current ? | 2937 new_trace.set_characters_preloaded(preload_is_current ? |
3231 preload_characters : | 2938 preload_characters : |
3232 0); | 2939 0); |
3233 if (preload_has_checked_bounds) { | 2940 if (preload_has_checked_bounds) { |
3234 new_trace.set_bound_checked_up_to(preload_characters); | 2941 new_trace.set_bound_checked_up_to(preload_characters); |
3235 } | 2942 } |
3236 new_trace.quick_check_performed()->Clear(); | 2943 new_trace.quick_check_performed()->Clear(); |
3237 if (not_at_start_) new_trace.set_at_start(Trace::FALSE); | 2944 if (not_at_start_) new_trace.set_at_start(Trace::FALSE); |
3238 alt_gen->expects_preload = preload_is_current; | 2945 alt_gen->expects_preload = preload_is_current; |
3239 bool generate_full_check_inline = false; | 2946 bool generate_full_check_inline = false; |
3240 if (FLAG_irregexp_optimization && | 2947 if (FLAG_regexp_optimization && |
3241 try_to_emit_quick_check_for_alternative(i) && | 2948 try_to_emit_quick_check_for_alternative(i) && |
3242 alternative.node()->EmitQuickCheck(compiler, | 2949 alternative.node()->EmitQuickCheck(compiler, |
3243 &new_trace, | 2950 &new_trace, |
3244 preload_has_checked_bounds, | 2951 preload_has_checked_bounds, |
3245 &alt_gen->possible_success, | 2952 &alt_gen->possible_success, |
3246 &alt_gen->quick_check_details, | 2953 &alt_gen->quick_check_details, |
3247 i < choice_count - 1)) { | 2954 i < choice_count - 1)) { |
3248 // Quick check was generated for this choice. | 2955 // Quick check was generated for this choice. |
3249 preload_is_current = true; | 2956 preload_is_current = true; |
3250 preload_has_checked_bounds = true; | 2957 preload_has_checked_bounds = true; |
(...skipping 780 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4031 // this case. | 3738 // this case. |
4032 static const int kMaxUnrolledMinMatches = 3; // Unroll (foo)+ and (foo){3,} | 3739 static const int kMaxUnrolledMinMatches = 3; // Unroll (foo)+ and (foo){3,} |
4033 static const int kMaxUnrolledMaxMatches = 3; // Unroll (foo)? and (foo){x,3} | 3740 static const int kMaxUnrolledMaxMatches = 3; // Unroll (foo)? and (foo){x,3} |
4034 if (max == 0) return on_success; // This can happen due to recursion. | 3741 if (max == 0) return on_success; // This can happen due to recursion. |
4035 bool body_can_be_empty = (body->min_match() == 0); | 3742 bool body_can_be_empty = (body->min_match() == 0); |
4036 int body_start_reg = RegExpCompiler::kNoRegister; | 3743 int body_start_reg = RegExpCompiler::kNoRegister; |
4037 Interval capture_registers = body->CaptureRegisters(); | 3744 Interval capture_registers = body->CaptureRegisters(); |
4038 bool needs_capture_clearing = !capture_registers.is_empty(); | 3745 bool needs_capture_clearing = !capture_registers.is_empty(); |
4039 if (body_can_be_empty) { | 3746 if (body_can_be_empty) { |
4040 body_start_reg = compiler->AllocateRegister(); | 3747 body_start_reg = compiler->AllocateRegister(); |
4041 } else if (FLAG_irregexp_optimization && !needs_capture_clearing) { | 3748 } else if (FLAG_regexp_optimization && !needs_capture_clearing) { |
4042 // Only unroll if there are no captures and the body can't be | 3749 // Only unroll if there are no captures and the body can't be |
4043 // empty. | 3750 // empty. |
4044 if (min > 0 && min <= kMaxUnrolledMinMatches) { | 3751 if (min > 0 && min <= kMaxUnrolledMinMatches) { |
4045 int new_max = (max == kInfinity) ? max : max - min; | 3752 int new_max = (max == kInfinity) ? max : max - min; |
4046 // Recurse once to get the loop or optional matches after the fixed ones. | 3753 // Recurse once to get the loop or optional matches after the fixed ones. |
4047 RegExpNode* answer = ToNode( | 3754 RegExpNode* answer = ToNode( |
4048 0, new_max, is_greedy, body, compiler, on_success, true); | 3755 0, new_max, is_greedy, body, compiler, on_success, true); |
4049 // Unroll the forced matches from 0 to min. This can cause chains of | 3756 // Unroll the forced matches from 0 to min. This can cause chains of |
4050 // TextNodes (which the parser does not generate). These should be | 3757 // TextNodes (which the parser does not generate). These should be |
4051 // combined if it turns out they hinder good code generation. | 3758 // combined if it turns out they hinder good code generation. |
(...skipping 871 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4923 } else { | 4630 } else { |
4924 node = loop_node; | 4631 node = loop_node; |
4925 } | 4632 } |
4926 } | 4633 } |
4927 data->node = node; | 4634 data->node = node; |
4928 Analysis analysis(ignore_case); | 4635 Analysis analysis(ignore_case); |
4929 analysis.EnsureAnalyzed(node); | 4636 analysis.EnsureAnalyzed(node); |
4930 | 4637 |
4931 NodeInfo info = *node->info(); | 4638 NodeInfo info = *node->info(); |
4932 | 4639 |
4933 if (FLAG_irregexp_native) { | 4640 if (FLAG_regexp_native) { |
4934 #ifdef ARM | 4641 #ifdef ARM |
4935 // Unimplemented, fall-through to bytecode implementation. | 4642 // Unimplemented, fall-through to bytecode implementation. |
4936 #else // IA32 | 4643 #else // IA32 |
4937 RegExpMacroAssemblerIA32::Mode mode; | 4644 RegExpMacroAssemblerIA32::Mode mode; |
4938 if (is_ascii) { | 4645 if (is_ascii) { |
4939 mode = RegExpMacroAssemblerIA32::ASCII; | 4646 mode = RegExpMacroAssemblerIA32::ASCII; |
4940 } else { | 4647 } else { |
4941 mode = RegExpMacroAssemblerIA32::UC16; | 4648 mode = RegExpMacroAssemblerIA32::UC16; |
4942 } | 4649 } |
4943 RegExpMacroAssemblerIA32 macro_assembler(mode, | 4650 RegExpMacroAssemblerIA32 macro_assembler(mode, |
4944 (data->capture_count + 1) * 2); | 4651 (data->capture_count + 1) * 2); |
4945 return compiler.Assemble(¯o_assembler, | 4652 return compiler.Assemble(¯o_assembler, |
4946 node, | 4653 node, |
4947 data->capture_count, | 4654 data->capture_count, |
4948 pattern); | 4655 pattern); |
4949 #endif | 4656 #endif |
4950 } | 4657 } |
4951 EmbeddedVector<byte, 1024> codes; | 4658 EmbeddedVector<byte, 1024> codes; |
4952 RegExpMacroAssemblerIrregexp macro_assembler(codes); | 4659 RegExpMacroAssemblerIrregexp macro_assembler(codes); |
4953 return compiler.Assemble(¯o_assembler, | 4660 return compiler.Assemble(¯o_assembler, |
4954 node, | 4661 node, |
4955 data->capture_count, | 4662 data->capture_count, |
4956 pattern); | 4663 pattern); |
4957 } | 4664 } |
4958 | 4665 |
4959 | 4666 |
4960 }} // namespace v8::internal | 4667 }} // namespace v8::internal |
OLD | NEW |