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 |