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 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 intptr_t delta = | 175 intptr_t delta = |
176 original_code->instruction_start() - code->instruction_start(); | 176 original_code->instruction_start() - code->instruction_start(); |
177 return addr + delta; | 177 return addr + delta; |
178 } | 178 } |
179 #endif | 179 #endif |
180 | 180 |
181 | 181 |
182 static bool TryRemoveInvalidPrototypeDependentStub(Code* target, | 182 static bool TryRemoveInvalidPrototypeDependentStub(Code* target, |
183 Object* receiver, | 183 Object* receiver, |
184 Object* name) { | 184 Object* name) { |
185 // If the code is NORMAL, it handles dictionary mode objects. Such stubs do | 185 if (target->is_keyed_load_stub() || |
186 // not check maps, but do positive/negative lookups. | 186 target->is_keyed_call_stub() || |
187 if (target->type() != Code::NORMAL) { | 187 target->is_keyed_store_stub()) { |
188 Map* map = target->FindFirstMap(); | 188 // Determine whether the failure is due to a name failure. |
189 if (map != NULL && map->is_deprecated()) { | 189 if (!name->IsName()) return false; |
190 return true; | 190 Name* stub_name = target->FindFirstName(); |
191 } | 191 if (Name::cast(name) != stub_name) return false; |
192 } | 192 } |
193 | 193 |
194 InlineCacheHolderFlag cache_holder = | 194 InlineCacheHolderFlag cache_holder = |
195 Code::ExtractCacheHolderFromFlags(target->flags()); | 195 Code::ExtractCacheHolderFromFlags(target->flags()); |
196 | 196 |
197 Isolate* isolate = target->GetIsolate(); | 197 Isolate* isolate = target->GetIsolate(); |
198 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { | 198 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { |
199 // The stub was generated for JSObject but called for non-JSObject. | 199 // The stub was generated for JSObject but called for non-JSObject. |
200 // IC::GetCodeCacheHolder is not applicable. | 200 // IC::GetCodeCacheHolder is not applicable. |
201 return false; | 201 return false; |
202 } else if (cache_holder == PROTOTYPE_MAP && | 202 } else if (cache_holder == PROTOTYPE_MAP && |
203 receiver->GetPrototype(isolate)->IsNull()) { | 203 receiver->GetPrototype(isolate)->IsNull()) { |
204 // IC::GetCodeCacheHolder is not applicable. | 204 // IC::GetCodeCacheHolder is not applicable. |
205 return false; | 205 return false; |
206 } | 206 } |
207 Map* map = IC::GetCodeCacheHolder(isolate, receiver, cache_holder)->map(); | 207 Map* map = IC::GetCodeCacheHolder(isolate, receiver, cache_holder)->map(); |
208 | 208 |
209 // Decide whether the inline cache failed because of changes to the | 209 // Decide whether the inline cache failed because of changes to the |
210 // receiver itself or changes to one of its prototypes. | 210 // receiver itself or changes to one of its prototypes. |
211 // | 211 // |
212 // If there are changes to the receiver itself, the map of the | 212 // If there are changes to the receiver itself, the map of the |
213 // receiver will have changed and the current target will not be in | 213 // receiver will have changed and the current target will not be in |
214 // the receiver map's code cache. Therefore, if the current target | 214 // the receiver map's code cache. Therefore, if the current target |
215 // is in the receiver map's code cache, the inline cache failed due | 215 // is in the receiver map's code cache, the inline cache failed due |
216 // to prototype check failure. | 216 // to prototype check failure. |
217 int index = map->IndexInCodeCache(name, target); | 217 int index = map->IndexInCodeCache(name, target); |
218 if (index >= 0) { | 218 if (index >= 0) { |
219 map->RemoveFromCodeCache(String::cast(name), target, index); | 219 map->RemoveFromCodeCache(String::cast(name), target, index); |
| 220 // For loads, handlers are stored in addition to the ICs on the map. Remove |
| 221 // those, too. |
| 222 if (target->is_load_stub() || target->is_keyed_load_stub()) { |
| 223 Code* handler = target->FindFirstCode(); |
| 224 index = map->IndexInCodeCache(name, handler); |
| 225 if (index >= 0) { |
| 226 map->RemoveFromCodeCache(String::cast(name), handler, index); |
| 227 } |
| 228 } |
220 return true; | 229 return true; |
221 } | 230 } |
222 | 231 |
223 return false; | 232 // If the IC is shared between multiple receivers (slow dictionary mode), then |
| 233 // the map cannot be deprecated and the stub invalidated. |
| 234 if (cache_holder != OWN_MAP) return false; |
| 235 |
| 236 // The stub is not in the cache. We've ruled out all other kinds of failure |
| 237 // except for proptotype chain changes, a deprecated map, or a map that's |
| 238 // different from the one that the stub expects. If the map hasn't changed, |
| 239 // assume it's a prototype failure. Treat deprecated maps in the same way as |
| 240 // prototype failures (stay monomorphic if possible). |
| 241 Map* old_map = target->FindFirstMap(); |
| 242 if (old_map == NULL) return false; |
| 243 return old_map == map || old_map->is_deprecated(); |
224 } | 244 } |
225 | 245 |
226 | 246 |
227 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { | 247 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { |
228 IC::State state = target->ic_state(); | 248 IC::State state = target->ic_state(); |
229 | 249 |
230 if (state != MONOMORPHIC || !name->IsString()) return state; | 250 if (state != MONOMORPHIC || !name->IsString()) return state; |
231 if (receiver->IsUndefined() || receiver->IsNull()) return state; | 251 if (receiver->IsUndefined() || receiver->IsNull()) return state; |
232 | 252 |
233 // For keyed load/store/call, the most likely cause of cache failure is | |
234 // that the key has changed. We do not distinguish between | |
235 // prototype and non-prototype failures for keyed access. | |
236 Code::Kind kind = target->kind(); | 253 Code::Kind kind = target->kind(); |
237 if (kind == Code::KEYED_LOAD_IC || | |
238 kind == Code::KEYED_STORE_IC || | |
239 kind == Code::KEYED_CALL_IC) { | |
240 return MONOMORPHIC; | |
241 } | |
242 | |
243 // Remove the target from the code cache if it became invalid | 254 // Remove the target from the code cache if it became invalid |
244 // because of changes in the prototype chain to avoid hitting it | 255 // because of changes in the prototype chain to avoid hitting it |
245 // again. | 256 // again. |
246 // Call stubs handle this later to allow extra IC state | 257 // Call stubs handle this later to allow extra IC state |
247 // transitions. | 258 // transitions. |
248 if (kind != Code::CALL_IC && | 259 if (kind != Code::CALL_IC && kind != Code::KEYED_CALL_IC && |
249 TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) { | 260 TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) { |
250 return MONOMORPHIC_PROTOTYPE_FAILURE; | 261 return MONOMORPHIC_PROTOTYPE_FAILURE; |
251 } | 262 } |
252 | 263 |
253 // The builtins object is special. It only changes when JavaScript | 264 // The builtins object is special. It only changes when JavaScript |
254 // builtins are loaded lazily. It is important to keep inline | 265 // builtins are loaded lazily. It is important to keep inline |
255 // caches for the builtins object monomorphic. Therefore, if we get | 266 // caches for the builtins object monomorphic. Therefore, if we get |
256 // an inline cache miss for the builtins object after lazily loading | 267 // an inline cache miss for the builtins object after lazily loading |
257 // JavaScript builtins, we return uninitialized as the state to | 268 // JavaScript builtins, we return uninitialized as the state to |
258 // force the inline cache back to monomorphic state. | 269 // force the inline cache back to monomorphic state. |
(...skipping 458 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 // This is the first time we execute this inline cache. | 728 // This is the first time we execute this inline cache. |
718 // Set the target to the pre monomorphic stub to delay | 729 // Set the target to the pre monomorphic stub to delay |
719 // setting the monomorphic state. | 730 // setting the monomorphic state. |
720 code = isolate()->stub_cache()->ComputeCallPreMonomorphic( | 731 code = isolate()->stub_cache()->ComputeCallPreMonomorphic( |
721 argc, kind_, extra_ic_state); | 732 argc, kind_, extra_ic_state); |
722 } else if (state == MONOMORPHIC) { | 733 } else if (state == MONOMORPHIC) { |
723 if (kind_ == Code::CALL_IC && | 734 if (kind_ == Code::CALL_IC && |
724 TryUpdateExtraICState(lookup, object, &extra_ic_state)) { | 735 TryUpdateExtraICState(lookup, object, &extra_ic_state)) { |
725 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, | 736 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, |
726 object, name); | 737 object, name); |
727 } else if (kind_ == Code::CALL_IC && | 738 } else if (TryRemoveInvalidPrototypeDependentStub(target(), |
728 TryRemoveInvalidPrototypeDependentStub(target(), | |
729 *object, | 739 *object, |
730 *name)) { | 740 *name)) { |
731 state = MONOMORPHIC_PROTOTYPE_FAILURE; | 741 state = MONOMORPHIC_PROTOTYPE_FAILURE; |
732 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, | 742 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, |
733 object, name); | 743 object, name); |
734 } else { | 744 } else { |
735 code = isolate()->stub_cache()->ComputeCallMegamorphic( | 745 code = isolate()->stub_cache()->ComputeCallMegamorphic( |
736 argc, kind_, extra_ic_state); | 746 argc, kind_, extra_ic_state); |
737 } | 747 } |
738 } else { | 748 } else { |
739 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, | 749 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, |
740 object, name); | 750 object, name); |
741 } | 751 } |
742 | 752 |
743 // If there's no appropriate stub we simply avoid updating the caches. | 753 // If there's no appropriate stub we simply avoid updating the caches. |
744 if (code.is_null()) return; | 754 if (code.is_null()) return; |
745 | 755 |
746 // Patch the call site depending on the state of the cache. | 756 // Patch the call site depending on the state of the cache. |
747 switch (state) { | 757 switch (state) { |
748 case UNINITIALIZED: | 758 case UNINITIALIZED: |
749 case MONOMORPHIC_PROTOTYPE_FAILURE: | 759 case MONOMORPHIC_PROTOTYPE_FAILURE: |
750 case PREMONOMORPHIC: | 760 case PREMONOMORPHIC: |
751 set_target(*code); | |
752 break; | |
753 case MONOMORPHIC: | 761 case MONOMORPHIC: |
754 if (code->ic_state() != MONOMORPHIC) { | |
755 Map* map = target()->FindFirstMap(); | |
756 if (map != NULL) { | |
757 UpdateMegamorphicCache(map, *name, target()); | |
758 } | |
759 } | |
760 set_target(*code); | 762 set_target(*code); |
761 break; | 763 break; |
762 case MEGAMORPHIC: { | 764 case MEGAMORPHIC: { |
763 // Cache code holding map should be consistent with | 765 // Cache code holding map should be consistent with |
764 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. | 766 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. |
765 Handle<JSObject> cache_object = object->IsJSObject() | 767 Handle<JSObject> cache_object = object->IsJSObject() |
766 ? Handle<JSObject>::cast(object) | 768 ? Handle<JSObject>::cast(object) |
767 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())), | 769 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())), |
768 isolate()); | 770 isolate()); |
769 // Update the stub cache. | 771 // Update the stub cache. |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
979 if (code->type() == Code::NORMAL) return false; | 981 if (code->type() == Code::NORMAL) return false; |
980 if (target()->ic_state() == MONOMORPHIC && | 982 if (target()->ic_state() == MONOMORPHIC && |
981 target()->type() == Code::NORMAL) { | 983 target()->type() == Code::NORMAL) { |
982 return false; | 984 return false; |
983 } | 985 } |
984 | 986 |
985 MapHandleList receiver_maps; | 987 MapHandleList receiver_maps; |
986 CodeHandleList handlers; | 988 CodeHandleList handlers; |
987 | 989 |
988 int number_of_valid_maps; | 990 int number_of_valid_maps; |
| 991 int handler_to_overwrite = -1; |
| 992 Handle<Map> new_receiver_map(receiver->map()); |
989 { | 993 { |
990 AssertNoAllocation no_gc; | 994 AssertNoAllocation no_gc; |
991 target()->FindAllMaps(&receiver_maps); | 995 target()->FindAllMaps(&receiver_maps); |
992 int number_of_maps = receiver_maps.length(); | 996 int number_of_maps = receiver_maps.length(); |
993 number_of_valid_maps = number_of_maps; | 997 number_of_valid_maps = number_of_maps; |
| 998 |
994 for (int i = 0; i < number_of_maps; i++) { | 999 for (int i = 0; i < number_of_maps; i++) { |
995 if (receiver_maps.at(i)->is_deprecated()) { | 1000 Handle<Map> map = receiver_maps.at(i); |
| 1001 // Filter out deprecated maps to ensure its instances get migrated. |
| 1002 if (map->is_deprecated()) { |
996 number_of_valid_maps--; | 1003 number_of_valid_maps--; |
| 1004 // If the receiver map is already in the polymorphic IC, this indicates |
| 1005 // there was a prototoype chain failure. In that case, just overwrite the |
| 1006 // handler. |
| 1007 } else if (map.is_identical_to(new_receiver_map)) { |
| 1008 number_of_valid_maps--; |
| 1009 handler_to_overwrite = i; |
997 } | 1010 } |
998 } | 1011 } |
999 | 1012 |
1000 if (number_of_valid_maps >= 4) return false; | 1013 if (number_of_valid_maps >= 4) return false; |
1001 | 1014 |
1002 // Only allow 0 maps in case target() was reset to UNINITIALIZED by the GC. | 1015 // Only allow 0 maps in case target() was reset to UNINITIALIZED by the GC. |
1003 // In that case, allow the IC to go back monomorphic. | 1016 // In that case, allow the IC to go back monomorphic. |
1004 if (number_of_maps == 0 && target()->ic_state() != UNINITIALIZED) { | 1017 if (number_of_maps == 0 && target()->ic_state() != UNINITIALIZED) { |
1005 return false; | 1018 return false; |
1006 } | 1019 } |
1007 target()->FindAllCode(&handlers, receiver_maps.length()); | 1020 target()->FindAllCode(&handlers, receiver_maps.length()); |
1008 } | 1021 } |
1009 | 1022 |
1010 if (!AddOneReceiverMapIfMissing(&receiver_maps, | 1023 number_of_valid_maps++; |
1011 Handle<Map>(receiver->map()))) { | 1024 if (handler_to_overwrite >= 0) { |
1012 return false; | 1025 handlers.InsertAt(handler_to_overwrite, code); |
| 1026 } else { |
| 1027 receiver_maps.Add(new_receiver_map); |
| 1028 handlers.Add(code); |
1013 } | 1029 } |
1014 | 1030 |
1015 handlers.Add(code); | |
1016 Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC( | 1031 Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC( |
1017 &receiver_maps, &handlers, number_of_valid_maps + 1, name); | 1032 &receiver_maps, &handlers, number_of_valid_maps, name); |
1018 set_target(*ic); | 1033 set_target(*ic); |
1019 return true; | 1034 return true; |
1020 } | 1035 } |
1021 | 1036 |
1022 | 1037 |
1023 void LoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver, | 1038 void LoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver, |
1024 Handle<Code> handler, | 1039 Handle<Code> handler, |
1025 Handle<String> name) { | 1040 Handle<String> name) { |
1026 if (handler->type() == Code::NORMAL) return set_target(*handler); | 1041 if (handler->type() == Code::NORMAL) return set_target(*handler); |
1027 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC( | 1042 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC( |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1094 is_same_handler = old_handler == *code; | 1109 is_same_handler = old_handler == *code; |
1095 } | 1110 } |
1096 if (is_same_handler | 1111 if (is_same_handler |
1097 && IsTransitionedMapOfMonomorphicTarget(receiver->map())) { | 1112 && IsTransitionedMapOfMonomorphicTarget(receiver->map())) { |
1098 UpdateMonomorphicIC(receiver, code, name); | 1113 UpdateMonomorphicIC(receiver, code, name); |
1099 break; | 1114 break; |
1100 } | 1115 } |
1101 if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) { | 1116 if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) { |
1102 break; | 1117 break; |
1103 } | 1118 } |
1104 } | 1119 |
1105 if (target()->type() != Code::NORMAL) { | 1120 if (target()->type() != Code::NORMAL) { |
1106 if (target()->is_load_stub()) { | |
1107 CopyICToMegamorphicCache(name); | 1121 CopyICToMegamorphicCache(name); |
1108 } else if (target()->is_store_stub()) { | |
1109 // Ensure that the IC stays monomorphic when replacing a monomorphic | |
1110 // IC for a deprecated map. | |
1111 // TODO(verwaest): Remove this code once polymorphic store ICs are | |
1112 // implemented. Updating the polymorphic IC will keep it monomorphic | |
1113 // by filtering deprecated maps. | |
1114 MapHandleList maps; | |
1115 Code* handler = target(); | |
1116 handler->FindAllMaps(&maps); | |
1117 for (int i = 0; i < Min(1, maps.length()); i++) { | |
1118 if (maps.at(i)->is_deprecated()) { | |
1119 UpdateMonomorphicIC(receiver, code, name); | |
1120 return; | |
1121 } | |
1122 } | |
1123 if (maps.length() > 0) { | |
1124 if (receiver->map() == *maps.at(0)) { | |
1125 UpdateMonomorphicIC(receiver, code, name); | |
1126 return; | |
1127 } | |
1128 UpdateMegamorphicCache(*maps.at(0), *name, handler); | |
1129 } | |
1130 } else { | |
1131 Code* handler = target(); | |
1132 Map* map = handler->FindFirstMap(); | |
1133 if (map != NULL) { | |
1134 UpdateMegamorphicCache(map, *name, handler); | |
1135 } | |
1136 } | 1122 } |
1137 } | 1123 } |
1138 | 1124 |
1139 UpdateMegamorphicCache(receiver->map(), *name, *code); | 1125 UpdateMegamorphicCache(receiver->map(), *name, *code); |
1140 set_target((strict_mode == kStrictMode) | 1126 set_target((strict_mode == kStrictMode) |
1141 ? *megamorphic_stub_strict() | 1127 ? *megamorphic_stub_strict() |
1142 : *megamorphic_stub()); | 1128 : *megamorphic_stub()); |
1143 } | 1129 } |
1144 break; | 1130 break; |
1145 case MEGAMORPHIC: | 1131 case MEGAMORPHIC: |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1228 } else { | 1214 } else { |
1229 code = ComputeLoadHandler(lookup, receiver, name); | 1215 code = ComputeLoadHandler(lookup, receiver, name); |
1230 if (code.is_null()) return; | 1216 if (code.is_null()) return; |
1231 } | 1217 } |
1232 | 1218 |
1233 PatchCache(state, kNonStrictMode, receiver, name, code); | 1219 PatchCache(state, kNonStrictMode, receiver, name, code); |
1234 TRACE_IC("LoadIC", name, state, target()); | 1220 TRACE_IC("LoadIC", name, state, target()); |
1235 } | 1221 } |
1236 | 1222 |
1237 | 1223 |
1238 void IC::UpdateMegamorphicCache(Map* map, String* name, Code* code) { | 1224 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) { |
1239 // Cache code holding map should be consistent with | 1225 // Cache code holding map should be consistent with |
1240 // GenerateMonomorphicCacheProbe. | 1226 // GenerateMonomorphicCacheProbe. |
1241 isolate()->stub_cache()->Set(name, map, code); | 1227 isolate()->stub_cache()->Set(name, map, code); |
1242 } | 1228 } |
1243 | 1229 |
1244 | 1230 |
1245 Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup, | 1231 Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup, |
1246 Handle<JSObject> receiver, | 1232 Handle<JSObject> receiver, |
1247 Handle<String> name) { | 1233 Handle<String> name) { |
1248 if (!lookup->IsProperty()) { | 1234 if (!lookup->IsProperty()) { |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1490 // repeatedly try to rewrite. | 1476 // repeatedly try to rewrite. |
1491 return generic_stub(); | 1477 return generic_stub(); |
1492 } | 1478 } |
1493 return Handle<Code>::null(); | 1479 return Handle<Code>::null(); |
1494 } | 1480 } |
1495 | 1481 |
1496 | 1482 |
1497 static bool LookupForWrite(Handle<JSObject> receiver, | 1483 static bool LookupForWrite(Handle<JSObject> receiver, |
1498 Handle<String> name, | 1484 Handle<String> name, |
1499 Handle<Object> value, | 1485 Handle<Object> value, |
1500 LookupResult* lookup) { | 1486 LookupResult* lookup, |
| 1487 IC::State* state) { |
1501 Handle<JSObject> holder = receiver; | 1488 Handle<JSObject> holder = receiver; |
1502 receiver->Lookup(*name, lookup); | 1489 receiver->Lookup(*name, lookup); |
1503 if (lookup->IsFound()) { | 1490 if (lookup->IsFound()) { |
1504 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; | 1491 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; |
1505 | 1492 |
1506 if (lookup->holder() == *receiver) { | 1493 if (lookup->holder() == *receiver) { |
1507 if (lookup->IsInterceptor() && | 1494 if (lookup->IsInterceptor() && |
1508 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { | 1495 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { |
1509 receiver->LocalLookupRealNamedProperty(*name, lookup); | 1496 receiver->LocalLookupRealNamedProperty(*name, lookup); |
1510 return lookup->IsFound() && | 1497 return lookup->IsFound() && |
(...skipping 16 matching lines...) Expand all Loading... |
1527 // While normally LookupTransition gets passed the receiver, in this case we | 1514 // While normally LookupTransition gets passed the receiver, in this case we |
1528 // pass the holder of the property that we overwrite. This keeps the holder in | 1515 // pass the holder of the property that we overwrite. This keeps the holder in |
1529 // the LookupResult intact so we can later use it to generate a prototype | 1516 // the LookupResult intact so we can later use it to generate a prototype |
1530 // chain check. This avoids a double lookup, but requires us to pass in the | 1517 // chain check. This avoids a double lookup, but requires us to pass in the |
1531 // receiver when trying to fetch extra information from the transition. | 1518 // receiver when trying to fetch extra information from the transition. |
1532 receiver->map()->LookupTransition(*holder, *name, lookup); | 1519 receiver->map()->LookupTransition(*holder, *name, lookup); |
1533 if (!lookup->IsTransition()) return false; | 1520 if (!lookup->IsTransition()) return false; |
1534 PropertyDetails target_details = | 1521 PropertyDetails target_details = |
1535 lookup->GetTransitionDetails(receiver->map()); | 1522 lookup->GetTransitionDetails(receiver->map()); |
1536 if (target_details.IsReadOnly()) return false; | 1523 if (target_details.IsReadOnly()) return false; |
1537 return value->FitsRepresentation(target_details.representation()); | 1524 |
| 1525 // If the value that's being stored does not fit in the field that the |
| 1526 // instance would transition to, create a new transition that fits the value. |
| 1527 // This has to be done before generating the IC, since that IC will embed the |
| 1528 // transition target. |
| 1529 // Ensure the instance and its map were migrated before trying to update the |
| 1530 // transition target. |
| 1531 ASSERT(!receiver->map()->is_deprecated()); |
| 1532 if (!value->FitsRepresentation(target_details.representation())) { |
| 1533 Handle<Map> target(lookup->GetTransitionMapFromMap(receiver->map())); |
| 1534 Map::GeneralizeRepresentation( |
| 1535 target, target->LastAdded(), value->OptimalRepresentation()); |
| 1536 *state = MONOMORPHIC_PROTOTYPE_FAILURE; |
| 1537 } |
| 1538 return true; |
1538 } | 1539 } |
1539 | 1540 |
1540 | 1541 |
1541 MaybeObject* StoreIC::Store(State state, | 1542 MaybeObject* StoreIC::Store(State state, |
1542 StrictModeFlag strict_mode, | 1543 StrictModeFlag strict_mode, |
1543 Handle<Object> object, | 1544 Handle<Object> object, |
1544 Handle<String> name, | 1545 Handle<String> name, |
1545 Handle<Object> value, | 1546 Handle<Object> value, |
1546 JSReceiver::StoreFromKeyed store_mode) { | 1547 JSReceiver::StoreFromKeyed store_mode) { |
1547 // Handle proxies. | 1548 // Handle proxies. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1611 ? global_proxy_stub_strict() | 1612 ? global_proxy_stub_strict() |
1612 : global_proxy_stub(); | 1613 : global_proxy_stub(); |
1613 set_target(*stub); | 1614 set_target(*stub); |
1614 TRACE_IC("StoreIC", name, state, *stub); | 1615 TRACE_IC("StoreIC", name, state, *stub); |
1615 } | 1616 } |
1616 return JSReceiver::SetPropertyOrFail( | 1617 return JSReceiver::SetPropertyOrFail( |
1617 receiver, name, value, NONE, strict_mode, store_mode); | 1618 receiver, name, value, NONE, strict_mode, store_mode); |
1618 } | 1619 } |
1619 | 1620 |
1620 LookupResult lookup(isolate()); | 1621 LookupResult lookup(isolate()); |
1621 if (LookupForWrite(receiver, name, value, &lookup)) { | 1622 if (LookupForWrite(receiver, name, value, &lookup, &state)) { |
1622 if (FLAG_use_ic) { | 1623 if (FLAG_use_ic) { |
1623 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); | 1624 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
1624 } | 1625 } |
1625 } else if (strict_mode == kStrictMode && | 1626 } else if (strict_mode == kStrictMode && |
1626 !(lookup.IsProperty() && lookup.IsReadOnly()) && | 1627 !(lookup.IsProperty() && lookup.IsReadOnly()) && |
1627 IsUndeclaredGlobal(object)) { | 1628 IsUndeclaredGlobal(object)) { |
1628 // Strict mode doesn't allow setting non-existent global property. | 1629 // Strict mode doesn't allow setting non-existent global property. |
1629 return ReferenceError("not_defined", name); | 1630 return ReferenceError("not_defined", name); |
1630 } | 1631 } |
1631 | 1632 |
(...skipping 1341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2973 #undef ADDR | 2974 #undef ADDR |
2974 }; | 2975 }; |
2975 | 2976 |
2976 | 2977 |
2977 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2978 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2978 return IC_utilities[id]; | 2979 return IC_utilities[id]; |
2979 } | 2980 } |
2980 | 2981 |
2981 | 2982 |
2982 } } // namespace v8::internal | 2983 } } // namespace v8::internal |
OLD | NEW |