| 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 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 break; | 263 break; |
| 264 default: | 264 default: |
| 265 return false; | 265 return false; |
| 266 } | 266 } |
| 267 return false; | 267 return false; |
| 268 } | 268 } |
| 269 | 269 |
| 270 | 270 |
| 271 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver, | 271 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver, |
| 272 Handle<String> name) { | 272 Handle<String> name) { |
| 273 DisallowHeapAllocation no_gc; | |
| 274 | |
| 275 if (target()->is_call_stub()) { | 273 if (target()->is_call_stub()) { |
| 276 LookupResult lookup(isolate()); | 274 LookupResult lookup(isolate()); |
| 277 LookupForRead(receiver, name, &lookup); | 275 LookupForRead(receiver, name, &lookup); |
| 278 if (static_cast<CallIC*>(this)->TryUpdateExtraICState(&lookup, receiver)) { | 276 if (static_cast<CallIC*>(this)->TryUpdateExtraICState(&lookup, receiver)) { |
| 279 return true; | 277 return true; |
| 280 } | 278 } |
| 281 } | 279 } |
| 282 | 280 |
| 283 if (target()->is_keyed_stub()) { | 281 if (target()->is_keyed_stub()) { |
| 284 // Determine whether the failure is due to a name failure. | 282 // Determine whether the failure is due to a name failure. |
| (...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 761 target()->arguments_count(), kind_, extra_ic_state()); | 759 target()->arguments_count(), kind_, extra_ic_state()); |
| 762 } | 760 } |
| 763 | 761 |
| 764 | 762 |
| 765 void CallICBase::UpdateCaches(LookupResult* lookup, | 763 void CallICBase::UpdateCaches(LookupResult* lookup, |
| 766 Handle<Object> object, | 764 Handle<Object> object, |
| 767 Handle<String> name) { | 765 Handle<String> name) { |
| 768 // Bail out if we didn't find a result. | 766 // Bail out if we didn't find a result. |
| 769 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | 767 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
| 770 | 768 |
| 771 // Compute the number of arguments. | 769 if (state() == UNINITIALIZED) { |
| 772 Handle<Code> code; | 770 set_target(*pre_monomorphic_stub()); |
| 773 code = state() == UNINITIALIZED | 771 TRACE_IC("CallIC", name); |
| 774 ? pre_monomorphic_stub() | 772 return; |
| 775 : ComputeMonomorphicStub(lookup, object, name); | 773 } |
| 776 | 774 |
| 775 Handle<Code> code = ComputeMonomorphicStub(lookup, object, name); |
| 777 // If there's no appropriate stub we simply avoid updating the caches. | 776 // If there's no appropriate stub we simply avoid updating the caches. |
| 778 // TODO(verwaest): Install a slow fallback in this case to avoid not learning, | 777 // TODO(verwaest): Install a slow fallback in this case to avoid not learning, |
| 779 // and deopting Crankshaft code. | 778 // and deopting Crankshaft code. |
| 780 if (code.is_null()) return; | 779 if (code.is_null()) return; |
| 781 | 780 |
| 782 Handle<JSObject> cache_object = object->IsJSObject() | 781 Handle<JSObject> cache_object = object->IsJSObject() |
| 783 ? Handle<JSObject>::cast(object) | 782 ? Handle<JSObject>::cast(object) |
| 784 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())), | 783 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())), |
| 785 isolate()); | 784 isolate()); |
| 786 | 785 |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 947 } | 946 } |
| 948 receiver_maps->Add(new_receiver_map); | 947 receiver_maps->Add(new_receiver_map); |
| 949 return true; | 948 return true; |
| 950 } | 949 } |
| 951 | 950 |
| 952 | 951 |
| 953 bool IC::UpdatePolymorphicIC(Handle<HeapObject> receiver, | 952 bool IC::UpdatePolymorphicIC(Handle<HeapObject> receiver, |
| 954 Handle<String> name, | 953 Handle<String> name, |
| 955 Handle<Code> code) { | 954 Handle<Code> code) { |
| 956 if (!code->is_handler()) return false; | 955 if (!code->is_handler()) return false; |
| 957 | |
| 958 MapHandleList receiver_maps; | 956 MapHandleList receiver_maps; |
| 959 CodeHandleList handlers; | 957 CodeHandleList handlers; |
| 960 | 958 |
| 961 int number_of_valid_maps; | 959 int number_of_valid_maps; |
| 962 int handler_to_overwrite = -1; | 960 int handler_to_overwrite = -1; |
| 963 Handle<Map> new_receiver_map(receiver->map()); | 961 Handle<Map> new_receiver_map(receiver->map()); |
| 964 { | |
| 965 DisallowHeapAllocation no_gc; | |
| 966 target()->FindAllMaps(&receiver_maps); | |
| 967 int number_of_maps = receiver_maps.length(); | |
| 968 number_of_valid_maps = number_of_maps; | |
| 969 | 962 |
| 970 for (int i = 0; i < number_of_maps; i++) { | 963 target()->FindAllMaps(&receiver_maps); |
| 971 Handle<Map> map = receiver_maps.at(i); | 964 int number_of_maps = receiver_maps.length(); |
| 972 // Filter out deprecated maps to ensure its instances get migrated. | 965 number_of_valid_maps = number_of_maps; |
| 973 if (map->is_deprecated()) { | |
| 974 number_of_valid_maps--; | |
| 975 // If the receiver map is already in the polymorphic IC, this indicates | |
| 976 // there was a prototoype chain failure. In that case, just overwrite the | |
| 977 // handler. | |
| 978 } else if (map.is_identical_to(new_receiver_map)) { | |
| 979 number_of_valid_maps--; | |
| 980 handler_to_overwrite = i; | |
| 981 } | |
| 982 } | |
| 983 | 966 |
| 984 if (number_of_valid_maps >= 4) return false; | 967 for (int i = 0; i < number_of_maps; i++) { |
| 985 if (number_of_maps == 0) return false; | 968 Handle<Map> map = receiver_maps.at(i); |
| 986 | 969 // Filter out deprecated maps to ensure its instances get migrated. |
| 987 if (!target()->FindHandlers(&handlers, receiver_maps.length())) { | 970 if (map->is_deprecated()) { |
| 988 return false; | 971 number_of_valid_maps--; |
| 972 // If the receiver map is already in the polymorphic IC, this indicates |
| 973 // there was a prototoype chain failure. In that case, just overwrite the |
| 974 // handler. |
| 975 } else if (map.is_identical_to(new_receiver_map)) { |
| 976 number_of_valid_maps--; |
| 977 handler_to_overwrite = i; |
| 989 } | 978 } |
| 990 } | 979 } |
| 991 | 980 |
| 981 if (number_of_valid_maps >= 4) return false; |
| 982 if (number_of_maps == 0) return false; |
| 983 |
| 984 if (!target()->FindHandlers(&handlers, receiver_maps.length())) { |
| 985 return false; |
| 986 } |
| 987 |
| 992 number_of_valid_maps++; | 988 number_of_valid_maps++; |
| 993 if (handler_to_overwrite >= 0) { | 989 if (handler_to_overwrite >= 0) { |
| 994 handlers.Set(handler_to_overwrite, code); | 990 handlers.Set(handler_to_overwrite, code); |
| 995 } else { | 991 } else { |
| 996 receiver_maps.Add(new_receiver_map); | 992 receiver_maps.Add(new_receiver_map); |
| 997 handlers.Add(code); | 993 handlers.Add(code); |
| 998 } | 994 } |
| 999 | 995 |
| 1000 Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC( | 996 Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC( |
| 1001 &receiver_maps, &handlers, number_of_valid_maps, name, strict_mode()); | 997 &receiver_maps, &handlers, number_of_valid_maps, name, strict_mode()); |
| 1002 set_target(*ic); | 998 set_target(*ic); |
| 1003 return true; | 999 return true; |
| 1004 } | 1000 } |
| 1005 | 1001 |
| 1006 | 1002 |
| 1007 void IC::UpdateMonomorphicIC(Handle<HeapObject> receiver, | 1003 void IC::UpdateMonomorphicIC(Handle<HeapObject> receiver, |
| 1008 Handle<Code> handler, | 1004 Handle<Code> handler, |
| 1009 Handle<String> name) { | 1005 Handle<String> name) { |
| 1010 if (!handler->is_handler()) return set_target(*handler); | 1006 if (!handler->is_handler()) return set_target(*handler); |
| 1011 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC( | 1007 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC( |
| 1012 receiver, handler, name, strict_mode()); | 1008 receiver, handler, name, strict_mode()); |
| 1013 set_target(*ic); | 1009 set_target(*ic); |
| 1014 } | 1010 } |
| 1015 | 1011 |
| 1016 | 1012 |
| 1017 void IC::CopyICToMegamorphicCache(Handle<String> name) { | 1013 void IC::CopyICToMegamorphicCache(Handle<String> name) { |
| 1018 MapHandleList receiver_maps; | 1014 MapHandleList receiver_maps; |
| 1019 CodeHandleList handlers; | 1015 CodeHandleList handlers; |
| 1020 { | 1016 target()->FindAllMaps(&receiver_maps); |
| 1021 DisallowHeapAllocation no_gc; | 1017 if (!target()->FindHandlers(&handlers, receiver_maps.length())) return; |
| 1022 target()->FindAllMaps(&receiver_maps); | |
| 1023 if (!target()->FindHandlers(&handlers, receiver_maps.length())) return; | |
| 1024 } | |
| 1025 for (int i = 0; i < receiver_maps.length(); i++) { | 1018 for (int i = 0; i < receiver_maps.length(); i++) { |
| 1026 UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i)); | 1019 UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i)); |
| 1027 } | 1020 } |
| 1028 } | 1021 } |
| 1029 | 1022 |
| 1030 | 1023 |
| 1031 bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) { | 1024 bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) { |
| 1032 DisallowHeapAllocation no_allocation; | |
| 1033 | |
| 1034 Map* current_map = target()->FindFirstMap(); | 1025 Map* current_map = target()->FindFirstMap(); |
| 1035 ElementsKind receiver_elements_kind = receiver_map->elements_kind(); | 1026 ElementsKind receiver_elements_kind = receiver_map->elements_kind(); |
| 1036 bool more_general_transition = | 1027 bool more_general_transition = |
| 1037 IsMoreGeneralElementsKindTransition( | 1028 IsMoreGeneralElementsKindTransition( |
| 1038 current_map->elements_kind(), receiver_elements_kind); | 1029 current_map->elements_kind(), receiver_elements_kind); |
| 1039 Map* transitioned_map = more_general_transition | 1030 Map* transitioned_map = more_general_transition |
| 1040 ? current_map->LookupElementsTransitionMap(receiver_elements_kind) | 1031 ? current_map->LookupElementsTransitionMap(receiver_elements_kind) |
| 1041 : NULL; | 1032 : NULL; |
| 1042 | 1033 |
| 1043 return transitioned_map == receiver_map; | 1034 return transitioned_map == receiver_map; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1054 UpdateMonomorphicIC(receiver, code, name); | 1045 UpdateMonomorphicIC(receiver, code, name); |
| 1055 break; | 1046 break; |
| 1056 case MONOMORPHIC: | 1047 case MONOMORPHIC: |
| 1057 // For now, call stubs are allowed to rewrite to the same stub. This | 1048 // For now, call stubs are allowed to rewrite to the same stub. This |
| 1058 // happens e.g., when the field does not contain a function. | 1049 // happens e.g., when the field does not contain a function. |
| 1059 ASSERT(target()->is_call_stub() || | 1050 ASSERT(target()->is_call_stub() || |
| 1060 target()->is_keyed_call_stub() || | 1051 target()->is_keyed_call_stub() || |
| 1061 !target().is_identical_to(code)); | 1052 !target().is_identical_to(code)); |
| 1062 if (!target()->is_keyed_stub()) { | 1053 if (!target()->is_keyed_stub()) { |
| 1063 bool is_same_handler = false; | 1054 bool is_same_handler = false; |
| 1064 { | 1055 Code* old_handler = target()->FindFirstHandler(); |
| 1065 DisallowHeapAllocation no_allocation; | 1056 is_same_handler = old_handler == *code; |
| 1066 Code* old_handler = target()->FindFirstHandler(); | 1057 |
| 1067 is_same_handler = old_handler == *code; | 1058 if (is_same_handler && |
| 1068 } | 1059 IsTransitionedMapOfMonomorphicTarget(receiver->map())) { |
| 1069 if (is_same_handler | |
| 1070 && IsTransitionedMapOfMonomorphicTarget(receiver->map())) { | |
| 1071 UpdateMonomorphicIC(receiver, code, name); | 1060 UpdateMonomorphicIC(receiver, code, name); |
| 1072 break; | 1061 break; |
| 1073 } | 1062 } |
| 1074 if (UpdatePolymorphicIC(receiver, name, code)) { | 1063 } |
| 1075 break; | 1064 // Fall through. |
| 1076 } | 1065 case POLYMORPHIC: |
| 1077 | 1066 if (!target()->is_keyed_stub()) { |
| 1067 if (UpdatePolymorphicIC(receiver, name, code)) break; |
| 1078 CopyICToMegamorphicCache(name); | 1068 CopyICToMegamorphicCache(name); |
| 1079 } | 1069 } |
| 1080 | |
| 1081 UpdateMegamorphicCache(receiver->map(), *name, *code); | |
| 1082 set_target(*megamorphic_stub()); | 1070 set_target(*megamorphic_stub()); |
| 1083 break; | 1071 // Fall through. |
| 1084 case MEGAMORPHIC: | 1072 case MEGAMORPHIC: |
| 1085 UpdateMegamorphicCache(receiver->map(), *name, *code); | 1073 UpdateMegamorphicCache(receiver->map(), *name, *code); |
| 1086 break; | 1074 break; |
| 1087 case POLYMORPHIC: | |
| 1088 if (target()->is_keyed_stub()) { | |
| 1089 // When trying to patch a polymorphic keyed stub with anything other | |
| 1090 // than another polymorphic stub, go generic. | |
| 1091 set_target(*generic_stub()); | |
| 1092 } else { | |
| 1093 if (UpdatePolymorphicIC(receiver, name, code)) { | |
| 1094 break; | |
| 1095 } | |
| 1096 CopyICToMegamorphicCache(name); | |
| 1097 UpdateMegamorphicCache(receiver->map(), *name, *code); | |
| 1098 set_target(*megamorphic_stub()); | |
| 1099 } | |
| 1100 break; | |
| 1101 case DEBUG_STUB: | 1075 case DEBUG_STUB: |
| 1102 break; | 1076 break; |
| 1103 case GENERIC: | 1077 case GENERIC: |
| 1104 UNREACHABLE(); | 1078 UNREACHABLE(); |
| 1105 break; | 1079 break; |
| 1106 } | 1080 } |
| 1107 } | 1081 } |
| 1108 | 1082 |
| 1109 | 1083 |
| 1110 Handle<Code> LoadIC::SimpleFieldLoad(int offset, | 1084 Handle<Code> LoadIC::SimpleFieldLoad(int offset, |
| 1111 bool inobject, | 1085 bool inobject, |
| 1112 Representation representation) { | 1086 Representation representation) { |
| 1113 if (kind() == Code::LOAD_IC) { | 1087 if (kind() == Code::LOAD_IC) { |
| 1114 LoadFieldStub stub(inobject, offset, representation); | 1088 LoadFieldStub stub(inobject, offset, representation); |
| 1115 return stub.GetCode(isolate()); | 1089 return stub.GetCode(isolate()); |
| 1116 } else { | 1090 } else { |
| 1117 KeyedLoadFieldStub stub(inobject, offset, representation); | 1091 KeyedLoadFieldStub stub(inobject, offset, representation); |
| 1118 return stub.GetCode(isolate()); | 1092 return stub.GetCode(isolate()); |
| 1119 } | 1093 } |
| 1120 } | 1094 } |
| 1121 | 1095 |
| 1096 |
| 1122 void LoadIC::UpdateCaches(LookupResult* lookup, | 1097 void LoadIC::UpdateCaches(LookupResult* lookup, |
| 1123 Handle<Object> object, | 1098 Handle<Object> object, |
| 1124 Handle<String> name) { | 1099 Handle<String> name) { |
| 1125 // TODO(verwaest): It would be nice to support loading fields from smis as | 1100 // TODO(verwaest): It would be nice to support loading fields from smis as |
| 1126 // well. For now just fail to update the cache. | 1101 // well. For now just fail to update the cache. |
| 1127 if (!object->IsHeapObject()) return; | 1102 if (!object->IsHeapObject()) return; |
| 1128 | 1103 |
| 1129 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object); | 1104 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object); |
| 1130 | 1105 |
| 1131 Handle<Code> code; | 1106 Handle<Code> code; |
| 1132 if (state() == UNINITIALIZED) { | 1107 if (state() == UNINITIALIZED) { |
| 1133 // This is the first time we execute this inline cache. | 1108 // This is the first time we execute this inline cache. |
| 1134 // Set the target to the pre monomorphic stub to delay | 1109 // Set the target to the pre monomorphic stub to delay |
| 1135 // setting the monomorphic state. | 1110 // setting the monomorphic state. |
| 1136 code = pre_monomorphic_stub(); | 1111 set_target(*pre_monomorphic_stub()); |
| 1112 TRACE_IC("LoadIC", name); |
| 1113 return; |
| 1137 } else if (!lookup->IsCacheable()) { | 1114 } else if (!lookup->IsCacheable()) { |
| 1138 // Bail out if the result is not cacheable. | 1115 // Bail out if the result is not cacheable. |
| 1139 code = slow_stub(); | 1116 code = slow_stub(); |
| 1140 } else if (object->IsString() && | 1117 } else if (object->IsString() && |
| 1141 name->Equals(isolate()->heap()->length_string())) { | 1118 name->Equals(isolate()->heap()->length_string())) { |
| 1142 int length_index = String::kLengthOffset / kPointerSize; | 1119 int length_index = String::kLengthOffset / kPointerSize; |
| 1143 code = SimpleFieldLoad(length_index); | 1120 code = SimpleFieldLoad(length_index); |
| 1144 } else if (!object->IsJSObject()) { | 1121 } else if (!object->IsJSObject()) { |
| 1145 // TODO(jkummerow): It would be nice to support non-JSObjects in | 1122 // TODO(jkummerow): It would be nice to support non-JSObjects in |
| 1146 // ComputeLoadHandler, then we wouldn't need to go generic here. | 1123 // ComputeLoadHandler, then we wouldn't need to go generic here. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1168 | 1145 |
| 1169 Handle<Code> IC::ComputeHandler(LookupResult* lookup, | 1146 Handle<Code> IC::ComputeHandler(LookupResult* lookup, |
| 1170 Handle<JSObject> receiver, | 1147 Handle<JSObject> receiver, |
| 1171 Handle<String> name, | 1148 Handle<String> name, |
| 1172 Handle<Object> value) { | 1149 Handle<Object> value) { |
| 1173 Handle<Code> code = isolate()->stub_cache()->FindHandler( | 1150 Handle<Code> code = isolate()->stub_cache()->FindHandler( |
| 1174 name, receiver, kind()); | 1151 name, receiver, kind()); |
| 1175 if (!code.is_null()) return code; | 1152 if (!code.is_null()) return code; |
| 1176 | 1153 |
| 1177 code = CompileHandler(lookup, receiver, name, value); | 1154 code = CompileHandler(lookup, receiver, name, value); |
| 1155 ASSERT(code->is_handler()); |
| 1178 | 1156 |
| 1179 if (code->is_handler() && code->type() != Code::NORMAL) { | 1157 if (code->type() != Code::NORMAL) { |
| 1180 HeapObject::UpdateMapCodeCache(receiver, name, code); | 1158 HeapObject::UpdateMapCodeCache(receiver, name, code); |
| 1181 } | 1159 } |
| 1182 | 1160 |
| 1183 return code; | 1161 return code; |
| 1184 } | 1162 } |
| 1185 | 1163 |
| 1186 | 1164 |
| 1187 Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, | 1165 Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, |
| 1188 Handle<JSObject> receiver, | 1166 Handle<JSObject> receiver, |
| 1189 Handle<String> name, | 1167 Handle<String> name, |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1208 // be embedded into code. | 1186 // be embedded into code. |
| 1209 if (constant->IsConsString()) break; | 1187 if (constant->IsConsString()) break; |
| 1210 return compiler.CompileLoadConstant(receiver, holder, name, constant); | 1188 return compiler.CompileLoadConstant(receiver, holder, name, constant); |
| 1211 } | 1189 } |
| 1212 case NORMAL: | 1190 case NORMAL: |
| 1213 if (kind() != Code::LOAD_IC) break; | 1191 if (kind() != Code::LOAD_IC) break; |
| 1214 if (holder->IsGlobalObject()) { | 1192 if (holder->IsGlobalObject()) { |
| 1215 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); | 1193 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); |
| 1216 Handle<PropertyCell> cell( | 1194 Handle<PropertyCell> cell( |
| 1217 global->GetPropertyCell(lookup), isolate()); | 1195 global->GetPropertyCell(lookup), isolate()); |
| 1218 // TODO(verwaest): Turn into a handler. | 1196 Handle<Code> code = compiler.CompileLoadGlobal( |
| 1219 return isolate()->stub_cache()->ComputeLoadGlobal( | 1197 receiver, global, cell, name, lookup->IsDontDelete()); |
| 1220 name, receiver, global, cell, lookup->IsDontDelete()); | 1198 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. |
| 1199 HeapObject::UpdateMapCodeCache(receiver, name, code); |
| 1200 return code; |
| 1221 } | 1201 } |
| 1222 // There is only one shared stub for loading normalized | 1202 // There is only one shared stub for loading normalized |
| 1223 // properties. It does not traverse the prototype chain, so the | 1203 // properties. It does not traverse the prototype chain, so the |
| 1224 // property must be found in the receiver for the stub to be | 1204 // property must be found in the receiver for the stub to be |
| 1225 // applicable. | 1205 // applicable. |
| 1226 if (!holder.is_identical_to(receiver)) break; | 1206 if (!holder.is_identical_to(receiver)) break; |
| 1227 return isolate()->builtins()->LoadIC_Normal(); | 1207 return isolate()->builtins()->LoadIC_Normal(); |
| 1228 case CALLBACKS: { | 1208 case CALLBACKS: { |
| 1229 // Use simple field loads for some well-known callback properties. | 1209 // Use simple field loads for some well-known callback properties. |
| 1230 int object_offset; | 1210 int object_offset; |
| (...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1625 return compiler.CompileStoreTransition( | 1605 return compiler.CompileStoreTransition( |
| 1626 receiver, lookup, transition, name); | 1606 receiver, lookup, transition, name); |
| 1627 } | 1607 } |
| 1628 case NORMAL: | 1608 case NORMAL: |
| 1629 if (kind() == Code::KEYED_STORE_IC) break; | 1609 if (kind() == Code::KEYED_STORE_IC) break; |
| 1630 if (receiver->IsGlobalObject()) { | 1610 if (receiver->IsGlobalObject()) { |
| 1631 // The stub generated for the global object picks the value directly | 1611 // The stub generated for the global object picks the value directly |
| 1632 // from the property cell. So the property must be directly on the | 1612 // from the property cell. So the property must be directly on the |
| 1633 // global object. | 1613 // global object. |
| 1634 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1614 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
| 1635 Handle<PropertyCell> cell( | 1615 Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate()); |
| 1636 global->GetPropertyCell(lookup), isolate()); | 1616 Handle<Type> union_type = PropertyCell::UpdatedType(cell, value); |
| 1637 // TODO(verwaest): Turn into a handler. | 1617 StoreGlobalStub stub(strict_mode(), union_type->IsConstant()); |
| 1638 return isolate()->stub_cache()->ComputeStoreGlobal( | 1618 |
| 1639 name, global, cell, value, strict_mode()); | 1619 Handle<Code> code = stub.GetCodeCopyFromTemplate( |
| 1620 isolate(), receiver->map(), *cell); |
| 1621 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. |
| 1622 HeapObject::UpdateMapCodeCache(receiver, name, code); |
| 1623 return code; |
| 1640 } | 1624 } |
| 1641 ASSERT(holder.is_identical_to(receiver)); | 1625 ASSERT(holder.is_identical_to(receiver)); |
| 1642 return strict_mode() == kStrictMode | 1626 return strict_mode() == kStrictMode |
| 1643 ? isolate()->builtins()->StoreIC_Normal_Strict() | 1627 ? isolate()->builtins()->StoreIC_Normal_Strict() |
| 1644 : isolate()->builtins()->StoreIC_Normal(); | 1628 : isolate()->builtins()->StoreIC_Normal(); |
| 1645 case CALLBACKS: { | 1629 case CALLBACKS: { |
| 1646 if (kind() == Code::KEYED_STORE_IC) break; | 1630 if (kind() == Code::KEYED_STORE_IC) break; |
| 1647 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | 1631 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
| 1648 if (callback->IsExecutableAccessorInfo()) { | 1632 if (callback->IsExecutableAccessorInfo()) { |
| 1649 Handle<ExecutableAccessorInfo> info = | 1633 Handle<ExecutableAccessorInfo> info = |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1929 } | 1913 } |
| 1930 } | 1914 } |
| 1931 } | 1915 } |
| 1932 | 1916 |
| 1933 | 1917 |
| 1934 MaybeObject* KeyedStoreIC::Store(Handle<Object> object, | 1918 MaybeObject* KeyedStoreIC::Store(Handle<Object> object, |
| 1935 Handle<Object> key, | 1919 Handle<Object> key, |
| 1936 Handle<Object> value, | 1920 Handle<Object> value, |
| 1937 ICMissMode miss_mode) { | 1921 ICMissMode miss_mode) { |
| 1938 if (MigrateDeprecated(object)) { | 1922 if (MigrateDeprecated(object)) { |
| 1939 return Runtime::SetObjectPropertyOrFail( | 1923 Handle<Object> result = Runtime::SetObjectProperty(isolate(), object, |
| 1940 isolate(), object , key, value, NONE, strict_mode()); | 1924 key, |
| 1925 value, |
| 1926 NONE, |
| 1927 strict_mode()); |
| 1928 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 1929 return *result; |
| 1941 } | 1930 } |
| 1942 | 1931 |
| 1943 // Check for values that can be converted into an internalized string directly | 1932 // Check for values that can be converted into an internalized string directly |
| 1944 // or is representable as a smi. | 1933 // or is representable as a smi. |
| 1945 key = TryConvertKey(key, isolate()); | 1934 key = TryConvertKey(key, isolate()); |
| 1946 | 1935 |
| 1947 MaybeObject* maybe_object = NULL; | 1936 MaybeObject* maybe_object = NULL; |
| 1948 Handle<Code> stub = generic_stub(); | 1937 Handle<Code> stub = generic_stub(); |
| 1949 | 1938 |
| 1950 if (key->IsInternalizedString()) { | 1939 if (key->IsInternalizedString()) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1969 ASSERT(!object->IsJSGlobalProxy()); | 1958 ASSERT(!object->IsJSGlobalProxy()); |
| 1970 | 1959 |
| 1971 if (miss_mode != MISS_FORCE_GENERIC) { | 1960 if (miss_mode != MISS_FORCE_GENERIC) { |
| 1972 if (object->IsJSObject()) { | 1961 if (object->IsJSObject()) { |
| 1973 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1962 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1974 bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure(); | 1963 bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure(); |
| 1975 if (receiver->elements()->map() == | 1964 if (receiver->elements()->map() == |
| 1976 isolate()->heap()->non_strict_arguments_elements_map()) { | 1965 isolate()->heap()->non_strict_arguments_elements_map()) { |
| 1977 stub = non_strict_arguments_stub(); | 1966 stub = non_strict_arguments_stub(); |
| 1978 } else if (key_is_smi_like && | 1967 } else if (key_is_smi_like && |
| 1979 (!target().is_identical_to(non_strict_arguments_stub()))) { | 1968 !(target().is_identical_to(non_strict_arguments_stub()))) { |
| 1980 KeyedAccessStoreMode store_mode = | 1969 // We should go generic if receiver isn't a dictionary, but our |
| 1981 GetStoreMode(receiver, key, value); | 1970 // prototype chain does have dictionary elements. This ensures that |
| 1982 stub = StoreElementStub(receiver, store_mode); | 1971 // other non-dictionary receivers in the polymorphic case benefit |
| 1972 // from fast path keyed stores. |
| 1973 if (!(receiver->map()->DictionaryElementsInPrototypeChainOnly())) { |
| 1974 KeyedAccessStoreMode store_mode = |
| 1975 GetStoreMode(receiver, key, value); |
| 1976 stub = StoreElementStub(receiver, store_mode); |
| 1977 } |
| 1983 } | 1978 } |
| 1984 } | 1979 } |
| 1985 } | 1980 } |
| 1986 } | 1981 } |
| 1987 } | 1982 } |
| 1988 | 1983 |
| 1989 if (!is_target_set()) { | 1984 if (!is_target_set()) { |
| 1990 if (*stub == *generic_stub()) { | 1985 if (*stub == *generic_stub()) { |
| 1991 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic"); | 1986 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic"); |
| 1992 } | 1987 } |
| 1993 ASSERT(!stub.is_null()); | 1988 ASSERT(!stub.is_null()); |
| 1994 set_target(*stub); | 1989 set_target(*stub); |
| 1995 TRACE_IC("StoreIC", key); | 1990 TRACE_IC("StoreIC", key); |
| 1996 } | 1991 } |
| 1997 | 1992 |
| 1998 if (maybe_object) return maybe_object; | 1993 if (maybe_object) return maybe_object; |
| 1999 return Runtime::SetObjectPropertyOrFail( | 1994 Handle<Object> result = Runtime::SetObjectProperty(isolate(), object, key, |
| 2000 isolate(), object , key, value, NONE, strict_mode()); | 1995 value, |
| 1996 NONE, |
| 1997 strict_mode()); |
| 1998 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 1999 return *result; |
| 2001 } | 2000 } |
| 2002 | 2001 |
| 2003 | 2002 |
| 2004 #undef TRACE_IC | 2003 #undef TRACE_IC |
| 2005 | 2004 |
| 2006 | 2005 |
| 2007 // ---------------------------------------------------------------------------- | 2006 // ---------------------------------------------------------------------------- |
| 2008 // Static IC stub generators. | 2007 // Static IC stub generators. |
| 2009 // | 2008 // |
| 2010 | 2009 |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2221 | 2220 |
| 2222 | 2221 |
| 2223 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Slow) { | 2222 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Slow) { |
| 2224 HandleScope scope(isolate); | 2223 HandleScope scope(isolate); |
| 2225 ASSERT(args.length() == 3); | 2224 ASSERT(args.length() == 3); |
| 2226 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2225 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
| 2227 Handle<Object> object = args.at<Object>(0); | 2226 Handle<Object> object = args.at<Object>(0); |
| 2228 Handle<Object> key = args.at<Object>(1); | 2227 Handle<Object> key = args.at<Object>(1); |
| 2229 Handle<Object> value = args.at<Object>(2); | 2228 Handle<Object> value = args.at<Object>(2); |
| 2230 StrictModeFlag strict_mode = ic.strict_mode(); | 2229 StrictModeFlag strict_mode = ic.strict_mode(); |
| 2231 return Runtime::SetObjectProperty(isolate, | 2230 Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key, |
| 2232 object, | 2231 value, |
| 2233 key, | 2232 NONE, |
| 2234 value, | 2233 strict_mode); |
| 2235 NONE, | 2234 RETURN_IF_EMPTY_HANDLE(isolate, result); |
| 2236 strict_mode); | 2235 return *result; |
| 2237 } | 2236 } |
| 2238 | 2237 |
| 2239 | 2238 |
| 2240 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) { | 2239 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) { |
| 2241 HandleScope scope(isolate); | 2240 HandleScope scope(isolate); |
| 2242 ASSERT(args.length() == 3); | 2241 ASSERT(args.length() == 3); |
| 2243 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2242 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
| 2244 Handle<Object> object = args.at<Object>(0); | 2243 Handle<Object> object = args.at<Object>(0); |
| 2245 Handle<Object> key = args.at<Object>(1); | 2244 Handle<Object> key = args.at<Object>(1); |
| 2246 Handle<Object> value = args.at<Object>(2); | 2245 Handle<Object> value = args.at<Object>(2); |
| 2247 StrictModeFlag strict_mode = ic.strict_mode(); | 2246 StrictModeFlag strict_mode = ic.strict_mode(); |
| 2248 return Runtime::SetObjectProperty(isolate, | 2247 Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key, |
| 2249 object, | 2248 value, |
| 2250 key, | 2249 NONE, |
| 2251 value, | 2250 strict_mode); |
| 2252 NONE, | 2251 RETURN_IF_EMPTY_HANDLE(isolate, result); |
| 2253 strict_mode); | 2252 return *result; |
| 2254 } | 2253 } |
| 2255 | 2254 |
| 2256 | 2255 |
| 2257 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) { | 2256 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) { |
| 2258 HandleScope scope(isolate); | 2257 HandleScope scope(isolate); |
| 2259 ASSERT(args.length() == 3); | 2258 ASSERT(args.length() == 3); |
| 2260 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2259 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
| 2261 Handle<Object> receiver = args.at<Object>(0); | 2260 Handle<Object> receiver = args.at<Object>(0); |
| 2262 Handle<Object> key = args.at<Object>(1); | 2261 Handle<Object> key = args.at<Object>(1); |
| 2263 ic.UpdateState(receiver, key); | 2262 ic.UpdateState(receiver, key); |
| 2264 return ic.Store(receiver, key, args.at<Object>(2), MISS_FORCE_GENERIC); | 2263 return ic.Store(receiver, key, args.at<Object>(2), MISS_FORCE_GENERIC); |
| 2265 } | 2264 } |
| 2266 | 2265 |
| 2267 | 2266 |
| 2268 RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss) { | 2267 RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss) { |
| 2269 HandleScope scope(isolate); | 2268 HandleScope scope(isolate); |
| 2270 ASSERT(args.length() == 4); | 2269 ASSERT(args.length() == 4); |
| 2271 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); | 2270 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); |
| 2272 Handle<Object> value = args.at<Object>(0); | 2271 Handle<Object> value = args.at<Object>(0); |
| 2272 Handle<Map> map = args.at<Map>(1); |
| 2273 Handle<Object> key = args.at<Object>(2); | 2273 Handle<Object> key = args.at<Object>(2); |
| 2274 Handle<Object> object = args.at<Object>(3); | 2274 Handle<Object> object = args.at<Object>(3); |
| 2275 StrictModeFlag strict_mode = ic.strict_mode(); | 2275 StrictModeFlag strict_mode = ic.strict_mode(); |
| 2276 return Runtime::SetObjectProperty(isolate, | 2276 if (object->IsJSObject()) { |
| 2277 object, | 2277 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), |
| 2278 key, | 2278 map->elements_kind()); |
| 2279 value, | 2279 } |
| 2280 NONE, | 2280 Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key, |
| 2281 strict_mode); | 2281 value, |
| 2282 NONE, |
| 2283 strict_mode); |
| 2284 RETURN_IF_EMPTY_HANDLE(isolate, result); |
| 2285 return *result; |
| 2282 } | 2286 } |
| 2283 | 2287 |
| 2284 | 2288 |
| 2285 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 2289 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
| 2286 switch (type_info) { | 2290 switch (type_info) { |
| 2287 case UNINITIALIZED: return "Uninitialized"; | 2291 case UNINITIALIZED: return "Uninitialized"; |
| 2288 case SMI: return "Smi"; | 2292 case SMI: return "Smi"; |
| 2289 case INT32: return "Int32"; | 2293 case INT32: return "Int32"; |
| 2290 case NUMBER: return "Number"; | 2294 case NUMBER: return "Number"; |
| 2291 case ODDBALL: return "Oddball"; | 2295 case ODDBALL: return "Oddball"; |
| 2292 case STRING: return "String"; | 2296 case STRING: return "String"; |
| 2293 case GENERIC: return "Generic"; | 2297 case GENERIC: return "Generic"; |
| 2294 default: return "Invalid"; | 2298 default: return "Invalid"; |
| 2295 } | 2299 } |
| 2296 } | 2300 } |
| 2297 | 2301 |
| 2298 | 2302 |
| 2299 MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) { | 2303 MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) { |
| 2300 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state(); | 2304 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state(); |
| 2301 BinaryOpStub stub(extra_ic_state); | 2305 BinaryOpStub stub(extra_ic_state); |
| 2302 | 2306 |
| 2303 Handle<Type> left_type = stub.GetLeftType(isolate()); | 2307 Handle<Type> left_type = stub.GetLeftType(isolate()); |
| 2304 Handle<Type> right_type = stub.GetRightType(isolate()); | 2308 Handle<Type> right_type = stub.GetRightType(isolate()); |
| 2305 bool smi_was_enabled = left_type->Maybe(Type::Smi()) && | 2309 bool smi_was_enabled = left_type->Maybe(Type::Smi()) && |
| 2306 right_type->Maybe(Type::Smi()); | 2310 right_type->Maybe(Type::Smi()); |
| 2307 | 2311 |
| 2308 Maybe<Handle<Object> > result = stub.Result(left, right, isolate()); | 2312 Maybe<Handle<Object> > result = stub.Result(left, right, isolate()); |
| 2313 if (!result.has_value) return Failure::Exception(); |
| 2309 | 2314 |
| 2310 #ifdef DEBUG | 2315 #ifdef DEBUG |
| 2311 if (FLAG_trace_ic) { | 2316 if (FLAG_trace_ic) { |
| 2312 char buffer[100]; | 2317 char buffer[100]; |
| 2313 NoAllocationStringAllocator allocator(buffer, | 2318 NoAllocationStringAllocator allocator(buffer, |
| 2314 static_cast<unsigned>(sizeof(buffer))); | 2319 static_cast<unsigned>(sizeof(buffer))); |
| 2315 StringStream stream(&allocator); | 2320 StringStream stream(&allocator); |
| 2316 stream.Add("["); | 2321 stream.Add("["); |
| 2317 stub.PrintName(&stream); | 2322 stub.PrintName(&stream); |
| 2318 | 2323 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2339 right_type = stub.GetRightType(isolate()); | 2344 right_type = stub.GetRightType(isolate()); |
| 2340 bool enable_smi = left_type->Maybe(Type::Smi()) && | 2345 bool enable_smi = left_type->Maybe(Type::Smi()) && |
| 2341 right_type->Maybe(Type::Smi()); | 2346 right_type->Maybe(Type::Smi()); |
| 2342 | 2347 |
| 2343 if (!smi_was_enabled && enable_smi) { | 2348 if (!smi_was_enabled && enable_smi) { |
| 2344 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); | 2349 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
| 2345 } else if (smi_was_enabled && !enable_smi) { | 2350 } else if (smi_was_enabled && !enable_smi) { |
| 2346 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK); | 2351 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK); |
| 2347 } | 2352 } |
| 2348 | 2353 |
| 2349 return result.has_value | 2354 ASSERT(result.has_value); |
| 2350 ? static_cast<MaybeObject*>(*result.value) | 2355 return static_cast<MaybeObject*>(*result.value); |
| 2351 : Failure::Exception(); | |
| 2352 } | 2356 } |
| 2353 | 2357 |
| 2354 | 2358 |
| 2355 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) { | 2359 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) { |
| 2356 HandleScope scope(isolate); | 2360 HandleScope scope(isolate); |
| 2357 Handle<Object> left = args.at<Object>(0); | 2361 Handle<Object> left = args.at<Object>(0); |
| 2358 Handle<Object> right = args.at<Object>(1); | 2362 Handle<Object> right = args.at<Object>(1); |
| 2359 BinaryOpIC ic(isolate); | 2363 BinaryOpIC ic(isolate); |
| 2360 return ic.Transition(left, right); | 2364 return ic.Transition(left, right); |
| 2361 } | 2365 } |
| (...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2726 #undef ADDR | 2730 #undef ADDR |
| 2727 }; | 2731 }; |
| 2728 | 2732 |
| 2729 | 2733 |
| 2730 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2734 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2731 return IC_utilities[id]; | 2735 return IC_utilities[id]; |
| 2732 } | 2736 } |
| 2733 | 2737 |
| 2734 | 2738 |
| 2735 } } // namespace v8::internal | 2739 } } // namespace v8::internal |
| OLD | NEW |