OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
344 | 344 |
345 | 345 |
346 // Load a fast property out of a holder object (src). In-object properties | 346 // Load a fast property out of a holder object (src). In-object properties |
347 // are loaded directly otherwise the property is loaded from the properties | 347 // are loaded directly otherwise the property is loaded from the properties |
348 // fixed array. | 348 // fixed array. |
349 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, | 349 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, |
350 Register dst, | 350 Register dst, |
351 Register src, | 351 Register src, |
352 Handle<JSObject> holder, | 352 Handle<JSObject> holder, |
353 PropertyIndex index) { | 353 PropertyIndex index) { |
354 if (index.is_header_index()) { | 354 DoGenerateFastPropertyLoad( |
355 int offset = index.header_index() * kPointerSize; | 355 masm, dst, src, index.is_inobject(holder), index.translate(holder)); |
356 __ movq(dst, FieldOperand(src, offset)); | |
357 } else { | |
358 // Adjust for the number of properties stored in the holder. | |
359 int slot = index.field_index() - holder->map()->inobject_properties(); | |
360 if (slot < 0) { | |
361 // Get the property straight out of the holder. | |
362 int offset = holder->map()->instance_size() + (slot * kPointerSize); | |
363 __ movq(dst, FieldOperand(src, offset)); | |
364 } else { | |
365 // Calculate the offset into the properties array. | |
366 int offset = slot * kPointerSize + FixedArray::kHeaderSize; | |
367 __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset)); | |
368 __ movq(dst, FieldOperand(dst, offset)); | |
369 } | |
370 } | |
371 } | 356 } |
372 | 357 |
373 | 358 |
| 359 void StubCompiler::DoGenerateFastPropertyLoad(MacroAssembler* masm, |
| 360 Register dst, |
| 361 Register src, |
| 362 bool inobject, |
| 363 int index) { |
| 364 int offset = index * kPointerSize; |
| 365 if (!inobject) { |
| 366 // Calculate the offset into the properties array. |
| 367 offset = offset + FixedArray::kHeaderSize; |
| 368 __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset)); |
| 369 src = dst; |
| 370 } |
| 371 __ movq(dst, FieldOperand(src, offset)); |
| 372 } |
| 373 |
| 374 |
374 static void PushInterceptorArguments(MacroAssembler* masm, | 375 static void PushInterceptorArguments(MacroAssembler* masm, |
375 Register receiver, | 376 Register receiver, |
376 Register holder, | 377 Register holder, |
377 Register name, | 378 Register name, |
378 Handle<JSObject> holder_obj) { | 379 Handle<JSObject> holder_obj) { |
379 __ push(name); | 380 __ push(name); |
380 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); | 381 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); |
381 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor)); | 382 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor)); |
382 __ Move(kScratchRegister, interceptor); | 383 __ Move(kScratchRegister, interceptor); |
383 __ push(kScratchRegister); | 384 __ push(kScratchRegister); |
(...skipping 520 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
904 miss); | 905 miss); |
905 } | 906 } |
906 current = Handle<JSObject>(JSObject::cast(current->GetPrototype())); | 907 current = Handle<JSObject>(JSObject::cast(current->GetPrototype())); |
907 } | 908 } |
908 } | 909 } |
909 | 910 |
910 #undef __ | 911 #undef __ |
911 #define __ ACCESS_MASM((masm())) | 912 #define __ ACCESS_MASM((masm())) |
912 | 913 |
913 | 914 |
| 915 void StubCompiler::GenerateTailCall(Handle<Code> code) { |
| 916 __ jmp(code, RelocInfo::CODE_TARGET); |
| 917 } |
| 918 |
| 919 |
914 Register StubCompiler::CheckPrototypes(Handle<JSObject> object, | 920 Register StubCompiler::CheckPrototypes(Handle<JSObject> object, |
915 Register object_reg, | 921 Register object_reg, |
916 Handle<JSObject> holder, | 922 Handle<JSObject> holder, |
917 Register holder_reg, | 923 Register holder_reg, |
918 Register scratch1, | 924 Register scratch1, |
919 Register scratch2, | 925 Register scratch2, |
920 Handle<String> name, | 926 Handle<String> name, |
921 int save_at_depth, | 927 int save_at_depth, |
922 Label* miss) { | 928 Label* miss, |
| 929 PrototypeCheckType check) { |
| 930 Handle<JSObject> first = object; |
923 // Make sure there's no overlap between holder and object registers. | 931 // Make sure there's no overlap between holder and object registers. |
924 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 932 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
925 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) | 933 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) |
926 && !scratch2.is(scratch1)); | 934 && !scratch2.is(scratch1)); |
927 | 935 |
928 // Keep track of the current object in register reg. On the first | 936 // Keep track of the current object in register reg. On the first |
929 // iteration, reg is an alias for object_reg, on later iterations, | 937 // iteration, reg is an alias for object_reg, on later iterations, |
930 // it is an alias for holder_reg. | 938 // it is an alias for holder_reg. |
931 Register reg = object_reg; | 939 Register reg = object_reg; |
932 int depth = 0; | 940 int depth = 0; |
(...skipping 28 matching lines...) Expand all Loading... |
961 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | 969 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
962 reg = holder_reg; // From now on the object will be in holder_reg. | 970 reg = holder_reg; // From now on the object will be in holder_reg. |
963 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); | 971 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); |
964 } else { | 972 } else { |
965 bool in_new_space = heap()->InNewSpace(*prototype); | 973 bool in_new_space = heap()->InNewSpace(*prototype); |
966 Handle<Map> current_map(current->map()); | 974 Handle<Map> current_map(current->map()); |
967 if (in_new_space) { | 975 if (in_new_space) { |
968 // Save the map in scratch1 for later. | 976 // Save the map in scratch1 for later. |
969 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | 977 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
970 } | 978 } |
971 __ CheckMap(reg, Handle<Map>(current_map), | 979 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) { |
972 miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS); | 980 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK, |
| 981 ALLOW_ELEMENT_TRANSITION_MAPS); |
| 982 } |
973 | 983 |
974 // Check access rights to the global object. This has to happen after | 984 // Check access rights to the global object. This has to happen after |
975 // the map check so that we know that the object is actually a global | 985 // the map check so that we know that the object is actually a global |
976 // object. | 986 // object. |
977 if (current->IsJSGlobalProxy()) { | 987 if (current->IsJSGlobalProxy()) { |
978 __ CheckAccessGlobalProxy(reg, scratch2, miss); | 988 __ CheckAccessGlobalProxy(reg, scratch2, miss); |
979 } | 989 } |
980 reg = holder_reg; // From now on the object will be in holder_reg. | 990 reg = holder_reg; // From now on the object will be in holder_reg. |
981 | 991 |
982 if (in_new_space) { | 992 if (in_new_space) { |
(...skipping 11 matching lines...) Expand all Loading... |
994 } | 1004 } |
995 | 1005 |
996 // Go to the next object in the prototype chain. | 1006 // Go to the next object in the prototype chain. |
997 current = prototype; | 1007 current = prototype; |
998 } | 1008 } |
999 ASSERT(current.is_identical_to(holder)); | 1009 ASSERT(current.is_identical_to(holder)); |
1000 | 1010 |
1001 // Log the check depth. | 1011 // Log the check depth. |
1002 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 1012 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
1003 | 1013 |
1004 // Check the holder map. | 1014 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) { |
1005 __ CheckMap(reg, Handle<Map>(holder->map()), | 1015 // Check the holder map. |
1006 miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS); | 1016 __ CheckMap(reg, Handle<Map>(holder->map()), |
| 1017 miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS); |
| 1018 } |
1007 | 1019 |
1008 // Perform security check for access to the global object. | 1020 // Perform security check for access to the global object. |
1009 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); | 1021 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); |
1010 if (current->IsJSGlobalProxy()) { | 1022 if (current->IsJSGlobalProxy()) { |
1011 __ CheckAccessGlobalProxy(reg, scratch1, miss); | 1023 __ CheckAccessGlobalProxy(reg, scratch1, miss); |
1012 } | 1024 } |
1013 | 1025 |
1014 // If we've skipped any global objects, it's not enough to verify that | 1026 // If we've skipped any global objects, it's not enough to verify that |
1015 // their maps haven't changed. We also need to check that the property | 1027 // their maps haven't changed. We also need to check that the property |
1016 // cell for the property is still empty. | 1028 // cell for the property is still empty. |
1017 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss); | 1029 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss); |
1018 | 1030 |
1019 // Return the register containing the holder. | 1031 // Return the register containing the holder. |
1020 return reg; | 1032 return reg; |
1021 } | 1033 } |
1022 | 1034 |
1023 | 1035 |
1024 void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success, | 1036 void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success, |
1025 Label* miss) { | 1037 Label* miss) { |
1026 __ jmp(success); | 1038 if (!miss->is_unused()) { |
1027 __ bind(miss); | 1039 __ jmp(success); |
1028 GenerateLoadMiss(masm(), kind()); | 1040 __ bind(miss); |
| 1041 GenerateLoadMiss(masm(), kind()); |
| 1042 } |
1029 } | 1043 } |
1030 | 1044 |
1031 | 1045 |
1032 Register BaseLoadStubCompiler::CallbackHandlerFrontend( | 1046 Register BaseLoadStubCompiler::CallbackHandlerFrontend( |
1033 Handle<JSObject> object, | 1047 Handle<JSObject> object, |
1034 Register object_reg, | 1048 Register object_reg, |
1035 Handle<JSObject> holder, | 1049 Handle<JSObject> holder, |
1036 Handle<String> name, | 1050 Handle<String> name, |
1037 Label* success, | 1051 Label* success, |
1038 FrontendCheckType check, | |
1039 Handle<ExecutableAccessorInfo> callback) { | 1052 Handle<ExecutableAccessorInfo> callback) { |
1040 Label miss; | 1053 Label miss; |
1041 | 1054 |
1042 Register reg = HandlerFrontendHeader( | 1055 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss); |
1043 object, object_reg, holder, name, &miss, check); | |
1044 | 1056 |
1045 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { | 1057 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { |
1046 ASSERT(!reg.is(scratch2())); | 1058 ASSERT(!reg.is(scratch2())); |
1047 ASSERT(!reg.is(scratch3())); | 1059 ASSERT(!reg.is(scratch3())); |
1048 ASSERT(!reg.is(scratch4())); | 1060 ASSERT(!reg.is(scratch4())); |
1049 | 1061 |
1050 // Load the properties dictionary. | 1062 // Load the properties dictionary. |
1051 Register dictionary = scratch4(); | 1063 Register dictionary = scratch4(); |
1052 __ movq(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset)); | 1064 __ movq(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset)); |
1053 | 1065 |
(...skipping 29 matching lines...) Expand all Loading... |
1083 | 1095 |
1084 | 1096 |
1085 void BaseLoadStubCompiler::NonexistentHandlerFrontend( | 1097 void BaseLoadStubCompiler::NonexistentHandlerFrontend( |
1086 Handle<JSObject> object, | 1098 Handle<JSObject> object, |
1087 Handle<JSObject> last, | 1099 Handle<JSObject> last, |
1088 Handle<String> name, | 1100 Handle<String> name, |
1089 Label* success, | 1101 Label* success, |
1090 Handle<GlobalObject> global) { | 1102 Handle<GlobalObject> global) { |
1091 Label miss; | 1103 Label miss; |
1092 | 1104 |
1093 Register reg = HandlerFrontendHeader( | 1105 Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss); |
1094 object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS); | |
1095 | 1106 |
1096 // If the last object in the prototype chain is a global object, | 1107 // If the last object in the prototype chain is a global object, |
1097 // check that the global property cell is empty. | 1108 // check that the global property cell is empty. |
1098 if (!global.is_null()) { | 1109 if (!global.is_null()) { |
1099 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss); | 1110 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss); |
1100 } | 1111 } |
1101 | 1112 |
1102 if (!last->HasFastProperties()) { | 1113 if (!last->HasFastProperties()) { |
1103 __ movq(scratch2(), FieldOperand(reg, HeapObject::kMapOffset)); | 1114 __ movq(scratch2(), FieldOperand(reg, HeapObject::kMapOffset)); |
1104 __ movq(scratch2(), FieldOperand(scratch2(), Map::kPrototypeOffset)); | 1115 __ movq(scratch2(), FieldOperand(scratch2(), Map::kPrototypeOffset)); |
(...skipping 25 matching lines...) Expand all Loading... |
1130 __ push(reg); // holder | 1141 __ push(reg); // holder |
1131 if (heap()->InNewSpace(callback->data())) { | 1142 if (heap()->InNewSpace(callback->data())) { |
1132 __ Move(scratch1(), callback); | 1143 __ Move(scratch1(), callback); |
1133 __ push(FieldOperand(scratch1(), | 1144 __ push(FieldOperand(scratch1(), |
1134 ExecutableAccessorInfo::kDataOffset)); // data | 1145 ExecutableAccessorInfo::kDataOffset)); // data |
1135 } else { | 1146 } else { |
1136 __ Push(Handle<Object>(callback->data(), isolate())); | 1147 __ Push(Handle<Object>(callback->data(), isolate())); |
1137 } | 1148 } |
1138 __ PushAddress(ExternalReference::isolate_address()); // isolate | 1149 __ PushAddress(ExternalReference::isolate_address()); // isolate |
1139 __ push(name()); // name | 1150 __ push(name()); // name |
1140 // Save a pointer to where we pushed the arguments pointer. | 1151 // Save a pointer to where we pushed the arguments pointer. This will be |
1141 // This will be passed as the const AccessorInfo& to the C++ callback. | 1152 // passed as the const ExecutableAccessorInfo& to the C++ callback. |
1142 | 1153 |
1143 #if defined(__MINGW64__) | 1154 #if defined(__MINGW64__) |
1144 Register accessor_info_arg = rdx; | 1155 Register accessor_info_arg = rdx; |
1145 Register name_arg = rcx; | 1156 Register name_arg = rcx; |
1146 #elif defined(_WIN64) | 1157 #elif defined(_WIN64) |
1147 // Win64 uses first register--rcx--for returned value. | 1158 // Win64 uses first register--rcx--for returned value. |
1148 Register accessor_info_arg = r8; | 1159 Register accessor_info_arg = r8; |
1149 Register name_arg = rdx; | 1160 Register name_arg = rdx; |
1150 #else | 1161 #else |
1151 Register accessor_info_arg = rsi; | 1162 Register accessor_info_arg = rsi; |
(...skipping 1599 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2751 | 2762 |
2752 NonexistentHandlerFrontend(object, last, name, &success, global); | 2763 NonexistentHandlerFrontend(object, last, name, &success, global); |
2753 | 2764 |
2754 __ bind(&success); | 2765 __ bind(&success); |
2755 // Return undefined if maps of the full prototype chain are still the | 2766 // Return undefined if maps of the full prototype chain are still the |
2756 // same and no global property with this name contains a value. | 2767 // same and no global property with this name contains a value. |
2757 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 2768 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
2758 __ ret(0); | 2769 __ ret(0); |
2759 | 2770 |
2760 // Return the generated code. | 2771 // Return the generated code. |
2761 return GetCode(Code::NONEXISTENT, factory()->empty_string()); | 2772 return GetCode(Code::HANDLER_FRAGMENT, Code::NONEXISTENT, name); |
2762 } | 2773 } |
2763 | 2774 |
2764 | 2775 |
2765 Register* LoadStubCompiler::registers() { | 2776 Register* LoadStubCompiler::registers() { |
2766 // receiver, name, scratch1, scratch2, scratch3, scratch4. | 2777 // receiver, name, scratch1, scratch2, scratch3, scratch4. |
2767 static Register registers[] = { rax, rcx, rdx, rbx, rdi, r8 }; | 2778 static Register registers[] = { rax, rcx, rdx, rbx, rdi, r8 }; |
2768 return registers; | 2779 return registers; |
2769 } | 2780 } |
2770 | 2781 |
2771 | 2782 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2825 Handle<JSObject> object, | 2836 Handle<JSObject> object, |
2826 Handle<GlobalObject> global, | 2837 Handle<GlobalObject> global, |
2827 Handle<JSGlobalPropertyCell> cell, | 2838 Handle<JSGlobalPropertyCell> cell, |
2828 Handle<String> name, | 2839 Handle<String> name, |
2829 bool is_dont_delete) { | 2840 bool is_dont_delete) { |
2830 Label success, miss; | 2841 Label success, miss; |
2831 // TODO(verwaest): Directly store to rax. Currently we cannot do this, since | 2842 // TODO(verwaest): Directly store to rax. Currently we cannot do this, since |
2832 // rax is used as receiver(), which we would otherwise clobber before a | 2843 // rax is used as receiver(), which we would otherwise clobber before a |
2833 // potential miss. | 2844 // potential miss. |
2834 | 2845 |
2835 HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global), | 2846 __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK); |
2836 name, &miss, PERFORM_INITIAL_CHECKS); | 2847 HandlerFrontendHeader( |
| 2848 object, receiver(), Handle<JSObject>::cast(global), name, &miss); |
2837 | 2849 |
2838 // Get the value from the cell. | 2850 // Get the value from the cell. |
2839 __ Move(rbx, cell); | 2851 __ Move(rbx, cell); |
2840 __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset)); | 2852 __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset)); |
2841 | 2853 |
2842 // Check for deleted property if property can actually be deleted. | 2854 // Check for deleted property if property can actually be deleted. |
2843 if (!is_dont_delete) { | 2855 if (!is_dont_delete) { |
2844 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); | 2856 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); |
2845 __ j(equal, &miss); | 2857 __ j(equal, &miss); |
2846 } else if (FLAG_debug_code) { | 2858 } else if (FLAG_debug_code) { |
2847 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); | 2859 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); |
2848 __ Check(not_equal, "DontDelete cells can't contain the hole"); | 2860 __ Check(not_equal, "DontDelete cells can't contain the hole"); |
2849 } | 2861 } |
2850 | 2862 |
2851 HandlerFrontendFooter(&success, &miss); | 2863 HandlerFrontendFooter(&success, &miss); |
2852 __ bind(&success); | 2864 __ bind(&success); |
2853 | 2865 |
2854 Counters* counters = isolate()->counters(); | 2866 Counters* counters = isolate()->counters(); |
2855 __ IncrementCounter(counters->named_load_global_stub(), 1); | 2867 __ IncrementCounter(counters->named_load_global_stub(), 1); |
2856 __ movq(rax, rbx); | 2868 __ movq(rax, rbx); |
2857 __ ret(0); | 2869 __ ret(0); |
2858 | 2870 |
2859 // Return the generated code. | 2871 // Return the generated code. |
2860 return GetCode(Code::NORMAL, name); | 2872 return GetCode(Code::IC_FRAGMENT, Code::NORMAL, name); |
2861 } | 2873 } |
2862 | 2874 |
2863 | 2875 |
2864 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement( | 2876 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement( |
2865 Handle<Map> receiver_map) { | 2877 Handle<Map> receiver_map) { |
2866 // ----------- S t a t e ------------- | 2878 // ----------- S t a t e ------------- |
2867 // -- rax : key | 2879 // -- rax : key |
2868 // -- rdx : receiver | 2880 // -- rdx : receiver |
2869 // -- rsp[0] : return address | 2881 // -- rsp[0] : return address |
2870 // ----------------------------------- | 2882 // ----------------------------------- |
2871 ElementsKind elements_kind = receiver_map->elements_kind(); | 2883 ElementsKind elements_kind = receiver_map->elements_kind(); |
2872 if (receiver_map->has_fast_elements() || | 2884 if (receiver_map->has_fast_elements() || |
2873 receiver_map->has_external_array_elements()) { | 2885 receiver_map->has_external_array_elements()) { |
2874 Handle<Code> stub = KeyedLoadFastElementStub( | 2886 Handle<Code> stub = KeyedLoadFastElementStub( |
2875 receiver_map->instance_type() == JS_ARRAY_TYPE, | 2887 receiver_map->instance_type() == JS_ARRAY_TYPE, |
2876 elements_kind).GetCode(isolate()); | 2888 elements_kind).GetCode(isolate()); |
2877 __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK); | 2889 __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK); |
2878 } else { | 2890 } else { |
2879 Handle<Code> stub = | 2891 Handle<Code> stub = |
2880 KeyedLoadDictionaryElementStub().GetCode(isolate()); | 2892 KeyedLoadDictionaryElementStub().GetCode(isolate()); |
2881 __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK); | 2893 __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK); |
2882 } | 2894 } |
2883 | 2895 |
2884 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 2896 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
2885 | 2897 |
2886 // Return the generated code. | 2898 // Return the generated code. |
2887 return GetCode(Code::NORMAL, factory()->empty_string()); | 2899 return GetCode(Code::IC_FRAGMENT, Code::NORMAL, factory()->empty_string()); |
2888 } | 2900 } |
2889 | 2901 |
2890 | 2902 |
2891 Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic( | 2903 Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC( |
2892 MapHandleList* receiver_maps, | 2904 MapHandleList* receiver_maps, |
2893 CodeHandleList* handler_ics) { | 2905 CodeHandleList* handlers, |
2894 // ----------- S t a t e ------------- | 2906 Handle<String> name, |
2895 // -- rax : key | 2907 Code::StubType type, |
2896 // -- rdx : receiver | 2908 IcCheckType check) { |
2897 // -- rsp[0] : return address | |
2898 // ----------------------------------- | |
2899 Label miss; | 2909 Label miss; |
2900 __ JumpIfSmi(rdx, &miss); | |
2901 | 2910 |
2902 Register map_reg = rbx; | 2911 if (check == PROPERTY) { |
2903 __ movq(map_reg, FieldOperand(rdx, HeapObject::kMapOffset)); | 2912 GenerateNameCheck(name, this->name(), &miss); |
| 2913 } |
| 2914 |
| 2915 __ JumpIfSmi(receiver(), &miss); |
| 2916 Register map_reg = scratch1(); |
| 2917 __ movq(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset)); |
2904 int receiver_count = receiver_maps->length(); | 2918 int receiver_count = receiver_maps->length(); |
2905 for (int current = 0; current < receiver_count; ++current) { | 2919 for (int current = 0; current < receiver_count; ++current) { |
2906 // Check map and tail call if there's a match | 2920 // Check map and tail call if there's a match |
2907 __ Cmp(map_reg, receiver_maps->at(current)); | 2921 __ Cmp(map_reg, receiver_maps->at(current)); |
2908 __ j(equal, handler_ics->at(current), RelocInfo::CODE_TARGET); | 2922 __ j(equal, handlers->at(current), RelocInfo::CODE_TARGET); |
2909 } | 2923 } |
2910 | 2924 |
2911 __ bind(&miss); | 2925 __ bind(&miss); |
2912 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 2926 GenerateLoadMiss(masm(), kind()); |
2913 | 2927 |
2914 // Return the generated code. | 2928 // Return the generated code. |
2915 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC); | 2929 InlineCacheState state = |
| 2930 receiver_maps->length() > 1 ? POLYMORPHIC : MONOMORPHIC; |
| 2931 return GetCode(Code::IC_FRAGMENT, type, name, state); |
2916 } | 2932 } |
2917 | 2933 |
2918 | 2934 |
2919 // Specialized stub for constructing objects from functions which only have only | 2935 // Specialized stub for constructing objects from functions which only have only |
2920 // simple assignments of the form this.x = ...; in their body. | 2936 // simple assignments of the form this.x = ...; in their body. |
2921 Handle<Code> ConstructStubCompiler::CompileConstructStub( | 2937 Handle<Code> ConstructStubCompiler::CompileConstructStub( |
2922 Handle<JSFunction> function) { | 2938 Handle<JSFunction> function) { |
2923 // ----------- S t a t e ------------- | 2939 // ----------- S t a t e ------------- |
2924 // -- rax : argc | 2940 // -- rax : argc |
2925 // -- rdi : constructor | 2941 // -- rdi : constructor |
(...skipping 662 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3588 __ jmp(ic_slow, RelocInfo::CODE_TARGET); | 3604 __ jmp(ic_slow, RelocInfo::CODE_TARGET); |
3589 } | 3605 } |
3590 } | 3606 } |
3591 | 3607 |
3592 | 3608 |
3593 #undef __ | 3609 #undef __ |
3594 | 3610 |
3595 } } // namespace v8::internal | 3611 } } // namespace v8::internal |
3596 | 3612 |
3597 #endif // V8_TARGET_ARCH_X64 | 3613 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |