| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 723 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 734 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); | 734 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); |
| 735 | 735 |
| 736 __ CallExternalReference( | 736 __ CallExternalReference( |
| 737 ExternalReference(IC_Utility(id), masm->isolate()), | 737 ExternalReference(IC_Utility(id), masm->isolate()), |
| 738 StubCache::kInterceptorArgsLength); | 738 StubCache::kInterceptorArgsLength); |
| 739 } | 739 } |
| 740 | 740 |
| 741 | 741 |
| 742 static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength; | 742 static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength; |
| 743 | 743 |
| 744 // Reserves space for the extra arguments to API function in the | 744 static void GenerateFastApiCallBody(MacroAssembler* masm, |
| 745 // caller's frame. | 745 const CallOptimization& optimization, |
| 746 // | 746 int argc, |
| 747 // These arguments are set by CheckPrototypes and GenerateFastApiDirectCall. | 747 Register holder, |
| 748 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, | 748 Register scratch1, |
| 749 Register scratch) { | 749 Register scratch2, |
| 750 ASSERT(Smi::FromInt(0) == 0); | 750 Register scratch3, |
| 751 __ PushMultipleTimes(kFastApiCallArguments, xzr); | 751 bool restore_context) { |
| 752 } | 752 // TODO(all): We don't use all of the provided scratch registers. |
| 753 | 753 |
| 754 // ----------- S t a t e ------------- |
| 755 // -- sp[0] : last JS argument |
| 756 // -- ... |
| 757 // -- sp[(argc - 1) * 8] : first JS argument |
| 758 // -- sp[argc * 8] : receiver |
| 759 // ----------------------------------- |
| 760 ASSERT(optimization.is_simple_api_call()); |
| 754 | 761 |
| 755 // Undoes the effects of ReserveSpaceForFastApiCall. | 762 typedef FunctionCallbackArguments FCA; |
| 756 static void FreeSpaceForFastApiCall(MacroAssembler* masm) { | |
| 757 __ Drop(kFastApiCallArguments); | |
| 758 } | |
| 759 | 763 |
| 764 STATIC_ASSERT(FCA::kHolderIndex == 0); |
| 765 STATIC_ASSERT(FCA::kIsolateIndex == 1); |
| 766 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2); |
| 767 STATIC_ASSERT(FCA::kReturnValueOffset == 3); |
| 768 STATIC_ASSERT(FCA::kDataIndex == 4); |
| 769 STATIC_ASSERT(FCA::kCalleeIndex == 5); |
| 770 STATIC_ASSERT(FCA::kContextSaveIndex == 6); |
| 771 STATIC_ASSERT(FCA::kArgsLength == 7); |
| 760 | 772 |
| 761 static void GenerateFastApiDirectCall(MacroAssembler* masm, | 773 ASSERT(!AreAliased(holder, cp)); |
| 762 const CallOptimization& optimization, | 774 |
| 763 int argc, | |
| 764 bool restore_context) { | |
| 765 // ----------- S t a t e ------------- | |
| 766 // -- sp[0] - sp[48] : FunctionCallbackInfo, including | |
| 767 // holder (set by CheckPrototypes) | |
| 768 // -- sp[56] : last JS argument | |
| 769 // -- ... | |
| 770 // -- sp[(argc + 6) * 8] : first JS argument | |
| 771 // -- sp[(argc + 7) * 8] : receiver | |
| 772 // ----------------------------------- | |
| 773 typedef FunctionCallbackArguments FCA; | |
| 774 // Save calling context. | 775 // Save calling context. |
| 775 __ Poke(cp, FCA::kContextSaveIndex * kPointerSize); | 776 __ Push(cp); |
| 776 // Get the function and setup the context. | 777 // Get the function and setup the context. |
| 777 Handle<JSFunction> function = optimization.constant_function(); | 778 Handle<JSFunction> function = optimization.constant_function(); |
| 778 Register function_reg = x5; | 779 __ LoadHeapObject(scratch1, function); |
| 779 __ LoadHeapObject(function_reg, function); | 780 __ Ldr(cp, FieldMemOperand(scratch1, JSFunction::kContextOffset)); |
| 780 __ Ldr(cp, FieldMemOperand(function_reg, JSFunction::kContextOffset)); | 781 __ Push(scratch1); |
| 781 __ Poke(function_reg, FCA::kCalleeIndex * kPointerSize); | |
| 782 | 782 |
| 783 // Construct the FunctionCallbackInfo. | 783 // Construct the FunctionCallbackInfo. |
| 784 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); | 784 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
| 785 Handle<Object> call_data(api_call_info->data(), masm->isolate()); | 785 Handle<Object> call_data(api_call_info->data(), masm->isolate()); |
| 786 bool call_data_undefined = false; |
| 786 Register call_data_reg = x6; | 787 Register call_data_reg = x6; |
| 787 if (masm->isolate()->heap()->InNewSpace(*call_data)) { | 788 if (masm->isolate()->heap()->InNewSpace(*call_data)) { |
| 788 __ Mov(x0, Operand(api_call_info)); | 789 __ Mov(scratch1, Operand(api_call_info)); |
| 789 __ Ldr(call_data_reg, FieldMemOperand(x0, CallHandlerInfo::kDataOffset)); | 790 __ Ldr(scratch1, FieldMemOperand(scratch1, CallHandlerInfo::kDataOffset)); |
| 791 } else if (call_data->IsUndefined()) { |
| 792 call_data_undefined = true; |
| 793 // TODO(jbramley): Why load this into scratch3 here? It isn't used. Should |
| 794 // it be scratch1? |
| 795 __ LoadRoot(scratch3, Heap::kUndefinedValueRootIndex); |
| 790 } else { | 796 } else { |
| 791 __ Mov(call_data_reg, Operand(call_data)); | 797 __ Mov(call_data_reg, Operand(call_data)); |
| 792 } | 798 } |
| 793 // Store call data. | 799 __ Push(scratch1); |
| 794 __ Poke(call_data_reg, FCA::kDataIndex * kPointerSize); | 800 if (!call_data_undefined) { |
| 795 // Store isolate. | 801 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex); |
| 796 Register isolate_reg = x7; | 802 } |
| 797 __ Mov(isolate_reg, | 803 // Store ReturnValue default and ReturnValue. |
| 804 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex); |
| 805 __ Push(scratch1, scratch1); |
| 806 // Store isolate and holder. |
| 807 __ Mov(scratch1, |
| 798 Operand(ExternalReference::isolate_address(masm->isolate()))); | 808 Operand(ExternalReference::isolate_address(masm->isolate()))); |
| 799 __ Poke(isolate_reg, FCA::kIsolateIndex * kPointerSize); | 809 __ Push(scratch1, holder); |
| 800 // Store ReturnValue default and ReturnValue. | |
| 801 Register undefined_reg = x8; | |
| 802 __ LoadRoot(undefined_reg, Heap::kUndefinedValueRootIndex); | |
| 803 // TODO(all): These are adjacent. Once things settle down, use PokePair. | |
| 804 __ Poke(undefined_reg, FCA::kReturnValueOffset * kPointerSize); | |
| 805 __ Poke(undefined_reg, FCA::kReturnValueDefaultValueIndex * kPointerSize); | |
| 806 | 810 |
| 807 Register implicit_args = x2; | 811 Register implicit_args = x2; |
| 808 __ Mov(implicit_args, masm->StackPointer()); | 812 __ Mov(implicit_args, masm->StackPointer()); |
| 809 | 813 |
| 810 FrameScope frame_scope(masm, StackFrame::MANUAL); | 814 FrameScope frame_scope(masm, StackFrame::MANUAL); |
| 811 // Allocate the v8::Arguments structure inside the ExitFrame since it's not | 815 // Allocate the v8::Arguments structure inside the ExitFrame since it's not |
| 812 // controlled by GC. | 816 // controlled by GC. |
| 813 const int kApiArgsStackSpace = 4; | 817 const int kApiArgsStackSpace = 4; |
| 814 __ EnterExitFrame( | 818 __ EnterExitFrame( |
| 815 false, | 819 false, |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 866 thunk_ref, | 870 thunk_ref, |
| 867 x1, | 871 x1, |
| 868 kStackUnwindSpace, | 872 kStackUnwindSpace, |
| 869 spill_offset, | 873 spill_offset, |
| 870 return_value_operand, | 874 return_value_operand, |
| 871 restore_context ? | 875 restore_context ? |
| 872 &context_restore_operand : NULL); | 876 &context_restore_operand : NULL); |
| 873 } | 877 } |
| 874 | 878 |
| 875 | 879 |
| 880 // Generates call to API function. |
| 881 static void GenerateFastApiCall(MacroAssembler* masm, |
| 882 const CallOptimization& optimization, |
| 883 int argc, |
| 884 Handle<Map> map_to_holder, |
| 885 CallOptimization::HolderLookup holder_lookup) { |
| 886 Counters* counters = masm->isolate()->counters(); |
| 887 __ IncrementCounter(counters->call_const_fast_api(), 1, x0, x1); |
| 888 |
| 889 // Move holder to a register |
| 890 Register holder_reg = x0; |
| 891 switch (holder_lookup) { |
| 892 case CallOptimization::kHolderIsReceiver: |
| 893 { |
| 894 ASSERT(map_to_holder.is_null()); |
| 895 __ Peek(holder_reg, argc * kPointerSize); |
| 896 } |
| 897 break; |
| 898 case CallOptimization::kHolderIsPrototypeOfMap: |
| 899 { |
| 900 Handle<JSObject> holder(JSObject::cast(map_to_holder->prototype())); |
| 901 if (!masm->isolate()->heap()->InNewSpace(*holder)) { |
| 902 __ LoadObject(holder_reg, holder); |
| 903 } else { |
| 904 __ LoadObject(holder_reg, map_to_holder); |
| 905 __ Ldr(holder_reg, |
| 906 FieldMemOperand(holder_reg, Map::kPrototypeOffset)); |
| 907 } |
| 908 } |
| 909 break; |
| 910 case CallOptimization::kHolderNotFound: |
| 911 UNREACHABLE(); |
| 912 } |
| 913 GenerateFastApiCallBody(masm, |
| 914 optimization, |
| 915 argc, |
| 916 holder_reg, |
| 917 x1, |
| 918 x2, |
| 919 x3, |
| 920 false); |
| 921 } |
| 922 |
| 923 |
| 876 // Generate call to api function. | 924 // Generate call to api function. |
| 877 static void GenerateFastApiCall(MacroAssembler* masm, | 925 static void GenerateFastApiCall(MacroAssembler* masm, |
| 878 const CallOptimization& optimization, | 926 const CallOptimization& optimization, |
| 879 Register receiver, | 927 Register receiver, |
| 880 Register scratch, | 928 Register scratch, |
| 881 int argc, | 929 int argc, |
| 882 Register* values) { | 930 Register* values) { |
| 883 ASSERT(optimization.is_simple_api_call()); | |
| 884 ASSERT(!AreAliased(receiver, scratch)); | 931 ASSERT(!AreAliased(receiver, scratch)); |
| 885 | 932 |
| 886 typedef FunctionCallbackArguments FCA; | 933 __ Push(receiver); |
| 887 const int stack_space = kFastApiCallArguments + argc + 1; | |
| 888 // Assign stack space for the call arguments. | |
| 889 __ Claim(stack_space); | |
| 890 // Write holder to stack frame. | |
| 891 __ Poke(receiver, FCA::kHolderIndex * kPointerSize); | |
| 892 // Write receiver to stack frame. | |
| 893 int index = stack_space - 1; | |
| 894 __ Poke(receiver, index-- * kPointerSize); | |
| 895 // Write the arguments to stack frame. | 934 // Write the arguments to stack frame. |
| 896 for (int i = 0; i < argc; i++) { | 935 for (int i = 0; i < argc; i++) { |
| 897 ASSERT(!AreAliased(receiver, scratch, values[i])); | 936 // TODO(all): Groups pushes to minimize Push overhead. |
| 898 __ Poke(values[i], index-- * kPointerSize); | 937 Register arg = values[argc-1-i]; |
| 938 ASSERT(!receiver.is(arg)); |
| 939 ASSERT(!scratch.is(arg)); |
| 940 __ Push(arg); |
| 899 } | 941 } |
| 900 | 942 Register scratch1 = x0; |
| 901 GenerateFastApiDirectCall(masm, optimization, argc, true); | 943 Register scratch2 = x1; |
| 944 Register scratch3 = x2; |
| 945 // Make sure the receiver is in x3. |
| 946 __ Mov(x3, receiver); |
| 947 receiver = x3; |
| 948 // Stack now matches JSFunction ABI. |
| 949 GenerateFastApiCallBody(masm, |
| 950 optimization, |
| 951 argc, |
| 952 receiver, |
| 953 scratch1, |
| 954 scratch2, |
| 955 scratch3, |
| 956 true); |
| 902 } | 957 } |
| 903 | 958 |
| 904 | 959 |
| 905 class CallInterceptorCompiler BASE_EMBEDDED { | 960 class CallInterceptorCompiler BASE_EMBEDDED { |
| 906 public: | 961 public: |
| 907 CallInterceptorCompiler(CallStubCompiler* stub_compiler, | 962 CallInterceptorCompiler(CallStubCompiler* stub_compiler, |
| 908 const ParameterCount& arguments, | 963 const ParameterCount& arguments, |
| 909 Register name) | 964 Register name) |
| 910 : stub_compiler_(stub_compiler), | 965 : stub_compiler_(stub_compiler), |
| 911 arguments_(arguments), | 966 arguments_(arguments), |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 946 Register scratch3, | 1001 Register scratch3, |
| 947 Handle<JSObject> interceptor_holder, | 1002 Handle<JSObject> interceptor_holder, |
| 948 LookupResult* lookup, | 1003 LookupResult* lookup, |
| 949 Handle<Name> name, | 1004 Handle<Name> name, |
| 950 const CallOptimization& optimization, | 1005 const CallOptimization& optimization, |
| 951 Label* miss_label) { | 1006 Label* miss_label) { |
| 952 ASSERT(optimization.is_constant_call()); | 1007 ASSERT(optimization.is_constant_call()); |
| 953 ASSERT(!lookup->holder()->IsGlobalObject()); | 1008 ASSERT(!lookup->holder()->IsGlobalObject()); |
| 954 | 1009 |
| 955 Counters* counters = masm->isolate()->counters(); | 1010 Counters* counters = masm->isolate()->counters(); |
| 956 int depth1 = kInvalidProtoDepth; | |
| 957 int depth2 = kInvalidProtoDepth; | |
| 958 bool can_do_fast_api_call = false; | |
| 959 | |
| 960 if (optimization.is_simple_api_call() && | |
| 961 !lookup->holder()->IsGlobalObject()) { | |
| 962 depth1 = optimization.GetPrototypeDepthOfExpectedType( | |
| 963 object, interceptor_holder); | |
| 964 if (depth1 == kInvalidProtoDepth) { | |
| 965 depth2 = optimization.GetPrototypeDepthOfExpectedType( | |
| 966 interceptor_holder, Handle<JSObject>(lookup->holder())); | |
| 967 } | |
| 968 can_do_fast_api_call = | |
| 969 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth; | |
| 970 } | |
| 971 | |
| 972 __ IncrementCounter(counters->call_const_interceptor(), 1, | 1011 __ IncrementCounter(counters->call_const_interceptor(), 1, |
| 973 scratch1, scratch2); | 1012 scratch1, scratch2); |
| 974 | 1013 |
| 975 if (can_do_fast_api_call) { | |
| 976 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1, | |
| 977 scratch1, scratch2); | |
| 978 ReserveSpaceForFastApiCall(masm, scratch1); | |
| 979 } | |
| 980 | |
| 981 // Check that the maps from receiver to interceptor's holder | 1014 // Check that the maps from receiver to interceptor's holder |
| 982 // haven't changed and thus we can invoke interceptor. | 1015 // haven't changed and thus we can invoke interceptor. |
| 983 Label miss_cleanup; | 1016 Label miss_cleanup; |
| 984 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; | |
| 985 Register holder = | 1017 Register holder = |
| 986 stub_compiler_->CheckPrototypes( | 1018 stub_compiler_->CheckPrototypes( |
| 987 IC::CurrentTypeOf(object, masm->isolate()), receiver, | 1019 IC::CurrentTypeOf(object, masm->isolate()), receiver, |
| 988 interceptor_holder, scratch1, scratch2, scratch3, | 1020 interceptor_holder, scratch1, scratch2, scratch3, |
| 989 name, depth1, miss); | 1021 name, miss_label); |
| 990 | 1022 |
| 991 // Invoke an interceptor and if it provides a value, | 1023 // Invoke an interceptor and if it provides a value, |
| 992 // branch to |regular_invoke|. | 1024 // branch to |regular_invoke|. |
| 993 Label regular_invoke; | 1025 Label regular_invoke; |
| 994 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2, | 1026 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2, |
| 995 ®ular_invoke); | 1027 ®ular_invoke); |
| 996 | 1028 |
| 997 // Interceptor returned nothing for this property. Try to use cached | 1029 // Interceptor returned nothing for this property. Try to use cached |
| 998 // constant function. | 1030 // constant function. |
| 999 | 1031 |
| 1000 // Check that the maps from interceptor's holder to constant function's | 1032 // Check that the maps from interceptor's holder to constant function's |
| 1001 // holder haven't changed and thus we can use cached constant function. | 1033 // holder haven't changed and thus we can use cached constant function. |
| 1002 if (*interceptor_holder != lookup->holder()) { | 1034 if (*interceptor_holder != lookup->holder()) { |
| 1003 stub_compiler_->CheckPrototypes( | 1035 stub_compiler_->CheckPrototypes( |
| 1004 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, | 1036 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, |
| 1005 handle(lookup->holder()), scratch1, scratch2, scratch3, | 1037 handle(lookup->holder()), scratch1, scratch2, scratch3, |
| 1006 name, depth2, miss); | 1038 name, miss_label); |
| 1007 } else { | 1039 } |
| 1008 // CheckPrototypes has a side effect of fetching a 'holder' | 1040 |
| 1009 // for API (object which is instanceof for the signature). It's | 1041 Handle<Map> lookup_map; |
| 1010 // safe to omit it here, as if present, it should be fetched | 1042 CallOptimization::HolderLookup holder_lookup = |
| 1011 // by the previous CheckPrototypes. | 1043 CallOptimization::kHolderNotFound; |
| 1012 ASSERT(depth2 == kInvalidProtoDepth); | 1044 if (optimization.is_simple_api_call() && |
| 1045 !lookup->holder()->IsGlobalObject()) { |
| 1046 lookup_map = optimization.LookupHolderOfExpectedType( |
| 1047 object, object, interceptor_holder, &holder_lookup); |
| 1048 if (holder_lookup == CallOptimization::kHolderNotFound) { |
| 1049 lookup_map = |
| 1050 optimization.LookupHolderOfExpectedType( |
| 1051 object, |
| 1052 interceptor_holder, |
| 1053 Handle<JSObject>(lookup->holder()), |
| 1054 &holder_lookup); |
| 1055 } |
| 1013 } | 1056 } |
| 1014 | 1057 |
| 1015 // Invoke function. | 1058 // Invoke function. |
| 1016 if (can_do_fast_api_call) { | 1059 if (holder_lookup != CallOptimization::kHolderNotFound) { |
| 1017 GenerateFastApiDirectCall( | 1060 int argc = arguments_.immediate(); |
| 1018 masm, optimization, arguments_.immediate(), false); | 1061 GenerateFastApiCall(masm, |
| 1062 optimization, |
| 1063 argc, |
| 1064 lookup_map, |
| 1065 holder_lookup); |
| 1019 } else { | 1066 } else { |
| 1020 Handle<JSFunction> function = optimization.constant_function(); | 1067 Handle<JSFunction> function = optimization.constant_function(); |
| 1021 __ Mov(x0, receiver); | 1068 __ Mov(x0, receiver); |
| 1022 stub_compiler_->GenerateJumpFunction(object, function); | 1069 stub_compiler_->GenerateJumpFunction(object, function); |
| 1023 } | 1070 } |
| 1024 | 1071 |
| 1025 // Deferred code for fast API call case, clean preallocated space. | |
| 1026 if (can_do_fast_api_call) { | |
| 1027 __ Bind(&miss_cleanup); | |
| 1028 FreeSpaceForFastApiCall(masm); | |
| 1029 __ B(miss_label); | |
| 1030 } | |
| 1031 | |
| 1032 // Invoke a regular function. | 1072 // Invoke a regular function. |
| 1033 __ Bind(®ular_invoke); | 1073 __ Bind(®ular_invoke); |
| 1034 if (can_do_fast_api_call) { | |
| 1035 FreeSpaceForFastApiCall(masm); | |
| 1036 } | |
| 1037 } | 1074 } |
| 1038 | 1075 |
| 1039 void CompileRegular(MacroAssembler* masm, | 1076 void CompileRegular(MacroAssembler* masm, |
| 1040 Handle<JSObject> object, | 1077 Handle<JSObject> object, |
| 1041 Register receiver, | 1078 Register receiver, |
| 1042 Register scratch1, | 1079 Register scratch1, |
| 1043 Register scratch2, | 1080 Register scratch2, |
| 1044 Register scratch3, | 1081 Register scratch3, |
| 1045 Handle<Name> name, | 1082 Handle<Name> name, |
| 1046 Handle<JSObject> interceptor_holder, | 1083 Handle<JSObject> interceptor_holder, |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1096 | 1133 |
| 1097 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { | 1134 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { |
| 1098 __ Jump(code, RelocInfo::CODE_TARGET); | 1135 __ Jump(code, RelocInfo::CODE_TARGET); |
| 1099 } | 1136 } |
| 1100 | 1137 |
| 1101 | 1138 |
| 1102 #undef __ | 1139 #undef __ |
| 1103 #define __ ACCESS_MASM(masm()) | 1140 #define __ ACCESS_MASM(masm()) |
| 1104 | 1141 |
| 1105 | 1142 |
| 1106 Register StubCompiler::CheckPrototypes(Handle<Type> type, | 1143 Register StubCompiler::CheckPrototypes(Handle<HeapType> type, |
| 1107 Register object_reg, | 1144 Register object_reg, |
| 1108 Handle<JSObject> holder, | 1145 Handle<JSObject> holder, |
| 1109 Register holder_reg, | 1146 Register holder_reg, |
| 1110 Register scratch1, | 1147 Register scratch1, |
| 1111 Register scratch2, | 1148 Register scratch2, |
| 1112 Handle<Name> name, | 1149 Handle<Name> name, |
| 1113 int save_at_depth, | |
| 1114 Label* miss, | 1150 Label* miss, |
| 1115 PrototypeCheckType check) { | 1151 PrototypeCheckType check) { |
| 1116 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate())); | 1152 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate())); |
| 1117 // Make sure that the type feedback oracle harvests the receiver map. | 1153 // Make sure that the type feedback oracle harvests the receiver map. |
| 1118 // TODO(svenpanne) Remove this hack when all ICs are reworked. | 1154 // TODO(svenpanne) Remove this hack when all ICs are reworked. |
| 1119 __ Mov(scratch1, Operand(receiver_map)); | 1155 __ Mov(scratch1, Operand(receiver_map)); |
| 1120 | 1156 |
| 1121 // object_reg and holder_reg registers can alias. | 1157 // object_reg and holder_reg registers can alias. |
| 1122 ASSERT(!AreAliased(object_reg, scratch1, scratch2)); | 1158 ASSERT(!AreAliased(object_reg, scratch1, scratch2)); |
| 1123 ASSERT(!AreAliased(holder_reg, scratch1, scratch2)); | 1159 ASSERT(!AreAliased(holder_reg, scratch1, scratch2)); |
| 1124 | 1160 |
| 1125 // Keep track of the current object in register reg. | 1161 // Keep track of the current object in register reg. |
| 1126 Register reg = object_reg; | 1162 Register reg = object_reg; |
| 1127 int depth = 0; | 1163 int depth = 0; |
| 1128 | 1164 |
| 1129 typedef FunctionCallbackArguments FCA; | |
| 1130 if (save_at_depth == depth) { | |
| 1131 __ Poke(reg, FCA::kHolderIndex * kPointerSize); | |
| 1132 } | |
| 1133 | |
| 1134 Handle<JSObject> current = Handle<JSObject>::null(); | 1165 Handle<JSObject> current = Handle<JSObject>::null(); |
| 1135 if (type->IsConstant()) { | 1166 if (type->IsConstant()) { |
| 1136 current = Handle<JSObject>::cast(type->AsConstant()); | 1167 current = Handle<JSObject>::cast(type->AsConstant()); |
| 1137 } | 1168 } |
| 1138 Handle<JSObject> prototype = Handle<JSObject>::null(); | 1169 Handle<JSObject> prototype = Handle<JSObject>::null(); |
| 1139 Handle<Map> current_map = receiver_map; | 1170 Handle<Map> current_map = receiver_map; |
| 1140 Handle<Map> holder_map(holder->map()); | 1171 Handle<Map> holder_map(holder->map()); |
| 1141 // Traverse the prototype chain and check the maps in the prototype chain for | 1172 // Traverse the prototype chain and check the maps in the prototype chain for |
| 1142 // fast and global objects or do negative lookup for normal objects. | 1173 // fast and global objects or do negative lookup for normal objects. |
| 1143 while (!current_map.is_identical_to(holder_map)) { | 1174 while (!current_map.is_identical_to(holder_map)) { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1191 if (heap()->InNewSpace(*prototype)) { | 1222 if (heap()->InNewSpace(*prototype)) { |
| 1192 // The prototype is in new space; we cannot store a reference to it | 1223 // The prototype is in new space; we cannot store a reference to it |
| 1193 // in the code. Load it from the map. | 1224 // in the code. Load it from the map. |
| 1194 __ Ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); | 1225 __ Ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); |
| 1195 } else { | 1226 } else { |
| 1196 // The prototype is in old space; load it directly. | 1227 // The prototype is in old space; load it directly. |
| 1197 __ Mov(reg, Operand(prototype)); | 1228 __ Mov(reg, Operand(prototype)); |
| 1198 } | 1229 } |
| 1199 } | 1230 } |
| 1200 | 1231 |
| 1201 if (save_at_depth == depth) { | |
| 1202 __ Poke(reg, FCA::kHolderIndex * kPointerSize); | |
| 1203 } | |
| 1204 | |
| 1205 // Go to the next object in the prototype chain. | 1232 // Go to the next object in the prototype chain. |
| 1206 current = prototype; | 1233 current = prototype; |
| 1207 current_map = handle(current->map()); | 1234 current_map = handle(current->map()); |
| 1208 } | 1235 } |
| 1209 | 1236 |
| 1210 // Log the check depth. | 1237 // Log the check depth. |
| 1211 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 1238 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
| 1212 | 1239 |
| 1213 // Check the holder map. | 1240 // Check the holder map. |
| 1214 if (depth != 0 || check == CHECK_ALL_MAPS) { | 1241 if (depth != 0 || check == CHECK_ALL_MAPS) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1247 __ B(&success); | 1274 __ B(&success); |
| 1248 | 1275 |
| 1249 GenerateRestoreName(masm(), miss, name); | 1276 GenerateRestoreName(masm(), miss, name); |
| 1250 TailCallBuiltin(masm(), MissBuiltin(kind())); | 1277 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 1251 | 1278 |
| 1252 __ Bind(&success); | 1279 __ Bind(&success); |
| 1253 } | 1280 } |
| 1254 } | 1281 } |
| 1255 | 1282 |
| 1256 | 1283 |
| 1257 Register LoadStubCompiler::CallbackHandlerFrontend(Handle<Type> type, | 1284 Register LoadStubCompiler::CallbackHandlerFrontend(Handle<HeapType> type, |
| 1258 Register object_reg, | 1285 Register object_reg, |
| 1259 Handle<JSObject> holder, | 1286 Handle<JSObject> holder, |
| 1260 Handle<Name> name, | 1287 Handle<Name> name, |
| 1261 Handle<Object> callback) { | 1288 Handle<Object> callback) { |
| 1262 Label miss; | 1289 Label miss; |
| 1263 | 1290 |
| 1264 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss); | 1291 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss); |
| 1265 | 1292 |
| 1266 // TODO(jbramely): HandlerFrontendHeader returns its result in scratch1(), so | 1293 // TODO(jbramely): HandlerFrontendHeader returns its result in scratch1(), so |
| 1267 // we can't use it below, but that isn't very obvious. Is there a better way | 1294 // we can't use it below, but that isn't very obvious. Is there a better way |
| (...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1596 Representation::Tagged()); | 1623 Representation::Tagged()); |
| 1597 GenerateJumpFunction(object, function, &miss); | 1624 GenerateJumpFunction(object, function, &miss); |
| 1598 | 1625 |
| 1599 HandlerFrontendFooter(&miss); | 1626 HandlerFrontendFooter(&miss); |
| 1600 | 1627 |
| 1601 // Return the generated code. | 1628 // Return the generated code. |
| 1602 return GetCode(Code::FAST, name); | 1629 return GetCode(Code::FAST, name); |
| 1603 } | 1630 } |
| 1604 | 1631 |
| 1605 | 1632 |
| 1606 Handle<Code> CallStubCompiler::CompileArrayCodeCall( | |
| 1607 Handle<Object> object, | |
| 1608 Handle<JSObject> holder, | |
| 1609 Handle<Cell> cell, | |
| 1610 Handle<JSFunction> function, | |
| 1611 Handle<String> name, | |
| 1612 Code::StubType type) { | |
| 1613 Label miss; | |
| 1614 | |
| 1615 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1616 if (!cell.is_null()) { | |
| 1617 ASSERT(cell->value() == *function); | |
| 1618 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 1619 } | |
| 1620 | |
| 1621 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite(); | |
| 1622 site->SetElementsKind(GetInitialFastElementsKind()); | |
| 1623 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site); | |
| 1624 const int argc = arguments().immediate(); | |
| 1625 __ Mov(x0, argc); | |
| 1626 __ Mov(x1, Operand(function)); | |
| 1627 __ Mov(x2, Operand(site_feedback_cell)); | |
| 1628 | |
| 1629 ArrayConstructorStub stub(isolate()); | |
| 1630 __ TailCallStub(&stub); | |
| 1631 | |
| 1632 HandlerFrontendFooter(&miss); | |
| 1633 | |
| 1634 // Return the generated code. | |
| 1635 return GetCode(type, name); | |
| 1636 } | |
| 1637 | |
| 1638 | |
| 1639 Handle<Code> CallStubCompiler::CompileArrayPushCall( | |
| 1640 Handle<Object> object, | |
| 1641 Handle<JSObject> holder, | |
| 1642 Handle<Cell> cell, | |
| 1643 Handle<JSFunction> function, | |
| 1644 Handle<String> name, | |
| 1645 Code::StubType type) { | |
| 1646 // If object is not an array or is observed or sealed, bail out to regular | |
| 1647 // call. | |
| 1648 if (!object->IsJSArray() || | |
| 1649 !cell.is_null() || | |
| 1650 Handle<JSArray>::cast(object)->map()->is_observed() || | |
| 1651 !Handle<JSArray>::cast(object)->map()->is_extensible()) { | |
| 1652 return Handle<Code>::null(); | |
| 1653 } | |
| 1654 | |
| 1655 Label miss; | |
| 1656 | |
| 1657 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1658 | |
| 1659 Register receiver = x0; | |
| 1660 | |
| 1661 const int argc = arguments().immediate(); | |
| 1662 if (argc == 0) { | |
| 1663 // Nothing to do, just return the length. | |
| 1664 __ Ldr(x0, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1665 __ Drop(argc + 1); | |
| 1666 __ Ret(); | |
| 1667 } else { | |
| 1668 Label call_builtin; | |
| 1669 | |
| 1670 if (argc == 1) { // Otherwise fall through to call the builtin. | |
| 1671 Label attempt_to_grow_elements, with_write_barrier, check_double; | |
| 1672 | |
| 1673 Register elements_length = x8; | |
| 1674 Register length = x7; | |
| 1675 Register elements = x6; | |
| 1676 Register end_elements = x5; | |
| 1677 Register value = x4; | |
| 1678 // Get the elements array of the object. | |
| 1679 __ Ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); | |
| 1680 | |
| 1681 // Check that the elements are in fast mode and writable. | |
| 1682 __ CheckMap(elements, | |
| 1683 x10, | |
| 1684 Heap::kFixedArrayMapRootIndex, | |
| 1685 &check_double, | |
| 1686 DONT_DO_SMI_CHECK); | |
| 1687 | |
| 1688 // Get the array's length and calculate new length. | |
| 1689 __ Ldr(length, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1690 STATIC_ASSERT(kSmiTag == 0); | |
| 1691 __ Add(length, length, Operand(Smi::FromInt(argc))); | |
| 1692 | |
| 1693 // Check if we could survive without allocation. | |
| 1694 __ Ldr(elements_length, | |
| 1695 FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 1696 __ Cmp(length, elements_length); | |
| 1697 __ B(gt, &attempt_to_grow_elements); | |
| 1698 | |
| 1699 // Check if value is a smi. | |
| 1700 __ Peek(value, (argc - 1) * kPointerSize); | |
| 1701 __ JumpIfNotSmi(value, &with_write_barrier); | |
| 1702 | |
| 1703 // Save new length. | |
| 1704 __ Str(length, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1705 | |
| 1706 // Store the value. | |
| 1707 // We may need a register containing the address end_elements below, | |
| 1708 // so write back the value in end_elements. | |
| 1709 __ Add(end_elements, elements, | |
| 1710 Operand::UntagSmiAndScale(length, kPointerSizeLog2)); | |
| 1711 const int kEndElementsOffset = | |
| 1712 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize; | |
| 1713 __ Str(value, MemOperand(end_elements, kEndElementsOffset, PreIndex)); | |
| 1714 | |
| 1715 // Return length. | |
| 1716 __ Drop(argc + 1); | |
| 1717 __ Mov(x0, length); | |
| 1718 __ Ret(); | |
| 1719 | |
| 1720 __ Bind(&check_double); | |
| 1721 // Check that the elements are in fast mode and writable. | |
| 1722 __ CheckMap(elements, | |
| 1723 x10, | |
| 1724 Heap::kFixedDoubleArrayMapRootIndex, | |
| 1725 &call_builtin, | |
| 1726 DONT_DO_SMI_CHECK); | |
| 1727 | |
| 1728 // Get the array's length and calculate new length. | |
| 1729 Register old_length = x5; | |
| 1730 __ Ldr(old_length, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1731 STATIC_ASSERT(kSmiTag == 0); | |
| 1732 __ Add(length, old_length, Operand(Smi::FromInt(argc))); | |
| 1733 | |
| 1734 // Check if we could survive without allocation. | |
| 1735 __ Ldr(x10, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 1736 __ Cmp(length, x10); | |
| 1737 __ B(gt, &call_builtin); | |
| 1738 | |
| 1739 __ Peek(value, (argc - 1) * kPointerSize); | |
| 1740 __ StoreNumberToDoubleElements( | |
| 1741 value, old_length, elements, x10, d0, d1, | |
| 1742 &call_builtin); | |
| 1743 | |
| 1744 // Save new length. | |
| 1745 __ Str(length, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1746 | |
| 1747 // Return length. | |
| 1748 __ Drop(argc + 1); | |
| 1749 __ Mov(x0, length); | |
| 1750 __ Ret(); | |
| 1751 | |
| 1752 | |
| 1753 __ Bind(&with_write_barrier); | |
| 1754 Register map = x3; | |
| 1755 __ Ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 1756 | |
| 1757 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) { | |
| 1758 Label fast_object, not_fast_object; | |
| 1759 __ CheckFastObjectElements(map, x10, ¬_fast_object); | |
| 1760 __ B(&fast_object); | |
| 1761 | |
| 1762 // In case of fast smi-only, convert to fast object, otherwise bail out. | |
| 1763 __ Bind(¬_fast_object); | |
| 1764 __ CheckFastSmiElements(map, x10, &call_builtin); | |
| 1765 | |
| 1766 __ Ldr(x10, FieldMemOperand(value, HeapObject::kMapOffset)); | |
| 1767 __ JumpIfRoot(x10, Heap::kHeapNumberMapRootIndex, &call_builtin); | |
| 1768 | |
| 1769 Label try_holey_map; | |
| 1770 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, | |
| 1771 FAST_ELEMENTS, | |
| 1772 map, | |
| 1773 x10, | |
| 1774 &try_holey_map); | |
| 1775 // GenerateMapChangeElementsTransition expects the receiver to be in x2. | |
| 1776 // Since from this point we cannot jump on 'miss' it is ok to clobber | |
| 1777 // x2 (which initialy contained called function name). | |
| 1778 __ Mov(x2, receiver); | |
| 1779 ElementsTransitionGenerator:: | |
| 1780 GenerateMapChangeElementsTransition(masm(), | |
| 1781 DONT_TRACK_ALLOCATION_SITE, | |
| 1782 NULL); | |
| 1783 __ B(&fast_object); | |
| 1784 | |
| 1785 __ Bind(&try_holey_map); | |
| 1786 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS, | |
| 1787 FAST_HOLEY_ELEMENTS, | |
| 1788 map, | |
| 1789 x10, | |
| 1790 &call_builtin); | |
| 1791 // The previous comment about x2 usage also applies here. | |
| 1792 __ Mov(x2, receiver); | |
| 1793 ElementsTransitionGenerator:: | |
| 1794 GenerateMapChangeElementsTransition(masm(), | |
| 1795 DONT_TRACK_ALLOCATION_SITE, | |
| 1796 NULL); | |
| 1797 __ Bind(&fast_object); | |
| 1798 } else { | |
| 1799 __ CheckFastObjectElements(map, x3, &call_builtin); | |
| 1800 } | |
| 1801 | |
| 1802 // Save new length. | |
| 1803 __ Str(length, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1804 | |
| 1805 // Store the value. | |
| 1806 // We may need a register containing the address end_elements below, | |
| 1807 // so write back the value in end_elements. | |
| 1808 __ Add(end_elements, elements, | |
| 1809 Operand::UntagSmiAndScale(length, kPointerSizeLog2)); | |
| 1810 __ Str(value, MemOperand(end_elements, kEndElementsOffset, PreIndex)); | |
| 1811 | |
| 1812 __ RecordWrite(elements, | |
| 1813 end_elements, | |
| 1814 value, | |
| 1815 kLRHasNotBeenSaved, | |
| 1816 kDontSaveFPRegs, | |
| 1817 EMIT_REMEMBERED_SET, | |
| 1818 OMIT_SMI_CHECK); | |
| 1819 __ Drop(argc + 1); | |
| 1820 __ Mov(x0, length); | |
| 1821 __ Ret(); | |
| 1822 | |
| 1823 | |
| 1824 __ Bind(&attempt_to_grow_elements); | |
| 1825 | |
| 1826 if (!FLAG_inline_new) { | |
| 1827 __ B(&call_builtin); | |
| 1828 } | |
| 1829 | |
| 1830 Register argument = x2; | |
| 1831 __ Peek(argument, (argc - 1) * kPointerSize); | |
| 1832 // Growing elements that are SMI-only requires special handling in case | |
| 1833 // the new element is non-Smi. For now, delegate to the builtin. | |
| 1834 Label no_fast_elements_check; | |
| 1835 __ JumpIfSmi(argument, &no_fast_elements_check); | |
| 1836 __ Ldr(x10, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 1837 __ CheckFastObjectElements(x10, x10, &call_builtin); | |
| 1838 __ Bind(&no_fast_elements_check); | |
| 1839 | |
| 1840 ExternalReference new_space_allocation_top = | |
| 1841 ExternalReference::new_space_allocation_top_address(isolate()); | |
| 1842 ExternalReference new_space_allocation_limit = | |
| 1843 ExternalReference::new_space_allocation_limit_address(isolate()); | |
| 1844 | |
| 1845 const int kAllocationDelta = 4; | |
| 1846 Register allocation_top_addr = x5; | |
| 1847 Register allocation_top = x9; | |
| 1848 // Load top and check if it is the end of elements. | |
| 1849 __ Add(end_elements, elements, | |
| 1850 Operand::UntagSmiAndScale(length, kPointerSizeLog2)); | |
| 1851 __ Add(end_elements, end_elements, kEndElementsOffset); | |
| 1852 __ Mov(allocation_top_addr, Operand(new_space_allocation_top)); | |
| 1853 __ Ldr(allocation_top, MemOperand(allocation_top_addr)); | |
| 1854 __ Cmp(end_elements, allocation_top); | |
| 1855 __ B(ne, &call_builtin); | |
| 1856 | |
| 1857 __ Mov(x10, Operand(new_space_allocation_limit)); | |
| 1858 __ Ldr(x10, MemOperand(x10)); | |
| 1859 __ Add(allocation_top, allocation_top, kAllocationDelta * kPointerSize); | |
| 1860 __ Cmp(allocation_top, x10); | |
| 1861 __ B(hi, &call_builtin); | |
| 1862 | |
| 1863 // We fit and could grow elements. | |
| 1864 // Update new_space_allocation_top. | |
| 1865 __ Str(allocation_top, MemOperand(allocation_top_addr)); | |
| 1866 // Push the argument. | |
| 1867 __ Str(argument, MemOperand(end_elements)); | |
| 1868 // Fill the rest with holes. | |
| 1869 __ LoadRoot(x10, Heap::kTheHoleValueRootIndex); | |
| 1870 for (int i = 1; i < kAllocationDelta; i++) { | |
| 1871 // TODO(all): Try to use stp here. | |
| 1872 __ Str(x10, MemOperand(end_elements, i * kPointerSize)); | |
| 1873 } | |
| 1874 | |
| 1875 // Update elements' and array's sizes. | |
| 1876 __ Str(length, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1877 __ Add(elements_length, | |
| 1878 elements_length, | |
| 1879 Operand(Smi::FromInt(kAllocationDelta))); | |
| 1880 __ Str(elements_length, | |
| 1881 FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 1882 | |
| 1883 // Elements are in new space, so write barrier is not required. | |
| 1884 __ Drop(argc + 1); | |
| 1885 __ Mov(x0, length); | |
| 1886 __ Ret(); | |
| 1887 } | |
| 1888 __ Bind(&call_builtin); | |
| 1889 __ TailCallExternalReference( | |
| 1890 ExternalReference(Builtins::c_ArrayPush, isolate()), argc + 1, 1); | |
| 1891 } | |
| 1892 | |
| 1893 HandlerFrontendFooter(&miss); | |
| 1894 | |
| 1895 // Return the generated code. | |
| 1896 return GetCode(type, name); | |
| 1897 } | |
| 1898 | |
| 1899 | |
| 1900 Handle<Code> CallStubCompiler::CompileArrayPopCall( | |
| 1901 Handle<Object> object, | |
| 1902 Handle<JSObject> holder, | |
| 1903 Handle<Cell> cell, | |
| 1904 Handle<JSFunction> function, | |
| 1905 Handle<String> name, | |
| 1906 Code::StubType type) { | |
| 1907 // If object is not an array or is observed or sealed, bail out to regular | |
| 1908 // call. | |
| 1909 if (!object->IsJSArray() || | |
| 1910 !cell.is_null() || | |
| 1911 Handle<JSArray>::cast(object)->map()->is_observed() || | |
| 1912 !Handle<JSArray>::cast(object)->map()->is_extensible()) { | |
| 1913 return Handle<Code>::null(); | |
| 1914 } | |
| 1915 | |
| 1916 const int argc = arguments().immediate(); | |
| 1917 Label miss, return_undefined, call_builtin; | |
| 1918 Register receiver = x0; | |
| 1919 Register result = x1; | |
| 1920 Register elements = x3; | |
| 1921 Register length = x4; | |
| 1922 | |
| 1923 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1924 | |
| 1925 // Get the elements array of the object. | |
| 1926 __ Ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); | |
| 1927 | |
| 1928 // Check that the elements are in fast mode and writable. | |
| 1929 __ CheckMap(elements, | |
| 1930 x10, | |
| 1931 Heap::kFixedArrayMapRootIndex, | |
| 1932 &call_builtin, | |
| 1933 DONT_DO_SMI_CHECK); | |
| 1934 | |
| 1935 // Get the array's length and calculate new length. | |
| 1936 __ Ldr(length, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1937 __ Subs(length, length, Operand(Smi::FromInt(1))); | |
| 1938 __ B(lt, &return_undefined); | |
| 1939 | |
| 1940 // Get the last element. | |
| 1941 __ Add(elements, elements, | |
| 1942 Operand::UntagSmiAndScale(length, kPointerSizeLog2)); | |
| 1943 __ Ldr(result, FieldMemOperand(elements, FixedArray::kHeaderSize)); | |
| 1944 __ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &call_builtin); | |
| 1945 | |
| 1946 // Set the array's length. | |
| 1947 __ Str(length, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1948 | |
| 1949 // Fill with the hole. | |
| 1950 __ LoadRoot(x10, Heap::kTheHoleValueRootIndex); | |
| 1951 __ Str(x10, FieldMemOperand(elements, FixedArray::kHeaderSize)); | |
| 1952 __ Drop(argc + 1); | |
| 1953 __ Mov(x0, result); | |
| 1954 __ Ret(); | |
| 1955 | |
| 1956 __ Bind(&return_undefined); | |
| 1957 __ LoadRoot(x0, Heap::kUndefinedValueRootIndex); | |
| 1958 __ Drop(argc + 1); | |
| 1959 __ Ret(); | |
| 1960 | |
| 1961 __ Bind(&call_builtin); | |
| 1962 __ TailCallExternalReference( | |
| 1963 ExternalReference(Builtins::c_ArrayPop, isolate()), argc + 1, 1); | |
| 1964 | |
| 1965 HandlerFrontendFooter(&miss); | |
| 1966 | |
| 1967 // Return the generated code. | |
| 1968 return GetCode(type, name); | |
| 1969 } | |
| 1970 | |
| 1971 | |
| 1972 Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall( | |
| 1973 Handle<Object> object, | |
| 1974 Handle<JSObject> holder, | |
| 1975 Handle<Cell> cell, | |
| 1976 Handle<JSFunction> function, | |
| 1977 Handle<String> name, | |
| 1978 Code::StubType type) { | |
| 1979 // If object is not a string, bail out to regular call. | |
| 1980 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null(); | |
| 1981 | |
| 1982 Label miss; | |
| 1983 Label name_miss; | |
| 1984 Label index_out_of_range; | |
| 1985 Label* index_out_of_range_label = &index_out_of_range; | |
| 1986 | |
| 1987 if (kind_ == Code::CALL_IC && | |
| 1988 (CallICBase::StringStubState::decode(extra_state()) == | |
| 1989 DEFAULT_STRING_STUB)) { | |
| 1990 index_out_of_range_label = &miss; | |
| 1991 } | |
| 1992 HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss); | |
| 1993 | |
| 1994 Register receiver = x0; | |
| 1995 Register result = x1; | |
| 1996 Register index = x4; | |
| 1997 | |
| 1998 const int argc = arguments().immediate(); | |
| 1999 __ Peek(receiver, argc * kPointerSize); | |
| 2000 if (argc > 0) { | |
| 2001 __ Peek(index, (argc - 1) * kPointerSize); | |
| 2002 } else { | |
| 2003 __ LoadRoot(index, Heap::kUndefinedValueRootIndex); | |
| 2004 } | |
| 2005 | |
| 2006 StringCharCodeAtGenerator generator(receiver, | |
| 2007 index, | |
| 2008 result, | |
| 2009 &miss, // When not a string. | |
| 2010 &miss, // When not a number. | |
| 2011 index_out_of_range_label, | |
| 2012 STRING_INDEX_IS_NUMBER); | |
| 2013 generator.GenerateFast(masm()); | |
| 2014 __ Drop(argc + 1); | |
| 2015 __ Mov(x0, result); | |
| 2016 __ Ret(); | |
| 2017 | |
| 2018 StubRuntimeCallHelper call_helper; | |
| 2019 generator.GenerateSlow(masm(), call_helper); | |
| 2020 | |
| 2021 if (index_out_of_range.is_linked()) { | |
| 2022 __ Bind(&index_out_of_range); | |
| 2023 __ LoadRoot(x0, Heap::kNanValueRootIndex); | |
| 2024 __ Drop(argc + 1); | |
| 2025 __ Ret(); | |
| 2026 } | |
| 2027 | |
| 2028 __ Bind(&miss); | |
| 2029 // Restore function name in x2. | |
| 2030 __ Mov(x2, Operand(name)); | |
| 2031 HandlerFrontendFooter(&name_miss); | |
| 2032 | |
| 2033 // Return the generated code. | |
| 2034 return GetCode(type, name); | |
| 2035 } | |
| 2036 | |
| 2037 | |
| 2038 Handle<Code> CallStubCompiler::CompileStringCharAtCall( | |
| 2039 Handle<Object> object, | |
| 2040 Handle<JSObject> holder, | |
| 2041 Handle<Cell> cell, | |
| 2042 Handle<JSFunction> function, | |
| 2043 Handle<String> name, | |
| 2044 Code::StubType type) { | |
| 2045 // If object is not a string, bail out to regular call. | |
| 2046 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null(); | |
| 2047 | |
| 2048 const int argc = arguments().immediate(); | |
| 2049 Label miss; | |
| 2050 Label name_miss; | |
| 2051 Label index_out_of_range; | |
| 2052 Label* index_out_of_range_label = &index_out_of_range; | |
| 2053 | |
| 2054 if (kind_ == Code::CALL_IC && | |
| 2055 (CallICBase::StringStubState::decode(extra_state()) == | |
| 2056 DEFAULT_STRING_STUB)) { | |
| 2057 index_out_of_range_label = &miss; | |
| 2058 } | |
| 2059 | |
| 2060 HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss); | |
| 2061 | |
| 2062 Register receiver = x0; | |
| 2063 Register index = x4; | |
| 2064 Register scratch = x3; | |
| 2065 Register result = x1; | |
| 2066 | |
| 2067 if (argc > 0) { | |
| 2068 __ Peek(index, (argc - 1) * kPointerSize); | |
| 2069 } else { | |
| 2070 __ LoadRoot(index, Heap::kUndefinedValueRootIndex); | |
| 2071 } | |
| 2072 | |
| 2073 StringCharAtGenerator generator(receiver, | |
| 2074 index, | |
| 2075 scratch, | |
| 2076 result, | |
| 2077 &miss, // When not a string. | |
| 2078 &miss, // When not a number. | |
| 2079 index_out_of_range_label, | |
| 2080 STRING_INDEX_IS_NUMBER); | |
| 2081 generator.GenerateFast(masm()); | |
| 2082 __ Drop(argc + 1); | |
| 2083 __ Mov(x0, result); | |
| 2084 __ Ret(); | |
| 2085 | |
| 2086 StubRuntimeCallHelper call_helper; | |
| 2087 generator.GenerateSlow(masm(), call_helper); | |
| 2088 | |
| 2089 if (index_out_of_range.is_linked()) { | |
| 2090 __ Bind(&index_out_of_range); | |
| 2091 __ LoadRoot(x0, Heap::kempty_stringRootIndex); | |
| 2092 __ Drop(argc + 1); | |
| 2093 __ Ret(); | |
| 2094 } | |
| 2095 | |
| 2096 __ Bind(&miss); | |
| 2097 // Restore function name in x2. | |
| 2098 __ Mov(x2, Operand(name)); | |
| 2099 HandlerFrontendFooter(&name_miss); | |
| 2100 | |
| 2101 // Return the generated code. | |
| 2102 return GetCode(type, name); | |
| 2103 } | |
| 2104 | |
| 2105 | |
| 2106 Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall( | |
| 2107 Handle<Object> object, | |
| 2108 Handle<JSObject> holder, | |
| 2109 Handle<Cell> cell, | |
| 2110 Handle<JSFunction> function, | |
| 2111 Handle<String> name, | |
| 2112 Code::StubType type) { | |
| 2113 const int argc = arguments().immediate(); | |
| 2114 | |
| 2115 // If the object is not a JSObject or we got an unexpected number of | |
| 2116 // arguments, bail out to the regular call. | |
| 2117 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null(); | |
| 2118 | |
| 2119 Label miss; | |
| 2120 | |
| 2121 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 2122 if (!cell.is_null()) { | |
| 2123 ASSERT(cell->value() == *function); | |
| 2124 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 2125 } | |
| 2126 | |
| 2127 // Load the char code argument. | |
| 2128 Register code = x1; | |
| 2129 __ Peek(code, 0); | |
| 2130 | |
| 2131 // Check the code is a smi. | |
| 2132 Label slow; | |
| 2133 __ JumpIfNotSmi(code, &slow); | |
| 2134 | |
| 2135 // Make sure the smi code is a uint16. | |
| 2136 __ And(code, code, Operand(Smi::FromInt(0xffff))); | |
| 2137 | |
| 2138 Register result = x0; | |
| 2139 StringCharFromCodeGenerator generator(code, result); | |
| 2140 generator.GenerateFast(masm()); | |
| 2141 __ Drop(argc + 1); | |
| 2142 __ Ret(); | |
| 2143 | |
| 2144 StubRuntimeCallHelper call_helper; | |
| 2145 generator.GenerateSlow(masm(), call_helper); | |
| 2146 | |
| 2147 __ Bind(&slow); | |
| 2148 // We do not have to patch the receiver because the function makes no use of | |
| 2149 // it. | |
| 2150 GenerateJumpFunctionIgnoreReceiver(function); | |
| 2151 | |
| 2152 HandlerFrontendFooter(&miss); | |
| 2153 | |
| 2154 // Return the generated code. | |
| 2155 return GetCode(type, name); | |
| 2156 } | |
| 2157 | |
| 2158 | |
| 2159 Handle<Code> CallStubCompiler::CompileMathFloorCall( | |
| 2160 Handle<Object> object, | |
| 2161 Handle<JSObject> holder, | |
| 2162 Handle<Cell> cell, | |
| 2163 Handle<JSFunction> function, | |
| 2164 Handle<String> name, | |
| 2165 Code::StubType type) { | |
| 2166 Label miss; | |
| 2167 Label return_result; | |
| 2168 Register result = x0; | |
| 2169 const int argc = arguments().immediate(); | |
| 2170 | |
| 2171 // If the object is not a JSObject or we got an unexpected number of | |
| 2172 // arguments, bail out to the regular call. | |
| 2173 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null(); | |
| 2174 | |
| 2175 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 2176 if (!cell.is_null()) { | |
| 2177 ASSERT(cell->value() == *function); | |
| 2178 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 2179 } | |
| 2180 | |
| 2181 // Load the (only) argument. | |
| 2182 Register arg = x0; | |
| 2183 __ Peek(arg, 0); | |
| 2184 | |
| 2185 // If the argument is a smi, just return. | |
| 2186 __ JumpIfSmi(arg, &return_result); | |
| 2187 | |
| 2188 // Load the HeapNumber. | |
| 2189 Label slow; | |
| 2190 __ CheckMap(arg, x1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK); | |
| 2191 | |
| 2192 FPRegister double_value = d0; | |
| 2193 __ Ldr(double_value, FieldMemOperand(arg, HeapNumber::kValueOffset)); | |
| 2194 | |
| 2195 // Try to do the conversion and check for overflow. | |
| 2196 Label zero_or_overflow; | |
| 2197 Register int_value = x3; | |
| 2198 __ Fcvtms(int_value, double_value); | |
| 2199 __ Cmp(int_value, Smi::kMaxValue); | |
| 2200 __ Ccmp(int_value, Smi::kMinValue, NFlag, le); | |
| 2201 // If the second comparison is skipped, we will have N=1 and V=0, this will | |
| 2202 // force the following "lt" condition to be true. | |
| 2203 __ B(lt, &zero_or_overflow); | |
| 2204 | |
| 2205 Label smi_result; | |
| 2206 __ Cbnz(int_value, &smi_result); | |
| 2207 | |
| 2208 __ Bind(&zero_or_overflow); | |
| 2209 Register value = x1; | |
| 2210 __ Fmov(value, double_value); | |
| 2211 | |
| 2212 // Extract the exponent. | |
| 2213 // TODO(all): The constants in the HeapNumber class assume that the double | |
| 2214 // is stored in two 32-bit registers. They should assume offset within a | |
| 2215 // 64-bit register on 64-bit systems. However if we want to change that we | |
| 2216 // have to make some changes in x64 back-end. | |
| 2217 static const int exponent_shift = | |
| 2218 CountTrailingZeros(Double::kExponentMask, 64); | |
| 2219 static const int exponent_width = CountSetBits(Double::kExponentMask, 64); | |
| 2220 Register exponent = x3; | |
| 2221 __ Ubfx(exponent, value, exponent_shift, exponent_width); | |
| 2222 | |
| 2223 // Check for NaN, Infinity, and -Infinity. They are invariant through | |
| 2224 // a Math.Floor call, so just return the original argument. | |
| 2225 __ Cmp(exponent, Double::kExponentMask >> exponent_shift); | |
| 2226 __ B(&return_result, eq); | |
| 2227 | |
| 2228 // If the exponent is null, the number was 0 or -0. Otherwise the result | |
| 2229 // can't fit in a smi and we go to the slow path. | |
| 2230 __ Cbnz(exponent, &slow); | |
| 2231 | |
| 2232 // Check for -0. | |
| 2233 // If our HeapNumber is negative it was -0, so we just return it. | |
| 2234 __ TestAndBranchIfAnySet(value, Double::kSignMask, &return_result); | |
| 2235 | |
| 2236 __ Bind(&smi_result); | |
| 2237 // Tag and return the result. | |
| 2238 __ SmiTag(result, int_value); | |
| 2239 | |
| 2240 __ Bind(&return_result); | |
| 2241 __ Drop(argc + 1); | |
| 2242 __ Ret(); | |
| 2243 | |
| 2244 __ Bind(&slow); | |
| 2245 // We do not have to patch the receiver because the function makes no use of | |
| 2246 // it. | |
| 2247 GenerateJumpFunctionIgnoreReceiver(function); | |
| 2248 | |
| 2249 HandlerFrontendFooter(&miss); | |
| 2250 | |
| 2251 // Return the generated code. | |
| 2252 return GetCode(type, name); | |
| 2253 } | |
| 2254 | |
| 2255 | |
| 2256 Handle<Code> CallStubCompiler::CompileMathAbsCall( | |
| 2257 Handle<Object> object, | |
| 2258 Handle<JSObject> holder, | |
| 2259 Handle<Cell> cell, | |
| 2260 Handle<JSFunction> function, | |
| 2261 Handle<String> name, | |
| 2262 Code::StubType type) { | |
| 2263 const int argc = arguments().immediate(); | |
| 2264 | |
| 2265 // If the object is not a JSObject or we got an unexpected number of | |
| 2266 // arguments, bail out to the regular call. | |
| 2267 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null(); | |
| 2268 | |
| 2269 Register result = x0; | |
| 2270 Label miss, slow; | |
| 2271 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 2272 if (!cell.is_null()) { | |
| 2273 ASSERT(cell->value() == *function); | |
| 2274 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 2275 } | |
| 2276 | |
| 2277 // Load the (only) argument. | |
| 2278 Register arg = x0; | |
| 2279 __ Peek(arg, 0); | |
| 2280 | |
| 2281 // Check if the argument is a smi. | |
| 2282 Label not_smi; | |
| 2283 __ JumpIfNotSmi(arg, ¬_smi); | |
| 2284 | |
| 2285 __ SmiAbs(arg, &slow); | |
| 2286 // Smi case done. | |
| 2287 __ Drop(argc + 1); | |
| 2288 __ Ret(); | |
| 2289 | |
| 2290 // Check if the argument is a heap number and load its value. | |
| 2291 __ Bind(¬_smi); | |
| 2292 __ CheckMap( | |
| 2293 arg, x1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK); | |
| 2294 Register value = x1; | |
| 2295 __ Ldr(value, FieldMemOperand(arg, HeapNumber::kValueOffset)); | |
| 2296 | |
| 2297 // Check the sign of the argument. If the argument is positive, return it. | |
| 2298 Label negative_sign; | |
| 2299 __ TestAndBranchIfAnySet(value, Double::kSignMask, &negative_sign); | |
| 2300 __ Drop(argc + 1); | |
| 2301 __ Ret(); | |
| 2302 | |
| 2303 __ Bind(&negative_sign); | |
| 2304 FPRegister double_value = d0; | |
| 2305 __ Fmov(double_value, value); | |
| 2306 __ Fabs(double_value, double_value); | |
| 2307 __ AllocateHeapNumberWithValue(result, double_value, &slow, x1, x3); | |
| 2308 __ Drop(argc + 1); | |
| 2309 __ Ret(); | |
| 2310 | |
| 2311 __ Bind(&slow); | |
| 2312 // We do not have to patch the receiver because the function makes no use of | |
| 2313 // it. | |
| 2314 GenerateJumpFunctionIgnoreReceiver(function); | |
| 2315 | |
| 2316 HandlerFrontendFooter(&miss); | |
| 2317 | |
| 2318 // Return the generated code. | |
| 2319 return GetCode(type, name); | |
| 2320 } | |
| 2321 | |
| 2322 | |
| 2323 Handle<Code> CallStubCompiler::CompileFastApiCall( | 1633 Handle<Code> CallStubCompiler::CompileFastApiCall( |
| 2324 const CallOptimization& optimization, | 1634 const CallOptimization& optimization, |
| 2325 Handle<Object> object, | 1635 Handle<Object> object, |
| 2326 Handle<JSObject> holder, | 1636 Handle<JSObject> holder, |
| 2327 Handle<Cell> cell, | 1637 Handle<Cell> cell, |
| 2328 Handle<JSFunction> function, | 1638 Handle<JSFunction> function, |
| 2329 Handle<String> name) { | 1639 Handle<String> name) { |
| 2330 Counters* counters = isolate()->counters(); | 1640 Counters* counters = isolate()->counters(); |
| 2331 | 1641 |
| 2332 ASSERT(optimization.is_simple_api_call()); | 1642 ASSERT(optimization.is_simple_api_call()); |
| 2333 // Bail out if object is a global object as we don't want to | 1643 // Bail out if object is a global object as we don't want to |
| 2334 // repatch it to global receiver. | 1644 // repatch it to global receiver. |
| 2335 if (object->IsGlobalObject()) return Handle<Code>::null(); | 1645 if (object->IsGlobalObject()) return Handle<Code>::null(); |
| 2336 if (!cell.is_null()) return Handle<Code>::null(); | 1646 if (!cell.is_null()) return Handle<Code>::null(); |
| 2337 if (!object->IsJSObject()) return Handle<Code>::null(); | 1647 if (!object->IsJSObject()) return Handle<Code>::null(); |
| 2338 int depth = optimization.GetPrototypeDepthOfExpectedType( | 1648 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 2339 Handle<JSObject>::cast(object), holder); | 1649 CallOptimization::HolderLookup holder_lookup = |
| 2340 if (depth == kInvalidProtoDepth) return Handle<Code>::null(); | 1650 CallOptimization::kHolderNotFound; |
| 1651 Handle<Map> lookup_map = optimization.LookupHolderOfExpectedType( |
| 1652 receiver, receiver, holder, &holder_lookup); |
| 1653 if (holder_lookup == CallOptimization::kHolderNotFound) { |
| 1654 return Handle<Code>::null(); |
| 1655 } |
| 2341 | 1656 |
| 2342 Label miss, miss_before_stack_reserved; | 1657 Label miss; |
| 2343 GenerateNameCheck(name, &miss_before_stack_reserved); | 1658 GenerateNameCheck(name, &miss); |
| 2344 | 1659 |
| 2345 const int argc = arguments().immediate(); | 1660 const int argc = arguments().immediate(); |
| 2346 | 1661 |
| 2347 // Get the receiver from the stack. | 1662 // Get the receiver from the stack. |
| 2348 Register receiver = x1; | 1663 Register receiver_reg = x1; |
| 2349 __ Peek(receiver, argc * kPointerSize); | 1664 __ Peek(receiver_reg, argc * kPointerSize); |
| 2350 | 1665 |
| 2351 // Check that the receiver isn't a smi. | 1666 // Check that the receiver isn't a smi. |
| 2352 __ JumpIfSmi(receiver, &miss_before_stack_reserved); | 1667 __ JumpIfSmi(receiver_reg, &miss); |
| 2353 | 1668 |
| 2354 __ IncrementCounter(counters->call_const(), 1, x0, x3); | 1669 __ IncrementCounter(counters->call_const(), 1, x0, x3); |
| 2355 __ IncrementCounter(counters->call_const_fast_api(), 1, x0, x3); | |
| 2356 | |
| 2357 ReserveSpaceForFastApiCall(masm(), x0); | |
| 2358 | 1670 |
| 2359 // Check that the maps haven't changed and find a Holder as a side effect. | 1671 // Check that the maps haven't changed and find a Holder as a side effect. |
| 2360 CheckPrototypes(IC::CurrentTypeOf(object, isolate()), | 1672 CheckPrototypes(IC::CurrentTypeOf(object, isolate()), |
| 2361 receiver, holder, x0, x3, x4, name, depth, &miss); | 1673 receiver_reg, holder, x0, x3, x4, name, &miss); |
| 2362 | 1674 |
| 2363 GenerateFastApiDirectCall(masm(), optimization, argc, false); | 1675 GenerateFastApiCall( |
| 1676 masm(), optimization, argc, lookup_map, holder_lookup); |
| 2364 | 1677 |
| 2365 __ Bind(&miss); | 1678 HandlerFrontendFooter(&miss); |
| 2366 FreeSpaceForFastApiCall(masm()); | |
| 2367 | |
| 2368 HandlerFrontendFooter(&miss_before_stack_reserved); | |
| 2369 | 1679 |
| 2370 // Return the generated code. | 1680 // Return the generated code. |
| 2371 return GetCode(function); | 1681 return GetCode(function); |
| 2372 } | 1682 } |
| 2373 | 1683 |
| 2374 | 1684 |
| 2375 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { | 1685 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { |
| 2376 Label success; | 1686 Label success; |
| 2377 // Check that the object is a boolean. | 1687 // Check that the object is a boolean. |
| 2378 // TODO(all): Optimize this like LCodeGen::DoDeferredTaggedToI. | 1688 // TODO(all): Optimize this like LCodeGen::DoDeferredTaggedToI. |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2560 return GetCode(Code::NORMAL, name); | 1870 return GetCode(Code::NORMAL, name); |
| 2561 } | 1871 } |
| 2562 | 1872 |
| 2563 | 1873 |
| 2564 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 1874 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
| 2565 Handle<JSObject> object, | 1875 Handle<JSObject> object, |
| 2566 Handle<JSObject> holder, | 1876 Handle<JSObject> holder, |
| 2567 Handle<Name> name, | 1877 Handle<Name> name, |
| 2568 Handle<ExecutableAccessorInfo> callback) { | 1878 Handle<ExecutableAccessorInfo> callback) { |
| 2569 ASM_LOCATION("StoreStubCompiler::CompileStoreCallback"); | 1879 ASM_LOCATION("StoreStubCompiler::CompileStoreCallback"); |
| 2570 HandlerFrontend(IC::CurrentTypeOf(object, isolate()), | 1880 Register holder_reg = HandlerFrontend( |
| 2571 receiver(), holder, name); | 1881 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); |
| 2572 | 1882 |
| 2573 // Stub never generated for non-global objects that require access checks. | 1883 // Stub never generated for non-global objects that require access checks. |
| 2574 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); | 1884 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); |
| 2575 | 1885 |
| 1886 // TODO(jbramley): Make Push take more than four arguments and combine these |
| 1887 // two calls. |
| 1888 __ Push(receiver(), holder_reg); |
| 2576 __ Mov(scratch1(), Operand(callback)); | 1889 __ Mov(scratch1(), Operand(callback)); |
| 2577 __ Mov(scratch2(), Operand(name)); | 1890 __ Mov(scratch2(), Operand(name)); |
| 2578 __ Push(receiver(), scratch1(), scratch2(), value()); | 1891 __ Push(scratch1(), scratch2(), value()); |
| 2579 | 1892 |
| 2580 // Do tail-call to the runtime system. | 1893 // Do tail-call to the runtime system. |
| 2581 ExternalReference store_callback_property = | 1894 ExternalReference store_callback_property = |
| 2582 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); | 1895 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); |
| 2583 __ TailCallExternalReference(store_callback_property, 4, 1); | 1896 __ TailCallExternalReference(store_callback_property, 5, 1); |
| 2584 | 1897 |
| 2585 // Return the generated code. | 1898 // Return the generated code. |
| 2586 return GetCode(kind(), Code::FAST, name); | 1899 return GetCode(kind(), Code::FAST, name); |
| 2587 } | 1900 } |
| 2588 | 1901 |
| 2589 | 1902 |
| 2590 #undef __ | 1903 #undef __ |
| 2591 #define __ ACCESS_MASM(masm) | 1904 #define __ ACCESS_MASM(masm) |
| 2592 | 1905 |
| 2593 | 1906 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2665 | 1978 |
| 2666 // Handle store cache miss. | 1979 // Handle store cache miss. |
| 2667 __ Bind(&miss); | 1980 __ Bind(&miss); |
| 2668 TailCallBuiltin(masm(), MissBuiltin(kind())); | 1981 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 2669 | 1982 |
| 2670 // Return the generated code. | 1983 // Return the generated code. |
| 2671 return GetCode(kind(), Code::FAST, name); | 1984 return GetCode(kind(), Code::FAST, name); |
| 2672 } | 1985 } |
| 2673 | 1986 |
| 2674 | 1987 |
| 2675 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<Type> type, | 1988 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<HeapType> type, |
| 2676 Handle<JSObject> last, | 1989 Handle<JSObject> last, |
| 2677 Handle<Name> name) { | 1990 Handle<Name> name) { |
| 2678 NonexistentHandlerFrontend(type, last, name); | 1991 NonexistentHandlerFrontend(type, last, name); |
| 2679 | 1992 |
| 2680 // Return undefined if maps of the full prototype chain are still the | 1993 // Return undefined if maps of the full prototype chain are still the |
| 2681 // same and no global property with this name contains a value. | 1994 // same and no global property with this name contains a value. |
| 2682 __ LoadRoot(x0, Heap::kUndefinedValueRootIndex); | 1995 __ LoadRoot(x0, Heap::kUndefinedValueRootIndex); |
| 2683 __ Ret(); | 1996 __ Ret(); |
| 2684 | 1997 |
| 2685 // Return the generated code. | 1998 // Return the generated code. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2714 } | 2027 } |
| 2715 | 2028 |
| 2716 | 2029 |
| 2717 Register* KeyedStoreStubCompiler::registers() { | 2030 Register* KeyedStoreStubCompiler::registers() { |
| 2718 // receiver, name, value, scratch1, scratch2, scratch3. | 2031 // receiver, name, value, scratch1, scratch2, scratch3. |
| 2719 static Register registers[] = { x2, x1, x0, x3, x4, x5 }; | 2032 static Register registers[] = { x2, x1, x0, x3, x4, x5 }; |
| 2720 return registers; | 2033 return registers; |
| 2721 } | 2034 } |
| 2722 | 2035 |
| 2723 | 2036 |
| 2724 void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name, | |
| 2725 Register name_reg, | |
| 2726 Label* miss) { | |
| 2727 __ Cmp(name_reg, Operand(name)); | |
| 2728 __ B(ne, miss); | |
| 2729 } | |
| 2730 | |
| 2731 | |
| 2732 void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name, | |
| 2733 Register name_reg, | |
| 2734 Label* miss) { | |
| 2735 __ Cmp(name_reg, Operand(name)); | |
| 2736 __ B(ne, miss); | |
| 2737 } | |
| 2738 | |
| 2739 | |
| 2740 #undef __ | 2037 #undef __ |
| 2741 #define __ ACCESS_MASM(masm) | 2038 #define __ ACCESS_MASM(masm) |
| 2742 | 2039 |
| 2743 void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm, | 2040 void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm, |
| 2744 Register receiver, | 2041 Register receiver, |
| 2745 Handle<JSFunction> getter) { | 2042 Handle<JSFunction> getter) { |
| 2746 { | 2043 { |
| 2747 FrameScope scope(masm, StackFrame::INTERNAL); | 2044 FrameScope scope(masm, StackFrame::INTERNAL); |
| 2748 | 2045 |
| 2749 if (!getter.is_null()) { | 2046 if (!getter.is_null()) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2764 } | 2061 } |
| 2765 __ Ret(); | 2062 __ Ret(); |
| 2766 } | 2063 } |
| 2767 | 2064 |
| 2768 | 2065 |
| 2769 #undef __ | 2066 #undef __ |
| 2770 #define __ ACCESS_MASM(masm()) | 2067 #define __ ACCESS_MASM(masm()) |
| 2771 | 2068 |
| 2772 | 2069 |
| 2773 Handle<Code> LoadStubCompiler::CompileLoadGlobal( | 2070 Handle<Code> LoadStubCompiler::CompileLoadGlobal( |
| 2774 Handle<Type> type, | 2071 Handle<HeapType> type, |
| 2775 Handle<GlobalObject> global, | 2072 Handle<GlobalObject> global, |
| 2776 Handle<PropertyCell> cell, | 2073 Handle<PropertyCell> cell, |
| 2777 Handle<Name> name, | 2074 Handle<Name> name, |
| 2778 bool is_dont_delete) { | 2075 bool is_dont_delete) { |
| 2779 Label miss; | 2076 Label miss; |
| 2780 | 2077 |
| 2781 HandlerFrontendHeader(type, receiver(), global, name, &miss); | 2078 HandlerFrontendHeader(type, receiver(), global, name, &miss); |
| 2782 | 2079 |
| 2783 // Get the value from the cell. | 2080 // Get the value from the cell. |
| 2784 __ Mov(x3, Operand(cell)); | 2081 __ Mov(x3, Operand(cell)); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2802 | 2099 |
| 2803 | 2100 |
| 2804 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( | 2101 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( |
| 2805 TypeHandleList* types, | 2102 TypeHandleList* types, |
| 2806 CodeHandleList* handlers, | 2103 CodeHandleList* handlers, |
| 2807 Handle<Name> name, | 2104 Handle<Name> name, |
| 2808 Code::StubType type, | 2105 Code::StubType type, |
| 2809 IcCheckType check) { | 2106 IcCheckType check) { |
| 2810 Label miss; | 2107 Label miss; |
| 2811 | 2108 |
| 2812 if (check == PROPERTY) { | 2109 if (check == PROPERTY && |
| 2813 GenerateNameCheck(name, this->name(), &miss); | 2110 (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) { |
| 2111 __ CompareAndBranch(this->name(), Operand(name), ne, &miss); |
| 2814 } | 2112 } |
| 2815 | 2113 |
| 2816 Label number_case; | 2114 Label number_case; |
| 2817 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; | 2115 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; |
| 2818 __ JumpIfSmi(receiver(), smi_target); | 2116 __ JumpIfSmi(receiver(), smi_target); |
| 2819 | 2117 |
| 2820 Register map_reg = scratch1(); | 2118 Register map_reg = scratch1(); |
| 2821 __ Ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset)); | 2119 __ Ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset)); |
| 2822 int receiver_count = types->length(); | 2120 int receiver_count = types->length(); |
| 2823 int number_of_handled_maps = 0; | 2121 int number_of_handled_maps = 0; |
| 2824 for (int current = 0; current < receiver_count; ++current) { | 2122 for (int current = 0; current < receiver_count; ++current) { |
| 2825 Handle<Type> type = types->at(current); | 2123 Handle<HeapType> type = types->at(current); |
| 2826 Handle<Map> map = IC::TypeToMap(*type, isolate()); | 2124 Handle<Map> map = IC::TypeToMap(*type, isolate()); |
| 2827 if (!map->is_deprecated()) { | 2125 if (!map->is_deprecated()) { |
| 2828 number_of_handled_maps++; | 2126 number_of_handled_maps++; |
| 2829 Label try_next; | 2127 Label try_next; |
| 2830 __ Cmp(map_reg, Operand(map)); | 2128 __ Cmp(map_reg, Operand(map)); |
| 2831 __ B(ne, &try_next); | 2129 __ B(ne, &try_next); |
| 2832 if (type->Is(Type::Number())) { | 2130 if (type->Is(HeapType::Number())) { |
| 2833 ASSERT(!number_case.is_unused()); | 2131 ASSERT(!number_case.is_unused()); |
| 2834 __ Bind(&number_case); | 2132 __ Bind(&number_case); |
| 2835 } | 2133 } |
| 2836 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET); | 2134 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET); |
| 2837 __ Bind(&try_next); | 2135 __ Bind(&try_next); |
| 2838 } | 2136 } |
| 2839 } | 2137 } |
| 2840 ASSERT(number_of_handled_maps != 0); | 2138 ASSERT(number_of_handled_maps != 0); |
| 2841 | 2139 |
| 2842 __ Bind(&miss); | 2140 __ Bind(&miss); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2928 | 2226 |
| 2929 // Miss case, call the runtime. | 2227 // Miss case, call the runtime. |
| 2930 __ Bind(&miss); | 2228 __ Bind(&miss); |
| 2931 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 2229 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
| 2932 } | 2230 } |
| 2933 | 2231 |
| 2934 | 2232 |
| 2935 } } // namespace v8::internal | 2233 } } // namespace v8::internal |
| 2936 | 2234 |
| 2937 #endif // V8_TARGET_ARCH_A64 | 2235 #endif // V8_TARGET_ARCH_A64 |
| OLD | NEW |