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 812 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
823 ReceiverToObjectIfRequired(result, object); | 823 ReceiverToObjectIfRequired(result, object); |
824 if (result->IsJSFunction()) return *result; | 824 if (result->IsJSFunction()) return *result; |
825 | 825 |
826 result = TryCallAsFunction(result); | 826 result = TryCallAsFunction(result); |
827 if (result->IsJSFunction()) return *result; | 827 if (result->IsJSFunction()) return *result; |
828 | 828 |
829 return TypeError("property_not_function", object, key); | 829 return TypeError("property_not_function", object, key); |
830 } | 830 } |
831 | 831 |
832 | 832 |
833 MaybeObject* IC::Load(State state, | 833 MaybeObject* LoadIC::Load(State state, |
834 Handle<Object> object, | 834 Handle<Object> object, |
835 Handle<String> name) { | 835 Handle<String> name) { |
836 // If the object is undefined or null it's illegal to try to get any | 836 // If the object is undefined or null it's illegal to try to get any |
837 // of its properties; throw a TypeError in that case. | 837 // of its properties; throw a TypeError in that case. |
838 if (object->IsUndefined() || object->IsNull()) { | 838 if (object->IsUndefined() || object->IsNull()) { |
839 return TypeError("non_object_property_load", object, name); | 839 return TypeError("non_object_property_load", object, name); |
840 } | 840 } |
841 | 841 |
842 if (FLAG_use_ic) { | 842 if (FLAG_use_ic) { |
843 // Use specialized code for getting the length of strings and | 843 // Use specialized code for getting the length of strings and |
844 // string wrapper objects. The length property of string wrapper | 844 // string wrapper objects. The length property of string wrapper |
845 // objects is read-only and therefore always returns the length of | 845 // objects is read-only and therefore always returns the length of |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1079 case POLYMORPHIC: | 1079 case POLYMORPHIC: |
1080 case GENERIC: | 1080 case GENERIC: |
1081 UNREACHABLE(); | 1081 UNREACHABLE(); |
1082 break; | 1082 break; |
1083 } | 1083 } |
1084 | 1084 |
1085 TRACE_IC("LoadIC", name, state, target()); | 1085 TRACE_IC("LoadIC", name, state, target()); |
1086 } | 1086 } |
1087 | 1087 |
1088 | 1088 |
1089 Handle<Code> KeyedLoadIC::GetElementStubWithoutMapCheck( | |
1090 bool is_js_array, | |
1091 ElementsKind elements_kind, | |
1092 KeyedAccessGrowMode grow_mode) { | |
1093 ASSERT(grow_mode == DO_NOT_ALLOW_JSARRAY_GROWTH); | |
1094 if (IsFastElementsKind(elements_kind) || | |
1095 IsExternalArrayElementsKind(elements_kind)) { | |
1096 return KeyedLoadFastElementStub(is_js_array, elements_kind).GetCode(); | |
1097 } else { | |
1098 ASSERT(elements_kind == DICTIONARY_ELEMENTS); | |
1099 return KeyedLoadDictionaryElementStub().GetCode(); | |
1100 } | |
1101 } | |
1102 | |
1103 | |
1104 Handle<Code> KeyedLoadIC::ComputePolymorphicStub( | |
1105 MapHandleList* receiver_maps, | |
1106 StrictModeFlag strict_mode, | |
1107 KeyedAccessGrowMode growth_mode) { | |
1108 CodeHandleList handler_ics(receiver_maps->length()); | |
1109 for (int i = 0; i < receiver_maps->length(); ++i) { | |
1110 Handle<Map> receiver_map = receiver_maps->at(i); | |
1111 Handle<Code> cached_stub = ComputeMonomorphicStubWithoutMapCheck( | |
1112 receiver_map, strict_mode, growth_mode); | |
1113 handler_ics.Add(cached_stub); | |
1114 } | |
1115 KeyedLoadStubCompiler compiler(isolate()); | |
1116 Handle<Code> code = compiler.CompileLoadPolymorphic( | |
1117 receiver_maps, &handler_ics); | |
1118 isolate()->counters()->keyed_load_polymorphic_stubs()->Increment(); | |
1119 PROFILE(isolate(), | |
1120 CodeCreateEvent(Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG, *code, 0)); | |
1121 return code; | |
1122 } | |
1123 | |
1124 | |
1125 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { | 1089 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { |
1126 // This helper implements a few common fast cases for converting | 1090 // This helper implements a few common fast cases for converting |
1127 // non-smi keys of keyed loads/stores to a smi or a string. | 1091 // non-smi keys of keyed loads/stores to a smi or a string. |
1128 if (key->IsHeapNumber()) { | 1092 if (key->IsHeapNumber()) { |
1129 double value = Handle<HeapNumber>::cast(key)->value(); | 1093 double value = Handle<HeapNumber>::cast(key)->value(); |
1130 if (isnan(value)) { | 1094 if (isnan(value)) { |
1131 key = isolate->factory()->nan_symbol(); | 1095 key = isolate->factory()->nan_symbol(); |
1132 } else { | 1096 } else { |
1133 int int_value = FastD2I(value); | 1097 int int_value = FastD2I(value); |
1134 if (value == int_value && Smi::IsValid(int_value)) { | 1098 if (value == int_value && Smi::IsValid(int_value)) { |
1135 key = Handle<Smi>(Smi::FromInt(int_value)); | 1099 key = Handle<Smi>(Smi::FromInt(int_value)); |
1136 } | 1100 } |
1137 } | 1101 } |
1138 } else if (key->IsUndefined()) { | 1102 } else if (key->IsUndefined()) { |
1139 key = isolate->factory()->undefined_symbol(); | 1103 key = isolate->factory()->undefined_symbol(); |
1140 } | 1104 } |
1141 return key; | 1105 return key; |
1142 } | 1106 } |
1143 | 1107 |
1144 | 1108 |
| 1109 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, |
| 1110 Handle<Map> new_receiver_map) { |
| 1111 ASSERT(!new_receiver_map.is_null()); |
| 1112 for (int current = 0; current < receiver_maps->length(); ++current) { |
| 1113 if (!receiver_maps->at(current).is_null() && |
| 1114 receiver_maps->at(current).is_identical_to(new_receiver_map)) { |
| 1115 return false; |
| 1116 } |
| 1117 } |
| 1118 receiver_maps->Add(new_receiver_map); |
| 1119 return true; |
| 1120 } |
| 1121 |
| 1122 |
| 1123 static void GetReceiverMapsForStub(Handle<Code> stub, |
| 1124 MapHandleList* result) { |
| 1125 ASSERT(stub->is_inline_cache_stub()); |
| 1126 if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) { |
| 1127 switch (stub->ic_state()) { |
| 1128 case MONOMORPHIC: |
| 1129 result->Add(Handle<Map>(stub->FindFirstMap())); |
| 1130 break; |
| 1131 case POLYMORPHIC: { |
| 1132 AssertNoAllocation no_allocation; |
| 1133 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); |
| 1134 for (RelocIterator it(*stub, mask); !it.done(); it.next()) { |
| 1135 RelocInfo* info = it.rinfo(); |
| 1136 Handle<Object> object(info->target_object()); |
| 1137 ASSERT(object->IsMap()); |
| 1138 AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object)); |
| 1139 } |
| 1140 break; |
| 1141 } |
| 1142 case MEGAMORPHIC: |
| 1143 case GENERIC: |
| 1144 break; |
| 1145 case UNINITIALIZED: |
| 1146 case PREMONOMORPHIC: |
| 1147 case MONOMORPHIC_PROTOTYPE_FAILURE: |
| 1148 case DEBUG_STUB: |
| 1149 UNREACHABLE(); |
| 1150 break; |
| 1151 } |
| 1152 } |
| 1153 } |
| 1154 |
| 1155 |
| 1156 Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) { |
| 1157 State ic_state = target()->ic_state(); |
| 1158 |
| 1159 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS |
| 1160 // via megamorphic stubs, since they don't have a map in their relocation info |
| 1161 // and so the stubs can't be harvested for the object needed for a map check. |
| 1162 if (target()->type() != Code::NORMAL) { |
| 1163 TRACE_GENERIC_IC("KeyedIC", "non-NORMAL target type"); |
| 1164 return generic_stub(); |
| 1165 } |
| 1166 |
| 1167 Handle<Map> receiver_map(receiver->map()); |
| 1168 MapHandleList target_receiver_maps; |
| 1169 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { |
| 1170 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state |
| 1171 // yet will do so and stay there. |
| 1172 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map); |
| 1173 } |
| 1174 |
| 1175 if (target() == *string_stub()) { |
| 1176 target_receiver_maps.Add(isolate()->factory()->string_map()); |
| 1177 } else { |
| 1178 GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps); |
| 1179 } |
| 1180 |
| 1181 // The first time a receiver is seen that is a transitioned version of the |
| 1182 // previous monomorphic receiver type, assume the new ElementsKind is the |
| 1183 // monomorphic type. This benefits global arrays that only transition |
| 1184 // once, and all call sites accessing them are faster if they remain |
| 1185 // monomorphic. If this optimistic assumption is not true, the IC will |
| 1186 // miss again and it will become polymorphic and support both the |
| 1187 // untransitioned and transitioned maps. |
| 1188 if (ic_state == MONOMORPHIC && |
| 1189 IsMoreGeneralElementsKindTransition( |
| 1190 target_receiver_maps.at(0)->elements_kind(), |
| 1191 receiver->GetElementsKind())) { |
| 1192 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map); |
| 1193 } |
| 1194 |
| 1195 ASSERT(target() != *generic_stub()); |
| 1196 |
| 1197 // Determine the list of receiver maps that this call site has seen, |
| 1198 // adding the map that was just encountered. |
| 1199 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) { |
| 1200 // If the miss wasn't due to an unseen map, a polymorphic stub |
| 1201 // won't help, use the generic stub. |
| 1202 TRACE_GENERIC_IC("KeyedIC", "same map added twice"); |
| 1203 return generic_stub(); |
| 1204 } |
| 1205 |
| 1206 // If the maximum number of receiver maps has been exceeded, use the generic |
| 1207 // version of the IC. |
| 1208 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { |
| 1209 TRACE_GENERIC_IC("KeyedIC", "max polymorph exceeded"); |
| 1210 return generic_stub(); |
| 1211 } |
| 1212 |
| 1213 return isolate()->stub_cache()->ComputeLoadElementPolymorphic( |
| 1214 &target_receiver_maps); |
| 1215 } |
| 1216 |
| 1217 |
1145 MaybeObject* KeyedLoadIC::Load(State state, | 1218 MaybeObject* KeyedLoadIC::Load(State state, |
1146 Handle<Object> object, | 1219 Handle<Object> object, |
1147 Handle<Object> key, | 1220 Handle<Object> key, |
1148 ICMissMode miss_mode) { | 1221 ICMissMode miss_mode) { |
1149 // Check for values that can be converted into a symbol directly or | 1222 // Check for values that can be converted into a symbol directly or |
1150 // is representable as a smi. | 1223 // is representable as a smi. |
1151 key = TryConvertKey(key, isolate()); | 1224 key = TryConvertKey(key, isolate()); |
1152 | 1225 |
1153 if (key->IsSymbol()) { | 1226 if (key->IsSymbol()) { |
1154 return IC::Load(state, object, Handle<String>::cast(key)); | 1227 return LoadIC::Load(state, object, Handle<String>::cast(key)); |
1155 } | 1228 } |
1156 | 1229 |
1157 // Do not use ICs for objects that require access checks (including | 1230 // Do not use ICs for objects that require access checks (including |
1158 // the global object). | 1231 // the global object). |
1159 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1232 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
1160 | 1233 |
1161 if (use_ic) { | 1234 if (use_ic) { |
1162 Handle<Code> stub = generic_stub(); | 1235 Handle<Code> stub = generic_stub(); |
1163 if (miss_mode != MISS_FORCE_GENERIC) { | 1236 if (miss_mode != MISS_FORCE_GENERIC) { |
1164 if (object->IsString() && key->IsNumber()) { | 1237 if (object->IsString() && key->IsNumber()) { |
1165 if (state == UNINITIALIZED) { | 1238 if (state == UNINITIALIZED) { |
1166 stub = string_stub(); | 1239 stub = string_stub(); |
1167 } | 1240 } |
1168 } else if (object->IsJSObject()) { | 1241 } else if (object->IsJSObject()) { |
1169 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1242 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
1170 if (receiver->elements()->map() == | 1243 if (receiver->elements()->map() == |
1171 isolate()->heap()->non_strict_arguments_elements_map()) { | 1244 isolate()->heap()->non_strict_arguments_elements_map()) { |
1172 stub = non_strict_arguments_stub(); | 1245 stub = non_strict_arguments_stub(); |
1173 } else if (receiver->HasIndexedInterceptor()) { | 1246 } else if (receiver->HasIndexedInterceptor()) { |
1174 stub = indexed_interceptor_stub(); | 1247 stub = indexed_interceptor_stub(); |
1175 } else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) { | 1248 } else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) { |
1176 stub = ComputeStub(receiver, KeyedIC::LOAD, kNonStrictMode, stub); | 1249 stub = LoadElementStub(receiver); |
1177 } | 1250 } |
1178 } | 1251 } |
1179 } else { | 1252 } else { |
1180 TRACE_GENERIC_IC("KeyedLoadIC", "force generic"); | 1253 TRACE_GENERIC_IC("KeyedLoadIC", "force generic"); |
1181 } | 1254 } |
1182 if (!stub.is_null()) set_target(*stub); | 1255 if (!stub.is_null()) set_target(*stub); |
1183 } | 1256 } |
1184 | 1257 |
1185 TRACE_IC("KeyedLoadIC", key, state, target()); | 1258 TRACE_IC("KeyedLoadIC", key, state, target()); |
1186 | 1259 |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1304 if (lookup->IsInterceptor() && | 1377 if (lookup->IsInterceptor() && |
1305 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { | 1378 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { |
1306 receiver->LocalLookupRealNamedProperty(*name, lookup); | 1379 receiver->LocalLookupRealNamedProperty(*name, lookup); |
1307 return StoreICableLookup(lookup); | 1380 return StoreICableLookup(lookup); |
1308 } | 1381 } |
1309 | 1382 |
1310 return true; | 1383 return true; |
1311 } | 1384 } |
1312 | 1385 |
1313 | 1386 |
1314 MaybeObject* IC::Store(State state, | 1387 MaybeObject* StoreIC::Store(State state, |
1315 StrictModeFlag strict_mode, | 1388 StrictModeFlag strict_mode, |
1316 Handle<Object> object, | 1389 Handle<Object> object, |
1317 Handle<String> name, | 1390 Handle<String> name, |
1318 Handle<Object> value, | 1391 Handle<Object> value, |
1319 JSReceiver::StoreFromKeyed store_mode) { | 1392 JSReceiver::StoreFromKeyed store_mode) { |
1320 // Handle proxies. | 1393 // Handle proxies. |
1321 if (object->IsJSProxy()) { | 1394 if (object->IsJSProxy()) { |
1322 return JSProxy::cast(*object)-> | 1395 return JSProxy::cast(*object)-> |
1323 SetProperty(*name, *value, NONE, strict_mode); | 1396 SetProperty(*name, *value, NONE, strict_mode); |
1324 } | 1397 } |
1325 | 1398 |
1326 // If the object is undefined or null it's illegal to try to set any | 1399 // If the object is undefined or null it's illegal to try to set any |
1327 // properties on it; throw a TypeError in that case. | 1400 // properties on it; throw a TypeError in that case. |
1328 if (object->IsUndefined() || object->IsNull()) { | 1401 if (object->IsUndefined() || object->IsNull()) { |
1329 return TypeError("non_object_property_store", object, name); | 1402 return TypeError("non_object_property_store", object, name); |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1530 case POLYMORPHIC: | 1603 case POLYMORPHIC: |
1531 case GENERIC: | 1604 case GENERIC: |
1532 UNREACHABLE(); | 1605 UNREACHABLE(); |
1533 break; | 1606 break; |
1534 } | 1607 } |
1535 | 1608 |
1536 TRACE_IC("StoreIC", name, state, target()); | 1609 TRACE_IC("StoreIC", name, state, target()); |
1537 } | 1610 } |
1538 | 1611 |
1539 | 1612 |
1540 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, | 1613 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, |
1541 Handle<Map> new_receiver_map) { | 1614 StubKind stub_kind, |
1542 ASSERT(!new_receiver_map.is_null()); | 1615 StrictModeFlag strict_mode) { |
1543 for (int current = 0; current < receiver_maps->length(); ++current) { | |
1544 if (!receiver_maps->at(current).is_null() && | |
1545 receiver_maps->at(current).is_identical_to(new_receiver_map)) { | |
1546 return false; | |
1547 } | |
1548 } | |
1549 receiver_maps->Add(new_receiver_map); | |
1550 return true; | |
1551 } | |
1552 | |
1553 | |
1554 void KeyedIC::GetReceiverMapsForStub(Handle<Code> stub, | |
1555 MapHandleList* result) { | |
1556 ASSERT(stub->is_inline_cache_stub()); | |
1557 if (!string_stub().is_null() && stub.is_identical_to(string_stub())) { | |
1558 return result->Add(isolate()->factory()->string_map()); | |
1559 } else if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) { | |
1560 switch (stub->ic_state()) { | |
1561 case MONOMORPHIC: | |
1562 result->Add(Handle<Map>(stub->FindFirstMap())); | |
1563 break; | |
1564 case POLYMORPHIC: { | |
1565 AssertNoAllocation no_allocation; | |
1566 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); | |
1567 for (RelocIterator it(*stub, mask); !it.done(); it.next()) { | |
1568 RelocInfo* info = it.rinfo(); | |
1569 Handle<Object> object(info->target_object()); | |
1570 ASSERT(object->IsMap()); | |
1571 AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object)); | |
1572 } | |
1573 break; | |
1574 } | |
1575 case MEGAMORPHIC: | |
1576 case GENERIC: | |
1577 break; | |
1578 case UNINITIALIZED: | |
1579 case PREMONOMORPHIC: | |
1580 case MONOMORPHIC_PROTOTYPE_FAILURE: | |
1581 case DEBUG_STUB: | |
1582 UNREACHABLE(); | |
1583 break; | |
1584 } | |
1585 } | |
1586 } | |
1587 | |
1588 | |
1589 Handle<Code> KeyedIC::ComputeStub(Handle<JSObject> receiver, | |
1590 StubKind stub_kind, | |
1591 StrictModeFlag strict_mode, | |
1592 Handle<Code> generic_stub) { | |
1593 State ic_state = target()->ic_state(); | 1616 State ic_state = target()->ic_state(); |
1594 KeyedAccessGrowMode grow_mode = IsGrowStubKind(stub_kind) | 1617 KeyedAccessGrowMode grow_mode = IsGrowStubKind(stub_kind) |
1595 ? ALLOW_JSARRAY_GROWTH | 1618 ? ALLOW_JSARRAY_GROWTH |
1596 : DO_NOT_ALLOW_JSARRAY_GROWTH; | 1619 : DO_NOT_ALLOW_JSARRAY_GROWTH; |
1597 | 1620 |
1598 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS | 1621 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS |
1599 // via megamorphic stubs, since they don't have a map in their relocation info | 1622 // via megamorphic stubs, since they don't have a map in their relocation info |
1600 // and so the stubs can't be harvested for the object needed for a map check. | 1623 // and so the stubs can't be harvested for the object needed for a map check. |
1601 if (target()->type() != Code::NORMAL) { | 1624 if (target()->type() != Code::NORMAL) { |
1602 TRACE_GENERIC_IC("KeyedIC", "non-NORMAL target type"); | 1625 TRACE_GENERIC_IC("KeyedIC", "non-NORMAL target type"); |
1603 return generic_stub; | 1626 return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub(); |
1604 } | 1627 } |
1605 | 1628 |
1606 bool monomorphic = false; | |
1607 bool is_transition_stub = IsTransitionStubKind(stub_kind); | |
1608 Handle<Map> receiver_map(receiver->map()); | 1629 Handle<Map> receiver_map(receiver->map()); |
1609 Handle<Map> monomorphic_map = receiver_map; | |
1610 MapHandleList target_receiver_maps; | 1630 MapHandleList target_receiver_maps; |
1611 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { | 1631 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { |
1612 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state | 1632 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state |
1613 // yet will do so and stay there. | 1633 // yet will do so and stay there. |
1614 monomorphic = true; | 1634 stub_kind = GetNoTransitionStubKind(stub_kind); |
1615 } else { | 1635 return isolate()->stub_cache()->ComputeKeyedStoreElement( |
1616 GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps); | 1636 receiver_map, stub_kind, strict_mode, grow_mode); |
1617 if (ic_state == MONOMORPHIC && (is_transition_stub || stub_kind == LOAD)) { | |
1618 // The first time a receiver is seen that is a transitioned version of the | |
1619 // previous monomorphic receiver type, assume the new ElementsKind is the | |
1620 // monomorphic type. This benefits global arrays that only transition | |
1621 // once, and all call sites accessing them are faster if they remain | |
1622 // monomorphic. If this optimistic assumption is not true, the IC will | |
1623 // miss again and it will become polymorphic and support both the | |
1624 // untransitioned and transitioned maps. | |
1625 monomorphic = IsMoreGeneralElementsKindTransition( | |
1626 target_receiver_maps.at(0)->elements_kind(), | |
1627 receiver->GetElementsKind()); | |
1628 } | |
1629 } | 1637 } |
1630 | 1638 |
1631 if (monomorphic) { | 1639 GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps); |
1632 if (is_transition_stub) { | 1640 // The first time a receiver is seen that is a transitioned version of the |
1633 monomorphic_map = ComputeTransitionedMap(receiver, stub_kind); | 1641 // previous monomorphic receiver type, assume the new ElementsKind is the |
1634 ASSERT(*monomorphic_map != *receiver_map); | 1642 // monomorphic type. This benefits global arrays that only transition |
1635 stub_kind = GetNoTransitionStubKind(stub_kind); | 1643 // once, and all call sites accessing them are faster if they remain |
1636 } | 1644 // monomorphic. If this optimistic assumption is not true, the IC will |
1637 return ComputeMonomorphicStub( | 1645 // miss again and it will become polymorphic and support both the |
1638 monomorphic_map, stub_kind, strict_mode, generic_stub); | 1646 // untransitioned and transitioned maps. |
| 1647 if (ic_state == MONOMORPHIC && |
| 1648 IsTransitionStubKind(stub_kind) && |
| 1649 IsMoreGeneralElementsKindTransition( |
| 1650 target_receiver_maps.at(0)->elements_kind(), |
| 1651 receiver->GetElementsKind())) { |
| 1652 Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver, stub_kind); |
| 1653 ASSERT(*monomorphic_map != *receiver_map); |
| 1654 stub_kind = GetNoTransitionStubKind(stub_kind); |
| 1655 return isolate()->stub_cache()->ComputeKeyedStoreElement( |
| 1656 monomorphic_map, stub_kind, strict_mode, grow_mode); |
1639 } | 1657 } |
1640 ASSERT(target() != *generic_stub); | |
1641 | 1658 |
1642 // Determine the list of receiver maps that this call site has seen, | 1659 ASSERT(target() != *generic_stub() && target() != *generic_stub_strict()); |
1643 // adding the map that was just encountered. | 1660 |
1644 bool map_added = | 1661 bool map_added = |
1645 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map); | 1662 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map); |
| 1663 |
1646 if (IsTransitionStubKind(stub_kind)) { | 1664 if (IsTransitionStubKind(stub_kind)) { |
1647 Handle<Map> new_map = ComputeTransitionedMap(receiver, stub_kind); | 1665 Handle<Map> new_map = ComputeTransitionedMap(receiver, stub_kind); |
1648 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, new_map); | 1666 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, new_map); |
1649 } | 1667 } |
| 1668 |
1650 if (!map_added) { | 1669 if (!map_added) { |
1651 // If the miss wasn't due to an unseen map, a polymorphic stub | 1670 // If the miss wasn't due to an unseen map, a polymorphic stub |
1652 // won't help, use the generic stub. | 1671 // won't help, use the generic stub. |
1653 TRACE_GENERIC_IC("KeyedIC", "same map added twice"); | 1672 TRACE_GENERIC_IC("KeyedIC", "same map added twice"); |
1654 return generic_stub; | 1673 return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub(); |
1655 } | 1674 } |
1656 | 1675 |
1657 // If the maximum number of receiver maps has been exceeded, use the generic | 1676 // If the maximum number of receiver maps has been exceeded, use the generic |
1658 // version of the IC. | 1677 // version of the IC. |
1659 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { | 1678 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { |
1660 TRACE_GENERIC_IC("KeyedIC", "max polymorph exceeded"); | 1679 TRACE_GENERIC_IC("KeyedIC", "max polymorph exceeded"); |
1661 return generic_stub; | 1680 return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub(); |
1662 } | 1681 } |
1663 | 1682 |
1664 if ((Code::GetKeyedAccessGrowMode(target()->extra_ic_state()) == | 1683 if ((Code::GetKeyedAccessGrowMode(target()->extra_ic_state()) == |
1665 ALLOW_JSARRAY_GROWTH)) { | 1684 ALLOW_JSARRAY_GROWTH)) { |
1666 grow_mode = ALLOW_JSARRAY_GROWTH; | 1685 grow_mode = ALLOW_JSARRAY_GROWTH; |
1667 } | 1686 } |
1668 | 1687 |
1669 Handle<PolymorphicCodeCache> cache = | 1688 return isolate()->stub_cache()->ComputeStoreElementPolymorphic( |
1670 isolate()->factory()->polymorphic_code_cache(); | 1689 &target_receiver_maps, grow_mode, strict_mode); |
1671 Code::ExtraICState extra_state = Code::ComputeExtraICState(grow_mode, | |
1672 strict_mode); | |
1673 Code::Flags flags = Code::ComputeFlags(kind(), POLYMORPHIC, extra_state); | |
1674 Handle<Object> probe = cache->Lookup(&target_receiver_maps, flags); | |
1675 if (probe->IsCode()) return Handle<Code>::cast(probe); | |
1676 | |
1677 Handle<Code> stub = | |
1678 ComputePolymorphicStub(&target_receiver_maps, strict_mode, grow_mode); | |
1679 PolymorphicCodeCache::Update(cache, &target_receiver_maps, flags, stub); | |
1680 return stub; | |
1681 } | 1690 } |
1682 | 1691 |
1683 | 1692 |
1684 Handle<Code> KeyedIC::ComputeMonomorphicStubWithoutMapCheck( | 1693 Handle<Map> KeyedStoreIC::ComputeTransitionedMap(Handle<JSObject> receiver, |
1685 Handle<Map> receiver_map, | 1694 StubKind stub_kind) { |
1686 StrictModeFlag strict_mode, | |
1687 KeyedAccessGrowMode grow_mode) { | |
1688 if ((receiver_map->instance_type() & kNotStringTag) == 0) { | |
1689 ASSERT(!string_stub().is_null()); | |
1690 return string_stub(); | |
1691 } else { | |
1692 ASSERT(receiver_map->has_dictionary_elements() || | |
1693 receiver_map->has_fast_smi_or_object_elements() || | |
1694 receiver_map->has_fast_double_elements() || | |
1695 receiver_map->has_external_array_elements()); | |
1696 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; | |
1697 return GetElementStubWithoutMapCheck(is_js_array, | |
1698 receiver_map->elements_kind(), | |
1699 grow_mode); | |
1700 } | |
1701 } | |
1702 | |
1703 | |
1704 Handle<Code> KeyedIC::ComputeMonomorphicStub(Handle<Map> receiver_map, | |
1705 StubKind stub_kind, | |
1706 StrictModeFlag strict_mode, | |
1707 Handle<Code> generic_stub) { | |
1708 ElementsKind elements_kind = receiver_map->elements_kind(); | |
1709 if (IsFastElementsKind(elements_kind) || | |
1710 IsExternalArrayElementsKind(elements_kind) || | |
1711 IsDictionaryElementsKind(elements_kind)) { | |
1712 return isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement( | |
1713 receiver_map, stub_kind, strict_mode); | |
1714 } else { | |
1715 return generic_stub; | |
1716 } | |
1717 } | |
1718 | |
1719 | |
1720 Handle<Map> KeyedIC::ComputeTransitionedMap(Handle<JSObject> receiver, | |
1721 StubKind stub_kind) { | |
1722 switch (stub_kind) { | 1695 switch (stub_kind) { |
1723 case KeyedIC::STORE_TRANSITION_SMI_TO_OBJECT: | 1696 case STORE_TRANSITION_SMI_TO_OBJECT: |
1724 case KeyedIC::STORE_TRANSITION_DOUBLE_TO_OBJECT: | 1697 case STORE_TRANSITION_DOUBLE_TO_OBJECT: |
1725 case KeyedIC::STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT: | 1698 case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT: |
1726 case KeyedIC::STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT: | 1699 case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT: |
1727 return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS); | 1700 return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS); |
1728 case KeyedIC::STORE_TRANSITION_SMI_TO_DOUBLE: | 1701 case STORE_TRANSITION_SMI_TO_DOUBLE: |
1729 case KeyedIC::STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE: | 1702 case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE: |
1730 return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS); | 1703 return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS); |
1731 case KeyedIC::STORE_TRANSITION_HOLEY_SMI_TO_OBJECT: | 1704 case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT: |
1732 case KeyedIC::STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT: | 1705 case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT: |
1733 case KeyedIC::STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT: | 1706 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT: |
1734 case KeyedIC::STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT: | 1707 case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT: |
1735 return JSObject::GetElementsTransitionMap(receiver, | 1708 return JSObject::GetElementsTransitionMap(receiver, |
1736 FAST_HOLEY_ELEMENTS); | 1709 FAST_HOLEY_ELEMENTS); |
1737 case KeyedIC::STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE: | 1710 case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE: |
1738 case KeyedIC::STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE: | 1711 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE: |
1739 return JSObject::GetElementsTransitionMap(receiver, | 1712 return JSObject::GetElementsTransitionMap(receiver, |
1740 FAST_HOLEY_DOUBLE_ELEMENTS); | 1713 FAST_HOLEY_DOUBLE_ELEMENTS); |
1741 case KeyedIC::LOAD: | 1714 case STORE_NO_TRANSITION: |
1742 case KeyedIC::STORE_NO_TRANSITION: | 1715 case STORE_AND_GROW_NO_TRANSITION: |
1743 case KeyedIC::STORE_AND_GROW_NO_TRANSITION: | |
1744 UNREACHABLE(); | 1716 UNREACHABLE(); |
1745 break; | 1717 break; |
1746 } | 1718 } |
1747 return Handle<Map>::null(); | 1719 return Handle<Map>::null(); |
1748 } | 1720 } |
1749 | 1721 |
1750 | 1722 |
1751 Handle<Code> KeyedStoreIC::GetElementStubWithoutMapCheck( | 1723 KeyedStoreIC::StubKind KeyedStoreIC::GetStubKind(Handle<JSObject> receiver, |
1752 bool is_js_array, | 1724 Handle<Object> key, |
1753 ElementsKind elements_kind, | 1725 Handle<Object> value) { |
1754 KeyedAccessGrowMode grow_mode) { | |
1755 return KeyedStoreElementStub(is_js_array, elements_kind, grow_mode).GetCode(); | |
1756 } | |
1757 | |
1758 | |
1759 Handle<Code> KeyedStoreIC::ComputePolymorphicStub( | |
1760 MapHandleList* receiver_maps, | |
1761 StrictModeFlag strict_mode, | |
1762 KeyedAccessGrowMode grow_mode) { | |
1763 // Collect MONOMORPHIC stubs for all target_receiver_maps. | |
1764 CodeHandleList handler_ics(receiver_maps->length()); | |
1765 MapHandleList transitioned_maps(receiver_maps->length()); | |
1766 for (int i = 0; i < receiver_maps->length(); ++i) { | |
1767 Handle<Map> receiver_map(receiver_maps->at(i)); | |
1768 Handle<Code> cached_stub; | |
1769 Handle<Map> transitioned_map = | |
1770 receiver_map->FindTransitionedMap(receiver_maps); | |
1771 | |
1772 // TODO(mvstanton): The code below is doing pessimistic elements | |
1773 // transitions. I would like to stop doing that and rely on Allocation Site | |
1774 // Tracking to do a better job of ensuring the data types are what they need | |
1775 // to be. Not all the elements are in place yet, pessimistic elements | |
1776 // transitions are still important for performance. | |
1777 if (!transitioned_map.is_null()) { | |
1778 cached_stub = ElementsTransitionAndStoreStub( | |
1779 receiver_map->elements_kind(), // original elements_kind | |
1780 transitioned_map->elements_kind(), | |
1781 receiver_map->instance_type() == JS_ARRAY_TYPE, // is_js_array | |
1782 strict_mode, grow_mode).GetCode(); | |
1783 } else { | |
1784 cached_stub = ComputeMonomorphicStubWithoutMapCheck(receiver_map, | |
1785 strict_mode, | |
1786 grow_mode); | |
1787 } | |
1788 ASSERT(!cached_stub.is_null()); | |
1789 handler_ics.Add(cached_stub); | |
1790 transitioned_maps.Add(transitioned_map); | |
1791 } | |
1792 KeyedStoreStubCompiler compiler(isolate(), strict_mode, grow_mode); | |
1793 Handle<Code> code = compiler.CompileStorePolymorphic( | |
1794 receiver_maps, &handler_ics, &transitioned_maps); | |
1795 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment(); | |
1796 PROFILE(isolate(), | |
1797 CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0)); | |
1798 return code; | |
1799 } | |
1800 | |
1801 | |
1802 KeyedIC::StubKind KeyedStoreIC::GetStubKind(Handle<JSObject> receiver, | |
1803 Handle<Object> key, | |
1804 Handle<Object> value) { | |
1805 ASSERT(key->IsSmi()); | 1726 ASSERT(key->IsSmi()); |
1806 int index = Smi::cast(*key)->value(); | 1727 int index = Smi::cast(*key)->value(); |
1807 bool allow_growth = receiver->IsJSArray() && | 1728 bool allow_growth = receiver->IsJSArray() && |
1808 JSArray::cast(*receiver)->length()->IsSmi() && | 1729 JSArray::cast(*receiver)->length()->IsSmi() && |
1809 index >= Smi::cast(JSArray::cast(*receiver)->length())->value(); | 1730 index >= Smi::cast(JSArray::cast(*receiver)->length())->value(); |
1810 | 1731 |
1811 if (allow_growth) { | 1732 if (allow_growth) { |
1812 // Handle growing array in stub if necessary. | 1733 // Handle growing array in stub if necessary. |
1813 if (receiver->HasFastSmiElements()) { | 1734 if (receiver->HasFastSmiElements()) { |
1814 if (value->IsHeapNumber()) { | 1735 if (value->IsHeapNumber()) { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1870 Handle<Object> object, | 1791 Handle<Object> object, |
1871 Handle<Object> key, | 1792 Handle<Object> key, |
1872 Handle<Object> value, | 1793 Handle<Object> value, |
1873 ICMissMode miss_mode) { | 1794 ICMissMode miss_mode) { |
1874 // Check for values that can be converted into a symbol directly or | 1795 // Check for values that can be converted into a symbol directly or |
1875 // is representable as a smi. | 1796 // is representable as a smi. |
1876 key = TryConvertKey(key, isolate()); | 1797 key = TryConvertKey(key, isolate()); |
1877 | 1798 |
1878 if (key->IsSymbol()) { | 1799 if (key->IsSymbol()) { |
1879 Handle<String> name = Handle<String>::cast(key); | 1800 Handle<String> name = Handle<String>::cast(key); |
1880 return IC::Store(state, | 1801 return StoreIC::Store(state, |
1881 strict_mode, | 1802 strict_mode, |
1882 object, | 1803 object, |
1883 name, | 1804 name, |
1884 value, | 1805 value, |
1885 JSReceiver::MAY_BE_STORE_FROM_KEYED); | 1806 JSReceiver::MAY_BE_STORE_FROM_KEYED); |
1886 } | 1807 } |
1887 | 1808 |
1888 // Do not use ICs for objects that require access checks (including | 1809 // Do not use ICs for objects that require access checks (including |
1889 // the global object), or are observed. | 1810 // the global object), or are observed. |
1890 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() && | 1811 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() && |
1891 !(FLAG_harmony_observation && object->IsJSObject() && | 1812 !(FLAG_harmony_observation && object->IsJSObject() && |
1892 JSObject::cast(*object)->map()->is_observed()); | 1813 JSObject::cast(*object)->map()->is_observed()); |
1893 ASSERT(!(use_ic && object->IsJSGlobalProxy())); | 1814 ASSERT(!(use_ic && object->IsJSGlobalProxy())); |
1894 | 1815 |
1895 if (use_ic) { | 1816 if (use_ic) { |
1896 Handle<Code> stub = (strict_mode == kStrictMode) | 1817 Handle<Code> stub = (strict_mode == kStrictMode) |
1897 ? generic_stub_strict() | 1818 ? generic_stub_strict() |
1898 : generic_stub(); | 1819 : generic_stub(); |
1899 if (object->IsJSObject()) { | 1820 if (object->IsJSObject()) { |
1900 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1821 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
1901 if (receiver->elements()->map() == | 1822 if (receiver->elements()->map() == |
1902 isolate()->heap()->non_strict_arguments_elements_map()) { | 1823 isolate()->heap()->non_strict_arguments_elements_map()) { |
1903 stub = non_strict_arguments_stub(); | 1824 stub = non_strict_arguments_stub(); |
1904 } else if (miss_mode != MISS_FORCE_GENERIC) { | 1825 } else if (miss_mode != MISS_FORCE_GENERIC) { |
1905 if (key->IsSmi() && (target() != *non_strict_arguments_stub())) { | 1826 if (key->IsSmi() && (target() != *non_strict_arguments_stub())) { |
1906 StubKind stub_kind = GetStubKind(receiver, key, value); | 1827 StubKind stub_kind = GetStubKind(receiver, key, value); |
1907 stub = ComputeStub(receiver, stub_kind, strict_mode, stub); | 1828 stub = StoreElementStub(receiver, stub_kind, strict_mode); |
1908 } | 1829 } |
1909 } else { | 1830 } else { |
1910 TRACE_GENERIC_IC("KeyedStoreIC", "force generic"); | 1831 TRACE_GENERIC_IC("KeyedStoreIC", "force generic"); |
1911 } | 1832 } |
1912 } | 1833 } |
1913 if (!stub.is_null()) set_target(*stub); | 1834 if (!stub.is_null()) set_target(*stub); |
1914 } | 1835 } |
1915 | 1836 |
1916 TRACE_IC("KeyedStoreIC", key, state, target()); | 1837 TRACE_IC("KeyedStoreIC", key, state, target()); |
1917 | 1838 |
(...skipping 834 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2752 #undef ADDR | 2673 #undef ADDR |
2753 }; | 2674 }; |
2754 | 2675 |
2755 | 2676 |
2756 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2677 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2757 return IC_utilities[id]; | 2678 return IC_utilities[id]; |
2758 } | 2679 } |
2759 | 2680 |
2760 | 2681 |
2761 } } // namespace v8::internal | 2682 } } // namespace v8::internal |
OLD | NEW |