| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/arguments.h" | 9 #include "src/arguments.h" |
| 10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
| (...skipping 615 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 626 Handle<Code> code) { | 626 Handle<Code> code) { |
| 627 __ jmp(code, RelocInfo::CODE_TARGET); | 627 __ jmp(code, RelocInfo::CODE_TARGET); |
| 628 } | 628 } |
| 629 | 629 |
| 630 | 630 |
| 631 #undef __ | 631 #undef __ |
| 632 #define __ ACCESS_MASM((masm())) | 632 #define __ ACCESS_MASM((masm())) |
| 633 | 633 |
| 634 | 634 |
| 635 Register PropertyHandlerCompiler::CheckPrototypes( | 635 Register PropertyHandlerCompiler::CheckPrototypes( |
| 636 Handle<HeapType> type, Register object_reg, Handle<JSObject> holder, | 636 Register object_reg, Handle<JSObject> holder, Register holder_reg, |
| 637 Register holder_reg, Register scratch1, Register scratch2, | 637 Register scratch1, Register scratch2, Handle<Name> name, Label* miss, |
| 638 Handle<Name> name, Label* miss, PrototypeCheckType check) { | 638 PrototypeCheckType check) { |
| 639 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate())); | 639 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); |
| 640 | 640 |
| 641 // Make sure there's no overlap between holder and object registers. | 641 // Make sure there's no overlap between holder and object registers. |
| 642 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 642 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
| 643 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) | 643 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) |
| 644 && !scratch2.is(scratch1)); | 644 && !scratch2.is(scratch1)); |
| 645 | 645 |
| 646 // Keep track of the current object in register reg. On the first | 646 // Keep track of the current object in register reg. On the first |
| 647 // iteration, reg is an alias for object_reg, on later iterations, | 647 // iteration, reg is an alias for object_reg, on later iterations, |
| 648 // it is an alias for holder_reg. | 648 // it is an alias for holder_reg. |
| 649 Register reg = object_reg; | 649 Register reg = object_reg; |
| 650 int depth = 0; | 650 int depth = 0; |
| 651 | 651 |
| 652 Handle<JSObject> current = Handle<JSObject>::null(); | 652 Handle<JSObject> current = Handle<JSObject>::null(); |
| 653 if (type->IsConstant()) { | 653 if (type()->IsConstant()) { |
| 654 current = Handle<JSObject>::cast(type->AsConstant()->Value()); | 654 current = Handle<JSObject>::cast(type()->AsConstant()->Value()); |
| 655 } | 655 } |
| 656 Handle<JSObject> prototype = Handle<JSObject>::null(); | 656 Handle<JSObject> prototype = Handle<JSObject>::null(); |
| 657 Handle<Map> current_map = receiver_map; | 657 Handle<Map> current_map = receiver_map; |
| 658 Handle<Map> holder_map(holder->map()); | 658 Handle<Map> holder_map(holder->map()); |
| 659 // Traverse the prototype chain and check the maps in the prototype chain for | 659 // Traverse the prototype chain and check the maps in the prototype chain for |
| 660 // fast and global objects or do negative lookup for normal objects. | 660 // fast and global objects or do negative lookup for normal objects. |
| 661 while (!current_map.is_identical_to(holder_map)) { | 661 while (!current_map.is_identical_to(holder_map)) { |
| 662 ++depth; | 662 ++depth; |
| 663 | 663 |
| 664 // Only global objects and objects that do not require access | 664 // Only global objects and objects that do not require access |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 758 if (!miss->is_unused()) { | 758 if (!miss->is_unused()) { |
| 759 Label success; | 759 Label success; |
| 760 __ jmp(&success); | 760 __ jmp(&success); |
| 761 GenerateRestoreName(masm(), miss, name); | 761 GenerateRestoreName(masm(), miss, name); |
| 762 TailCallBuiltin(masm(), MissBuiltin(kind())); | 762 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 763 __ bind(&success); | 763 __ bind(&success); |
| 764 } | 764 } |
| 765 } | 765 } |
| 766 | 766 |
| 767 | 767 |
| 768 Register NamedLoadHandlerCompiler::CallbackFrontend(Handle<HeapType> type, | 768 Register NamedLoadHandlerCompiler::CallbackFrontend(Register object_reg, |
| 769 Register object_reg, | |
| 770 Handle<JSObject> holder, | 769 Handle<JSObject> holder, |
| 771 Handle<Name> name, | 770 Handle<Name> name, |
| 772 Handle<Object> callback) { | 771 Handle<Object> callback) { |
| 773 Label miss; | 772 Label miss; |
| 774 | 773 |
| 775 Register reg = FrontendHeader(type, object_reg, holder, name, &miss); | 774 Register reg = FrontendHeader(object_reg, holder, name, &miss); |
| 776 | 775 |
| 777 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { | 776 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { |
| 778 ASSERT(!reg.is(scratch2())); | 777 ASSERT(!reg.is(scratch2())); |
| 779 ASSERT(!reg.is(scratch3())); | 778 ASSERT(!reg.is(scratch3())); |
| 780 ASSERT(!reg.is(scratch4())); | 779 ASSERT(!reg.is(scratch4())); |
| 781 | 780 |
| 782 // Load the properties dictionary. | 781 // Load the properties dictionary. |
| 783 Register dictionary = scratch4(); | 782 Register dictionary = scratch4(); |
| 784 __ movp(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset)); | 783 __ movp(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset)); |
| 785 | 784 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 868 | 867 |
| 869 | 868 |
| 870 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) { | 869 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) { |
| 871 // Return the constant value. | 870 // Return the constant value. |
| 872 __ Move(rax, value); | 871 __ Move(rax, value); |
| 873 __ ret(0); | 872 __ ret(0); |
| 874 } | 873 } |
| 875 | 874 |
| 876 | 875 |
| 877 void NamedLoadHandlerCompiler::GenerateLoadInterceptor( | 876 void NamedLoadHandlerCompiler::GenerateLoadInterceptor( |
| 878 Register holder_reg, Handle<Object> object, | 877 Register holder_reg, Handle<JSObject> interceptor_holder, |
| 879 Handle<JSObject> interceptor_holder, LookupResult* lookup, | 878 LookupResult* lookup, Handle<Name> name) { |
| 880 Handle<Name> name) { | |
| 881 ASSERT(interceptor_holder->HasNamedInterceptor()); | 879 ASSERT(interceptor_holder->HasNamedInterceptor()); |
| 882 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); | 880 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 883 | 881 |
| 884 // So far the most popular follow ups for interceptor loads are FIELD | 882 // So far the most popular follow ups for interceptor loads are FIELD |
| 885 // and CALLBACKS, so inline only them, other cases may be added | 883 // and CALLBACKS, so inline only them, other cases may be added |
| 886 // later. | 884 // later. |
| 887 bool compile_followup_inline = false; | 885 bool compile_followup_inline = false; |
| 888 if (lookup->IsFound() && lookup->IsCacheable()) { | 886 if (lookup->IsFound() && lookup->IsCacheable()) { |
| 889 if (lookup->IsField()) { | 887 if (lookup->IsField()) { |
| 890 compile_followup_inline = true; | 888 compile_followup_inline = true; |
| 891 } else if (lookup->type() == CALLBACKS && | 889 } else if (lookup->type() == CALLBACKS && |
| 892 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) { | 890 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) { |
| 893 ExecutableAccessorInfo* callback = | 891 Handle<ExecutableAccessorInfo> callback( |
| 894 ExecutableAccessorInfo::cast(lookup->GetCallbackObject()); | 892 ExecutableAccessorInfo::cast(lookup->GetCallbackObject())); |
| 895 compile_followup_inline = callback->getter() != NULL && | 893 compile_followup_inline = |
| 896 callback->IsCompatibleReceiver(*object); | 894 callback->getter() != NULL && |
| 895 ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback, |
| 896 type()); |
| 897 } | 897 } |
| 898 } | 898 } |
| 899 | 899 |
| 900 if (compile_followup_inline) { | 900 if (compile_followup_inline) { |
| 901 // Compile the interceptor call, followed by inline code to load the | 901 // Compile the interceptor call, followed by inline code to load the |
| 902 // property from further up the prototype chain if the call fails. | 902 // property from further up the prototype chain if the call fails. |
| 903 // Check that the maps haven't changed. | 903 // Check that the maps haven't changed. |
| 904 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1())); | 904 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1())); |
| 905 | 905 |
| 906 // Preserve the receiver register explicitly whenever it is different from | 906 // Preserve the receiver register explicitly whenever it is different from |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 960 IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); | 960 IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); |
| 961 __ TailCallExternalReference( | 961 __ TailCallExternalReference( |
| 962 ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1); | 962 ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1); |
| 963 } | 963 } |
| 964 } | 964 } |
| 965 | 965 |
| 966 | 966 |
| 967 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( | 967 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( |
| 968 Handle<JSObject> object, Handle<JSObject> holder, Handle<Name> name, | 968 Handle<JSObject> object, Handle<JSObject> holder, Handle<Name> name, |
| 969 Handle<ExecutableAccessorInfo> callback) { | 969 Handle<ExecutableAccessorInfo> callback) { |
| 970 Register holder_reg = | 970 Register holder_reg = Frontend(receiver(), holder, name); |
| 971 Frontend(IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); | |
| 972 | 971 |
| 973 __ PopReturnAddressTo(scratch1()); | 972 __ PopReturnAddressTo(scratch1()); |
| 974 __ Push(receiver()); | 973 __ Push(receiver()); |
| 975 __ Push(holder_reg); | 974 __ Push(holder_reg); |
| 976 __ Push(callback); // callback info | 975 __ Push(callback); // callback info |
| 977 __ Push(name); | 976 __ Push(name); |
| 978 __ Push(value()); | 977 __ Push(value()); |
| 979 __ PushReturnAddressFrom(scratch1()); | 978 __ PushReturnAddressFrom(scratch1()); |
| 980 | 979 |
| 981 // Do tail-call to the runtime system. | 980 // Do tail-call to the runtime system. |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1096 __ bind(&miss); | 1095 __ bind(&miss); |
| 1097 | 1096 |
| 1098 TailCallBuiltin(masm(), MissBuiltin(kind())); | 1097 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 1099 | 1098 |
| 1100 // Return the generated code. | 1099 // Return the generated code. |
| 1101 return GetCode(kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); | 1100 return GetCode(kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); |
| 1102 } | 1101 } |
| 1103 | 1102 |
| 1104 | 1103 |
| 1105 Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent( | 1104 Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent( |
| 1106 Handle<HeapType> type, Handle<JSObject> last, Handle<Name> name) { | 1105 Handle<JSObject> last, Handle<Name> name) { |
| 1107 NonexistentFrontend(type, last, name); | 1106 NonexistentFrontend(last, name); |
| 1108 | 1107 |
| 1109 // Return undefined if maps of the full prototype chain are still the | 1108 // Return undefined if maps of the full prototype chain are still the |
| 1110 // same and no global property with this name contains a value. | 1109 // same and no global property with this name contains a value. |
| 1111 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 1110 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
| 1112 __ ret(0); | 1111 __ ret(0); |
| 1113 | 1112 |
| 1114 // Return the generated code. | 1113 // Return the generated code. |
| 1115 return GetCode(kind(), Code::FAST, name); | 1114 return GetCode(kind(), Code::FAST, name); |
| 1116 } | 1115 } |
| 1117 | 1116 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1185 } | 1184 } |
| 1186 __ ret(0); | 1185 __ ret(0); |
| 1187 } | 1186 } |
| 1188 | 1187 |
| 1189 | 1188 |
| 1190 #undef __ | 1189 #undef __ |
| 1191 #define __ ACCESS_MASM(masm()) | 1190 #define __ ACCESS_MASM(masm()) |
| 1192 | 1191 |
| 1193 | 1192 |
| 1194 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( | 1193 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( |
| 1195 Handle<HeapType> type, Handle<GlobalObject> global, | 1194 Handle<GlobalObject> global, Handle<PropertyCell> cell, Handle<Name> name, |
| 1196 Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) { | 1195 bool is_dont_delete) { |
| 1197 Label miss; | 1196 Label miss; |
| 1198 // TODO(verwaest): Directly store to rax. Currently we cannot do this, since | 1197 FrontendHeader(receiver(), global, name, &miss); |
| 1199 // rax is used as receiver(), which we would otherwise clobber before a | |
| 1200 // potential miss. | |
| 1201 FrontendHeader(type, receiver(), global, name, &miss); | |
| 1202 | 1198 |
| 1203 // Get the value from the cell. | 1199 // Get the value from the cell. |
| 1204 __ Move(rbx, cell); | 1200 Register result = StoreIC::ValueRegister(); |
| 1205 __ movp(rbx, FieldOperand(rbx, PropertyCell::kValueOffset)); | 1201 __ Move(result, cell); |
| 1202 __ movp(result, FieldOperand(result, PropertyCell::kValueOffset)); |
| 1206 | 1203 |
| 1207 // Check for deleted property if property can actually be deleted. | 1204 // Check for deleted property if property can actually be deleted. |
| 1208 if (!is_dont_delete) { | 1205 if (!is_dont_delete) { |
| 1209 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); | 1206 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); |
| 1210 __ j(equal, &miss); | 1207 __ j(equal, &miss); |
| 1211 } else if (FLAG_debug_code) { | 1208 } else if (FLAG_debug_code) { |
| 1212 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); | 1209 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); |
| 1213 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); | 1210 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); |
| 1214 } | 1211 } |
| 1215 | 1212 |
| 1216 Counters* counters = isolate()->counters(); | 1213 Counters* counters = isolate()->counters(); |
| 1217 __ IncrementCounter(counters->named_load_global_stub(), 1); | 1214 __ IncrementCounter(counters->named_load_global_stub(), 1); |
| 1218 __ movp(rax, rbx); | |
| 1219 __ ret(0); | 1215 __ ret(0); |
| 1220 | 1216 |
| 1221 FrontendFooter(name, &miss); | 1217 FrontendFooter(name, &miss); |
| 1222 | 1218 |
| 1223 // Return the generated code. | 1219 // Return the generated code. |
| 1224 return GetCode(kind(), Code::NORMAL, name); | 1220 return GetCode(kind(), Code::NORMAL, name); |
| 1225 } | 1221 } |
| 1226 | 1222 |
| 1227 | 1223 |
| 1228 Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types, | 1224 Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types, |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1321 // ----------------------------------- | 1317 // ----------------------------------- |
| 1322 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 1318 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
| 1323 } | 1319 } |
| 1324 | 1320 |
| 1325 | 1321 |
| 1326 #undef __ | 1322 #undef __ |
| 1327 | 1323 |
| 1328 } } // namespace v8::internal | 1324 } } // namespace v8::internal |
| 1329 | 1325 |
| 1330 #endif // V8_TARGET_ARCH_X64 | 1326 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |