| 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 #include "src/ic/call-optimization.h" |
| 7 #include "src/ic/ic-inl.h" | 8 #include "src/ic/ic-inl.h" |
| 8 #include "src/ic/ic-compiler.h" | 9 #include "src/ic/ic-compiler.h" |
| 9 | 10 |
| 10 | 11 |
| 11 namespace v8 { | 12 namespace v8 { |
| 12 namespace internal { | 13 namespace internal { |
| 13 | 14 |
| 14 | 15 |
| 15 Handle<Code> PropertyICCompiler::Find(Handle<Name> name, | 16 Handle<Code> PropertyICCompiler::Find(Handle<Name> name, |
| 16 Handle<Map> stub_holder, Code::Kind kind, | 17 Handle<Map> stub_holder, Code::Kind kind, |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 Handle<Code> code = | 172 Handle<Code> code = |
| 172 compiler.CompileKeyedStoreMonomorphic(receiver_map, store_mode); | 173 compiler.CompileKeyedStoreMonomorphic(receiver_map, store_mode); |
| 173 | 174 |
| 174 Map::UpdateCodeCache(receiver_map, name, code); | 175 Map::UpdateCodeCache(receiver_map, name, code); |
| 175 DCHECK(KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state()) == | 176 DCHECK(KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state()) == |
| 176 store_mode); | 177 store_mode); |
| 177 return code; | 178 return code; |
| 178 } | 179 } |
| 179 | 180 |
| 180 | 181 |
| 181 #define CALL_LOGGER_TAG(kind, type) (Logger::KEYED_##type) | |
| 182 | |
| 183 | |
| 184 Code* PropertyICCompiler::FindPreMonomorphic(Isolate* isolate, Code::Kind kind, | 182 Code* PropertyICCompiler::FindPreMonomorphic(Isolate* isolate, Code::Kind kind, |
| 185 ExtraICState state) { | 183 ExtraICState state) { |
| 186 Code::Flags flags = Code::ComputeFlags(kind, PREMONOMORPHIC, state); | 184 Code::Flags flags = Code::ComputeFlags(kind, PREMONOMORPHIC, state); |
| 187 UnseededNumberDictionary* dictionary = | 185 UnseededNumberDictionary* dictionary = |
| 188 isolate->heap()->non_monomorphic_cache(); | 186 isolate->heap()->non_monomorphic_cache(); |
| 189 int entry = dictionary->FindEntry(isolate, flags); | 187 int entry = dictionary->FindEntry(isolate, flags); |
| 190 DCHECK(entry != -1); | 188 DCHECK(entry != -1); |
| 191 Object* code = dictionary->ValueAt(entry); | 189 Object* code = dictionary->ValueAt(entry); |
| 192 // This might be called during the marking phase of the collector | 190 // This might be called during the marking phase of the collector |
| 193 // hence the unchecked cast. | 191 // hence the unchecked cast. |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 | 393 |
| 396 | 394 |
| 397 Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) { | 395 Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) { |
| 398 StoreIC::GenerateMegamorphic(masm()); | 396 StoreIC::GenerateMegamorphic(masm()); |
| 399 Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic"); | 397 Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic"); |
| 400 PROFILE(isolate(), CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0)); | 398 PROFILE(isolate(), CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0)); |
| 401 return code; | 399 return code; |
| 402 } | 400 } |
| 403 | 401 |
| 404 | 402 |
| 405 #undef CALL_LOGGER_TAG | |
| 406 | |
| 407 | |
| 408 Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags, | |
| 409 const char* name) { | |
| 410 // Create code object in the heap. | |
| 411 CodeDesc desc; | |
| 412 masm()->GetCode(&desc); | |
| 413 Handle<Code> code = factory()->NewCode(desc, flags, masm()->CodeObject()); | |
| 414 if (code->IsCodeStubOrIC()) code->set_stub_key(CodeStub::NoCacheKey()); | |
| 415 #ifdef ENABLE_DISASSEMBLER | |
| 416 if (FLAG_print_code_stubs) { | |
| 417 OFStream os(stdout); | |
| 418 code->Disassemble(name, os); | |
| 419 } | |
| 420 #endif | |
| 421 return code; | |
| 422 } | |
| 423 | |
| 424 | |
| 425 Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags, | |
| 426 Handle<Name> name) { | |
| 427 return (FLAG_print_code_stubs && !name.is_null() && name->IsString()) | |
| 428 ? GetCodeWithFlags(flags, | |
| 429 Handle<String>::cast(name)->ToCString().get()) | |
| 430 : GetCodeWithFlags(flags, NULL); | |
| 431 } | |
| 432 | |
| 433 | |
| 434 #define __ ACCESS_MASM(masm()) | 403 #define __ ACCESS_MASM(masm()) |
| 435 | 404 |
| 436 | 405 |
| 437 Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg, | 406 Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg, |
| 438 Handle<Name> name, | 407 Handle<Name> name, |
| 439 Label* miss) { | 408 Label* miss) { |
| 440 PrototypeCheckType check_type = CHECK_ALL_MAPS; | 409 PrototypeCheckType check_type = CHECK_ALL_MAPS; |
| 441 int function_index = -1; | 410 int function_index = -1; |
| 442 if (type()->Is(HeapType::String())) { | 411 if (type()->Is(HeapType::String())) { |
| 443 function_index = Context::STRING_FUNCTION_INDEX; | 412 function_index = Context::STRING_FUNCTION_INDEX; |
| (...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 748 | 717 |
| 749 TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss); | 718 TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss); |
| 750 | 719 |
| 751 return GetCode(kind(), Code::NORMAL, factory()->empty_string()); | 720 return GetCode(kind(), Code::NORMAL, factory()->empty_string()); |
| 752 } | 721 } |
| 753 | 722 |
| 754 | 723 |
| 755 #undef __ | 724 #undef __ |
| 756 | 725 |
| 757 | 726 |
| 758 void PropertyAccessCompiler::TailCallBuiltin(MacroAssembler* masm, | |
| 759 Builtins::Name name) { | |
| 760 Handle<Code> code(masm->isolate()->builtins()->builtin(name)); | |
| 761 GenerateTailCall(masm, code); | |
| 762 } | |
| 763 | |
| 764 | |
| 765 Register* PropertyAccessCompiler::GetCallingConvention(Code::Kind kind) { | |
| 766 if (kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC) { | |
| 767 return load_calling_convention(); | |
| 768 } | |
| 769 DCHECK(kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC); | |
| 770 return store_calling_convention(); | |
| 771 } | |
| 772 | |
| 773 | |
| 774 Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type, | 727 Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type, |
| 775 Handle<Name> name, | 728 Handle<Name> name, |
| 776 InlineCacheState state) { | 729 InlineCacheState state) { |
| 777 Code::Flags flags = | 730 Code::Flags flags = |
| 778 Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder()); | 731 Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder()); |
| 779 Handle<Code> code = GetCodeWithFlags(flags, name); | 732 Handle<Code> code = GetCodeWithFlags(flags, name); |
| 780 IC::RegisterWeakMapDependency(code); | 733 IC::RegisterWeakMapDependency(code); |
| 781 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name)); | 734 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name)); |
| 782 return code; | 735 return code; |
| 783 } | 736 } |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 873 return code; | 826 return code; |
| 874 } | 827 } |
| 875 | 828 |
| 876 | 829 |
| 877 void ElementHandlerCompiler::GenerateStoreDictionaryElement( | 830 void ElementHandlerCompiler::GenerateStoreDictionaryElement( |
| 878 MacroAssembler* masm) { | 831 MacroAssembler* masm) { |
| 879 KeyedStoreIC::GenerateSlow(masm); | 832 KeyedStoreIC::GenerateSlow(masm); |
| 880 } | 833 } |
| 881 | 834 |
| 882 | 835 |
| 883 CallOptimization::CallOptimization(Handle<JSFunction> function) { | |
| 884 Initialize(function); | |
| 885 } | |
| 886 | |
| 887 | |
| 888 Handle<JSObject> CallOptimization::LookupHolderOfExpectedType( | |
| 889 Handle<Map> object_map, HolderLookup* holder_lookup) const { | |
| 890 DCHECK(is_simple_api_call()); | |
| 891 if (!object_map->IsJSObjectMap()) { | |
| 892 *holder_lookup = kHolderNotFound; | |
| 893 return Handle<JSObject>::null(); | |
| 894 } | |
| 895 if (expected_receiver_type_.is_null() || | |
| 896 expected_receiver_type_->IsTemplateFor(*object_map)) { | |
| 897 *holder_lookup = kHolderIsReceiver; | |
| 898 return Handle<JSObject>::null(); | |
| 899 } | |
| 900 while (true) { | |
| 901 if (!object_map->prototype()->IsJSObject()) break; | |
| 902 Handle<JSObject> prototype(JSObject::cast(object_map->prototype())); | |
| 903 if (!prototype->map()->is_hidden_prototype()) break; | |
| 904 object_map = handle(prototype->map()); | |
| 905 if (expected_receiver_type_->IsTemplateFor(*object_map)) { | |
| 906 *holder_lookup = kHolderFound; | |
| 907 return prototype; | |
| 908 } | |
| 909 } | |
| 910 *holder_lookup = kHolderNotFound; | |
| 911 return Handle<JSObject>::null(); | |
| 912 } | |
| 913 | |
| 914 | |
| 915 bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver, | |
| 916 Handle<JSObject> holder) const { | |
| 917 DCHECK(is_simple_api_call()); | |
| 918 if (!receiver->IsJSObject()) return false; | |
| 919 Handle<Map> map(JSObject::cast(*receiver)->map()); | |
| 920 HolderLookup holder_lookup; | |
| 921 Handle<JSObject> api_holder = LookupHolderOfExpectedType(map, &holder_lookup); | |
| 922 switch (holder_lookup) { | |
| 923 case kHolderNotFound: | |
| 924 return false; | |
| 925 case kHolderIsReceiver: | |
| 926 return true; | |
| 927 case kHolderFound: | |
| 928 if (api_holder.is_identical_to(holder)) return true; | |
| 929 // Check if holder is in prototype chain of api_holder. | |
| 930 { | |
| 931 JSObject* object = *api_holder; | |
| 932 while (true) { | |
| 933 Object* prototype = object->map()->prototype(); | |
| 934 if (!prototype->IsJSObject()) return false; | |
| 935 if (prototype == *holder) return true; | |
| 936 object = JSObject::cast(prototype); | |
| 937 } | |
| 938 } | |
| 939 break; | |
| 940 } | |
| 941 UNREACHABLE(); | |
| 942 return false; | |
| 943 } | |
| 944 | |
| 945 | |
| 946 void CallOptimization::Initialize(Handle<JSFunction> function) { | |
| 947 constant_function_ = Handle<JSFunction>::null(); | |
| 948 is_simple_api_call_ = false; | |
| 949 expected_receiver_type_ = Handle<FunctionTemplateInfo>::null(); | |
| 950 api_call_info_ = Handle<CallHandlerInfo>::null(); | |
| 951 | |
| 952 if (function.is_null() || !function->is_compiled()) return; | |
| 953 | |
| 954 constant_function_ = function; | |
| 955 AnalyzePossibleApiFunction(function); | |
| 956 } | |
| 957 | |
| 958 | |
| 959 void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) { | |
| 960 if (!function->shared()->IsApiFunction()) return; | |
| 961 Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data()); | |
| 962 | |
| 963 // Require a C++ callback. | |
| 964 if (info->call_code()->IsUndefined()) return; | |
| 965 api_call_info_ = | |
| 966 Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code())); | |
| 967 | |
| 968 // Accept signatures that either have no restrictions at all or | |
| 969 // only have restrictions on the receiver. | |
| 970 if (!info->signature()->IsUndefined()) { | |
| 971 Handle<SignatureInfo> signature = | |
| 972 Handle<SignatureInfo>(SignatureInfo::cast(info->signature())); | |
| 973 if (!signature->args()->IsUndefined()) return; | |
| 974 if (!signature->receiver()->IsUndefined()) { | |
| 975 expected_receiver_type_ = Handle<FunctionTemplateInfo>( | |
| 976 FunctionTemplateInfo::cast(signature->receiver())); | |
| 977 } | |
| 978 } | |
| 979 | |
| 980 is_simple_api_call_ = true; | |
| 981 } | |
| 982 } | 836 } |
| 983 } // namespace v8::internal | 837 } // namespace v8::internal |
| OLD | NEW |