Chromium Code Reviews| 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 814 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 825 ReceiverToObjectIfRequired(result, object); | 825 ReceiverToObjectIfRequired(result, object); |
| 826 if (result->IsJSFunction()) return *result; | 826 if (result->IsJSFunction()) return *result; |
| 827 | 827 |
| 828 result = TryCallAsFunction(result); | 828 result = TryCallAsFunction(result); |
| 829 if (result->IsJSFunction()) return *result; | 829 if (result->IsJSFunction()) return *result; |
| 830 | 830 |
| 831 return TypeError("property_not_function", object, key); | 831 return TypeError("property_not_function", object, key); |
| 832 } | 832 } |
| 833 | 833 |
| 834 | 834 |
| 835 bool IC::HandleLoad(State state, | 835 MaybeObject* IC::Load(State state, |
| 836 Handle<Object> object, | 836 Handle<Object> object, |
| 837 Handle<String> name, | 837 Handle<String> name) { |
| 838 MaybeObject** result) { | 838 // If the object is undefined or null it's illegal to try to get any |
| 839 // of its properties; throw a TypeError in that case. | |
| 840 if (object->IsUndefined() || object->IsNull()) { | |
| 841 return TypeError("non_object_property_load", object, name); | |
| 842 } | |
| 843 | |
| 839 if (FLAG_use_ic) { | 844 if (FLAG_use_ic) { |
| 840 // Use specialized code for getting the length of strings and | 845 // Use specialized code for getting the length of strings and |
| 841 // string wrapper objects. The length property of string wrapper | 846 // string wrapper objects. The length property of string wrapper |
| 842 // objects is read-only and therefore always returns the length of | 847 // objects is read-only and therefore always returns the length of |
| 843 // the underlying string value. See ECMA-262 15.5.5.1. | 848 // the underlying string value. See ECMA-262 15.5.5.1. |
| 844 if ((object->IsString() || object->IsStringWrapper()) && | 849 if ((object->IsString() || object->IsStringWrapper()) && |
| 845 name->Equals(isolate()->heap()->length_symbol())) { | 850 name->Equals(isolate()->heap()->length_symbol())) { |
| 846 Handle<Code> stub; | 851 Handle<Code> stub; |
| 847 if (state == UNINITIALIZED) { | 852 if (state == UNINITIALIZED) { |
| 848 stub = pre_monomorphic_stub(); | 853 stub = pre_monomorphic_stub(); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 859 if (!stub.is_null()) { | 864 if (!stub.is_null()) { |
| 860 set_target(*stub); | 865 set_target(*stub); |
| 861 #ifdef DEBUG | 866 #ifdef DEBUG |
| 862 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); | 867 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); |
| 863 #endif | 868 #endif |
| 864 } | 869 } |
| 865 // Get the string if we have a string wrapper object. | 870 // Get the string if we have a string wrapper object. |
| 866 Handle<Object> string = object->IsJSValue() | 871 Handle<Object> string = object->IsJSValue() |
| 867 ? Handle<Object>(Handle<JSValue>::cast(object)->value()) | 872 ? Handle<Object>(Handle<JSValue>::cast(object)->value()) |
| 868 : object; | 873 : object; |
| 869 *result = Smi::FromInt(String::cast(*string)->length()); | 874 return Smi::FromInt(String::cast(*string)->length()); |
| 870 return true; | |
| 871 } | 875 } |
| 872 | 876 |
| 873 // Use specialized code for getting the length of arrays. | 877 // Use specialized code for getting the length of arrays. |
| 874 if (object->IsJSArray() && | 878 if (object->IsJSArray() && |
| 875 name->Equals(isolate()->heap()->length_symbol())) { | 879 name->Equals(isolate()->heap()->length_symbol())) { |
| 876 Handle<Code> stub; | 880 Handle<Code> stub; |
| 877 if (state == UNINITIALIZED) { | 881 if (state == UNINITIALIZED) { |
| 878 stub = pre_monomorphic_stub(); | 882 stub = pre_monomorphic_stub(); |
| 879 } else if (state == PREMONOMORPHIC) { | 883 } else if (state == PREMONOMORPHIC) { |
| 880 ArrayLengthStub array_length_stub(kind()); | 884 ArrayLengthStub array_length_stub(kind()); |
| 881 stub = array_length_stub.GetCode(); | 885 stub = array_length_stub.GetCode(); |
| 882 } else if (state != MEGAMORPHIC) { | 886 } else if (state != MEGAMORPHIC) { |
| 883 ASSERT(state != GENERIC); | 887 ASSERT(state != GENERIC); |
| 884 stub = megamorphic_stub(); | 888 stub = megamorphic_stub(); |
| 885 } | 889 } |
| 886 if (!stub.is_null()) { | 890 if (!stub.is_null()) { |
| 887 set_target(*stub); | 891 set_target(*stub); |
| 888 #ifdef DEBUG | 892 #ifdef DEBUG |
| 889 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); | 893 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); |
| 890 #endif | 894 #endif |
| 891 } | 895 } |
| 892 *result = JSArray::cast(*object)->length(); | 896 return JSArray::cast(*object)->length(); |
| 893 return true; | |
| 894 } | 897 } |
| 895 | 898 |
| 896 // Use specialized code for getting prototype of functions. | 899 // Use specialized code for getting prototype of functions. |
| 897 if (object->IsJSFunction() && | 900 if (object->IsJSFunction() && |
| 898 name->Equals(isolate()->heap()->prototype_symbol()) && | 901 name->Equals(isolate()->heap()->prototype_symbol()) && |
| 899 Handle<JSFunction>::cast(object)->should_have_prototype()) { | 902 Handle<JSFunction>::cast(object)->should_have_prototype()) { |
| 900 Handle<Code> stub; | 903 Handle<Code> stub; |
| 901 if (state == UNINITIALIZED) { | 904 if (state == UNINITIALIZED) { |
| 902 stub = pre_monomorphic_stub(); | 905 stub = pre_monomorphic_stub(); |
| 903 } else if (state == PREMONOMORPHIC) { | 906 } else if (state == PREMONOMORPHIC) { |
| 904 FunctionPrototypeStub function_prototype_stub(kind()); | 907 FunctionPrototypeStub function_prototype_stub(kind()); |
| 905 stub = function_prototype_stub.GetCode(); | 908 stub = function_prototype_stub.GetCode(); |
| 906 } else if (state != MEGAMORPHIC) { | 909 } else if (state != MEGAMORPHIC) { |
| 907 ASSERT(state != GENERIC); | 910 ASSERT(state != GENERIC); |
| 908 stub = megamorphic_stub(); | 911 stub = megamorphic_stub(); |
| 909 } | 912 } |
| 910 if (!stub.is_null()) { | 913 if (!stub.is_null()) { |
| 911 set_target(*stub); | 914 set_target(*stub); |
| 912 #ifdef DEBUG | 915 #ifdef DEBUG |
| 913 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); | 916 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); |
| 914 #endif | 917 #endif |
| 915 } | 918 } |
| 916 *result = Accessors::FunctionGetPrototype(*object, 0); | 919 return Accessors::FunctionGetPrototype(*object, 0); |
| 917 return true; | |
| 918 } | 920 } |
| 919 } | 921 } |
| 920 | 922 |
| 921 return false; | 923 // Check if the name is trivially convertible to an index and get |
| 922 } | 924 // the element or char if so. |
| 923 | 925 uint32_t index; |
| 924 | 926 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) { |
| 925 MaybeObject* LoadIC::Load(State state, | 927 // Rewrite to the generic keyed load stub. |
| 926 Handle<Object> object, | 928 if (FLAG_use_ic) set_target(*generic_stub()); |
| 927 Handle<String> name) { | 929 return Runtime::GetElementOrCharAt(isolate(), object, index); |
| 928 // If the object is undefined or null it's illegal to try to get any | |
| 929 // of its properties; throw a TypeError in that case. | |
| 930 if (object->IsUndefined() || object->IsNull()) { | |
| 931 return TypeError("non_object_property_load", object, name); | |
| 932 } | 930 } |
| 933 | 931 |
| 934 MaybeObject* result; | |
| 935 if (HandleLoad(state, object, name, &result)) { | |
| 936 return result; | |
| 937 } | |
| 938 | |
| 939 // Check if the name is trivially convertible to an index and get | |
| 940 // the element if so. | |
| 941 uint32_t index; | |
| 942 if (name->AsArrayIndex(&index)) return object->GetElement(index); | |
|
Jakob Kummerow
2013/01/22 09:24:39
Per offline discussion: it seems this condition ca
| |
| 943 | |
| 944 // Named lookup in the object. | 932 // Named lookup in the object. |
| 945 LookupResult lookup(isolate()); | 933 LookupResult lookup(isolate()); |
| 946 LookupForRead(object, name, &lookup); | 934 LookupForRead(object, name, &lookup); |
| 947 | 935 |
| 948 // If we did not find a property, check if we need to throw an exception. | 936 // If we did not find a property, check if we need to throw an exception. |
| 949 if (!lookup.IsFound()) { | 937 if (!lookup.IsFound()) { |
| 950 if (IsContextual(object)) { | 938 if (IsContextual(object)) { |
| 951 return ReferenceError("not_defined", name); | 939 return ReferenceError("not_defined", name); |
| 952 } | 940 } |
| 953 LOG(isolate(), SuspectReadEvent(*name, *object)); | 941 LOG(isolate(), SuspectReadEvent(*name, *object)); |
| 954 } | 942 } |
| 955 | 943 |
| 956 // Update inline cache and stub cache. | 944 // Update inline cache and stub cache. |
| 957 if (FLAG_use_ic) { | 945 if (FLAG_use_ic) { |
| 958 UpdateCaches(&lookup, state, object, name); | 946 UpdateLoadCaches(&lookup, state, object, name); |
| 959 } | 947 } |
| 960 | 948 |
| 961 PropertyAttributes attr; | 949 PropertyAttributes attr; |
| 962 if (lookup.IsInterceptor() || lookup.IsHandler()) { | 950 if (lookup.IsInterceptor() || lookup.IsHandler()) { |
| 963 // Get the property. | 951 // Get the property. |
| 964 Handle<Object> result = | 952 Handle<Object> result = |
| 965 Object::GetProperty(object, object, &lookup, name, &attr); | 953 Object::GetProperty(object, object, &lookup, name, &attr); |
| 966 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 954 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 967 // If the property is not present, check if we need to throw an | 955 // If the property is not present, check if we need to throw an |
| 968 // exception. | 956 // exception. |
| 969 if (attr == ABSENT && IsContextual(object)) { | 957 if (attr == ABSENT && IsContextual(object)) { |
| 970 return ReferenceError("not_defined", name); | 958 return ReferenceError("not_defined", name); |
| 971 } | 959 } |
| 972 return *result; | 960 return *result; |
| 973 } | 961 } |
| 974 | 962 |
| 975 // Get the property. | 963 // Get the property. |
| 976 return object->GetProperty(*object, &lookup, *name, &attr); | 964 return object->GetProperty(*object, &lookup, *name, &attr); |
| 977 } | 965 } |
| 978 | 966 |
| 979 | 967 |
| 980 void LoadIC::UpdateCaches(LookupResult* lookup, | 968 void LoadIC::UpdateLoadCaches(LookupResult* lookup, |
| 981 State state, | 969 State state, |
| 982 Handle<Object> object, | 970 Handle<Object> object, |
| 983 Handle<String> name) { | 971 Handle<String> name) { |
| 984 // Bail out if the result is not cacheable. | 972 // Bail out if the result is not cacheable. |
| 985 if (!lookup->IsCacheable()) return; | 973 if (!lookup->IsCacheable()) return; |
| 986 | 974 |
| 987 // Loading properties from values is not common, so don't try to | 975 // Loading properties from values is not common, so don't try to |
| 988 // deal with non-JS objects here. | 976 // deal with non-JS objects here. |
| 989 if (!object->IsJSObject()) return; | 977 if (!object->IsJSObject()) return; |
| 990 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 978 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 991 | 979 |
| 992 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; | 980 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; |
| 993 | 981 |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1158 | 1146 |
| 1159 MaybeObject* KeyedLoadIC::Load(State state, | 1147 MaybeObject* KeyedLoadIC::Load(State state, |
| 1160 Handle<Object> object, | 1148 Handle<Object> object, |
| 1161 Handle<Object> key, | 1149 Handle<Object> key, |
| 1162 ICMissMode miss_mode) { | 1150 ICMissMode miss_mode) { |
| 1163 // Check for values that can be converted into a symbol directly or | 1151 // Check for values that can be converted into a symbol directly or |
| 1164 // is representable as a smi. | 1152 // is representable as a smi. |
| 1165 key = TryConvertKey(key, isolate()); | 1153 key = TryConvertKey(key, isolate()); |
| 1166 | 1154 |
| 1167 if (key->IsSymbol()) { | 1155 if (key->IsSymbol()) { |
| 1168 Handle<String> name = Handle<String>::cast(key); | 1156 return IC::Load(state, object, Handle<String>::cast(key)); |
| 1169 | |
| 1170 // If the object is undefined or null it's illegal to try to get any | |
| 1171 // of its properties; throw a TypeError in that case. | |
| 1172 if (object->IsUndefined() || object->IsNull()) { | |
| 1173 return TypeError("non_object_property_load", object, name); | |
| 1174 } | |
| 1175 | |
| 1176 MaybeObject* result; | |
| 1177 if (HandleLoad(state, object, name, &result)) { | |
| 1178 return result; | |
| 1179 } | |
| 1180 | |
| 1181 // Check if the name is trivially convertible to an index and get | |
| 1182 // the element or char if so. | |
| 1183 uint32_t index = 0; | |
| 1184 if (name->AsArrayIndex(&index)) { | |
| 1185 // Rewrite to the generic keyed load stub. | |
| 1186 if (FLAG_use_ic) set_target(*generic_stub()); | |
| 1187 return Runtime::GetElementOrCharAt(isolate(), object, index); | |
| 1188 } | |
| 1189 | |
| 1190 // Named lookup. | |
| 1191 LookupResult lookup(isolate()); | |
| 1192 LookupForRead(object, name, &lookup); | |
| 1193 | |
| 1194 // If we did not find a property, check if we need to throw an exception. | |
| 1195 if (!lookup.IsFound() && IsContextual(object)) { | |
| 1196 return ReferenceError("not_defined", name); | |
| 1197 } | |
| 1198 | |
| 1199 if (FLAG_use_ic) { | |
| 1200 UpdateCaches(&lookup, state, object, name); | |
| 1201 } | |
| 1202 | |
| 1203 PropertyAttributes attr; | |
| 1204 if (lookup.IsInterceptor()) { | |
| 1205 // Get the property. | |
| 1206 Handle<Object> result = | |
| 1207 Object::GetProperty(object, object, &lookup, name, &attr); | |
| 1208 RETURN_IF_EMPTY_HANDLE(isolate(), result); | |
| 1209 // If the property is not present, check if we need to throw an | |
| 1210 // exception. | |
| 1211 if (attr == ABSENT && IsContextual(object)) { | |
| 1212 return ReferenceError("not_defined", name); | |
| 1213 } | |
| 1214 return *result; | |
| 1215 } | |
| 1216 | |
| 1217 return object->GetProperty(*object, &lookup, *name, &attr); | |
| 1218 } | 1157 } |
| 1219 | 1158 |
| 1220 // Do not use ICs for objects that require access checks (including | 1159 // Do not use ICs for objects that require access checks (including |
| 1221 // the global object). | 1160 // the global object). |
| 1222 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1161 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
| 1223 | 1162 |
| 1224 if (use_ic) { | 1163 if (use_ic) { |
| 1225 Handle<Code> stub = generic_stub(); | 1164 Handle<Code> stub = generic_stub(); |
| 1226 if (miss_mode != MISS_FORCE_GENERIC) { | 1165 if (miss_mode != MISS_FORCE_GENERIC) { |
| 1227 if (object->IsString() && key->IsNumber()) { | 1166 if (object->IsString() && key->IsNumber()) { |
| 1228 if (state == UNINITIALIZED) { | 1167 if (state == UNINITIALIZED) { |
| 1229 stub = string_stub(); | 1168 stub = string_stub(); |
| 1230 } | 1169 } |
| 1231 } else if (object->IsJSObject()) { | 1170 } else if (object->IsJSObject()) { |
| 1232 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1171 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1233 if (receiver->elements()->map() == | 1172 if (receiver->elements()->map() == |
| 1234 isolate()->heap()->non_strict_arguments_elements_map()) { | 1173 isolate()->heap()->non_strict_arguments_elements_map()) { |
| 1235 stub = non_strict_arguments_stub(); | 1174 stub = non_strict_arguments_stub(); |
| 1236 } else if (receiver->HasIndexedInterceptor()) { | 1175 } else if (receiver->HasIndexedInterceptor()) { |
| 1237 stub = indexed_interceptor_stub(); | 1176 stub = indexed_interceptor_stub(); |
| 1238 } else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) { | 1177 } else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) { |
| 1239 stub = ComputeStub(receiver, LOAD, kNonStrictMode, stub); | 1178 stub = ComputeStub(receiver, KeyedIC::LOAD, kNonStrictMode, stub); |
| 1240 } | 1179 } |
| 1241 } | 1180 } |
| 1242 } else { | 1181 } else { |
| 1243 TRACE_GENERIC_IC("KeyedLoadIC", "force generic"); | 1182 TRACE_GENERIC_IC("KeyedLoadIC", "force generic"); |
| 1244 } | 1183 } |
| 1245 if (!stub.is_null()) set_target(*stub); | 1184 if (!stub.is_null()) set_target(*stub); |
| 1246 } | 1185 } |
| 1247 | 1186 |
| 1248 TRACE_IC("KeyedLoadIC", key, state, target()); | 1187 TRACE_IC("KeyedLoadIC", key, state, target()); |
| 1249 | 1188 |
| 1250 // Get the property. | 1189 // Get the property. |
| 1251 return Runtime::GetObjectProperty(isolate(), object, key); | 1190 return Runtime::GetObjectProperty(isolate(), object, key); |
| 1252 } | 1191 } |
| 1253 | 1192 |
| 1254 | 1193 |
| 1255 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, | 1194 void KeyedLoadIC::UpdateLoadCaches(LookupResult* lookup, |
| 1256 State state, | 1195 State state, |
| 1257 Handle<Object> object, | 1196 Handle<Object> object, |
| 1258 Handle<String> name) { | 1197 Handle<String> name) { |
| 1259 // Bail out if we didn't find a result. | 1198 // Bail out if we didn't find a result. |
| 1260 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | 1199 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
| 1261 | 1200 |
| 1262 if (!object->IsJSObject()) return; | 1201 if (!object->IsJSObject()) return; |
| 1263 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1202 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1264 | 1203 |
| 1265 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; | 1204 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; |
| 1266 | 1205 |
| 1267 // Compute the code stub for this load. | 1206 // Compute the code stub for this load. |
| 1268 Handle<Code> code; | 1207 Handle<Code> code; |
| (...skipping 1589 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2858 #undef ADDR | 2797 #undef ADDR |
| 2859 }; | 2798 }; |
| 2860 | 2799 |
| 2861 | 2800 |
| 2862 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2801 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2863 return IC_utilities[id]; | 2802 return IC_utilities[id]; |
| 2864 } | 2803 } |
| 2865 | 2804 |
| 2866 | 2805 |
| 2867 } } // namespace v8::internal | 2806 } } // namespace v8::internal |
| OLD | NEW |