Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(69)

Side by Side Diff: src/ic.cc

Issue 14611006: Cleanup IC heuristics. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed nit Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ic.h ('k') | src/objects.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/ic.h ('k') | src/objects.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698