| 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 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 if (raw_frame->is_internal()) { | 82 if (raw_frame->is_internal()) { |
| 83 Code* apply_builtin = isolate()->builtins()->builtin( | 83 Code* apply_builtin = isolate()->builtins()->builtin( |
| 84 Builtins::kFunctionApply); | 84 Builtins::kFunctionApply); |
| 85 if (raw_frame->unchecked_code() == apply_builtin) { | 85 if (raw_frame->unchecked_code() == apply_builtin) { |
| 86 PrintF("apply from "); | 86 PrintF("apply from "); |
| 87 it.Advance(); | 87 it.Advance(); |
| 88 raw_frame = it.frame(); | 88 raw_frame = it.frame(); |
| 89 } | 89 } |
| 90 } | 90 } |
| 91 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); | 91 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); |
| 92 Code::ExtraICState extra_state = new_target->extra_ic_state(); | 92 ExtraICState extra_state = new_target->extra_ic_state(); |
| 93 const char* modifier = | 93 const char* modifier = |
| 94 GetTransitionMarkModifier(Code::GetKeyedAccessStoreMode(extra_state)); | 94 GetTransitionMarkModifier( |
| 95 KeyedStoreIC::GetKeyedAccessStoreMode(extra_state)); |
| 95 PrintF(" (%c->%c%s)", | 96 PrintF(" (%c->%c%s)", |
| 96 TransitionMarkFromState(state()), | 97 TransitionMarkFromState(state()), |
| 97 TransitionMarkFromState(new_state), | 98 TransitionMarkFromState(new_state), |
| 98 modifier); | 99 modifier); |
| 99 name->Print(); | 100 name->Print(); |
| 100 PrintF("]\n"); | 101 PrintF("]\n"); |
| 101 } | 102 } |
| 102 } | 103 } |
| 103 | 104 |
| 104 #define TRACE_GENERIC_IC(isolate, type, reason) \ | 105 #define TRACE_GENERIC_IC(isolate, type, reason) \ |
| (...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 bool was_uninitialized = | 433 bool was_uninitialized = |
| 433 old_state == UNINITIALIZED || old_state == PREMONOMORPHIC; | 434 old_state == UNINITIALIZED || old_state == PREMONOMORPHIC; |
| 434 bool is_uninitialized = | 435 bool is_uninitialized = |
| 435 new_state == UNINITIALIZED || new_state == PREMONOMORPHIC; | 436 new_state == UNINITIALIZED || new_state == PREMONOMORPHIC; |
| 436 return (was_uninitialized && !is_uninitialized) ? 1 : | 437 return (was_uninitialized && !is_uninitialized) ? 1 : |
| 437 (!was_uninitialized && is_uninitialized) ? -1 : 0; | 438 (!was_uninitialized && is_uninitialized) ? -1 : 0; |
| 438 } | 439 } |
| 439 | 440 |
| 440 | 441 |
| 441 void IC::PostPatching(Address address, Code* target, Code* old_target) { | 442 void IC::PostPatching(Address address, Code* target, Code* old_target) { |
| 442 if (FLAG_type_info_threshold == 0 && !FLAG_watch_ic_patching) { | |
| 443 return; | |
| 444 } | |
| 445 Isolate* isolate = target->GetHeap()->isolate(); | 443 Isolate* isolate = target->GetHeap()->isolate(); |
| 446 Code* host = isolate-> | 444 Code* host = isolate-> |
| 447 inner_pointer_to_code_cache()->GetCacheEntry(address)->code; | 445 inner_pointer_to_code_cache()->GetCacheEntry(address)->code; |
| 448 if (host->kind() != Code::FUNCTION) return; | 446 if (host->kind() != Code::FUNCTION) return; |
| 449 | 447 |
| 450 if (FLAG_type_info_threshold > 0 && | 448 if (FLAG_type_info_threshold > 0 && |
| 451 old_target->is_inline_cache_stub() && | 449 old_target->is_inline_cache_stub() && |
| 452 target->is_inline_cache_stub()) { | 450 target->is_inline_cache_stub()) { |
| 453 int delta = ComputeTypeInfoCountDelta(old_target->ic_state(), | 451 int delta = ComputeTypeInfoCountDelta(old_target->ic_state(), |
| 454 target->ic_state()); | 452 target->ic_state()); |
| 455 // Not all Code objects have TypeFeedbackInfo. | 453 // Not all Code objects have TypeFeedbackInfo. |
| 456 if (host->type_feedback_info()->IsTypeFeedbackInfo() && delta != 0) { | 454 if (host->type_feedback_info()->IsTypeFeedbackInfo() && delta != 0) { |
| 457 TypeFeedbackInfo* info = | 455 TypeFeedbackInfo* info = |
| 458 TypeFeedbackInfo::cast(host->type_feedback_info()); | 456 TypeFeedbackInfo::cast(host->type_feedback_info()); |
| 459 info->change_ic_with_type_info_count(delta); | 457 info->change_ic_with_type_info_count(delta); |
| 460 } | 458 } |
| 461 } | 459 } |
| 462 if (host->type_feedback_info()->IsTypeFeedbackInfo()) { | 460 if (host->type_feedback_info()->IsTypeFeedbackInfo()) { |
| 463 TypeFeedbackInfo* info = | 461 TypeFeedbackInfo* info = |
| 464 TypeFeedbackInfo::cast(host->type_feedback_info()); | 462 TypeFeedbackInfo::cast(host->type_feedback_info()); |
| 465 info->change_own_type_change_checksum(); | 463 info->change_own_type_change_checksum(); |
| 466 } | 464 } |
| 467 if (FLAG_watch_ic_patching) { | 465 host->set_profiler_ticks(0); |
| 468 host->set_profiler_ticks(0); | 466 isolate->runtime_profiler()->NotifyICChanged(); |
| 469 isolate->runtime_profiler()->NotifyICChanged(); | |
| 470 } | |
| 471 // TODO(2029): When an optimized function is patched, it would | 467 // TODO(2029): When an optimized function is patched, it would |
| 472 // be nice to propagate the corresponding type information to its | 468 // be nice to propagate the corresponding type information to its |
| 473 // unoptimized version for the benefit of later inlining. | 469 // unoptimized version for the benefit of later inlining. |
| 474 } | 470 } |
| 475 | 471 |
| 476 | 472 |
| 477 void IC::Clear(Isolate* isolate, Address address) { | 473 void IC::Clear(Isolate* isolate, Address address) { |
| 478 Code* target = GetTargetAtAddress(address); | 474 Code* target = GetTargetAtAddress(address); |
| 479 | 475 |
| 480 // Don't clear debug break inline cache as it will remove the break point. | 476 // Don't clear debug break inline cache as it will remove the break point. |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 void LoadIC::Clear(Isolate* isolate, Address address, Code* target) { | 521 void LoadIC::Clear(Isolate* isolate, Address address, Code* target) { |
| 526 if (IsCleared(target)) return; | 522 if (IsCleared(target)) return; |
| 527 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate)); | 523 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate)); |
| 528 } | 524 } |
| 529 | 525 |
| 530 | 526 |
| 531 void StoreIC::Clear(Isolate* isolate, Address address, Code* target) { | 527 void StoreIC::Clear(Isolate* isolate, Address address, Code* target) { |
| 532 if (IsCleared(target)) return; | 528 if (IsCleared(target)) return; |
| 533 SetTargetAtAddress(address, | 529 SetTargetAtAddress(address, |
| 534 *pre_monomorphic_stub( | 530 *pre_monomorphic_stub( |
| 535 isolate, Code::GetStrictMode(target->extra_ic_state()))); | 531 isolate, StoreIC::GetStrictMode(target->extra_ic_state()))); |
| 536 } | 532 } |
| 537 | 533 |
| 538 | 534 |
| 539 void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target) { | 535 void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target) { |
| 540 if (IsCleared(target)) return; | 536 if (IsCleared(target)) return; |
| 541 SetTargetAtAddress(address, | 537 SetTargetAtAddress(address, |
| 542 *pre_monomorphic_stub( | 538 *pre_monomorphic_stub( |
| 543 isolate, Code::GetStrictMode(target->extra_ic_state()))); | 539 isolate, StoreIC::GetStrictMode(target->extra_ic_state()))); |
| 544 } | 540 } |
| 545 | 541 |
| 546 | 542 |
| 547 void CompareIC::Clear(Isolate* isolate, Address address, Code* target) { | 543 void CompareIC::Clear(Isolate* isolate, Address address, Code* target) { |
| 548 ASSERT(target->major_key() == CodeStub::CompareIC); | 544 ASSERT(target->major_key() == CodeStub::CompareIC); |
| 549 CompareIC::State handler_state; | 545 CompareIC::State handler_state; |
| 550 Token::Value op; | 546 Token::Value op; |
| 551 ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL, | 547 ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL, |
| 552 &handler_state, &op); | 548 &handler_state, &op); |
| 553 // Only clear CompareICs that can retain objects. | 549 // Only clear CompareICs that can retain objects. |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 776 // If there's no appropriate stub we simply avoid updating the caches. | 772 // If there's no appropriate stub we simply avoid updating the caches. |
| 777 // TODO(verwaest): Install a slow fallback in this case to avoid not learning, | 773 // TODO(verwaest): Install a slow fallback in this case to avoid not learning, |
| 778 // and deopting Crankshaft code. | 774 // and deopting Crankshaft code. |
| 779 if (code.is_null()) return; | 775 if (code.is_null()) return; |
| 780 | 776 |
| 781 Handle<JSObject> cache_object = object->IsJSObject() | 777 Handle<JSObject> cache_object = object->IsJSObject() |
| 782 ? Handle<JSObject>::cast(object) | 778 ? Handle<JSObject>::cast(object) |
| 783 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())), | 779 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())), |
| 784 isolate()); | 780 isolate()); |
| 785 | 781 |
| 786 PatchCache(handle(Type::OfCurrently(cache_object), isolate()), name, code); | 782 PatchCache(CurrentTypeOf(cache_object, isolate()), name, code); |
| 787 TRACE_IC("CallIC", name); | 783 TRACE_IC("CallIC", name); |
| 788 } | 784 } |
| 789 | 785 |
| 790 | 786 |
| 791 MaybeObject* KeyedCallIC::LoadFunction(Handle<Object> object, | 787 MaybeObject* KeyedCallIC::LoadFunction(Handle<Object> object, |
| 792 Handle<Object> key) { | 788 Handle<Object> key) { |
| 793 if (key->IsInternalizedString()) { | 789 if (key->IsInternalizedString()) { |
| 794 return CallICBase::LoadFunction(object, Handle<String>::cast(key)); | 790 return CallICBase::LoadFunction(object, Handle<String>::cast(key)); |
| 795 } | 791 } |
| 796 | 792 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 815 ElementsKind kind = array->map()->elements_kind(); | 811 ElementsKind kind = array->map()->elements_kind(); |
| 816 if (IsFastObjectElementsKind(kind) && | 812 if (IsFastObjectElementsKind(kind) && |
| 817 array->map() == isolate()->get_initial_js_array_map(kind)) { | 813 array->map() == isolate()->get_initial_js_array_map(kind)) { |
| 818 KeyedArrayCallStub stub_gen(IsHoleyElementsKind(kind), argc); | 814 KeyedArrayCallStub stub_gen(IsHoleyElementsKind(kind), argc); |
| 819 stub = stub_gen.GetCode(isolate()); | 815 stub = stub_gen.GetCode(isolate()); |
| 820 } | 816 } |
| 821 } | 817 } |
| 822 | 818 |
| 823 if (stub.is_null()) { | 819 if (stub.is_null()) { |
| 824 stub = isolate()->stub_cache()->ComputeCallMegamorphic( | 820 stub = isolate()->stub_cache()->ComputeCallMegamorphic( |
| 825 argc, Code::KEYED_CALL_IC, Code::kNoExtraICState); | 821 argc, Code::KEYED_CALL_IC, kNoExtraICState); |
| 826 if (object->IsJSObject()) { | 822 if (object->IsJSObject()) { |
| 827 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 823 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 828 if (receiver->elements()->map() == | 824 if (receiver->elements()->map() == |
| 829 isolate()->heap()->non_strict_arguments_elements_map()) { | 825 isolate()->heap()->non_strict_arguments_elements_map()) { |
| 830 stub = isolate()->stub_cache()->ComputeCallArguments(argc); | 826 stub = isolate()->stub_cache()->ComputeCallArguments(argc); |
| 831 } | 827 } |
| 832 } | 828 } |
| 833 ASSERT(!stub.is_null()); | 829 ASSERT(!stub.is_null()); |
| 834 } | 830 } |
| 835 set_target(*stub); | 831 set_target(*stub); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 872 stub = pre_monomorphic_stub(); | 868 stub = pre_monomorphic_stub(); |
| 873 } else if (state() == PREMONOMORPHIC || state() == MONOMORPHIC) { | 869 } else if (state() == PREMONOMORPHIC || state() == MONOMORPHIC) { |
| 874 StringLengthStub string_length_stub(kind()); | 870 StringLengthStub string_length_stub(kind()); |
| 875 stub = string_length_stub.GetCode(isolate()); | 871 stub = string_length_stub.GetCode(isolate()); |
| 876 } else if (state() != MEGAMORPHIC) { | 872 } else if (state() != MEGAMORPHIC) { |
| 877 ASSERT(state() != GENERIC); | 873 ASSERT(state() != GENERIC); |
| 878 stub = megamorphic_stub(); | 874 stub = megamorphic_stub(); |
| 879 } | 875 } |
| 880 if (!stub.is_null()) { | 876 if (!stub.is_null()) { |
| 881 set_target(*stub); | 877 set_target(*stub); |
| 882 #ifdef DEBUG | |
| 883 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /stringwrapper]\n"); | 878 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /stringwrapper]\n"); |
| 884 #endif | |
| 885 } | 879 } |
| 886 // Get the string if we have a string wrapper object. | 880 // Get the string if we have a string wrapper object. |
| 887 String* string = String::cast(JSValue::cast(*object)->value()); | 881 String* string = String::cast(JSValue::cast(*object)->value()); |
| 888 return Smi::FromInt(string->length()); | 882 return Smi::FromInt(string->length()); |
| 889 } | 883 } |
| 890 | 884 |
| 891 // Use specialized code for getting prototype of functions. | 885 // Use specialized code for getting prototype of functions. |
| 892 if (object->IsJSFunction() && | 886 if (object->IsJSFunction() && |
| 893 name->Equals(isolate()->heap()->prototype_string()) && | 887 name->Equals(isolate()->heap()->prototype_string()) && |
| 894 Handle<JSFunction>::cast(object)->should_have_prototype()) { | 888 Handle<JSFunction>::cast(object)->should_have_prototype()) { |
| 895 Handle<Code> stub; | 889 Handle<Code> stub; |
| 896 if (state() == UNINITIALIZED) { | 890 if (state() == UNINITIALIZED) { |
| 897 stub = pre_monomorphic_stub(); | 891 stub = pre_monomorphic_stub(); |
| 898 } else if (state() == PREMONOMORPHIC) { | 892 } else if (state() == PREMONOMORPHIC) { |
| 899 FunctionPrototypeStub function_prototype_stub(kind()); | 893 FunctionPrototypeStub function_prototype_stub(kind()); |
| 900 stub = function_prototype_stub.GetCode(isolate()); | 894 stub = function_prototype_stub.GetCode(isolate()); |
| 901 } else if (state() != MEGAMORPHIC) { | 895 } else if (state() != MEGAMORPHIC) { |
| 902 ASSERT(state() != GENERIC); | 896 ASSERT(state() != GENERIC); |
| 903 stub = megamorphic_stub(); | 897 stub = megamorphic_stub(); |
| 904 } | 898 } |
| 905 if (!stub.is_null()) { | 899 if (!stub.is_null()) { |
| 906 set_target(*stub); | 900 set_target(*stub); |
| 907 #ifdef DEBUG | |
| 908 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); | 901 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); |
| 909 #endif | |
| 910 } | 902 } |
| 911 return *Accessors::FunctionGetPrototype(Handle<JSFunction>::cast(object)); | 903 return *Accessors::FunctionGetPrototype(Handle<JSFunction>::cast(object)); |
| 912 } | 904 } |
| 913 } | 905 } |
| 914 | 906 |
| 915 // Check if the name is trivially convertible to an index and get | 907 // Check if the name is trivially convertible to an index and get |
| 916 // the element or char if so. | 908 // the element or char if so. |
| 917 uint32_t index; | 909 uint32_t index; |
| 918 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) { | 910 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) { |
| 919 // Rewrite to the generic keyed load stub. | 911 // Rewrite to the generic keyed load stub. |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 982 number_of_valid_types = number_of_types; | 974 number_of_valid_types = number_of_types; |
| 983 | 975 |
| 984 for (int i = 0; i < number_of_types; i++) { | 976 for (int i = 0; i < number_of_types; i++) { |
| 985 Handle<Type> current_type = types.at(i); | 977 Handle<Type> current_type = types.at(i); |
| 986 // Filter out deprecated maps to ensure their instances get migrated. | 978 // Filter out deprecated maps to ensure their instances get migrated. |
| 987 if (current_type->IsClass() && current_type->AsClass()->is_deprecated()) { | 979 if (current_type->IsClass() && current_type->AsClass()->is_deprecated()) { |
| 988 number_of_valid_types--; | 980 number_of_valid_types--; |
| 989 // If the receiver type is already in the polymorphic IC, this indicates | 981 // If the receiver type is already in the polymorphic IC, this indicates |
| 990 // there was a prototoype chain failure. In that case, just overwrite the | 982 // there was a prototoype chain failure. In that case, just overwrite the |
| 991 // handler. | 983 // handler. |
| 992 } else if (type->Is(current_type)) { | 984 } else if (type->IsCurrently(current_type)) { |
| 993 ASSERT(handler_to_overwrite == -1); | 985 ASSERT(handler_to_overwrite == -1); |
| 994 number_of_valid_types--; | 986 number_of_valid_types--; |
| 995 handler_to_overwrite = i; | 987 handler_to_overwrite = i; |
| 996 } | 988 } |
| 997 } | 989 } |
| 998 | 990 |
| 999 if (number_of_valid_types >= 4) return false; | 991 if (number_of_valid_types >= 4) return false; |
| 1000 if (number_of_types == 0) return false; | 992 if (number_of_types == 0) return false; |
| 1001 if (!target()->FindHandlers(&handlers, types.length())) return false; | 993 if (!target()->FindHandlers(&handlers, types.length())) return false; |
| 1002 | 994 |
| 1003 number_of_valid_types++; | 995 number_of_valid_types++; |
| 1004 if (handler_to_overwrite >= 0) { | 996 if (handler_to_overwrite >= 0) { |
| 1005 handlers.Set(handler_to_overwrite, code); | 997 handlers.Set(handler_to_overwrite, code); |
| 1006 } else { | 998 } else { |
| 1007 types.Add(type); | 999 types.Add(type); |
| 1008 handlers.Add(code); | 1000 handlers.Add(code); |
| 1009 } | 1001 } |
| 1010 | 1002 |
| 1011 Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC( | 1003 Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC( |
| 1012 &types, &handlers, number_of_valid_types, name, strict_mode()); | 1004 &types, &handlers, number_of_valid_types, name, extra_ic_state()); |
| 1013 set_target(*ic); | 1005 set_target(*ic); |
| 1014 return true; | 1006 return true; |
| 1015 } | 1007 } |
| 1016 | 1008 |
| 1017 | 1009 |
| 1010 Handle<Type> IC::CurrentTypeOf(Handle<Object> object, Isolate* isolate) { |
| 1011 Type* type = object->IsJSGlobalObject() |
| 1012 ? Type::Constant(Handle<JSGlobalObject>::cast(object)) |
| 1013 : Type::OfCurrently(object); |
| 1014 return handle(type, isolate); |
| 1015 } |
| 1016 |
| 1017 |
| 1018 Handle<Map> IC::TypeToMap(Type* type, Isolate* isolate) { | 1018 Handle<Map> IC::TypeToMap(Type* type, Isolate* isolate) { |
| 1019 if (type->Is(Type::Number())) return isolate->factory()->heap_number_map(); | 1019 if (type->Is(Type::Number())) return isolate->factory()->heap_number_map(); |
| 1020 if (type->Is(Type::Boolean())) return isolate->factory()->oddball_map(); | 1020 if (type->Is(Type::Boolean())) return isolate->factory()->oddball_map(); |
| 1021 if (type->IsConstant()) { |
| 1022 return handle(Handle<JSGlobalObject>::cast(type->AsConstant())->map()); |
| 1023 } |
| 1021 ASSERT(type->IsClass()); | 1024 ASSERT(type->IsClass()); |
| 1022 return type->AsClass(); | 1025 return type->AsClass(); |
| 1023 } | 1026 } |
| 1024 | 1027 |
| 1025 | 1028 |
| 1026 Type* IC::MapToType(Handle<Map> map) { | 1029 Type* IC::MapToType(Handle<Map> map) { |
| 1027 if (map->instance_type() == HEAP_NUMBER_TYPE) return Type::Number(); | 1030 if (map->instance_type() == HEAP_NUMBER_TYPE) return Type::Number(); |
| 1028 // The only oddballs that can be recorded in ICs are booleans. | 1031 // The only oddballs that can be recorded in ICs are booleans. |
| 1029 if (map->instance_type() == ODDBALL_TYPE) return Type::Boolean(); | 1032 if (map->instance_type() == ODDBALL_TYPE) return Type::Boolean(); |
| 1030 return Type::Class(map); | 1033 return Type::Class(map); |
| 1031 } | 1034 } |
| 1032 | 1035 |
| 1033 | 1036 |
| 1034 void IC::UpdateMonomorphicIC(Handle<Type> type, | 1037 void IC::UpdateMonomorphicIC(Handle<Type> type, |
| 1035 Handle<Code> handler, | 1038 Handle<Code> handler, |
| 1036 Handle<String> name) { | 1039 Handle<String> name) { |
| 1037 if (!handler->is_handler()) return set_target(*handler); | 1040 if (!handler->is_handler()) return set_target(*handler); |
| 1038 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC( | 1041 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC( |
| 1039 name, type, handler, strict_mode()); | 1042 name, type, handler, extra_ic_state()); |
| 1040 set_target(*ic); | 1043 set_target(*ic); |
| 1041 } | 1044 } |
| 1042 | 1045 |
| 1043 | 1046 |
| 1044 void IC::CopyICToMegamorphicCache(Handle<String> name) { | 1047 void IC::CopyICToMegamorphicCache(Handle<String> name) { |
| 1045 TypeHandleList types; | 1048 TypeHandleList types; |
| 1046 CodeHandleList handlers; | 1049 CodeHandleList handlers; |
| 1047 target()->FindAllTypes(&types); | 1050 target()->FindAllTypes(&types); |
| 1048 if (!target()->FindHandlers(&handlers, types.length())) return; | 1051 if (!target()->FindHandlers(&handlers, types.length())) return; |
| 1049 for (int i = 0; i < types.length(); i++) { | 1052 for (int i = 0; i < types.length(); i++) { |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1127 Handle<String> name) { | 1130 Handle<String> name) { |
| 1128 if (state() == UNINITIALIZED) { | 1131 if (state() == UNINITIALIZED) { |
| 1129 // This is the first time we execute this inline cache. | 1132 // This is the first time we execute this inline cache. |
| 1130 // Set the target to the pre monomorphic stub to delay | 1133 // Set the target to the pre monomorphic stub to delay |
| 1131 // setting the monomorphic state. | 1134 // setting the monomorphic state. |
| 1132 set_target(*pre_monomorphic_stub()); | 1135 set_target(*pre_monomorphic_stub()); |
| 1133 TRACE_IC("LoadIC", name); | 1136 TRACE_IC("LoadIC", name); |
| 1134 return; | 1137 return; |
| 1135 } | 1138 } |
| 1136 | 1139 |
| 1140 Handle<Type> type = CurrentTypeOf(object, isolate()); |
| 1137 Handle<Code> code; | 1141 Handle<Code> code; |
| 1138 if (!lookup->IsCacheable()) { | 1142 if (!lookup->IsCacheable()) { |
| 1139 // Bail out if the result is not cacheable. | 1143 // Bail out if the result is not cacheable. |
| 1140 code = slow_stub(); | 1144 code = slow_stub(); |
| 1141 } else if (!lookup->IsProperty()) { | 1145 } else if (!lookup->IsProperty()) { |
| 1142 if (kind() == Code::LOAD_IC) { | 1146 if (kind() == Code::LOAD_IC) { |
| 1143 code = isolate()->stub_cache()->ComputeLoadNonexistent(name, object); | 1147 code = isolate()->stub_cache()->ComputeLoadNonexistent(name, type); |
| 1144 } else { | 1148 } else { |
| 1145 code = slow_stub(); | 1149 code = slow_stub(); |
| 1146 } | 1150 } |
| 1147 } else { | 1151 } else { |
| 1148 code = ComputeHandler(lookup, object, name); | 1152 code = ComputeHandler(lookup, object, name); |
| 1149 } | 1153 } |
| 1150 | 1154 |
| 1151 PatchCache(handle(Type::OfCurrently(object), isolate()), name, code); | 1155 PatchCache(type, name, code); |
| 1152 TRACE_IC("LoadIC", name); | 1156 TRACE_IC("LoadIC", name); |
| 1153 } | 1157 } |
| 1154 | 1158 |
| 1155 | 1159 |
| 1156 void IC::UpdateMegamorphicCache(Type* type, Name* name, Code* code) { | 1160 void IC::UpdateMegamorphicCache(Type* type, Name* name, Code* code) { |
| 1157 // Cache code holding map should be consistent with | 1161 // Cache code holding map should be consistent with |
| 1158 // GenerateMonomorphicCacheProbe. | 1162 // GenerateMonomorphicCacheProbe. |
| 1159 Map* map = *TypeToMap(type, isolate()); | 1163 Map* map = *TypeToMap(type, isolate()); |
| 1160 isolate()->stub_cache()->Set(name, map, code); | 1164 isolate()->stub_cache()->Set(name, map, code); |
| 1161 } | 1165 } |
| 1162 | 1166 |
| 1163 | 1167 |
| 1164 Handle<Code> IC::ComputeHandler(LookupResult* lookup, | 1168 Handle<Code> IC::ComputeHandler(LookupResult* lookup, |
| 1165 Handle<Object> object, | 1169 Handle<Object> object, |
| 1166 Handle<String> name, | 1170 Handle<String> name, |
| 1167 Handle<Object> value) { | 1171 Handle<Object> value) { |
| 1168 InlineCacheHolderFlag cache_holder = GetCodeCacheForObject(*object); | 1172 InlineCacheHolderFlag cache_holder = GetCodeCacheForObject(*object); |
| 1169 Handle<HeapObject> stub_holder(GetCodeCacheHolder( | 1173 Handle<HeapObject> stub_holder(GetCodeCacheHolder( |
| 1170 isolate(), *object, cache_holder)); | 1174 isolate(), *object, cache_holder)); |
| 1171 | 1175 |
| 1172 Handle<Code> code = isolate()->stub_cache()->FindHandler( | 1176 Handle<Code> code = isolate()->stub_cache()->FindHandler( |
| 1173 name, stub_holder, kind(), cache_holder, strict_mode()); | 1177 name, handle(stub_holder->map()), kind(), cache_holder); |
| 1174 if (!code.is_null()) return code; | 1178 if (!code.is_null()) return code; |
| 1175 | 1179 |
| 1176 code = CompileHandler(lookup, object, name, value, cache_holder); | 1180 code = CompileHandler(lookup, object, name, value, cache_holder); |
| 1177 ASSERT(code->is_handler()); | 1181 ASSERT(code->is_handler()); |
| 1178 | 1182 |
| 1179 if (code->type() != Code::NORMAL) { | 1183 if (code->type() != Code::NORMAL) { |
| 1180 HeapObject::UpdateMapCodeCache(stub_holder, name, code); | 1184 HeapObject::UpdateMapCodeCache(stub_holder, name, code); |
| 1181 } | 1185 } |
| 1182 | 1186 |
| 1183 return code; | 1187 return code; |
| 1184 } | 1188 } |
| 1185 | 1189 |
| 1186 | 1190 |
| 1187 Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, | 1191 Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, |
| 1188 Handle<Object> object, | 1192 Handle<Object> object, |
| 1189 Handle<String> name, | 1193 Handle<String> name, |
| 1190 Handle<Object> unused, | 1194 Handle<Object> unused, |
| 1191 InlineCacheHolderFlag cache_holder) { | 1195 InlineCacheHolderFlag cache_holder) { |
| 1192 if (object->IsString() && name->Equals(isolate()->heap()->length_string())) { | 1196 if (object->IsString() && name->Equals(isolate()->heap()->length_string())) { |
| 1193 int length_index = String::kLengthOffset / kPointerSize; | 1197 int length_index = String::kLengthOffset / kPointerSize; |
| 1194 return SimpleFieldLoad(length_index); | 1198 return SimpleFieldLoad(length_index); |
| 1195 } | 1199 } |
| 1196 | 1200 |
| 1201 Handle<Type> type = CurrentTypeOf(object, isolate()); |
| 1197 Handle<JSObject> holder(lookup->holder()); | 1202 Handle<JSObject> holder(lookup->holder()); |
| 1198 LoadStubCompiler compiler(isolate(), cache_holder, kind()); | 1203 LoadStubCompiler compiler(isolate(), kNoExtraICState, cache_holder, kind()); |
| 1199 | 1204 |
| 1200 switch (lookup->type()) { | 1205 switch (lookup->type()) { |
| 1201 case FIELD: { | 1206 case FIELD: { |
| 1202 PropertyIndex field = lookup->GetFieldIndex(); | 1207 PropertyIndex field = lookup->GetFieldIndex(); |
| 1203 if (object.is_identical_to(holder)) { | 1208 if (object.is_identical_to(holder)) { |
| 1204 return SimpleFieldLoad(field.translate(holder), | 1209 return SimpleFieldLoad(field.translate(holder), |
| 1205 field.is_inobject(holder), | 1210 field.is_inobject(holder), |
| 1206 lookup->representation()); | 1211 lookup->representation()); |
| 1207 } | 1212 } |
| 1208 return compiler.CompileLoadField( | 1213 return compiler.CompileLoadField( |
| 1209 object, holder, name, field, lookup->representation()); | 1214 type, holder, name, field, lookup->representation()); |
| 1210 } | 1215 } |
| 1211 case CONSTANT: { | 1216 case CONSTANT: { |
| 1212 Handle<Object> constant(lookup->GetConstant(), isolate()); | 1217 Handle<Object> constant(lookup->GetConstant(), isolate()); |
| 1213 // TODO(2803): Don't compute a stub for cons strings because they cannot | 1218 // TODO(2803): Don't compute a stub for cons strings because they cannot |
| 1214 // be embedded into code. | 1219 // be embedded into code. |
| 1215 if (constant->IsConsString()) break; | 1220 if (constant->IsConsString()) break; |
| 1216 return compiler.CompileLoadConstant(object, holder, name, constant); | 1221 return compiler.CompileLoadConstant(type, holder, name, constant); |
| 1217 } | 1222 } |
| 1218 case NORMAL: | 1223 case NORMAL: |
| 1219 if (kind() != Code::LOAD_IC) break; | 1224 if (kind() != Code::LOAD_IC) break; |
| 1220 if (holder->IsGlobalObject()) { | 1225 if (holder->IsGlobalObject()) { |
| 1221 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); | 1226 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); |
| 1222 Handle<PropertyCell> cell( | 1227 Handle<PropertyCell> cell( |
| 1223 global->GetPropertyCell(lookup), isolate()); | 1228 global->GetPropertyCell(lookup), isolate()); |
| 1224 Handle<Code> code = compiler.CompileLoadGlobal( | 1229 Handle<Code> code = compiler.CompileLoadGlobal( |
| 1225 object, global, cell, name, lookup->IsDontDelete()); | 1230 type, global, cell, name, lookup->IsDontDelete()); |
| 1226 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. | 1231 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. |
| 1227 Handle<HeapObject> stub_holder(GetCodeCacheHolder( | 1232 Handle<HeapObject> stub_holder(GetCodeCacheHolder( |
| 1228 isolate(), *object, cache_holder)); | 1233 isolate(), *object, cache_holder)); |
| 1229 HeapObject::UpdateMapCodeCache(stub_holder, name, code); | 1234 HeapObject::UpdateMapCodeCache(stub_holder, name, code); |
| 1230 return code; | 1235 return code; |
| 1231 } | 1236 } |
| 1232 // There is only one shared stub for loading normalized | 1237 // There is only one shared stub for loading normalized |
| 1233 // properties. It does not traverse the prototype chain, so the | 1238 // properties. It does not traverse the prototype chain, so the |
| 1234 // property must be found in the object for the stub to be | 1239 // property must be found in the object for the stub to be |
| 1235 // applicable. | 1240 // applicable. |
| 1236 if (!object.is_identical_to(holder)) break; | 1241 if (!object.is_identical_to(holder)) break; |
| 1237 return isolate()->builtins()->LoadIC_Normal(); | 1242 return isolate()->builtins()->LoadIC_Normal(); |
| 1238 case CALLBACKS: { | 1243 case CALLBACKS: { |
| 1239 // Use simple field loads for some well-known callback properties. | 1244 // Use simple field loads for some well-known callback properties. |
| 1240 if (object->IsJSObject()) { | 1245 if (object->IsJSObject()) { |
| 1241 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1246 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1242 Handle<Map> map(receiver->map()); | 1247 Handle<Map> map(receiver->map()); |
| 1243 int object_offset; | 1248 int object_offset; |
| 1244 if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) { | 1249 if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) { |
| 1245 return SimpleFieldLoad(object_offset / kPointerSize); | 1250 return SimpleFieldLoad(object_offset / kPointerSize); |
| 1246 } | 1251 } |
| 1247 } | 1252 } |
| 1248 | 1253 |
| 1249 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | 1254 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
| 1250 if (callback->IsExecutableAccessorInfo()) { | 1255 if (callback->IsExecutableAccessorInfo()) { |
| 1251 Handle<ExecutableAccessorInfo> info = | 1256 Handle<ExecutableAccessorInfo> info = |
| 1252 Handle<ExecutableAccessorInfo>::cast(callback); | 1257 Handle<ExecutableAccessorInfo>::cast(callback); |
| 1253 if (v8::ToCData<Address>(info->getter()) == 0) break; | 1258 if (v8::ToCData<Address>(info->getter()) == 0) break; |
| 1254 if (!info->IsCompatibleReceiver(*object)) break; | 1259 if (!info->IsCompatibleReceiver(*object)) break; |
| 1255 return compiler.CompileLoadCallback(object, holder, name, info); | 1260 return compiler.CompileLoadCallback(type, holder, name, info); |
| 1256 } else if (callback->IsAccessorPair()) { | 1261 } else if (callback->IsAccessorPair()) { |
| 1257 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(), | 1262 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(), |
| 1258 isolate()); | 1263 isolate()); |
| 1259 if (!getter->IsJSFunction()) break; | 1264 if (!getter->IsJSFunction()) break; |
| 1260 if (holder->IsGlobalObject()) break; | 1265 if (holder->IsGlobalObject()) break; |
| 1261 if (!holder->HasFastProperties()) break; | 1266 if (!holder->HasFastProperties()) break; |
| 1262 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); | 1267 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); |
| 1263 if (!object->IsJSObject() && | 1268 if (!object->IsJSObject() && |
| 1264 !function->IsBuiltin() && | 1269 !function->IsBuiltin() && |
| 1265 function->shared()->is_classic_mode()) { | 1270 function->shared()->is_classic_mode()) { |
| 1266 // Calling non-strict non-builtins with a value as the receiver | 1271 // Calling non-strict non-builtins with a value as the receiver |
| 1267 // requires boxing. | 1272 // requires boxing. |
| 1268 break; | 1273 break; |
| 1269 } | 1274 } |
| 1270 CallOptimization call_optimization(function); | 1275 CallOptimization call_optimization(function); |
| 1271 if (call_optimization.is_simple_api_call() && | 1276 if (call_optimization.is_simple_api_call() && |
| 1272 call_optimization.IsCompatibleReceiver(*object)) { | 1277 call_optimization.IsCompatibleReceiver(*object)) { |
| 1273 return compiler.CompileLoadCallback( | 1278 return compiler.CompileLoadCallback( |
| 1274 object, holder, name, call_optimization); | 1279 type, holder, name, call_optimization); |
| 1275 } | 1280 } |
| 1276 return compiler.CompileLoadViaGetter(object, holder, name, function); | 1281 return compiler.CompileLoadViaGetter(type, holder, name, function); |
| 1277 } | 1282 } |
| 1278 // TODO(dcarney): Handle correctly. | 1283 // TODO(dcarney): Handle correctly. |
| 1279 if (callback->IsDeclaredAccessorInfo()) break; | 1284 if (callback->IsDeclaredAccessorInfo()) break; |
| 1280 ASSERT(callback->IsForeign()); | 1285 ASSERT(callback->IsForeign()); |
| 1281 // No IC support for old-style native accessors. | 1286 // No IC support for old-style native accessors. |
| 1282 break; | 1287 break; |
| 1283 } | 1288 } |
| 1284 case INTERCEPTOR: | 1289 case INTERCEPTOR: |
| 1285 ASSERT(HasInterceptorGetter(*holder)); | 1290 ASSERT(HasInterceptorGetter(*holder)); |
| 1286 return compiler.CompileLoadInterceptor(object, holder, name); | 1291 return compiler.CompileLoadInterceptor(type, holder, name); |
| 1287 default: | 1292 default: |
| 1288 break; | 1293 break; |
| 1289 } | 1294 } |
| 1290 | 1295 |
| 1291 return slow_stub(); | 1296 return slow_stub(); |
| 1292 } | 1297 } |
| 1293 | 1298 |
| 1294 | 1299 |
| 1295 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { | 1300 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { |
| 1296 // This helper implements a few common fast cases for converting | 1301 // This helper implements a few common fast cases for converting |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1437 receiver->LocalLookupRealNamedProperty(*name, lookup); | 1442 receiver->LocalLookupRealNamedProperty(*name, lookup); |
| 1438 return lookup->IsFound() && | 1443 return lookup->IsFound() && |
| 1439 !lookup->IsReadOnly() && | 1444 !lookup->IsReadOnly() && |
| 1440 lookup->CanHoldValue(value) && | 1445 lookup->CanHoldValue(value) && |
| 1441 lookup->IsCacheable(); | 1446 lookup->IsCacheable(); |
| 1442 } | 1447 } |
| 1443 return lookup->CanHoldValue(value); | 1448 return lookup->CanHoldValue(value); |
| 1444 } | 1449 } |
| 1445 | 1450 |
| 1446 if (lookup->IsPropertyCallbacks()) return true; | 1451 if (lookup->IsPropertyCallbacks()) return true; |
| 1447 | 1452 // JSGlobalProxy always goes via the runtime, so it's safe to cache. |
| 1453 if (receiver->IsJSGlobalProxy()) return true; |
| 1448 // Currently normal holders in the prototype chain are not supported. They | 1454 // Currently normal holders in the prototype chain are not supported. They |
| 1449 // would require a runtime positive lookup and verification that the details | 1455 // would require a runtime positive lookup and verification that the details |
| 1450 // have not changed. | 1456 // have not changed. |
| 1451 if (lookup->IsInterceptor() || lookup->IsNormal()) return false; | 1457 if (lookup->IsInterceptor() || lookup->IsNormal()) return false; |
| 1452 holder = Handle<JSObject>(lookup->holder(), lookup->isolate()); | 1458 holder = Handle<JSObject>(lookup->holder(), lookup->isolate()); |
| 1453 } | 1459 } |
| 1454 | 1460 |
| 1455 // While normally LookupTransition gets passed the receiver, in this case we | 1461 // While normally LookupTransition gets passed the receiver, in this case we |
| 1456 // pass the holder of the property that we overwrite. This keeps the holder in | 1462 // pass the holder of the property that we overwrite. This keeps the holder in |
| 1457 // the LookupResult intact so we can later use it to generate a prototype | 1463 // the LookupResult intact so we can later use it to generate a prototype |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1544 Handle<Code> stub = | 1550 Handle<Code> stub = |
| 1545 StoreArrayLengthStub(kind(), strict_mode()).GetCode(isolate()); | 1551 StoreArrayLengthStub(kind(), strict_mode()).GetCode(isolate()); |
| 1546 set_target(*stub); | 1552 set_target(*stub); |
| 1547 TRACE_IC("StoreIC", name); | 1553 TRACE_IC("StoreIC", name); |
| 1548 Handle<Object> result = JSReceiver::SetProperty( | 1554 Handle<Object> result = JSReceiver::SetProperty( |
| 1549 receiver, name, value, NONE, strict_mode(), store_mode); | 1555 receiver, name, value, NONE, strict_mode(), store_mode); |
| 1550 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 1556 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 1551 return *result; | 1557 return *result; |
| 1552 } | 1558 } |
| 1553 | 1559 |
| 1554 if (receiver->IsJSGlobalProxy()) { | |
| 1555 if (FLAG_use_ic && kind() != Code::KEYED_STORE_IC) { | |
| 1556 // Generate a generic stub that goes to the runtime when we see a global | |
| 1557 // proxy as receiver. | |
| 1558 Handle<Code> stub = global_proxy_stub(); | |
| 1559 set_target(*stub); | |
| 1560 TRACE_IC("StoreIC", name); | |
| 1561 } | |
| 1562 Handle<Object> result = JSReceiver::SetProperty( | |
| 1563 receiver, name, value, NONE, strict_mode(), store_mode); | |
| 1564 RETURN_IF_EMPTY_HANDLE(isolate(), result); | |
| 1565 return *result; | |
| 1566 } | |
| 1567 | |
| 1568 LookupResult lookup(isolate()); | 1560 LookupResult lookup(isolate()); |
| 1569 bool can_store = LookupForWrite(receiver, name, value, &lookup, this); | 1561 bool can_store = LookupForWrite(receiver, name, value, &lookup, this); |
| 1570 if (!can_store && | 1562 if (!can_store && |
| 1571 strict_mode() == kStrictMode && | 1563 strict_mode() == kStrictMode && |
| 1572 !(lookup.IsProperty() && lookup.IsReadOnly()) && | 1564 !(lookup.IsProperty() && lookup.IsReadOnly()) && |
| 1573 IsUndeclaredGlobal(object)) { | 1565 IsUndeclaredGlobal(object)) { |
| 1574 // Strict mode doesn't allow setting non-existent global property. | 1566 // Strict mode doesn't allow setting non-existent global property. |
| 1575 return ReferenceError("not_defined", name); | 1567 return ReferenceError("not_defined", name); |
| 1576 } | 1568 } |
| 1577 if (FLAG_use_ic) { | 1569 if (FLAG_use_ic) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1594 receiver, name, value, NONE, strict_mode(), store_mode); | 1586 receiver, name, value, NONE, strict_mode(), store_mode); |
| 1595 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 1587 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 1596 return *result; | 1588 return *result; |
| 1597 } | 1589 } |
| 1598 | 1590 |
| 1599 | 1591 |
| 1600 void StoreIC::UpdateCaches(LookupResult* lookup, | 1592 void StoreIC::UpdateCaches(LookupResult* lookup, |
| 1601 Handle<JSObject> receiver, | 1593 Handle<JSObject> receiver, |
| 1602 Handle<String> name, | 1594 Handle<String> name, |
| 1603 Handle<Object> value) { | 1595 Handle<Object> value) { |
| 1604 ASSERT(!receiver->IsJSGlobalProxy()); | |
| 1605 ASSERT(lookup->IsFound()); | 1596 ASSERT(lookup->IsFound()); |
| 1606 | 1597 |
| 1607 // These are not cacheable, so we never see such LookupResults here. | 1598 // These are not cacheable, so we never see such LookupResults here. |
| 1608 ASSERT(!lookup->IsHandler()); | 1599 ASSERT(!lookup->IsHandler()); |
| 1609 | 1600 |
| 1610 Handle<Code> code = ComputeHandler(lookup, receiver, name, value); | 1601 Handle<Code> code = ComputeHandler(lookup, receiver, name, value); |
| 1611 | 1602 |
| 1612 PatchCache(handle(Type::OfCurrently(receiver), isolate()), name, code); | 1603 PatchCache(CurrentTypeOf(receiver, isolate()), name, code); |
| 1613 TRACE_IC("StoreIC", name); | 1604 TRACE_IC("StoreIC", name); |
| 1614 } | 1605 } |
| 1615 | 1606 |
| 1616 | 1607 |
| 1617 Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, | 1608 Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, |
| 1618 Handle<Object> object, | 1609 Handle<Object> object, |
| 1619 Handle<String> name, | 1610 Handle<String> name, |
| 1620 Handle<Object> value, | 1611 Handle<Object> value, |
| 1621 InlineCacheHolderFlag cache_holder) { | 1612 InlineCacheHolderFlag cache_holder) { |
| 1613 if (object->IsJSGlobalProxy()) return slow_stub(); |
| 1622 ASSERT(cache_holder == OWN_MAP); | 1614 ASSERT(cache_holder == OWN_MAP); |
| 1623 // This is currently guaranteed by checks in StoreIC::Store. | 1615 // This is currently guaranteed by checks in StoreIC::Store. |
| 1624 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1616 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1625 | 1617 |
| 1626 Handle<JSObject> holder(lookup->holder()); | 1618 Handle<JSObject> holder(lookup->holder()); |
| 1627 StoreStubCompiler compiler(isolate(), strict_mode(), kind()); | 1619 // Handlers do not use strict mode. |
| 1620 StoreStubCompiler compiler(isolate(), kNonStrictMode, kind()); |
| 1628 switch (lookup->type()) { | 1621 switch (lookup->type()) { |
| 1629 case FIELD: | 1622 case FIELD: |
| 1630 return compiler.CompileStoreField(receiver, lookup, name); | 1623 return compiler.CompileStoreField(receiver, lookup, name); |
| 1631 case TRANSITION: { | 1624 case TRANSITION: { |
| 1632 // Explicitly pass in the receiver map since LookupForWrite may have | 1625 // Explicitly pass in the receiver map since LookupForWrite may have |
| 1633 // stored something else than the receiver in the holder. | 1626 // stored something else than the receiver in the holder. |
| 1634 Handle<Map> transition( | 1627 Handle<Map> transition( |
| 1635 lookup->GetTransitionTarget(receiver->map()), isolate()); | 1628 lookup->GetTransitionTarget(receiver->map()), isolate()); |
| 1636 int descriptor = transition->LastAdded(); | 1629 int descriptor = transition->LastAdded(); |
| 1637 | 1630 |
| 1638 DescriptorArray* target_descriptors = transition->instance_descriptors(); | 1631 DescriptorArray* target_descriptors = transition->instance_descriptors(); |
| 1639 PropertyDetails details = target_descriptors->GetDetails(descriptor); | 1632 PropertyDetails details = target_descriptors->GetDetails(descriptor); |
| 1640 | 1633 |
| 1641 if (details.type() == CALLBACKS || details.attributes() != NONE) break; | 1634 if (details.type() == CALLBACKS || details.attributes() != NONE) break; |
| 1642 | 1635 |
| 1643 return compiler.CompileStoreTransition( | 1636 return compiler.CompileStoreTransition( |
| 1644 receiver, lookup, transition, name); | 1637 receiver, lookup, transition, name); |
| 1645 } | 1638 } |
| 1646 case NORMAL: | 1639 case NORMAL: |
| 1647 if (kind() == Code::KEYED_STORE_IC) break; | 1640 if (kind() == Code::KEYED_STORE_IC) break; |
| 1648 if (receiver->IsGlobalObject()) { | 1641 if (receiver->IsGlobalObject()) { |
| 1649 // The stub generated for the global object picks the value directly | 1642 // The stub generated for the global object picks the value directly |
| 1650 // from the property cell. So the property must be directly on the | 1643 // from the property cell. So the property must be directly on the |
| 1651 // global object. | 1644 // global object. |
| 1652 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1645 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
| 1653 Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate()); | 1646 Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate()); |
| 1654 Handle<Type> union_type = PropertyCell::UpdatedType(cell, value); | 1647 Handle<Type> union_type = PropertyCell::UpdatedType(cell, value); |
| 1655 StoreGlobalStub stub(strict_mode(), union_type->IsConstant()); | 1648 StoreGlobalStub stub(union_type->IsConstant()); |
| 1656 | 1649 |
| 1657 Handle<Code> code = stub.GetCodeCopyFromTemplate( | 1650 Handle<Code> code = stub.GetCodeCopyFromTemplate( |
| 1658 isolate(), receiver->map(), *cell); | 1651 isolate(), receiver->map(), *cell); |
| 1659 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. | 1652 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. |
| 1660 HeapObject::UpdateMapCodeCache(receiver, name, code); | 1653 HeapObject::UpdateMapCodeCache(receiver, name, code); |
| 1661 return code; | 1654 return code; |
| 1662 } | 1655 } |
| 1663 ASSERT(holder.is_identical_to(receiver)); | 1656 ASSERT(holder.is_identical_to(receiver)); |
| 1664 return strict_mode() == kStrictMode | 1657 return isolate()->builtins()->StoreIC_Normal(); |
| 1665 ? isolate()->builtins()->StoreIC_Normal_Strict() | |
| 1666 : isolate()->builtins()->StoreIC_Normal(); | |
| 1667 case CALLBACKS: { | 1658 case CALLBACKS: { |
| 1668 if (kind() == Code::KEYED_STORE_IC) break; | 1659 if (kind() == Code::KEYED_STORE_IC) break; |
| 1669 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | 1660 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
| 1670 if (callback->IsExecutableAccessorInfo()) { | 1661 if (callback->IsExecutableAccessorInfo()) { |
| 1671 Handle<ExecutableAccessorInfo> info = | 1662 Handle<ExecutableAccessorInfo> info = |
| 1672 Handle<ExecutableAccessorInfo>::cast(callback); | 1663 Handle<ExecutableAccessorInfo>::cast(callback); |
| 1673 if (v8::ToCData<Address>(info->setter()) == 0) break; | 1664 if (v8::ToCData<Address>(info->setter()) == 0) break; |
| 1674 if (!holder->HasFastProperties()) break; | 1665 if (!holder->HasFastProperties()) break; |
| 1675 if (!info->IsCompatibleReceiver(*receiver)) break; | 1666 if (!info->IsCompatibleReceiver(*receiver)) break; |
| 1676 return compiler.CompileStoreCallback(receiver, holder, name, info); | 1667 return compiler.CompileStoreCallback(receiver, holder, name, info); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1738 // stores into properties in dictionary mode), then there will be not | 1729 // stores into properties in dictionary mode), then there will be not |
| 1739 // receiver maps in the target. | 1730 // receiver maps in the target. |
| 1740 return generic_stub(); | 1731 return generic_stub(); |
| 1741 } | 1732 } |
| 1742 | 1733 |
| 1743 // There are several special cases where an IC that is MONOMORPHIC can still | 1734 // There are several special cases where an IC that is MONOMORPHIC can still |
| 1744 // transition to a different GetNonTransitioningStoreMode IC that handles a | 1735 // transition to a different GetNonTransitioningStoreMode IC that handles a |
| 1745 // superset of the original IC. Handle those here if the receiver map hasn't | 1736 // superset of the original IC. Handle those here if the receiver map hasn't |
| 1746 // changed or it has transitioned to a more general kind. | 1737 // changed or it has transitioned to a more general kind. |
| 1747 KeyedAccessStoreMode old_store_mode = | 1738 KeyedAccessStoreMode old_store_mode = |
| 1748 Code::GetKeyedAccessStoreMode(target()->extra_ic_state()); | 1739 KeyedStoreIC::GetKeyedAccessStoreMode(target()->extra_ic_state()); |
| 1749 Handle<Map> previous_receiver_map = target_receiver_maps.at(0); | 1740 Handle<Map> previous_receiver_map = target_receiver_maps.at(0); |
| 1750 if (state() == MONOMORPHIC) { | 1741 if (state() == MONOMORPHIC) { |
| 1751 // If the "old" and "new" maps are in the same elements map family, stay | 1742 // If the "old" and "new" maps are in the same elements map family, stay |
| 1752 // MONOMORPHIC and use the map for the most generic ElementsKind. | 1743 // MONOMORPHIC and use the map for the most generic ElementsKind. |
| 1753 Handle<Map> transitioned_receiver_map = receiver_map; | 1744 Handle<Map> transitioned_receiver_map = receiver_map; |
| 1754 if (IsTransitionStoreMode(store_mode)) { | 1745 if (IsTransitionStoreMode(store_mode)) { |
| 1755 transitioned_receiver_map = | 1746 transitioned_receiver_map = |
| 1756 ComputeTransitionedMap(receiver, store_mode); | 1747 ComputeTransitionedMap(receiver, store_mode); |
| 1757 } | 1748 } |
| 1758 if (IsTransitionOfMonomorphicTarget(MapToType(transitioned_receiver_map))) { | 1749 if (IsTransitionOfMonomorphicTarget(MapToType(transitioned_receiver_map))) { |
| (...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2314 } | 2305 } |
| 2315 Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key, | 2306 Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key, |
| 2316 value, | 2307 value, |
| 2317 NONE, | 2308 NONE, |
| 2318 strict_mode); | 2309 strict_mode); |
| 2319 RETURN_IF_EMPTY_HANDLE(isolate, result); | 2310 RETURN_IF_EMPTY_HANDLE(isolate, result); |
| 2320 return *result; | 2311 return *result; |
| 2321 } | 2312 } |
| 2322 | 2313 |
| 2323 | 2314 |
| 2324 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 2315 BinaryOpIC::State::State(ExtraICState extra_ic_state) { |
| 2325 switch (type_info) { | 2316 // We don't deserialize the SSE2 Field, since this is only used to be able |
| 2326 case UNINITIALIZED: return "Uninitialized"; | 2317 // to include SSE2 as well as non-SSE2 versions in the snapshot. For code |
| 2318 // generation we always want it to reflect the current state. |
| 2319 op_ = static_cast<Token::Value>( |
| 2320 FIRST_TOKEN + OpField::decode(extra_ic_state)); |
| 2321 mode_ = OverwriteModeField::decode(extra_ic_state); |
| 2322 fixed_right_arg_ = Maybe<int>( |
| 2323 HasFixedRightArgField::decode(extra_ic_state), |
| 2324 1 << FixedRightArgValueField::decode(extra_ic_state)); |
| 2325 left_kind_ = LeftKindField::decode(extra_ic_state); |
| 2326 if (fixed_right_arg_.has_value) { |
| 2327 right_kind_ = Smi::IsValid(fixed_right_arg_.value) ? SMI : INT32; |
| 2328 } else { |
| 2329 right_kind_ = RightKindField::decode(extra_ic_state); |
| 2330 } |
| 2331 result_kind_ = ResultKindField::decode(extra_ic_state); |
| 2332 ASSERT_LE(FIRST_TOKEN, op_); |
| 2333 ASSERT_LE(op_, LAST_TOKEN); |
| 2334 } |
| 2335 |
| 2336 |
| 2337 ExtraICState BinaryOpIC::State::GetExtraICState() const { |
| 2338 bool sse2 = (Max(result_kind_, Max(left_kind_, right_kind_)) > SMI && |
| 2339 CpuFeatures::IsSafeForSnapshot(SSE2)); |
| 2340 ExtraICState extra_ic_state = |
| 2341 SSE2Field::encode(sse2) | |
| 2342 OpField::encode(op_ - FIRST_TOKEN) | |
| 2343 OverwriteModeField::encode(mode_) | |
| 2344 LeftKindField::encode(left_kind_) | |
| 2345 ResultKindField::encode(result_kind_) | |
| 2346 HasFixedRightArgField::encode(fixed_right_arg_.has_value); |
| 2347 if (fixed_right_arg_.has_value) { |
| 2348 extra_ic_state = FixedRightArgValueField::update( |
| 2349 extra_ic_state, WhichPowerOf2(fixed_right_arg_.value)); |
| 2350 } else { |
| 2351 extra_ic_state = RightKindField::update(extra_ic_state, right_kind_); |
| 2352 } |
| 2353 return extra_ic_state; |
| 2354 } |
| 2355 |
| 2356 |
| 2357 // static |
| 2358 void BinaryOpIC::State::GenerateAheadOfTime( |
| 2359 Isolate* isolate, void (*Generate)(Isolate*, const State&)) { |
| 2360 // TODO(olivf) We should investigate why adding stubs to the snapshot is so |
| 2361 // expensive at runtime. When solved we should be able to add most binops to |
| 2362 // the snapshot instead of hand-picking them. |
| 2363 // Generated list of commonly used stubs |
| 2364 #define GENERATE(op, left_kind, right_kind, result_kind, mode) \ |
| 2365 do { \ |
| 2366 State state(op, mode); \ |
| 2367 state.left_kind_ = left_kind; \ |
| 2368 state.fixed_right_arg_.has_value = false; \ |
| 2369 state.right_kind_ = right_kind; \ |
| 2370 state.result_kind_ = result_kind; \ |
| 2371 Generate(isolate, state); \ |
| 2372 } while (false) |
| 2373 GENERATE(Token::ADD, INT32, INT32, INT32, NO_OVERWRITE); |
| 2374 GENERATE(Token::ADD, INT32, INT32, INT32, OVERWRITE_LEFT); |
| 2375 GENERATE(Token::ADD, INT32, INT32, NUMBER, NO_OVERWRITE); |
| 2376 GENERATE(Token::ADD, INT32, INT32, NUMBER, OVERWRITE_LEFT); |
| 2377 GENERATE(Token::ADD, INT32, NUMBER, NUMBER, NO_OVERWRITE); |
| 2378 GENERATE(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_LEFT); |
| 2379 GENERATE(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT); |
| 2380 GENERATE(Token::ADD, INT32, SMI, INT32, NO_OVERWRITE); |
| 2381 GENERATE(Token::ADD, INT32, SMI, INT32, OVERWRITE_LEFT); |
| 2382 GENERATE(Token::ADD, INT32, SMI, INT32, OVERWRITE_RIGHT); |
| 2383 GENERATE(Token::ADD, NUMBER, INT32, NUMBER, NO_OVERWRITE); |
| 2384 GENERATE(Token::ADD, NUMBER, INT32, NUMBER, OVERWRITE_LEFT); |
| 2385 GENERATE(Token::ADD, NUMBER, INT32, NUMBER, OVERWRITE_RIGHT); |
| 2386 GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER, NO_OVERWRITE); |
| 2387 GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT); |
| 2388 GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT); |
| 2389 GENERATE(Token::ADD, NUMBER, SMI, NUMBER, NO_OVERWRITE); |
| 2390 GENERATE(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT); |
| 2391 GENERATE(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT); |
| 2392 GENERATE(Token::ADD, SMI, INT32, INT32, NO_OVERWRITE); |
| 2393 GENERATE(Token::ADD, SMI, INT32, INT32, OVERWRITE_LEFT); |
| 2394 GENERATE(Token::ADD, SMI, INT32, NUMBER, NO_OVERWRITE); |
| 2395 GENERATE(Token::ADD, SMI, NUMBER, NUMBER, NO_OVERWRITE); |
| 2396 GENERATE(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_LEFT); |
| 2397 GENERATE(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT); |
| 2398 GENERATE(Token::ADD, SMI, SMI, INT32, OVERWRITE_LEFT); |
| 2399 GENERATE(Token::ADD, SMI, SMI, SMI, OVERWRITE_RIGHT); |
| 2400 GENERATE(Token::BIT_AND, INT32, INT32, INT32, NO_OVERWRITE); |
| 2401 GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_LEFT); |
| 2402 GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_RIGHT); |
| 2403 GENERATE(Token::BIT_AND, INT32, INT32, SMI, NO_OVERWRITE); |
| 2404 GENERATE(Token::BIT_AND, INT32, INT32, SMI, OVERWRITE_RIGHT); |
| 2405 GENERATE(Token::BIT_AND, INT32, SMI, INT32, NO_OVERWRITE); |
| 2406 GENERATE(Token::BIT_AND, INT32, SMI, INT32, OVERWRITE_RIGHT); |
| 2407 GENERATE(Token::BIT_AND, INT32, SMI, SMI, NO_OVERWRITE); |
| 2408 GENERATE(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_LEFT); |
| 2409 GENERATE(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_RIGHT); |
| 2410 GENERATE(Token::BIT_AND, NUMBER, INT32, INT32, OVERWRITE_RIGHT); |
| 2411 GENERATE(Token::BIT_AND, NUMBER, SMI, SMI, NO_OVERWRITE); |
| 2412 GENERATE(Token::BIT_AND, NUMBER, SMI, SMI, OVERWRITE_RIGHT); |
| 2413 GENERATE(Token::BIT_AND, SMI, INT32, INT32, NO_OVERWRITE); |
| 2414 GENERATE(Token::BIT_AND, SMI, INT32, SMI, OVERWRITE_RIGHT); |
| 2415 GENERATE(Token::BIT_AND, SMI, NUMBER, SMI, OVERWRITE_RIGHT); |
| 2416 GENERATE(Token::BIT_AND, SMI, SMI, SMI, NO_OVERWRITE); |
| 2417 GENERATE(Token::BIT_AND, SMI, SMI, SMI, OVERWRITE_LEFT); |
| 2418 GENERATE(Token::BIT_AND, SMI, SMI, SMI, OVERWRITE_RIGHT); |
| 2419 GENERATE(Token::BIT_OR, INT32, INT32, INT32, OVERWRITE_LEFT); |
| 2420 GENERATE(Token::BIT_OR, INT32, INT32, INT32, OVERWRITE_RIGHT); |
| 2421 GENERATE(Token::BIT_OR, INT32, INT32, SMI, OVERWRITE_LEFT); |
| 2422 GENERATE(Token::BIT_OR, INT32, SMI, INT32, NO_OVERWRITE); |
| 2423 GENERATE(Token::BIT_OR, INT32, SMI, INT32, OVERWRITE_LEFT); |
| 2424 GENERATE(Token::BIT_OR, INT32, SMI, INT32, OVERWRITE_RIGHT); |
| 2425 GENERATE(Token::BIT_OR, INT32, SMI, SMI, NO_OVERWRITE); |
| 2426 GENERATE(Token::BIT_OR, INT32, SMI, SMI, OVERWRITE_RIGHT); |
| 2427 GENERATE(Token::BIT_OR, NUMBER, SMI, INT32, NO_OVERWRITE); |
| 2428 GENERATE(Token::BIT_OR, NUMBER, SMI, INT32, OVERWRITE_LEFT); |
| 2429 GENERATE(Token::BIT_OR, NUMBER, SMI, INT32, OVERWRITE_RIGHT); |
| 2430 GENERATE(Token::BIT_OR, NUMBER, SMI, SMI, NO_OVERWRITE); |
| 2431 GENERATE(Token::BIT_OR, NUMBER, SMI, SMI, OVERWRITE_LEFT); |
| 2432 GENERATE(Token::BIT_OR, SMI, INT32, INT32, OVERWRITE_LEFT); |
| 2433 GENERATE(Token::BIT_OR, SMI, INT32, INT32, OVERWRITE_RIGHT); |
| 2434 GENERATE(Token::BIT_OR, SMI, INT32, SMI, OVERWRITE_RIGHT); |
| 2435 GENERATE(Token::BIT_OR, SMI, SMI, SMI, OVERWRITE_LEFT); |
| 2436 GENERATE(Token::BIT_OR, SMI, SMI, SMI, OVERWRITE_RIGHT); |
| 2437 GENERATE(Token::BIT_XOR, INT32, INT32, INT32, NO_OVERWRITE); |
| 2438 GENERATE(Token::BIT_XOR, INT32, INT32, INT32, OVERWRITE_LEFT); |
| 2439 GENERATE(Token::BIT_XOR, INT32, INT32, INT32, OVERWRITE_RIGHT); |
| 2440 GENERATE(Token::BIT_XOR, INT32, INT32, SMI, NO_OVERWRITE); |
| 2441 GENERATE(Token::BIT_XOR, INT32, INT32, SMI, OVERWRITE_LEFT); |
| 2442 GENERATE(Token::BIT_XOR, INT32, NUMBER, SMI, NO_OVERWRITE); |
| 2443 GENERATE(Token::BIT_XOR, INT32, SMI, INT32, NO_OVERWRITE); |
| 2444 GENERATE(Token::BIT_XOR, INT32, SMI, INT32, OVERWRITE_LEFT); |
| 2445 GENERATE(Token::BIT_XOR, INT32, SMI, INT32, OVERWRITE_RIGHT); |
| 2446 GENERATE(Token::BIT_XOR, NUMBER, INT32, INT32, NO_OVERWRITE); |
| 2447 GENERATE(Token::BIT_XOR, NUMBER, SMI, INT32, NO_OVERWRITE); |
| 2448 GENERATE(Token::BIT_XOR, NUMBER, SMI, SMI, NO_OVERWRITE); |
| 2449 GENERATE(Token::BIT_XOR, SMI, INT32, INT32, NO_OVERWRITE); |
| 2450 GENERATE(Token::BIT_XOR, SMI, INT32, INT32, OVERWRITE_LEFT); |
| 2451 GENERATE(Token::BIT_XOR, SMI, INT32, SMI, OVERWRITE_LEFT); |
| 2452 GENERATE(Token::BIT_XOR, SMI, SMI, SMI, NO_OVERWRITE); |
| 2453 GENERATE(Token::BIT_XOR, SMI, SMI, SMI, OVERWRITE_LEFT); |
| 2454 GENERATE(Token::BIT_XOR, SMI, SMI, SMI, OVERWRITE_RIGHT); |
| 2455 GENERATE(Token::DIV, INT32, INT32, INT32, NO_OVERWRITE); |
| 2456 GENERATE(Token::DIV, INT32, INT32, NUMBER, NO_OVERWRITE); |
| 2457 GENERATE(Token::DIV, INT32, NUMBER, NUMBER, NO_OVERWRITE); |
| 2458 GENERATE(Token::DIV, INT32, NUMBER, NUMBER, OVERWRITE_LEFT); |
| 2459 GENERATE(Token::DIV, INT32, SMI, INT32, NO_OVERWRITE); |
| 2460 GENERATE(Token::DIV, INT32, SMI, NUMBER, NO_OVERWRITE); |
| 2461 GENERATE(Token::DIV, NUMBER, INT32, NUMBER, NO_OVERWRITE); |
| 2462 GENERATE(Token::DIV, NUMBER, INT32, NUMBER, OVERWRITE_LEFT); |
| 2463 GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER, NO_OVERWRITE); |
| 2464 GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT); |
| 2465 GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT); |
| 2466 GENERATE(Token::DIV, NUMBER, SMI, NUMBER, NO_OVERWRITE); |
| 2467 GENERATE(Token::DIV, NUMBER, SMI, NUMBER, OVERWRITE_LEFT); |
| 2468 GENERATE(Token::DIV, SMI, INT32, INT32, NO_OVERWRITE); |
| 2469 GENERATE(Token::DIV, SMI, INT32, NUMBER, NO_OVERWRITE); |
| 2470 GENERATE(Token::DIV, SMI, INT32, NUMBER, OVERWRITE_LEFT); |
| 2471 GENERATE(Token::DIV, SMI, NUMBER, NUMBER, NO_OVERWRITE); |
| 2472 GENERATE(Token::DIV, SMI, NUMBER, NUMBER, OVERWRITE_LEFT); |
| 2473 GENERATE(Token::DIV, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT); |
| 2474 GENERATE(Token::DIV, SMI, SMI, NUMBER, NO_OVERWRITE); |
| 2475 GENERATE(Token::DIV, SMI, SMI, NUMBER, OVERWRITE_LEFT); |
| 2476 GENERATE(Token::DIV, SMI, SMI, NUMBER, OVERWRITE_RIGHT); |
| 2477 GENERATE(Token::DIV, SMI, SMI, SMI, NO_OVERWRITE); |
| 2478 GENERATE(Token::DIV, SMI, SMI, SMI, OVERWRITE_LEFT); |
| 2479 GENERATE(Token::DIV, SMI, SMI, SMI, OVERWRITE_RIGHT); |
| 2480 GENERATE(Token::MOD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT); |
| 2481 GENERATE(Token::MOD, SMI, SMI, SMI, NO_OVERWRITE); |
| 2482 GENERATE(Token::MOD, SMI, SMI, SMI, OVERWRITE_LEFT); |
| 2483 GENERATE(Token::MUL, INT32, INT32, INT32, NO_OVERWRITE); |
| 2484 GENERATE(Token::MUL, INT32, INT32, NUMBER, NO_OVERWRITE); |
| 2485 GENERATE(Token::MUL, INT32, NUMBER, NUMBER, NO_OVERWRITE); |
| 2486 GENERATE(Token::MUL, INT32, NUMBER, NUMBER, OVERWRITE_LEFT); |
| 2487 GENERATE(Token::MUL, INT32, SMI, INT32, NO_OVERWRITE); |
| 2488 GENERATE(Token::MUL, INT32, SMI, INT32, OVERWRITE_LEFT); |
| 2489 GENERATE(Token::MUL, INT32, SMI, NUMBER, NO_OVERWRITE); |
| 2490 GENERATE(Token::MUL, NUMBER, INT32, NUMBER, NO_OVERWRITE); |
| 2491 GENERATE(Token::MUL, NUMBER, INT32, NUMBER, OVERWRITE_LEFT); |
| 2492 GENERATE(Token::MUL, NUMBER, INT32, NUMBER, OVERWRITE_RIGHT); |
| 2493 GENERATE(Token::MUL, NUMBER, NUMBER, NUMBER, NO_OVERWRITE); |
| 2494 GENERATE(Token::MUL, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT); |
| 2495 GENERATE(Token::MUL, NUMBER, SMI, NUMBER, NO_OVERWRITE); |
| 2496 GENERATE(Token::MUL, NUMBER, SMI, NUMBER, OVERWRITE_LEFT); |
| 2497 GENERATE(Token::MUL, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT); |
| 2498 GENERATE(Token::MUL, SMI, INT32, INT32, NO_OVERWRITE); |
| 2499 GENERATE(Token::MUL, SMI, INT32, INT32, OVERWRITE_LEFT); |
| 2500 GENERATE(Token::MUL, SMI, INT32, NUMBER, NO_OVERWRITE); |
| 2501 GENERATE(Token::MUL, SMI, NUMBER, NUMBER, NO_OVERWRITE); |
| 2502 GENERATE(Token::MUL, SMI, NUMBER, NUMBER, OVERWRITE_LEFT); |
| 2503 GENERATE(Token::MUL, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT); |
| 2504 GENERATE(Token::MUL, SMI, SMI, INT32, NO_OVERWRITE); |
| 2505 GENERATE(Token::MUL, SMI, SMI, NUMBER, NO_OVERWRITE); |
| 2506 GENERATE(Token::MUL, SMI, SMI, NUMBER, OVERWRITE_LEFT); |
| 2507 GENERATE(Token::MUL, SMI, SMI, SMI, NO_OVERWRITE); |
| 2508 GENERATE(Token::MUL, SMI, SMI, SMI, OVERWRITE_LEFT); |
| 2509 GENERATE(Token::MUL, SMI, SMI, SMI, OVERWRITE_RIGHT); |
| 2510 GENERATE(Token::SAR, INT32, SMI, INT32, OVERWRITE_RIGHT); |
| 2511 GENERATE(Token::SAR, INT32, SMI, SMI, NO_OVERWRITE); |
| 2512 GENERATE(Token::SAR, INT32, SMI, SMI, OVERWRITE_RIGHT); |
| 2513 GENERATE(Token::SAR, NUMBER, SMI, SMI, NO_OVERWRITE); |
| 2514 GENERATE(Token::SAR, NUMBER, SMI, SMI, OVERWRITE_RIGHT); |
| 2515 GENERATE(Token::SAR, SMI, SMI, SMI, OVERWRITE_LEFT); |
| 2516 GENERATE(Token::SAR, SMI, SMI, SMI, OVERWRITE_RIGHT); |
| 2517 GENERATE(Token::SHL, INT32, SMI, INT32, NO_OVERWRITE); |
| 2518 GENERATE(Token::SHL, INT32, SMI, INT32, OVERWRITE_RIGHT); |
| 2519 GENERATE(Token::SHL, INT32, SMI, SMI, NO_OVERWRITE); |
| 2520 GENERATE(Token::SHL, INT32, SMI, SMI, OVERWRITE_RIGHT); |
| 2521 GENERATE(Token::SHL, NUMBER, SMI, SMI, OVERWRITE_RIGHT); |
| 2522 GENERATE(Token::SHL, SMI, SMI, INT32, NO_OVERWRITE); |
| 2523 GENERATE(Token::SHL, SMI, SMI, INT32, OVERWRITE_LEFT); |
| 2524 GENERATE(Token::SHL, SMI, SMI, INT32, OVERWRITE_RIGHT); |
| 2525 GENERATE(Token::SHL, SMI, SMI, SMI, NO_OVERWRITE); |
| 2526 GENERATE(Token::SHL, SMI, SMI, SMI, OVERWRITE_LEFT); |
| 2527 GENERATE(Token::SHL, SMI, SMI, SMI, OVERWRITE_RIGHT); |
| 2528 GENERATE(Token::SHR, INT32, SMI, SMI, NO_OVERWRITE); |
| 2529 GENERATE(Token::SHR, INT32, SMI, SMI, OVERWRITE_LEFT); |
| 2530 GENERATE(Token::SHR, INT32, SMI, SMI, OVERWRITE_RIGHT); |
| 2531 GENERATE(Token::SHR, NUMBER, SMI, SMI, NO_OVERWRITE); |
| 2532 GENERATE(Token::SHR, NUMBER, SMI, SMI, OVERWRITE_LEFT); |
| 2533 GENERATE(Token::SHR, NUMBER, SMI, INT32, OVERWRITE_RIGHT); |
| 2534 GENERATE(Token::SHR, SMI, SMI, SMI, NO_OVERWRITE); |
| 2535 GENERATE(Token::SHR, SMI, SMI, SMI, OVERWRITE_LEFT); |
| 2536 GENERATE(Token::SHR, SMI, SMI, SMI, OVERWRITE_RIGHT); |
| 2537 GENERATE(Token::SUB, INT32, INT32, INT32, NO_OVERWRITE); |
| 2538 GENERATE(Token::SUB, INT32, INT32, INT32, OVERWRITE_LEFT); |
| 2539 GENERATE(Token::SUB, INT32, NUMBER, NUMBER, NO_OVERWRITE); |
| 2540 GENERATE(Token::SUB, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT); |
| 2541 GENERATE(Token::SUB, INT32, SMI, INT32, OVERWRITE_LEFT); |
| 2542 GENERATE(Token::SUB, INT32, SMI, INT32, OVERWRITE_RIGHT); |
| 2543 GENERATE(Token::SUB, NUMBER, INT32, NUMBER, NO_OVERWRITE); |
| 2544 GENERATE(Token::SUB, NUMBER, INT32, NUMBER, OVERWRITE_LEFT); |
| 2545 GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER, NO_OVERWRITE); |
| 2546 GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT); |
| 2547 GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT); |
| 2548 GENERATE(Token::SUB, NUMBER, SMI, NUMBER, NO_OVERWRITE); |
| 2549 GENERATE(Token::SUB, NUMBER, SMI, NUMBER, OVERWRITE_LEFT); |
| 2550 GENERATE(Token::SUB, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT); |
| 2551 GENERATE(Token::SUB, SMI, INT32, INT32, NO_OVERWRITE); |
| 2552 GENERATE(Token::SUB, SMI, NUMBER, NUMBER, NO_OVERWRITE); |
| 2553 GENERATE(Token::SUB, SMI, NUMBER, NUMBER, OVERWRITE_LEFT); |
| 2554 GENERATE(Token::SUB, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT); |
| 2555 GENERATE(Token::SUB, SMI, SMI, SMI, NO_OVERWRITE); |
| 2556 GENERATE(Token::SUB, SMI, SMI, SMI, OVERWRITE_LEFT); |
| 2557 GENERATE(Token::SUB, SMI, SMI, SMI, OVERWRITE_RIGHT); |
| 2558 #undef GENERATE |
| 2559 #define GENERATE(op, left_kind, fixed_right_arg_value, result_kind, mode) \ |
| 2560 do { \ |
| 2561 State state(op, mode); \ |
| 2562 state.left_kind_ = left_kind; \ |
| 2563 state.fixed_right_arg_.has_value = true; \ |
| 2564 state.fixed_right_arg_.value = fixed_right_arg_value; \ |
| 2565 state.right_kind_ = SMI; \ |
| 2566 state.result_kind_ = result_kind; \ |
| 2567 Generate(isolate, state); \ |
| 2568 } while (false) |
| 2569 GENERATE(Token::MOD, SMI, 2, SMI, NO_OVERWRITE); |
| 2570 GENERATE(Token::MOD, SMI, 4, SMI, NO_OVERWRITE); |
| 2571 GENERATE(Token::MOD, SMI, 4, SMI, OVERWRITE_LEFT); |
| 2572 GENERATE(Token::MOD, SMI, 8, SMI, NO_OVERWRITE); |
| 2573 GENERATE(Token::MOD, SMI, 16, SMI, OVERWRITE_LEFT); |
| 2574 GENERATE(Token::MOD, SMI, 32, SMI, NO_OVERWRITE); |
| 2575 GENERATE(Token::MOD, SMI, 2048, SMI, NO_OVERWRITE); |
| 2576 #undef GENERATE |
| 2577 } |
| 2578 |
| 2579 |
| 2580 Handle<Type> BinaryOpIC::State::GetResultType(Isolate* isolate) const { |
| 2581 Kind result_kind = result_kind_; |
| 2582 if (HasSideEffects()) { |
| 2583 result_kind = NONE; |
| 2584 } else if (result_kind == GENERIC && op_ == Token::ADD) { |
| 2585 return handle(Type::Union(handle(Type::Number(), isolate), |
| 2586 handle(Type::String(), isolate)), isolate); |
| 2587 } else if (result_kind == NUMBER && op_ == Token::SHR) { |
| 2588 return handle(Type::Unsigned32(), isolate); |
| 2589 } |
| 2590 ASSERT_NE(GENERIC, result_kind); |
| 2591 return KindToType(result_kind, isolate); |
| 2592 } |
| 2593 |
| 2594 |
| 2595 void BinaryOpIC::State::Print(StringStream* stream) const { |
| 2596 stream->Add("(%s", Token::Name(op_)); |
| 2597 if (mode_ == OVERWRITE_LEFT) stream->Add("_ReuseLeft"); |
| 2598 else if (mode_ == OVERWRITE_RIGHT) stream->Add("_ReuseRight"); |
| 2599 stream->Add(":%s*", KindToString(left_kind_)); |
| 2600 if (fixed_right_arg_.has_value) { |
| 2601 stream->Add("%d", fixed_right_arg_.value); |
| 2602 } else { |
| 2603 stream->Add("%s", KindToString(right_kind_)); |
| 2604 } |
| 2605 stream->Add("->%s)", KindToString(result_kind_)); |
| 2606 } |
| 2607 |
| 2608 |
| 2609 void BinaryOpIC::State::Update(Handle<Object> left, |
| 2610 Handle<Object> right, |
| 2611 Handle<Object> result) { |
| 2612 ExtraICState old_extra_ic_state = GetExtraICState(); |
| 2613 |
| 2614 left_kind_ = UpdateKind(left, left_kind_); |
| 2615 right_kind_ = UpdateKind(right, right_kind_); |
| 2616 |
| 2617 int32_t fixed_right_arg_value = 0; |
| 2618 bool has_fixed_right_arg = |
| 2619 op_ == Token::MOD && |
| 2620 right->ToInt32(&fixed_right_arg_value) && |
| 2621 fixed_right_arg_value > 0 && |
| 2622 IsPowerOf2(fixed_right_arg_value) && |
| 2623 FixedRightArgValueField::is_valid(WhichPowerOf2(fixed_right_arg_value)) && |
| 2624 (left_kind_ == SMI || left_kind_ == INT32) && |
| 2625 (result_kind_ == NONE || !fixed_right_arg_.has_value); |
| 2626 fixed_right_arg_ = Maybe<int32_t>(has_fixed_right_arg, |
| 2627 fixed_right_arg_value); |
| 2628 |
| 2629 result_kind_ = UpdateKind(result, result_kind_); |
| 2630 |
| 2631 if (!Token::IsTruncatingBinaryOp(op_)) { |
| 2632 Kind input_kind = Max(left_kind_, right_kind_); |
| 2633 if (result_kind_ < input_kind && input_kind <= NUMBER) { |
| 2634 result_kind_ = input_kind; |
| 2635 } |
| 2636 } |
| 2637 |
| 2638 // Reset overwrite mode unless we can actually make use of it, or may be able |
| 2639 // to make use of it at some point in the future. |
| 2640 if ((mode_ == OVERWRITE_LEFT && left_kind_ > NUMBER) || |
| 2641 (mode_ == OVERWRITE_RIGHT && right_kind_ > NUMBER) || |
| 2642 result_kind_ > NUMBER) { |
| 2643 mode_ = NO_OVERWRITE; |
| 2644 } |
| 2645 |
| 2646 if (old_extra_ic_state == GetExtraICState()) { |
| 2647 // Tagged operations can lead to non-truncating HChanges |
| 2648 if (left->IsUndefined() || left->IsBoolean()) { |
| 2649 left_kind_ = GENERIC; |
| 2650 } else if (right->IsUndefined() || right->IsBoolean()) { |
| 2651 right_kind_ = GENERIC; |
| 2652 } else { |
| 2653 // Since the X87 is too precise, we might bail out on numbers which |
| 2654 // actually would truncate with 64 bit precision. |
| 2655 ASSERT(!CpuFeatures::IsSupported(SSE2)); |
| 2656 ASSERT(result_kind_ < NUMBER); |
| 2657 result_kind_ = NUMBER; |
| 2658 } |
| 2659 } |
| 2660 } |
| 2661 |
| 2662 |
| 2663 BinaryOpIC::State::Kind BinaryOpIC::State::UpdateKind(Handle<Object> object, |
| 2664 Kind kind) const { |
| 2665 Kind new_kind = GENERIC; |
| 2666 bool is_truncating = Token::IsTruncatingBinaryOp(op()); |
| 2667 if (object->IsBoolean() && is_truncating) { |
| 2668 // Booleans will be automatically truncated by HChange. |
| 2669 new_kind = INT32; |
| 2670 } else if (object->IsUndefined()) { |
| 2671 // Undefined will be automatically truncated by HChange. |
| 2672 new_kind = is_truncating ? INT32 : NUMBER; |
| 2673 } else if (object->IsSmi()) { |
| 2674 new_kind = SMI; |
| 2675 } else if (object->IsHeapNumber()) { |
| 2676 double value = Handle<HeapNumber>::cast(object)->value(); |
| 2677 new_kind = TypeInfo::IsInt32Double(value) ? INT32 : NUMBER; |
| 2678 } else if (object->IsString() && op() == Token::ADD) { |
| 2679 new_kind = STRING; |
| 2680 } |
| 2681 if (new_kind == INT32 && SmiValuesAre32Bits()) { |
| 2682 new_kind = NUMBER; |
| 2683 } |
| 2684 if (kind != NONE && |
| 2685 ((new_kind <= NUMBER && kind > NUMBER) || |
| 2686 (new_kind > NUMBER && kind <= NUMBER))) { |
| 2687 new_kind = GENERIC; |
| 2688 } |
| 2689 return Max(kind, new_kind); |
| 2690 } |
| 2691 |
| 2692 |
| 2693 // static |
| 2694 const char* BinaryOpIC::State::KindToString(Kind kind) { |
| 2695 switch (kind) { |
| 2696 case NONE: return "None"; |
| 2327 case SMI: return "Smi"; | 2697 case SMI: return "Smi"; |
| 2328 case INT32: return "Int32"; | 2698 case INT32: return "Int32"; |
| 2329 case NUMBER: return "Number"; | 2699 case NUMBER: return "Number"; |
| 2330 case ODDBALL: return "Oddball"; | |
| 2331 case STRING: return "String"; | 2700 case STRING: return "String"; |
| 2332 case GENERIC: return "Generic"; | 2701 case GENERIC: return "Generic"; |
| 2333 default: return "Invalid"; | 2702 } |
| 2334 } | 2703 UNREACHABLE(); |
| 2704 return NULL; |
| 2705 } |
| 2706 |
| 2707 |
| 2708 // static |
| 2709 Handle<Type> BinaryOpIC::State::KindToType(Kind kind, Isolate* isolate) { |
| 2710 Type* type = NULL; |
| 2711 switch (kind) { |
| 2712 case NONE: type = Type::None(); break; |
| 2713 case SMI: type = Type::Smi(); break; |
| 2714 case INT32: type = Type::Signed32(); break; |
| 2715 case NUMBER: type = Type::Number(); break; |
| 2716 case STRING: type = Type::String(); break; |
| 2717 case GENERIC: type = Type::Any(); break; |
| 2718 } |
| 2719 return handle(type, isolate); |
| 2335 } | 2720 } |
| 2336 | 2721 |
| 2337 | 2722 |
| 2338 MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) { | 2723 MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) { |
| 2339 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state(); | 2724 State state(target()->extended_extra_ic_state()); |
| 2340 BinaryOpStub stub(extra_ic_state); | 2725 |
| 2341 | 2726 // Compute the actual result using the builtin for the binary operation. |
| 2342 Handle<Type> left_type = stub.GetLeftType(isolate()); | 2727 Object* builtin = isolate()->js_builtins_object()->javascript_builtin( |
| 2343 Handle<Type> right_type = stub.GetRightType(isolate()); | 2728 TokenToJSBuiltin(state.op())); |
| 2344 bool smi_was_enabled = left_type->Maybe(Type::Smi()) && | 2729 Handle<JSFunction> function = handle(JSFunction::cast(builtin), isolate()); |
| 2345 right_type->Maybe(Type::Smi()); | 2730 bool caught_exception; |
| 2346 | 2731 Handle<Object> result = Execution::Call( |
| 2347 Maybe<Handle<Object> > result = stub.Result(left, right, isolate()); | 2732 isolate(), function, left, 1, &right, &caught_exception); |
| 2348 if (!result.has_value) return Failure::Exception(); | 2733 if (caught_exception) return Failure::Exception(); |
| 2349 | 2734 |
| 2350 #ifdef DEBUG | 2735 // Compute the new state. |
| 2736 State old_state = state; |
| 2737 state.Update(left, right, result); |
| 2738 |
| 2739 // Install the new stub. |
| 2740 BinaryOpICStub stub(state); |
| 2741 set_target(*stub.GetCode(isolate())); |
| 2742 |
| 2351 if (FLAG_trace_ic) { | 2743 if (FLAG_trace_ic) { |
| 2352 char buffer[100]; | 2744 char buffer[150]; |
| 2353 NoAllocationStringAllocator allocator(buffer, | 2745 NoAllocationStringAllocator allocator( |
| 2354 static_cast<unsigned>(sizeof(buffer))); | 2746 buffer, static_cast<unsigned>(sizeof(buffer))); |
| 2355 StringStream stream(&allocator); | 2747 StringStream stream(&allocator); |
| 2356 stream.Add("["); | 2748 stream.Add("[BinaryOpIC"); |
| 2357 stub.PrintName(&stream); | 2749 old_state.Print(&stream); |
| 2358 | |
| 2359 stub.UpdateStatus(left, right, result); | |
| 2360 | |
| 2361 stream.Add(" => "); | 2750 stream.Add(" => "); |
| 2362 stub.PrintState(&stream); | 2751 state.Print(&stream); |
| 2363 stream.Add(" "); | 2752 stream.Add(" @ %p <- ", static_cast<void*>(*target())); |
| 2364 stream.OutputToStdOut(); | 2753 stream.OutputToStdOut(); |
| 2365 PrintF(" @ %p <- ", static_cast<void*>(*stub.GetCode(isolate()))); | |
| 2366 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); | 2754 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); |
| 2367 PrintF("]\n"); | 2755 PrintF("]\n"); |
| 2368 } else { | 2756 } |
| 2369 stub.UpdateStatus(left, right, result); | 2757 |
| 2370 } | 2758 // Patch the inlined smi code as necessary. |
| 2371 #else | 2759 if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) { |
| 2372 stub.UpdateStatus(left, right, result); | |
| 2373 #endif | |
| 2374 | |
| 2375 Handle<Code> code = stub.GetCode(isolate()); | |
| 2376 set_target(*code); | |
| 2377 | |
| 2378 left_type = stub.GetLeftType(isolate()); | |
| 2379 right_type = stub.GetRightType(isolate()); | |
| 2380 bool enable_smi = left_type->Maybe(Type::Smi()) && | |
| 2381 right_type->Maybe(Type::Smi()); | |
| 2382 | |
| 2383 if (!smi_was_enabled && enable_smi) { | |
| 2384 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); | 2760 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
| 2385 } else if (smi_was_enabled && !enable_smi) { | 2761 } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) { |
| 2386 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK); | 2762 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK); |
| 2387 } | 2763 } |
| 2388 | 2764 |
| 2389 ASSERT(result.has_value); | 2765 return *result; |
| 2390 return static_cast<MaybeObject*>(*result.value); | |
| 2391 } | 2766 } |
| 2392 | 2767 |
| 2393 | 2768 |
| 2394 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) { | 2769 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) { |
| 2395 HandleScope scope(isolate); | 2770 HandleScope scope(isolate); |
| 2396 Handle<Object> left = args.at<Object>(0); | 2771 Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft); |
| 2397 Handle<Object> right = args.at<Object>(1); | 2772 Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight); |
| 2398 BinaryOpIC ic(isolate); | 2773 BinaryOpIC ic(isolate); |
| 2399 return ic.Transition(left, right); | 2774 return ic.Transition(left, right); |
| 2400 } | 2775 } |
| 2401 | 2776 |
| 2402 | 2777 |
| 2403 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { | 2778 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { |
| 2404 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2779 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
| 2405 Code* code = NULL; | 2780 Code* code = NULL; |
| 2406 CHECK(stub.FindCodeInCache(&code, isolate)); | 2781 CHECK(stub.FindCodeInCache(&code, isolate)); |
| 2407 return code; | 2782 return code; |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2592 State state = TargetState(previous_state, previous_left, previous_right, | 2967 State state = TargetState(previous_state, previous_left, previous_right, |
| 2593 HasInlinedSmiCode(address()), x, y); | 2968 HasInlinedSmiCode(address()), x, y); |
| 2594 ICCompareStub stub(op_, new_left, new_right, state); | 2969 ICCompareStub stub(op_, new_left, new_right, state); |
| 2595 if (state == KNOWN_OBJECT) { | 2970 if (state == KNOWN_OBJECT) { |
| 2596 stub.set_known_map( | 2971 stub.set_known_map( |
| 2597 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate())); | 2972 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate())); |
| 2598 } | 2973 } |
| 2599 Handle<Code> new_target = stub.GetCode(isolate()); | 2974 Handle<Code> new_target = stub.GetCode(isolate()); |
| 2600 set_target(*new_target); | 2975 set_target(*new_target); |
| 2601 | 2976 |
| 2602 #ifdef DEBUG | |
| 2603 if (FLAG_trace_ic) { | 2977 if (FLAG_trace_ic) { |
| 2604 PrintF("[CompareIC in "); | 2978 PrintF("[CompareIC in "); |
| 2605 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); | 2979 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); |
| 2606 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n", | 2980 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n", |
| 2607 GetStateName(previous_left), | 2981 GetStateName(previous_left), |
| 2608 GetStateName(previous_right), | 2982 GetStateName(previous_right), |
| 2609 GetStateName(previous_state), | 2983 GetStateName(previous_state), |
| 2610 GetStateName(new_left), | 2984 GetStateName(new_left), |
| 2611 GetStateName(new_right), | 2985 GetStateName(new_right), |
| 2612 GetStateName(state), | 2986 GetStateName(state), |
| 2613 Token::Name(op_), | 2987 Token::Name(op_), |
| 2614 static_cast<void*>(*stub.GetCode(isolate()))); | 2988 static_cast<void*>(*stub.GetCode(isolate()))); |
| 2615 } | 2989 } |
| 2616 #endif | |
| 2617 | 2990 |
| 2618 // Activate inlined smi code. | 2991 // Activate inlined smi code. |
| 2619 if (previous_state == UNINITIALIZED) { | 2992 if (previous_state == UNINITIALIZED) { |
| 2620 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); | 2993 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
| 2621 } | 2994 } |
| 2622 | 2995 |
| 2623 return *new_target; | 2996 return *new_target; |
| 2624 } | 2997 } |
| 2625 | 2998 |
| 2626 | 2999 |
| 2627 // Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc. | 3000 // Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc. |
| 2628 RUNTIME_FUNCTION(Code*, CompareIC_Miss) { | 3001 RUNTIME_FUNCTION(Code*, CompareIC_Miss) { |
| 2629 HandleScope scope(isolate); | 3002 HandleScope scope(isolate); |
| 2630 ASSERT(args.length() == 3); | 3003 ASSERT(args.length() == 3); |
| 2631 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2))); | 3004 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2))); |
| 2632 return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); | 3005 return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); |
| 2633 } | 3006 } |
| 2634 | 3007 |
| 2635 | 3008 |
| 2636 void CompareNilIC::Clear(Address address, Code* target) { | 3009 void CompareNilIC::Clear(Address address, Code* target) { |
| 2637 if (IsCleared(target)) return; | 3010 if (IsCleared(target)) return; |
| 2638 Code::ExtraICState state = target->extended_extra_ic_state(); | 3011 ExtraICState state = target->extended_extra_ic_state(); |
| 2639 | 3012 |
| 2640 CompareNilICStub stub(state, HydrogenCodeStub::UNINITIALIZED); | 3013 CompareNilICStub stub(state, HydrogenCodeStub::UNINITIALIZED); |
| 2641 stub.ClearState(); | 3014 stub.ClearState(); |
| 2642 | 3015 |
| 2643 Code* code = NULL; | 3016 Code* code = NULL; |
| 2644 CHECK(stub.FindCodeInCache(&code, target->GetIsolate())); | 3017 CHECK(stub.FindCodeInCache(&code, target->GetIsolate())); |
| 2645 | 3018 |
| 2646 SetTargetAtAddress(address, code); | 3019 SetTargetAtAddress(address, code); |
| 2647 } | 3020 } |
| 2648 | 3021 |
| 2649 | 3022 |
| 2650 MaybeObject* CompareNilIC::DoCompareNilSlow(NilValue nil, | 3023 MaybeObject* CompareNilIC::DoCompareNilSlow(NilValue nil, |
| 2651 Handle<Object> object) { | 3024 Handle<Object> object) { |
| 2652 if (object->IsNull() || object->IsUndefined()) { | 3025 if (object->IsNull() || object->IsUndefined()) { |
| 2653 return Smi::FromInt(true); | 3026 return Smi::FromInt(true); |
| 2654 } | 3027 } |
| 2655 return Smi::FromInt(object->IsUndetectableObject()); | 3028 return Smi::FromInt(object->IsUndetectableObject()); |
| 2656 } | 3029 } |
| 2657 | 3030 |
| 2658 | 3031 |
| 2659 MaybeObject* CompareNilIC::CompareNil(Handle<Object> object) { | 3032 MaybeObject* CompareNilIC::CompareNil(Handle<Object> object) { |
| 2660 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state(); | 3033 ExtraICState extra_ic_state = target()->extended_extra_ic_state(); |
| 2661 | 3034 |
| 2662 CompareNilICStub stub(extra_ic_state); | 3035 CompareNilICStub stub(extra_ic_state); |
| 2663 | 3036 |
| 2664 // Extract the current supported types from the patched IC and calculate what | 3037 // Extract the current supported types from the patched IC and calculate what |
| 2665 // types must be supported as a result of the miss. | 3038 // types must be supported as a result of the miss. |
| 2666 bool already_monomorphic = stub.IsMonomorphic(); | 3039 bool already_monomorphic = stub.IsMonomorphic(); |
| 2667 | 3040 |
| 2668 stub.UpdateStatus(object); | 3041 stub.UpdateStatus(object); |
| 2669 | 3042 |
| 2670 NilValue nil = stub.GetNilValue(); | 3043 NilValue nil = stub.GetNilValue(); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2765 #undef ADDR | 3138 #undef ADDR |
| 2766 }; | 3139 }; |
| 2767 | 3140 |
| 2768 | 3141 |
| 2769 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 3142 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2770 return IC_utilities[id]; | 3143 return IC_utilities[id]; |
| 2771 } | 3144 } |
| 2772 | 3145 |
| 2773 | 3146 |
| 2774 } } // namespace v8::internal | 3147 } } // namespace v8::internal |
| OLD | NEW |