Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(438)

Side by Side Diff: src/ia32/builtins-ia32.cc

Issue 7623011: Implement function proxies (except for their use as constructors). (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed second round of comments. Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/hydrogen.cc ('k') | src/ia32/code-stubs-ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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); // return address
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,
705 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); 725 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
706 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset)); 726 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
707 __ SmiUntag(ebx); 727 __ SmiUntag(ebx);
708 __ SetCallKind(ecx, CALL_AS_METHOD); 728 __ SetCallKind(ecx, CALL_AS_METHOD);
709 __ cmp(eax, Operand(ebx)); 729 __ cmp(eax, Operand(ebx));
710 __ j(not_equal, 730 __ j(not_equal,
711 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline()); 731 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
712 732
713 ParameterCount expected(0); 733 ParameterCount expected(0);
714 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION, 734 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION,
715 NullCallWrapper(), CALL_AS_METHOD); 735 NullCallWrapper(), CALL_AS_METHOD);
716 } 736 }
717 737
718 738
719 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { 739 void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
740 static const int kArgumentsOffset = 2 * kPointerSize;
741 static const int kReceiverOffset = 3 * kPointerSize;
742 static const int kFunctionOffset = 4 * kPointerSize;
743
720 __ EnterInternalFrame(); 744 __ EnterInternalFrame();
721 745
722 __ push(Operand(ebp, 4 * kPointerSize)); // push this 746 __ push(Operand(ebp, kFunctionOffset)); // push this
723 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments 747 __ push(Operand(ebp, kArgumentsOffset)); // push arguments
724 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); 748 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
725 749
726 // Check the stack for overflow. We are not trying need to catch 750 // Check the stack for overflow. We are not trying to catch
727 // interruptions (e.g. debug break and preemption) here, so the "real stack 751 // interruptions (e.g. debug break and preemption) here, so the "real stack
728 // limit" is checked. 752 // limit" is checked.
729 Label okay; 753 Label okay;
730 ExternalReference real_stack_limit = 754 ExternalReference real_stack_limit =
731 ExternalReference::address_of_real_stack_limit(masm->isolate()); 755 ExternalReference::address_of_real_stack_limit(masm->isolate());
732 __ mov(edi, Operand::StaticVariable(real_stack_limit)); 756 __ mov(edi, Operand::StaticVariable(real_stack_limit));
733 // Make ecx the space we have left. The stack might already be overflowed 757 // Make ecx the space we have left. The stack might already be overflowed
734 // here which will cause ecx to become negative. 758 // here which will cause ecx to become negative.
735 __ mov(ecx, Operand(esp)); 759 __ mov(ecx, Operand(esp));
736 __ sub(ecx, Operand(edi)); 760 __ sub(ecx, Operand(edi));
(...skipping 12 matching lines...) Expand all
749 __ bind(&okay); 773 __ bind(&okay);
750 // End of stack check. 774 // End of stack check.
751 775
752 // Push current index and limit. 776 // Push current index and limit.
753 const int kLimitOffset = 777 const int kLimitOffset =
754 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; 778 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
755 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; 779 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
756 __ push(eax); // limit 780 __ push(eax); // limit
757 __ push(Immediate(0)); // index 781 __ push(Immediate(0)); // index
758 782
759 // Change context eagerly to get the right global object if 783 // Get the receiver.
760 // necessary. 784 __ mov(ebx, Operand(ebp, kReceiverOffset));
761 __ mov(edi, Operand(ebp, 4 * kPointerSize)); 785
786 // Check that the function is a JS function (otherwise it must be a proxy).
787 Label push_receiver;
788 __ mov(edi, Operand(ebp, kFunctionOffset));
789 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
790 __ j(not_equal, &push_receiver);
791
792 // Change context eagerly to get the right global object if necessary.
762 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 793 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
763 794
764 // Compute the receiver. 795 // 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. 796 // Do not transform the receiver for strict mode functions.
797 Label call_to_object, use_global_receiver;
769 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 798 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
770 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset), 799 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
771 1 << SharedFunctionInfo::kStrictModeBitWithinByte); 800 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
772 __ j(not_equal, &push_receiver); 801 __ j(not_equal, &push_receiver);
773 802
774 Factory* factory = masm->isolate()->factory(); 803 Factory* factory = masm->isolate()->factory();
775 804
776 // Do not transform the receiver for natives (shared already in ecx). 805 // Do not transform the receiver for natives (shared already in ecx).
777 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset), 806 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
778 1 << SharedFunctionInfo::kNativeBitWithinByte); 807 1 << SharedFunctionInfo::kNativeBitWithinByte);
(...skipping 28 matching lines...) Expand all
807 836
808 // Push the receiver. 837 // Push the receiver.
809 __ bind(&push_receiver); 838 __ bind(&push_receiver);
810 __ push(ebx); 839 __ push(ebx);
811 840
812 // Copy all arguments from the array to the stack. 841 // Copy all arguments from the array to the stack.
813 Label entry, loop; 842 Label entry, loop;
814 __ mov(eax, Operand(ebp, kIndexOffset)); 843 __ mov(eax, Operand(ebp, kIndexOffset));
815 __ jmp(&entry); 844 __ jmp(&entry);
816 __ bind(&loop); 845 __ bind(&loop);
817 __ mov(edx, Operand(ebp, 2 * kPointerSize)); // load arguments 846 __ mov(edx, Operand(ebp, kArgumentsOffset)); // load arguments
818 847
819 // Use inline caching to speed up access to arguments. 848 // Use inline caching to speed up access to arguments.
820 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize(); 849 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
821 __ call(ic, RelocInfo::CODE_TARGET); 850 __ call(ic, RelocInfo::CODE_TARGET);
822 // It is important that we do not have a test instruction after the 851 // It is important that we do not have a test instruction after the
823 // call. A test instruction after the call is used to indicate that 852 // call. A test instruction after the call is used to indicate that
824 // we have generated an inline version of the keyed load. In this 853 // we have generated an inline version of the keyed load. In this
825 // case, we know that we are not generating a test instruction next. 854 // case, we know that we are not generating a test instruction next.
826 855
827 // Push the nth argument. 856 // Push the nth argument.
828 __ push(eax); 857 __ push(eax);
829 858
830 // Update the index on the stack and in register eax. 859 // Update the index on the stack and in register eax.
831 __ mov(eax, Operand(ebp, kIndexOffset)); 860 __ mov(eax, Operand(ebp, kIndexOffset));
832 __ add(Operand(eax), Immediate(1 << kSmiTagSize)); 861 __ add(Operand(eax), Immediate(1 << kSmiTagSize));
833 __ mov(Operand(ebp, kIndexOffset), eax); 862 __ mov(Operand(ebp, kIndexOffset), eax);
834 863
835 __ bind(&entry); 864 __ bind(&entry);
836 __ cmp(eax, Operand(ebp, kLimitOffset)); 865 __ cmp(eax, Operand(ebp, kLimitOffset));
837 __ j(not_equal, &loop); 866 __ j(not_equal, &loop);
838 867
839 // Invoke the function. 868 // Invoke the function.
869 Label call_proxy;
840 ParameterCount actual(eax); 870 ParameterCount actual(eax);
841 __ SmiUntag(eax); 871 __ SmiUntag(eax);
842 __ mov(edi, Operand(ebp, 4 * kPointerSize)); 872 __ mov(edi, Operand(ebp, kFunctionOffset));
873 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
874 __ j(not_equal, &call_proxy);
843 __ InvokeFunction(edi, actual, CALL_FUNCTION, 875 __ InvokeFunction(edi, actual, CALL_FUNCTION,
844 NullCallWrapper(), CALL_AS_METHOD); 876 NullCallWrapper(), CALL_AS_METHOD);
845 877
846 __ LeaveInternalFrame(); 878 __ LeaveInternalFrame();
847 __ ret(3 * kPointerSize); // remove this, receiver, and arguments 879 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
880
881 // Invoke the function proxy.
882 __ bind(&call_proxy);
883 __ push(edi); // add function proxy as last argument
884 __ inc(eax);
885 __ Set(ebx, Immediate(0));
886 __ SetCallKind(ecx, CALL_AS_METHOD);
887 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
888 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
889 RelocInfo::CODE_TARGET);
890
891 __ LeaveInternalFrame();
892 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
848 } 893 }
849 894
850 895
851 // Number of empty elements to allocate for an empty array. 896 // Number of empty elements to allocate for an empty array.
852 static const int kPreallocatedArrayElements = 4; 897 static const int kPreallocatedArrayElements = 4;
853 898
854 899
855 // Allocate an empty JSArray. The allocated array is put into the result 900 // 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 901 // 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. 902 // 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
1607 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR); 1652 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR);
1608 generator.Generate(); 1653 generator.Generate();
1609 } 1654 }
1610 1655
1611 1656
1612 #undef __ 1657 #undef __
1613 } 1658 }
1614 } // namespace v8::internal 1659 } // namespace v8::internal
1615 1660
1616 #endif // V8_TARGET_ARCH_IA32 1661 #endif // V8_TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « src/hydrogen.cc ('k') | src/ia32/code-stubs-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698