| 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 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 293 // The stub was generated for JSObject but called for non-JSObject. | 293 // The stub was generated for JSObject but called for non-JSObject. |
| 294 // IC::GetCodeCacheHolder is not applicable. | 294 // IC::GetCodeCacheHolder is not applicable. |
| 295 if (!receiver->IsJSObject()) return false; | 295 if (!receiver->IsJSObject()) return false; |
| 296 break; | 296 break; |
| 297 case PROTOTYPE_MAP: | 297 case PROTOTYPE_MAP: |
| 298 // IC::GetCodeCacheHolder is not applicable. | 298 // IC::GetCodeCacheHolder is not applicable. |
| 299 if (receiver->GetPrototype(isolate())->IsNull()) return false; | 299 if (receiver->GetPrototype(isolate())->IsNull()) return false; |
| 300 break; | 300 break; |
| 301 } | 301 } |
| 302 | 302 |
| 303 Map* map = IC::GetCodeCacheHolder(isolate(), *receiver, cache_holder)->map(); | 303 Handle<Map> map( |
| 304 IC::GetCodeCacheHolder(isolate(), *receiver, cache_holder)->map()); |
| 304 | 305 |
| 305 // Decide whether the inline cache failed because of changes to the | 306 // Decide whether the inline cache failed because of changes to the |
| 306 // receiver itself or changes to one of its prototypes. | 307 // receiver itself or changes to one of its prototypes. |
| 307 // | 308 // |
| 308 // If there are changes to the receiver itself, the map of the | 309 // If there are changes to the receiver itself, the map of the |
| 309 // receiver will have changed and the current target will not be in | 310 // receiver will have changed and the current target will not be in |
| 310 // the receiver map's code cache. Therefore, if the current target | 311 // the receiver map's code cache. Therefore, if the current target |
| 311 // is in the receiver map's code cache, the inline cache failed due | 312 // is in the receiver map's code cache, the inline cache failed due |
| 312 // to prototype check failure. | 313 // to prototype check failure. |
| 313 int index = map->IndexInCodeCache(*name, *target()); | 314 int index = map->IndexInCodeCache(*name, *target()); |
| 314 if (index >= 0) { | 315 if (index >= 0) { |
| 315 map->RemoveFromCodeCache(*name, *target(), index); | 316 map->RemoveFromCodeCache(*name, *target(), index); |
| 316 // Handlers are stored in addition to the ICs on the map. Remove those, too. | 317 // Handlers are stored in addition to the ICs on the map. Remove those, too. |
| 317 Code* handler = target()->FindFirstHandler(); | 318 TryRemoveInvalidHandlers(map, name); |
| 318 if (handler != NULL) { | |
| 319 index = map->IndexInCodeCache(*name, handler); | |
| 320 if (index >= 0) { | |
| 321 map->RemoveFromCodeCache(*name, handler, index); | |
| 322 } | |
| 323 } | |
| 324 return true; | 319 return true; |
| 325 } | 320 } |
| 326 | 321 |
| 327 // The stub is not in the cache. We've ruled out all other kinds of failure | 322 // The stub is not in the cache. We've ruled out all other kinds of failure |
| 328 // except for proptotype chain changes, a deprecated map, a map that's | 323 // except for proptotype chain changes, a deprecated map, a map that's |
| 329 // different from the one that the stub expects, elements kind changes, or a | 324 // different from the one that the stub expects, elements kind changes, or a |
| 330 // constant global property that will become mutable. Threat all those | 325 // constant global property that will become mutable. Threat all those |
| 331 // situations as prototype failures (stay monomorphic if possible). | 326 // situations as prototype failures (stay monomorphic if possible). |
| 332 | 327 |
| 333 // If the IC is shared between multiple receivers (slow dictionary mode), then | 328 // If the IC is shared between multiple receivers (slow dictionary mode), then |
| 334 // the map cannot be deprecated and the stub invalidated. | 329 // the map cannot be deprecated and the stub invalidated. |
| 335 if (cache_holder == OWN_MAP) { | 330 if (cache_holder == OWN_MAP) { |
| 336 Map* old_map = target()->FindFirstMap(); | 331 Map* old_map = target()->FindFirstMap(); |
| 337 if (old_map == map) return true; | 332 if (old_map == *map) return true; |
| 338 if (old_map != NULL) { | 333 if (old_map != NULL) { |
| 339 if (old_map->is_deprecated()) return true; | 334 if (old_map->is_deprecated()) return true; |
| 340 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(), | 335 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(), |
| 341 map->elements_kind())) { | 336 map->elements_kind())) { |
| 342 return true; | 337 return true; |
| 343 } | 338 } |
| 344 } | 339 } |
| 345 } | 340 } |
| 346 | 341 |
| 347 if (receiver->IsGlobalObject()) { | 342 if (receiver->IsGlobalObject()) { |
| 348 LookupResult lookup(isolate()); | 343 LookupResult lookup(isolate()); |
| 349 GlobalObject* global = GlobalObject::cast(*receiver); | 344 GlobalObject* global = GlobalObject::cast(*receiver); |
| 350 global->LocalLookupRealNamedProperty(*name, &lookup); | 345 global->LocalLookupRealNamedProperty(*name, &lookup); |
| 351 if (!lookup.IsFound()) return false; | 346 if (!lookup.IsFound()) return false; |
| 352 PropertyCell* cell = global->GetPropertyCell(&lookup); | 347 PropertyCell* cell = global->GetPropertyCell(&lookup); |
| 353 return cell->type()->IsConstant(); | 348 return cell->type()->IsConstant(); |
| 354 } | 349 } |
| 355 | 350 |
| 356 return false; | 351 return false; |
| 357 } | 352 } |
| 358 | 353 |
| 359 | 354 |
| 355 void IC::TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name) { |
| 356 CodeHandleList handlers; |
| 357 target()->FindHandlers(&handlers); |
| 358 for (int i = 0; i < handlers.length(); i++) { |
| 359 Handle<Code> handler = handlers.at(i); |
| 360 int index = map->IndexInCodeCache(*name, *handler); |
| 361 if (index >= 0) { |
| 362 map->RemoveFromCodeCache(*name, *handler, index); |
| 363 return; |
| 364 } |
| 365 } |
| 366 } |
| 367 |
| 368 |
| 360 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { | 369 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { |
| 361 if (state() != MONOMORPHIC || !name->IsString()) return; | 370 if (!name->IsString()) return; |
| 371 if (state() != MONOMORPHIC) { |
| 372 if (state() == POLYMORPHIC && receiver->IsHeapObject()) { |
| 373 TryRemoveInvalidHandlers( |
| 374 handle(Handle<HeapObject>::cast(receiver)->map()), |
| 375 Handle<String>::cast(name)); |
| 376 } |
| 377 return; |
| 378 } |
| 362 if (receiver->IsUndefined() || receiver->IsNull()) return; | 379 if (receiver->IsUndefined() || receiver->IsNull()) return; |
| 363 | 380 |
| 364 // Remove the target from the code cache if it became invalid | 381 // Remove the target from the code cache if it became invalid |
| 365 // because of changes in the prototype chain to avoid hitting it | 382 // because of changes in the prototype chain to avoid hitting it |
| 366 // again. | 383 // again. |
| 367 if (TryRemoveInvalidPrototypeDependentStub( | 384 if (TryRemoveInvalidPrototypeDependentStub( |
| 368 receiver, Handle<String>::cast(name))) { | 385 receiver, Handle<String>::cast(name))) { |
| 369 return MarkMonomorphicPrototypeFailure(); | 386 return MarkMonomorphicPrototypeFailure(); |
| 370 } | 387 } |
| 371 | 388 |
| (...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1115 } else { | 1132 } else { |
| 1116 KeyedLoadFieldStub stub(true, length_index, Representation::Tagged()); | 1133 KeyedLoadFieldStub stub(true, length_index, Representation::Tagged()); |
| 1117 code = stub.GetCode(isolate()); | 1134 code = stub.GetCode(isolate()); |
| 1118 } | 1135 } |
| 1119 } else if (!object->IsJSObject()) { | 1136 } else if (!object->IsJSObject()) { |
| 1120 // TODO(jkummerow): It would be nice to support non-JSObjects in | 1137 // TODO(jkummerow): It would be nice to support non-JSObjects in |
| 1121 // ComputeLoadHandler, then we wouldn't need to go generic here. | 1138 // ComputeLoadHandler, then we wouldn't need to go generic here. |
| 1122 code = slow_stub(); | 1139 code = slow_stub(); |
| 1123 } else { | 1140 } else { |
| 1124 code = ComputeLoadHandler(lookup, Handle<JSObject>::cast(receiver), name); | 1141 code = ComputeLoadHandler(lookup, Handle<JSObject>::cast(receiver), name); |
| 1125 if (code.is_null()) code = slow_stub(); | |
| 1126 } | 1142 } |
| 1127 | 1143 |
| 1128 PatchCache(receiver, name, code); | 1144 PatchCache(receiver, name, code); |
| 1129 TRACE_IC("LoadIC", name); | 1145 TRACE_IC("LoadIC", name); |
| 1130 } | 1146 } |
| 1131 | 1147 |
| 1132 | 1148 |
| 1133 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) { | 1149 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) { |
| 1134 // Cache code holding map should be consistent with | 1150 // Cache code holding map should be consistent with |
| 1135 // GenerateMonomorphicCacheProbe. | 1151 // GenerateMonomorphicCacheProbe. |
| 1136 isolate()->stub_cache()->Set(name, map, code); | 1152 isolate()->stub_cache()->Set(name, map, code); |
| 1137 } | 1153 } |
| 1138 | 1154 |
| 1139 | 1155 |
| 1140 Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup, | 1156 Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup, |
| 1141 Handle<JSObject> receiver, | 1157 Handle<JSObject> receiver, |
| 1142 Handle<String> name) { | 1158 Handle<String> name) { |
| 1143 if (!lookup->IsProperty()) { | 1159 if (!lookup->IsProperty()) { |
| 1144 // Nonexistent property. The result is undefined. | 1160 return kind() == Code::LOAD_IC |
| 1145 return isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver); | 1161 ? isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver) |
| 1162 : generic_stub(); |
| 1146 } | 1163 } |
| 1147 | 1164 |
| 1148 // Compute monomorphic stub. | 1165 Handle<Code> code = isolate()->stub_cache()->FindHandler( |
| 1166 name, receiver, kind()); |
| 1167 if (!code.is_null()) return code; |
| 1168 |
| 1169 code = CompileLoadHandler(lookup, receiver, name); |
| 1170 if (code.is_null()) return slow_stub(); |
| 1171 |
| 1172 if (code->is_handler() && code->type() != Code::NORMAL) { |
| 1173 HeapObject::UpdateMapCodeCache(receiver, name, code); |
| 1174 } |
| 1175 |
| 1176 return code; |
| 1177 } |
| 1178 |
| 1179 |
| 1180 Handle<Code> LoadIC::CompileLoadHandler(LookupResult* lookup, |
| 1181 Handle<JSObject> receiver, |
| 1182 Handle<String> name) { |
| 1149 Handle<JSObject> holder(lookup->holder()); | 1183 Handle<JSObject> holder(lookup->holder()); |
| 1150 switch (lookup->type()) { | 1184 switch (lookup->type()) { |
| 1151 case FIELD: | 1185 case FIELD: |
| 1152 return isolate()->stub_cache()->ComputeLoadField( | 1186 return isolate()->stub_cache()->ComputeLoadField( |
| 1153 name, receiver, holder, | 1187 name, receiver, holder, |
| 1154 lookup->GetFieldIndex(), lookup->representation()); | 1188 lookup->GetFieldIndex(), lookup->representation()); |
| 1155 case CONSTANT: { | 1189 case CONSTANT: { |
| 1156 Handle<Object> constant(lookup->GetConstant(), isolate()); | 1190 Handle<Object> constant(lookup->GetConstant(), isolate()); |
| 1157 // TODO(2803): Don't compute a stub for cons strings because they cannot | 1191 // TODO(2803): Don't compute a stub for cons strings because they cannot |
| 1158 // be embedded into code. | 1192 // be embedded into code. |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1349 ASSERT(!stub.is_null()); | 1383 ASSERT(!stub.is_null()); |
| 1350 set_target(*stub); | 1384 set_target(*stub); |
| 1351 TRACE_IC("LoadIC", key); | 1385 TRACE_IC("LoadIC", key); |
| 1352 } | 1386 } |
| 1353 | 1387 |
| 1354 | 1388 |
| 1355 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); | 1389 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); |
| 1356 } | 1390 } |
| 1357 | 1391 |
| 1358 | 1392 |
| 1359 Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup, | 1393 Handle<Code> KeyedLoadIC::CompileLoadHandler(LookupResult* lookup, |
| 1360 Handle<JSObject> receiver, | 1394 Handle<JSObject> receiver, |
| 1361 Handle<String> name) { | 1395 Handle<String> name) { |
| 1362 // Bail out if we didn't find a result. | |
| 1363 if (!lookup->IsProperty()) return Handle<Code>::null(); | |
| 1364 | |
| 1365 // Compute a monomorphic stub. | 1396 // Compute a monomorphic stub. |
| 1366 Handle<JSObject> holder(lookup->holder(), isolate()); | 1397 Handle<JSObject> holder(lookup->holder(), isolate()); |
| 1367 switch (lookup->type()) { | 1398 switch (lookup->type()) { |
| 1368 case FIELD: | 1399 case FIELD: |
| 1369 return isolate()->stub_cache()->ComputeKeyedLoadField( | 1400 return isolate()->stub_cache()->ComputeKeyedLoadField( |
| 1370 name, receiver, holder, | 1401 name, receiver, holder, |
| 1371 lookup->GetFieldIndex(), lookup->representation()); | 1402 lookup->GetFieldIndex(), lookup->representation()); |
| 1372 case CONSTANT: { | 1403 case CONSTANT: { |
| 1373 Handle<Object> constant(lookup->GetConstant(), isolate()); | 1404 Handle<Object> constant(lookup->GetConstant(), isolate()); |
| 1374 // TODO(2803): Don't compute a stub for cons strings because they cannot | 1405 // TODO(2803): Don't compute a stub for cons strings because they cannot |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1596 Handle<JSObject> receiver, | 1627 Handle<JSObject> receiver, |
| 1597 Handle<String> name, | 1628 Handle<String> name, |
| 1598 Handle<Object> value) { | 1629 Handle<Object> value) { |
| 1599 ASSERT(!receiver->IsJSGlobalProxy()); | 1630 ASSERT(!receiver->IsJSGlobalProxy()); |
| 1600 ASSERT(lookup->IsFound()); | 1631 ASSERT(lookup->IsFound()); |
| 1601 | 1632 |
| 1602 // These are not cacheable, so we never see such LookupResults here. | 1633 // These are not cacheable, so we never see such LookupResults here. |
| 1603 ASSERT(!lookup->IsHandler()); | 1634 ASSERT(!lookup->IsHandler()); |
| 1604 | 1635 |
| 1605 Handle<Code> code = ComputeStoreHandler(lookup, receiver, name, value); | 1636 Handle<Code> code = ComputeStoreHandler(lookup, receiver, name, value); |
| 1606 if (code.is_null()) { | |
| 1607 set_target(*generic_stub()); | |
| 1608 return; | |
| 1609 } | |
| 1610 | 1637 |
| 1611 PatchCache(receiver, name, code); | 1638 PatchCache(receiver, name, code); |
| 1612 TRACE_IC("StoreIC", name); | 1639 TRACE_IC("StoreIC", name); |
| 1613 } | 1640 } |
| 1614 | 1641 |
| 1615 | 1642 |
| 1616 Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup, | 1643 Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup, |
| 1617 Handle<JSObject> receiver, | 1644 Handle<JSObject> receiver, |
| 1618 Handle<String> name, | 1645 Handle<String> name, |
| 1619 Handle<Object> value) { | 1646 Handle<Object> value) { |
| 1647 Handle<Code> code = isolate()->stub_cache()->FindHandler( |
| 1648 name, receiver, kind(), strict_mode()); |
| 1649 if (!code.is_null()) return code; |
| 1650 |
| 1651 code = CompileStoreHandler(lookup, receiver, name, value); |
| 1652 if (code.is_null()) return generic_stub(); |
| 1653 |
| 1654 if (code->is_handler() && code->type() != Code::NORMAL) { |
| 1655 HeapObject::UpdateMapCodeCache(receiver, name, code); |
| 1656 } |
| 1657 |
| 1658 return code; |
| 1659 } |
| 1660 |
| 1661 |
| 1662 Handle<Code> StoreIC::CompileStoreHandler(LookupResult* lookup, |
| 1663 Handle<JSObject> receiver, |
| 1664 Handle<String> name, |
| 1665 Handle<Object> value) { |
| 1620 Handle<JSObject> holder(lookup->holder()); | 1666 Handle<JSObject> holder(lookup->holder()); |
| 1621 switch (lookup->type()) { | 1667 switch (lookup->type()) { |
| 1622 case FIELD: | 1668 case FIELD: |
| 1623 return isolate()->stub_cache()->ComputeStoreField( | 1669 return isolate()->stub_cache()->ComputeStoreField( |
| 1624 name, receiver, lookup, strict_mode()); | 1670 name, receiver, lookup, strict_mode()); |
| 1625 case NORMAL: | 1671 case NORMAL: |
| 1626 if (receiver->IsGlobalObject()) { | 1672 if (receiver->IsGlobalObject()) { |
| 1627 // The stub generated for the global object picks the value directly | 1673 // The stub generated for the global object picks the value directly |
| 1628 // from the property cell. So the property must be directly on the | 1674 // from the property cell. So the property must be directly on the |
| 1629 // global object. | 1675 // global object. |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1998 ASSERT(!stub.is_null()); | 2044 ASSERT(!stub.is_null()); |
| 1999 set_target(*stub); | 2045 set_target(*stub); |
| 2000 TRACE_IC("StoreIC", key); | 2046 TRACE_IC("StoreIC", key); |
| 2001 } | 2047 } |
| 2002 | 2048 |
| 2003 return Runtime::SetObjectPropertyOrFail( | 2049 return Runtime::SetObjectPropertyOrFail( |
| 2004 isolate(), object , key, value, NONE, strict_mode()); | 2050 isolate(), object , key, value, NONE, strict_mode()); |
| 2005 } | 2051 } |
| 2006 | 2052 |
| 2007 | 2053 |
| 2008 Handle<Code> KeyedStoreIC::ComputeStoreHandler(LookupResult* lookup, | 2054 Handle<Code> KeyedStoreIC::CompileStoreHandler(LookupResult* lookup, |
| 2009 Handle<JSObject> receiver, | 2055 Handle<JSObject> receiver, |
| 2010 Handle<String> name, | 2056 Handle<String> name, |
| 2011 Handle<Object> value) { | 2057 Handle<Object> value) { |
| 2012 // If the property has a non-field type allowing map transitions | 2058 // If the property has a non-field type allowing map transitions |
| 2013 // where there is extra room in the object, we leave the IC in its | 2059 // where there is extra room in the object, we leave the IC in its |
| 2014 // current state. | 2060 // current state. |
| 2015 switch (lookup->type()) { | 2061 switch (lookup->type()) { |
| 2016 case FIELD: | 2062 case FIELD: |
| 2017 return isolate()->stub_cache()->ComputeKeyedStoreField( | 2063 return isolate()->stub_cache()->ComputeKeyedStoreField( |
| 2018 name, receiver, lookup, strict_mode()); | 2064 name, receiver, lookup, strict_mode()); |
| (...skipping 754 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2773 #undef ADDR | 2819 #undef ADDR |
| 2774 }; | 2820 }; |
| 2775 | 2821 |
| 2776 | 2822 |
| 2777 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2823 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2778 return IC_utilities[id]; | 2824 return IC_utilities[id]; |
| 2779 } | 2825 } |
| 2780 | 2826 |
| 2781 | 2827 |
| 2782 } } // namespace v8::internal | 2828 } } // namespace v8::internal |
| OLD | NEW |