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 #include "v8.h" | 5 #include "v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_IA32 | 7 #if V8_TARGET_ARCH_X87 |
8 | 8 |
9 #include "bootstrapper.h" | 9 #include "bootstrapper.h" |
10 #include "code-stubs.h" | 10 #include "code-stubs.h" |
11 #include "isolate.h" | 11 #include "isolate.h" |
12 #include "jsregexp.h" | 12 #include "jsregexp.h" |
13 #include "regexp-macro-assembler.h" | 13 #include "regexp-macro-assembler.h" |
14 #include "runtime.h" | 14 #include "runtime.h" |
15 #include "stub-cache.h" | 15 #include "stub-cache.h" |
16 #include "codegen.h" | 16 #include "codegen.h" |
17 #include "runtime.h" | 17 #include "runtime.h" |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 Runtime::FunctionForId(Runtime::kHiddenNumberToString)->entry; | 57 Runtime::FunctionForId(Runtime::kHiddenNumberToString)->entry; |
58 } | 58 } |
59 | 59 |
60 | 60 |
61 void FastCloneShallowArrayStub::InitializeInterfaceDescriptor( | 61 void FastCloneShallowArrayStub::InitializeInterfaceDescriptor( |
62 CodeStubInterfaceDescriptor* descriptor) { | 62 CodeStubInterfaceDescriptor* descriptor) { |
63 static Register registers[] = { eax, ebx, ecx }; | 63 static Register registers[] = { eax, ebx, ecx }; |
64 descriptor->register_param_count_ = 3; | 64 descriptor->register_param_count_ = 3; |
65 descriptor->register_params_ = registers; | 65 descriptor->register_params_ = registers; |
66 static Representation representations[] = { | 66 static Representation representations[] = { |
67 Representation::Tagged(), | 67 Representation::Tagged(), |
68 Representation::Smi(), | 68 Representation::Smi(), |
69 Representation::Tagged() }; | 69 Representation::Tagged() }; |
70 descriptor->register_param_representations_ = representations; | 70 descriptor->register_param_representations_ = representations; |
71 descriptor->deoptimization_handler_ = | 71 descriptor->deoptimization_handler_ = |
72 Runtime::FunctionForId( | 72 Runtime::FunctionForId( |
73 Runtime::kHiddenCreateArrayLiteralStubBailout)->entry; | 73 Runtime::kHiddenCreateArrayLiteralStubBailout)->entry; |
74 } | 74 } |
75 | 75 |
76 | 76 |
77 void FastCloneShallowObjectStub::InitializeInterfaceDescriptor( | 77 void FastCloneShallowObjectStub::InitializeInterfaceDescriptor( |
78 CodeStubInterfaceDescriptor* descriptor) { | 78 CodeStubInterfaceDescriptor* descriptor) { |
79 static Register registers[] = { eax, ebx, ecx, edx }; | 79 static Register registers[] = { eax, ebx, ecx, edx }; |
(...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
472 | 472 |
473 __ ret(0); | 473 __ ret(0); |
474 } | 474 } |
475 | 475 |
476 | 476 |
477 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { | 477 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { |
478 // We don't allow a GC during a store buffer overflow so there is no need to | 478 // We don't allow a GC during a store buffer overflow so there is no need to |
479 // store the registers in any particular way, but we do have to store and | 479 // store the registers in any particular way, but we do have to store and |
480 // restore them. | 480 // restore them. |
481 __ pushad(); | 481 __ pushad(); |
482 if (save_doubles_ == kSaveFPRegs) { | |
483 __ sub(esp, Immediate(kDoubleSize * XMMRegister::kMaxNumRegisters)); | |
484 for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) { | |
485 XMMRegister reg = XMMRegister::from_code(i); | |
486 __ movsd(Operand(esp, i * kDoubleSize), reg); | |
487 } | |
488 } | |
489 const int argument_count = 1; | 482 const int argument_count = 1; |
490 | 483 |
491 AllowExternalCallThatCantCauseGC scope(masm); | 484 AllowExternalCallThatCantCauseGC scope(masm); |
492 __ PrepareCallCFunction(argument_count, ecx); | 485 __ PrepareCallCFunction(argument_count, ecx); |
493 __ mov(Operand(esp, 0 * kPointerSize), | 486 __ mov(Operand(esp, 0 * kPointerSize), |
494 Immediate(ExternalReference::isolate_address(isolate()))); | 487 Immediate(ExternalReference::isolate_address(isolate()))); |
495 __ CallCFunction( | 488 __ CallCFunction( |
496 ExternalReference::store_buffer_overflow_function(isolate()), | 489 ExternalReference::store_buffer_overflow_function(isolate()), |
497 argument_count); | 490 argument_count); |
498 if (save_doubles_ == kSaveFPRegs) { | |
499 for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) { | |
500 XMMRegister reg = XMMRegister::from_code(i); | |
501 __ movsd(reg, Operand(esp, i * kDoubleSize)); | |
502 } | |
503 __ add(esp, Immediate(kDoubleSize * XMMRegister::kMaxNumRegisters)); | |
504 } | |
505 __ popad(); | 491 __ popad(); |
506 __ ret(0); | 492 __ ret(0); |
507 } | 493 } |
508 | 494 |
509 | 495 |
510 class FloatingPointHelper : public AllStatic { | 496 class FloatingPointHelper : public AllStatic { |
511 public: | 497 public: |
512 enum ArgLocation { | 498 enum ArgLocation { |
513 ARGS_ON_STACK, | 499 ARGS_ON_STACK, |
514 ARGS_IN_REGISTERS | 500 ARGS_IN_REGISTERS |
515 }; | 501 }; |
516 | 502 |
517 // Code pattern for loading a floating point value. Input value must | 503 // Code pattern for loading a floating point value. Input value must |
518 // be either a smi or a heap number object (fp value). Requirements: | 504 // be either a smi or a heap number object (fp value). Requirements: |
519 // operand in register number. Returns operand as floating point number | 505 // operand in register number. Returns operand as floating point number |
520 // on FPU stack. | 506 // on FPU stack. |
521 static void LoadFloatOperand(MacroAssembler* masm, Register number); | 507 static void LoadFloatOperand(MacroAssembler* masm, Register number); |
522 | 508 |
523 // Test if operands are smi or number objects (fp). Requirements: | 509 // Test if operands are smi or number objects (fp). Requirements: |
524 // operand_1 in eax, operand_2 in edx; falls through on float | 510 // operand_1 in eax, operand_2 in edx; falls through on float |
525 // operands, jumps to the non_float label otherwise. | 511 // operands, jumps to the non_float label otherwise. |
526 static void CheckFloatOperands(MacroAssembler* masm, | 512 static void CheckFloatOperands(MacroAssembler* masm, |
527 Label* non_float, | 513 Label* non_float, |
528 Register scratch); | 514 Register scratch); |
529 | |
530 // Test if operands are numbers (smi or HeapNumber objects), and load | |
531 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if | |
532 // either operand is not a number. Operands are in edx and eax. | |
533 // Leaves operands unchanged. | |
534 static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers); | |
535 }; | 515 }; |
536 | 516 |
537 | 517 |
538 void DoubleToIStub::Generate(MacroAssembler* masm) { | 518 void DoubleToIStub::Generate(MacroAssembler* masm) { |
539 Register input_reg = this->source(); | 519 Register input_reg = this->source(); |
540 Register final_result_reg = this->destination(); | 520 Register final_result_reg = this->destination(); |
541 ASSERT(is_truncating()); | 521 ASSERT(is_truncating()); |
542 | 522 |
543 Label check_negative, process_64_bits, done, done_no_stash; | 523 Label check_negative, process_64_bits, done, done_no_stash; |
544 | 524 |
(...skipping 19 matching lines...) Expand all Loading... |
564 Register result_reg = final_result_reg.is(ecx) ? eax : final_result_reg; | 544 Register result_reg = final_result_reg.is(ecx) ? eax : final_result_reg; |
565 // Save ecx if it isn't the return register and therefore volatile, or if it | 545 // Save ecx if it isn't the return register and therefore volatile, or if it |
566 // is the return register, then save the temp register we use in its stead for | 546 // is the return register, then save the temp register we use in its stead for |
567 // the result. | 547 // the result. |
568 Register save_reg = final_result_reg.is(ecx) ? eax : ecx; | 548 Register save_reg = final_result_reg.is(ecx) ? eax : ecx; |
569 __ push(scratch1); | 549 __ push(scratch1); |
570 __ push(save_reg); | 550 __ push(save_reg); |
571 | 551 |
572 bool stash_exponent_copy = !input_reg.is(esp); | 552 bool stash_exponent_copy = !input_reg.is(esp); |
573 __ mov(scratch1, mantissa_operand); | 553 __ mov(scratch1, mantissa_operand); |
574 if (CpuFeatures::IsSupported(SSE3)) { | |
575 CpuFeatureScope scope(masm, SSE3); | |
576 // Load x87 register with heap number. | |
577 __ fld_d(mantissa_operand); | |
578 } | |
579 __ mov(ecx, exponent_operand); | 554 __ mov(ecx, exponent_operand); |
580 if (stash_exponent_copy) __ push(ecx); | 555 if (stash_exponent_copy) __ push(ecx); |
581 | 556 |
582 __ and_(ecx, HeapNumber::kExponentMask); | 557 __ and_(ecx, HeapNumber::kExponentMask); |
583 __ shr(ecx, HeapNumber::kExponentShift); | 558 __ shr(ecx, HeapNumber::kExponentShift); |
584 __ lea(result_reg, MemOperand(ecx, -HeapNumber::kExponentBias)); | 559 __ lea(result_reg, MemOperand(ecx, -HeapNumber::kExponentBias)); |
585 __ cmp(result_reg, Immediate(HeapNumber::kMantissaBits)); | 560 __ cmp(result_reg, Immediate(HeapNumber::kMantissaBits)); |
586 __ j(below, &process_64_bits); | 561 __ j(below, &process_64_bits); |
587 | 562 |
588 // Result is entirely in lower 32-bits of mantissa | 563 // Result is entirely in lower 32-bits of mantissa |
589 int delta = HeapNumber::kExponentBias + Double::kPhysicalSignificandSize; | 564 int delta = HeapNumber::kExponentBias + Double::kPhysicalSignificandSize; |
590 if (CpuFeatures::IsSupported(SSE3)) { | |
591 __ fstp(0); | |
592 } | |
593 __ sub(ecx, Immediate(delta)); | 565 __ sub(ecx, Immediate(delta)); |
594 __ xor_(result_reg, result_reg); | 566 __ xor_(result_reg, result_reg); |
595 __ cmp(ecx, Immediate(31)); | 567 __ cmp(ecx, Immediate(31)); |
596 __ j(above, &done); | 568 __ j(above, &done); |
597 __ shl_cl(scratch1); | 569 __ shl_cl(scratch1); |
598 __ jmp(&check_negative); | 570 __ jmp(&check_negative); |
599 | 571 |
600 __ bind(&process_64_bits); | 572 __ bind(&process_64_bits); |
601 if (CpuFeatures::IsSupported(SSE3)) { | 573 // Result must be extracted from shifted 32-bit mantissa |
602 CpuFeatureScope scope(masm, SSE3); | 574 __ sub(ecx, Immediate(delta)); |
603 if (stash_exponent_copy) { | 575 __ neg(ecx); |
604 // Already a copy of the exponent on the stack, overwrite it. | 576 if (stash_exponent_copy) { |
605 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize); | 577 __ mov(result_reg, MemOperand(esp, 0)); |
606 __ sub(esp, Immediate(kDoubleSize / 2)); | |
607 } else { | |
608 // Reserve space for 64 bit answer. | |
609 __ sub(esp, Immediate(kDoubleSize)); // Nolint. | |
610 } | |
611 // Do conversion, which cannot fail because we checked the exponent. | |
612 __ fisttp_d(Operand(esp, 0)); | |
613 __ mov(result_reg, Operand(esp, 0)); // Load low word of answer as result | |
614 __ add(esp, Immediate(kDoubleSize)); | |
615 __ jmp(&done_no_stash); | |
616 } else { | 578 } else { |
617 // Result must be extracted from shifted 32-bit mantissa | 579 __ mov(result_reg, exponent_operand); |
618 __ sub(ecx, Immediate(delta)); | 580 } |
619 __ neg(ecx); | 581 __ and_(result_reg, |
620 if (stash_exponent_copy) { | 582 Immediate(static_cast<uint32_t>(Double::kSignificandMask >> 32))); |
621 __ mov(result_reg, MemOperand(esp, 0)); | 583 __ add(result_reg, |
622 } else { | 584 Immediate(static_cast<uint32_t>(Double::kHiddenBit >> 32))); |
623 __ mov(result_reg, exponent_operand); | 585 __ shrd(result_reg, scratch1); |
624 } | 586 __ shr_cl(result_reg); |
625 __ and_(result_reg, | 587 __ test(ecx, Immediate(32)); |
626 Immediate(static_cast<uint32_t>(Double::kSignificandMask >> 32))); | 588 { |
627 __ add(result_reg, | 589 Label skip_mov; |
628 Immediate(static_cast<uint32_t>(Double::kHiddenBit >> 32))); | 590 __ j(equal, &skip_mov, Label::kNear); |
629 __ shrd(result_reg, scratch1); | 591 __ mov(scratch1, result_reg); |
630 __ shr_cl(result_reg); | 592 __ bind(&skip_mov); |
631 __ test(ecx, Immediate(32)); | |
632 __ cmov(not_equal, scratch1, result_reg); | |
633 } | 593 } |
634 | 594 |
635 // If the double was negative, negate the integer result. | 595 // If the double was negative, negate the integer result. |
636 __ bind(&check_negative); | 596 __ bind(&check_negative); |
637 __ mov(result_reg, scratch1); | 597 __ mov(result_reg, scratch1); |
638 __ neg(result_reg); | 598 __ neg(result_reg); |
639 if (stash_exponent_copy) { | 599 if (stash_exponent_copy) { |
640 __ cmp(MemOperand(esp, 0), Immediate(0)); | 600 __ cmp(MemOperand(esp, 0), Immediate(0)); |
641 } else { | 601 } else { |
642 __ cmp(exponent_operand, Immediate(0)); | 602 __ cmp(exponent_operand, Immediate(0)); |
643 } | 603 } |
644 __ cmov(greater, result_reg, scratch1); | 604 { |
| 605 Label skip_mov; |
| 606 __ j(less_equal, &skip_mov, Label::kNear); |
| 607 __ mov(result_reg, scratch1); |
| 608 __ bind(&skip_mov); |
| 609 } |
645 | 610 |
646 // Restore registers | 611 // Restore registers |
647 __ bind(&done); | 612 __ bind(&done); |
648 if (stash_exponent_copy) { | 613 if (stash_exponent_copy) { |
649 __ add(esp, Immediate(kDoubleSize / 2)); | 614 __ add(esp, Immediate(kDoubleSize / 2)); |
650 } | 615 } |
651 __ bind(&done_no_stash); | 616 __ bind(&done_no_stash); |
652 if (!final_result_reg.is(result_reg)) { | 617 if (!final_result_reg.is(result_reg)) { |
653 ASSERT(final_result_reg.is(ecx)); | 618 ASSERT(final_result_reg.is(ecx)); |
654 __ mov(final_result_reg, result_reg); | 619 __ mov(final_result_reg, result_reg); |
(...skipping 15 matching lines...) Expand all Loading... |
670 __ bind(&load_smi); | 635 __ bind(&load_smi); |
671 __ SmiUntag(number); | 636 __ SmiUntag(number); |
672 __ push(number); | 637 __ push(number); |
673 __ fild_s(Operand(esp, 0)); | 638 __ fild_s(Operand(esp, 0)); |
674 __ pop(number); | 639 __ pop(number); |
675 | 640 |
676 __ bind(&done); | 641 __ bind(&done); |
677 } | 642 } |
678 | 643 |
679 | 644 |
680 void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm, | |
681 Label* not_numbers) { | |
682 Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; | |
683 // Load operand in edx into xmm0, or branch to not_numbers. | |
684 __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); | |
685 Factory* factory = masm->isolate()->factory(); | |
686 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map()); | |
687 __ j(not_equal, not_numbers); // Argument in edx is not a number. | |
688 __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | |
689 __ bind(&load_eax); | |
690 // Load operand in eax into xmm1, or branch to not_numbers. | |
691 __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); | |
692 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map()); | |
693 __ j(equal, &load_float_eax, Label::kNear); | |
694 __ jmp(not_numbers); // Argument in eax is not a number. | |
695 __ bind(&load_smi_edx); | |
696 __ SmiUntag(edx); // Untag smi before converting to float. | |
697 __ Cvtsi2sd(xmm0, edx); | |
698 __ SmiTag(edx); // Retag smi for heap number overwriting test. | |
699 __ jmp(&load_eax); | |
700 __ bind(&load_smi_eax); | |
701 __ SmiUntag(eax); // Untag smi before converting to float. | |
702 __ Cvtsi2sd(xmm1, eax); | |
703 __ SmiTag(eax); // Retag smi for heap number overwriting test. | |
704 __ jmp(&done, Label::kNear); | |
705 __ bind(&load_float_eax); | |
706 __ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | |
707 __ bind(&done); | |
708 } | |
709 | |
710 | |
711 void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, | 645 void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, |
712 Label* non_float, | 646 Label* non_float, |
713 Register scratch) { | 647 Register scratch) { |
714 Label test_other, done; | 648 Label test_other, done; |
715 // Test if both operands are floats or smi -> scratch=k_is_float; | 649 // Test if both operands are floats or smi -> scratch=k_is_float; |
716 // Otherwise scratch = k_not_float. | 650 // Otherwise scratch = k_not_float. |
717 __ JumpIfSmi(edx, &test_other, Label::kNear); | 651 __ JumpIfSmi(edx, &test_other, Label::kNear); |
718 __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset)); | 652 __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset)); |
719 Factory* factory = masm->isolate()->factory(); | 653 Factory* factory = masm->isolate()->factory(); |
720 __ cmp(scratch, factory->heap_number_map()); | 654 __ cmp(scratch, factory->heap_number_map()); |
721 __ j(not_equal, non_float); // argument in edx is not a number -> NaN | 655 __ j(not_equal, non_float); // argument in edx is not a number -> NaN |
722 | 656 |
723 __ bind(&test_other); | 657 __ bind(&test_other); |
724 __ JumpIfSmi(eax, &done, Label::kNear); | 658 __ JumpIfSmi(eax, &done, Label::kNear); |
725 __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset)); | 659 __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset)); |
726 __ cmp(scratch, factory->heap_number_map()); | 660 __ cmp(scratch, factory->heap_number_map()); |
727 __ j(not_equal, non_float); // argument in eax is not a number -> NaN | 661 __ j(not_equal, non_float); // argument in eax is not a number -> NaN |
728 | 662 |
729 // Fall-through: Both operands are numbers. | 663 // Fall-through: Both operands are numbers. |
730 __ bind(&done); | 664 __ bind(&done); |
731 } | 665 } |
732 | 666 |
733 | 667 |
734 void MathPowStub::Generate(MacroAssembler* masm) { | 668 void MathPowStub::Generate(MacroAssembler* masm) { |
735 Factory* factory = isolate()->factory(); | 669 // No SSE2 support |
736 const Register exponent = eax; | 670 UNREACHABLE(); |
737 const Register base = edx; | |
738 const Register scratch = ecx; | |
739 const XMMRegister double_result = xmm3; | |
740 const XMMRegister double_base = xmm2; | |
741 const XMMRegister double_exponent = xmm1; | |
742 const XMMRegister double_scratch = xmm4; | |
743 | |
744 Label call_runtime, done, exponent_not_smi, int_exponent; | |
745 | |
746 // Save 1 in double_result - we need this several times later on. | |
747 __ mov(scratch, Immediate(1)); | |
748 __ Cvtsi2sd(double_result, scratch); | |
749 | |
750 if (exponent_type_ == ON_STACK) { | |
751 Label base_is_smi, unpack_exponent; | |
752 // The exponent and base are supplied as arguments on the stack. | |
753 // This can only happen if the stub is called from non-optimized code. | |
754 // Load input parameters from stack. | |
755 __ mov(base, Operand(esp, 2 * kPointerSize)); | |
756 __ mov(exponent, Operand(esp, 1 * kPointerSize)); | |
757 | |
758 __ JumpIfSmi(base, &base_is_smi, Label::kNear); | |
759 __ cmp(FieldOperand(base, HeapObject::kMapOffset), | |
760 factory->heap_number_map()); | |
761 __ j(not_equal, &call_runtime); | |
762 | |
763 __ movsd(double_base, FieldOperand(base, HeapNumber::kValueOffset)); | |
764 __ jmp(&unpack_exponent, Label::kNear); | |
765 | |
766 __ bind(&base_is_smi); | |
767 __ SmiUntag(base); | |
768 __ Cvtsi2sd(double_base, base); | |
769 | |
770 __ bind(&unpack_exponent); | |
771 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear); | |
772 __ SmiUntag(exponent); | |
773 __ jmp(&int_exponent); | |
774 | |
775 __ bind(&exponent_not_smi); | |
776 __ cmp(FieldOperand(exponent, HeapObject::kMapOffset), | |
777 factory->heap_number_map()); | |
778 __ j(not_equal, &call_runtime); | |
779 __ movsd(double_exponent, | |
780 FieldOperand(exponent, HeapNumber::kValueOffset)); | |
781 } else if (exponent_type_ == TAGGED) { | |
782 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear); | |
783 __ SmiUntag(exponent); | |
784 __ jmp(&int_exponent); | |
785 | |
786 __ bind(&exponent_not_smi); | |
787 __ movsd(double_exponent, | |
788 FieldOperand(exponent, HeapNumber::kValueOffset)); | |
789 } | |
790 | |
791 if (exponent_type_ != INTEGER) { | |
792 Label fast_power, try_arithmetic_simplification; | |
793 __ DoubleToI(exponent, double_exponent, double_scratch, | |
794 TREAT_MINUS_ZERO_AS_ZERO, &try_arithmetic_simplification); | |
795 __ jmp(&int_exponent); | |
796 | |
797 __ bind(&try_arithmetic_simplification); | |
798 // Skip to runtime if possibly NaN (indicated by the indefinite integer). | |
799 __ cvttsd2si(exponent, Operand(double_exponent)); | |
800 __ cmp(exponent, Immediate(0x1)); | |
801 __ j(overflow, &call_runtime); | |
802 | |
803 if (exponent_type_ == ON_STACK) { | |
804 // Detect square root case. Crankshaft detects constant +/-0.5 at | |
805 // compile time and uses DoMathPowHalf instead. We then skip this check | |
806 // for non-constant cases of +/-0.5 as these hardly occur. | |
807 Label continue_sqrt, continue_rsqrt, not_plus_half; | |
808 // Test for 0.5. | |
809 // Load double_scratch with 0.5. | |
810 __ mov(scratch, Immediate(0x3F000000u)); | |
811 __ movd(double_scratch, scratch); | |
812 __ cvtss2sd(double_scratch, double_scratch); | |
813 // Already ruled out NaNs for exponent. | |
814 __ ucomisd(double_scratch, double_exponent); | |
815 __ j(not_equal, ¬_plus_half, Label::kNear); | |
816 | |
817 // Calculates square root of base. Check for the special case of | |
818 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13). | |
819 // According to IEEE-754, single-precision -Infinity has the highest | |
820 // 9 bits set and the lowest 23 bits cleared. | |
821 __ mov(scratch, 0xFF800000u); | |
822 __ movd(double_scratch, scratch); | |
823 __ cvtss2sd(double_scratch, double_scratch); | |
824 __ ucomisd(double_base, double_scratch); | |
825 // Comparing -Infinity with NaN results in "unordered", which sets the | |
826 // zero flag as if both were equal. However, it also sets the carry flag. | |
827 __ j(not_equal, &continue_sqrt, Label::kNear); | |
828 __ j(carry, &continue_sqrt, Label::kNear); | |
829 | |
830 // Set result to Infinity in the special case. | |
831 __ xorps(double_result, double_result); | |
832 __ subsd(double_result, double_scratch); | |
833 __ jmp(&done); | |
834 | |
835 __ bind(&continue_sqrt); | |
836 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. | |
837 __ xorps(double_scratch, double_scratch); | |
838 __ addsd(double_scratch, double_base); // Convert -0 to +0. | |
839 __ sqrtsd(double_result, double_scratch); | |
840 __ jmp(&done); | |
841 | |
842 // Test for -0.5. | |
843 __ bind(¬_plus_half); | |
844 // Load double_exponent with -0.5 by substracting 1. | |
845 __ subsd(double_scratch, double_result); | |
846 // Already ruled out NaNs for exponent. | |
847 __ ucomisd(double_scratch, double_exponent); | |
848 __ j(not_equal, &fast_power, Label::kNear); | |
849 | |
850 // Calculates reciprocal of square root of base. Check for the special | |
851 // case of Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13). | |
852 // According to IEEE-754, single-precision -Infinity has the highest | |
853 // 9 bits set and the lowest 23 bits cleared. | |
854 __ mov(scratch, 0xFF800000u); | |
855 __ movd(double_scratch, scratch); | |
856 __ cvtss2sd(double_scratch, double_scratch); | |
857 __ ucomisd(double_base, double_scratch); | |
858 // Comparing -Infinity with NaN results in "unordered", which sets the | |
859 // zero flag as if both were equal. However, it also sets the carry flag. | |
860 __ j(not_equal, &continue_rsqrt, Label::kNear); | |
861 __ j(carry, &continue_rsqrt, Label::kNear); | |
862 | |
863 // Set result to 0 in the special case. | |
864 __ xorps(double_result, double_result); | |
865 __ jmp(&done); | |
866 | |
867 __ bind(&continue_rsqrt); | |
868 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. | |
869 __ xorps(double_exponent, double_exponent); | |
870 __ addsd(double_exponent, double_base); // Convert -0 to +0. | |
871 __ sqrtsd(double_exponent, double_exponent); | |
872 __ divsd(double_result, double_exponent); | |
873 __ jmp(&done); | |
874 } | |
875 | |
876 // Using FPU instructions to calculate power. | |
877 Label fast_power_failed; | |
878 __ bind(&fast_power); | |
879 __ fnclex(); // Clear flags to catch exceptions later. | |
880 // Transfer (B)ase and (E)xponent onto the FPU register stack. | |
881 __ sub(esp, Immediate(kDoubleSize)); | |
882 __ movsd(Operand(esp, 0), double_exponent); | |
883 __ fld_d(Operand(esp, 0)); // E | |
884 __ movsd(Operand(esp, 0), double_base); | |
885 __ fld_d(Operand(esp, 0)); // B, E | |
886 | |
887 // Exponent is in st(1) and base is in st(0) | |
888 // B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B) | |
889 // FYL2X calculates st(1) * log2(st(0)) | |
890 __ fyl2x(); // X | |
891 __ fld(0); // X, X | |
892 __ frndint(); // rnd(X), X | |
893 __ fsub(1); // rnd(X), X-rnd(X) | |
894 __ fxch(1); // X - rnd(X), rnd(X) | |
895 // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1 | |
896 __ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X) | |
897 __ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X) | |
898 __ faddp(1); // 2^(X-rnd(X)), rnd(X) | |
899 // FSCALE calculates st(0) * 2^st(1) | |
900 __ fscale(); // 2^X, rnd(X) | |
901 __ fstp(1); // 2^X | |
902 // Bail out to runtime in case of exceptions in the status word. | |
903 __ fnstsw_ax(); | |
904 __ test_b(eax, 0x5F); // We check for all but precision exception. | |
905 __ j(not_zero, &fast_power_failed, Label::kNear); | |
906 __ fstp_d(Operand(esp, 0)); | |
907 __ movsd(double_result, Operand(esp, 0)); | |
908 __ add(esp, Immediate(kDoubleSize)); | |
909 __ jmp(&done); | |
910 | |
911 __ bind(&fast_power_failed); | |
912 __ fninit(); | |
913 __ add(esp, Immediate(kDoubleSize)); | |
914 __ jmp(&call_runtime); | |
915 } | |
916 | |
917 // Calculate power with integer exponent. | |
918 __ bind(&int_exponent); | |
919 const XMMRegister double_scratch2 = double_exponent; | |
920 __ mov(scratch, exponent); // Back up exponent. | |
921 __ movsd(double_scratch, double_base); // Back up base. | |
922 __ movsd(double_scratch2, double_result); // Load double_exponent with 1. | |
923 | |
924 // Get absolute value of exponent. | |
925 Label no_neg, while_true, while_false; | |
926 __ test(scratch, scratch); | |
927 __ j(positive, &no_neg, Label::kNear); | |
928 __ neg(scratch); | |
929 __ bind(&no_neg); | |
930 | |
931 __ j(zero, &while_false, Label::kNear); | |
932 __ shr(scratch, 1); | |
933 // Above condition means CF==0 && ZF==0. This means that the | |
934 // bit that has been shifted out is 0 and the result is not 0. | |
935 __ j(above, &while_true, Label::kNear); | |
936 __ movsd(double_result, double_scratch); | |
937 __ j(zero, &while_false, Label::kNear); | |
938 | |
939 __ bind(&while_true); | |
940 __ shr(scratch, 1); | |
941 __ mulsd(double_scratch, double_scratch); | |
942 __ j(above, &while_true, Label::kNear); | |
943 __ mulsd(double_result, double_scratch); | |
944 __ j(not_zero, &while_true); | |
945 | |
946 __ bind(&while_false); | |
947 // scratch has the original value of the exponent - if the exponent is | |
948 // negative, return 1/result. | |
949 __ test(exponent, exponent); | |
950 __ j(positive, &done); | |
951 __ divsd(double_scratch2, double_result); | |
952 __ movsd(double_result, double_scratch2); | |
953 // Test whether result is zero. Bail out to check for subnormal result. | |
954 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. | |
955 __ xorps(double_scratch2, double_scratch2); | |
956 __ ucomisd(double_scratch2, double_result); // Result cannot be NaN. | |
957 // double_exponent aliased as double_scratch2 has already been overwritten | |
958 // and may not have contained the exponent value in the first place when the | |
959 // exponent is a smi. We reset it with exponent value before bailing out. | |
960 __ j(not_equal, &done); | |
961 __ Cvtsi2sd(double_exponent, exponent); | |
962 | |
963 // Returning or bailing out. | |
964 Counters* counters = isolate()->counters(); | |
965 if (exponent_type_ == ON_STACK) { | |
966 // The arguments are still on the stack. | |
967 __ bind(&call_runtime); | |
968 __ TailCallRuntime(Runtime::kHiddenMathPow, 2, 1); | |
969 | |
970 // The stub is called from non-optimized code, which expects the result | |
971 // as heap number in exponent. | |
972 __ bind(&done); | |
973 __ AllocateHeapNumber(eax, scratch, base, &call_runtime); | |
974 __ movsd(FieldOperand(eax, HeapNumber::kValueOffset), double_result); | |
975 __ IncrementCounter(counters->math_pow(), 1); | |
976 __ ret(2 * kPointerSize); | |
977 } else { | |
978 __ bind(&call_runtime); | |
979 { | |
980 AllowExternalCallThatCantCauseGC scope(masm); | |
981 __ PrepareCallCFunction(4, scratch); | |
982 __ movsd(Operand(esp, 0 * kDoubleSize), double_base); | |
983 __ movsd(Operand(esp, 1 * kDoubleSize), double_exponent); | |
984 __ CallCFunction( | |
985 ExternalReference::power_double_double_function(isolate()), 4); | |
986 } | |
987 // Return value is in st(0) on ia32. | |
988 // Store it into the (fixed) result register. | |
989 __ sub(esp, Immediate(kDoubleSize)); | |
990 __ fstp_d(Operand(esp, 0)); | |
991 __ movsd(double_result, Operand(esp, 0)); | |
992 __ add(esp, Immediate(kDoubleSize)); | |
993 | |
994 __ bind(&done); | |
995 __ IncrementCounter(counters->math_pow(), 1); | |
996 __ ret(0); | |
997 } | |
998 } | 671 } |
999 | 672 |
1000 | 673 |
1001 void FunctionPrototypeStub::Generate(MacroAssembler* masm) { | 674 void FunctionPrototypeStub::Generate(MacroAssembler* masm) { |
1002 // ----------- S t a t e ------------- | 675 // ----------- S t a t e ------------- |
1003 // -- ecx : name | 676 // -- ecx : name |
1004 // -- edx : receiver | 677 // -- edx : receiver |
1005 // -- esp[0] : return address | 678 // -- esp[0] : return address |
1006 // ----------------------------------- | 679 // ----------------------------------- |
1007 Label miss; | 680 Label miss; |
(...skipping 753 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1761 __ SmiTag(edx); // Number of capture registers to smi. | 1434 __ SmiTag(edx); // Number of capture registers to smi. |
1762 __ mov(FieldOperand(ebx, RegExpImpl::kLastCaptureCountOffset), edx); | 1435 __ mov(FieldOperand(ebx, RegExpImpl::kLastCaptureCountOffset), edx); |
1763 __ SmiUntag(edx); // Number of capture registers back from smi. | 1436 __ SmiUntag(edx); // Number of capture registers back from smi. |
1764 // Store last subject and last input. | 1437 // Store last subject and last input. |
1765 __ mov(eax, Operand(esp, kSubjectOffset)); | 1438 __ mov(eax, Operand(esp, kSubjectOffset)); |
1766 __ mov(ecx, eax); | 1439 __ mov(ecx, eax); |
1767 __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax); | 1440 __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax); |
1768 __ RecordWriteField(ebx, | 1441 __ RecordWriteField(ebx, |
1769 RegExpImpl::kLastSubjectOffset, | 1442 RegExpImpl::kLastSubjectOffset, |
1770 eax, | 1443 eax, |
1771 edi, | 1444 edi); |
1772 kDontSaveFPRegs); | |
1773 __ mov(eax, ecx); | 1445 __ mov(eax, ecx); |
1774 __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax); | 1446 __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax); |
1775 __ RecordWriteField(ebx, | 1447 __ RecordWriteField(ebx, |
1776 RegExpImpl::kLastInputOffset, | 1448 RegExpImpl::kLastInputOffset, |
1777 eax, | 1449 eax, |
1778 edi, | 1450 edi); |
1779 kDontSaveFPRegs); | |
1780 | 1451 |
1781 // Get the static offsets vector filled by the native regexp code. | 1452 // Get the static offsets vector filled by the native regexp code. |
1782 ExternalReference address_of_static_offsets_vector = | 1453 ExternalReference address_of_static_offsets_vector = |
1783 ExternalReference::address_of_static_offsets_vector(isolate()); | 1454 ExternalReference::address_of_static_offsets_vector(isolate()); |
1784 __ mov(ecx, Immediate(address_of_static_offsets_vector)); | 1455 __ mov(ecx, Immediate(address_of_static_offsets_vector)); |
1785 | 1456 |
1786 // ebx: last_match_info backing store (FixedArray) | 1457 // ebx: last_match_info backing store (FixedArray) |
1787 // ecx: offsets vector | 1458 // ecx: offsets vector |
1788 // edx: number of capture registers | 1459 // edx: number of capture registers |
1789 Label next_capture, done; | 1460 Label next_capture, done; |
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2039 __ j(equal, &return_not_equal); | 1710 __ j(equal, &return_not_equal); |
2040 | 1711 |
2041 // Fall through to the general case. | 1712 // Fall through to the general case. |
2042 __ bind(&slow); | 1713 __ bind(&slow); |
2043 } | 1714 } |
2044 | 1715 |
2045 // Generate the number comparison code. | 1716 // Generate the number comparison code. |
2046 Label non_number_comparison; | 1717 Label non_number_comparison; |
2047 Label unordered; | 1718 Label unordered; |
2048 __ bind(&generic_heap_number_comparison); | 1719 __ bind(&generic_heap_number_comparison); |
| 1720 FloatingPointHelper::CheckFloatOperands( |
| 1721 masm, &non_number_comparison, ebx); |
| 1722 FloatingPointHelper::LoadFloatOperand(masm, eax); |
| 1723 FloatingPointHelper::LoadFloatOperand(masm, edx); |
| 1724 __ FCmp(); |
2049 | 1725 |
2050 FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); | |
2051 __ ucomisd(xmm0, xmm1); | |
2052 // Don't base result on EFLAGS when a NaN is involved. | 1726 // Don't base result on EFLAGS when a NaN is involved. |
2053 __ j(parity_even, &unordered, Label::kNear); | 1727 __ j(parity_even, &unordered, Label::kNear); |
2054 | 1728 |
2055 __ mov(eax, 0); // equal | 1729 Label below_label, above_label; |
2056 __ mov(ecx, Immediate(Smi::FromInt(1))); | 1730 // Return a result of -1, 0, or 1, based on EFLAGS. |
2057 __ cmov(above, eax, ecx); | 1731 __ j(below, &below_label, Label::kNear); |
2058 __ mov(ecx, Immediate(Smi::FromInt(-1))); | 1732 __ j(above, &above_label, Label::kNear); |
2059 __ cmov(below, eax, ecx); | 1733 |
| 1734 __ Move(eax, Immediate(0)); |
| 1735 __ ret(0); |
| 1736 |
| 1737 __ bind(&below_label); |
| 1738 __ mov(eax, Immediate(Smi::FromInt(-1))); |
| 1739 __ ret(0); |
| 1740 |
| 1741 __ bind(&above_label); |
| 1742 __ mov(eax, Immediate(Smi::FromInt(1))); |
2060 __ ret(0); | 1743 __ ret(0); |
2061 | 1744 |
2062 // If one of the numbers was NaN, then the result is always false. | 1745 // If one of the numbers was NaN, then the result is always false. |
2063 // The cc is never not-equal. | 1746 // The cc is never not-equal. |
2064 __ bind(&unordered); | 1747 __ bind(&unordered); |
2065 ASSERT(cc != not_equal); | 1748 ASSERT(cc != not_equal); |
2066 if (cc == less || cc == less_equal) { | 1749 if (cc == less || cc == less_equal) { |
2067 __ mov(eax, Immediate(Smi::FromInt(1))); | 1750 __ mov(eax, Immediate(Smi::FromInt(1))); |
2068 } else { | 1751 } else { |
2069 __ mov(eax, Immediate(Smi::FromInt(-1))); | 1752 __ mov(eax, Immediate(Smi::FromInt(-1))); |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2261 __ bind(¬_array_function); | 1944 __ bind(¬_array_function); |
2262 } | 1945 } |
2263 | 1946 |
2264 __ mov(FieldOperand(ebx, edx, times_half_pointer_size, | 1947 __ mov(FieldOperand(ebx, edx, times_half_pointer_size, |
2265 FixedArray::kHeaderSize), | 1948 FixedArray::kHeaderSize), |
2266 edi); | 1949 edi); |
2267 // We won't need edx or ebx anymore, just save edi | 1950 // We won't need edx or ebx anymore, just save edi |
2268 __ push(edi); | 1951 __ push(edi); |
2269 __ push(ebx); | 1952 __ push(ebx); |
2270 __ push(edx); | 1953 __ push(edx); |
2271 __ RecordWriteArray(ebx, edi, edx, kDontSaveFPRegs, | 1954 __ RecordWriteArray(ebx, edi, edx, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
2272 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | |
2273 __ pop(edx); | 1955 __ pop(edx); |
2274 __ pop(ebx); | 1956 __ pop(ebx); |
2275 __ pop(edi); | 1957 __ pop(edi); |
2276 | 1958 |
2277 __ bind(&done); | 1959 __ bind(&done); |
2278 } | 1960 } |
2279 | 1961 |
2280 | 1962 |
2281 static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) { | 1963 static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) { |
2282 // Do not transform the receiver for strict mode functions. | 1964 // Do not transform the receiver for strict mode functions. |
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2635 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); | 2317 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); |
2636 // It is important that the store buffer overflow stubs are generated first. | 2318 // It is important that the store buffer overflow stubs are generated first. |
2637 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); | 2319 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); |
2638 CreateAllocationSiteStub::GenerateAheadOfTime(isolate); | 2320 CreateAllocationSiteStub::GenerateAheadOfTime(isolate); |
2639 BinaryOpICStub::GenerateAheadOfTime(isolate); | 2321 BinaryOpICStub::GenerateAheadOfTime(isolate); |
2640 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate); | 2322 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate); |
2641 } | 2323 } |
2642 | 2324 |
2643 | 2325 |
2644 void CodeStub::GenerateFPStubs(Isolate* isolate) { | 2326 void CodeStub::GenerateFPStubs(Isolate* isolate) { |
2645 CEntryStub save_doubles(isolate, 1, kSaveFPRegs); | 2327 // Do nothing. |
2646 // Stubs might already be in the snapshot, detect that and don't regenerate, | |
2647 // which would lead to code stub initialization state being messed up. | |
2648 Code* save_doubles_code; | |
2649 if (!save_doubles.FindCodeInCache(&save_doubles_code)) { | |
2650 save_doubles_code = *(save_doubles.GetCode()); | |
2651 } | |
2652 isolate->set_fp_stubs_generated(true); | |
2653 } | 2328 } |
2654 | 2329 |
2655 | 2330 |
2656 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) { | 2331 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) { |
2657 CEntryStub stub(isolate, 1, kDontSaveFPRegs); | 2332 CEntryStub stub(isolate, 1); |
2658 stub.GetCode(); | 2333 stub.GetCode(); |
2659 } | 2334 } |
2660 | 2335 |
2661 | 2336 |
2662 void CEntryStub::Generate(MacroAssembler* masm) { | 2337 void CEntryStub::Generate(MacroAssembler* masm) { |
2663 // eax: number of arguments including receiver | 2338 // eax: number of arguments including receiver |
2664 // ebx: pointer to C function (C callee-saved) | 2339 // ebx: pointer to C function (C callee-saved) |
2665 // ebp: frame pointer (restored after C call) | 2340 // ebp: frame pointer (restored after C call) |
2666 // esp: stack pointer (restored after C call) | 2341 // esp: stack pointer (restored after C call) |
2667 // esi: current context (C callee-saved) | 2342 // esi: current context (C callee-saved) |
2668 // edi: JS function of the caller (C callee-saved) | 2343 // edi: JS function of the caller (C callee-saved) |
2669 | 2344 |
2670 ProfileEntryHookStub::MaybeCallEntryHook(masm); | 2345 ProfileEntryHookStub::MaybeCallEntryHook(masm); |
2671 | 2346 |
2672 // Enter the exit frame that transitions from JavaScript to C++. | 2347 // Enter the exit frame that transitions from JavaScript to C++. |
2673 __ EnterExitFrame(save_doubles_ == kSaveFPRegs); | 2348 __ EnterExitFrame(); |
2674 | 2349 |
2675 // ebx: pointer to C function (C callee-saved) | 2350 // ebx: pointer to C function (C callee-saved) |
2676 // ebp: frame pointer (restored after C call) | 2351 // ebp: frame pointer (restored after C call) |
2677 // esp: stack pointer (restored after C call) | 2352 // esp: stack pointer (restored after C call) |
2678 // edi: number of arguments including receiver (C callee-saved) | 2353 // edi: number of arguments including receiver (C callee-saved) |
2679 // esi: pointer to the first argument (C callee-saved) | 2354 // esi: pointer to the first argument (C callee-saved) |
2680 | 2355 |
2681 // Result returned in eax, or eax+edx if result_size_ is 2. | 2356 // Result returned in eax, or eax+edx if result_size_ is 2. |
2682 | 2357 |
2683 // Check stack alignment. | 2358 // Check stack alignment. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2719 Label okay; | 2394 Label okay; |
2720 __ cmp(edx, Operand::StaticVariable(pending_exception_address)); | 2395 __ cmp(edx, Operand::StaticVariable(pending_exception_address)); |
2721 // Cannot use check here as it attempts to generate call into runtime. | 2396 // Cannot use check here as it attempts to generate call into runtime. |
2722 __ j(equal, &okay, Label::kNear); | 2397 __ j(equal, &okay, Label::kNear); |
2723 __ int3(); | 2398 __ int3(); |
2724 __ bind(&okay); | 2399 __ bind(&okay); |
2725 __ pop(edx); | 2400 __ pop(edx); |
2726 } | 2401 } |
2727 | 2402 |
2728 // Exit the JavaScript to C++ exit frame. | 2403 // Exit the JavaScript to C++ exit frame. |
2729 __ LeaveExitFrame(save_doubles_ == kSaveFPRegs); | 2404 __ LeaveExitFrame(); |
2730 __ ret(0); | 2405 __ ret(0); |
2731 | 2406 |
2732 // Handling of exception. | 2407 // Handling of exception. |
2733 __ bind(&exception_returned); | 2408 __ bind(&exception_returned); |
2734 | 2409 |
2735 // Retrieve the pending exception. | 2410 // Retrieve the pending exception. |
2736 __ mov(eax, Operand::StaticVariable(pending_exception_address)); | 2411 __ mov(eax, Operand::StaticVariable(pending_exception_address)); |
2737 | 2412 |
2738 // Clear the pending exception. | 2413 // Clear the pending exception. |
2739 __ mov(edx, Immediate(isolate()->factory()->the_hole_value())); | 2414 __ mov(edx, Immediate(isolate()->factory()->the_hole_value())); |
(...skipping 1050 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3790 Label unordered, maybe_undefined1, maybe_undefined2; | 3465 Label unordered, maybe_undefined1, maybe_undefined2; |
3791 Label miss; | 3466 Label miss; |
3792 | 3467 |
3793 if (left_ == CompareIC::SMI) { | 3468 if (left_ == CompareIC::SMI) { |
3794 __ JumpIfNotSmi(edx, &miss); | 3469 __ JumpIfNotSmi(edx, &miss); |
3795 } | 3470 } |
3796 if (right_ == CompareIC::SMI) { | 3471 if (right_ == CompareIC::SMI) { |
3797 __ JumpIfNotSmi(eax, &miss); | 3472 __ JumpIfNotSmi(eax, &miss); |
3798 } | 3473 } |
3799 | 3474 |
3800 // Load left and right operand. | 3475 // Inlining the double comparison and falling back to the general compare |
3801 Label done, left, left_smi, right_smi; | 3476 // stub if NaN is involved or SSE2 or CMOV is unsupported. |
3802 __ JumpIfSmi(eax, &right_smi, Label::kNear); | 3477 __ mov(ecx, edx); |
| 3478 __ and_(ecx, eax); |
| 3479 __ JumpIfSmi(ecx, &generic_stub, Label::kNear); |
| 3480 |
3803 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 3481 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
3804 isolate()->factory()->heap_number_map()); | 3482 isolate()->factory()->heap_number_map()); |
3805 __ j(not_equal, &maybe_undefined1, Label::kNear); | 3483 __ j(not_equal, &maybe_undefined1, Label::kNear); |
3806 __ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | |
3807 __ jmp(&left, Label::kNear); | |
3808 __ bind(&right_smi); | |
3809 __ mov(ecx, eax); // Can't clobber eax because we can still jump away. | |
3810 __ SmiUntag(ecx); | |
3811 __ Cvtsi2sd(xmm1, ecx); | |
3812 | |
3813 __ bind(&left); | |
3814 __ JumpIfSmi(edx, &left_smi, Label::kNear); | |
3815 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 3484 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
3816 isolate()->factory()->heap_number_map()); | 3485 isolate()->factory()->heap_number_map()); |
3817 __ j(not_equal, &maybe_undefined2, Label::kNear); | 3486 __ j(not_equal, &maybe_undefined2, Label::kNear); |
3818 __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | |
3819 __ jmp(&done); | |
3820 __ bind(&left_smi); | |
3821 __ mov(ecx, edx); // Can't clobber edx because we can still jump away. | |
3822 __ SmiUntag(ecx); | |
3823 __ Cvtsi2sd(xmm0, ecx); | |
3824 | |
3825 __ bind(&done); | |
3826 // Compare operands. | |
3827 __ ucomisd(xmm0, xmm1); | |
3828 | |
3829 // Don't base result on EFLAGS when a NaN is involved. | |
3830 __ j(parity_even, &unordered, Label::kNear); | |
3831 | |
3832 // Return a result of -1, 0, or 1, based on EFLAGS. | |
3833 // Performing mov, because xor would destroy the flag register. | |
3834 __ mov(eax, 0); // equal | |
3835 __ mov(ecx, Immediate(Smi::FromInt(1))); | |
3836 __ cmov(above, eax, ecx); | |
3837 __ mov(ecx, Immediate(Smi::FromInt(-1))); | |
3838 __ cmov(below, eax, ecx); | |
3839 __ ret(0); | |
3840 | 3487 |
3841 __ bind(&unordered); | 3488 __ bind(&unordered); |
3842 __ bind(&generic_stub); | 3489 __ bind(&generic_stub); |
3843 ICCompareStub stub(isolate(), op_, CompareIC::GENERIC, CompareIC::GENERIC, | 3490 ICCompareStub stub(isolate(), op_, CompareIC::GENERIC, CompareIC::GENERIC, |
3844 CompareIC::GENERIC); | 3491 CompareIC::GENERIC); |
3845 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); | 3492 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); |
3846 | 3493 |
3847 __ bind(&maybe_undefined1); | 3494 __ bind(&maybe_undefined1); |
3848 if (Token::IsOrderedRelationalCompareOp(op_)) { | 3495 if (Token::IsOrderedRelationalCompareOp(op_)) { |
3849 __ cmp(eax, Immediate(isolate()->factory()->undefined_value())); | 3496 __ cmp(eax, Immediate(isolate()->factory()->undefined_value())); |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4319 | 3966 |
4320 __ bind(¬_in_dictionary); | 3967 __ bind(¬_in_dictionary); |
4321 __ mov(result_, Immediate(0)); | 3968 __ mov(result_, Immediate(0)); |
4322 __ Drop(1); | 3969 __ Drop(1); |
4323 __ ret(2 * kPointerSize); | 3970 __ ret(2 * kPointerSize); |
4324 } | 3971 } |
4325 | 3972 |
4326 | 3973 |
4327 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime( | 3974 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime( |
4328 Isolate* isolate) { | 3975 Isolate* isolate) { |
4329 StoreBufferOverflowStub stub(isolate, kDontSaveFPRegs); | 3976 StoreBufferOverflowStub stub(isolate); |
4330 stub.GetCode(); | 3977 stub.GetCode(); |
4331 StoreBufferOverflowStub stub2(isolate, kSaveFPRegs); | |
4332 stub2.GetCode(); | |
4333 } | 3978 } |
4334 | 3979 |
4335 | 3980 |
4336 // Takes the input in 3 registers: address_ value_ and object_. A pointer to | 3981 // Takes the input in 3 registers: address_ value_ and object_. A pointer to |
4337 // the value has just been written into the object, now this stub makes sure | 3982 // the value has just been written into the object, now this stub makes sure |
4338 // we keep the GC informed. The word in the object where the value has been | 3983 // we keep the GC informed. The word in the object where the value has been |
4339 // written is in the address register. | 3984 // written is in the address register. |
4340 void RecordWriteStub::Generate(MacroAssembler* masm) { | 3985 void RecordWriteStub::Generate(MacroAssembler* masm) { |
4341 Label skip_to_incremental_noncompacting; | 3986 Label skip_to_incremental_noncompacting; |
4342 Label skip_to_incremental_compacting; | 3987 Label skip_to_incremental_compacting; |
4343 | 3988 |
4344 // The first two instructions are generated with labels so as to get the | 3989 // The first two instructions are generated with labels so as to get the |
4345 // offset fixed up correctly by the bind(Label*) call. We patch it back and | 3990 // offset fixed up correctly by the bind(Label*) call. We patch it back and |
4346 // forth between a compare instructions (a nop in this position) and the | 3991 // forth between a compare instructions (a nop in this position) and the |
4347 // real branch when we start and stop incremental heap marking. | 3992 // real branch when we start and stop incremental heap marking. |
4348 __ jmp(&skip_to_incremental_noncompacting, Label::kNear); | 3993 __ jmp(&skip_to_incremental_noncompacting, Label::kNear); |
4349 __ jmp(&skip_to_incremental_compacting, Label::kFar); | 3994 __ jmp(&skip_to_incremental_compacting, Label::kFar); |
4350 | 3995 |
4351 if (remembered_set_action_ == EMIT_REMEMBERED_SET) { | 3996 if (remembered_set_action_ == EMIT_REMEMBERED_SET) { |
4352 __ RememberedSetHelper(object_, | 3997 __ RememberedSetHelper(object_, |
4353 address_, | 3998 address_, |
4354 value_, | 3999 value_, |
4355 save_fp_regs_mode_, | |
4356 MacroAssembler::kReturnAtEnd); | 4000 MacroAssembler::kReturnAtEnd); |
4357 } else { | 4001 } else { |
4358 __ ret(0); | 4002 __ ret(0); |
4359 } | 4003 } |
4360 | 4004 |
4361 __ bind(&skip_to_incremental_noncompacting); | 4005 __ bind(&skip_to_incremental_noncompacting); |
4362 GenerateIncremental(masm, INCREMENTAL); | 4006 GenerateIncremental(masm, INCREMENTAL); |
4363 | 4007 |
4364 __ bind(&skip_to_incremental_compacting); | 4008 __ bind(&skip_to_incremental_compacting); |
4365 GenerateIncremental(masm, INCREMENTAL_COMPACTION); | 4009 GenerateIncremental(masm, INCREMENTAL_COMPACTION); |
(...skipping 26 matching lines...) Expand all Loading... |
4392 // remembered set. | 4036 // remembered set. |
4393 CheckNeedsToInformIncrementalMarker( | 4037 CheckNeedsToInformIncrementalMarker( |
4394 masm, | 4038 masm, |
4395 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, | 4039 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, |
4396 mode); | 4040 mode); |
4397 InformIncrementalMarker(masm); | 4041 InformIncrementalMarker(masm); |
4398 regs_.Restore(masm); | 4042 regs_.Restore(masm); |
4399 __ RememberedSetHelper(object_, | 4043 __ RememberedSetHelper(object_, |
4400 address_, | 4044 address_, |
4401 value_, | 4045 value_, |
4402 save_fp_regs_mode_, | |
4403 MacroAssembler::kReturnAtEnd); | 4046 MacroAssembler::kReturnAtEnd); |
4404 | 4047 |
4405 __ bind(&dont_need_remembered_set); | 4048 __ bind(&dont_need_remembered_set); |
4406 } | 4049 } |
4407 | 4050 |
4408 CheckNeedsToInformIncrementalMarker( | 4051 CheckNeedsToInformIncrementalMarker( |
4409 masm, | 4052 masm, |
4410 kReturnOnNoNeedToInformIncrementalMarker, | 4053 kReturnOnNoNeedToInformIncrementalMarker, |
4411 mode); | 4054 mode); |
4412 InformIncrementalMarker(masm); | 4055 InformIncrementalMarker(masm); |
4413 regs_.Restore(masm); | 4056 regs_.Restore(masm); |
4414 __ ret(0); | 4057 __ ret(0); |
4415 } | 4058 } |
4416 | 4059 |
4417 | 4060 |
4418 void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) { | 4061 void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) { |
4419 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_); | 4062 regs_.SaveCallerSaveRegisters(masm); |
4420 int argument_count = 3; | 4063 int argument_count = 3; |
4421 __ PrepareCallCFunction(argument_count, regs_.scratch0()); | 4064 __ PrepareCallCFunction(argument_count, regs_.scratch0()); |
4422 __ mov(Operand(esp, 0 * kPointerSize), regs_.object()); | 4065 __ mov(Operand(esp, 0 * kPointerSize), regs_.object()); |
4423 __ mov(Operand(esp, 1 * kPointerSize), regs_.address()); // Slot. | 4066 __ mov(Operand(esp, 1 * kPointerSize), regs_.address()); // Slot. |
4424 __ mov(Operand(esp, 2 * kPointerSize), | 4067 __ mov(Operand(esp, 2 * kPointerSize), |
4425 Immediate(ExternalReference::isolate_address(isolate()))); | 4068 Immediate(ExternalReference::isolate_address(isolate()))); |
4426 | 4069 |
4427 AllowExternalCallThatCantCauseGC scope(masm); | 4070 AllowExternalCallThatCantCauseGC scope(masm); |
4428 __ CallCFunction( | 4071 __ CallCFunction( |
4429 ExternalReference::incremental_marking_record_write_function(isolate()), | 4072 ExternalReference::incremental_marking_record_write_function(isolate()), |
4430 argument_count); | 4073 argument_count); |
4431 | 4074 |
4432 regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_); | 4075 regs_.RestoreCallerSaveRegisters(masm); |
4433 } | 4076 } |
4434 | 4077 |
4435 | 4078 |
4436 void RecordWriteStub::CheckNeedsToInformIncrementalMarker( | 4079 void RecordWriteStub::CheckNeedsToInformIncrementalMarker( |
4437 MacroAssembler* masm, | 4080 MacroAssembler* masm, |
4438 OnNoNeedToInformIncrementalMarker on_no_need, | 4081 OnNoNeedToInformIncrementalMarker on_no_need, |
4439 Mode mode) { | 4082 Mode mode) { |
4440 Label object_is_black, need_incremental, need_incremental_pop_object; | 4083 Label object_is_black, need_incremental, need_incremental_pop_object; |
4441 | 4084 |
4442 __ mov(regs_.scratch0(), Immediate(~Page::kPageAlignmentMask)); | 4085 __ mov(regs_.scratch0(), Immediate(~Page::kPageAlignmentMask)); |
(...skipping 13 matching lines...) Expand all Loading... |
4456 regs_.scratch0(), | 4099 regs_.scratch0(), |
4457 regs_.scratch1(), | 4100 regs_.scratch1(), |
4458 &object_is_black, | 4101 &object_is_black, |
4459 Label::kNear); | 4102 Label::kNear); |
4460 | 4103 |
4461 regs_.Restore(masm); | 4104 regs_.Restore(masm); |
4462 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { | 4105 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { |
4463 __ RememberedSetHelper(object_, | 4106 __ RememberedSetHelper(object_, |
4464 address_, | 4107 address_, |
4465 value_, | 4108 value_, |
4466 save_fp_regs_mode_, | |
4467 MacroAssembler::kReturnAtEnd); | 4109 MacroAssembler::kReturnAtEnd); |
4468 } else { | 4110 } else { |
4469 __ ret(0); | 4111 __ ret(0); |
4470 } | 4112 } |
4471 | 4113 |
4472 __ bind(&object_is_black); | 4114 __ bind(&object_is_black); |
4473 | 4115 |
4474 // Get the value from the slot. | 4116 // Get the value from the slot. |
4475 __ mov(regs_.scratch0(), Operand(regs_.address(), 0)); | 4117 __ mov(regs_.scratch0(), Operand(regs_.address(), 0)); |
4476 | 4118 |
(...skipping 27 matching lines...) Expand all Loading... |
4504 regs_.object(), // Scratch. | 4146 regs_.object(), // Scratch. |
4505 &need_incremental_pop_object, | 4147 &need_incremental_pop_object, |
4506 Label::kNear); | 4148 Label::kNear); |
4507 __ pop(regs_.object()); | 4149 __ pop(regs_.object()); |
4508 | 4150 |
4509 regs_.Restore(masm); | 4151 regs_.Restore(masm); |
4510 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { | 4152 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { |
4511 __ RememberedSetHelper(object_, | 4153 __ RememberedSetHelper(object_, |
4512 address_, | 4154 address_, |
4513 value_, | 4155 value_, |
4514 save_fp_regs_mode_, | |
4515 MacroAssembler::kReturnAtEnd); | 4156 MacroAssembler::kReturnAtEnd); |
4516 } else { | 4157 } else { |
4517 __ ret(0); | 4158 __ ret(0); |
4518 } | 4159 } |
4519 | 4160 |
4520 __ bind(&need_incremental_pop_object); | 4161 __ bind(&need_incremental_pop_object); |
4521 __ pop(regs_.object()); | 4162 __ pop(regs_.object()); |
4522 | 4163 |
4523 __ bind(&need_incremental); | 4164 __ bind(&need_incremental); |
4524 | 4165 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4575 __ jmp(&slow_elements); | 4216 __ jmp(&slow_elements); |
4576 | 4217 |
4577 // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object. | 4218 // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object. |
4578 __ bind(&fast_elements); | 4219 __ bind(&fast_elements); |
4579 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); | 4220 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); |
4580 __ lea(ecx, FieldOperand(ebx, ecx, times_half_pointer_size, | 4221 __ lea(ecx, FieldOperand(ebx, ecx, times_half_pointer_size, |
4581 FixedArrayBase::kHeaderSize)); | 4222 FixedArrayBase::kHeaderSize)); |
4582 __ mov(Operand(ecx, 0), eax); | 4223 __ mov(Operand(ecx, 0), eax); |
4583 // Update the write barrier for the array store. | 4224 // Update the write barrier for the array store. |
4584 __ RecordWrite(ebx, ecx, eax, | 4225 __ RecordWrite(ebx, ecx, eax, |
4585 kDontSaveFPRegs, | |
4586 EMIT_REMEMBERED_SET, | 4226 EMIT_REMEMBERED_SET, |
4587 OMIT_SMI_CHECK); | 4227 OMIT_SMI_CHECK); |
4588 __ ret(0); | 4228 __ ret(0); |
4589 | 4229 |
4590 // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS, | 4230 // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS, |
4591 // and value is Smi. | 4231 // and value is Smi. |
4592 __ bind(&smi_element); | 4232 __ bind(&smi_element); |
4593 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); | 4233 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); |
4594 __ mov(FieldOperand(ebx, ecx, times_half_pointer_size, | 4234 __ mov(FieldOperand(ebx, ecx, times_half_pointer_size, |
4595 FixedArrayBase::kHeaderSize), eax); | 4235 FixedArrayBase::kHeaderSize), eax); |
4596 __ ret(0); | 4236 __ ret(0); |
4597 | 4237 |
4598 // Array literal has ElementsKind of FAST_*_DOUBLE_ELEMENTS. | 4238 // Array literal has ElementsKind of FAST_*_DOUBLE_ELEMENTS. |
4599 __ bind(&double_elements); | 4239 __ bind(&double_elements); |
4600 | 4240 |
4601 __ push(edx); | 4241 __ push(edx); |
4602 __ mov(edx, FieldOperand(ebx, JSObject::kElementsOffset)); | 4242 __ mov(edx, FieldOperand(ebx, JSObject::kElementsOffset)); |
4603 __ StoreNumberToDoubleElements(eax, | 4243 __ StoreNumberToDoubleElements(eax, |
4604 edx, | 4244 edx, |
4605 ecx, | 4245 ecx, |
4606 edi, | 4246 edi, |
4607 xmm0, | 4247 &slow_elements_from_double, |
4608 &slow_elements_from_double); | 4248 false); |
4609 __ pop(edx); | 4249 __ pop(edx); |
4610 __ ret(0); | 4250 __ ret(0); |
4611 } | 4251 } |
4612 | 4252 |
4613 | 4253 |
4614 void StubFailureTrampolineStub::Generate(MacroAssembler* masm) { | 4254 void StubFailureTrampolineStub::Generate(MacroAssembler* masm) { |
4615 CEntryStub ces(isolate(), 1, kSaveFPRegs); | 4255 CEntryStub ces(isolate(), 1); |
4616 __ call(ces.GetCode(), RelocInfo::CODE_TARGET); | 4256 __ call(ces.GetCode(), RelocInfo::CODE_TARGET); |
4617 int parameter_count_offset = | 4257 int parameter_count_offset = |
4618 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset; | 4258 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset; |
4619 __ mov(ebx, MemOperand(ebp, parameter_count_offset)); | 4259 __ mov(ebx, MemOperand(ebp, parameter_count_offset)); |
4620 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); | 4260 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); |
4621 __ pop(ecx); | 4261 __ pop(ecx); |
4622 int additional_offset = function_mode_ == JS_FUNCTION_STUB_MODE | 4262 int additional_offset = function_mode_ == JS_FUNCTION_STUB_MODE |
4623 ? kPointerSize | 4263 ? kPointerSize |
4624 : 0; | 4264 : 0; |
4625 __ lea(esp, MemOperand(esp, ebx, times_pointer_size, additional_offset)); | 4265 __ lea(esp, MemOperand(esp, ebx, times_pointer_size, additional_offset)); |
(...skipping 505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5131 kStackSpace, | 4771 kStackSpace, |
5132 Operand(ebp, 7 * kPointerSize), | 4772 Operand(ebp, 7 * kPointerSize), |
5133 NULL); | 4773 NULL); |
5134 } | 4774 } |
5135 | 4775 |
5136 | 4776 |
5137 #undef __ | 4777 #undef __ |
5138 | 4778 |
5139 } } // namespace v8::internal | 4779 } } // namespace v8::internal |
5140 | 4780 |
5141 #endif // V8_TARGET_ARCH_IA32 | 4781 #endif // V8_TARGET_ARCH_X87 |
OLD | NEW |