OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 923 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
934 // If we did not find a property, check if we need to throw an exception. | 934 // If we did not find a property, check if we need to throw an exception. |
935 if (!lookup.IsFound()) { | 935 if (!lookup.IsFound()) { |
936 if (IsUndeclaredGlobal(object)) { | 936 if (IsUndeclaredGlobal(object)) { |
937 return ReferenceError("not_defined", name); | 937 return ReferenceError("not_defined", name); |
938 } | 938 } |
939 LOG(isolate(), SuspectReadEvent(*name, *object)); | 939 LOG(isolate(), SuspectReadEvent(*name, *object)); |
940 } | 940 } |
941 | 941 |
942 // Update inline cache and stub cache. | 942 // Update inline cache and stub cache. |
943 if (FLAG_use_ic) { | 943 if (FLAG_use_ic) { |
944 UpdateLoadCaches(&lookup, state, object, name); | 944 UpdateCaches(&lookup, state, object, name); |
945 } | 945 } |
946 | 946 |
947 PropertyAttributes attr; | 947 PropertyAttributes attr; |
948 if (lookup.IsInterceptor() || lookup.IsHandler()) { | 948 if (lookup.IsInterceptor() || lookup.IsHandler()) { |
949 // Get the property. | 949 // Get the property. |
950 Handle<Object> result = | 950 Handle<Object> result = |
951 Object::GetProperty(object, object, &lookup, name, &attr); | 951 Object::GetProperty(object, object, &lookup, name, &attr); |
952 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 952 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
953 // If the property is not present, check if we need to throw an | 953 // If the property is not present, check if we need to throw an |
954 // exception. | 954 // exception. |
955 if (attr == ABSENT && IsUndeclaredGlobal(object)) { | 955 if (attr == ABSENT && IsUndeclaredGlobal(object)) { |
956 return ReferenceError("not_defined", name); | 956 return ReferenceError("not_defined", name); |
957 } | 957 } |
958 return *result; | 958 return *result; |
959 } | 959 } |
960 | 960 |
961 // Get the property. | 961 // Get the property. |
962 return object->GetProperty(*object, &lookup, *name, &attr); | 962 return object->GetProperty(*object, &lookup, *name, &attr); |
963 } | 963 } |
964 | 964 |
965 | 965 |
966 void LoadIC::UpdateLoadCaches(LookupResult* lookup, | 966 void LoadIC::UpdateCaches(LookupResult* lookup, |
967 State state, | 967 State state, |
968 Handle<Object> object, | 968 Handle<Object> object, |
969 Handle<String> name) { | 969 Handle<String> name) { |
970 // Bail out if the result is not cacheable. | 970 // Bail out if the result is not cacheable. |
971 if (!lookup->IsCacheable()) return; | 971 if (!lookup->IsCacheable()) return; |
972 | 972 |
973 // Loading properties from values is not common, so don't try to | 973 // Loading properties from values is not common, so don't try to |
974 // deal with non-JS objects here. | 974 // deal with non-JS objects here. |
975 if (!object->IsJSObject()) return; | 975 if (!object->IsJSObject()) return; |
976 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
977 | 976 |
978 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; | 977 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; |
979 | 978 |
980 // Compute the code stub for this load. | 979 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
981 Handle<Code> code; | 980 Handle<Code> code; |
982 if (state == UNINITIALIZED) { | 981 if (state == UNINITIALIZED) { |
983 // This is the first time we execute this inline cache. | 982 // This is the first time we execute this inline cache. |
984 // Set the target to the pre monomorphic stub to delay | 983 // Set the target to the pre monomorphic stub to delay |
985 // setting the monomorphic state. | 984 // setting the monomorphic state. |
986 code = pre_monomorphic_stub(); | 985 code = pre_monomorphic_stub(); |
987 } else if (!lookup->IsProperty()) { | |
988 // Nonexistent property. The result is undefined. | |
989 code = isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver); | |
990 } else { | 986 } else { |
991 // Compute monomorphic stub. | 987 code = ComputeLoadMonomorphic(lookup, receiver, name); |
992 Handle<JSObject> holder(lookup->holder()); | 988 if (code.is_null()) return; |
993 switch (lookup->type()) { | |
994 case FIELD: | |
995 code = isolate()->stub_cache()->ComputeLoadField( | |
996 name, receiver, holder, lookup->GetFieldIndex()); | |
997 break; | |
998 case CONSTANT_FUNCTION: { | |
999 Handle<JSFunction> constant(lookup->GetConstantFunction()); | |
1000 code = isolate()->stub_cache()->ComputeLoadConstant( | |
1001 name, receiver, holder, constant); | |
1002 break; | |
1003 } | |
1004 case NORMAL: | |
1005 if (holder->IsGlobalObject()) { | |
1006 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); | |
1007 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); | |
1008 code = isolate()->stub_cache()->ComputeLoadGlobal( | |
1009 name, receiver, global, cell, lookup->IsDontDelete()); | |
1010 } else { | |
1011 // There is only one shared stub for loading normalized | |
1012 // properties. It does not traverse the prototype chain, so the | |
1013 // property must be found in the receiver for the stub to be | |
1014 // applicable. | |
1015 if (!holder.is_identical_to(receiver)) return; | |
1016 code = isolate()->stub_cache()->ComputeLoadNormal(); | |
1017 } | |
1018 break; | |
1019 case CALLBACKS: { | |
1020 Handle<Object> callback(lookup->GetCallbackObject()); | |
1021 if (callback->IsAccessorInfo()) { | |
1022 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(callback); | |
1023 if (v8::ToCData<Address>(info->getter()) == 0) return; | |
1024 if (!info->IsCompatibleReceiver(*receiver)) return; | |
1025 code = isolate()->stub_cache()->ComputeLoadCallback( | |
1026 name, receiver, holder, info); | |
1027 } else if (callback->IsAccessorPair()) { | |
1028 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter()); | |
1029 if (!getter->IsJSFunction()) return; | |
1030 if (holder->IsGlobalObject()) return; | |
1031 if (!holder->HasFastProperties()) return; | |
1032 code = isolate()->stub_cache()->ComputeLoadViaGetter( | |
1033 name, receiver, holder, Handle<JSFunction>::cast(getter)); | |
1034 } else { | |
1035 ASSERT(callback->IsForeign()); | |
1036 // No IC support for old-style native accessors. | |
1037 return; | |
1038 } | |
1039 break; | |
1040 } | |
1041 case INTERCEPTOR: | |
1042 ASSERT(HasInterceptorGetter(*holder)); | |
1043 code = isolate()->stub_cache()->ComputeLoadInterceptor( | |
1044 name, receiver, holder); | |
1045 break; | |
1046 default: | |
1047 return; | |
1048 } | |
1049 } | 989 } |
1050 | 990 |
1051 // Patch the call site depending on the state of the cache. | 991 // Patch the call site depending on the state of the cache. |
1052 switch (state) { | 992 switch (state) { |
1053 case UNINITIALIZED: | 993 case UNINITIALIZED: |
1054 case PREMONOMORPHIC: | 994 case PREMONOMORPHIC: |
1055 case MONOMORPHIC_PROTOTYPE_FAILURE: | 995 case MONOMORPHIC_PROTOTYPE_FAILURE: |
1056 set_target(*code); | 996 set_target(*code); |
1057 break; | 997 break; |
1058 case MONOMORPHIC: | 998 case MONOMORPHIC: |
1059 if (target() != *code) { | 999 if (target() != *code) { |
1060 // We are transitioning from monomorphic to megamorphic case. | 1000 // We are transitioning from monomorphic to megamorphic case. |
1061 // Place the current monomorphic stub and stub compiled for | 1001 // Place the current monomorphic stub and stub compiled for |
1062 // the receiver into stub cache. | 1002 // the receiver into stub cache. |
1063 Map* map = target()->FindFirstMap(); | 1003 Map* map = target()->FindFirstMap(); |
1064 if (map != NULL) { | 1004 if (map != NULL) { |
1065 isolate()->stub_cache()->Set(*name, map, target()); | 1005 UpdateMegamorphicCache(map, *name, target()); |
1066 } | 1006 } |
1067 isolate()->stub_cache()->Set(*name, receiver->map(), *code); | 1007 UpdateMegamorphicCache(receiver->map(), *name, *code); |
1068 | |
1069 set_target(*megamorphic_stub()); | 1008 set_target(*megamorphic_stub()); |
1070 } | 1009 } |
1071 break; | 1010 break; |
1072 case MEGAMORPHIC: | 1011 case MEGAMORPHIC: |
1073 // Cache code holding map should be consistent with | 1012 UpdateMegamorphicCache(receiver->map(), *name, *code); |
1074 // GenerateMonomorphicCacheProbe. | |
1075 isolate()->stub_cache()->Set(*name, receiver->map(), *code); | |
1076 break; | 1013 break; |
1077 case DEBUG_STUB: | 1014 case DEBUG_STUB: |
1078 break; | 1015 break; |
1079 case POLYMORPHIC: | 1016 case POLYMORPHIC: |
1080 case GENERIC: | 1017 case GENERIC: |
1081 UNREACHABLE(); | 1018 UNREACHABLE(); |
1082 break; | 1019 break; |
1083 } | 1020 } |
1084 | 1021 |
1085 TRACE_IC("LoadIC", name, state, target()); | 1022 TRACE_IC("LoadIC", name, state, target()); |
1086 } | 1023 } |
1087 | 1024 |
1088 | 1025 |
| 1026 void LoadIC::UpdateMegamorphicCache(Map* map, String* name, Code* code) { |
| 1027 // Cache code holding map should be consistent with |
| 1028 // GenerateMonomorphicCacheProbe. |
| 1029 isolate()->stub_cache()->Set(name, map, code); |
| 1030 } |
| 1031 |
| 1032 |
| 1033 Handle<Code> LoadIC::ComputeLoadMonomorphic(LookupResult* lookup, |
| 1034 Handle<JSObject> receiver, |
| 1035 Handle<String> name) { |
| 1036 if (!lookup->IsProperty()) { |
| 1037 // Nonexistent property. The result is undefined. |
| 1038 return isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver); |
| 1039 } |
| 1040 |
| 1041 // Compute monomorphic stub. |
| 1042 Handle<JSObject> holder(lookup->holder()); |
| 1043 switch (lookup->type()) { |
| 1044 case FIELD: |
| 1045 return isolate()->stub_cache()->ComputeLoadField( |
| 1046 name, receiver, holder, lookup->GetFieldIndex()); |
| 1047 case CONSTANT_FUNCTION: { |
| 1048 Handle<JSFunction> constant(lookup->GetConstantFunction()); |
| 1049 return isolate()->stub_cache()->ComputeLoadConstant( |
| 1050 name, receiver, holder, constant); |
| 1051 } |
| 1052 case NORMAL: |
| 1053 if (holder->IsGlobalObject()) { |
| 1054 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); |
| 1055 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); |
| 1056 return isolate()->stub_cache()->ComputeLoadGlobal( |
| 1057 name, receiver, global, cell, lookup->IsDontDelete()); |
| 1058 } |
| 1059 // There is only one shared stub for loading normalized |
| 1060 // properties. It does not traverse the prototype chain, so the |
| 1061 // property must be found in the receiver for the stub to be |
| 1062 // applicable. |
| 1063 if (!holder.is_identical_to(receiver)) break; |
| 1064 return isolate()->stub_cache()->ComputeLoadNormal(); |
| 1065 case CALLBACKS: { |
| 1066 Handle<Object> callback(lookup->GetCallbackObject()); |
| 1067 if (callback->IsAccessorInfo()) { |
| 1068 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(callback); |
| 1069 if (v8::ToCData<Address>(info->getter()) == 0) break; |
| 1070 if (!info->IsCompatibleReceiver(*receiver)) break; |
| 1071 return isolate()->stub_cache()->ComputeLoadCallback( |
| 1072 name, receiver, holder, info); |
| 1073 } else if (callback->IsAccessorPair()) { |
| 1074 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter()); |
| 1075 if (!getter->IsJSFunction()) break; |
| 1076 if (holder->IsGlobalObject()) break; |
| 1077 if (!holder->HasFastProperties()) break; |
| 1078 return isolate()->stub_cache()->ComputeLoadViaGetter( |
| 1079 name, receiver, holder, Handle<JSFunction>::cast(getter)); |
| 1080 } |
| 1081 ASSERT(callback->IsForeign()); |
| 1082 // No IC support for old-style native accessors. |
| 1083 break; |
| 1084 } |
| 1085 case INTERCEPTOR: |
| 1086 ASSERT(HasInterceptorGetter(*holder)); |
| 1087 return isolate()->stub_cache()->ComputeLoadInterceptor( |
| 1088 name, receiver, holder); |
| 1089 default: |
| 1090 break; |
| 1091 } |
| 1092 return Handle<Code>::null(); |
| 1093 } |
| 1094 |
| 1095 |
1089 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { | 1096 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { |
1090 // This helper implements a few common fast cases for converting | 1097 // This helper implements a few common fast cases for converting |
1091 // non-smi keys of keyed loads/stores to a smi or a string. | 1098 // non-smi keys of keyed loads/stores to a smi or a string. |
1092 if (key->IsHeapNumber()) { | 1099 if (key->IsHeapNumber()) { |
1093 double value = Handle<HeapNumber>::cast(key)->value(); | 1100 double value = Handle<HeapNumber>::cast(key)->value(); |
1094 if (isnan(value)) { | 1101 if (isnan(value)) { |
1095 key = isolate->factory()->nan_symbol(); | 1102 key = isolate->factory()->nan_symbol(); |
1096 } else { | 1103 } else { |
1097 int int_value = FastD2I(value); | 1104 int int_value = FastD2I(value); |
1098 if (value == int_value && Smi::IsValid(int_value)) { | 1105 if (value == int_value && Smi::IsValid(int_value)) { |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1255 if (!stub.is_null()) set_target(*stub); | 1262 if (!stub.is_null()) set_target(*stub); |
1256 } | 1263 } |
1257 | 1264 |
1258 TRACE_IC("KeyedLoadIC", key, state, target()); | 1265 TRACE_IC("KeyedLoadIC", key, state, target()); |
1259 | 1266 |
1260 // Get the property. | 1267 // Get the property. |
1261 return Runtime::GetObjectProperty(isolate(), object, key); | 1268 return Runtime::GetObjectProperty(isolate(), object, key); |
1262 } | 1269 } |
1263 | 1270 |
1264 | 1271 |
1265 void KeyedLoadIC::UpdateLoadCaches(LookupResult* lookup, | 1272 Handle<Code> KeyedLoadIC::ComputeLoadMonomorphic(LookupResult* lookup, |
1266 State state, | 1273 Handle<JSObject> receiver, |
1267 Handle<Object> object, | 1274 Handle<String> name) { |
1268 Handle<String> name) { | |
1269 // Bail out if we didn't find a result. | 1275 // Bail out if we didn't find a result. |
1270 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | 1276 if (!lookup->IsProperty()) return Handle<Code>::null(); |
1271 | 1277 |
1272 if (!object->IsJSObject()) return; | 1278 // Compute a monomorphic stub. |
1273 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1279 Handle<JSObject> holder(lookup->holder()); |
1274 | 1280 switch (lookup->type()) { |
1275 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; | 1281 case FIELD: |
1276 | 1282 return isolate()->stub_cache()->ComputeKeyedLoadField( |
1277 // Compute the code stub for this load. | 1283 name, receiver, holder, lookup->GetFieldIndex()); |
1278 Handle<Code> code; | 1284 case CONSTANT_FUNCTION: { |
1279 | 1285 Handle<JSFunction> constant(lookup->GetConstantFunction()); |
1280 if (state == UNINITIALIZED) { | 1286 return isolate()->stub_cache()->ComputeKeyedLoadConstant( |
1281 // This is the first time we execute this inline cache. | 1287 name, receiver, holder, constant); |
1282 // Set the target to the pre monomorphic stub to delay | |
1283 // setting the monomorphic state. | |
1284 code = pre_monomorphic_stub(); | |
1285 } else { | |
1286 // Compute a monomorphic stub. | |
1287 Handle<JSObject> holder(lookup->holder()); | |
1288 switch (lookup->type()) { | |
1289 case FIELD: | |
1290 code = isolate()->stub_cache()->ComputeKeyedLoadField( | |
1291 name, receiver, holder, lookup->GetFieldIndex()); | |
1292 break; | |
1293 case CONSTANT_FUNCTION: { | |
1294 Handle<JSFunction> constant(lookup->GetConstantFunction()); | |
1295 code = isolate()->stub_cache()->ComputeKeyedLoadConstant( | |
1296 name, receiver, holder, constant); | |
1297 break; | |
1298 } | |
1299 case CALLBACKS: { | |
1300 Handle<Object> callback_object(lookup->GetCallbackObject()); | |
1301 if (!callback_object->IsAccessorInfo()) return; | |
1302 Handle<AccessorInfo> callback = | |
1303 Handle<AccessorInfo>::cast(callback_object); | |
1304 if (v8::ToCData<Address>(callback->getter()) == 0) return; | |
1305 if (!callback->IsCompatibleReceiver(*receiver)) return; | |
1306 code = isolate()->stub_cache()->ComputeKeyedLoadCallback( | |
1307 name, receiver, holder, callback); | |
1308 break; | |
1309 } | |
1310 case INTERCEPTOR: | |
1311 ASSERT(HasInterceptorGetter(lookup->holder())); | |
1312 code = isolate()->stub_cache()->ComputeKeyedLoadInterceptor( | |
1313 name, receiver, holder); | |
1314 break; | |
1315 default: | |
1316 // Always rewrite to the generic case so that we do not | |
1317 // repeatedly try to rewrite. | |
1318 code = generic_stub(); | |
1319 break; | |
1320 } | 1288 } |
| 1289 case CALLBACKS: { |
| 1290 Handle<Object> callback_object(lookup->GetCallbackObject()); |
| 1291 if (!callback_object->IsAccessorInfo()) break; |
| 1292 Handle<AccessorInfo> callback = |
| 1293 Handle<AccessorInfo>::cast(callback_object); |
| 1294 if (v8::ToCData<Address>(callback->getter()) == 0) break; |
| 1295 if (!callback->IsCompatibleReceiver(*receiver)) break; |
| 1296 return isolate()->stub_cache()->ComputeKeyedLoadCallback( |
| 1297 name, receiver, holder, callback); |
| 1298 } |
| 1299 case INTERCEPTOR: |
| 1300 ASSERT(HasInterceptorGetter(lookup->holder())); |
| 1301 return isolate()->stub_cache()->ComputeKeyedLoadInterceptor( |
| 1302 name, receiver, holder); |
| 1303 default: |
| 1304 // Always rewrite to the generic case so that we do not |
| 1305 // repeatedly try to rewrite. |
| 1306 return generic_stub(); |
1321 } | 1307 } |
1322 | 1308 return Handle<Code>::null(); |
1323 // Patch the call site depending on the state of the cache. | |
1324 switch (state) { | |
1325 case UNINITIALIZED: | |
1326 case PREMONOMORPHIC: | |
1327 case POLYMORPHIC: | |
1328 set_target(*code); | |
1329 break; | |
1330 case MONOMORPHIC: | |
1331 // Only move to megamorphic if the target changes. | |
1332 if (target() != *code) { | |
1333 set_target(*megamorphic_stub()); | |
1334 } | |
1335 break; | |
1336 case MEGAMORPHIC: | |
1337 case GENERIC: | |
1338 case DEBUG_STUB: | |
1339 break; | |
1340 case MONOMORPHIC_PROTOTYPE_FAILURE: | |
1341 UNREACHABLE(); | |
1342 break; | |
1343 } | |
1344 | |
1345 TRACE_IC("KeyedLoadIC", name, state, target()); | |
1346 } | 1309 } |
1347 | 1310 |
1348 | 1311 |
1349 static bool StoreICableLookup(LookupResult* lookup) { | 1312 static bool StoreICableLookup(LookupResult* lookup) { |
1350 // Bail out if we didn't find a result. | 1313 // Bail out if we didn't find a result. |
1351 if (!lookup->IsFound()) return false; | 1314 if (!lookup->IsFound()) return false; |
1352 | 1315 |
1353 // Bail out if inline caching is not allowed. | 1316 // Bail out if inline caching is not allowed. |
1354 if (!lookup->IsCacheable()) return false; | 1317 if (!lookup->IsCacheable()) return false; |
1355 | 1318 |
(...skipping 1316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2672 #undef ADDR | 2635 #undef ADDR |
2673 }; | 2636 }; |
2674 | 2637 |
2675 | 2638 |
2676 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2639 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2677 return IC_utilities[id]; | 2640 return IC_utilities[id]; |
2678 } | 2641 } |
2679 | 2642 |
2680 | 2643 |
2681 } } // namespace v8::internal | 2644 } } // namespace v8::internal |
OLD | NEW |