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