OLD | NEW |
---|---|
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 572 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
583 __ j(not_zero, &done); | 583 __ j(not_zero, &done); |
584 __ pop(ebx); | 584 __ pop(ebx); |
585 __ push(Immediate(factory->undefined_value())); | 585 __ push(Immediate(factory->undefined_value())); |
586 __ push(ebx); | 586 __ push(ebx); |
587 __ inc(eax); | 587 __ inc(eax); |
588 __ bind(&done); | 588 __ bind(&done); |
589 } | 589 } |
590 | 590 |
591 // 2. Get the function to call (passed as receiver) from the stack, check | 591 // 2. Get the function to call (passed as receiver) from the stack, check |
592 // if it is a function. | 592 // if it is a function. |
593 Label non_function; | 593 Label slow, non_function; |
594 // 1 ~ return address. | 594 // 1 ~ return address. |
595 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); | 595 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); |
596 __ JumpIfSmi(edi, &non_function); | 596 __ JumpIfSmi(edi, &non_function); |
597 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | 597 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
598 __ j(not_equal, &non_function); | 598 __ j(not_equal, &slow); |
599 | 599 |
600 | 600 |
601 // 3a. Patch the first argument if necessary when calling a function. | 601 // 3a. Patch the first argument if necessary when calling a function. |
602 Label shift_arguments; | 602 Label shift_arguments; |
603 __ Set(edx, Immediate(0)); // indicate regular JS_FUNCTION | |
603 { Label convert_to_object, use_global_receiver, patch_receiver; | 604 { Label convert_to_object, use_global_receiver, patch_receiver; |
604 // Change context eagerly in case we need the global receiver. | 605 // Change context eagerly in case we need the global receiver. |
605 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 606 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
606 | 607 |
607 // Do not transform the receiver for strict mode functions. | 608 // Do not transform the receiver for strict mode functions. |
608 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 609 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
609 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset), | 610 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset), |
610 1 << SharedFunctionInfo::kStrictModeBitWithinByte); | 611 1 << SharedFunctionInfo::kStrictModeBitWithinByte); |
611 __ j(not_equal, &shift_arguments); | 612 __ j(not_equal, &shift_arguments); |
612 | 613 |
(...skipping 17 matching lines...) Expand all Loading... | |
630 __ j(above_equal, &shift_arguments); | 631 __ j(above_equal, &shift_arguments); |
631 | 632 |
632 __ bind(&convert_to_object); | 633 __ bind(&convert_to_object); |
633 __ EnterInternalFrame(); // In order to preserve argument count. | 634 __ EnterInternalFrame(); // In order to preserve argument count. |
634 __ SmiTag(eax); | 635 __ SmiTag(eax); |
635 __ push(eax); | 636 __ push(eax); |
636 | 637 |
637 __ push(ebx); | 638 __ push(ebx); |
638 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 639 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
639 __ mov(ebx, eax); | 640 __ mov(ebx, eax); |
641 __ Set(edx, Immediate(0)); // restore | |
640 | 642 |
641 __ pop(eax); | 643 __ pop(eax); |
642 __ SmiUntag(eax); | 644 __ SmiUntag(eax); |
643 __ LeaveInternalFrame(); | 645 __ LeaveInternalFrame(); |
644 // Restore the function to edi. | 646 // Restore the function to edi. |
645 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); | 647 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); |
646 __ jmp(&patch_receiver); | 648 __ jmp(&patch_receiver); |
647 | 649 |
648 // Use the global receiver object from the called function as the | 650 // Use the global receiver object from the called function as the |
649 // receiver. | 651 // receiver. |
650 __ bind(&use_global_receiver); | 652 __ bind(&use_global_receiver); |
651 const int kGlobalIndex = | 653 const int kGlobalIndex = |
652 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; | 654 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; |
653 __ mov(ebx, FieldOperand(esi, kGlobalIndex)); | 655 __ mov(ebx, FieldOperand(esi, kGlobalIndex)); |
654 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset)); | 656 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset)); |
655 __ mov(ebx, FieldOperand(ebx, kGlobalIndex)); | 657 __ mov(ebx, FieldOperand(ebx, kGlobalIndex)); |
656 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); | 658 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); |
657 | 659 |
658 __ bind(&patch_receiver); | 660 __ bind(&patch_receiver); |
659 __ mov(Operand(esp, eax, times_4, 0), ebx); | 661 __ mov(Operand(esp, eax, times_4, 0), ebx); |
660 | 662 |
661 __ jmp(&shift_arguments); | 663 __ jmp(&shift_arguments); |
662 } | 664 } |
663 | 665 |
664 // 3b. Patch the first argument when calling a non-function. The | 666 // 3b. Check for function proxy. |
667 __ bind(&slow); | |
668 __ Set(edx, Immediate(1)); // indicate function proxy | |
669 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); | |
670 __ j(equal, &shift_arguments); | |
671 __ bind(&non_function); | |
672 __ Set(edx, Immediate(2)); // indicate non-function | |
673 | |
674 // 3c. Patch the first argument when calling a non-function. The | |
665 // CALL_NON_FUNCTION builtin expects the non-function callee as | 675 // CALL_NON_FUNCTION builtin expects the non-function callee as |
666 // receiver, so overwrite the first argument which will ultimately | 676 // receiver, so overwrite the first argument which will ultimately |
667 // become the receiver. | 677 // become the receiver. |
668 __ bind(&non_function); | |
669 __ mov(Operand(esp, eax, times_4, 0), edi); | 678 __ mov(Operand(esp, eax, times_4, 0), edi); |
670 // Clear edi to indicate a non-function being called. | |
671 __ Set(edi, Immediate(0)); | |
672 | 679 |
673 // 4. Shift arguments and return address one slot down on the stack | 680 // 4. Shift arguments and return address one slot down on the stack |
674 // (overwriting the original receiver). Adjust argument count to make | 681 // (overwriting the original receiver). Adjust argument count to make |
675 // the original first argument the new receiver. | 682 // the original first argument the new receiver. |
676 __ bind(&shift_arguments); | 683 __ bind(&shift_arguments); |
677 { Label loop; | 684 { Label loop; |
678 __ mov(ecx, eax); | 685 __ mov(ecx, eax); |
679 __ bind(&loop); | 686 __ bind(&loop); |
680 __ mov(ebx, Operand(esp, ecx, times_4, 0)); | 687 __ mov(ebx, Operand(esp, ecx, times_4, 0)); |
681 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); | 688 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); |
682 __ dec(ecx); | 689 __ dec(ecx); |
683 __ j(not_sign, &loop); // While non-negative (to copy return address). | 690 __ j(not_sign, &loop); // While non-negative (to copy return address). |
684 __ pop(ebx); // Discard copy of return address. | 691 __ pop(ebx); // Discard copy of return address. |
685 __ dec(eax); // One fewer argument (first argument is new receiver). | 692 __ dec(eax); // One fewer argument (first argument is new receiver). |
686 } | 693 } |
687 | 694 |
688 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin. | 695 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin, |
689 { Label function; | 696 // or a function proxy via CALL_FUNCTION_PROXY. |
690 __ test(edi, Operand(edi)); | 697 { Label function, non_proxy; |
691 __ j(not_zero, &function); | 698 __ test(edx, Operand(edx)); |
699 __ j(zero, &function); | |
692 __ Set(ebx, Immediate(0)); | 700 __ Set(ebx, Immediate(0)); |
701 __ SetCallKind(ecx, CALL_AS_METHOD); | |
702 __ cmp(Operand(edx), Immediate(1)); | |
703 __ j(not_equal, &non_proxy); | |
704 | |
705 __ pop(edx); | |
Kevin Millikin (Chromium)
2011/09/08 17:30:40
This is return address, right? It needs a // retu
rossberg
2011/09/09 17:05:30
Done (here and in -x64).
| |
706 __ push(edi); // re-add proxy object as additional argument | |
707 __ push(edx); | |
708 __ inc(eax); | |
709 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY); | |
710 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | |
711 RelocInfo::CODE_TARGET); | |
712 | |
713 __ bind(&non_proxy); | |
693 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); | 714 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); |
694 __ SetCallKind(ecx, CALL_AS_METHOD); | |
695 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | 715 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
696 RelocInfo::CODE_TARGET); | 716 RelocInfo::CODE_TARGET); |
697 __ bind(&function); | 717 __ bind(&function); |
698 } | 718 } |
699 | 719 |
700 // 5b. Get the code to call from the function and check that the number of | 720 // 5b. Get the code to call from the function and check that the number of |
701 // expected arguments matches what we're providing. If so, jump | 721 // expected arguments matches what we're providing. If so, jump |
702 // (tail-call) to the code in register edx without checking arguments. | 722 // (tail-call) to the code in register edx without checking arguments. |
703 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 723 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
704 __ mov(ebx, | 724 __ mov(ebx, |
(...skipping 11 matching lines...) Expand all Loading... | |
716 } | 736 } |
717 | 737 |
718 | 738 |
719 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { | 739 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
720 __ EnterInternalFrame(); | 740 __ EnterInternalFrame(); |
721 | 741 |
722 __ push(Operand(ebp, 4 * kPointerSize)); // push this | 742 __ push(Operand(ebp, 4 * kPointerSize)); // push this |
723 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments | 743 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments |
724 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); | 744 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); |
725 | 745 |
726 // Check the stack for overflow. We are not trying need to catch | 746 // Check the stack for overflow. We are not trying to catch |
727 // interruptions (e.g. debug break and preemption) here, so the "real stack | 747 // interruptions (e.g. debug break and preemption) here, so the "real stack |
728 // limit" is checked. | 748 // limit" is checked. |
729 Label okay; | 749 Label okay; |
730 ExternalReference real_stack_limit = | 750 ExternalReference real_stack_limit = |
731 ExternalReference::address_of_real_stack_limit(masm->isolate()); | 751 ExternalReference::address_of_real_stack_limit(masm->isolate()); |
732 __ mov(edi, Operand::StaticVariable(real_stack_limit)); | 752 __ mov(edi, Operand::StaticVariable(real_stack_limit)); |
733 // Make ecx the space we have left. The stack might already be overflowed | 753 // Make ecx the space we have left. The stack might already be overflowed |
734 // here which will cause ecx to become negative. | 754 // here which will cause ecx to become negative. |
735 __ mov(ecx, Operand(esp)); | 755 __ mov(ecx, Operand(esp)); |
736 __ sub(ecx, Operand(edi)); | 756 __ sub(ecx, Operand(edi)); |
(...skipping 12 matching lines...) Expand all Loading... | |
749 __ bind(&okay); | 769 __ bind(&okay); |
750 // End of stack check. | 770 // End of stack check. |
751 | 771 |
752 // Push current index and limit. | 772 // Push current index and limit. |
753 const int kLimitOffset = | 773 const int kLimitOffset = |
754 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; | 774 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; |
755 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; | 775 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; |
756 __ push(eax); // limit | 776 __ push(eax); // limit |
757 __ push(Immediate(0)); // index | 777 __ push(Immediate(0)); // index |
758 | 778 |
759 // Change context eagerly to get the right global object if | 779 // Get the receiver. |
760 // necessary. | 780 __ mov(ebx, Operand(ebp, 3 * kPointerSize)); |
Kevin Millikin (Chromium)
2011/09/08 17:30:40
I guess you should name '3' and '4' in this code s
rossberg
2011/09/09 17:05:30
Done.
| |
781 | |
782 // Check that the function is a JS function (otherwise it must be a proxy). | |
783 Label push_receiver; | |
761 __ mov(edi, Operand(ebp, 4 * kPointerSize)); | 784 __ mov(edi, Operand(ebp, 4 * kPointerSize)); |
785 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | |
786 __ j(not_equal, &push_receiver); | |
787 | |
788 // Change context eagerly to get the right global object if necessary. | |
762 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 789 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
763 | 790 |
764 // Compute the receiver. | 791 // Compute the receiver. |
765 Label call_to_object, use_global_receiver, push_receiver; | |
766 __ mov(ebx, Operand(ebp, 3 * kPointerSize)); | |
767 | |
768 // Do not transform the receiver for strict mode functions. | 792 // Do not transform the receiver for strict mode functions. |
793 Label call_to_object, use_global_receiver; | |
769 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 794 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
770 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset), | 795 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset), |
771 1 << SharedFunctionInfo::kStrictModeBitWithinByte); | 796 1 << SharedFunctionInfo::kStrictModeBitWithinByte); |
772 __ j(not_equal, &push_receiver); | 797 __ j(not_equal, &push_receiver); |
773 | 798 |
774 Factory* factory = masm->isolate()->factory(); | 799 Factory* factory = masm->isolate()->factory(); |
775 | 800 |
776 // Do not transform the receiver for natives (shared already in ecx). | 801 // Do not transform the receiver for natives (shared already in ecx). |
777 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset), | 802 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset), |
778 1 << SharedFunctionInfo::kNativeBitWithinByte); | 803 1 << SharedFunctionInfo::kNativeBitWithinByte); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
830 // Update the index on the stack and in register eax. | 855 // Update the index on the stack and in register eax. |
831 __ mov(eax, Operand(ebp, kIndexOffset)); | 856 __ mov(eax, Operand(ebp, kIndexOffset)); |
832 __ add(Operand(eax), Immediate(1 << kSmiTagSize)); | 857 __ add(Operand(eax), Immediate(1 << kSmiTagSize)); |
833 __ mov(Operand(ebp, kIndexOffset), eax); | 858 __ mov(Operand(ebp, kIndexOffset), eax); |
834 | 859 |
835 __ bind(&entry); | 860 __ bind(&entry); |
836 __ cmp(eax, Operand(ebp, kLimitOffset)); | 861 __ cmp(eax, Operand(ebp, kLimitOffset)); |
837 __ j(not_equal, &loop); | 862 __ j(not_equal, &loop); |
838 | 863 |
839 // Invoke the function. | 864 // Invoke the function. |
865 Label call_proxy; | |
840 ParameterCount actual(eax); | 866 ParameterCount actual(eax); |
841 __ SmiUntag(eax); | 867 __ SmiUntag(eax); |
842 __ mov(edi, Operand(ebp, 4 * kPointerSize)); | 868 __ mov(edi, Operand(ebp, 4 * kPointerSize)); |
869 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | |
870 __ j(not_equal, &call_proxy); | |
843 __ InvokeFunction(edi, actual, CALL_FUNCTION, | 871 __ InvokeFunction(edi, actual, CALL_FUNCTION, |
844 NullCallWrapper(), CALL_AS_METHOD); | 872 NullCallWrapper(), CALL_AS_METHOD); |
845 | 873 |
846 __ LeaveInternalFrame(); | 874 __ LeaveInternalFrame(); |
847 __ ret(3 * kPointerSize); // remove this, receiver, and arguments | 875 __ ret(3 * kPointerSize); // remove this, receiver, and arguments |
876 | |
877 // Invoke the function proxy. | |
878 __ bind(&call_proxy); | |
879 __ push(edi); // add function proxy as last argument | |
880 __ inc(eax); | |
881 __ Set(ebx, Immediate(0)); | |
882 __ SetCallKind(ecx, CALL_AS_METHOD); | |
883 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY); | |
884 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | |
885 RelocInfo::CODE_TARGET); | |
886 | |
887 __ LeaveInternalFrame(); | |
888 __ ret(3 * kPointerSize); // remove this, receiver, and arguments | |
848 } | 889 } |
849 | 890 |
850 | 891 |
851 // Number of empty elements to allocate for an empty array. | 892 // Number of empty elements to allocate for an empty array. |
852 static const int kPreallocatedArrayElements = 4; | 893 static const int kPreallocatedArrayElements = 4; |
853 | 894 |
854 | 895 |
855 // Allocate an empty JSArray. The allocated array is put into the result | 896 // Allocate an empty JSArray. The allocated array is put into the result |
856 // register. If the parameter initial_capacity is larger than zero an elements | 897 // register. If the parameter initial_capacity is larger than zero an elements |
857 // backing store is allocated with this size and filled with the hole values. | 898 // backing store is allocated with this size and filled with the hole values. |
(...skipping 749 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1607 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR); | 1648 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR); |
1608 generator.Generate(); | 1649 generator.Generate(); |
1609 } | 1650 } |
1610 | 1651 |
1611 | 1652 |
1612 #undef __ | 1653 #undef __ |
1613 } | 1654 } |
1614 } // namespace v8::internal | 1655 } // namespace v8::internal |
1615 | 1656 |
1616 #endif // V8_TARGET_ARCH_IA32 | 1657 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |