OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 #if V8_TARGET_ARCH_IA32 | 5 #if V8_TARGET_ARCH_IA32 |
6 | 6 |
7 #include "src/code-stubs.h" | 7 #include "src/code-stubs.h" |
8 #include "src/api-arguments.h" | 8 #include "src/api-arguments.h" |
9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
456 __ sub(esp, Immediate(kDoubleSize)); | 456 __ sub(esp, Immediate(kDoubleSize)); |
457 __ fstp_d(Operand(esp, 0)); | 457 __ fstp_d(Operand(esp, 0)); |
458 __ movsd(double_result, Operand(esp, 0)); | 458 __ movsd(double_result, Operand(esp, 0)); |
459 __ add(esp, Immediate(kDoubleSize)); | 459 __ add(esp, Immediate(kDoubleSize)); |
460 | 460 |
461 __ bind(&done); | 461 __ bind(&done); |
462 __ ret(0); | 462 __ ret(0); |
463 } | 463 } |
464 | 464 |
465 void RegExpExecStub::Generate(MacroAssembler* masm) { | 465 void RegExpExecStub::Generate(MacroAssembler* masm) { |
466 // Just jump directly to runtime if native RegExp is not selected at compile | |
467 // time or if regexp entry in generated code is turned off runtime switch or | |
468 // at compilation. | |
469 #ifdef V8_INTERPRETED_REGEXP | 466 #ifdef V8_INTERPRETED_REGEXP |
470 __ TailCallRuntime(Runtime::kRegExpExec); | 467 // This case is handled prior to the RegExpExecStub call. |
| 468 __ Abort(kUnexpectedRegExpExecCall); |
471 #else // V8_INTERPRETED_REGEXP | 469 #else // V8_INTERPRETED_REGEXP |
472 | |
473 // Stack frame on entry. | |
474 // esp[0]: return address | |
475 // esp[4]: last_match_info (expected JSArray) | |
476 // esp[8]: previous index | |
477 // esp[12]: subject string | |
478 // esp[16]: JSRegExp object | |
479 | |
480 static const int kLastMatchInfoOffset = 1 * kPointerSize; | |
481 static const int kPreviousIndexOffset = 2 * kPointerSize; | |
482 static const int kSubjectOffset = 3 * kPointerSize; | |
483 static const int kJSRegExpOffset = 4 * kPointerSize; | |
484 | |
485 Label runtime; | |
486 Factory* factory = isolate()->factory(); | |
487 | |
488 // Ensure that a RegExp stack is allocated. | |
489 ExternalReference address_of_regexp_stack_memory_address = | |
490 ExternalReference::address_of_regexp_stack_memory_address(isolate()); | |
491 ExternalReference address_of_regexp_stack_memory_size = | |
492 ExternalReference::address_of_regexp_stack_memory_size(isolate()); | |
493 __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); | |
494 __ test(ebx, ebx); | |
495 __ j(zero, &runtime); | |
496 | |
497 // Check that the first argument is a JSRegExp object. | |
498 __ mov(eax, Operand(esp, kJSRegExpOffset)); | |
499 STATIC_ASSERT(kSmiTag == 0); | |
500 __ JumpIfSmi(eax, &runtime); | |
501 __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx); | |
502 __ j(not_equal, &runtime); | |
503 | |
504 // Check that the RegExp has been compiled (data contains a fixed array). | |
505 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); | |
506 if (FLAG_debug_code) { | |
507 __ test(ecx, Immediate(kSmiTagMask)); | |
508 __ Check(not_zero, kUnexpectedTypeForRegExpDataFixedArrayExpected); | |
509 __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); | |
510 __ Check(equal, kUnexpectedTypeForRegExpDataFixedArrayExpected); | |
511 } | |
512 | |
513 // ecx: RegExp data (FixedArray) | |
514 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | |
515 __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset)); | |
516 __ cmp(ebx, Immediate(Smi::FromInt(JSRegExp::IRREGEXP))); | |
517 __ j(not_equal, &runtime); | |
518 | |
519 // ecx: RegExp data (FixedArray) | |
520 // Check that the number of captures fit in the static offsets vector buffer. | |
521 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); | |
522 // Check (number_of_captures + 1) * 2 <= offsets vector size | |
523 // Or number_of_captures * 2 <= offsets vector size - 2 | |
524 // Multiplying by 2 comes for free since edx is smi-tagged. | |
525 STATIC_ASSERT(kSmiTag == 0); | |
526 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | |
527 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); | |
528 __ cmp(edx, Isolate::kJSRegexpStaticOffsetsVectorSize - 2); | |
529 __ j(above, &runtime); | |
530 | |
531 // Reset offset for possibly sliced string. | |
532 __ Move(edi, Immediate(0)); | |
533 __ mov(eax, Operand(esp, kSubjectOffset)); | |
534 __ JumpIfSmi(eax, &runtime); | |
535 __ mov(edx, eax); // Make a copy of the original subject string. | |
536 | |
537 // eax: subject string | |
538 // edx: subject string | |
539 // ecx: RegExp data (FixedArray) | |
540 // Handle subject string according to its encoding and representation: | |
541 // (1) Sequential two byte? If yes, go to (9). | |
542 // (2) Sequential one byte? If yes, go to (5). | |
543 // (3) Sequential or cons? If not, go to (6). | |
544 // (4) Cons string. If the string is flat, replace subject with first string | |
545 // and go to (1). Otherwise bail out to runtime. | |
546 // (5) One byte sequential. Load regexp code for one byte. | |
547 // (E) Carry on. | |
548 /// [...] | |
549 | |
550 // Deferred code at the end of the stub: | |
551 // (6) Long external string? If not, go to (10). | |
552 // (7) External string. Make it, offset-wise, look like a sequential string. | |
553 // (8) Is the external string one byte? If yes, go to (5). | |
554 // (9) Two byte sequential. Load regexp code for two byte. Go to (E). | |
555 // (10) Short external string or not a string? If yes, bail out to runtime. | |
556 // (11) Sliced or thin string. Replace subject with parent. Go to (1). | |
557 | |
558 Label seq_one_byte_string /* 5 */, seq_two_byte_string /* 9 */, | |
559 external_string /* 7 */, check_underlying /* 1 */, | |
560 not_seq_nor_cons /* 6 */, check_code /* E */, not_long_external /* 10 */; | |
561 | |
562 __ bind(&check_underlying); | |
563 // (1) Sequential two byte? If yes, go to (9). | |
564 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | |
565 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | |
566 | |
567 __ and_(ebx, kIsNotStringMask | | |
568 kStringRepresentationMask | | |
569 kStringEncodingMask | | |
570 kShortExternalStringMask); | |
571 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); | |
572 __ j(zero, &seq_two_byte_string); // Go to (9). | |
573 | |
574 // (2) Sequential one byte? If yes, go to (5). | |
575 // Any other sequential string must be one byte. | |
576 __ and_(ebx, Immediate(kIsNotStringMask | | |
577 kStringRepresentationMask | | |
578 kShortExternalStringMask)); | |
579 __ j(zero, &seq_one_byte_string, Label::kNear); // Go to (5). | |
580 | |
581 // (3) Sequential or cons? If not, go to (6). | |
582 // We check whether the subject string is a cons, since sequential strings | |
583 // have already been covered. | |
584 STATIC_ASSERT(kConsStringTag < kExternalStringTag); | |
585 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); | |
586 STATIC_ASSERT(kThinStringTag > kExternalStringTag); | |
587 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); | |
588 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); | |
589 __ cmp(ebx, Immediate(kExternalStringTag)); | |
590 __ j(greater_equal, ¬_seq_nor_cons); // Go to (6). | |
591 | |
592 // (4) Cons string. Check that it's flat. | |
593 // Replace subject with first string and reload instance type. | |
594 __ cmp(FieldOperand(eax, ConsString::kSecondOffset), factory->empty_string()); | |
595 __ j(not_equal, &runtime); | |
596 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); | |
597 __ jmp(&check_underlying); | |
598 | |
599 // eax: sequential subject string (or look-alike, external string) | |
600 // edx: original subject string | |
601 // ecx: RegExp data (FixedArray) | |
602 // (5) One byte sequential. Load regexp code for one byte. | |
603 __ bind(&seq_one_byte_string); | |
604 // Load previous index and check range before edx is overwritten. We have | |
605 // to use edx instead of eax here because it might have been only made to | |
606 // look like a sequential string when it actually is an external string. | |
607 __ mov(ebx, Operand(esp, kPreviousIndexOffset)); | |
608 __ JumpIfNotSmi(ebx, &runtime); | |
609 __ cmp(ebx, FieldOperand(edx, String::kLengthOffset)); | |
610 __ j(above_equal, &runtime); | |
611 __ mov(edx, FieldOperand(ecx, JSRegExp::kDataOneByteCodeOffset)); | |
612 __ Move(ecx, Immediate(1)); // Type is one byte. | |
613 | |
614 // (E) Carry on. String handling is done. | |
615 __ bind(&check_code); | |
616 // edx: irregexp code | |
617 // Check that the irregexp code has been generated for the actual string | |
618 // encoding. If it has, the field contains a code object otherwise it contains | |
619 // a smi (code flushing support). | |
620 __ JumpIfSmi(edx, &runtime); | |
621 | |
622 // eax: subject string | |
623 // ebx: previous index (smi) | |
624 // edx: code | |
625 // ecx: encoding of subject string (1 if one_byte, 0 if two_byte); | |
626 // All checks done. Now push arguments for native regexp code. | |
627 Counters* counters = isolate()->counters(); | |
628 __ IncrementCounter(counters->regexp_entry_native(), 1); | |
629 | |
630 // Isolates: note we add an additional parameter here (isolate pointer). | 470 // Isolates: note we add an additional parameter here (isolate pointer). |
631 static const int kRegExpExecuteArguments = 9; | 471 static const int kRegExpExecuteArguments = 9; |
632 __ EnterApiExitFrame(kRegExpExecuteArguments); | 472 __ EnterApiExitFrame(kRegExpExecuteArguments); |
633 | 473 |
634 // Argument 9: Pass current isolate address. | 474 // Argument 9: Pass current isolate address. |
635 __ mov(Operand(esp, 8 * kPointerSize), | 475 __ mov(Operand(esp, 8 * kPointerSize), |
636 Immediate(ExternalReference::isolate_address(isolate()))); | 476 Immediate(ExternalReference::isolate_address(isolate()))); |
637 | 477 |
638 // Argument 8: Indicate that this is a direct call from JavaScript. | 478 // Argument 8: Indicate that this is a direct call from JavaScript. |
639 __ mov(Operand(esp, 7 * kPointerSize), Immediate(1)); | 479 __ mov(Operand(esp, 7 * kPointerSize), Immediate(1)); |
640 | 480 |
641 // Argument 7: Start (high end) of backtracking stack memory area. | 481 // Argument 7: Start (high end) of backtracking stack memory area. |
| 482 ExternalReference address_of_regexp_stack_memory_address = |
| 483 ExternalReference::address_of_regexp_stack_memory_address(isolate()); |
| 484 ExternalReference address_of_regexp_stack_memory_size = |
| 485 ExternalReference::address_of_regexp_stack_memory_size(isolate()); |
642 __ mov(esi, Operand::StaticVariable(address_of_regexp_stack_memory_address)); | 486 __ mov(esi, Operand::StaticVariable(address_of_regexp_stack_memory_address)); |
643 __ add(esi, Operand::StaticVariable(address_of_regexp_stack_memory_size)); | 487 __ add(esi, Operand::StaticVariable(address_of_regexp_stack_memory_size)); |
644 __ mov(Operand(esp, 6 * kPointerSize), esi); | 488 __ mov(Operand(esp, 6 * kPointerSize), esi); |
645 | 489 |
646 // Argument 6: Set the number of capture registers to zero to force global | 490 // Argument 6: Set the number of capture registers to zero to force global |
647 // regexps to behave as non-global. This does not affect non-global regexps. | 491 // regexps to behave as non-global. This does not affect non-global regexps. |
648 __ mov(Operand(esp, 5 * kPointerSize), Immediate(0)); | 492 __ mov(Operand(esp, 5 * kPointerSize), Immediate(0)); |
649 | 493 |
650 // Argument 5: static offsets vector buffer. | 494 // Argument 5: static offsets vector buffer. |
651 __ mov(Operand(esp, 4 * kPointerSize), | 495 __ mov(Operand(esp, 4 * kPointerSize), |
652 Immediate(ExternalReference::address_of_static_offsets_vector( | 496 Immediate(ExternalReference::address_of_static_offsets_vector( |
653 isolate()))); | 497 isolate()))); |
654 | 498 |
| 499 // Argument 4: End of string data |
| 500 // Argument 3: Start of string data |
| 501 __ mov(Operand(esp, 3 * kPointerSize), |
| 502 RegExpExecDescriptor::StringEndRegister()); |
| 503 __ mov(Operand(esp, 2 * kPointerSize), |
| 504 RegExpExecDescriptor::StringStartRegister()); |
| 505 |
655 // Argument 2: Previous index. | 506 // Argument 2: Previous index. |
656 __ SmiUntag(ebx); | 507 __ mov(Operand(esp, 1 * kPointerSize), |
657 __ mov(Operand(esp, 1 * kPointerSize), ebx); | 508 RegExpExecDescriptor::LastIndexRegister()); |
658 | 509 |
659 // Argument 1: Original subject string. | 510 // Argument 1: Original subject string. |
660 // The original subject is in the previous stack frame. Therefore we have to | 511 __ mov(Operand(esp, 0 * kPointerSize), |
661 // use ebp, which points exactly to one pointer size below the previous esp. | 512 RegExpExecDescriptor::StringRegister()); |
662 // (Because creating a new stack frame pushes the previous ebp onto the stack | |
663 // and thereby moves up esp by one kPointerSize.) | |
664 __ mov(esi, Operand(ebp, kSubjectOffset + kPointerSize)); | |
665 __ mov(Operand(esp, 0 * kPointerSize), esi); | |
666 | |
667 // esi: original subject string | |
668 // eax: underlying subject string | |
669 // ebx: previous index | |
670 // ecx: encoding of subject string (1 if one_byte 0 if two_byte); | |
671 // edx: code | |
672 // Argument 4: End of string data | |
673 // Argument 3: Start of string data | |
674 // Prepare start and end index of the input. | |
675 // Load the length from the original sliced string if that is the case. | |
676 __ mov(esi, FieldOperand(esi, String::kLengthOffset)); | |
677 __ add(esi, edi); // Calculate input end wrt offset. | |
678 __ SmiUntag(edi); | |
679 __ add(ebx, edi); // Calculate input start wrt offset. | |
680 | |
681 // ebx: start index of the input string | |
682 // esi: end index of the input string | |
683 Label setup_two_byte, setup_rest; | |
684 __ test(ecx, ecx); | |
685 __ j(zero, &setup_two_byte, Label::kNear); | |
686 __ SmiUntag(esi); | |
687 __ lea(ecx, FieldOperand(eax, esi, times_1, SeqOneByteString::kHeaderSize)); | |
688 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. | |
689 __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqOneByteString::kHeaderSize)); | |
690 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. | |
691 __ jmp(&setup_rest, Label::kNear); | |
692 | |
693 __ bind(&setup_two_byte); | |
694 STATIC_ASSERT(kSmiTag == 0); | |
695 STATIC_ASSERT(kSmiTagSize == 1); // esi is smi (powered by 2). | |
696 __ lea(ecx, FieldOperand(eax, esi, times_1, SeqTwoByteString::kHeaderSize)); | |
697 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. | |
698 __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); | |
699 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. | |
700 | |
701 __ bind(&setup_rest); | |
702 | 513 |
703 // Locate the code entry and call it. | 514 // Locate the code entry and call it. |
704 __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag)); | 515 __ add(RegExpExecDescriptor::CodeRegister(), |
705 __ call(edx); | 516 Immediate(Code::kHeaderSize - kHeapObjectTag)); |
| 517 __ call(RegExpExecDescriptor::CodeRegister()); |
706 | 518 |
707 // Drop arguments and come back to JS mode. | 519 // Drop arguments and come back to JS mode. |
708 __ LeaveApiExitFrame(true); | 520 __ LeaveApiExitFrame(true); |
709 | 521 |
710 // Check the result. | 522 // TODO(jgruber): Don't tag return value once this is supported by stubs. |
711 Label success; | 523 __ SmiTag(eax); |
712 __ cmp(eax, 1); | 524 __ ret(0 * kPointerSize); |
713 // We expect exactly one result since we force the called regexp to behave | |
714 // as non-global. | |
715 __ j(equal, &success); | |
716 Label failure; | |
717 __ cmp(eax, NativeRegExpMacroAssembler::FAILURE); | |
718 __ j(equal, &failure); | |
719 __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION); | |
720 // If not exception it can only be retry. Handle that in the runtime system. | |
721 __ j(not_equal, &runtime); | |
722 // Result must now be exception. If there is no pending exception already a | |
723 // stack overflow (on the backtrack stack) was detected in RegExp code but | |
724 // haven't created the exception yet. Handle that in the runtime system. | |
725 // TODO(592): Rerunning the RegExp to get the stack overflow exception. | |
726 ExternalReference pending_exception(Isolate::kPendingExceptionAddress, | |
727 isolate()); | |
728 __ mov(edx, Immediate(isolate()->factory()->the_hole_value())); | |
729 __ mov(eax, Operand::StaticVariable(pending_exception)); | |
730 __ cmp(edx, eax); | |
731 __ j(equal, &runtime); | |
732 | |
733 // For exception, throw the exception again. | |
734 __ TailCallRuntime(Runtime::kRegExpExecReThrow); | |
735 | |
736 __ bind(&failure); | |
737 // For failure to match, return null. | |
738 __ mov(eax, factory->null_value()); | |
739 __ ret(4 * kPointerSize); | |
740 | |
741 // Load RegExp data. | |
742 __ bind(&success); | |
743 __ mov(eax, Operand(esp, kJSRegExpOffset)); | |
744 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); | |
745 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); | |
746 // Calculate number of capture registers (number_of_captures + 1) * 2. | |
747 STATIC_ASSERT(kSmiTag == 0); | |
748 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | |
749 __ add(edx, Immediate(2)); // edx was a smi. | |
750 | |
751 // edx: Number of capture registers | |
752 // Check that the last match info is a FixedArray. | |
753 __ mov(ebx, Operand(esp, kLastMatchInfoOffset)); | |
754 __ JumpIfSmi(ebx, &runtime); | |
755 // Check that the object has fast elements. | |
756 __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset)); | |
757 __ cmp(eax, factory->fixed_array_map()); | |
758 __ j(not_equal, &runtime); | |
759 // Check that the last match info has space for the capture registers and the | |
760 // additional information. | |
761 __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset)); | |
762 __ SmiUntag(eax); | |
763 __ sub(eax, Immediate(RegExpMatchInfo::kLastMatchOverhead)); | |
764 __ cmp(edx, eax); | |
765 __ j(greater, &runtime); | |
766 | |
767 // ebx: last_match_info (FixedArray) | |
768 // edx: number of capture registers | |
769 // Store the capture count. | |
770 __ SmiTag(edx); // Number of capture registers to smi. | |
771 __ mov(FieldOperand(ebx, RegExpMatchInfo::kNumberOfCapturesOffset), edx); | |
772 __ SmiUntag(edx); // Number of capture registers back from smi. | |
773 // Store last subject and last input. | |
774 __ mov(eax, Operand(esp, kSubjectOffset)); | |
775 __ mov(ecx, eax); | |
776 __ mov(FieldOperand(ebx, RegExpMatchInfo::kLastSubjectOffset), eax); | |
777 __ RecordWriteField(ebx, RegExpMatchInfo::kLastSubjectOffset, eax, edi, | |
778 kDontSaveFPRegs); | |
779 __ mov(eax, ecx); | |
780 __ mov(FieldOperand(ebx, RegExpMatchInfo::kLastInputOffset), eax); | |
781 __ RecordWriteField(ebx, RegExpMatchInfo::kLastInputOffset, eax, edi, | |
782 kDontSaveFPRegs); | |
783 | |
784 // Get the static offsets vector filled by the native regexp code. | |
785 ExternalReference address_of_static_offsets_vector = | |
786 ExternalReference::address_of_static_offsets_vector(isolate()); | |
787 __ mov(ecx, Immediate(address_of_static_offsets_vector)); | |
788 | |
789 // ebx: last_match_info (FixedArray) | |
790 // ecx: offsets vector | |
791 // edx: number of capture registers | |
792 Label next_capture, done; | |
793 // Capture register counter starts from number of capture registers and | |
794 // counts down until wrapping after zero. | |
795 __ bind(&next_capture); | |
796 __ sub(edx, Immediate(1)); | |
797 __ j(negative, &done, Label::kNear); | |
798 // Read the value from the static offsets vector buffer. | |
799 __ mov(edi, Operand(ecx, edx, times_int_size, 0)); | |
800 __ SmiTag(edi); | |
801 // Store the smi value in the last match info. | |
802 __ mov(FieldOperand(ebx, edx, times_pointer_size, | |
803 RegExpMatchInfo::kFirstCaptureOffset), | |
804 edi); | |
805 __ jmp(&next_capture); | |
806 __ bind(&done); | |
807 | |
808 // Return last match info. | |
809 __ mov(eax, ebx); | |
810 __ ret(4 * kPointerSize); | |
811 | |
812 // Do the runtime call to execute the regexp. | |
813 __ bind(&runtime); | |
814 __ TailCallRuntime(Runtime::kRegExpExec); | |
815 | |
816 // Deferred code for string handling. | |
817 // (6) Long external string? If not, go to (10). | |
818 __ bind(¬_seq_nor_cons); | |
819 // Compare flags are still set from (3). | |
820 __ j(greater, ¬_long_external, Label::kNear); // Go to (10). | |
821 | |
822 // (7) External string. Short external strings have been ruled out. | |
823 __ bind(&external_string); | |
824 // Reload instance type. | |
825 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | |
826 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | |
827 if (FLAG_debug_code) { | |
828 // Assert that we do not have a cons or slice (indirect strings) here. | |
829 // Sequential strings have already been ruled out. | |
830 __ test_b(ebx, Immediate(kIsIndirectStringMask)); | |
831 __ Assert(zero, kExternalStringExpectedButNotFound); | |
832 } | |
833 __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset)); | |
834 // Move the pointer so that offset-wise, it looks like a sequential string. | |
835 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | |
836 __ sub(eax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
837 STATIC_ASSERT(kTwoByteStringTag == 0); | |
838 // (8) Is the external string one byte? If yes, go to (5). | |
839 __ test_b(ebx, Immediate(kStringEncodingMask)); | |
840 __ j(not_zero, &seq_one_byte_string); // Go to (5). | |
841 | |
842 // eax: sequential subject string (or look-alike, external string) | |
843 // edx: original subject string | |
844 // ecx: RegExp data (FixedArray) | |
845 // (9) Two byte sequential. Load regexp code for two byte. Go to (E). | |
846 __ bind(&seq_two_byte_string); | |
847 // Load previous index and check range before edx is overwritten. We have | |
848 // to use edx instead of eax here because it might have been only made to | |
849 // look like a sequential string when it actually is an external string. | |
850 __ mov(ebx, Operand(esp, kPreviousIndexOffset)); | |
851 __ JumpIfNotSmi(ebx, &runtime); | |
852 __ cmp(ebx, FieldOperand(edx, String::kLengthOffset)); | |
853 __ j(above_equal, &runtime); | |
854 __ mov(edx, FieldOperand(ecx, JSRegExp::kDataUC16CodeOffset)); | |
855 __ Move(ecx, Immediate(0)); // Type is two byte. | |
856 __ jmp(&check_code); // Go to (E). | |
857 | |
858 // (10) Not a string or a short external string? If yes, bail out to runtime. | |
859 __ bind(¬_long_external); | |
860 // Catch non-string subject or short external string. | |
861 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); | |
862 __ test(ebx, Immediate(kIsNotStringMask | kShortExternalStringTag)); | |
863 __ j(not_zero, &runtime); | |
864 | |
865 // (11) Sliced or thin string. Replace subject with parent. Go to (1). | |
866 Label thin_string; | |
867 __ cmp(ebx, Immediate(kThinStringTag)); | |
868 __ j(equal, &thin_string, Label::kNear); | |
869 // Load offset into edi and replace subject string with parent. | |
870 __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset)); | |
871 __ mov(eax, FieldOperand(eax, SlicedString::kParentOffset)); | |
872 __ jmp(&check_underlying); // Go to (1). | |
873 | |
874 __ bind(&thin_string); | |
875 __ mov(eax, FieldOperand(eax, ThinString::kActualOffset)); | |
876 __ jmp(&check_underlying); // Go to (1). | |
877 #endif // V8_INTERPRETED_REGEXP | 525 #endif // V8_INTERPRETED_REGEXP |
878 } | 526 } |
879 | 527 |
880 | 528 |
881 static int NegativeComparisonResult(Condition cc) { | 529 static int NegativeComparisonResult(Condition cc) { |
882 DCHECK(cc != equal); | 530 DCHECK(cc != equal); |
883 DCHECK((cc == less) || (cc == less_equal) | 531 DCHECK((cc == less) || (cc == less_equal) |
884 || (cc == greater) || (cc == greater_equal)); | 532 || (cc == greater) || (cc == greater_equal)); |
885 return (cc == greater || cc == greater_equal) ? LESS : GREATER; | 533 return (cc == greater || cc == greater_equal) ? LESS : GREATER; |
886 } | 534 } |
(...skipping 2454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3341 kStackUnwindSpace, nullptr, return_value_operand, | 2989 kStackUnwindSpace, nullptr, return_value_operand, |
3342 NULL); | 2990 NULL); |
3343 } | 2991 } |
3344 | 2992 |
3345 #undef __ | 2993 #undef __ |
3346 | 2994 |
3347 } // namespace internal | 2995 } // namespace internal |
3348 } // namespace v8 | 2996 } // namespace v8 |
3349 | 2997 |
3350 #endif // V8_TARGET_ARCH_IA32 | 2998 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |