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

Side by Side Diff: src/a64/stub-cache-a64.cc

Issue 143633007: A64: Synchronize with r18764. (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/a64
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/a64/macro-assembler-a64.cc ('k') | src/api.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 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
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
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
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 &regular_invoke); 1027 &regular_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(&regular_invoke); 1073 __ Bind(&regular_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
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
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
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
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, &not_fast_object);
1760 __ B(&fast_object);
1761
1762 // In case of fast smi-only, convert to fast object, otherwise bail out.
1763 __ Bind(&not_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, &not_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(&not_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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/a64/macro-assembler-a64.cc ('k') | src/api.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698