OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_X64 | 7 #if V8_TARGET_ARCH_X64 |
8 | 8 |
9 #include "src/ic/call-optimization.h" | 9 #include "src/ic/call-optimization.h" |
10 #include "src/ic/ic-compiler.h" | 10 #include "src/ic/handler-compiler.h" |
11 | 11 |
12 namespace v8 { | 12 namespace v8 { |
13 namespace internal { | 13 namespace internal { |
14 | 14 |
15 #define __ ACCESS_MASM(masm) | 15 #define __ ACCESS_MASM(masm) |
16 | 16 |
17 | |
18 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( | 17 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( |
19 MacroAssembler* masm, Label* miss_label, Register receiver, | 18 MacroAssembler* masm, Label* miss_label, Register receiver, |
20 Handle<Name> name, Register scratch0, Register scratch1) { | 19 Handle<Name> name, Register scratch0, Register scratch1) { |
21 DCHECK(name->IsUniqueName()); | 20 DCHECK(name->IsUniqueName()); |
22 DCHECK(!receiver.is(scratch0)); | 21 DCHECK(!receiver.is(scratch0)); |
23 Counters* counters = masm->isolate()->counters(); | 22 Counters* counters = masm->isolate()->counters(); |
24 __ IncrementCounter(counters->negative_lookups(), 1); | 23 __ IncrementCounter(counters->negative_lookups(), 1); |
25 __ IncrementCounter(counters->negative_lookups_miss(), 1); | 24 __ IncrementCounter(counters->negative_lookups_miss(), 1); |
26 | 25 |
27 __ movp(scratch0, FieldOperand(receiver, HeapObject::kMapOffset)); | 26 __ movp(scratch0, FieldOperand(receiver, HeapObject::kMapOffset)); |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 Register scratch, Label* miss) { | 191 Register scratch, Label* miss) { |
193 Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name); | 192 Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name); |
194 DCHECK(cell->value()->IsTheHole()); | 193 DCHECK(cell->value()->IsTheHole()); |
195 __ Move(scratch, cell); | 194 __ Move(scratch, cell); |
196 __ Cmp(FieldOperand(scratch, Cell::kValueOffset), | 195 __ Cmp(FieldOperand(scratch, Cell::kValueOffset), |
197 masm->isolate()->factory()->the_hole_value()); | 196 masm->isolate()->factory()->the_hole_value()); |
198 __ j(not_equal, miss); | 197 __ j(not_equal, miss); |
199 } | 198 } |
200 | 199 |
201 | 200 |
| 201 void NamedStoreHandlerCompiler::GenerateStoreViaSetter( |
| 202 MacroAssembler* masm, Handle<HeapType> type, Register receiver, |
| 203 Handle<JSFunction> setter) { |
| 204 // ----------- S t a t e ------------- |
| 205 // -- rsp[0] : return address |
| 206 // ----------------------------------- |
| 207 { |
| 208 FrameScope scope(masm, StackFrame::INTERNAL); |
| 209 |
| 210 // Save value register, so we can restore it later. |
| 211 __ Push(value()); |
| 212 |
| 213 if (!setter.is_null()) { |
| 214 // Call the JavaScript setter with receiver and value on the stack. |
| 215 if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { |
| 216 // Swap in the global receiver. |
| 217 __ movp(receiver, |
| 218 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); |
| 219 } |
| 220 __ Push(receiver); |
| 221 __ Push(value()); |
| 222 ParameterCount actual(1); |
| 223 ParameterCount expected(setter); |
| 224 __ InvokeFunction(setter, expected, actual, CALL_FUNCTION, |
| 225 NullCallWrapper()); |
| 226 } else { |
| 227 // If we generate a global code snippet for deoptimization only, remember |
| 228 // the place to continue after deoptimization. |
| 229 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); |
| 230 } |
| 231 |
| 232 // We have to return the passed value, not the return value of the setter. |
| 233 __ Pop(rax); |
| 234 |
| 235 // Restore context register. |
| 236 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 237 } |
| 238 __ ret(0); |
| 239 } |
| 240 |
| 241 |
| 242 void NamedLoadHandlerCompiler::GenerateLoadViaGetter( |
| 243 MacroAssembler* masm, Handle<HeapType> type, Register receiver, |
| 244 Handle<JSFunction> getter) { |
| 245 // ----------- S t a t e ------------- |
| 246 // -- rax : receiver |
| 247 // -- rcx : name |
| 248 // -- rsp[0] : return address |
| 249 // ----------------------------------- |
| 250 { |
| 251 FrameScope scope(masm, StackFrame::INTERNAL); |
| 252 |
| 253 if (!getter.is_null()) { |
| 254 // Call the JavaScript getter with the receiver on the stack. |
| 255 if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { |
| 256 // Swap in the global receiver. |
| 257 __ movp(receiver, |
| 258 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); |
| 259 } |
| 260 __ Push(receiver); |
| 261 ParameterCount actual(0); |
| 262 ParameterCount expected(getter); |
| 263 __ InvokeFunction(getter, expected, actual, CALL_FUNCTION, |
| 264 NullCallWrapper()); |
| 265 } else { |
| 266 // If we generate a global code snippet for deoptimization only, remember |
| 267 // the place to continue after deoptimization. |
| 268 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); |
| 269 } |
| 270 |
| 271 // Restore context register. |
| 272 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 273 } |
| 274 __ ret(0); |
| 275 } |
| 276 |
| 277 |
| 278 void ElementHandlerCompiler::GenerateLoadDictionaryElement( |
| 279 MacroAssembler* masm) { |
| 280 // ----------- S t a t e ------------- |
| 281 // -- rcx : key |
| 282 // -- rdx : receiver |
| 283 // -- rsp[0] : return address |
| 284 // ----------------------------------- |
| 285 DCHECK(rdx.is(LoadIC::ReceiverRegister())); |
| 286 DCHECK(rcx.is(LoadIC::NameRegister())); |
| 287 Label slow, miss; |
| 288 |
| 289 // This stub is meant to be tail-jumped to, the receiver must already |
| 290 // have been verified by the caller to not be a smi. |
| 291 |
| 292 __ JumpIfNotSmi(rcx, &miss); |
| 293 __ SmiToInteger32(rbx, rcx); |
| 294 __ movp(rax, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 295 |
| 296 // Check whether the elements is a number dictionary. |
| 297 // rdx: receiver |
| 298 // rcx: key |
| 299 // rbx: key as untagged int32 |
| 300 // rax: elements |
| 301 __ LoadFromNumberDictionary(&slow, rax, rcx, rbx, r9, rdi, rax); |
| 302 __ ret(0); |
| 303 |
| 304 __ bind(&slow); |
| 305 // ----------- S t a t e ------------- |
| 306 // -- rcx : key |
| 307 // -- rdx : receiver |
| 308 // -- rsp[0] : return address |
| 309 // ----------------------------------- |
| 310 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); |
| 311 |
| 312 __ bind(&miss); |
| 313 // ----------- S t a t e ------------- |
| 314 // -- rcx : key |
| 315 // -- rdx : receiver |
| 316 // -- rsp[0] : return address |
| 317 // ----------------------------------- |
| 318 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
| 319 } |
| 320 |
| 321 |
202 #undef __ | 322 #undef __ |
203 #define __ ACCESS_MASM((masm())) | 323 #define __ ACCESS_MASM((masm())) |
204 | 324 |
205 | 325 |
206 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, | 326 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, |
207 Handle<Name> name) { | 327 Handle<Name> name) { |
208 if (!label->is_unused()) { | 328 if (!label->is_unused()) { |
209 __ bind(label); | 329 __ bind(label); |
210 __ Move(this->name(), name); | 330 __ Move(this->name(), name); |
211 } | 331 } |
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
657 // Do tail-call to the runtime system. | 777 // Do tail-call to the runtime system. |
658 ExternalReference store_callback_property = | 778 ExternalReference store_callback_property = |
659 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); | 779 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); |
660 __ TailCallExternalReference(store_callback_property, 5, 1); | 780 __ TailCallExternalReference(store_callback_property, 5, 1); |
661 | 781 |
662 // Return the generated code. | 782 // Return the generated code. |
663 return GetCode(kind(), Code::FAST, name); | 783 return GetCode(kind(), Code::FAST, name); |
664 } | 784 } |
665 | 785 |
666 | 786 |
667 #undef __ | |
668 #define __ ACCESS_MASM(masm) | |
669 | |
670 | |
671 void NamedStoreHandlerCompiler::GenerateStoreViaSetter( | |
672 MacroAssembler* masm, Handle<HeapType> type, Register receiver, | |
673 Handle<JSFunction> setter) { | |
674 // ----------- S t a t e ------------- | |
675 // -- rsp[0] : return address | |
676 // ----------------------------------- | |
677 { | |
678 FrameScope scope(masm, StackFrame::INTERNAL); | |
679 | |
680 // Save value register, so we can restore it later. | |
681 __ Push(value()); | |
682 | |
683 if (!setter.is_null()) { | |
684 // Call the JavaScript setter with receiver and value on the stack. | |
685 if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { | |
686 // Swap in the global receiver. | |
687 __ movp(receiver, | |
688 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); | |
689 } | |
690 __ Push(receiver); | |
691 __ Push(value()); | |
692 ParameterCount actual(1); | |
693 ParameterCount expected(setter); | |
694 __ InvokeFunction(setter, expected, actual, CALL_FUNCTION, | |
695 NullCallWrapper()); | |
696 } else { | |
697 // If we generate a global code snippet for deoptimization only, remember | |
698 // the place to continue after deoptimization. | |
699 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); | |
700 } | |
701 | |
702 // We have to return the passed value, not the return value of the setter. | |
703 __ Pop(rax); | |
704 | |
705 // Restore context register. | |
706 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | |
707 } | |
708 __ ret(0); | |
709 } | |
710 | |
711 | |
712 #undef __ | |
713 #define __ ACCESS_MASM(masm()) | |
714 | |
715 | |
716 Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor( | 787 Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor( |
717 Handle<Name> name) { | 788 Handle<Name> name) { |
718 __ PopReturnAddressTo(scratch1()); | 789 __ PopReturnAddressTo(scratch1()); |
719 __ Push(receiver()); | 790 __ Push(receiver()); |
720 __ Push(this->name()); | 791 __ Push(this->name()); |
721 __ Push(value()); | 792 __ Push(value()); |
722 __ PushReturnAddressFrom(scratch1()); | 793 __ PushReturnAddressFrom(scratch1()); |
723 | 794 |
724 // Do tail-call to the runtime system. | 795 // Do tail-call to the runtime system. |
725 ExternalReference store_ic_property = ExternalReference( | 796 ExternalReference store_ic_property = ExternalReference( |
726 IC_Utility(IC::kStorePropertyWithInterceptor), isolate()); | 797 IC_Utility(IC::kStorePropertyWithInterceptor), isolate()); |
727 __ TailCallExternalReference(store_ic_property, 3, 1); | 798 __ TailCallExternalReference(store_ic_property, 3, 1); |
728 | 799 |
729 // Return the generated code. | 800 // Return the generated code. |
730 return GetCode(kind(), Code::FAST, name); | 801 return GetCode(kind(), Code::FAST, name); |
731 } | 802 } |
732 | 803 |
733 | 804 |
734 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( | |
735 MapHandleList* receiver_maps, CodeHandleList* handler_stubs, | |
736 MapHandleList* transitioned_maps) { | |
737 Label miss; | |
738 __ JumpIfSmi(receiver(), &miss, Label::kNear); | |
739 | |
740 __ movp(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset)); | |
741 int receiver_count = receiver_maps->length(); | |
742 for (int i = 0; i < receiver_count; ++i) { | |
743 // Check map and tail call if there's a match | |
744 __ Cmp(scratch1(), receiver_maps->at(i)); | |
745 if (transitioned_maps->at(i).is_null()) { | |
746 __ j(equal, handler_stubs->at(i), RelocInfo::CODE_TARGET); | |
747 } else { | |
748 Label next_map; | |
749 __ j(not_equal, &next_map, Label::kNear); | |
750 __ Move(transition_map(), transitioned_maps->at(i), | |
751 RelocInfo::EMBEDDED_OBJECT); | |
752 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET); | |
753 __ bind(&next_map); | |
754 } | |
755 } | |
756 | |
757 __ bind(&miss); | |
758 | |
759 TailCallBuiltin(masm(), MissBuiltin(kind())); | |
760 | |
761 // Return the generated code. | |
762 return GetCode(kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); | |
763 } | |
764 | |
765 | |
766 Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } | 805 Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } |
767 | 806 |
768 | 807 |
769 #undef __ | |
770 #define __ ACCESS_MASM(masm) | |
771 | |
772 | |
773 void NamedLoadHandlerCompiler::GenerateLoadViaGetter( | |
774 MacroAssembler* masm, Handle<HeapType> type, Register receiver, | |
775 Handle<JSFunction> getter) { | |
776 // ----------- S t a t e ------------- | |
777 // -- rax : receiver | |
778 // -- rcx : name | |
779 // -- rsp[0] : return address | |
780 // ----------------------------------- | |
781 { | |
782 FrameScope scope(masm, StackFrame::INTERNAL); | |
783 | |
784 if (!getter.is_null()) { | |
785 // Call the JavaScript getter with the receiver on the stack. | |
786 if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { | |
787 // Swap in the global receiver. | |
788 __ movp(receiver, | |
789 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); | |
790 } | |
791 __ Push(receiver); | |
792 ParameterCount actual(0); | |
793 ParameterCount expected(getter); | |
794 __ InvokeFunction(getter, expected, actual, CALL_FUNCTION, | |
795 NullCallWrapper()); | |
796 } else { | |
797 // If we generate a global code snippet for deoptimization only, remember | |
798 // the place to continue after deoptimization. | |
799 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); | |
800 } | |
801 | |
802 // Restore context register. | |
803 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | |
804 } | |
805 __ ret(0); | |
806 } | |
807 | |
808 | |
809 #undef __ | |
810 #define __ ACCESS_MASM(masm()) | |
811 | |
812 | |
813 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( | 808 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( |
814 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { | 809 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { |
815 Label miss; | 810 Label miss; |
816 FrontendHeader(receiver(), name, &miss); | 811 FrontendHeader(receiver(), name, &miss); |
817 | 812 |
818 // Get the value from the cell. | 813 // Get the value from the cell. |
819 Register result = StoreIC::ValueRegister(); | 814 Register result = StoreIC::ValueRegister(); |
820 __ Move(result, cell); | 815 __ Move(result, cell); |
821 __ movp(result, FieldOperand(result, PropertyCell::kValueOffset)); | 816 __ movp(result, FieldOperand(result, PropertyCell::kValueOffset)); |
822 | 817 |
(...skipping 10 matching lines...) Expand all Loading... |
833 __ IncrementCounter(counters->named_load_global_stub(), 1); | 828 __ IncrementCounter(counters->named_load_global_stub(), 1); |
834 __ ret(0); | 829 __ ret(0); |
835 | 830 |
836 FrontendFooter(name, &miss); | 831 FrontendFooter(name, &miss); |
837 | 832 |
838 // Return the generated code. | 833 // Return the generated code. |
839 return GetCode(kind(), Code::NORMAL, name); | 834 return GetCode(kind(), Code::NORMAL, name); |
840 } | 835 } |
841 | 836 |
842 | 837 |
843 Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types, | |
844 CodeHandleList* handlers, | |
845 Handle<Name> name, | |
846 Code::StubType type, | |
847 IcCheckType check) { | |
848 Label miss; | |
849 | |
850 if (check == PROPERTY && | |
851 (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) { | |
852 // In case we are compiling an IC for dictionary loads and stores, just | |
853 // check whether the name is unique. | |
854 if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) { | |
855 __ JumpIfNotUniqueName(this->name(), &miss); | |
856 } else { | |
857 __ Cmp(this->name(), name); | |
858 __ j(not_equal, &miss); | |
859 } | |
860 } | |
861 | |
862 Label number_case; | |
863 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; | |
864 __ JumpIfSmi(receiver(), smi_target); | |
865 | |
866 // Polymorphic keyed stores may use the map register | |
867 Register map_reg = scratch1(); | |
868 DCHECK(kind() != Code::KEYED_STORE_IC || | |
869 map_reg.is(KeyedStoreIC::MapRegister())); | |
870 __ movp(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset)); | |
871 int receiver_count = types->length(); | |
872 int number_of_handled_maps = 0; | |
873 for (int current = 0; current < receiver_count; ++current) { | |
874 Handle<HeapType> type = types->at(current); | |
875 Handle<Map> map = IC::TypeToMap(*type, isolate()); | |
876 if (!map->is_deprecated()) { | |
877 number_of_handled_maps++; | |
878 // Check map and tail call if there's a match | |
879 __ Cmp(map_reg, map); | |
880 if (type->Is(HeapType::Number())) { | |
881 DCHECK(!number_case.is_unused()); | |
882 __ bind(&number_case); | |
883 } | |
884 __ j(equal, handlers->at(current), RelocInfo::CODE_TARGET); | |
885 } | |
886 } | |
887 DCHECK(number_of_handled_maps > 0); | |
888 | |
889 __ bind(&miss); | |
890 TailCallBuiltin(masm(), MissBuiltin(kind())); | |
891 | |
892 // Return the generated code. | |
893 InlineCacheState state = | |
894 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC; | |
895 return GetCode(kind(), type, name, state); | |
896 } | |
897 | |
898 | |
899 #undef __ | |
900 #define __ ACCESS_MASM(masm) | |
901 | |
902 | |
903 void ElementHandlerCompiler::GenerateLoadDictionaryElement( | |
904 MacroAssembler* masm) { | |
905 // ----------- S t a t e ------------- | |
906 // -- rcx : key | |
907 // -- rdx : receiver | |
908 // -- rsp[0] : return address | |
909 // ----------------------------------- | |
910 DCHECK(rdx.is(LoadIC::ReceiverRegister())); | |
911 DCHECK(rcx.is(LoadIC::NameRegister())); | |
912 Label slow, miss; | |
913 | |
914 // This stub is meant to be tail-jumped to, the receiver must already | |
915 // have been verified by the caller to not be a smi. | |
916 | |
917 __ JumpIfNotSmi(rcx, &miss); | |
918 __ SmiToInteger32(rbx, rcx); | |
919 __ movp(rax, FieldOperand(rdx, JSObject::kElementsOffset)); | |
920 | |
921 // Check whether the elements is a number dictionary. | |
922 // rdx: receiver | |
923 // rcx: key | |
924 // rbx: key as untagged int32 | |
925 // rax: elements | |
926 __ LoadFromNumberDictionary(&slow, rax, rcx, rbx, r9, rdi, rax); | |
927 __ ret(0); | |
928 | |
929 __ bind(&slow); | |
930 // ----------- S t a t e ------------- | |
931 // -- rcx : key | |
932 // -- rdx : receiver | |
933 // -- rsp[0] : return address | |
934 // ----------------------------------- | |
935 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); | |
936 | |
937 __ bind(&miss); | |
938 // ----------- S t a t e ------------- | |
939 // -- rcx : key | |
940 // -- rdx : receiver | |
941 // -- rsp[0] : return address | |
942 // ----------------------------------- | |
943 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | |
944 } | |
945 | |
946 | |
947 void PropertyICCompiler::GenerateRuntimeSetProperty(MacroAssembler* masm, | |
948 StrictMode strict_mode) { | |
949 // Return address is on the stack. | |
950 DCHECK(!rbx.is(StoreIC::ReceiverRegister()) && | |
951 !rbx.is(StoreIC::NameRegister()) && !rbx.is(StoreIC::ValueRegister())); | |
952 | |
953 __ PopReturnAddressTo(rbx); | |
954 __ Push(StoreIC::ReceiverRegister()); | |
955 __ Push(StoreIC::NameRegister()); | |
956 __ Push(StoreIC::ValueRegister()); | |
957 __ Push(Smi::FromInt(strict_mode)); | |
958 __ PushReturnAddressFrom(rbx); | |
959 | |
960 // Do tail-call to runtime routine. | |
961 __ TailCallRuntime(Runtime::kSetProperty, 4, 1); | |
962 } | |
963 | |
964 | |
965 #undef __ | 838 #undef __ |
966 } | 839 } |
967 } // namespace v8::internal | 840 } // namespace v8::internal |
968 | 841 |
969 #endif // V8_TARGET_ARCH_X64 | 842 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |