Chromium Code Reviews| 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::ComputeMonomorphicBuiltinFastElementStub( | |
| 1069 bool is_js_array) { | |
| 1070 if (is_js_array) { | |
|
Mads Ager (chromium)
2011/05/10 13:38:06
If you simplify the stub hierarchy this can be jus
danno
2011/05/11 14:20:19
Done.
| |
| 1071 JSArrayKeyedLoadStub stub; | |
| 1072 return stub.TryGetCode(); | |
| 1073 } else { | |
| 1074 ObjectKeyedLoadStub stub; | |
| 1075 return stub.TryGetCode(); | |
| 1076 } | |
| 1077 } | |
| 1078 | |
| 1079 | |
| 1080 MaybeObject* KeyedLoadIC::ComputeMonomorphicBuiltinExternalArrayStub( | |
| 1081 ExternalArrayType array_type) { | |
| 1082 switch (array_type) { | |
|
Mads Ager (chromium)
2011/05/10 13:38:06
ExternalArrayLoadStub stub(array_type);
return stu
danno
2011/05/11 14:20:19
Done.
| |
| 1083 case kExternalByteArray: { | |
| 1084 ExternalByteArrayLoadStub stub; | |
| 1085 return stub.TryGetCode(); | |
| 1086 break; | |
| 1087 } | |
| 1088 case kExternalUnsignedByteArray: { | |
| 1089 ExternalUnsignedByteArrayLoadStub stub; | |
| 1090 return stub.TryGetCode(); | |
| 1091 break; | |
| 1092 } | |
| 1093 case kExternalShortArray: { | |
| 1094 ExternalShortArrayLoadStub stub; | |
| 1095 return stub.TryGetCode(); | |
| 1096 break; | |
| 1097 } | |
| 1098 case kExternalUnsignedShortArray: { | |
| 1099 ExternalUnsignedShortArrayLoadStub stub; | |
| 1100 return stub.TryGetCode(); | |
| 1101 break; | |
| 1102 } | |
| 1103 case kExternalIntArray: { | |
| 1104 ExternalIntArrayLoadStub stub; | |
| 1105 return stub.TryGetCode(); | |
| 1106 break; | |
| 1107 } | |
| 1108 case kExternalUnsignedIntArray: { | |
| 1109 ExternalUnsignedIntArrayLoadStub stub; | |
| 1110 return stub.TryGetCode(); | |
| 1111 break; | |
| 1112 } | |
| 1113 case kExternalDoubleArray: { | |
| 1114 ExternalDoubleArrayLoadStub stub; | |
| 1115 return stub.TryGetCode(); | |
| 1116 break; | |
| 1117 } | |
| 1118 case kExternalFloatArray: { | |
| 1119 ExternalFloatArrayLoadStub stub; | |
| 1120 return stub.TryGetCode(); | |
| 1121 break; | |
| 1122 } | |
| 1123 case kExternalPixelArray: { | |
| 1124 ExternalPixelArrayLoadStub stub; | |
| 1125 return stub.TryGetCode(); | |
| 1126 break; | |
| 1127 } | |
| 1128 } | |
| 1129 UNREACHABLE(); | |
| 1130 return NULL; | |
| 1131 } | |
| 1132 | |
| 1133 | |
| 1134 MaybeObject* KeyedLoadIC::ConstructMonomorphicFastElementStub( | |
| 1135 Map* receiver_map, | |
| 1136 StrictModeFlag strict_mode) { | |
| 1137 Object* object; | |
| 1138 KeyedLoadStubCompiler compiler; | |
| 1139 MaybeObject* maybe_code = compiler.CompileLoadFastElement(receiver_map); | |
| 1140 if (!maybe_code->ToObject(&object)) return maybe_code; | |
| 1141 PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, | |
| 1142 Code::cast(object), 0)); | |
| 1143 return object; | |
| 1144 } | |
| 1145 | |
| 1146 | |
| 1147 MaybeObject* KeyedLoadIC::ConstructMegamorphicStub( | |
| 1148 MapList* receiver_maps, | |
| 1149 CodeList* targets, | |
| 1150 StrictModeFlag strict_mode) { | |
| 1151 Object* object; | |
| 1152 KeyedLoadStubCompiler compiler; | |
| 1153 MaybeObject* maybe_code = compiler.CompileLoadMegamorphic(receiver_maps, | |
| 1154 targets); | |
| 1155 if (!maybe_code->ToObject(&object)) return maybe_code; | |
| 1156 isolate()->counters()->keyed_load_polymorphic_stubs()->Increment(); | |
| 1157 PROFILE(isolate(), CodeCreateEvent( | |
| 1158 Logger::KEYED_LOAD_MEGAMORPHIC_IC_TAG, | |
| 1159 Code::cast(object), 0)); | |
| 1160 return object; | |
| 1161 } | |
| 1162 | |
| 1163 | |
| 1034 MaybeObject* KeyedLoadIC::Load(State state, | 1164 MaybeObject* KeyedLoadIC::Load(State state, |
| 1035 Handle<Object> object, | 1165 Handle<Object> object, |
| 1036 Handle<Object> key) { | 1166 Handle<Object> key, |
| 1167 bool force_generic_stub) { | |
| 1037 // Check for values that can be converted into a symbol. | 1168 // Check for values that can be converted into a symbol. |
| 1038 // TODO(1295): Remove this code. | 1169 // TODO(1295): Remove this code. |
| 1039 HandleScope scope(isolate()); | 1170 HandleScope scope(isolate()); |
| 1040 if (key->IsHeapNumber() && | 1171 if (key->IsHeapNumber() && |
| 1041 isnan(HeapNumber::cast(*key)->value())) { | 1172 isnan(HeapNumber::cast(*key)->value())) { |
| 1042 key = isolate()->factory()->nan_symbol(); | 1173 key = isolate()->factory()->nan_symbol(); |
| 1043 } else if (key->IsUndefined()) { | 1174 } else if (key->IsUndefined()) { |
| 1044 key = isolate()->factory()->undefined_symbol(); | 1175 key = isolate()->factory()->undefined_symbol(); |
| 1045 } | 1176 } |
| 1046 | 1177 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1152 | 1283 |
| 1153 return object->GetProperty(*object, &lookup, *name, &attr); | 1284 return object->GetProperty(*object, &lookup, *name, &attr); |
| 1154 } | 1285 } |
| 1155 | 1286 |
| 1156 // Do not use ICs for objects that require access checks (including | 1287 // Do not use ICs for objects that require access checks (including |
| 1157 // the global object). | 1288 // the global object). |
| 1158 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1289 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
| 1159 | 1290 |
| 1160 if (use_ic) { | 1291 if (use_ic) { |
| 1161 Code* stub = generic_stub(); | 1292 Code* stub = generic_stub(); |
| 1162 if (state == UNINITIALIZED) { | 1293 if (!force_generic_stub) { |
| 1163 if (object->IsString() && key->IsNumber()) { | 1294 if (object->IsString() && key->IsNumber()) { |
| 1164 stub = string_stub(); | 1295 if (state == UNINITIALIZED) { |
| 1296 stub = string_stub(); | |
| 1297 } | |
| 1165 } else if (object->IsJSObject()) { | 1298 } else if (object->IsJSObject()) { |
| 1166 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1299 JSObject* receiver = JSObject::cast(*object); |
| 1167 if (receiver->HasExternalArrayElements()) { | 1300 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(); | 1301 stub = indexed_interceptor_stub(); |
| 1175 } else if (key->IsSmi() && | 1302 } else if (key->IsSmi()) { |
| 1176 receiver->map()->has_fast_elements()) { | 1303 MaybeObject* maybe_stub = ComputeStub(receiver, |
| 1177 MaybeObject* probe = | 1304 false, |
| 1178 isolate()->stub_cache()->ComputeKeyedLoadSpecialized(*receiver); | 1305 kNonStrictMode, |
| 1179 stub = probe->IsFailure() ? | 1306 stub); |
| 1180 NULL : Code::cast(probe->ToObjectUnchecked()); | 1307 stub = maybe_stub->IsFailure() ? |
| 1308 NULL : Code::cast(maybe_stub->ToObjectUnchecked()); | |
| 1181 } | 1309 } |
| 1182 } | 1310 } |
| 1183 } | 1311 } |
| 1184 if (stub != NULL) set_target(stub); | 1312 if (stub != NULL) set_target(stub); |
| 1313 } | |
| 1185 | 1314 |
| 1186 #ifdef DEBUG | 1315 #ifdef DEBUG |
| 1187 TraceIC("KeyedLoadIC", key, state, target()); | 1316 TraceIC("KeyedLoadIC", key, state, target()); |
| 1188 #endif // DEBUG | 1317 #endif // DEBUG |
| 1189 } | |
| 1190 | 1318 |
| 1191 // Get the property. | 1319 // Get the property. |
| 1192 return Runtime::GetObjectProperty(isolate(), object, key); | 1320 return Runtime::GetObjectProperty(isolate(), object, key); |
| 1193 } | 1321 } |
| 1194 | 1322 |
| 1195 | 1323 |
| 1196 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, | 1324 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, |
| 1197 Handle<Object> object, Handle<String> name) { | 1325 Handle<Object> object, Handle<String> name) { |
| 1198 // Bail out if we didn't find a result. | 1326 // Bail out if we didn't find a result. |
| 1199 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | 1327 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1476 receiver->map(), | 1604 receiver->map(), |
| 1477 Code::cast(code)); | 1605 Code::cast(code)); |
| 1478 } | 1606 } |
| 1479 | 1607 |
| 1480 #ifdef DEBUG | 1608 #ifdef DEBUG |
| 1481 TraceIC("StoreIC", name, state, target()); | 1609 TraceIC("StoreIC", name, state, target()); |
| 1482 #endif | 1610 #endif |
| 1483 } | 1611 } |
| 1484 | 1612 |
| 1485 | 1613 |
| 1614 static bool AddOneReceiverMapIfMissing(MapList* receiver_maps, | |
| 1615 Map* new_receiver_map) { | |
| 1616 for (int current = 0; current < receiver_maps->length(); ++current) { | |
| 1617 if (receiver_maps->at(current) == new_receiver_map) { | |
| 1618 return false; | |
| 1619 } | |
| 1620 } | |
| 1621 receiver_maps->Add(new_receiver_map); | |
| 1622 return true; | |
| 1623 } | |
| 1624 | |
| 1625 | |
| 1626 void KeyedIC::GetReceiverMapsForStub(Code* stub, MapList* result) { | |
| 1627 ASSERT(stub->is_inline_cache_stub()); | |
| 1628 if (stub == string_stub()) { | |
| 1629 return result->Add(isolate()->heap()->string_map()); | |
| 1630 } else if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) { | |
| 1631 if (stub->ic_state() == MONOMORPHIC) { | |
| 1632 result->Add(Map::cast(stub->FindFirstMap())); | |
| 1633 } else { | |
| 1634 ASSERT(stub->ic_state() == MEGAMORPHIC); | |
| 1635 AssertNoAllocation no_allocation; | |
| 1636 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); | |
| 1637 for (RelocIterator it(stub, mask); !it.done(); it.next()) { | |
| 1638 RelocInfo* info = it.rinfo(); | |
| 1639 Object* object = info->target_object(); | |
| 1640 ASSERT(object->IsMap()); | |
| 1641 result->Add(Map::cast(object)); | |
| 1642 } | |
| 1643 } | |
| 1644 } | |
| 1645 } | |
| 1646 | |
| 1647 | |
| 1648 MaybeObject* KeyedIC::ComputeStub(JSObject* receiver, | |
| 1649 bool is_store, | |
| 1650 StrictModeFlag strict_mode, | |
| 1651 Code* generic_stub) { | |
| 1652 State ic_state = target()->ic_state(); | |
| 1653 Code* monomorphic_stub; | |
| 1654 // Always compute the MONOMORPHIC stub, even if the MEGAMORPHIC stub ends up | |
| 1655 // being used. This is necessary because the megamorphic stub needs to have | |
| 1656 // the MONOMORPHIC stubs to jump into for all of the receiver types that it | |
|
Mads Ager (chromium)
2011/05/10 13:38:06
Is this comment correct any more? You might need t
danno
2011/05/11 14:20:19
Done.
| |
| 1657 // handles. | |
| 1658 MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver, | |
| 1659 is_store, | |
| 1660 strict_mode, | |
| 1661 generic_stub); | |
| 1662 if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub; | |
| 1663 | |
| 1664 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { | |
| 1665 return monomorphic_stub; | |
| 1666 } | |
| 1667 ASSERT(target() != generic_stub); | |
| 1668 | |
| 1669 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS | |
| 1670 // via megamorphic stubs, since they don't have a map in their relocation info | |
| 1671 // and so the stubs can't be harvested for the object needed for a map check. | |
| 1672 if (target()->type() != NORMAL) { | |
| 1673 return generic_stub; | |
| 1674 } | |
| 1675 | |
| 1676 // Determine the list of receiver maps that this call site has seen, | |
| 1677 // adding the map that was just encountered. | |
| 1678 MapList target_receiver_maps; | |
| 1679 GetReceiverMapsForStub(target(), &target_receiver_maps); | |
| 1680 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map())) { | |
| 1681 // If the miss wasn't due to an unseen map, a MEGAMORPHIC stub | |
| 1682 // won't help, use the generic stub. | |
| 1683 return generic_stub; | |
| 1684 } | |
| 1685 | |
| 1686 Code::Kind kind = this->kind(); | |
| 1687 Code::Flags flags = Code::ComputeFlags(kind, | |
| 1688 NOT_IN_LOOP, | |
| 1689 MEGAMORPHIC, | |
| 1690 strict_mode); | |
| 1691 String* megamorphic_name = GetStubNameForCache(MEGAMORPHIC); | |
| 1692 Object* maybe_cached_stub = receiver->map()->FindInCodeCache(megamorphic_name, | |
|
Mads Ager (chromium)
2011/05/10 13:38:06
I'm not sure I understand why you cache this stub
danno
2011/05/11 14:20:19
Yes, we should have a global cache instead of cach
| |
| 1693 flags); | |
| 1694 | |
| 1695 // Create a set of all receiver maps that have been seen at the IC call site | |
| 1696 // and those seen by the MEGAMORPHIC cached stub, if that's the stub that's | |
| 1697 // been selected. | |
| 1698 MapList receiver_maps; | |
| 1699 if (!maybe_cached_stub->IsUndefined()) { | |
| 1700 GetReceiverMapsForStub(Code::cast(maybe_cached_stub), &receiver_maps); | |
| 1701 } | |
| 1702 bool added_map = false; | |
| 1703 for (int i = 0; i < target_receiver_maps.length(); ++i) { | |
| 1704 if (AddOneReceiverMapIfMissing(&receiver_maps, | |
| 1705 target_receiver_maps.at(i))) { | |
| 1706 added_map = true; | |
| 1707 } | |
| 1708 } | |
| 1709 ASSERT(receiver_maps.length() > 0); | |
| 1710 | |
| 1711 // If the maximum number of receiver maps has been exceeded, use the Generic | |
| 1712 // version of the IC. | |
| 1713 if (receiver_maps.length() > KeyedIC::kMaxKeyedPolymorphism) { | |
| 1714 return generic_stub; | |
| 1715 } | |
| 1716 | |
| 1717 // If no maps have been seen at the call site that aren't in the cached | |
| 1718 // stub, then use it. | |
| 1719 if (!added_map) { | |
| 1720 ASSERT(!maybe_cached_stub->IsUndefined()); | |
| 1721 ASSERT(maybe_cached_stub->IsCode()); | |
| 1722 return Code::cast(maybe_cached_stub); | |
| 1723 } | |
| 1724 | |
| 1725 // Lookup all of the receiver maps in the cache, they should all already | |
| 1726 // have MONOMORPHIC stubs. | |
| 1727 CodeList handler_ics(KeyedIC::kMaxKeyedPolymorphism); | |
| 1728 for (int current = 0; current < receiver_maps.length(); ++current) { | |
| 1729 Map* receiver_map(receiver_maps.at(current)); | |
| 1730 MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck( | |
| 1731 receiver_map, | |
| 1732 strict_mode, | |
| 1733 generic_stub); | |
| 1734 Code* cached_stub; | |
| 1735 if (!maybe_cached_stub->To(&cached_stub)) { | |
| 1736 return maybe_cached_stub; | |
| 1737 } | |
| 1738 handler_ics.Add(cached_stub); | |
| 1739 } | |
| 1740 | |
| 1741 Code* stub; | |
| 1742 // Build the MEGAMORPHIC stub. | |
| 1743 maybe_stub = ConstructMegamorphicStub(&receiver_maps, | |
| 1744 &handler_ics, | |
| 1745 strict_mode); | |
| 1746 if (!maybe_stub->To(&stub)) return maybe_stub; | |
| 1747 | |
| 1748 MaybeObject* maybe_update = receiver->UpdateMapCodeCache( | |
| 1749 megamorphic_name, | |
| 1750 stub); | |
| 1751 if (maybe_update->IsFailure()) return maybe_update; | |
| 1752 return stub; | |
| 1753 } | |
| 1754 | |
| 1755 | |
| 1756 MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck( | |
| 1757 Map* receiver_map, | |
| 1758 StrictModeFlag strict_mode, | |
| 1759 Code* generic_stub) { | |
| 1760 if ((receiver_map->instance_type() & kNotStringTag) == 0) { | |
| 1761 ASSERT(string_stub() != NULL); | |
| 1762 return string_stub(); | |
| 1763 } else if (receiver_map->has_external_array_elements()) { | |
| 1764 // Determine the array type from the default MONOMORPHIC already generated | |
| 1765 // stub. There is no other way to determine the type of the external array | |
| 1766 // directly from the receiver type. | |
| 1767 Code::Kind kind = this->kind(); | |
| 1768 Code::Flags flags = Code::ComputeMonomorphicFlags(kind, | |
| 1769 NORMAL, | |
| 1770 strict_mode); | |
| 1771 String* monomorphic_name = GetStubNameForCache(MONOMORPHIC); | |
| 1772 Object* maybe_default_stub = receiver_map->FindInCodeCache(monomorphic_name, | |
| 1773 flags); | |
| 1774 if (maybe_default_stub->IsUndefined()) { | |
| 1775 return generic_stub; | |
| 1776 } | |
| 1777 Code* default_stub = Code::cast(maybe_default_stub); | |
| 1778 return ComputeMonomorphicBuiltinExternalArrayStub( | |
| 1779 default_stub->external_array_type()); | |
| 1780 } else if (receiver_map->has_fast_elements()) { | |
| 1781 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; | |
| 1782 return ComputeMonomorphicBuiltinFastElementStub(is_js_array); | |
| 1783 } else { | |
| 1784 return generic_stub; | |
| 1785 } | |
| 1786 } | |
| 1787 | |
| 1788 | |
| 1789 MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver, | |
| 1790 bool is_store, | |
| 1791 StrictModeFlag strict_mode, | |
| 1792 Code* generic_stub) { | |
| 1793 Code* result = NULL; | |
| 1794 if (receiver->HasExternalArrayElements()) { | |
| 1795 MaybeObject* maybe_stub = | |
| 1796 isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray( | |
| 1797 receiver, is_store, strict_mode); | |
| 1798 if (!maybe_stub->To(&result)) return maybe_stub; | |
| 1799 } else if (receiver->map()->has_fast_elements()) { | |
| 1800 Code::Kind kind = this->kind(); | |
| 1801 Code::Flags flags = Code::ComputeMonomorphicFlags(kind, | |
| 1802 NORMAL, | |
| 1803 strict_mode); | |
| 1804 String* name = GetStubNameForCache(MONOMORPHIC); | |
| 1805 Object* maybe_cached_stub = receiver->map()->FindInCodeCache(name, flags); | |
| 1806 if (maybe_cached_stub->IsUndefined()) { | |
| 1807 MaybeObject* maybe_stub = ConstructMonomorphicFastElementStub( | |
| 1808 receiver->map(), | |
| 1809 strict_mode); | |
| 1810 if (maybe_stub->To(&result)) return maybe_stub; | |
| 1811 MaybeObject* maybe_update = receiver->UpdateMapCodeCache(name, result); | |
|
Mads Ager (chromium)
2011/05/10 13:38:06
It seems to me that something like this should be
danno
2011/05/11 14:20:19
Done for the Monomorphic stubs. The megamorphic st
| |
| 1812 if (maybe_update->IsFailure()) return maybe_update; | |
| 1813 } else { | |
| 1814 result = Code::cast(maybe_cached_stub); | |
| 1815 } | |
| 1816 } else { | |
| 1817 result = generic_stub; | |
| 1818 } | |
| 1819 return result; | |
| 1820 } | |
| 1821 | |
| 1822 | |
| 1823 String* KeyedStoreIC::GetStubNameForCache(IC::State ic_state) { | |
| 1824 if (ic_state == MONOMORPHIC) { | |
| 1825 return isolate()->heap()->KeyedStoreSpecializedMonomorphic_symbol(); | |
| 1826 } else { | |
| 1827 ASSERT(ic_state == MEGAMORPHIC); | |
| 1828 return isolate()->heap()->KeyedStoreSpecializedPolymorphic_symbol(); | |
| 1829 } | |
| 1830 } | |
| 1831 | |
| 1832 | |
| 1833 MaybeObject* KeyedStoreIC::ComputeMonomorphicBuiltinFastElementStub( | |
| 1834 bool is_js_array) { | |
| 1835 if (is_js_array) { | |
| 1836 JSArrayKeyedStoreStub stub; | |
| 1837 return stub.TryGetCode(); | |
| 1838 } else { | |
| 1839 ObjectKeyedStoreStub stub; | |
| 1840 return stub.TryGetCode(); | |
| 1841 } | |
| 1842 } | |
| 1843 | |
| 1844 | |
| 1845 MaybeObject* KeyedStoreIC::ComputeMonomorphicBuiltinExternalArrayStub( | |
| 1846 ExternalArrayType array_type) { | |
| 1847 switch (array_type) { | |
| 1848 case kExternalByteArray: { | |
| 1849 ExternalByteArrayStoreStub stub; | |
| 1850 return stub.TryGetCode(); | |
| 1851 } | |
| 1852 case kExternalUnsignedByteArray: { | |
| 1853 ExternalUnsignedByteArrayStoreStub stub; | |
| 1854 return stub.TryGetCode(); | |
| 1855 } | |
| 1856 case kExternalShortArray: { | |
| 1857 ExternalShortArrayStoreStub stub; | |
| 1858 return stub.TryGetCode(); | |
| 1859 } | |
| 1860 case kExternalUnsignedShortArray: { | |
| 1861 ExternalUnsignedShortArrayStoreStub stub; | |
| 1862 return stub.TryGetCode(); | |
| 1863 } | |
| 1864 case kExternalIntArray: { | |
| 1865 ExternalIntArrayStoreStub stub; | |
| 1866 return stub.TryGetCode(); | |
| 1867 } | |
| 1868 case kExternalUnsignedIntArray: { | |
| 1869 ExternalUnsignedIntArrayStoreStub stub; | |
| 1870 return stub.TryGetCode(); | |
| 1871 } | |
| 1872 case kExternalDoubleArray: { | |
| 1873 ExternalDoubleArrayStoreStub stub; | |
| 1874 return stub.TryGetCode(); | |
| 1875 } | |
| 1876 case kExternalFloatArray: { | |
| 1877 ExternalFloatArrayStoreStub stub; | |
| 1878 return stub.TryGetCode(); | |
| 1879 } | |
| 1880 case kExternalPixelArray: { | |
| 1881 ExternalPixelArrayStoreStub stub; | |
| 1882 return stub.TryGetCode(); | |
| 1883 } | |
| 1884 } | |
| 1885 UNREACHABLE(); | |
| 1886 return NULL; | |
| 1887 } | |
| 1888 | |
| 1889 | |
| 1890 MaybeObject* KeyedStoreIC::ConstructMonomorphicFastElementStub( | |
| 1891 Map* receiver_map, | |
| 1892 StrictModeFlag strict_mode) { | |
| 1893 Object* object; | |
| 1894 KeyedStoreStubCompiler compiler(strict_mode); | |
| 1895 MaybeObject* maybe_code = compiler.CompileStoreFastElement(receiver_map); | |
| 1896 if (!maybe_code->ToObject(&object)) return maybe_code; | |
| 1897 PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, | |
| 1898 Code::cast(object), 0)); | |
| 1899 return object; | |
| 1900 } | |
| 1901 | |
| 1902 | |
| 1903 MaybeObject* KeyedStoreIC::ConstructMegamorphicStub( | |
| 1904 MapList* receiver_maps, | |
| 1905 CodeList* targets, | |
| 1906 StrictModeFlag strict_mode) { | |
| 1907 Object* object; | |
| 1908 KeyedStoreStubCompiler compiler(strict_mode); | |
| 1909 MaybeObject* maybe_code = compiler.CompileStoreMegamorphic(receiver_maps, | |
| 1910 targets); | |
| 1911 if (!maybe_code->ToObject(&object)) return maybe_code; | |
| 1912 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment(); | |
| 1913 PROFILE(isolate(), CodeCreateEvent( | |
| 1914 Logger::KEYED_STORE_MEGAMORPHIC_IC_TAG, | |
| 1915 Code::cast(object), 0)); | |
| 1916 return object; | |
| 1917 } | |
| 1918 | |
| 1919 | |
| 1486 MaybeObject* KeyedStoreIC::Store(State state, | 1920 MaybeObject* KeyedStoreIC::Store(State state, |
| 1487 StrictModeFlag strict_mode, | 1921 StrictModeFlag strict_mode, |
| 1488 Handle<Object> object, | 1922 Handle<Object> object, |
| 1489 Handle<Object> key, | 1923 Handle<Object> key, |
| 1490 Handle<Object> value) { | 1924 Handle<Object> value, |
| 1925 bool force_generic) { | |
| 1491 if (key->IsSymbol()) { | 1926 if (key->IsSymbol()) { |
| 1492 Handle<String> name = Handle<String>::cast(key); | 1927 Handle<String> name = Handle<String>::cast(key); |
| 1493 | 1928 |
| 1494 // If the object is undefined or null it's illegal to try to set any | 1929 // 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. | 1930 // properties on it; throw a TypeError in that case. |
| 1496 if (object->IsUndefined() || object->IsNull()) { | 1931 if (object->IsUndefined() || object->IsNull()) { |
| 1497 return TypeError("non_object_property_store", object, name); | 1932 return TypeError("non_object_property_store", object, name); |
| 1498 } | 1933 } |
| 1499 | 1934 |
| 1500 // Ignore stores where the receiver is not a JSObject. | 1935 // Ignore stores where the receiver is not a JSObject. |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 1522 // Set the property. | 1957 // Set the property. |
| 1523 return receiver->SetProperty(*name, *value, NONE, strict_mode); | 1958 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1524 } | 1959 } |
| 1525 | 1960 |
| 1526 // Do not use ICs for objects that require access checks (including | 1961 // Do not use ICs for objects that require access checks (including |
| 1527 // the global object). | 1962 // the global object). |
| 1528 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1963 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
| 1529 ASSERT(!(use_ic && object->IsJSGlobalProxy())); | 1964 ASSERT(!(use_ic && object->IsJSGlobalProxy())); |
| 1530 | 1965 |
| 1531 if (use_ic) { | 1966 if (use_ic) { |
| 1532 Code* stub = | 1967 Code* stub = (strict_mode == kStrictMode) |
| 1533 (strict_mode == kStrictMode) ? generic_stub_strict() : generic_stub(); | 1968 ? generic_stub_strict() |
| 1534 if (state == UNINITIALIZED) { | 1969 : generic_stub(); |
| 1535 if (object->IsJSObject()) { | 1970 if (!force_generic) { |
| 1536 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1971 if (object->IsJSObject() && key->IsSmi()) { |
| 1537 if (receiver->HasExternalArrayElements()) { | 1972 JSObject* receiver = JSObject::cast(*object); |
| 1538 MaybeObject* probe = | 1973 MaybeObject* maybe_stub = ComputeStub(receiver, |
| 1539 isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray( | 1974 true, |
| 1540 *receiver, true, strict_mode); | 1975 strict_mode, |
| 1541 stub = probe->IsFailure() ? | 1976 stub); |
| 1542 NULL : Code::cast(probe->ToObjectUnchecked()); | 1977 stub = maybe_stub->IsFailure() ? |
| 1543 } else if (key->IsSmi() && receiver->map()->has_fast_elements()) { | 1978 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 } | 1979 } |
| 1551 } | 1980 } |
| 1552 if (stub != NULL) set_target(stub); | 1981 if (stub != NULL) set_target(stub); |
| 1553 } | 1982 } |
| 1554 | 1983 |
| 1984 #ifdef DEBUG | |
| 1985 TraceIC("KeyedStoreIC", key, state, target()); | |
| 1986 #endif | |
| 1987 | |
| 1555 // Set the property. | 1988 // Set the property. |
| 1556 return Runtime::SetObjectProperty( | 1989 return Runtime::SetObjectProperty( |
| 1557 isolate(), object , key, value, NONE, strict_mode); | 1990 isolate(), object , key, value, NONE, strict_mode); |
| 1558 } | 1991 } |
| 1559 | 1992 |
| 1560 | 1993 |
| 1561 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, | 1994 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, |
| 1562 State state, | 1995 State state, |
| 1563 StrictModeFlag strict_mode, | 1996 StrictModeFlag strict_mode, |
| 1564 Handle<JSObject> receiver, | 1997 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)); | 2146 return ic.Load(state, args.at<Object>(0), args.at<String>(1)); |
| 1714 } | 2147 } |
| 1715 | 2148 |
| 1716 | 2149 |
| 1717 // Used from ic-<arch>.cc | 2150 // Used from ic-<arch>.cc |
| 1718 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) { | 2151 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) { |
| 1719 NoHandleAllocation na; | 2152 NoHandleAllocation na; |
| 1720 ASSERT(args.length() == 2); | 2153 ASSERT(args.length() == 2); |
| 1721 KeyedLoadIC ic(isolate); | 2154 KeyedLoadIC ic(isolate); |
| 1722 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2155 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1723 return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); | 2156 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), false); |
| 1724 } | 2157 } |
| 1725 | 2158 |
| 1726 | 2159 |
| 2160 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) { | |
| 2161 NoHandleAllocation na; | |
| 2162 ASSERT(args.length() == 2); | |
| 2163 KeyedLoadIC ic(isolate); | |
| 2164 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | |
| 2165 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), true); | |
| 2166 } | |
| 2167 | |
| 2168 | |
| 1727 // Used from ic-<arch>.cc. | 2169 // Used from ic-<arch>.cc. |
| 1728 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { | 2170 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { |
| 1729 NoHandleAllocation na; | 2171 NoHandleAllocation na; |
| 1730 ASSERT(args.length() == 3); | 2172 ASSERT(args.length() == 3); |
| 1731 StoreIC ic(isolate); | 2173 StoreIC ic(isolate); |
| 1732 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2174 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1733 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 2175 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 1734 return ic.Store(state, | 2176 return ic.Store(state, |
| 1735 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), | 2177 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
| 1736 args.at<Object>(0), | 2178 args.at<Object>(0), |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1797 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { | 2239 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { |
| 1798 NoHandleAllocation na; | 2240 NoHandleAllocation na; |
| 1799 ASSERT(args.length() == 3); | 2241 ASSERT(args.length() == 3); |
| 1800 KeyedStoreIC ic(isolate); | 2242 KeyedStoreIC ic(isolate); |
| 1801 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2243 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1802 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 2244 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 1803 return ic.Store(state, | 2245 return ic.Store(state, |
| 1804 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), | 2246 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
| 1805 args.at<Object>(0), | 2247 args.at<Object>(0), |
| 1806 args.at<Object>(1), | 2248 args.at<Object>(1), |
| 1807 args.at<Object>(2)); | 2249 args.at<Object>(2), |
| 2250 false); | |
| 1808 } | 2251 } |
| 1809 | 2252 |
| 1810 | 2253 |
| 2254 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) { | |
| 2255 NoHandleAllocation na; | |
| 2256 ASSERT(args.length() == 3); | |
| 2257 KeyedStoreIC ic(isolate); | |
| 2258 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | |
| 2259 Handle<Object> object = args.at<Object>(0); | |
| 2260 Handle<Object> key = args.at<Object>(1); | |
| 2261 Handle<Object> value = args.at<Object>(2); | |
| 2262 StrictModeFlag strict_mode = | |
| 2263 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode); | |
| 2264 return Runtime::SetObjectProperty(isolate, | |
| 2265 object, | |
| 2266 key, | |
| 2267 value, | |
| 2268 NONE, | |
| 2269 strict_mode); | |
| 2270 } | |
| 2271 | |
| 2272 | |
| 2273 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) { | |
| 2274 NoHandleAllocation na; | |
| 2275 ASSERT(args.length() == 3); | |
| 2276 KeyedStoreIC ic(isolate); | |
| 2277 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | |
| 2278 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | |
| 2279 return ic.Store(state, | |
| 2280 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), | |
| 2281 args.at<Object>(0), | |
| 2282 args.at<Object>(1), | |
| 2283 args.at<Object>(2), | |
| 2284 true); | |
| 2285 } | |
| 2286 | |
| 2287 | |
| 1811 void TRUnaryOpIC::patch(Code* code) { | 2288 void TRUnaryOpIC::patch(Code* code) { |
| 1812 set_target(code); | 2289 set_target(code); |
| 1813 } | 2290 } |
| 1814 | 2291 |
| 1815 | 2292 |
| 1816 const char* TRUnaryOpIC::GetName(TypeInfo type_info) { | 2293 const char* TRUnaryOpIC::GetName(TypeInfo type_info) { |
| 1817 switch (type_info) { | 2294 switch (type_info) { |
| 1818 case UNINITIALIZED: return "Uninitialized"; | 2295 case UNINITIALIZED: return "Uninitialized"; |
| 1819 case SMI: return "Smi"; | 2296 case SMI: return "Smi"; |
| 1820 case HEAP_NUMBER: return "HeapNumbers"; | 2297 case HEAP_NUMBER: return "HeapNumbers"; |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2189 #undef ADDR | 2666 #undef ADDR |
| 2190 }; | 2667 }; |
| 2191 | 2668 |
| 2192 | 2669 |
| 2193 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2670 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2194 return IC_utilities[id]; | 2671 return IC_utilities[id]; |
| 2195 } | 2672 } |
| 2196 | 2673 |
| 2197 | 2674 |
| 2198 } } // namespace v8::internal | 2675 } } // namespace v8::internal |
| OLD | NEW |