Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(115)

Side by Side Diff: src/ic.cc

Issue 11953025: Move polymorphic stub computation and compilation to stub cache (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Address comments Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ic.h ('k') | src/stub-cache.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/ic.h ('k') | src/stub-cache.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698