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 |