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

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

Issue 193125: Handle array construction on native code (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 11 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/builtins.cc ('k') | src/v8-counters.h » ('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 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 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 640 matching lines...) Expand 10 before | Expand all | Expand 10 after
651 ParameterCount actual(eax); 651 ParameterCount actual(eax);
652 __ shr(eax, kSmiTagSize); 652 __ shr(eax, kSmiTagSize);
653 __ mov(edi, Operand(ebp, 4 * kPointerSize)); 653 __ mov(edi, Operand(ebp, 4 * kPointerSize));
654 __ InvokeFunction(edi, actual, CALL_FUNCTION); 654 __ InvokeFunction(edi, actual, CALL_FUNCTION);
655 655
656 __ LeaveInternalFrame(); 656 __ LeaveInternalFrame();
657 __ ret(3 * kPointerSize); // remove this, receiver, and arguments 657 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
658 } 658 }
659 659
660 660
661 // Load the built-in Array function from the current context.
662 static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
663 // Load the global context.
664 __ mov(result, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
665 __ mov(result, FieldOperand(result, GlobalObject::kGlobalContextOffset));
666 // Load the Array function from the global context.
667 __ mov(result,
668 Operand(result, Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
669 }
670
671
672 // Number of empty elements to allocate for an empty array.
673 static const int kPreallocatedArrayElements = 4;
674
675
676 // Allocate an empty JSArray. The allocated array is put into the result
677 // register. If the parameter holes is larger than zero an elements backing
678 // store is allocated with this size and filled with the hole values. Otherwise
679 // the elements backing store is set to the empty FixedArray.
680 static void AllocateEmptyJSArray(MacroAssembler* masm,
681 Register array_function,
682 Register result,
683 Register scratch1,
684 Register scratch2,
685 Register scratch3,
686 int holes,
687 Label* gc_required) {
688 ASSERT(holes >= 0);
689
690 // Load the initial map from the array function.
691 __ mov(scratch1, FieldOperand(array_function,
692 JSFunction::kPrototypeOrInitialMapOffset));
693
694 // Allocate the JSArray object together with space for a fixed array with the
695 // requested elements.
696 int size = JSArray::kSize;
697 if (holes > 0) {
698 size += FixedArray::SizeFor(holes);
699 }
700 __ AllocateObjectInNewSpace(size,
701 result,
702 scratch2,
703 scratch3,
704 gc_required,
705 TAG_OBJECT);
706
707 // Allocated the JSArray. Now initialize the fields except for the elements
708 // array.
709 // result: JSObject
710 // scratch1: initial map
711 // scratch2: start of next object
712 __ mov(FieldOperand(result, JSObject::kMapOffset), scratch1);
713 __ mov(FieldOperand(result, JSArray::kPropertiesOffset),
714 Factory::empty_fixed_array());
715 // Field JSArray::kElementsOffset is initialized later.
716 __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0));
717
718 // If no storage is requested for the elements array just set the empty
719 // fixed array.
720 if (holes == 0) {
721 __ mov(FieldOperand(result, JSArray::kElementsOffset),
722 Factory::empty_fixed_array());
723 return;
724 }
725
726 // Calculate the location of the elements array and set elements array member
727 // of the JSArray.
728 // result: JSObject
729 // scratch2: start of next object
730 __ lea(scratch1, Operand(result, JSArray::kSize));
731 __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1);
732
733 // Initialize the FixedArray and fill it with holes. FixedArray length is not
734 // stored as a smi.
735 // result: JSObject
736 // scratch1: elements array
737 // scratch2: start of next object
738 __ mov(FieldOperand(scratch1, JSObject::kMapOffset),
739 Factory::fixed_array_map());
740 __ mov(FieldOperand(scratch1, Array::kLengthOffset), Immediate(holes));
741
742 // Fill the FixedArray with the hole value. Inline the code if short.
743 if (holes <= 4) {
744 // Use a scratch register here to have only one reloc info when unfolding
745 // the loop.
746 __ mov(scratch3, Factory::the_hole_value());
747 for (int i = 0; i < holes; i++) {
748 __ mov(FieldOperand(scratch1,
749 FixedArray::kHeaderSize + i * kPointerSize),
750 scratch3);
751 }
752 } else {
753 Label loop, entry;
754 __ jmp(&entry);
755 __ bind(&loop);
756 __ mov(Operand(scratch1, 0), Factory::the_hole_value());
757 __ add(Operand(scratch1), Immediate(kPointerSize));
758 __ bind(&entry);
759 __ cmp(scratch1, Operand(scratch2));
760 __ j(below, &loop);
761 }
762 }
763
764
765 // Allocate a JSArray with the number of elements stored in a register. The
766 // register array_function holds the built-in Array function and the register
767 // array_size holds the size of the array as a smi. The allocated array is put
768 // into the result register and beginning and end of the FixedArray elements
769 // storage is put into registers elements_array and elements_array_end (see
770 // below for when that is not the case). If the parameter fill_with_holes is
771 // true the allocated elements backing store is filled with the hole values
772 // otherwise it is left uninitialized. When the backing store is filled the
773 // register elements_array is scratched.
774 static void AllocateJSArray(MacroAssembler* masm,
775 Register array_function, // Array function.
776 Register array_size, // As a smi.
777 Register result,
778 Register elements_array,
779 Register elements_array_end,
780 Register scratch,
781 bool fill_with_hole,
782 Label* gc_required) {
783 Label not_empty, allocated;
784
785 // Load the initial map from the array function.
786 __ mov(elements_array,
787 FieldOperand(array_function,
788 JSFunction::kPrototypeOrInitialMapOffset));
789
790 // Check whether an empty sized array is requested.
791 __ test(array_size, Operand(array_size));
792 __ j(not_zero, &not_empty);
793
794 // If an empty array is requested allocate a small elements array anyway. This
795 // keeps the code below free of special casing for the empty array.
796 int size = JSArray::kSize + FixedArray::SizeFor(kPreallocatedArrayElements);
797 __ AllocateObjectInNewSpace(size,
798 result,
799 elements_array_end,
800 scratch,
801 gc_required,
802 TAG_OBJECT);
803 __ jmp(&allocated);
804
805 // Allocate the JSArray object together with space for a FixedArray with the
806 // requested elements.
807 __ bind(&not_empty);
808 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
809 __ AllocateObjectInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
810 times_half_pointer_size, // array_size is a smi.
811 array_size,
812 result,
813 elements_array_end,
814 scratch,
815 gc_required,
816 TAG_OBJECT);
817
818 // Allocated the JSArray. Now initialize the fields except for the elements
819 // array.
820 // result: JSObject
821 // elements_array: initial map
822 // elements_array_end: start of next object
823 // array_size: size of array (smi)
824 __ bind(&allocated);
825 __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array);
826 __ mov(elements_array, Factory::empty_fixed_array());
827 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
828 // Field JSArray::kElementsOffset is initialized later.
829 __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size);
830
831 // Calculate the location of the elements array and set elements array member
832 // of the JSArray.
833 // result: JSObject
834 // elements_array_end: start of next object
835 // array_size: size of array (smi)
836 __ lea(elements_array, Operand(result, JSArray::kSize));
837 __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array);
838
839 // Initialize the fixed array and fill it with holes. FixedArray length is not
840 // stored as a smi.
841 // result: JSObject
842 // elements_array: elements array
843 // elements_array_end: start of next object
844 // array_size: size of array (smi)
845 ASSERT(kSmiTag == 0);
846 __ shr(array_size, kSmiTagSize); // Convert from smi to value.
847 __ mov(FieldOperand(elements_array, JSObject::kMapOffset),
848 Factory::fixed_array_map());
849 Label not_empty_2, fill_array;
850 __ test(array_size, Operand(array_size));
851 __ j(not_zero, &not_empty_2);
852 // Length of the FixedArray is the number of pre-allocated elements even
853 // though the actual JSArray has length 0.
854 __ mov(FieldOperand(elements_array, Array::kLengthOffset),
855 Immediate(kPreallocatedArrayElements));
856 __ jmp(&fill_array);
857 __ bind(&not_empty_2);
858 // For non-empty JSArrays the length of the FixedArray and the JSArray is the
859 // same.
860 __ mov(FieldOperand(elements_array, Array::kLengthOffset), array_size);
861
862 // Fill the allocated FixedArray with the hole value if requested.
863 // result: JSObject
864 // elements_array: elements array
865 // elements_array_end: start of next object
866 __ bind(&fill_array);
867 if (fill_with_hole) {
868 Label loop, entry;
869 __ mov(scratch, Factory::the_hole_value());
870 __ lea(elements_array, Operand(elements_array,
871 FixedArray::kHeaderSize - kHeapObjectTag));
872 __ jmp(&entry);
873 __ bind(&loop);
874 __ mov(Operand(elements_array, 0), scratch);
875 __ add(Operand(elements_array), Immediate(kPointerSize));
876 __ bind(&entry);
877 __ cmp(elements_array, Operand(elements_array_end));
878 __ j(below, &loop);
879 }
880 }
881
882
883 // Create a new array for the built-in Array function. This function allocates
884 // the JSArray object and the FixedArray elements array and initializes these.
885 // If the Array cannot be constructed in native code the runtime is called. This
886 // function assumes the following state:
887 // edi: constructor (built-in Array function)
888 // eax: argc
889 // esp[0]: return address
890 // esp[4]: last argument
891 // This function is used for both construct and normal calls of Array. Whether
892 // it is a construct call or not is indicated by the construct_call parameter.
893 // The only difference between handling a construct call and a normal call is
894 // that for a construct call the constructor function in edi needs to be
895 // preserved for entering the generic code. In both cases argc in eax needs to
896 // be preserved.
897 static void ArrayNativeCode(MacroAssembler* masm,
898 bool construct_call,
899 Label *call_generic_code) {
900 Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call;
901
902 // Push the constructor and argc. No need to tag argc as a smi, as there will
903 // be no garbage collection with this on the stack.
904 int push_count = 0;
905 if (construct_call) {
906 push_count++;
907 __ push(edi);
908 }
909 push_count++;
910 __ push(eax);
911
912 // Check for array construction with zero arguments or one.
913 __ test(eax, Operand(eax));
914 __ j(not_zero, &argc_one_or_more);
915
916 // Handle construction of an empty array.
917 AllocateEmptyJSArray(masm,
918 edi,
919 eax,
920 ebx,
921 ecx,
922 edi,
923 kPreallocatedArrayElements,
924 &prepare_generic_code_call);
925 __ IncrementCounter(&Counters::array_function_native, 1);
926 __ pop(ebx);
927 if (construct_call) {
928 __ pop(edi);
929 }
930 __ ret(kPointerSize);
931
932 // Check for one argument. Bail out if argument is not smi or if it is
933 // negative.
934 __ bind(&argc_one_or_more);
935 __ cmp(eax, 1);
936 __ j(not_equal, &argc_two_or_more);
937 ASSERT(kSmiTag == 0);
938 __ test(Operand(esp, (push_count + 1) * kPointerSize),
939 Immediate(kIntptrSignBit | kSmiTagMask));
940 __ j(not_zero, &prepare_generic_code_call);
941
942 // Handle construction of an empty array of a certain size. Get the size from
943 // the stack and bail out if size is to large to actually allocate an elements
944 // array.
945 __ mov(edx, Operand(esp, (push_count + 1) * kPointerSize));
946 ASSERT(kSmiTag == 0);
947 __ cmp(edx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
948 __ j(greater_equal, &prepare_generic_code_call);
949
950 // edx: array_size (smi)
951 // edi: constructor
952 // esp[0]: argc
953 // esp[4]: constructor (only if construct_call)
954 // esp[8]: return address
955 // esp[C]: argument
956 AllocateJSArray(masm,
957 edi,
958 edx,
959 eax,
960 ebx,
961 ecx,
962 edi,
963 true,
964 &prepare_generic_code_call);
965 __ IncrementCounter(&Counters::array_function_native, 1);
966 __ pop(ebx);
967 if (construct_call) {
968 __ pop(edi);
969 }
970 __ ret(2 * kPointerSize);
971
972 // Handle construction of an array from a list of arguments.
973 __ bind(&argc_two_or_more);
974 ASSERT(kSmiTag == 0);
975 __ shl(eax, kSmiTagSize); // Convet argc to a smi.
976 // eax: array_size (smi)
977 // edi: constructor
978 // esp[0] : argc
979 // esp[4]: constructor (only if construct_call)
980 // esp[8] : return address
981 // esp[C] : last argument
982 AllocateJSArray(masm,
983 edi,
984 eax,
985 ebx,
986 ecx,
987 edx,
988 edi,
989 false,
990 &prepare_generic_code_call);
991 __ IncrementCounter(&Counters::array_function_native, 1);
992 __ mov(eax, ebx);
993 __ pop(ebx);
994 if (construct_call) {
995 __ pop(edi);
996 }
997 __ push(eax);
998 // eax: JSArray
999 // ebx: argc
1000 // edx: elements_array_end (untagged)
1001 // esp[0]: JSArray
1002 // esp[4]: return address
1003 // esp[8]: last argument
1004
1005 // Location of the last argument
1006 __ lea(edi, Operand(esp, 2 * kPointerSize));
1007
1008 // Location of the first array element (fill_with_holes is false, so the
1009 // FixedArray is returned).
1010 __ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag));
1011
1012 // ebx: argc
1013 // edx: location of the first array element
1014 // edi: location of the last argument
1015 // esp[0]: JSArray
1016 // esp[4]: return address
1017 // esp[8]: last argument
1018 Label loop, entry;
1019 __ mov(ecx, ebx);
1020 __ jmp(&entry);
1021 __ bind(&loop);
1022 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
1023 __ mov(Operand(edx, 0), eax);
1024 __ add(Operand(edx), Immediate(kPointerSize));
1025 __ bind(&entry);
1026 __ dec(ecx);
1027 __ j(greater_equal, &loop);
1028
1029 // Remove caller arguments from the stack and return.
1030 // ebx: argc
1031 // esp[0]: JSArray
1032 // esp[4]: return address
1033 // esp[8]: last argument
1034 __ pop(eax);
1035 __ pop(ecx);
1036 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
1037 __ push(ecx);
1038 __ ret(0);
1039
1040 // Restore argc and constructor before running the generic code.
1041 __ bind(&prepare_generic_code_call);
1042 __ pop(eax);
1043 if (construct_call) {
1044 __ pop(edi);
1045 }
1046 __ jmp(call_generic_code);
1047 }
1048
1049
1050 void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1051 // ----------- S t a t e -------------
1052 // -- eax : argc
1053 // -- esp[0] : return address
1054 // -- esp[4] : last argument
1055 // -----------------------------------
1056 Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
1057
1058 // Get the Array function.
1059 GenerateLoadArrayFunction(masm, edi);
1060
1061 if (FLAG_debug_code) {
1062 // Initial map for the builtin Array function shoud be a map.
1063 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1064 // Will both indicate a NULL and a Smi.
1065 __ test(ebx, Immediate(kSmiTagMask));
1066 __ Assert(not_zero, "Unexpected initial map for Array function");
1067 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1068 __ Assert(equal, "Unexpected initial map for Array function");
1069 }
1070
1071 // Run the native code for the Array function called as constructor.
1072 ArrayNativeCode(masm, false, &generic_array_code);
1073
1074 // Jump to the generic array code in case the specialized code cannot handle
1075 // the construction.
1076 __ bind(&generic_array_code);
1077 Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
1078 Handle<Code> array_code(code);
1079 __ jmp(array_code, RelocInfo::CODE_TARGET);
1080 }
1081
1082
1083 void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
1084 // ----------- S t a t e -------------
1085 // -- eax : argc
1086 // -- edi : constructor
1087 // -- esp[0] : return address
1088 // -- esp[4] : last argument
1089 // -----------------------------------
1090 Label generic_constructor;
1091
1092 if (FLAG_debug_code) {
1093 // The array construct code is only set for the builtin Array function which
1094 // does always have a map.
1095 GenerateLoadArrayFunction(masm, ebx);
1096 __ cmp(edi, Operand(ebx));
1097 __ Assert(equal, "Unexpected Array function");
1098 // Initial map for the builtin Array function should be a map.
1099 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1100 // Will both indicate a NULL and a Smi.
1101 __ test(ebx, Immediate(kSmiTagMask));
1102 __ Assert(not_zero, "Unexpected initial map for Array function");
1103 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1104 __ Assert(equal, "Unexpected initial map for Array function");
1105 }
1106
1107 // Run the native code for the Array function called as constructor.
1108 ArrayNativeCode(masm, false, &generic_constructor);
1109
1110 // Jump to the generic construct code in case the specialized code cannot
1111 // handle the construction.
1112 __ bind(&generic_constructor);
1113 GenerateLoadArrayFunction(masm, edi);
1114 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
1115 Handle<Code> generic_construct_stub(code);
1116 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
1117 }
1118
1119
661 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { 1120 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
662 __ push(ebp); 1121 __ push(ebp);
663 __ mov(ebp, Operand(esp)); 1122 __ mov(ebp, Operand(esp));
664 1123
665 // Store the arguments adaptor context sentinel. 1124 // Store the arguments adaptor context sentinel.
666 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 1125 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
667 1126
668 // Push the function on the stack. 1127 // Push the function on the stack.
669 __ push(edi); 1128 __ push(edi);
670 1129
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
768 // Dont adapt arguments. 1227 // Dont adapt arguments.
769 // ------------------------------------------- 1228 // -------------------------------------------
770 __ bind(&dont_adapt_arguments); 1229 __ bind(&dont_adapt_arguments);
771 __ jmp(Operand(edx)); 1230 __ jmp(Operand(edx));
772 } 1231 }
773 1232
774 1233
775 #undef __ 1234 #undef __
776 1235
777 } } // namespace v8::internal 1236 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/builtins.cc ('k') | src/v8-counters.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698