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

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: Eps: refined a comment. 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
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);
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/hydrogen.cc ('k') | src/ia32/code-stubs-ia32.cc » ('j') | src/runtime.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698