| 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 |