OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 |
11 // with the distribution. | 11 // with the distribution. |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 | 60 |
61 void IC::TraceIC(const char* type, | 61 void IC::TraceIC(const char* type, |
62 Handle<Object> name, | 62 Handle<Object> name, |
63 State old_state, | 63 State old_state, |
64 Code* new_target, | 64 Code* new_target, |
65 const char* extra_info) { | 65 const char* extra_info) { |
66 if (FLAG_trace_ic) { | 66 if (FLAG_trace_ic) { |
67 State new_state = StateFrom(new_target, | 67 State new_state = StateFrom(new_target, |
68 HEAP->undefined_value(), | 68 HEAP->undefined_value(), |
69 HEAP->undefined_value()); | 69 HEAP->undefined_value()); |
70 PrintF("[%s (%c->%c)%s", type, | 70 PrintF("[%s in ", type); |
| 71 StackFrameIterator it; |
| 72 while (it.frame()->fp() != this->fp()) it.Advance(); |
| 73 StackFrame* raw_frame = it.frame(); |
| 74 if (raw_frame->is_internal()) { |
| 75 Isolate* isolate = new_target->GetIsolate(); |
| 76 Code* apply_builtin = isolate->builtins()->builtin( |
| 77 Builtins::kFunctionApply); |
| 78 if (raw_frame->unchecked_code() == apply_builtin) { |
| 79 PrintF("apply from "); |
| 80 it.Advance(); |
| 81 raw_frame = it.frame(); |
| 82 } |
| 83 } |
| 84 if (raw_frame->is_java_script()) { |
| 85 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); |
| 86 Code* js_code = frame->unchecked_code(); |
| 87 // Find the function on the stack and both the active code for the |
| 88 // function and the original code. |
| 89 JSFunction* function = JSFunction::cast(frame->function()); |
| 90 function->PrintName(); |
| 91 int code_offset = address() - js_code->instruction_start(); |
| 92 PrintF("+%d", code_offset); |
| 93 } else { |
| 94 PrintF("<unknown>"); |
| 95 } |
| 96 PrintF(" (%c->%c)%s", |
71 TransitionMarkFromState(old_state), | 97 TransitionMarkFromState(old_state), |
72 TransitionMarkFromState(new_state), | 98 TransitionMarkFromState(new_state), |
73 extra_info); | 99 extra_info); |
74 name->Print(); | 100 name->Print(); |
75 PrintF("]\n"); | 101 PrintF("]\n"); |
76 } | 102 } |
77 } | 103 } |
78 #endif | 104 #endif |
79 | 105 |
80 | 106 |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 | 293 |
268 void IC::Clear(Address address) { | 294 void IC::Clear(Address address) { |
269 Code* target = GetTargetAtAddress(address); | 295 Code* target = GetTargetAtAddress(address); |
270 | 296 |
271 // Don't clear debug break inline cache as it will remove the break point. | 297 // Don't clear debug break inline cache as it will remove the break point. |
272 if (target->ic_state() == DEBUG_BREAK) return; | 298 if (target->ic_state() == DEBUG_BREAK) return; |
273 | 299 |
274 switch (target->kind()) { | 300 switch (target->kind()) { |
275 case Code::LOAD_IC: return LoadIC::Clear(address, target); | 301 case Code::LOAD_IC: return LoadIC::Clear(address, target); |
276 case Code::KEYED_LOAD_IC: | 302 case Code::KEYED_LOAD_IC: |
277 case Code::KEYED_EXTERNAL_ARRAY_LOAD_IC: | |
278 return KeyedLoadIC::Clear(address, target); | 303 return KeyedLoadIC::Clear(address, target); |
279 case Code::STORE_IC: return StoreIC::Clear(address, target); | 304 case Code::STORE_IC: return StoreIC::Clear(address, target); |
280 case Code::KEYED_STORE_IC: | 305 case Code::KEYED_STORE_IC: |
281 case Code::KEYED_EXTERNAL_ARRAY_STORE_IC: | |
282 return KeyedStoreIC::Clear(address, target); | 306 return KeyedStoreIC::Clear(address, target); |
283 case Code::CALL_IC: return CallIC::Clear(address, target); | 307 case Code::CALL_IC: return CallIC::Clear(address, target); |
284 case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); | 308 case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); |
285 case Code::TYPE_RECORDING_UNARY_OP_IC: | 309 case Code::TYPE_RECORDING_UNARY_OP_IC: |
286 case Code::TYPE_RECORDING_BINARY_OP_IC: | 310 case Code::TYPE_RECORDING_BINARY_OP_IC: |
287 case Code::COMPARE_IC: | 311 case Code::COMPARE_IC: |
288 // Clearing these is tricky and does not | 312 // Clearing these is tricky and does not |
289 // make any performance difference. | 313 // make any performance difference. |
290 return; | 314 return; |
291 default: UNREACHABLE(); | 315 default: UNREACHABLE(); |
(...skipping 733 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1025 | 1049 |
1026 isolate()->stub_cache()->Set(*name, map, Code::cast(code)); | 1050 isolate()->stub_cache()->Set(*name, map, Code::cast(code)); |
1027 } | 1051 } |
1028 | 1052 |
1029 #ifdef DEBUG | 1053 #ifdef DEBUG |
1030 TraceIC("LoadIC", name, state, target()); | 1054 TraceIC("LoadIC", name, state, target()); |
1031 #endif | 1055 #endif |
1032 } | 1056 } |
1033 | 1057 |
1034 | 1058 |
| 1059 String* KeyedLoadIC::GetStubNameForCache(IC::State ic_state) { |
| 1060 if (ic_state == MONOMORPHIC) { |
| 1061 return isolate()->heap()->KeyedLoadSpecializedMonomorphic_symbol(); |
| 1062 } else { |
| 1063 ASSERT(ic_state == MEGAMORPHIC); |
| 1064 return isolate()->heap()->KeyedLoadSpecializedPolymorphic_symbol(); |
| 1065 } |
| 1066 } |
| 1067 |
| 1068 |
| 1069 MaybeObject* KeyedLoadIC::GetFastElementStubWithoutMapCheck( |
| 1070 bool is_js_array) { |
| 1071 return KeyedLoadFastElementStub().TryGetCode(); |
| 1072 } |
| 1073 |
| 1074 |
| 1075 MaybeObject* KeyedLoadIC::GetExternalArrayStubWithoutMapCheck( |
| 1076 ExternalArrayType array_type) { |
| 1077 return KeyedLoadExternalArrayStub(array_type).TryGetCode(); |
| 1078 } |
| 1079 |
| 1080 |
| 1081 MaybeObject* KeyedLoadIC::ConstructMegamorphicStub( |
| 1082 MapList* receiver_maps, |
| 1083 CodeList* targets, |
| 1084 StrictModeFlag strict_mode) { |
| 1085 Object* object; |
| 1086 KeyedLoadStubCompiler compiler; |
| 1087 MaybeObject* maybe_code = compiler.CompileLoadMegamorphic(receiver_maps, |
| 1088 targets); |
| 1089 if (!maybe_code->ToObject(&object)) return maybe_code; |
| 1090 isolate()->counters()->keyed_load_polymorphic_stubs()->Increment(); |
| 1091 PROFILE(isolate(), CodeCreateEvent( |
| 1092 Logger::KEYED_LOAD_MEGAMORPHIC_IC_TAG, |
| 1093 Code::cast(object), 0)); |
| 1094 return object; |
| 1095 } |
| 1096 |
| 1097 |
1035 MaybeObject* KeyedLoadIC::Load(State state, | 1098 MaybeObject* KeyedLoadIC::Load(State state, |
1036 Handle<Object> object, | 1099 Handle<Object> object, |
1037 Handle<Object> key) { | 1100 Handle<Object> key, |
| 1101 bool force_generic_stub) { |
1038 // Check for values that can be converted into a symbol. | 1102 // Check for values that can be converted into a symbol. |
1039 // TODO(1295): Remove this code. | 1103 // TODO(1295): Remove this code. |
1040 HandleScope scope(isolate()); | 1104 HandleScope scope(isolate()); |
1041 if (key->IsHeapNumber() && | 1105 if (key->IsHeapNumber() && |
1042 isnan(HeapNumber::cast(*key)->value())) { | 1106 isnan(HeapNumber::cast(*key)->value())) { |
1043 key = isolate()->factory()->nan_symbol(); | 1107 key = isolate()->factory()->nan_symbol(); |
1044 } else if (key->IsUndefined()) { | 1108 } else if (key->IsUndefined()) { |
1045 key = isolate()->factory()->undefined_symbol(); | 1109 key = isolate()->factory()->undefined_symbol(); |
1046 } | 1110 } |
1047 | 1111 |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1153 | 1217 |
1154 return object->GetProperty(*object, &lookup, *name, &attr); | 1218 return object->GetProperty(*object, &lookup, *name, &attr); |
1155 } | 1219 } |
1156 | 1220 |
1157 // Do not use ICs for objects that require access checks (including | 1221 // Do not use ICs for objects that require access checks (including |
1158 // the global object). | 1222 // the global object). |
1159 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1223 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
1160 | 1224 |
1161 if (use_ic) { | 1225 if (use_ic) { |
1162 Code* stub = generic_stub(); | 1226 Code* stub = generic_stub(); |
1163 if (state == UNINITIALIZED) { | 1227 if (!force_generic_stub) { |
1164 if (object->IsString() && key->IsNumber()) { | 1228 if (object->IsString() && key->IsNumber()) { |
1165 stub = string_stub(); | 1229 if (state == UNINITIALIZED) { |
| 1230 stub = string_stub(); |
| 1231 } |
1166 } else if (object->IsJSObject()) { | 1232 } else if (object->IsJSObject()) { |
1167 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1233 JSObject* receiver = JSObject::cast(*object); |
1168 if (receiver->HasExternalArrayElements()) { | 1234 if (receiver->HasIndexedInterceptor()) { |
1169 MaybeObject* probe = | |
1170 isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray( | |
1171 *receiver, false, kNonStrictMode); | |
1172 stub = probe->IsFailure() ? | |
1173 NULL : Code::cast(probe->ToObjectUnchecked()); | |
1174 } else if (receiver->HasIndexedInterceptor()) { | |
1175 stub = indexed_interceptor_stub(); | 1235 stub = indexed_interceptor_stub(); |
1176 } else if (key->IsSmi() && | 1236 } else if (key->IsSmi()) { |
1177 receiver->map()->has_fast_elements()) { | 1237 MaybeObject* maybe_stub = ComputeStub(receiver, |
1178 MaybeObject* probe = | 1238 false, |
1179 isolate()->stub_cache()->ComputeKeyedLoadSpecialized(*receiver); | 1239 kNonStrictMode, |
1180 stub = probe->IsFailure() ? | 1240 stub); |
1181 NULL : Code::cast(probe->ToObjectUnchecked()); | 1241 stub = maybe_stub->IsFailure() ? |
| 1242 NULL : Code::cast(maybe_stub->ToObjectUnchecked()); |
1182 } | 1243 } |
1183 } | 1244 } |
1184 } | 1245 } |
1185 if (stub != NULL) set_target(stub); | 1246 if (stub != NULL) set_target(stub); |
| 1247 } |
1186 | 1248 |
1187 #ifdef DEBUG | 1249 #ifdef DEBUG |
1188 TraceIC("KeyedLoadIC", key, state, target()); | 1250 TraceIC("KeyedLoadIC", key, state, target()); |
1189 #endif // DEBUG | 1251 #endif // DEBUG |
1190 } | |
1191 | 1252 |
1192 // Get the property. | 1253 // Get the property. |
1193 return Runtime::GetObjectProperty(isolate(), object, key); | 1254 return Runtime::GetObjectProperty(isolate(), object, key); |
1194 } | 1255 } |
1195 | 1256 |
1196 | 1257 |
1197 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, | 1258 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, |
1198 Handle<Object> object, Handle<String> name) { | 1259 Handle<Object> object, Handle<String> name) { |
1199 // Bail out if we didn't find a result. | 1260 // Bail out if we didn't find a result. |
1200 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | 1261 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1477 receiver->map(), | 1538 receiver->map(), |
1478 Code::cast(code)); | 1539 Code::cast(code)); |
1479 } | 1540 } |
1480 | 1541 |
1481 #ifdef DEBUG | 1542 #ifdef DEBUG |
1482 TraceIC("StoreIC", name, state, target()); | 1543 TraceIC("StoreIC", name, state, target()); |
1483 #endif | 1544 #endif |
1484 } | 1545 } |
1485 | 1546 |
1486 | 1547 |
| 1548 static bool AddOneReceiverMapIfMissing(MapList* receiver_maps, |
| 1549 Map* new_receiver_map) { |
| 1550 for (int current = 0; current < receiver_maps->length(); ++current) { |
| 1551 if (receiver_maps->at(current) == new_receiver_map) { |
| 1552 return false; |
| 1553 } |
| 1554 } |
| 1555 receiver_maps->Add(new_receiver_map); |
| 1556 return true; |
| 1557 } |
| 1558 |
| 1559 |
| 1560 void KeyedIC::GetReceiverMapsForStub(Code* stub, MapList* result) { |
| 1561 ASSERT(stub->is_inline_cache_stub()); |
| 1562 if (stub == string_stub()) { |
| 1563 return result->Add(isolate()->heap()->string_map()); |
| 1564 } else if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) { |
| 1565 if (stub->ic_state() == MONOMORPHIC) { |
| 1566 result->Add(Map::cast(stub->FindFirstMap())); |
| 1567 } else { |
| 1568 ASSERT(stub->ic_state() == MEGAMORPHIC); |
| 1569 AssertNoAllocation no_allocation; |
| 1570 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); |
| 1571 for (RelocIterator it(stub, mask); !it.done(); it.next()) { |
| 1572 RelocInfo* info = it.rinfo(); |
| 1573 Object* object = info->target_object(); |
| 1574 ASSERT(object->IsMap()); |
| 1575 result->Add(Map::cast(object)); |
| 1576 } |
| 1577 } |
| 1578 } |
| 1579 } |
| 1580 |
| 1581 |
| 1582 MaybeObject* KeyedIC::ComputeStub(JSObject* receiver, |
| 1583 bool is_store, |
| 1584 StrictModeFlag strict_mode, |
| 1585 Code* generic_stub) { |
| 1586 State ic_state = target()->ic_state(); |
| 1587 Code* monomorphic_stub; |
| 1588 // Always compute the MONOMORPHIC stub, even if the MEGAMORPHIC stub ends up |
| 1589 // being used. This is necessary because the megamorphic stub needs to have |
| 1590 // access to more information than what is stored in the receiver map in some |
| 1591 // cases (external arrays need the array type from the MONOMORPHIC stub). |
| 1592 MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver, |
| 1593 is_store, |
| 1594 strict_mode, |
| 1595 generic_stub); |
| 1596 if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub; |
| 1597 |
| 1598 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { |
| 1599 return monomorphic_stub; |
| 1600 } |
| 1601 ASSERT(target() != generic_stub); |
| 1602 |
| 1603 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS |
| 1604 // via megamorphic stubs, since they don't have a map in their relocation info |
| 1605 // and so the stubs can't be harvested for the object needed for a map check. |
| 1606 if (target()->type() != NORMAL) { |
| 1607 return generic_stub; |
| 1608 } |
| 1609 |
| 1610 // Determine the list of receiver maps that this call site has seen, |
| 1611 // adding the map that was just encountered. |
| 1612 MapList target_receiver_maps; |
| 1613 GetReceiverMapsForStub(target(), &target_receiver_maps); |
| 1614 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map())) { |
| 1615 // If the miss wasn't due to an unseen map, a MEGAMORPHIC stub |
| 1616 // won't help, use the generic stub. |
| 1617 return generic_stub; |
| 1618 } |
| 1619 |
| 1620 // TODO(1385): Currently MEGAMORPHIC stubs are cached in the receiver map stub |
| 1621 // cache, but that can put receiver types together from unrelated call sites |
| 1622 // into the same stub--they always handle the union of all receiver maps seen |
| 1623 // at all call sites involving the receiver map. This is only an |
| 1624 // approximation: ideally, there would be a global cache that mapped sets of |
| 1625 // receiver maps to MEGAMORPHIC stubs. The complexity of the MEGAMORPHIC stub |
| 1626 // computation also leads to direct manipulation of the stub cache from the IC |
| 1627 // code, which the global cache solution would avoid. |
| 1628 Code::Kind kind = this->kind(); |
| 1629 Code::Flags flags = Code::ComputeFlags(kind, |
| 1630 NOT_IN_LOOP, |
| 1631 MEGAMORPHIC, |
| 1632 strict_mode); |
| 1633 String* megamorphic_name = GetStubNameForCache(MEGAMORPHIC); |
| 1634 Object* maybe_cached_stub = receiver->map()->FindInCodeCache(megamorphic_name, |
| 1635 flags); |
| 1636 |
| 1637 // Create a set of all receiver maps that have been seen at the IC call site |
| 1638 // and those seen by the MEGAMORPHIC cached stub, if that's the stub that's |
| 1639 // been selected. |
| 1640 MapList receiver_maps; |
| 1641 if (!maybe_cached_stub->IsUndefined()) { |
| 1642 GetReceiverMapsForStub(Code::cast(maybe_cached_stub), &receiver_maps); |
| 1643 } |
| 1644 bool added_map = false; |
| 1645 for (int i = 0; i < target_receiver_maps.length(); ++i) { |
| 1646 if (AddOneReceiverMapIfMissing(&receiver_maps, |
| 1647 target_receiver_maps.at(i))) { |
| 1648 added_map = true; |
| 1649 } |
| 1650 } |
| 1651 ASSERT(receiver_maps.length() > 0); |
| 1652 |
| 1653 // If the maximum number of receiver maps has been exceeded, use the Generic |
| 1654 // version of the IC. |
| 1655 if (receiver_maps.length() > KeyedIC::kMaxKeyedPolymorphism) { |
| 1656 return generic_stub; |
| 1657 } |
| 1658 |
| 1659 // If no maps have been seen at the call site that aren't in the cached |
| 1660 // stub, then use it. |
| 1661 if (!added_map) { |
| 1662 ASSERT(!maybe_cached_stub->IsUndefined()); |
| 1663 ASSERT(maybe_cached_stub->IsCode()); |
| 1664 return Code::cast(maybe_cached_stub); |
| 1665 } |
| 1666 |
| 1667 // Lookup all of the receiver maps in the cache, they should all already |
| 1668 // have MONOMORPHIC stubs. |
| 1669 CodeList handler_ics(KeyedIC::kMaxKeyedPolymorphism); |
| 1670 for (int current = 0; current < receiver_maps.length(); ++current) { |
| 1671 Map* receiver_map(receiver_maps.at(current)); |
| 1672 MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck( |
| 1673 receiver_map, |
| 1674 strict_mode, |
| 1675 generic_stub); |
| 1676 Code* cached_stub; |
| 1677 if (!maybe_cached_stub->To(&cached_stub)) { |
| 1678 return maybe_cached_stub; |
| 1679 } |
| 1680 handler_ics.Add(cached_stub); |
| 1681 } |
| 1682 |
| 1683 Code* stub; |
| 1684 // Build the MEGAMORPHIC stub. |
| 1685 maybe_stub = ConstructMegamorphicStub(&receiver_maps, |
| 1686 &handler_ics, |
| 1687 strict_mode); |
| 1688 if (!maybe_stub->To(&stub)) return maybe_stub; |
| 1689 |
| 1690 MaybeObject* maybe_update = receiver->UpdateMapCodeCache( |
| 1691 megamorphic_name, |
| 1692 stub); |
| 1693 if (maybe_update->IsFailure()) return maybe_update; |
| 1694 return stub; |
| 1695 } |
| 1696 |
| 1697 |
| 1698 MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck( |
| 1699 Map* receiver_map, |
| 1700 StrictModeFlag strict_mode, |
| 1701 Code* generic_stub) { |
| 1702 if ((receiver_map->instance_type() & kNotStringTag) == 0) { |
| 1703 ASSERT(string_stub() != NULL); |
| 1704 return string_stub(); |
| 1705 } else if (receiver_map->has_external_array_elements()) { |
| 1706 // Determine the array type from the default MONOMORPHIC already generated |
| 1707 // stub. There is no other way to determine the type of the external array |
| 1708 // directly from the receiver type. |
| 1709 Code::Kind kind = this->kind(); |
| 1710 Code::Flags flags = Code::ComputeMonomorphicFlags(kind, |
| 1711 NORMAL, |
| 1712 strict_mode); |
| 1713 String* monomorphic_name = GetStubNameForCache(MONOMORPHIC); |
| 1714 Object* maybe_default_stub = receiver_map->FindInCodeCache(monomorphic_name, |
| 1715 flags); |
| 1716 if (maybe_default_stub->IsUndefined()) { |
| 1717 return generic_stub; |
| 1718 } |
| 1719 Code* default_stub = Code::cast(maybe_default_stub); |
| 1720 return GetExternalArrayStubWithoutMapCheck( |
| 1721 default_stub->external_array_type()); |
| 1722 } else if (receiver_map->has_fast_elements()) { |
| 1723 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; |
| 1724 return GetFastElementStubWithoutMapCheck(is_js_array); |
| 1725 } else { |
| 1726 return generic_stub; |
| 1727 } |
| 1728 } |
| 1729 |
| 1730 |
| 1731 MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver, |
| 1732 bool is_store, |
| 1733 StrictModeFlag strict_mode, |
| 1734 Code* generic_stub) { |
| 1735 Code* result = NULL; |
| 1736 if (receiver->HasExternalArrayElements()) { |
| 1737 MaybeObject* maybe_stub = |
| 1738 isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray( |
| 1739 receiver, is_store, strict_mode); |
| 1740 if (!maybe_stub->To(&result)) return maybe_stub; |
| 1741 } else if (receiver->map()->has_fast_elements()) { |
| 1742 MaybeObject* maybe_stub = |
| 1743 isolate()->stub_cache()->ComputeKeyedLoadOrStoreFastElement( |
| 1744 receiver, is_store, strict_mode); |
| 1745 if (!maybe_stub->To(&result)) return maybe_stub; |
| 1746 } else { |
| 1747 result = generic_stub; |
| 1748 } |
| 1749 return result; |
| 1750 } |
| 1751 |
| 1752 |
| 1753 String* KeyedStoreIC::GetStubNameForCache(IC::State ic_state) { |
| 1754 if (ic_state == MONOMORPHIC) { |
| 1755 return isolate()->heap()->KeyedStoreSpecializedMonomorphic_symbol(); |
| 1756 } else { |
| 1757 ASSERT(ic_state == MEGAMORPHIC); |
| 1758 return isolate()->heap()->KeyedStoreSpecializedPolymorphic_symbol(); |
| 1759 } |
| 1760 } |
| 1761 |
| 1762 |
| 1763 MaybeObject* KeyedStoreIC::GetFastElementStubWithoutMapCheck( |
| 1764 bool is_js_array) { |
| 1765 return KeyedStoreFastElementStub(is_js_array).TryGetCode(); |
| 1766 } |
| 1767 |
| 1768 |
| 1769 MaybeObject* KeyedStoreIC::GetExternalArrayStubWithoutMapCheck( |
| 1770 ExternalArrayType array_type) { |
| 1771 return KeyedStoreExternalArrayStub(array_type).TryGetCode(); |
| 1772 } |
| 1773 |
| 1774 |
| 1775 MaybeObject* KeyedStoreIC::ConstructMegamorphicStub( |
| 1776 MapList* receiver_maps, |
| 1777 CodeList* targets, |
| 1778 StrictModeFlag strict_mode) { |
| 1779 Object* object; |
| 1780 KeyedStoreStubCompiler compiler(strict_mode); |
| 1781 MaybeObject* maybe_code = compiler.CompileStoreMegamorphic(receiver_maps, |
| 1782 targets); |
| 1783 if (!maybe_code->ToObject(&object)) return maybe_code; |
| 1784 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment(); |
| 1785 PROFILE(isolate(), CodeCreateEvent( |
| 1786 Logger::KEYED_STORE_MEGAMORPHIC_IC_TAG, |
| 1787 Code::cast(object), 0)); |
| 1788 return object; |
| 1789 } |
| 1790 |
| 1791 |
1487 MaybeObject* KeyedStoreIC::Store(State state, | 1792 MaybeObject* KeyedStoreIC::Store(State state, |
1488 StrictModeFlag strict_mode, | 1793 StrictModeFlag strict_mode, |
1489 Handle<Object> object, | 1794 Handle<Object> object, |
1490 Handle<Object> key, | 1795 Handle<Object> key, |
1491 Handle<Object> value) { | 1796 Handle<Object> value, |
| 1797 bool force_generic) { |
1492 if (key->IsSymbol()) { | 1798 if (key->IsSymbol()) { |
1493 Handle<String> name = Handle<String>::cast(key); | 1799 Handle<String> name = Handle<String>::cast(key); |
1494 | 1800 |
1495 // If the object is undefined or null it's illegal to try to set any | 1801 // If the object is undefined or null it's illegal to try to set any |
1496 // properties on it; throw a TypeError in that case. | 1802 // properties on it; throw a TypeError in that case. |
1497 if (object->IsUndefined() || object->IsNull()) { | 1803 if (object->IsUndefined() || object->IsNull()) { |
1498 return TypeError("non_object_property_store", object, name); | 1804 return TypeError("non_object_property_store", object, name); |
1499 } | 1805 } |
1500 | 1806 |
1501 // Ignore stores where the receiver is not a JSObject. | 1807 // Ignore stores where the receiver is not a JSObject. |
(...skipping 21 matching lines...) Expand all Loading... |
1523 // Set the property. | 1829 // Set the property. |
1524 return receiver->SetProperty(*name, *value, NONE, strict_mode); | 1830 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
1525 } | 1831 } |
1526 | 1832 |
1527 // Do not use ICs for objects that require access checks (including | 1833 // Do not use ICs for objects that require access checks (including |
1528 // the global object). | 1834 // the global object). |
1529 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1835 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
1530 ASSERT(!(use_ic && object->IsJSGlobalProxy())); | 1836 ASSERT(!(use_ic && object->IsJSGlobalProxy())); |
1531 | 1837 |
1532 if (use_ic) { | 1838 if (use_ic) { |
1533 Code* stub = | 1839 Code* stub = (strict_mode == kStrictMode) |
1534 (strict_mode == kStrictMode) ? generic_stub_strict() : generic_stub(); | 1840 ? generic_stub_strict() |
1535 if (state == UNINITIALIZED) { | 1841 : generic_stub(); |
1536 if (object->IsJSObject()) { | 1842 if (!force_generic) { |
1537 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1843 if (object->IsJSObject() && key->IsSmi()) { |
1538 if (receiver->HasExternalArrayElements()) { | 1844 JSObject* receiver = JSObject::cast(*object); |
1539 MaybeObject* probe = | 1845 MaybeObject* maybe_stub = ComputeStub(receiver, |
1540 isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray( | 1846 true, |
1541 *receiver, true, strict_mode); | 1847 strict_mode, |
1542 stub = probe->IsFailure() ? | 1848 stub); |
1543 NULL : Code::cast(probe->ToObjectUnchecked()); | 1849 stub = maybe_stub->IsFailure() ? |
1544 } else if (key->IsSmi() && receiver->map()->has_fast_elements()) { | 1850 NULL : Code::cast(maybe_stub->ToObjectUnchecked()); |
1545 MaybeObject* probe = | |
1546 isolate()->stub_cache()->ComputeKeyedStoreSpecialized( | |
1547 *receiver, strict_mode); | |
1548 stub = probe->IsFailure() ? | |
1549 NULL : Code::cast(probe->ToObjectUnchecked()); | |
1550 } | |
1551 } | 1851 } |
1552 } | 1852 } |
1553 if (stub != NULL) set_target(stub); | 1853 if (stub != NULL) set_target(stub); |
1554 } | 1854 } |
1555 | 1855 |
| 1856 #ifdef DEBUG |
| 1857 TraceIC("KeyedStoreIC", key, state, target()); |
| 1858 #endif |
| 1859 |
1556 // Set the property. | 1860 // Set the property. |
1557 return Runtime::SetObjectProperty( | 1861 return Runtime::SetObjectProperty( |
1558 isolate(), object , key, value, NONE, strict_mode); | 1862 isolate(), object , key, value, NONE, strict_mode); |
1559 } | 1863 } |
1560 | 1864 |
1561 | 1865 |
1562 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, | 1866 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, |
1563 State state, | 1867 State state, |
1564 StrictModeFlag strict_mode, | 1868 StrictModeFlag strict_mode, |
1565 Handle<JSObject> receiver, | 1869 Handle<JSObject> receiver, |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1714 return ic.Load(state, args.at<Object>(0), args.at<String>(1)); | 2018 return ic.Load(state, args.at<Object>(0), args.at<String>(1)); |
1715 } | 2019 } |
1716 | 2020 |
1717 | 2021 |
1718 // Used from ic-<arch>.cc | 2022 // Used from ic-<arch>.cc |
1719 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) { | 2023 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) { |
1720 NoHandleAllocation na; | 2024 NoHandleAllocation na; |
1721 ASSERT(args.length() == 2); | 2025 ASSERT(args.length() == 2); |
1722 KeyedLoadIC ic(isolate); | 2026 KeyedLoadIC ic(isolate); |
1723 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2027 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
1724 return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); | 2028 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), false); |
1725 } | 2029 } |
1726 | 2030 |
1727 | 2031 |
| 2032 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) { |
| 2033 NoHandleAllocation na; |
| 2034 ASSERT(args.length() == 2); |
| 2035 KeyedLoadIC ic(isolate); |
| 2036 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 2037 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), true); |
| 2038 } |
| 2039 |
| 2040 |
1728 // Used from ic-<arch>.cc. | 2041 // Used from ic-<arch>.cc. |
1729 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { | 2042 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { |
1730 NoHandleAllocation na; | 2043 NoHandleAllocation na; |
1731 ASSERT(args.length() == 3); | 2044 ASSERT(args.length() == 3); |
1732 StoreIC ic(isolate); | 2045 StoreIC ic(isolate); |
1733 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2046 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
1734 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 2047 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
1735 return ic.Store(state, | 2048 return ic.Store(state, |
1736 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), | 2049 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
1737 args.at<Object>(0), | 2050 args.at<Object>(0), |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1798 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { | 2111 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { |
1799 NoHandleAllocation na; | 2112 NoHandleAllocation na; |
1800 ASSERT(args.length() == 3); | 2113 ASSERT(args.length() == 3); |
1801 KeyedStoreIC ic(isolate); | 2114 KeyedStoreIC ic(isolate); |
1802 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2115 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
1803 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 2116 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
1804 return ic.Store(state, | 2117 return ic.Store(state, |
1805 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), | 2118 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
1806 args.at<Object>(0), | 2119 args.at<Object>(0), |
1807 args.at<Object>(1), | 2120 args.at<Object>(1), |
1808 args.at<Object>(2)); | 2121 args.at<Object>(2), |
| 2122 false); |
1809 } | 2123 } |
1810 | 2124 |
1811 | 2125 |
| 2126 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) { |
| 2127 NoHandleAllocation na; |
| 2128 ASSERT(args.length() == 3); |
| 2129 KeyedStoreIC ic(isolate); |
| 2130 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 2131 Handle<Object> object = args.at<Object>(0); |
| 2132 Handle<Object> key = args.at<Object>(1); |
| 2133 Handle<Object> value = args.at<Object>(2); |
| 2134 StrictModeFlag strict_mode = |
| 2135 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode); |
| 2136 return Runtime::SetObjectProperty(isolate, |
| 2137 object, |
| 2138 key, |
| 2139 value, |
| 2140 NONE, |
| 2141 strict_mode); |
| 2142 } |
| 2143 |
| 2144 |
| 2145 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) { |
| 2146 NoHandleAllocation na; |
| 2147 ASSERT(args.length() == 3); |
| 2148 KeyedStoreIC ic(isolate); |
| 2149 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 2150 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 2151 return ic.Store(state, |
| 2152 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
| 2153 args.at<Object>(0), |
| 2154 args.at<Object>(1), |
| 2155 args.at<Object>(2), |
| 2156 true); |
| 2157 } |
| 2158 |
| 2159 |
1812 void TRUnaryOpIC::patch(Code* code) { | 2160 void TRUnaryOpIC::patch(Code* code) { |
1813 set_target(code); | 2161 set_target(code); |
1814 } | 2162 } |
1815 | 2163 |
1816 | 2164 |
1817 const char* TRUnaryOpIC::GetName(TypeInfo type_info) { | 2165 const char* TRUnaryOpIC::GetName(TypeInfo type_info) { |
1818 switch (type_info) { | 2166 switch (type_info) { |
1819 case UNINITIALIZED: return "Uninitialized"; | 2167 case UNINITIALIZED: return "Uninitialized"; |
1820 case SMI: return "Smi"; | 2168 case SMI: return "Smi"; |
1821 case HEAP_NUMBER: return "HeapNumbers"; | 2169 case HEAP_NUMBER: return "HeapNumbers"; |
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2190 #undef ADDR | 2538 #undef ADDR |
2191 }; | 2539 }; |
2192 | 2540 |
2193 | 2541 |
2194 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2542 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2195 return IC_utilities[id]; | 2543 return IC_utilities[id]; |
2196 } | 2544 } |
2197 | 2545 |
2198 | 2546 |
2199 } } // namespace v8::internal | 2547 } } // namespace v8::internal |
OLD | NEW |