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

Side by Side Diff: src/ic.cc

Issue 12340112: Polymorphism support for load IC. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 7 years, 9 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
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 917 matching lines...) Expand 10 before | Expand all | Expand 10 after
928 return ReferenceError("not_defined", name); 928 return ReferenceError("not_defined", name);
929 } 929 }
930 return *result; 930 return *result;
931 } 931 }
932 932
933 // Get the property. 933 // Get the property.
934 return object->GetProperty(*object, &lookup, *name, &attr); 934 return object->GetProperty(*object, &lookup, *name, &attr);
935 } 935 }
936 936
937 937
938 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
939 Handle<Map> new_receiver_map) {
940 ASSERT(!new_receiver_map.is_null());
941 for (int current = 0; current < receiver_maps->length(); ++current) {
942 if (!receiver_maps->at(current).is_null() &&
943 receiver_maps->at(current).is_identical_to(new_receiver_map)) {
944 return false;
945 }
946 }
947 receiver_maps->Add(new_receiver_map);
948 return true;
949 }
950
951
952 bool IC::UpdatePolymorphicIC(State state,
953 StrictModeFlag strict_mode,
954 Handle<JSObject> receiver,
955 Handle<String> name,
956 Handle<Code> code) {
957 if (code->type() == Code::NORMAL) return false;
958 if (target()->ic_state() == MONOMORPHIC &&
959 target()->type() == Code::NORMAL) {
960 return false;
961 }
962 MapHandleList receiver_maps;
963 CodeHandleList handlers;
964 target()->FindAllMaps(&receiver_maps);
965 int number_of_maps = receiver_maps.length();
966 if (number_of_maps == 0 || number_of_maps >= 4) return false;
967
968 target()->FindAllCode(&handlers, receiver_maps.length());
969
970 if (!AddOneReceiverMapIfMissing(&receiver_maps,
971 Handle<Map>(receiver->map()))) {
972 return false;
973 }
974
975 handlers.Add(code);
976 Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC(
977 &receiver_maps, &handlers, name);
978 set_target(*ic);
979 return true;
980 }
981
982
983 void LoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
984 Handle<Code> handler,
985 Handle<String> name) {
986 if (handler->type() == Code::NORMAL) return set_target(*handler);
987 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
988 receiver, handler, name);
989 set_target(*ic);
990 }
991
992
993 void KeyedLoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
994 Handle<Code> handler,
995 Handle<String> name) {
996 if (handler->type() == Code::NORMAL) return set_target(*handler);
997 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedMonomorphicIC(
998 receiver, handler, name);
999 set_target(*ic);
1000 }
1001
1002
938 void IC::PatchCache(State state, 1003 void IC::PatchCache(State state,
939 StrictModeFlag strict_mode, 1004 StrictModeFlag strict_mode,
940 Handle<JSObject> receiver, 1005 Handle<JSObject> receiver,
941 Handle<String> name, 1006 Handle<String> name,
942 Handle<Code> code) { 1007 Handle<Code> code) {
943 switch (state) { 1008 switch (state) {
944 case UNINITIALIZED: 1009 case UNINITIALIZED:
945 case PREMONOMORPHIC: 1010 case PREMONOMORPHIC:
946 case MONOMORPHIC_PROTOTYPE_FAILURE: 1011 case MONOMORPHIC_PROTOTYPE_FAILURE:
947 set_target(*code); 1012 UpdateMonomorphicIC(receiver, code, name);
948 break; 1013 break;
949 case MONOMORPHIC: 1014 case MONOMORPHIC:
950 // Only move to megamorphic if the target changes. 1015 // Only move to megamorphic if the target changes.
951 if (target() != *code) { 1016 if (target() != *code) {
952 // We are transitioning from monomorphic to megamorphic case. 1017 if (target()->is_load_stub()) {
953 // Place the current monomorphic stub and stub compiled for 1018 if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) {
954 // the receiver into stub cache. 1019 break;
955 Map* map = target()->FindFirstMap(); 1020 }
956 if (map != NULL) { 1021 }
957 UpdateMegamorphicCache(map, *name, target()); 1022 // We are transitioning from monomorphic to megamorphic case. Place the
1023 // stub compiled for the receiver into stub cache.
1024 if (target()->is_store_stub()) {
1025 Map* map = target()->FindFirstMap();
1026 if (map != NULL) {
1027 UpdateMegamorphicCache(map, *name, target());
Jakob Kummerow 2013/03/01 22:21:04 Don't you want to do this for load stubs too when
Toon Verwaest 2013/03/04 10:54:08 Done.
1028 }
958 } 1029 }
959 UpdateMegamorphicCache(receiver->map(), *name, *code); 1030 UpdateMegamorphicCache(receiver->map(), *name, *code);
960 set_target((strict_mode == kStrictMode) 1031 set_target((strict_mode == kStrictMode)
961 ? *megamorphic_stub_strict() 1032 ? *megamorphic_stub_strict()
962 : *megamorphic_stub()); 1033 : *megamorphic_stub());
963 } 1034 }
964 break; 1035 break;
965 case MEGAMORPHIC: 1036 case MEGAMORPHIC:
966 // Update the stub cache. 1037 // Update the stub cache.
967 UpdateMegamorphicCache(receiver->map(), *name, *code); 1038 UpdateMegamorphicCache(receiver->map(), *name, *code);
968 break; 1039 break;
969 case POLYMORPHIC: 1040 case POLYMORPHIC:
970 // When trying to patch a polymorphic stub with anything other than 1041 if (target()->is_load_stub()) {
971 // another polymorphic stub, go generic. 1042 if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) {
972 // TODO(verwaest): Currently we always go generic since no polymorphic 1043 break;
973 // stubs enter this code path. Replace with proper updating once named 1044 }
974 // load/store can also be polymorphic. 1045 MapHandleList receiver_maps;
975 set_target((strict_mode == kStrictMode) 1046 CodeHandleList handlers;
976 ? *generic_stub_strict() 1047 target()->FindAllMaps(&receiver_maps);
977 : *generic_stub()); 1048 target()->FindAllCode(&handlers, receiver_maps.length());
1049 for (int i = 0; i < receiver_maps.length(); i++) {
1050 UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i));
1051 }
1052 UpdateMegamorphicCache(receiver->map(), *name, *code);
1053 set_target(*megamorphic_stub());
1054 } else {
1055 // When trying to patch a polymorphic keyed load/store element stub
Jakob Kummerow 2013/03/01 22:21:04 Comment seems inaccurate: We end up here when we t
Toon Verwaest 2013/03/04 10:54:08 The polymorphic stubs that are not load stubs are
1056 // with anything other than another polymorphic stub, go generic.
1057 set_target((strict_mode == kStrictMode)
1058 ? *generic_stub_strict()
1059 : *generic_stub());
1060 }
978 break; 1061 break;
979 case DEBUG_STUB: 1062 case DEBUG_STUB:
980 break; 1063 break;
981 case GENERIC: 1064 case GENERIC:
982 UNREACHABLE(); 1065 UNREACHABLE();
983 break; 1066 break;
984 } 1067 }
985 } 1068 }
986 1069
987 1070
1071 static void GetReceiverMapsForStub(Handle<Code> stub,
1072 MapHandleList* result) {
1073 ASSERT(stub->is_inline_cache_stub());
1074 switch (stub->ic_state()) {
1075 case MONOMORPHIC: {
1076 Map* map = stub->FindFirstMap();
1077 if (map != NULL) {
1078 result->Add(Handle<Map>(map));
1079 }
1080 break;
1081 }
1082 case POLYMORPHIC: {
1083 AssertNoAllocation no_allocation;
1084 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
1085 for (RelocIterator it(*stub, mask); !it.done(); it.next()) {
1086 RelocInfo* info = it.rinfo();
1087 Handle<Object> object(info->target_object(), stub->GetIsolate());
1088 if (object->IsString()) break;
1089 ASSERT(object->IsMap());
1090 AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
1091 }
1092 break;
1093 }
1094 case MEGAMORPHIC:
1095 break;
1096 case UNINITIALIZED:
1097 case PREMONOMORPHIC:
1098 case MONOMORPHIC_PROTOTYPE_FAILURE:
1099 case GENERIC:
1100 case DEBUG_STUB:
1101 UNREACHABLE();
1102 break;
1103 }
1104 }
1105
1106
988 void LoadIC::UpdateCaches(LookupResult* lookup, 1107 void LoadIC::UpdateCaches(LookupResult* lookup,
989 State state, 1108 State state,
990 Handle<Object> object, 1109 Handle<Object> object,
991 Handle<String> name) { 1110 Handle<String> name) {
992 // Bail out if the result is not cacheable. 1111 // Bail out if the result is not cacheable.
993 if (!lookup->IsCacheable()) return; 1112 if (!lookup->IsCacheable()) return;
994 1113
995 // Loading properties from values is not common, so don't try to 1114 // Loading properties from values is not common, so don't try to
996 // deal with non-JS objects here. 1115 // deal with non-JS objects here.
997 if (!object->IsJSObject()) return; 1116 if (!object->IsJSObject()) return;
998 1117
999 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1118 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1000 Handle<Code> code; 1119 Handle<Code> code;
1001 if (state == UNINITIALIZED) { 1120 if (state == UNINITIALIZED) {
1002 // This is the first time we execute this inline cache. 1121 // This is the first time we execute this inline cache.
1003 // Set the target to the pre monomorphic stub to delay 1122 // Set the target to the pre monomorphic stub to delay
1004 // setting the monomorphic state. 1123 // setting the monomorphic state.
1005 code = pre_monomorphic_stub(); 1124 code = pre_monomorphic_stub();
1006 } else { 1125 } else {
1007 code = ComputeLoadMonomorphic(lookup, receiver, name); 1126 code = ComputeLoadHandler(lookup, receiver, name);
1008 if (code.is_null()) return; 1127 if (code.is_null()) return;
1009 } 1128 }
1010 1129
1011 PatchCache(state, kNonStrictMode, receiver, name, code); 1130 PatchCache(state, kNonStrictMode, receiver, name, code);
1012 TRACE_IC("LoadIC", name, state, target()); 1131 TRACE_IC("LoadIC", name, state, target());
1013 } 1132 }
1014 1133
1015 1134
1016 void IC::UpdateMegamorphicCache(Map* map, String* name, Code* code) { 1135 void IC::UpdateMegamorphicCache(Map* map, String* name, Code* code) {
1017 // Cache code holding map should be consistent with 1136 // Cache code holding map should be consistent with
1018 // GenerateMonomorphicCacheProbe. 1137 // GenerateMonomorphicCacheProbe.
1019 isolate()->stub_cache()->Set(name, map, code); 1138 isolate()->stub_cache()->Set(name, map, code);
1020 } 1139 }
1021 1140
1022 1141
1023 Handle<Code> LoadIC::ComputeLoadMonomorphic(LookupResult* lookup, 1142 Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
1024 Handle<JSObject> receiver, 1143 Handle<JSObject> receiver,
1025 Handle<String> name) { 1144 Handle<String> name) {
1026 if (!lookup->IsProperty()) { 1145 if (!lookup->IsProperty()) {
1027 // Nonexistent property. The result is undefined. 1146 // Nonexistent property. The result is undefined.
1028 return isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver); 1147 return isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver);
1029 } 1148 }
1030 1149
1031 // Compute monomorphic stub. 1150 // Compute monomorphic stub.
1032 Handle<JSObject> holder(lookup->holder()); 1151 Handle<JSObject> holder(lookup->holder());
1033 switch (lookup->type()) { 1152 switch (lookup->type()) {
1034 case FIELD: 1153 case FIELD:
1035 return isolate()->stub_cache()->ComputeLoadField( 1154 return isolate()->stub_cache()->ComputeLoadField(
1036 name, receiver, holder, lookup->GetFieldIndex()); 1155 name, receiver, holder, lookup->GetFieldIndex());
1037 case CONSTANT_FUNCTION: { 1156 case CONSTANT_FUNCTION: {
1038 Handle<JSFunction> constant(lookup->GetConstantFunction()); 1157 Handle<JSFunction> constant(lookup->GetConstantFunction());
1039 return isolate()->stub_cache()->ComputeLoadConstant( 1158 return isolate()->stub_cache()->ComputeLoadConstant(
1040 name, receiver, holder, constant); 1159 name, receiver, holder, constant);
1041 } 1160 }
1042 case NORMAL: 1161 case NORMAL:
1043 if (holder->IsGlobalObject()) { 1162 if (holder->IsGlobalObject()) {
1044 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); 1163 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
1045 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); 1164 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup));
1046 return isolate()->stub_cache()->ComputeLoadGlobal( 1165 return isolate()->stub_cache()->ComputeLoadGlobal(
1047 name, receiver, global, cell, lookup->IsDontDelete()); 1166 name, receiver, global, cell, lookup->IsDontDelete());
1048 } 1167 }
1049 // There is only one shared stub for loading normalized 1168 // There is only one shared stub for loading normalized
1050 // properties. It does not traverse the prototype chain, so the 1169 // properties. It does not traverse the prototype chain, so the
1051 // property must be found in the receiver for the stub to be 1170 // property must be found in the receiver for the stub to be
1052 // applicable. 1171 // applicable.
1053 if (!holder.is_identical_to(receiver)) break; 1172 if (!holder.is_identical_to(receiver)) break;
1054 return isolate()->stub_cache()->ComputeLoadNormal(); 1173 return isolate()->stub_cache()->ComputeLoadNormal(name, receiver);
1055 case CALLBACKS: { 1174 case CALLBACKS: {
1056 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); 1175 Handle<Object> callback(lookup->GetCallbackObject(), isolate());
1057 if (callback->IsExecutableAccessorInfo()) { 1176 if (callback->IsExecutableAccessorInfo()) {
1058 Handle<ExecutableAccessorInfo> info = 1177 Handle<ExecutableAccessorInfo> info =
1059 Handle<ExecutableAccessorInfo>::cast(callback); 1178 Handle<ExecutableAccessorInfo>::cast(callback);
1060 if (v8::ToCData<Address>(info->getter()) == 0) break; 1179 if (v8::ToCData<Address>(info->getter()) == 0) break;
1061 if (!info->IsCompatibleReceiver(*receiver)) break; 1180 if (!info->IsCompatibleReceiver(*receiver)) break;
1062 return isolate()->stub_cache()->ComputeLoadCallback( 1181 return isolate()->stub_cache()->ComputeLoadCallback(
1063 name, receiver, holder, info); 1182 name, receiver, holder, info);
1064 } else if (callback->IsAccessorPair()) { 1183 } else if (callback->IsAccessorPair()) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1100 key = Handle<Smi>(Smi::FromInt(int_value), isolate); 1219 key = Handle<Smi>(Smi::FromInt(int_value), isolate);
1101 } 1220 }
1102 } 1221 }
1103 } else if (key->IsUndefined()) { 1222 } else if (key->IsUndefined()) {
1104 key = isolate->factory()->undefined_symbol(); 1223 key = isolate->factory()->undefined_symbol();
1105 } 1224 }
1106 return key; 1225 return key;
1107 } 1226 }
1108 1227
1109 1228
1110 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
1111 Handle<Map> new_receiver_map) {
1112 ASSERT(!new_receiver_map.is_null());
1113 for (int current = 0; current < receiver_maps->length(); ++current) {
1114 if (!receiver_maps->at(current).is_null() &&
1115 receiver_maps->at(current).is_identical_to(new_receiver_map)) {
1116 return false;
1117 }
1118 }
1119 receiver_maps->Add(new_receiver_map);
1120 return true;
1121 }
1122
1123
1124 static void GetReceiverMapsForStub(Handle<Code> stub,
1125 MapHandleList* result) {
1126 ASSERT(stub->is_inline_cache_stub());
1127 ASSERT(stub->is_keyed_load_stub() || stub->is_keyed_store_stub());
1128 switch (stub->ic_state()) {
1129 case MONOMORPHIC: {
1130 Map* map = stub->FindFirstMap();
1131 if (map != NULL) {
1132 result->Add(Handle<Map>(map));
1133 }
1134 break;
1135 }
1136 case POLYMORPHIC: {
1137 AssertNoAllocation no_allocation;
1138 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
1139 for (RelocIterator it(*stub, mask); !it.done(); it.next()) {
1140 RelocInfo* info = it.rinfo();
1141 Handle<Object> object(info->target_object(), stub->GetIsolate());
1142 ASSERT(object->IsMap());
1143 AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
1144 }
1145 break;
1146 }
1147 case MEGAMORPHIC:
1148 break;
1149 case UNINITIALIZED:
1150 case PREMONOMORPHIC:
1151 case MONOMORPHIC_PROTOTYPE_FAILURE:
1152 case GENERIC:
1153 case DEBUG_STUB:
1154 UNREACHABLE();
1155 break;
1156 }
1157 }
1158
1159
1160 Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) { 1229 Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) {
1161 State ic_state = target()->ic_state(); 1230 State ic_state = target()->ic_state();
1162 1231
1163 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS 1232 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
1164 // via megamorphic stubs, since they don't have a map in their relocation info 1233 // via megamorphic stubs, since they don't have a map in their relocation info
1165 // and so the stubs can't be harvested for the object needed for a map check. 1234 // and so the stubs can't be harvested for the object needed for a map check.
1166 if (target()->type() != Code::NORMAL) { 1235 if (target()->type() != Code::NORMAL) {
1167 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type"); 1236 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type");
1168 return generic_stub(); 1237 return generic_stub();
1169 } 1238 }
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
1261 ASSERT(!stub.is_null()); 1330 ASSERT(!stub.is_null());
1262 set_target(*stub); 1331 set_target(*stub);
1263 TRACE_IC("KeyedLoadIC", key, state, target()); 1332 TRACE_IC("KeyedLoadIC", key, state, target());
1264 } 1333 }
1265 1334
1266 1335
1267 return Runtime::GetObjectProperty(isolate(), object, key); 1336 return Runtime::GetObjectProperty(isolate(), object, key);
1268 } 1337 }
1269 1338
1270 1339
1271 Handle<Code> KeyedLoadIC::ComputeLoadMonomorphic(LookupResult* lookup, 1340 Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup,
1272 Handle<JSObject> receiver, 1341 Handle<JSObject> receiver,
1273 Handle<String> name) { 1342 Handle<String> name) {
1274 // Bail out if we didn't find a result. 1343 // Bail out if we didn't find a result.
1275 if (!lookup->IsProperty()) return Handle<Code>::null(); 1344 if (!lookup->IsProperty()) return Handle<Code>::null();
1276 1345
1277 // Compute a monomorphic stub. 1346 // Compute a monomorphic stub.
1278 Handle<JSObject> holder(lookup->holder()); 1347 Handle<JSObject> holder(lookup->holder());
1279 switch (lookup->type()) { 1348 switch (lookup->type()) {
1280 case FIELD: 1349 case FIELD:
1281 return isolate()->stub_cache()->ComputeKeyedLoadField( 1350 return isolate()->stub_cache()->ComputeKeyedLoadField(
1282 name, receiver, holder, lookup->GetFieldIndex()); 1351 name, receiver, holder, lookup->GetFieldIndex());
1283 case CONSTANT_FUNCTION: { 1352 case CONSTANT_FUNCTION: {
(...skipping 1279 matching lines...) Expand 10 before | Expand all | Expand 10 after
2563 #undef ADDR 2632 #undef ADDR
2564 }; 2633 };
2565 2634
2566 2635
2567 Address IC::AddressFromUtilityId(IC::UtilityId id) { 2636 Address IC::AddressFromUtilityId(IC::UtilityId id) {
2568 return IC_utilities[id]; 2637 return IC_utilities[id];
2569 } 2638 }
2570 2639
2571 2640
2572 } } // namespace v8::internal 2641 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698