Chromium Code Reviews| 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() || |
|
danno
2013/05/02 11:36:06
// Determine whether the failure is due to a name
Toon Verwaest
2013/05/02 12:27:20
Done.
| |
| 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 if (!name->IsName()) return false; |
| 189 if (map != NULL && map->is_deprecated()) { | 189 Name* stub_name = target->FindFirstName(); |
| 190 return true; | 190 if (Name::cast(name) != stub_name) return false; |
| 191 } | |
| 192 } | 191 } |
| 193 | 192 |
| 194 InlineCacheHolderFlag cache_holder = | 193 InlineCacheHolderFlag cache_holder = |
| 195 Code::ExtractCacheHolderFromFlags(target->flags()); | 194 Code::ExtractCacheHolderFromFlags(target->flags()); |
| 196 | 195 |
| 197 Isolate* isolate = target->GetIsolate(); | 196 Isolate* isolate = target->GetIsolate(); |
| 198 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { | 197 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { |
| 199 // The stub was generated for JSObject but called for non-JSObject. | 198 // The stub was generated for JSObject but called for non-JSObject. |
| 200 // IC::GetCodeCacheHolder is not applicable. | 199 // IC::GetCodeCacheHolder is not applicable. |
| 201 return false; | 200 return false; |
| 202 } else if (cache_holder == PROTOTYPE_MAP && | 201 } else if (cache_holder == PROTOTYPE_MAP && |
| 203 receiver->GetPrototype(isolate)->IsNull()) { | 202 receiver->GetPrototype(isolate)->IsNull()) { |
| 204 // IC::GetCodeCacheHolder is not applicable. | 203 // IC::GetCodeCacheHolder is not applicable. |
| 205 return false; | 204 return false; |
| 206 } | 205 } |
| 207 Map* map = IC::GetCodeCacheHolder(isolate, receiver, cache_holder)->map(); | 206 Map* map = IC::GetCodeCacheHolder(isolate, receiver, cache_holder)->map(); |
| 208 | 207 |
| 209 // Decide whether the inline cache failed because of changes to the | 208 // Decide whether the inline cache failed because of changes to the |
| 210 // receiver itself or changes to one of its prototypes. | 209 // receiver itself or changes to one of its prototypes. |
| 211 // | 210 // |
| 212 // If there are changes to the receiver itself, the map of the | 211 // 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 | 212 // receiver will have changed and the current target will not be in |
| 214 // the receiver map's code cache. Therefore, if the current target | 213 // 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 | 214 // is in the receiver map's code cache, the inline cache failed due |
| 216 // to prototype check failure. | 215 // to prototype check failure. |
| 217 int index = map->IndexInCodeCache(name, target); | 216 int index = map->IndexInCodeCache(name, target); |
| 218 if (index >= 0) { | 217 if (index >= 0) { |
| 219 map->RemoveFromCodeCache(String::cast(name), target, index); | 218 map->RemoveFromCodeCache(String::cast(name), target, index); |
| 219 if (target->is_load_stub() || target->is_keyed_load_stub()) { | |
|
danno
2013/05/02 11:36:06
// For loads, handlers are stored in addition to t
Toon Verwaest
2013/05/02 12:27:20
Done.
| |
| 220 Code* handler = target->FindFirstCode(); | |
| 221 index = map->IndexInCodeCache(name, handler); | |
| 222 if (index >= 0) { | |
| 223 map->RemoveFromCodeCache(String::cast(name), handler, index); | |
| 224 } | |
| 225 } | |
| 220 return true; | 226 return true; |
| 221 } | 227 } |
| 222 | 228 |
| 223 return false; | 229 if (cache_holder != OWN_MAP) return false; |
|
danno
2013/05/02 11:36:06
// If the IC is shared between multiple receivers
Toon Verwaest
2013/05/02 12:27:20
Done.
| |
| 230 | |
| 231 // Also flag monomorphic prototype failure if the old map was deprecated. | |
| 232 Map* old_map = target->FindFirstMap(); | |
| 233 if (old_map == NULL) return false; | |
| 234 return old_map == map || old_map->is_deprecated(); | |
|
danno
2013/05/02 11:36:06
// The stub is not in the cache. We've ruled out a
Toon Verwaest
2013/05/02 12:27:20
Done.
| |
| 224 } | 235 } |
| 225 | 236 |
| 226 | 237 |
| 227 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { | 238 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { |
| 228 IC::State state = target->ic_state(); | 239 IC::State state = target->ic_state(); |
| 229 | 240 |
| 230 if (state != MONOMORPHIC || !name->IsString()) return state; | 241 if (state != MONOMORPHIC || !name->IsString()) return state; |
| 231 if (receiver->IsUndefined() || receiver->IsNull()) return state; | 242 if (receiver->IsUndefined() || receiver->IsNull()) return state; |
| 232 | 243 |
| 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(); | 244 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 | 245 // Remove the target from the code cache if it became invalid |
| 244 // because of changes in the prototype chain to avoid hitting it | 246 // because of changes in the prototype chain to avoid hitting it |
| 245 // again. | 247 // again. |
| 246 // Call stubs handle this later to allow extra IC state | 248 // Call stubs handle this later to allow extra IC state |
| 247 // transitions. | 249 // transitions. |
| 248 if (kind != Code::CALL_IC && | 250 if (kind != Code::CALL_IC && kind != Code::KEYED_CALL_IC && |
| 249 TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) { | 251 TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) { |
| 250 return MONOMORPHIC_PROTOTYPE_FAILURE; | 252 return MONOMORPHIC_PROTOTYPE_FAILURE; |
| 251 } | 253 } |
| 252 | 254 |
| 253 // The builtins object is special. It only changes when JavaScript | 255 // The builtins object is special. It only changes when JavaScript |
| 254 // builtins are loaded lazily. It is important to keep inline | 256 // builtins are loaded lazily. It is important to keep inline |
| 255 // caches for the builtins object monomorphic. Therefore, if we get | 257 // caches for the builtins object monomorphic. Therefore, if we get |
| 256 // an inline cache miss for the builtins object after lazily loading | 258 // an inline cache miss for the builtins object after lazily loading |
| 257 // JavaScript builtins, we return uninitialized as the state to | 259 // JavaScript builtins, we return uninitialized as the state to |
| 258 // force the inline cache back to monomorphic state. | 260 // 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. | 719 // This is the first time we execute this inline cache. |
| 718 // Set the target to the pre monomorphic stub to delay | 720 // Set the target to the pre monomorphic stub to delay |
| 719 // setting the monomorphic state. | 721 // setting the monomorphic state. |
| 720 code = isolate()->stub_cache()->ComputeCallPreMonomorphic( | 722 code = isolate()->stub_cache()->ComputeCallPreMonomorphic( |
| 721 argc, kind_, extra_ic_state); | 723 argc, kind_, extra_ic_state); |
| 722 } else if (state == MONOMORPHIC) { | 724 } else if (state == MONOMORPHIC) { |
| 723 if (kind_ == Code::CALL_IC && | 725 if (kind_ == Code::CALL_IC && |
| 724 TryUpdateExtraICState(lookup, object, &extra_ic_state)) { | 726 TryUpdateExtraICState(lookup, object, &extra_ic_state)) { |
| 725 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, | 727 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, |
| 726 object, name); | 728 object, name); |
| 727 } else if (kind_ == Code::CALL_IC && | 729 } else if (TryRemoveInvalidPrototypeDependentStub(target(), |
| 728 TryRemoveInvalidPrototypeDependentStub(target(), | |
| 729 *object, | 730 *object, |
| 730 *name)) { | 731 *name)) { |
| 731 state = MONOMORPHIC_PROTOTYPE_FAILURE; | 732 state = MONOMORPHIC_PROTOTYPE_FAILURE; |
| 732 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, | 733 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, |
| 733 object, name); | 734 object, name); |
| 734 } else { | 735 } else { |
| 735 code = isolate()->stub_cache()->ComputeCallMegamorphic( | 736 code = isolate()->stub_cache()->ComputeCallMegamorphic( |
| 736 argc, kind_, extra_ic_state); | 737 argc, kind_, extra_ic_state); |
| 737 } | 738 } |
| 738 } else { | 739 } else { |
| 739 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, | 740 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, |
| 740 object, name); | 741 object, name); |
| 741 } | 742 } |
| 742 | 743 |
| 743 // If there's no appropriate stub we simply avoid updating the caches. | 744 // If there's no appropriate stub we simply avoid updating the caches. |
| 744 if (code.is_null()) return; | 745 if (code.is_null()) return; |
| 745 | 746 |
| 746 // Patch the call site depending on the state of the cache. | 747 // Patch the call site depending on the state of the cache. |
| 747 switch (state) { | 748 switch (state) { |
| 748 case UNINITIALIZED: | 749 case UNINITIALIZED: |
| 749 case MONOMORPHIC_PROTOTYPE_FAILURE: | 750 case MONOMORPHIC_PROTOTYPE_FAILURE: |
| 750 case PREMONOMORPHIC: | 751 case PREMONOMORPHIC: |
| 751 set_target(*code); | |
| 752 break; | |
| 753 case MONOMORPHIC: | 752 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); | 753 set_target(*code); |
| 761 break; | 754 break; |
| 762 case MEGAMORPHIC: { | 755 case MEGAMORPHIC: { |
| 763 // Cache code holding map should be consistent with | 756 // Cache code holding map should be consistent with |
| 764 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. | 757 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. |
| 765 Handle<JSObject> cache_object = object->IsJSObject() | 758 Handle<JSObject> cache_object = object->IsJSObject() |
| 766 ? Handle<JSObject>::cast(object) | 759 ? Handle<JSObject>::cast(object) |
| 767 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())), | 760 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())), |
| 768 isolate()); | 761 isolate()); |
| 769 // Update the stub cache. | 762 // Update the stub cache. |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1000 if (number_of_valid_maps >= 4) return false; | 993 if (number_of_valid_maps >= 4) return false; |
| 1001 | 994 |
| 1002 // Only allow 0 maps in case target() was reset to UNINITIALIZED by the GC. | 995 // 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. | 996 // In that case, allow the IC to go back monomorphic. |
| 1004 if (number_of_maps == 0 && target()->ic_state() != UNINITIALIZED) { | 997 if (number_of_maps == 0 && target()->ic_state() != UNINITIALIZED) { |
| 1005 return false; | 998 return false; |
| 1006 } | 999 } |
| 1007 target()->FindAllCode(&handlers, receiver_maps.length()); | 1000 target()->FindAllCode(&handlers, receiver_maps.length()); |
| 1008 } | 1001 } |
| 1009 | 1002 |
| 1010 if (!AddOneReceiverMapIfMissing(&receiver_maps, | 1003 bool overwrote = false; |
|
danno
2013/05/02 11:36:06
// If the name doesn't match, go generic. Otherwis
Toon Verwaest
2013/05/02 12:27:20
Done.
| |
| 1011 Handle<Map>(receiver->map()))) { | 1004 Handle<Map> new_receiver_map(receiver->map()); |
| 1012 return false; | 1005 for (int current = 0; current < receiver_maps.length(); ++current) { |
| 1006 if (!receiver_maps.at(current).is_null() && | |
| 1007 receiver_maps.at(current).is_identical_to(new_receiver_map)) { | |
| 1008 overwrote = true; | |
| 1009 handlers.InsertAt(current, code); | |
| 1010 break; | |
| 1011 } | |
| 1013 } | 1012 } |
|
danno
2013/05/02 11:36:06
Move this loop about the code above to get the map
Toon Verwaest
2013/05/02 12:27:20
Done.
| |
| 1014 | 1013 |
| 1015 handlers.Add(code); | 1014 if (!overwrote) { |
| 1015 receiver_maps.Add(new_receiver_map); | |
| 1016 handlers.Add(code); | |
| 1017 number_of_valid_maps++; | |
| 1018 } | |
| 1019 | |
| 1016 Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC( | 1020 Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC( |
| 1017 &receiver_maps, &handlers, number_of_valid_maps + 1, name); | 1021 &receiver_maps, &handlers, number_of_valid_maps, name); |
| 1018 set_target(*ic); | 1022 set_target(*ic); |
| 1019 return true; | 1023 return true; |
| 1020 } | 1024 } |
| 1021 | 1025 |
| 1022 | 1026 |
| 1023 void LoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver, | 1027 void LoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver, |
| 1024 Handle<Code> handler, | 1028 Handle<Code> handler, |
| 1025 Handle<String> name) { | 1029 Handle<String> name) { |
| 1026 if (handler->type() == Code::NORMAL) return set_target(*handler); | 1030 if (handler->type() == Code::NORMAL) return set_target(*handler); |
| 1027 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC( | 1031 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC( |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1042 | 1046 |
| 1043 void IC::CopyICToMegamorphicCache(Handle<String> name) { | 1047 void IC::CopyICToMegamorphicCache(Handle<String> name) { |
| 1044 MapHandleList receiver_maps; | 1048 MapHandleList receiver_maps; |
| 1045 CodeHandleList handlers; | 1049 CodeHandleList handlers; |
| 1046 { | 1050 { |
| 1047 AssertNoAllocation no_gc; | 1051 AssertNoAllocation no_gc; |
| 1048 target()->FindAllMaps(&receiver_maps); | 1052 target()->FindAllMaps(&receiver_maps); |
| 1049 target()->FindAllCode(&handlers, receiver_maps.length()); | 1053 target()->FindAllCode(&handlers, receiver_maps.length()); |
| 1050 } | 1054 } |
| 1051 for (int i = 0; i < receiver_maps.length(); i++) { | 1055 for (int i = 0; i < receiver_maps.length(); i++) { |
| 1056 if (receiver_maps.at(i)->is_deprecated()) continue; | |
|
danno
2013/05/02 11:36:06
Maybe defer this to Crankshaft? Don't throw away t
Toon Verwaest
2013/05/02 12:27:20
Done.
| |
| 1052 UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i)); | 1057 UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i)); |
| 1053 } | 1058 } |
| 1054 } | 1059 } |
| 1055 | 1060 |
| 1056 | 1061 |
| 1057 bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) { | 1062 bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) { |
| 1058 AssertNoAllocation no_allocation; | 1063 AssertNoAllocation no_allocation; |
| 1059 | 1064 |
| 1060 Map* current_map = target()->FindFirstMap(); | 1065 Map* current_map = target()->FindFirstMap(); |
| 1061 ElementsKind receiver_elements_kind = receiver_map->elements_kind(); | 1066 ElementsKind receiver_elements_kind = receiver_map->elements_kind(); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1094 is_same_handler = old_handler == *code; | 1099 is_same_handler = old_handler == *code; |
| 1095 } | 1100 } |
| 1096 if (is_same_handler | 1101 if (is_same_handler |
| 1097 && IsTransitionedMapOfMonomorphicTarget(receiver->map())) { | 1102 && IsTransitionedMapOfMonomorphicTarget(receiver->map())) { |
| 1098 UpdateMonomorphicIC(receiver, code, name); | 1103 UpdateMonomorphicIC(receiver, code, name); |
| 1099 break; | 1104 break; |
| 1100 } | 1105 } |
| 1101 if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) { | 1106 if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) { |
| 1102 break; | 1107 break; |
| 1103 } | 1108 } |
| 1104 } | 1109 |
| 1105 if (target()->type() != Code::NORMAL) { | 1110 if (target()->type() != Code::NORMAL) { |
| 1106 if (target()->is_load_stub()) { | |
| 1107 CopyICToMegamorphicCache(name); | 1111 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 } | 1112 } |
| 1137 } | 1113 } |
| 1138 | 1114 |
| 1139 UpdateMegamorphicCache(receiver->map(), *name, *code); | 1115 UpdateMegamorphicCache(receiver->map(), *name, *code); |
| 1140 set_target((strict_mode == kStrictMode) | 1116 set_target((strict_mode == kStrictMode) |
| 1141 ? *megamorphic_stub_strict() | 1117 ? *megamorphic_stub_strict() |
| 1142 : *megamorphic_stub()); | 1118 : *megamorphic_stub()); |
| 1143 } | 1119 } |
| 1144 break; | 1120 break; |
| 1145 case MEGAMORPHIC: | 1121 case MEGAMORPHIC: |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1228 } else { | 1204 } else { |
| 1229 code = ComputeLoadHandler(lookup, receiver, name); | 1205 code = ComputeLoadHandler(lookup, receiver, name); |
| 1230 if (code.is_null()) return; | 1206 if (code.is_null()) return; |
| 1231 } | 1207 } |
| 1232 | 1208 |
| 1233 PatchCache(state, kNonStrictMode, receiver, name, code); | 1209 PatchCache(state, kNonStrictMode, receiver, name, code); |
| 1234 TRACE_IC("LoadIC", name, state, target()); | 1210 TRACE_IC("LoadIC", name, state, target()); |
| 1235 } | 1211 } |
| 1236 | 1212 |
| 1237 | 1213 |
| 1238 void IC::UpdateMegamorphicCache(Map* map, String* name, Code* code) { | 1214 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) { |
| 1239 // Cache code holding map should be consistent with | 1215 // Cache code holding map should be consistent with |
| 1240 // GenerateMonomorphicCacheProbe. | 1216 // GenerateMonomorphicCacheProbe. |
| 1241 isolate()->stub_cache()->Set(name, map, code); | 1217 isolate()->stub_cache()->Set(name, map, code); |
| 1242 } | 1218 } |
| 1243 | 1219 |
| 1244 | 1220 |
| 1245 Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup, | 1221 Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup, |
| 1246 Handle<JSObject> receiver, | 1222 Handle<JSObject> receiver, |
| 1247 Handle<String> name) { | 1223 Handle<String> name) { |
| 1248 if (!lookup->IsProperty()) { | 1224 if (!lookup->IsProperty()) { |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1490 // repeatedly try to rewrite. | 1466 // repeatedly try to rewrite. |
| 1491 return generic_stub(); | 1467 return generic_stub(); |
| 1492 } | 1468 } |
| 1493 return Handle<Code>::null(); | 1469 return Handle<Code>::null(); |
| 1494 } | 1470 } |
| 1495 | 1471 |
| 1496 | 1472 |
| 1497 static bool LookupForWrite(Handle<JSObject> receiver, | 1473 static bool LookupForWrite(Handle<JSObject> receiver, |
| 1498 Handle<String> name, | 1474 Handle<String> name, |
| 1499 Handle<Object> value, | 1475 Handle<Object> value, |
| 1500 LookupResult* lookup) { | 1476 LookupResult* lookup, |
| 1477 IC::State* state) { | |
| 1501 Handle<JSObject> holder = receiver; | 1478 Handle<JSObject> holder = receiver; |
| 1502 receiver->Lookup(*name, lookup); | 1479 receiver->Lookup(*name, lookup); |
| 1503 if (lookup->IsFound()) { | 1480 if (lookup->IsFound()) { |
| 1504 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; | 1481 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; |
| 1505 | 1482 |
| 1506 if (lookup->holder() == *receiver) { | 1483 if (lookup->holder() == *receiver) { |
| 1507 if (lookup->IsInterceptor() && | 1484 if (lookup->IsInterceptor() && |
| 1508 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { | 1485 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { |
| 1509 receiver->LocalLookupRealNamedProperty(*name, lookup); | 1486 receiver->LocalLookupRealNamedProperty(*name, lookup); |
| 1510 return lookup->IsFound() && | 1487 return lookup->IsFound() && |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 1527 // While normally LookupTransition gets passed the receiver, in this case we | 1504 // 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 | 1505 // 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 | 1506 // 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 | 1507 // 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. | 1508 // receiver when trying to fetch extra information from the transition. |
| 1532 receiver->map()->LookupTransition(*holder, *name, lookup); | 1509 receiver->map()->LookupTransition(*holder, *name, lookup); |
| 1533 if (!lookup->IsTransition()) return false; | 1510 if (!lookup->IsTransition()) return false; |
| 1534 PropertyDetails target_details = | 1511 PropertyDetails target_details = |
| 1535 lookup->GetTransitionDetails(receiver->map()); | 1512 lookup->GetTransitionDetails(receiver->map()); |
| 1536 if (target_details.IsReadOnly()) return false; | 1513 if (target_details.IsReadOnly()) return false; |
| 1537 return value->FitsRepresentation(target_details.representation()); | 1514 if (!value->FitsRepresentation(target_details.representation())) { |
|
danno
2013/05/02 11:36:06
Comment this.
Toon Verwaest
2013/05/02 12:27:20
Done.
| |
| 1515 Handle<Map> target(lookup->GetTransitionMapFromMap(receiver->map())); | |
| 1516 Map::GeneralizeRepresentation( | |
| 1517 target, target->LastAdded(), value->OptimalRepresentation()); | |
| 1518 *state = MONOMORPHIC_PROTOTYPE_FAILURE; | |
|
danno
2013/05/02 11:36:06
Check for already deprecated maps? Deprecated maps
Toon Verwaest
2013/05/02 12:27:20
Done.
| |
| 1519 } | |
| 1520 return true; | |
| 1538 } | 1521 } |
| 1539 | 1522 |
| 1540 | 1523 |
| 1541 MaybeObject* StoreIC::Store(State state, | 1524 MaybeObject* StoreIC::Store(State state, |
| 1542 StrictModeFlag strict_mode, | 1525 StrictModeFlag strict_mode, |
| 1543 Handle<Object> object, | 1526 Handle<Object> object, |
| 1544 Handle<String> name, | 1527 Handle<String> name, |
| 1545 Handle<Object> value, | 1528 Handle<Object> value, |
| 1546 JSReceiver::StoreFromKeyed store_mode) { | 1529 JSReceiver::StoreFromKeyed store_mode) { |
| 1547 // Handle proxies. | 1530 // Handle proxies. |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1611 ? global_proxy_stub_strict() | 1594 ? global_proxy_stub_strict() |
| 1612 : global_proxy_stub(); | 1595 : global_proxy_stub(); |
| 1613 set_target(*stub); | 1596 set_target(*stub); |
| 1614 TRACE_IC("StoreIC", name, state, *stub); | 1597 TRACE_IC("StoreIC", name, state, *stub); |
| 1615 } | 1598 } |
| 1616 return JSReceiver::SetPropertyOrFail( | 1599 return JSReceiver::SetPropertyOrFail( |
| 1617 receiver, name, value, NONE, strict_mode, store_mode); | 1600 receiver, name, value, NONE, strict_mode, store_mode); |
| 1618 } | 1601 } |
| 1619 | 1602 |
| 1620 LookupResult lookup(isolate()); | 1603 LookupResult lookup(isolate()); |
| 1621 if (LookupForWrite(receiver, name, value, &lookup)) { | 1604 if (LookupForWrite(receiver, name, value, &lookup, &state)) { |
| 1622 if (FLAG_use_ic) { | 1605 if (FLAG_use_ic) { |
| 1623 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); | 1606 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
| 1624 } | 1607 } |
| 1625 } else if (strict_mode == kStrictMode && | 1608 } else if (strict_mode == kStrictMode && |
| 1626 !(lookup.IsProperty() && lookup.IsReadOnly()) && | 1609 !(lookup.IsProperty() && lookup.IsReadOnly()) && |
| 1627 IsUndeclaredGlobal(object)) { | 1610 IsUndeclaredGlobal(object)) { |
| 1628 // Strict mode doesn't allow setting non-existent global property. | 1611 // Strict mode doesn't allow setting non-existent global property. |
| 1629 return ReferenceError("not_defined", name); | 1612 return ReferenceError("not_defined", name); |
| 1630 } | 1613 } |
| 1631 | 1614 |
| (...skipping 1341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2973 #undef ADDR | 2956 #undef ADDR |
| 2974 }; | 2957 }; |
| 2975 | 2958 |
| 2976 | 2959 |
| 2977 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2960 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2978 return IC_utilities[id]; | 2961 return IC_utilities[id]; |
| 2979 } | 2962 } |
| 2980 | 2963 |
| 2981 | 2964 |
| 2982 } } // namespace v8::internal | 2965 } } // namespace v8::internal |
| OLD | NEW |