OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 749 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
760 IC::UtilityId id) { | 760 IC::UtilityId id) { |
761 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); | 761 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); |
762 __ CallExternalReference( | 762 __ CallExternalReference( |
763 ExternalReference(IC_Utility(id), masm->isolate()), | 763 ExternalReference(IC_Utility(id), masm->isolate()), |
764 StubCache::kInterceptorArgsLength); | 764 StubCache::kInterceptorArgsLength); |
765 } | 765 } |
766 | 766 |
767 | 767 |
768 static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength; | 768 static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength; |
769 | 769 |
770 // Reserves space for the extra arguments to API function in the | |
771 // caller's frame. | |
772 // | |
773 // These arguments are set by CheckPrototypes and GenerateFastApiDirectCall. | |
774 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, | |
775 Register scratch) { | |
776 ASSERT(Smi::FromInt(0) == 0); | |
777 for (int i = 0; i < kFastApiCallArguments; i++) { | |
778 __ push(zero_reg); | |
779 } | |
780 } | |
781 | 770 |
| 771 static void GenerateFastApiCallBody(MacroAssembler* masm, |
| 772 const CallOptimization& optimization, |
| 773 int argc, |
| 774 Register holder, |
| 775 Register scratch1, |
| 776 Register scratch2, |
| 777 Register scratch3, |
| 778 bool restore_context) { |
| 779 // ----------- S t a t e ------------- |
| 780 // -- sp[0] : last JS argument |
| 781 // -- ... |
| 782 // -- sp[(argc - 1) * 4] : first JS argument |
| 783 // -- sp[argc * 4] : receiver |
| 784 // ----------------------------------- |
| 785 ASSERT(optimization.is_simple_api_call()); |
782 | 786 |
783 // Undoes the effects of ReserveSpaceForFastApiCall. | 787 typedef FunctionCallbackArguments FCA; |
784 static void FreeSpaceForFastApiCall(MacroAssembler* masm) { | |
785 __ Drop(kFastApiCallArguments); | |
786 } | |
787 | 788 |
| 789 STATIC_ASSERT(FCA::kHolderIndex == 0); |
| 790 STATIC_ASSERT(FCA::kIsolateIndex == 1); |
| 791 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2); |
| 792 STATIC_ASSERT(FCA::kReturnValueOffset == 3); |
| 793 STATIC_ASSERT(FCA::kDataIndex == 4); |
| 794 STATIC_ASSERT(FCA::kCalleeIndex == 5); |
| 795 STATIC_ASSERT(FCA::kContextSaveIndex == 6); |
| 796 STATIC_ASSERT(FCA::kArgsLength == 7); |
788 | 797 |
789 static void GenerateFastApiDirectCall(MacroAssembler* masm, | 798 ASSERT(!holder.is(cp)); |
790 const CallOptimization& optimization, | 799 |
791 int argc, | |
792 bool restore_context) { | |
793 // ----------- S t a t e ------------- | |
794 // -- sp[0] - sp[24] : FunctionCallbackInfo, incl. | |
795 // : holder (set by CheckPrototypes) | |
796 // -- sp[28] : last JS argument | |
797 // -- ... | |
798 // -- sp[(argc + 6) * 4] : first JS argument | |
799 // -- sp[(argc + 7) * 4] : receiver | |
800 // ----------------------------------- | |
801 typedef FunctionCallbackArguments FCA; | |
802 // Save calling context. | 800 // Save calling context. |
803 __ sw(cp, MemOperand(sp, FCA::kContextSaveIndex * kPointerSize)); | 801 __ push(cp); |
804 // Get the function and setup the context. | 802 // Get the function and setup the context. |
805 Handle<JSFunction> function = optimization.constant_function(); | 803 Handle<JSFunction> function = optimization.constant_function(); |
806 __ li(t1, function); | 804 __ li(scratch1, function); |
807 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset)); | 805 __ lw(cp, FieldMemOperand(scratch1, JSFunction::kContextOffset)); |
808 __ sw(t1, MemOperand(sp, FCA::kCalleeIndex * kPointerSize)); | 806 __ push(scratch1); |
809 | 807 |
810 // Construct the FunctionCallbackInfo. | 808 // Construct the FunctionCallbackInfo. |
811 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); | 809 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
812 Handle<Object> call_data(api_call_info->data(), masm->isolate()); | 810 Handle<Object> call_data(api_call_info->data(), masm->isolate()); |
| 811 bool call_data_undefined = false; |
813 if (masm->isolate()->heap()->InNewSpace(*call_data)) { | 812 if (masm->isolate()->heap()->InNewSpace(*call_data)) { |
814 __ li(a0, api_call_info); | 813 __ li(scratch1, api_call_info); |
815 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset)); | 814 __ lw(scratch1, FieldMemOperand(scratch1, CallHandlerInfo::kDataOffset)); |
| 815 } else if (call_data->IsUndefined()) { |
| 816 call_data_undefined = true; |
| 817 __ LoadRoot(scratch3, Heap::kUndefinedValueRootIndex); |
816 } else { | 818 } else { |
817 __ li(t2, call_data); | 819 __ li(scratch1, call_data); |
818 } | 820 } |
819 // Store call data. | 821 // Store call data. |
820 __ sw(t2, MemOperand(sp, FCA::kDataIndex * kPointerSize)); | 822 __ push(scratch1); |
| 823 if (!call_data_undefined) { |
| 824 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex); |
| 825 } |
| 826 // Store ReturnValue default and ReturnValue. |
| 827 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex); |
| 828 __ Push(scratch1, scratch1); |
821 // Store isolate. | 829 // Store isolate. |
822 __ li(t3, Operand(ExternalReference::isolate_address(masm->isolate()))); | 830 __ li(scratch1, Operand(ExternalReference::isolate_address(masm->isolate()))); |
823 __ sw(t3, MemOperand(sp, FCA::kIsolateIndex * kPointerSize)); | 831 __ push(scratch1); |
824 // Store ReturnValue default and ReturnValue. | 832 // Store holder. |
825 __ LoadRoot(t1, Heap::kUndefinedValueRootIndex); | 833 __ push(holder); |
826 __ sw(t1, MemOperand(sp, FCA::kReturnValueOffset * kPointerSize)); | |
827 __ sw(t1, MemOperand(sp, FCA::kReturnValueDefaultValueIndex * kPointerSize)); | |
828 | 834 |
829 // Prepare arguments. | 835 // Prepare arguments. |
830 __ Move(a2, sp); | 836 __ Move(a2, sp); |
831 | 837 |
832 // Allocate the v8::Arguments structure in the arguments' space since | 838 // Allocate the v8::Arguments structure in the arguments' space since |
833 // it's not controlled by GC. | 839 // it's not controlled by GC. |
834 const int kApiStackSpace = 4; | 840 const int kApiStackSpace = 4; |
835 | 841 |
836 FrameScope frame_scope(masm, StackFrame::MANUAL); | 842 FrameScope frame_scope(masm, StackFrame::MANUAL); |
837 __ EnterExitFrame(false, kApiStackSpace); | 843 __ EnterExitFrame(false, kApiStackSpace); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
874 function_address, | 880 function_address, |
875 thunk_ref, | 881 thunk_ref, |
876 a1, | 882 a1, |
877 kStackUnwindSpace, | 883 kStackUnwindSpace, |
878 return_value_operand, | 884 return_value_operand, |
879 restore_context ? | 885 restore_context ? |
880 &context_restore_operand : NULL); | 886 &context_restore_operand : NULL); |
881 } | 887 } |
882 | 888 |
883 | 889 |
| 890 // Generates call to API function. |
| 891 static void GenerateFastApiCall(MacroAssembler* masm, |
| 892 const CallOptimization& optimization, |
| 893 int argc, |
| 894 Handle<Map> map_to_holder, |
| 895 CallOptimization::HolderLookup holder_lookup) { |
| 896 Counters* counters = masm->isolate()->counters(); |
| 897 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a1); |
| 898 |
| 899 // Move holder to a register. |
| 900 Register holder_reg = a0; |
| 901 switch (holder_lookup) { |
| 902 case CallOptimization::kHolderIsReceiver: |
| 903 { |
| 904 ASSERT(map_to_holder.is_null()); |
| 905 __ lw(holder_reg, MemOperand(sp, argc * kPointerSize)); |
| 906 } |
| 907 break; |
| 908 case CallOptimization::kHolderIsPrototypeOfMap: |
| 909 { |
| 910 Handle<JSObject> holder(JSObject::cast(map_to_holder->prototype())); |
| 911 if (!masm->isolate()->heap()->InNewSpace(*holder)) { |
| 912 __ li(holder_reg, holder); |
| 913 } else { |
| 914 __ li(holder_reg, map_to_holder); |
| 915 __ lw(holder_reg, |
| 916 FieldMemOperand(holder_reg, Map::kPrototypeOffset)); |
| 917 } |
| 918 } |
| 919 break; |
| 920 case CallOptimization::kHolderNotFound: |
| 921 UNREACHABLE(); |
| 922 } |
| 923 GenerateFastApiCallBody(masm, |
| 924 optimization, |
| 925 argc, |
| 926 holder_reg, |
| 927 a1, |
| 928 a2, |
| 929 a3, |
| 930 false); |
| 931 } |
| 932 |
| 933 |
884 // Generate call to api function. | 934 // Generate call to api function. |
885 static void GenerateFastApiCall(MacroAssembler* masm, | 935 static void GenerateFastApiCall(MacroAssembler* masm, |
886 const CallOptimization& optimization, | 936 const CallOptimization& optimization, |
887 Register receiver, | 937 Register receiver, |
888 Register scratch, | 938 Register scratch, |
889 int argc, | 939 int argc, |
890 Register* values) { | 940 Register* values) { |
891 ASSERT(optimization.is_simple_api_call()); | |
892 ASSERT(!receiver.is(scratch)); | 941 ASSERT(!receiver.is(scratch)); |
893 | 942 __ push(receiver); |
894 typedef FunctionCallbackArguments FCA; | |
895 const int stack_space = kFastApiCallArguments + argc + 1; | |
896 // Assign stack space for the call arguments. | |
897 __ Subu(sp, sp, Operand(stack_space * kPointerSize)); | |
898 // Write holder to stack frame. | |
899 __ sw(receiver, MemOperand(sp, FCA::kHolderIndex * kPointerSize)); | |
900 // Write receiver to stack frame. | |
901 int index = stack_space - 1; | |
902 __ sw(receiver, MemOperand(sp, index-- * kPointerSize)); | |
903 // Write the arguments to stack frame. | 943 // Write the arguments to stack frame. |
904 for (int i = 0; i < argc; i++) { | 944 for (int i = 0; i < argc; i++) { |
905 ASSERT(!receiver.is(values[i])); | 945 Register arg = values[argc-1-i]; |
906 ASSERT(!scratch.is(values[i])); | 946 ASSERT(!receiver.is(arg)); |
907 __ sw(values[i], MemOperand(sp, index-- * kPointerSize)); | 947 ASSERT(!scratch.is(arg)); |
| 948 __ push(arg); |
908 } | 949 } |
909 | 950 |
910 GenerateFastApiDirectCall(masm, optimization, argc, true); | 951 Register scratch1 = a0; |
| 952 Register scratch2 = a1; |
| 953 Register scratch3 = a2; |
| 954 if (!a3.is(receiver)) { |
| 955 __ mov(a3, receiver); |
| 956 receiver = a3; |
| 957 } |
| 958 // Stack now matches JSFunction abi. |
| 959 GenerateFastApiCallBody(masm, |
| 960 optimization, |
| 961 argc, |
| 962 receiver, |
| 963 scratch1, |
| 964 scratch2, |
| 965 scratch3, |
| 966 true); |
911 } | 967 } |
912 | 968 |
913 | 969 |
914 class CallInterceptorCompiler BASE_EMBEDDED { | 970 class CallInterceptorCompiler BASE_EMBEDDED { |
915 public: | 971 public: |
916 CallInterceptorCompiler(CallStubCompiler* stub_compiler, | 972 CallInterceptorCompiler(CallStubCompiler* stub_compiler, |
917 const ParameterCount& arguments, | 973 const ParameterCount& arguments, |
918 Register name) | 974 Register name) |
919 : stub_compiler_(stub_compiler), | 975 : stub_compiler_(stub_compiler), |
920 arguments_(arguments), | 976 arguments_(arguments), |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
953 Register scratch2, | 1009 Register scratch2, |
954 Register scratch3, | 1010 Register scratch3, |
955 Handle<JSObject> interceptor_holder, | 1011 Handle<JSObject> interceptor_holder, |
956 LookupResult* lookup, | 1012 LookupResult* lookup, |
957 Handle<Name> name, | 1013 Handle<Name> name, |
958 const CallOptimization& optimization, | 1014 const CallOptimization& optimization, |
959 Label* miss_label) { | 1015 Label* miss_label) { |
960 ASSERT(optimization.is_constant_call()); | 1016 ASSERT(optimization.is_constant_call()); |
961 ASSERT(!lookup->holder()->IsGlobalObject()); | 1017 ASSERT(!lookup->holder()->IsGlobalObject()); |
962 Counters* counters = masm->isolate()->counters(); | 1018 Counters* counters = masm->isolate()->counters(); |
963 int depth1 = kInvalidProtoDepth; | |
964 int depth2 = kInvalidProtoDepth; | |
965 bool can_do_fast_api_call = false; | |
966 if (optimization.is_simple_api_call() && | |
967 !lookup->holder()->IsGlobalObject()) { | |
968 depth1 = optimization.GetPrototypeDepthOfExpectedType( | |
969 object, interceptor_holder); | |
970 if (depth1 == kInvalidProtoDepth) { | |
971 depth2 = optimization.GetPrototypeDepthOfExpectedType( | |
972 interceptor_holder, Handle<JSObject>(lookup->holder())); | |
973 } | |
974 can_do_fast_api_call = | |
975 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth; | |
976 } | |
977 | |
978 __ IncrementCounter(counters->call_const_interceptor(), 1, | 1019 __ IncrementCounter(counters->call_const_interceptor(), 1, |
979 scratch1, scratch2); | 1020 scratch1, scratch2); |
980 | 1021 |
981 if (can_do_fast_api_call) { | |
982 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1, | |
983 scratch1, scratch2); | |
984 ReserveSpaceForFastApiCall(masm, scratch1); | |
985 } | |
986 | |
987 // Check that the maps from receiver to interceptor's holder | 1022 // Check that the maps from receiver to interceptor's holder |
988 // haven't changed and thus we can invoke interceptor. | 1023 // haven't changed and thus we can invoke interceptor. |
989 Label miss_cleanup; | 1024 Label miss_cleanup; |
990 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; | |
991 Register holder = | 1025 Register holder = |
992 stub_compiler_->CheckPrototypes( | 1026 stub_compiler_->CheckPrototypes( |
993 IC::CurrentTypeOf(object, masm->isolate()), receiver, | 1027 IC::CurrentTypeOf(object, masm->isolate()), receiver, |
994 interceptor_holder, scratch1, scratch2, scratch3, | 1028 interceptor_holder, scratch1, scratch2, scratch3, |
995 name, depth1, miss); | 1029 name, miss_label); |
996 | 1030 |
997 // Invoke an interceptor and if it provides a value, | 1031 // Invoke an interceptor and if it provides a value, |
998 // branch to |regular_invoke|. | 1032 // branch to |regular_invoke|. |
999 Label regular_invoke; | 1033 Label regular_invoke; |
1000 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2, | 1034 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2, |
1001 ®ular_invoke); | 1035 ®ular_invoke); |
1002 | 1036 |
1003 // Interceptor returned nothing for this property. Try to use cached | 1037 // Interceptor returned nothing for this property. Try to use cached |
1004 // constant function. | 1038 // constant function. |
1005 | 1039 |
1006 // Check that the maps from interceptor's holder to constant function's | 1040 // Check that the maps from interceptor's holder to constant function's |
1007 // holder haven't changed and thus we can use cached constant function. | 1041 // holder haven't changed and thus we can use cached constant function. |
1008 if (*interceptor_holder != lookup->holder()) { | 1042 if (*interceptor_holder != lookup->holder()) { |
1009 stub_compiler_->CheckPrototypes( | 1043 stub_compiler_->CheckPrototypes( |
1010 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, | 1044 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, |
1011 handle(lookup->holder()), scratch1, scratch2, scratch3, | 1045 handle(lookup->holder()), scratch1, scratch2, scratch3, |
1012 name, depth2, miss); | 1046 name, miss_label); |
1013 } else { | 1047 } |
1014 // CheckPrototypes has a side effect of fetching a 'holder' | 1048 |
1015 // for API (object which is instanceof for the signature). It's | 1049 Handle<Map> lookup_map; |
1016 // safe to omit it here, as if present, it should be fetched | 1050 CallOptimization::HolderLookup holder_lookup = |
1017 // by the previous CheckPrototypes. | 1051 CallOptimization::kHolderNotFound; |
1018 ASSERT(depth2 == kInvalidProtoDepth); | 1052 if (optimization.is_simple_api_call() && |
| 1053 !lookup->holder()->IsGlobalObject()) { |
| 1054 lookup_map = optimization.LookupHolderOfExpectedType( |
| 1055 object, object, interceptor_holder, &holder_lookup); |
| 1056 if (holder_lookup == CallOptimization::kHolderNotFound) { |
| 1057 lookup_map = |
| 1058 optimization.LookupHolderOfExpectedType( |
| 1059 object, |
| 1060 interceptor_holder, |
| 1061 Handle<JSObject>(lookup->holder()), |
| 1062 &holder_lookup); |
| 1063 } |
1019 } | 1064 } |
1020 | 1065 |
1021 // Invoke function. | 1066 // Invoke function. |
1022 if (can_do_fast_api_call) { | 1067 if (holder_lookup != CallOptimization::kHolderNotFound) { |
1023 GenerateFastApiDirectCall( | 1068 int argc = arguments_.immediate(); |
1024 masm, optimization, arguments_.immediate(), false); | 1069 GenerateFastApiCall(masm, |
| 1070 optimization, |
| 1071 argc, |
| 1072 lookup_map, |
| 1073 holder_lookup); |
1025 } else { | 1074 } else { |
1026 Handle<JSFunction> function = optimization.constant_function(); | 1075 Handle<JSFunction> function = optimization.constant_function(); |
1027 __ Move(a0, receiver); | 1076 __ Move(a0, receiver); |
1028 stub_compiler_->GenerateJumpFunction(object, function); | 1077 stub_compiler_->GenerateJumpFunction(object, function); |
1029 } | 1078 } |
1030 | 1079 |
1031 // Deferred code for fast API call case---clean preallocated space. | |
1032 if (can_do_fast_api_call) { | |
1033 __ bind(&miss_cleanup); | |
1034 FreeSpaceForFastApiCall(masm); | |
1035 __ Branch(miss_label); | |
1036 } | |
1037 | |
1038 // Invoke a regular function. | 1080 // Invoke a regular function. |
1039 __ bind(®ular_invoke); | 1081 __ bind(®ular_invoke); |
1040 if (can_do_fast_api_call) { | |
1041 FreeSpaceForFastApiCall(masm); | |
1042 } | |
1043 } | 1082 } |
1044 | 1083 |
1045 void CompileRegular(MacroAssembler* masm, | 1084 void CompileRegular(MacroAssembler* masm, |
1046 Handle<JSObject> object, | 1085 Handle<JSObject> object, |
1047 Register receiver, | 1086 Register receiver, |
1048 Register scratch1, | 1087 Register scratch1, |
1049 Register scratch2, | 1088 Register scratch2, |
1050 Register scratch3, | 1089 Register scratch3, |
1051 Handle<Name> name, | 1090 Handle<Name> name, |
1052 Handle<JSObject> interceptor_holder, | 1091 Handle<JSObject> interceptor_holder, |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1107 #define __ ACCESS_MASM(masm()) | 1146 #define __ ACCESS_MASM(masm()) |
1108 | 1147 |
1109 | 1148 |
1110 Register StubCompiler::CheckPrototypes(Handle<HeapType> type, | 1149 Register StubCompiler::CheckPrototypes(Handle<HeapType> type, |
1111 Register object_reg, | 1150 Register object_reg, |
1112 Handle<JSObject> holder, | 1151 Handle<JSObject> holder, |
1113 Register holder_reg, | 1152 Register holder_reg, |
1114 Register scratch1, | 1153 Register scratch1, |
1115 Register scratch2, | 1154 Register scratch2, |
1116 Handle<Name> name, | 1155 Handle<Name> name, |
1117 int save_at_depth, | |
1118 Label* miss, | 1156 Label* miss, |
1119 PrototypeCheckType check) { | 1157 PrototypeCheckType check) { |
1120 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate())); | 1158 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate())); |
1121 // Make sure that the type feedback oracle harvests the receiver map. | 1159 // Make sure that the type feedback oracle harvests the receiver map. |
1122 // TODO(svenpanne) Remove this hack when all ICs are reworked. | 1160 // TODO(svenpanne) Remove this hack when all ICs are reworked. |
1123 __ li(scratch1, Operand(receiver_map)); | 1161 __ li(scratch1, Operand(receiver_map)); |
1124 | 1162 |
1125 // Make sure there's no overlap between holder and object registers. | 1163 // Make sure there's no overlap between holder and object registers. |
1126 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 1164 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
1127 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) | 1165 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) |
1128 && !scratch2.is(scratch1)); | 1166 && !scratch2.is(scratch1)); |
1129 | 1167 |
1130 // Keep track of the current object in register reg. | 1168 // Keep track of the current object in register reg. |
1131 Register reg = object_reg; | 1169 Register reg = object_reg; |
1132 int depth = 0; | 1170 int depth = 0; |
1133 | 1171 |
1134 typedef FunctionCallbackArguments FCA; | |
1135 if (save_at_depth == depth) { | |
1136 __ sw(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize)); | |
1137 } | |
1138 | |
1139 Handle<JSObject> current = Handle<JSObject>::null(); | 1172 Handle<JSObject> current = Handle<JSObject>::null(); |
1140 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant()); | 1173 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant()); |
1141 Handle<JSObject> prototype = Handle<JSObject>::null(); | 1174 Handle<JSObject> prototype = Handle<JSObject>::null(); |
1142 Handle<Map> current_map = receiver_map; | 1175 Handle<Map> current_map = receiver_map; |
1143 Handle<Map> holder_map(holder->map()); | 1176 Handle<Map> holder_map(holder->map()); |
1144 // Traverse the prototype chain and check the maps in the prototype chain for | 1177 // Traverse the prototype chain and check the maps in the prototype chain for |
1145 // fast and global objects or do negative lookup for normal objects. | 1178 // fast and global objects or do negative lookup for normal objects. |
1146 while (!current_map.is_identical_to(holder_map)) { | 1179 while (!current_map.is_identical_to(holder_map)) { |
1147 ++depth; | 1180 ++depth; |
1148 | 1181 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1194 if (heap()->InNewSpace(*prototype)) { | 1227 if (heap()->InNewSpace(*prototype)) { |
1195 // The prototype is in new space; we cannot store a reference to it | 1228 // The prototype is in new space; we cannot store a reference to it |
1196 // in the code. Load it from the map. | 1229 // in the code. Load it from the map. |
1197 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); | 1230 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); |
1198 } else { | 1231 } else { |
1199 // The prototype is in old space; load it directly. | 1232 // The prototype is in old space; load it directly. |
1200 __ li(reg, Operand(prototype)); | 1233 __ li(reg, Operand(prototype)); |
1201 } | 1234 } |
1202 } | 1235 } |
1203 | 1236 |
1204 if (save_at_depth == depth) { | |
1205 __ sw(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize)); | |
1206 } | |
1207 | |
1208 // Go to the next object in the prototype chain. | 1237 // Go to the next object in the prototype chain. |
1209 current = prototype; | 1238 current = prototype; |
1210 current_map = handle(current->map()); | 1239 current_map = handle(current->map()); |
1211 } | 1240 } |
1212 | 1241 |
1213 // Log the check depth. | 1242 // Log the check depth. |
1214 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 1243 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
1215 | 1244 |
1216 if (depth != 0 || check == CHECK_ALL_MAPS) { | 1245 if (depth != 0 || check == CHECK_ALL_MAPS) { |
1217 // Check the holder map. | 1246 // Check the holder map. |
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1565 Handle<String> name) { | 1594 Handle<String> name) { |
1566 | 1595 |
1567 Counters* counters = isolate()->counters(); | 1596 Counters* counters = isolate()->counters(); |
1568 | 1597 |
1569 ASSERT(optimization.is_simple_api_call()); | 1598 ASSERT(optimization.is_simple_api_call()); |
1570 // Bail out if object is a global object as we don't want to | 1599 // Bail out if object is a global object as we don't want to |
1571 // repatch it to global receiver. | 1600 // repatch it to global receiver. |
1572 if (object->IsGlobalObject()) return Handle<Code>::null(); | 1601 if (object->IsGlobalObject()) return Handle<Code>::null(); |
1573 if (!cell.is_null()) return Handle<Code>::null(); | 1602 if (!cell.is_null()) return Handle<Code>::null(); |
1574 if (!object->IsJSObject()) return Handle<Code>::null(); | 1603 if (!object->IsJSObject()) return Handle<Code>::null(); |
1575 int depth = optimization.GetPrototypeDepthOfExpectedType( | 1604 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
1576 Handle<JSObject>::cast(object), holder); | 1605 CallOptimization::HolderLookup holder_lookup = |
1577 if (depth == kInvalidProtoDepth) return Handle<Code>::null(); | 1606 CallOptimization::kHolderNotFound; |
| 1607 Handle<Map> lookup_map = optimization.LookupHolderOfExpectedType( |
| 1608 receiver, receiver, holder, &holder_lookup); |
| 1609 if (holder_lookup == CallOptimization::kHolderNotFound) { |
| 1610 return Handle<Code>::null(); |
| 1611 } |
1578 | 1612 |
1579 Label miss, miss_before_stack_reserved; | 1613 Label miss; |
1580 | 1614 GenerateNameCheck(name, &miss); |
1581 GenerateNameCheck(name, &miss_before_stack_reserved); | |
1582 | 1615 |
1583 // Get the receiver from the stack. | 1616 // Get the receiver from the stack. |
1584 const int argc = arguments().immediate(); | 1617 const int argc = arguments().immediate(); |
1585 __ lw(a1, MemOperand(sp, argc * kPointerSize)); | 1618 __ lw(a1, MemOperand(sp, argc * kPointerSize)); |
1586 | 1619 |
1587 // Check that the receiver isn't a smi. | 1620 // Check that the receiver isn't a smi. |
1588 __ JumpIfSmi(a1, &miss_before_stack_reserved); | 1621 __ JumpIfSmi(a1, &miss); |
1589 | 1622 |
1590 __ IncrementCounter(counters->call_const(), 1, a0, a3); | 1623 __ IncrementCounter(counters->call_const(), 1, a0, a3); |
1591 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3); | |
1592 | |
1593 ReserveSpaceForFastApiCall(masm(), a0); | |
1594 | 1624 |
1595 // Check that the maps haven't changed and find a Holder as a side effect. | 1625 // Check that the maps haven't changed and find a Holder as a side effect. |
1596 CheckPrototypes( | 1626 CheckPrototypes( |
1597 IC::CurrentTypeOf(object, isolate()), | 1627 IC::CurrentTypeOf(object, isolate()), |
1598 a1, holder, a0, a3, t0, name, depth, &miss); | 1628 a1, holder, a0, a3, t0, name, &miss); |
1599 | 1629 |
1600 GenerateFastApiDirectCall(masm(), optimization, argc, false); | 1630 GenerateFastApiCall( |
| 1631 masm(), optimization, argc, lookup_map, holder_lookup); |
1601 | 1632 |
1602 __ bind(&miss); | 1633 HandlerFrontendFooter(&miss); |
1603 FreeSpaceForFastApiCall(masm()); | |
1604 | |
1605 HandlerFrontendFooter(&miss_before_stack_reserved); | |
1606 | 1634 |
1607 // Return the generated code. | 1635 // Return the generated code. |
1608 return GetCode(function); | 1636 return GetCode(function); |
1609 } | 1637 } |
1610 | 1638 |
1611 | 1639 |
1612 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { | 1640 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { |
1613 Label success; | 1641 Label success; |
1614 // Check that the object is a boolean. | 1642 // Check that the object is a boolean. |
1615 __ LoadRoot(at, Heap::kTrueValueRootIndex); | 1643 __ LoadRoot(at, Heap::kTrueValueRootIndex); |
(...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2155 // ----------------------------------- | 2183 // ----------------------------------- |
2156 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 2184 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
2157 } | 2185 } |
2158 | 2186 |
2159 | 2187 |
2160 #undef __ | 2188 #undef __ |
2161 | 2189 |
2162 } } // namespace v8::internal | 2190 } } // namespace v8::internal |
2163 | 2191 |
2164 #endif // V8_TARGET_ARCH_MIPS | 2192 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |