| OLD | NEW |
| 1 // Copyright 2011 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 |
| (...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 571 case kStringCharCodeAt: | 571 case kStringCharCodeAt: |
| 572 case kStringCharAt: | 572 case kStringCharAt: |
| 573 if (object->IsString()) { | 573 if (object->IsString()) { |
| 574 String* string = String::cast(*object); | 574 String* string = String::cast(*object); |
| 575 // Check there's the right string value or wrapper in the receiver slot. | 575 // Check there's the right string value or wrapper in the receiver slot. |
| 576 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value()); | 576 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value()); |
| 577 // If we're in the default (fastest) state and the index is | 577 // If we're in the default (fastest) state and the index is |
| 578 // out of bounds, update the state to record this fact. | 578 // out of bounds, update the state to record this fact. |
| 579 if (StringStubState::decode(*extra_ic_state) == DEFAULT_STRING_STUB && | 579 if (StringStubState::decode(*extra_ic_state) == DEFAULT_STRING_STUB && |
| 580 argc >= 1 && args[1]->IsNumber()) { | 580 argc >= 1 && args[1]->IsNumber()) { |
| 581 double index; | 581 double index = DoubleToInteger(args.number_at(1)); |
| 582 if (args[1]->IsSmi()) { | |
| 583 index = Smi::cast(args[1])->value(); | |
| 584 } else { | |
| 585 ASSERT(args[1]->IsHeapNumber()); | |
| 586 index = DoubleToInteger(HeapNumber::cast(args[1])->value()); | |
| 587 } | |
| 588 if (index < 0 || index >= string->length()) { | 582 if (index < 0 || index >= string->length()) { |
| 589 *extra_ic_state = | 583 *extra_ic_state = |
| 590 StringStubState::update(*extra_ic_state, | 584 StringStubState::update(*extra_ic_state, |
| 591 STRING_INDEX_OUT_OF_BOUNDS); | 585 STRING_INDEX_OUT_OF_BOUNDS); |
| 592 return true; | 586 return true; |
| 593 } | 587 } |
| 594 } | 588 } |
| 595 } | 589 } |
| 596 break; | 590 break; |
| 597 default: | 591 default: |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 792 return CallICBase::LoadFunction(state, | 786 return CallICBase::LoadFunction(state, |
| 793 Code::kNoExtraICState, | 787 Code::kNoExtraICState, |
| 794 object, | 788 object, |
| 795 Handle<String>::cast(key)); | 789 Handle<String>::cast(key)); |
| 796 } | 790 } |
| 797 | 791 |
| 798 if (object->IsUndefined() || object->IsNull()) { | 792 if (object->IsUndefined() || object->IsNull()) { |
| 799 return TypeError("non_object_property_call", object, key); | 793 return TypeError("non_object_property_call", object, key); |
| 800 } | 794 } |
| 801 | 795 |
| 802 if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) { | 796 if (FLAG_use_ic && state != MEGAMORPHIC && object->IsHeapObject()) { |
| 803 int argc = target()->arguments_count(); | 797 int argc = target()->arguments_count(); |
| 804 InLoopFlag in_loop = target()->ic_in_loop(); | 798 InLoopFlag in_loop = target()->ic_in_loop(); |
| 805 MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic( | 799 Heap* heap = Handle<HeapObject>::cast(object)->GetHeap(); |
| 806 argc, in_loop, Code::KEYED_CALL_IC, Code::kNoExtraICState); | 800 Map* map = heap->non_strict_arguments_elements_map(); |
| 807 Object* code; | 801 if (object->IsJSObject() && |
| 808 if (maybe_code->ToObject(&code)) { | 802 Handle<JSObject>::cast(object)->elements()->map() == map) { |
| 809 set_target(Code::cast(code)); | 803 MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallArguments( |
| 804 argc, in_loop, Code::KEYED_CALL_IC); |
| 805 Object* code; |
| 806 if (maybe_code->ToObject(&code)) { |
| 807 set_target(Code::cast(code)); |
| 810 #ifdef DEBUG | 808 #ifdef DEBUG |
| 811 TraceIC( | 809 TraceIC( |
| 812 "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : ""); | 810 "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : ""); |
| 813 #endif | 811 #endif |
| 812 } |
| 813 } else if (FLAG_use_ic && state != MEGAMORPHIC && |
| 814 !object->IsAccessCheckNeeded()) { |
| 815 MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic( |
| 816 argc, in_loop, Code::KEYED_CALL_IC, Code::kNoExtraICState); |
| 817 Object* code; |
| 818 if (maybe_code->ToObject(&code)) { |
| 819 set_target(Code::cast(code)); |
| 820 #ifdef DEBUG |
| 821 TraceIC( |
| 822 "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : ""); |
| 823 #endif |
| 824 } |
| 814 } | 825 } |
| 815 } | 826 } |
| 816 | 827 |
| 817 HandleScope scope(isolate()); | 828 HandleScope scope(isolate()); |
| 818 Handle<Object> result = GetProperty(object, key); | 829 Handle<Object> result = GetProperty(object, key); |
| 819 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 830 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 820 | 831 |
| 821 // Make receiver an object if the callee requires it. Strict mode or builtin | 832 // Make receiver an object if the callee requires it. Strict mode or builtin |
| 822 // functions do not wrap the receiver, non-strict functions and objects | 833 // functions do not wrap the receiver, non-strict functions and objects |
| 823 // called as functions do. | 834 // called as functions do. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 842 MaybeObject* LoadIC::Load(State state, | 853 MaybeObject* LoadIC::Load(State state, |
| 843 Handle<Object> object, | 854 Handle<Object> object, |
| 844 Handle<String> name) { | 855 Handle<String> name) { |
| 845 // If the object is undefined or null it's illegal to try to get any | 856 // If the object is undefined or null it's illegal to try to get any |
| 846 // of its properties; throw a TypeError in that case. | 857 // of its properties; throw a TypeError in that case. |
| 847 if (object->IsUndefined() || object->IsNull()) { | 858 if (object->IsUndefined() || object->IsNull()) { |
| 848 return TypeError("non_object_property_load", object, name); | 859 return TypeError("non_object_property_load", object, name); |
| 849 } | 860 } |
| 850 | 861 |
| 851 if (FLAG_use_ic) { | 862 if (FLAG_use_ic) { |
| 852 Code* non_monomorphic_stub = | |
| 853 (state == UNINITIALIZED) ? pre_monomorphic_stub() : megamorphic_stub(); | |
| 854 | |
| 855 // Use specialized code for getting the length of strings and | 863 // Use specialized code for getting the length of strings and |
| 856 // string wrapper objects. The length property of string wrapper | 864 // string wrapper objects. The length property of string wrapper |
| 857 // objects is read-only and therefore always returns the length of | 865 // objects is read-only and therefore always returns the length of |
| 858 // the underlying string value. See ECMA-262 15.5.5.1. | 866 // the underlying string value. See ECMA-262 15.5.5.1. |
| 859 if ((object->IsString() || object->IsStringWrapper()) && | 867 if ((object->IsString() || object->IsStringWrapper()) && |
| 860 name->Equals(isolate()->heap()->length_symbol())) { | 868 name->Equals(isolate()->heap()->length_symbol())) { |
| 861 HandleScope scope(isolate()); | 869 AssertNoAllocation no_allocation; |
| 862 #ifdef DEBUG | 870 Code* stub = NULL; |
| 863 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); | 871 if (state == UNINITIALIZED) { |
| 864 #endif | 872 stub = pre_monomorphic_stub(); |
| 865 if (state == PREMONOMORPHIC) { | 873 } else if (state == PREMONOMORPHIC) { |
| 866 if (object->IsString()) { | 874 if (object->IsString()) { |
| 867 set_target(isolate()->builtins()->builtin( | 875 stub = isolate()->builtins()->builtin( |
| 868 Builtins::kLoadIC_StringLength)); | 876 Builtins::kLoadIC_StringLength); |
| 869 } else { | 877 } else { |
| 870 set_target(isolate()->builtins()->builtin( | 878 stub = isolate()->builtins()->builtin( |
| 871 Builtins::kLoadIC_StringWrapperLength)); | 879 Builtins::kLoadIC_StringWrapperLength); |
| 872 } | 880 } |
| 873 } else if (state == MONOMORPHIC && object->IsStringWrapper()) { | 881 } else if (state == MONOMORPHIC && object->IsStringWrapper()) { |
| 874 set_target(isolate()->builtins()->builtin( | 882 stub = isolate()->builtins()->builtin( |
| 875 Builtins::kLoadIC_StringWrapperLength)); | 883 Builtins::kLoadIC_StringWrapperLength); |
| 876 } else { | 884 } else if (state != MEGAMORPHIC) { |
| 877 set_target(non_monomorphic_stub); | 885 stub = megamorphic_stub(); |
| 886 } |
| 887 if (stub != NULL) { |
| 888 set_target(stub); |
| 889 #ifdef DEBUG |
| 890 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); |
| 891 #endif |
| 878 } | 892 } |
| 879 // Get the string if we have a string wrapper object. | 893 // Get the string if we have a string wrapper object. |
| 880 if (object->IsJSValue()) { | 894 if (object->IsJSValue()) { |
| 881 object = Handle<Object>(Handle<JSValue>::cast(object)->value(), | 895 return Smi::FromInt( |
| 882 isolate()); | 896 String::cast(Handle<JSValue>::cast(object)->value())->length()); |
| 883 } | 897 } |
| 884 return Smi::FromInt(String::cast(*object)->length()); | 898 return Smi::FromInt(String::cast(*object)->length()); |
| 885 } | 899 } |
| 886 | 900 |
| 887 // Use specialized code for getting the length of arrays. | 901 // Use specialized code for getting the length of arrays. |
| 888 if (object->IsJSArray() && | 902 if (object->IsJSArray() && |
| 889 name->Equals(isolate()->heap()->length_symbol())) { | 903 name->Equals(isolate()->heap()->length_symbol())) { |
| 904 AssertNoAllocation no_allocation; |
| 905 Code* stub = NULL; |
| 906 if (state == UNINITIALIZED) { |
| 907 stub = pre_monomorphic_stub(); |
| 908 } else if (state == PREMONOMORPHIC) { |
| 909 stub = isolate()->builtins()->builtin( |
| 910 Builtins::kLoadIC_ArrayLength); |
| 911 } else if (state != MEGAMORPHIC) { |
| 912 stub = megamorphic_stub(); |
| 913 } |
| 914 if (stub != NULL) { |
| 915 set_target(stub); |
| 890 #ifdef DEBUG | 916 #ifdef DEBUG |
| 891 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); | 917 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); |
| 892 #endif | 918 #endif |
| 893 if (state == PREMONOMORPHIC) { | |
| 894 set_target(isolate()->builtins()->builtin( | |
| 895 Builtins::kLoadIC_ArrayLength)); | |
| 896 } else { | |
| 897 set_target(non_monomorphic_stub); | |
| 898 } | 919 } |
| 899 return JSArray::cast(*object)->length(); | 920 return JSArray::cast(*object)->length(); |
| 900 } | 921 } |
| 901 | 922 |
| 902 // Use specialized code for getting prototype of functions. | 923 // Use specialized code for getting prototype of functions. |
| 903 if (object->IsJSFunction() && | 924 if (object->IsJSFunction() && |
| 904 name->Equals(isolate()->heap()->prototype_symbol()) && | 925 name->Equals(isolate()->heap()->prototype_symbol()) && |
| 905 JSFunction::cast(*object)->should_have_prototype()) { | 926 JSFunction::cast(*object)->should_have_prototype()) { |
| 927 { AssertNoAllocation no_allocation; |
| 928 Code* stub = NULL; |
| 929 if (state == UNINITIALIZED) { |
| 930 stub = pre_monomorphic_stub(); |
| 931 } else if (state == PREMONOMORPHIC) { |
| 932 stub = isolate()->builtins()->builtin( |
| 933 Builtins::kLoadIC_FunctionPrototype); |
| 934 } else if (state != MEGAMORPHIC) { |
| 935 stub = megamorphic_stub(); |
| 936 } |
| 937 if (stub != NULL) { |
| 938 set_target(stub); |
| 906 #ifdef DEBUG | 939 #ifdef DEBUG |
| 907 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); | 940 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); |
| 908 #endif | 941 #endif |
| 909 if (state == PREMONOMORPHIC) { | 942 } |
| 910 set_target(isolate()->builtins()->builtin( | |
| 911 Builtins::kLoadIC_FunctionPrototype)); | |
| 912 } else { | |
| 913 set_target(non_monomorphic_stub); | |
| 914 } | 943 } |
| 915 return Accessors::FunctionGetPrototype(*object, 0); | 944 return Accessors::FunctionGetPrototype(*object, 0); |
| 916 } | 945 } |
| 917 } | 946 } |
| 918 | 947 |
| 919 // Check if the name is trivially convertible to an index and get | 948 // Check if the name is trivially convertible to an index and get |
| 920 // the element if so. | 949 // the element if so. |
| 921 uint32_t index; | 950 uint32_t index; |
| 922 if (name->AsArrayIndex(&index)) return object->GetElement(index); | 951 if (name->AsArrayIndex(&index)) return object->GetElement(index); |
| 923 | 952 |
| 924 // Named lookup in the object. | 953 // Named lookup in the object. |
| 925 LookupResult lookup; | 954 LookupResult lookup; |
| 926 LookupForRead(*object, *name, &lookup); | 955 LookupForRead(*object, *name, &lookup); |
| 927 | 956 |
| 928 // If we did not find a property, check if we need to throw an exception. | 957 // If we did not find a property, check if we need to throw an exception. |
| 929 if (!lookup.IsProperty()) { | 958 if (!lookup.IsProperty()) { |
| 930 if (FLAG_strict || IsContextual(object)) { | 959 if (IsContextual(object)) { |
| 931 return ReferenceError("not_defined", name); | 960 return ReferenceError("not_defined", name); |
| 932 } | 961 } |
| 933 LOG(isolate(), SuspectReadEvent(*name, *object)); | 962 LOG(isolate(), SuspectReadEvent(*name, *object)); |
| 934 } | 963 } |
| 935 | 964 |
| 936 // Update inline cache and stub cache. | 965 // Update inline cache and stub cache. |
| 937 if (FLAG_use_ic) { | 966 if (FLAG_use_ic) { |
| 938 UpdateCaches(&lookup, state, object, name); | 967 UpdateCaches(&lookup, state, object, name); |
| 939 } | 968 } |
| 940 | 969 |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1061 | 1090 |
| 1062 isolate()->stub_cache()->Set(*name, map, Code::cast(code)); | 1091 isolate()->stub_cache()->Set(*name, map, Code::cast(code)); |
| 1063 } | 1092 } |
| 1064 | 1093 |
| 1065 #ifdef DEBUG | 1094 #ifdef DEBUG |
| 1066 TraceIC("LoadIC", name, state, target()); | 1095 TraceIC("LoadIC", name, state, target()); |
| 1067 #endif | 1096 #endif |
| 1068 } | 1097 } |
| 1069 | 1098 |
| 1070 | 1099 |
| 1071 String* KeyedLoadIC::GetStubNameForCache(IC::State ic_state) { | 1100 MaybeObject* KeyedLoadIC::GetElementStubWithoutMapCheck( |
| 1072 if (ic_state == MONOMORPHIC) { | 1101 bool is_js_array, |
| 1073 return isolate()->heap()->KeyedLoadSpecializedMonomorphic_symbol(); | 1102 JSObject::ElementsKind elements_kind) { |
| 1074 } else { | 1103 return KeyedLoadElementStub(elements_kind).TryGetCode(); |
| 1075 ASSERT(ic_state == MEGAMORPHIC); | |
| 1076 return isolate()->heap()->KeyedLoadSpecializedPolymorphic_symbol(); | |
| 1077 } | |
| 1078 } | |
| 1079 | |
| 1080 | |
| 1081 MaybeObject* KeyedLoadIC::GetFastElementStubWithoutMapCheck( | |
| 1082 bool is_js_array) { | |
| 1083 return KeyedLoadFastElementStub().TryGetCode(); | |
| 1084 } | |
| 1085 | |
| 1086 | |
| 1087 MaybeObject* KeyedLoadIC::GetExternalArrayStubWithoutMapCheck( | |
| 1088 ExternalArrayType array_type) { | |
| 1089 return KeyedLoadExternalArrayStub(array_type).TryGetCode(); | |
| 1090 } | 1104 } |
| 1091 | 1105 |
| 1092 | 1106 |
| 1093 MaybeObject* KeyedLoadIC::ConstructMegamorphicStub( | 1107 MaybeObject* KeyedLoadIC::ConstructMegamorphicStub( |
| 1094 MapList* receiver_maps, | 1108 MapList* receiver_maps, |
| 1095 CodeList* targets, | 1109 CodeList* targets, |
| 1096 StrictModeFlag strict_mode) { | 1110 StrictModeFlag strict_mode) { |
| 1097 Object* object; | 1111 Object* object; |
| 1098 KeyedLoadStubCompiler compiler; | 1112 KeyedLoadStubCompiler compiler; |
| 1099 MaybeObject* maybe_code = compiler.CompileLoadMegamorphic(receiver_maps, | 1113 MaybeObject* maybe_code = compiler.CompileLoadMegamorphic(receiver_maps, |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1194 // Rewrite to the generic keyed load stub. | 1208 // Rewrite to the generic keyed load stub. |
| 1195 if (FLAG_use_ic) set_target(generic_stub()); | 1209 if (FLAG_use_ic) set_target(generic_stub()); |
| 1196 return Runtime::GetElementOrCharAt(isolate(), object, index); | 1210 return Runtime::GetElementOrCharAt(isolate(), object, index); |
| 1197 } | 1211 } |
| 1198 | 1212 |
| 1199 // Named lookup. | 1213 // Named lookup. |
| 1200 LookupResult lookup; | 1214 LookupResult lookup; |
| 1201 LookupForRead(*object, *name, &lookup); | 1215 LookupForRead(*object, *name, &lookup); |
| 1202 | 1216 |
| 1203 // If we did not find a property, check if we need to throw an exception. | 1217 // If we did not find a property, check if we need to throw an exception. |
| 1204 if (!lookup.IsProperty()) { | 1218 if (!lookup.IsProperty() && IsContextual(object)) { |
| 1205 if (FLAG_strict || IsContextual(object)) { | 1219 return ReferenceError("not_defined", name); |
| 1206 return ReferenceError("not_defined", name); | |
| 1207 } | |
| 1208 } | 1220 } |
| 1209 | 1221 |
| 1210 if (FLAG_use_ic) { | 1222 if (FLAG_use_ic) { |
| 1211 UpdateCaches(&lookup, state, object, name); | 1223 UpdateCaches(&lookup, state, object, name); |
| 1212 } | 1224 } |
| 1213 | 1225 |
| 1214 PropertyAttributes attr; | 1226 PropertyAttributes attr; |
| 1215 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) { | 1227 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) { |
| 1216 // Get the property. | 1228 // Get the property. |
| 1217 Object* result; | 1229 Object* result; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1236 | 1248 |
| 1237 if (use_ic) { | 1249 if (use_ic) { |
| 1238 Code* stub = generic_stub(); | 1250 Code* stub = generic_stub(); |
| 1239 if (!force_generic_stub) { | 1251 if (!force_generic_stub) { |
| 1240 if (object->IsString() && key->IsNumber()) { | 1252 if (object->IsString() && key->IsNumber()) { |
| 1241 if (state == UNINITIALIZED) { | 1253 if (state == UNINITIALIZED) { |
| 1242 stub = string_stub(); | 1254 stub = string_stub(); |
| 1243 } | 1255 } |
| 1244 } else if (object->IsJSObject()) { | 1256 } else if (object->IsJSObject()) { |
| 1245 JSObject* receiver = JSObject::cast(*object); | 1257 JSObject* receiver = JSObject::cast(*object); |
| 1246 if (receiver->HasIndexedInterceptor()) { | 1258 Heap* heap = Handle<JSObject>::cast(object)->GetHeap(); |
| 1259 Map* elements_map = Handle<JSObject>::cast(object)->elements()->map(); |
| 1260 if (elements_map == heap->non_strict_arguments_elements_map()) { |
| 1261 stub = non_strict_arguments_stub(); |
| 1262 } else if (receiver->HasIndexedInterceptor()) { |
| 1247 stub = indexed_interceptor_stub(); | 1263 stub = indexed_interceptor_stub(); |
| 1248 } else if (key->IsSmi()) { | 1264 } else if (key->IsSmi() && (target() != non_strict_arguments_stub())) { |
| 1249 MaybeObject* maybe_stub = ComputeStub(receiver, | 1265 MaybeObject* maybe_stub = ComputeStub(receiver, |
| 1250 false, | 1266 false, |
| 1251 kNonStrictMode, | 1267 kNonStrictMode, |
| 1252 stub); | 1268 stub); |
| 1253 stub = maybe_stub->IsFailure() ? | 1269 stub = maybe_stub->IsFailure() ? |
| 1254 NULL : Code::cast(maybe_stub->ToObjectUnchecked()); | 1270 NULL : Code::cast(maybe_stub->ToObjectUnchecked()); |
| 1255 } | 1271 } |
| 1256 } | 1272 } |
| 1257 } | 1273 } |
| 1258 if (stub != NULL) set_target(stub); | 1274 if (stub != NULL) set_target(stub); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1348 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return false; | 1364 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return false; |
| 1349 | 1365 |
| 1350 // If the property is read-only, we leave the IC in its current | 1366 // If the property is read-only, we leave the IC in its current |
| 1351 // state. | 1367 // state. |
| 1352 if (lookup->IsReadOnly()) return false; | 1368 if (lookup->IsReadOnly()) return false; |
| 1353 | 1369 |
| 1354 return true; | 1370 return true; |
| 1355 } | 1371 } |
| 1356 | 1372 |
| 1357 | 1373 |
| 1358 static bool LookupForWrite(JSObject* object, | 1374 static bool LookupForWrite(JSReceiver* receiver, |
| 1359 String* name, | 1375 String* name, |
| 1360 LookupResult* lookup) { | 1376 LookupResult* lookup) { |
| 1361 object->LocalLookup(name, lookup); | 1377 receiver->LocalLookup(name, lookup); |
| 1362 if (!StoreICableLookup(lookup)) { | 1378 if (!StoreICableLookup(lookup)) { |
| 1363 return false; | 1379 return false; |
| 1364 } | 1380 } |
| 1365 | 1381 |
| 1366 if (lookup->type() == INTERCEPTOR) { | 1382 if (lookup->type() == INTERCEPTOR) { |
| 1383 JSObject* object = JSObject::cast(receiver); |
| 1367 if (object->GetNamedInterceptor()->setter()->IsUndefined()) { | 1384 if (object->GetNamedInterceptor()->setter()->IsUndefined()) { |
| 1368 object->LocalLookupRealNamedProperty(name, lookup); | 1385 object->LocalLookupRealNamedProperty(name, lookup); |
| 1369 return StoreICableLookup(lookup); | 1386 return StoreICableLookup(lookup); |
| 1370 } | 1387 } |
| 1371 } | 1388 } |
| 1372 | 1389 |
| 1373 return true; | 1390 return true; |
| 1374 } | 1391 } |
| 1375 | 1392 |
| 1376 | 1393 |
| 1377 MaybeObject* StoreIC::Store(State state, | 1394 MaybeObject* StoreIC::Store(State state, |
| 1378 StrictModeFlag strict_mode, | 1395 StrictModeFlag strict_mode, |
| 1379 Handle<Object> object, | 1396 Handle<Object> object, |
| 1380 Handle<String> name, | 1397 Handle<String> name, |
| 1381 Handle<Object> value) { | 1398 Handle<Object> value) { |
| 1382 // If the object is undefined or null it's illegal to try to set any | 1399 // If the object is undefined or null it's illegal to try to set any |
| 1383 // properties on it; throw a TypeError in that case. | 1400 // properties on it; throw a TypeError in that case. |
| 1384 if (object->IsUndefined() || object->IsNull()) { | 1401 if (object->IsUndefined() || object->IsNull()) { |
| 1385 return TypeError("non_object_property_store", object, name); | 1402 return TypeError("non_object_property_store", object, name); |
| 1386 } | 1403 } |
| 1387 | 1404 |
| 1388 if (!object->IsJSObject()) { | 1405 if (!object->IsJSReceiver()) { |
| 1389 // The length property of string values is read-only. Throw in strict mode. | 1406 // The length property of string values is read-only. Throw in strict mode. |
| 1390 if (strict_mode == kStrictMode && object->IsString() && | 1407 if (strict_mode == kStrictMode && object->IsString() && |
| 1391 name->Equals(isolate()->heap()->length_symbol())) { | 1408 name->Equals(isolate()->heap()->length_symbol())) { |
| 1392 return TypeError("strict_read_only_property", object, name); | 1409 return TypeError("strict_read_only_property", object, name); |
| 1393 } | 1410 } |
| 1394 // Ignore stores where the receiver is not a JSObject. | 1411 // Ignore stores where the receiver is not a JSObject. |
| 1395 return *value; | 1412 return *value; |
| 1396 } | 1413 } |
| 1397 | 1414 |
| 1415 // Handle proxies. |
| 1416 if (object->IsJSProxy()) { |
| 1417 return JSReceiver::cast(*object)-> |
| 1418 SetProperty(*name, *value, NONE, strict_mode); |
| 1419 } |
| 1420 |
| 1398 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1421 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1399 | 1422 |
| 1400 // Check if the given name is an array index. | 1423 // Check if the given name is an array index. |
| 1401 uint32_t index; | 1424 uint32_t index; |
| 1402 if (name->AsArrayIndex(&index)) { | 1425 if (name->AsArrayIndex(&index)) { |
| 1403 HandleScope scope(isolate()); | 1426 HandleScope scope(isolate()); |
| 1404 Handle<Object> result = SetElement(receiver, index, value, strict_mode); | 1427 Handle<Object> result = SetElement(receiver, index, value, strict_mode); |
| 1405 if (result.is_null()) return Failure::Exception(); | 1428 if (result.is_null()) return Failure::Exception(); |
| 1406 return *value; | 1429 return *value; |
| 1407 } | 1430 } |
| 1408 | 1431 |
| 1409 // Use specialized code for setting the length of arrays. | 1432 // Use specialized code for setting the length of arrays. |
| 1410 if (receiver->IsJSArray() | 1433 if (receiver->IsJSArray() |
| 1411 && name->Equals(isolate()->heap()->length_symbol()) | 1434 && name->Equals(isolate()->heap()->length_symbol()) |
| 1412 && receiver->AllowsSetElementsLength()) { | 1435 && JSArray::cast(*receiver)->AllowsSetElementsLength()) { |
| 1413 #ifdef DEBUG | 1436 #ifdef DEBUG |
| 1414 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); | 1437 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); |
| 1415 #endif | 1438 #endif |
| 1416 Builtins::Name target = (strict_mode == kStrictMode) | 1439 Builtins::Name target = (strict_mode == kStrictMode) |
| 1417 ? Builtins::kStoreIC_ArrayLength_Strict | 1440 ? Builtins::kStoreIC_ArrayLength_Strict |
| 1418 : Builtins::kStoreIC_ArrayLength; | 1441 : Builtins::kStoreIC_ArrayLength; |
| 1419 set_target(isolate()->builtins()->builtin(target)); | 1442 set_target(isolate()->builtins()->builtin(target)); |
| 1420 return receiver->SetProperty(*name, *value, NONE, strict_mode); | 1443 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1421 } | 1444 } |
| 1422 | 1445 |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1589 } | 1612 } |
| 1590 } | 1613 } |
| 1591 } | 1614 } |
| 1592 | 1615 |
| 1593 | 1616 |
| 1594 MaybeObject* KeyedIC::ComputeStub(JSObject* receiver, | 1617 MaybeObject* KeyedIC::ComputeStub(JSObject* receiver, |
| 1595 bool is_store, | 1618 bool is_store, |
| 1596 StrictModeFlag strict_mode, | 1619 StrictModeFlag strict_mode, |
| 1597 Code* generic_stub) { | 1620 Code* generic_stub) { |
| 1598 State ic_state = target()->ic_state(); | 1621 State ic_state = target()->ic_state(); |
| 1599 Code* monomorphic_stub; | 1622 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { |
| 1600 // Always compute the MONOMORPHIC stub, even if the MEGAMORPHIC stub ends up | 1623 Code* monomorphic_stub; |
| 1601 // being used. This is necessary because the megamorphic stub needs to have | 1624 MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver, |
| 1602 // access to more information than what is stored in the receiver map in some | 1625 is_store, |
| 1603 // cases (external arrays need the array type from the MONOMORPHIC stub). | 1626 strict_mode, |
| 1604 MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver, | 1627 generic_stub); |
| 1605 is_store, | 1628 if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub; |
| 1606 strict_mode, | |
| 1607 generic_stub); | |
| 1608 if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub; | |
| 1609 | 1629 |
| 1610 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { | |
| 1611 return monomorphic_stub; | 1630 return monomorphic_stub; |
| 1612 } | 1631 } |
| 1613 ASSERT(target() != generic_stub); | 1632 ASSERT(target() != generic_stub); |
| 1614 | 1633 |
| 1615 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS | 1634 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS |
| 1616 // via megamorphic stubs, since they don't have a map in their relocation info | 1635 // via megamorphic stubs, since they don't have a map in their relocation info |
| 1617 // and so the stubs can't be harvested for the object needed for a map check. | 1636 // and so the stubs can't be harvested for the object needed for a map check. |
| 1618 if (target()->type() != NORMAL) { | 1637 if (target()->type() != NORMAL) { |
| 1619 return generic_stub; | 1638 return generic_stub; |
| 1620 } | 1639 } |
| 1621 | 1640 |
| 1622 // Determine the list of receiver maps that this call site has seen, | 1641 // Determine the list of receiver maps that this call site has seen, |
| 1623 // adding the map that was just encountered. | 1642 // adding the map that was just encountered. |
| 1624 MapList target_receiver_maps; | 1643 MapList target_receiver_maps; |
| 1625 GetReceiverMapsForStub(target(), &target_receiver_maps); | 1644 GetReceiverMapsForStub(target(), &target_receiver_maps); |
| 1626 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map())) { | 1645 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map())) { |
| 1627 // If the miss wasn't due to an unseen map, a MEGAMORPHIC stub | 1646 // If the miss wasn't due to an unseen map, a MEGAMORPHIC stub |
| 1628 // won't help, use the generic stub. | 1647 // won't help, use the generic stub. |
| 1629 return generic_stub; | 1648 return generic_stub; |
| 1630 } | 1649 } |
| 1631 | 1650 |
| 1632 // TODO(1385): Currently MEGAMORPHIC stubs are cached in the receiver map stub | 1651 // If the maximum number of receiver maps has been exceeded, use the generic |
| 1633 // cache, but that can put receiver types together from unrelated call sites | 1652 // version of the IC. |
| 1634 // into the same stub--they always handle the union of all receiver maps seen | 1653 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { |
| 1635 // at all call sites involving the receiver map. This is only an | 1654 return generic_stub; |
| 1636 // approximation: ideally, there would be a global cache that mapped sets of | 1655 } |
| 1637 // receiver maps to MEGAMORPHIC stubs. The complexity of the MEGAMORPHIC stub | 1656 |
| 1638 // computation also leads to direct manipulation of the stub cache from the IC | 1657 PolymorphicCodeCache* cache = isolate()->heap()->polymorphic_code_cache(); |
| 1639 // code, which the global cache solution would avoid. | 1658 Code::Flags flags = Code::ComputeFlags(this->kind(), |
| 1640 Code::Kind kind = this->kind(); | |
| 1641 Code::Flags flags = Code::ComputeFlags(kind, | |
| 1642 NOT_IN_LOOP, | 1659 NOT_IN_LOOP, |
| 1643 MEGAMORPHIC, | 1660 MEGAMORPHIC, |
| 1644 strict_mode); | 1661 strict_mode); |
| 1645 String* megamorphic_name = GetStubNameForCache(MEGAMORPHIC); | 1662 Object* maybe_cached_stub = cache->Lookup(&target_receiver_maps, flags); |
| 1646 Object* maybe_cached_stub = receiver->map()->FindInCodeCache(megamorphic_name, | 1663 // If there is a cached stub, use it. |
| 1647 flags); | |
| 1648 | |
| 1649 // Create a set of all receiver maps that have been seen at the IC call site | |
| 1650 // and those seen by the MEGAMORPHIC cached stub, if that's the stub that's | |
| 1651 // been selected. | |
| 1652 MapList receiver_maps; | |
| 1653 if (!maybe_cached_stub->IsUndefined()) { | 1664 if (!maybe_cached_stub->IsUndefined()) { |
| 1654 GetReceiverMapsForStub(Code::cast(maybe_cached_stub), &receiver_maps); | |
| 1655 } | |
| 1656 bool added_map = false; | |
| 1657 for (int i = 0; i < target_receiver_maps.length(); ++i) { | |
| 1658 if (AddOneReceiverMapIfMissing(&receiver_maps, | |
| 1659 target_receiver_maps.at(i))) { | |
| 1660 added_map = true; | |
| 1661 } | |
| 1662 } | |
| 1663 ASSERT(receiver_maps.length() > 0); | |
| 1664 | |
| 1665 // If the maximum number of receiver maps has been exceeded, use the Generic | |
| 1666 // version of the IC. | |
| 1667 if (receiver_maps.length() > KeyedIC::kMaxKeyedPolymorphism) { | |
| 1668 return generic_stub; | |
| 1669 } | |
| 1670 | |
| 1671 // If no maps have been seen at the call site that aren't in the cached | |
| 1672 // stub, then use it. | |
| 1673 if (!added_map) { | |
| 1674 ASSERT(!maybe_cached_stub->IsUndefined()); | |
| 1675 ASSERT(maybe_cached_stub->IsCode()); | 1665 ASSERT(maybe_cached_stub->IsCode()); |
| 1676 return Code::cast(maybe_cached_stub); | 1666 return Code::cast(maybe_cached_stub); |
| 1677 } | 1667 } |
| 1678 | 1668 // Collect MONOMORPHIC stubs for all target_receiver_maps. |
| 1679 // Lookup all of the receiver maps in the cache, they should all already | 1669 CodeList handler_ics(target_receiver_maps.length()); |
| 1680 // have MONOMORPHIC stubs. | 1670 for (int i = 0; i < target_receiver_maps.length(); ++i) { |
| 1681 CodeList handler_ics(KeyedIC::kMaxKeyedPolymorphism); | 1671 Map* receiver_map(target_receiver_maps.at(i)); |
| 1682 for (int current = 0; current < receiver_maps.length(); ++current) { | |
| 1683 Map* receiver_map(receiver_maps.at(current)); | |
| 1684 MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck( | 1672 MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck( |
| 1685 receiver_map, | 1673 receiver_map, strict_mode); |
| 1686 strict_mode, | |
| 1687 generic_stub); | |
| 1688 Code* cached_stub; | 1674 Code* cached_stub; |
| 1689 if (!maybe_cached_stub->To(&cached_stub)) { | 1675 if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub; |
| 1690 return maybe_cached_stub; | |
| 1691 } | |
| 1692 handler_ics.Add(cached_stub); | 1676 handler_ics.Add(cached_stub); |
| 1693 } | 1677 } |
| 1694 | 1678 // Build the MEGAMORPHIC stub. |
| 1695 Code* stub; | 1679 Code* stub; |
| 1696 // Build the MEGAMORPHIC stub. | 1680 MaybeObject* maybe_stub = ConstructMegamorphicStub(&target_receiver_maps, |
| 1697 maybe_stub = ConstructMegamorphicStub(&receiver_maps, | 1681 &handler_ics, |
| 1698 &handler_ics, | 1682 strict_mode); |
| 1699 strict_mode); | |
| 1700 if (!maybe_stub->To(&stub)) return maybe_stub; | 1683 if (!maybe_stub->To(&stub)) return maybe_stub; |
| 1701 | 1684 MaybeObject* maybe_update = cache->Update(&target_receiver_maps, flags, stub); |
| 1702 MaybeObject* maybe_update = receiver->UpdateMapCodeCache( | |
| 1703 megamorphic_name, | |
| 1704 stub); | |
| 1705 if (maybe_update->IsFailure()) return maybe_update; | 1685 if (maybe_update->IsFailure()) return maybe_update; |
| 1706 return stub; | 1686 return stub; |
| 1707 } | 1687 } |
| 1708 | 1688 |
| 1709 | 1689 |
| 1710 MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck( | 1690 MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck( |
| 1711 Map* receiver_map, | 1691 Map* receiver_map, |
| 1712 StrictModeFlag strict_mode, | 1692 StrictModeFlag strict_mode) { |
| 1713 Code* generic_stub) { | |
| 1714 if ((receiver_map->instance_type() & kNotStringTag) == 0) { | 1693 if ((receiver_map->instance_type() & kNotStringTag) == 0) { |
| 1715 ASSERT(string_stub() != NULL); | 1694 ASSERT(string_stub() != NULL); |
| 1716 return string_stub(); | 1695 return string_stub(); |
| 1717 } else if (receiver_map->has_external_array_elements()) { | 1696 } else { |
| 1718 // Determine the array type from the default MONOMORPHIC already generated | 1697 ASSERT(receiver_map->has_dictionary_elements() || |
| 1719 // stub. There is no other way to determine the type of the external array | 1698 receiver_map->has_fast_elements() || |
| 1720 // directly from the receiver type. | 1699 receiver_map->has_fast_double_elements() || |
| 1721 Code::Kind kind = this->kind(); | 1700 receiver_map->has_external_array_elements()); |
| 1722 Code::Flags flags = Code::ComputeMonomorphicFlags(kind, | |
| 1723 NORMAL, | |
| 1724 strict_mode); | |
| 1725 String* monomorphic_name = GetStubNameForCache(MONOMORPHIC); | |
| 1726 Object* maybe_default_stub = receiver_map->FindInCodeCache(monomorphic_name, | |
| 1727 flags); | |
| 1728 if (maybe_default_stub->IsUndefined()) { | |
| 1729 return generic_stub; | |
| 1730 } | |
| 1731 Code* default_stub = Code::cast(maybe_default_stub); | |
| 1732 return GetExternalArrayStubWithoutMapCheck( | |
| 1733 default_stub->external_array_type()); | |
| 1734 } else if (receiver_map->has_fast_elements()) { | |
| 1735 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; | 1701 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; |
| 1736 return GetFastElementStubWithoutMapCheck(is_js_array); | 1702 return GetElementStubWithoutMapCheck(is_js_array, |
| 1737 } else { | 1703 receiver_map->elements_kind()); |
| 1738 return generic_stub; | |
| 1739 } | 1704 } |
| 1740 } | 1705 } |
| 1741 | 1706 |
| 1742 | 1707 |
| 1743 MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver, | 1708 MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver, |
| 1744 bool is_store, | 1709 bool is_store, |
| 1745 StrictModeFlag strict_mode, | 1710 StrictModeFlag strict_mode, |
| 1746 Code* generic_stub) { | 1711 Code* generic_stub) { |
| 1747 Code* result = NULL; | 1712 Code* result = NULL; |
| 1748 if (receiver->HasExternalArrayElements()) { | 1713 if (receiver->HasFastElements() || |
| 1714 receiver->HasExternalArrayElements() || |
| 1715 receiver->HasFastDoubleElements() || |
| 1716 receiver->HasDictionaryElements()) { |
| 1749 MaybeObject* maybe_stub = | 1717 MaybeObject* maybe_stub = |
| 1750 isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray( | 1718 isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement( |
| 1751 receiver, is_store, strict_mode); | |
| 1752 if (!maybe_stub->To(&result)) return maybe_stub; | |
| 1753 } else if (receiver->map()->has_fast_elements()) { | |
| 1754 MaybeObject* maybe_stub = | |
| 1755 isolate()->stub_cache()->ComputeKeyedLoadOrStoreFastElement( | |
| 1756 receiver, is_store, strict_mode); | 1719 receiver, is_store, strict_mode); |
| 1757 if (!maybe_stub->To(&result)) return maybe_stub; | 1720 if (!maybe_stub->To(&result)) return maybe_stub; |
| 1758 } else { | 1721 } else { |
| 1759 result = generic_stub; | 1722 result = generic_stub; |
| 1760 } | 1723 } |
| 1761 return result; | 1724 return result; |
| 1762 } | 1725 } |
| 1763 | 1726 |
| 1764 | 1727 |
| 1765 String* KeyedStoreIC::GetStubNameForCache(IC::State ic_state) { | 1728 MaybeObject* KeyedStoreIC::GetElementStubWithoutMapCheck( |
| 1766 if (ic_state == MONOMORPHIC) { | 1729 bool is_js_array, |
| 1767 return isolate()->heap()->KeyedStoreSpecializedMonomorphic_symbol(); | 1730 JSObject::ElementsKind elements_kind) { |
| 1768 } else { | 1731 return KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode(); |
| 1769 ASSERT(ic_state == MEGAMORPHIC); | |
| 1770 return isolate()->heap()->KeyedStoreSpecializedPolymorphic_symbol(); | |
| 1771 } | |
| 1772 } | |
| 1773 | |
| 1774 | |
| 1775 MaybeObject* KeyedStoreIC::GetFastElementStubWithoutMapCheck( | |
| 1776 bool is_js_array) { | |
| 1777 return KeyedStoreFastElementStub(is_js_array).TryGetCode(); | |
| 1778 } | |
| 1779 | |
| 1780 | |
| 1781 MaybeObject* KeyedStoreIC::GetExternalArrayStubWithoutMapCheck( | |
| 1782 ExternalArrayType array_type) { | |
| 1783 return KeyedStoreExternalArrayStub(array_type).TryGetCode(); | |
| 1784 } | 1732 } |
| 1785 | 1733 |
| 1786 | 1734 |
| 1787 MaybeObject* KeyedStoreIC::ConstructMegamorphicStub( | 1735 MaybeObject* KeyedStoreIC::ConstructMegamorphicStub( |
| 1788 MapList* receiver_maps, | 1736 MapList* receiver_maps, |
| 1789 CodeList* targets, | 1737 CodeList* targets, |
| 1790 StrictModeFlag strict_mode) { | 1738 StrictModeFlag strict_mode) { |
| 1791 Object* object; | 1739 Object* object; |
| 1792 KeyedStoreStubCompiler compiler(strict_mode); | 1740 KeyedStoreStubCompiler compiler(strict_mode); |
| 1793 MaybeObject* maybe_code = compiler.CompileStoreMegamorphic(receiver_maps, | 1741 MaybeObject* maybe_code = compiler.CompileStoreMegamorphic(receiver_maps, |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1844 | 1792 |
| 1845 // Do not use ICs for objects that require access checks (including | 1793 // Do not use ICs for objects that require access checks (including |
| 1846 // the global object). | 1794 // the global object). |
| 1847 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1795 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
| 1848 ASSERT(!(use_ic && object->IsJSGlobalProxy())); | 1796 ASSERT(!(use_ic && object->IsJSGlobalProxy())); |
| 1849 | 1797 |
| 1850 if (use_ic) { | 1798 if (use_ic) { |
| 1851 Code* stub = (strict_mode == kStrictMode) | 1799 Code* stub = (strict_mode == kStrictMode) |
| 1852 ? generic_stub_strict() | 1800 ? generic_stub_strict() |
| 1853 : generic_stub(); | 1801 : generic_stub(); |
| 1854 if (!force_generic) { | 1802 if (object->IsJSObject()) { |
| 1855 if (object->IsJSObject() && key->IsSmi()) { | 1803 JSObject* receiver = JSObject::cast(*object); |
| 1856 JSObject* receiver = JSObject::cast(*object); | 1804 Heap* heap = Handle<JSObject>::cast(object)->GetHeap(); |
| 1857 MaybeObject* maybe_stub = ComputeStub(receiver, | 1805 Map* elements_map = Handle<JSObject>::cast(object)->elements()->map(); |
| 1858 true, | 1806 if (elements_map == heap->non_strict_arguments_elements_map()) { |
| 1859 strict_mode, | 1807 stub = non_strict_arguments_stub(); |
| 1860 stub); | 1808 } else if (!force_generic) { |
| 1861 stub = maybe_stub->IsFailure() ? | 1809 if (key->IsSmi() && (target() != non_strict_arguments_stub())) { |
| 1862 NULL : Code::cast(maybe_stub->ToObjectUnchecked()); | 1810 HandleScope scope(isolate()); |
| 1811 MaybeObject* maybe_stub = ComputeStub(receiver, |
| 1812 true, |
| 1813 strict_mode, |
| 1814 stub); |
| 1815 stub = maybe_stub->IsFailure() ? |
| 1816 NULL : Code::cast(maybe_stub->ToObjectUnchecked()); |
| 1817 } |
| 1863 } | 1818 } |
| 1864 } | 1819 } |
| 1865 if (stub != NULL) set_target(stub); | 1820 if (stub != NULL) set_target(stub); |
| 1866 } | 1821 } |
| 1867 | 1822 |
| 1868 #ifdef DEBUG | 1823 #ifdef DEBUG |
| 1869 TraceIC("KeyedStoreIC", key, state, target()); | 1824 TraceIC("KeyedStoreIC", key, state, target()); |
| 1870 #endif | 1825 #endif |
| 1871 | 1826 |
| 1872 // Set the property. | 1827 // Set the property. |
| (...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2318 } | 2273 } |
| 2319 | 2274 |
| 2320 // Check for oddball objects. | 2275 // Check for oddball objects. |
| 2321 if (left->IsUndefined() && right->IsNumber()) return ODDBALL; | 2276 if (left->IsUndefined() && right->IsNumber()) return ODDBALL; |
| 2322 if (left->IsNumber() && right->IsUndefined()) return ODDBALL; | 2277 if (left->IsNumber() && right->IsUndefined()) return ODDBALL; |
| 2323 | 2278 |
| 2324 return GENERIC; | 2279 return GENERIC; |
| 2325 } | 2280 } |
| 2326 | 2281 |
| 2327 | 2282 |
| 2328 // defined in code-stubs-<arch>.cc | |
| 2329 // Only needed to remove dependency of ic.cc on code-stubs-<arch>.h. | |
| 2330 Handle<Code> GetUnaryOpStub(int key, UnaryOpIC::TypeInfo type_info); | |
| 2331 | |
| 2332 | |
| 2333 RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) { | 2283 RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) { |
| 2334 ASSERT(args.length() == 4); | 2284 ASSERT(args.length() == 4); |
| 2335 | 2285 |
| 2336 HandleScope scope(isolate); | 2286 HandleScope scope(isolate); |
| 2337 Handle<Object> operand = args.at<Object>(0); | 2287 Handle<Object> operand = args.at<Object>(0); |
| 2338 int key = Smi::cast(args[1])->value(); | 2288 Token::Value op = static_cast<Token::Value>(args.smi_at(1)); |
| 2339 Token::Value op = static_cast<Token::Value>(Smi::cast(args[2])->value()); | 2289 UnaryOverwriteMode mode = static_cast<UnaryOverwriteMode>(args.smi_at(2)); |
| 2340 UnaryOpIC::TypeInfo previous_type = | 2290 UnaryOpIC::TypeInfo previous_type = |
| 2341 static_cast<UnaryOpIC::TypeInfo>(Smi::cast(args[3])->value()); | 2291 static_cast<UnaryOpIC::TypeInfo>(args.smi_at(3)); |
| 2342 | 2292 |
| 2343 UnaryOpIC::TypeInfo type = UnaryOpIC::GetTypeInfo(operand); | 2293 UnaryOpIC::TypeInfo type = UnaryOpIC::GetTypeInfo(operand); |
| 2344 type = UnaryOpIC::ComputeNewType(type, previous_type); | 2294 type = UnaryOpIC::ComputeNewType(type, previous_type); |
| 2345 | 2295 |
| 2346 Handle<Code> code = GetUnaryOpStub(key, type); | 2296 UnaryOpStub stub(op, mode, type); |
| 2297 Handle<Code> code = stub.GetCode(); |
| 2347 if (!code.is_null()) { | 2298 if (!code.is_null()) { |
| 2348 if (FLAG_trace_ic) { | 2299 if (FLAG_trace_ic) { |
| 2349 PrintF("[UnaryOpIC (%s->%s)#%s]\n", | 2300 PrintF("[UnaryOpIC (%s->%s)#%s]\n", |
| 2350 UnaryOpIC::GetName(previous_type), | 2301 UnaryOpIC::GetName(previous_type), |
| 2351 UnaryOpIC::GetName(type), | 2302 UnaryOpIC::GetName(type), |
| 2352 Token::Name(op)); | 2303 Token::Name(op)); |
| 2353 } | 2304 } |
| 2354 UnaryOpIC ic(isolate); | 2305 UnaryOpIC ic(isolate); |
| 2355 ic.patch(*code); | 2306 ic.patch(*code); |
| 2356 } | 2307 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2373 | 2324 |
| 2374 bool caught_exception; | 2325 bool caught_exception; |
| 2375 Handle<Object> result = Execution::Call(builtin_function, operand, 0, NULL, | 2326 Handle<Object> result = Execution::Call(builtin_function, operand, 0, NULL, |
| 2376 &caught_exception); | 2327 &caught_exception); |
| 2377 if (caught_exception) { | 2328 if (caught_exception) { |
| 2378 return Failure::Exception(); | 2329 return Failure::Exception(); |
| 2379 } | 2330 } |
| 2380 return *result; | 2331 return *result; |
| 2381 } | 2332 } |
| 2382 | 2333 |
| 2383 // defined in code-stubs-<arch>.cc | |
| 2384 // Only needed to remove dependency of ic.cc on code-stubs-<arch>.h. | |
| 2385 Handle<Code> GetBinaryOpStub(int key, | |
| 2386 BinaryOpIC::TypeInfo type_info, | |
| 2387 BinaryOpIC::TypeInfo result_type); | |
| 2388 | |
| 2389 | |
| 2390 RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { | 2334 RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { |
| 2391 ASSERT(args.length() == 5); | 2335 ASSERT(args.length() == 5); |
| 2392 | 2336 |
| 2393 HandleScope scope(isolate); | 2337 HandleScope scope(isolate); |
| 2394 Handle<Object> left = args.at<Object>(0); | 2338 Handle<Object> left = args.at<Object>(0); |
| 2395 Handle<Object> right = args.at<Object>(1); | 2339 Handle<Object> right = args.at<Object>(1); |
| 2396 int key = Smi::cast(args[2])->value(); | 2340 int key = args.smi_at(2); |
| 2397 Token::Value op = static_cast<Token::Value>(Smi::cast(args[3])->value()); | 2341 Token::Value op = static_cast<Token::Value>(args.smi_at(3)); |
| 2398 BinaryOpIC::TypeInfo previous_type = | 2342 BinaryOpIC::TypeInfo previous_type = |
| 2399 static_cast<BinaryOpIC::TypeInfo>(Smi::cast(args[4])->value()); | 2343 static_cast<BinaryOpIC::TypeInfo>(args.smi_at(4)); |
| 2400 | 2344 |
| 2401 BinaryOpIC::TypeInfo type = BinaryOpIC::GetTypeInfo(left, right); | 2345 BinaryOpIC::TypeInfo type = BinaryOpIC::GetTypeInfo(left, right); |
| 2402 type = BinaryOpIC::JoinTypes(type, previous_type); | 2346 type = BinaryOpIC::JoinTypes(type, previous_type); |
| 2403 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED; | 2347 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED; |
| 2404 if ((type == BinaryOpIC::STRING || type == BinaryOpIC::BOTH_STRING) && | 2348 if ((type == BinaryOpIC::STRING || type == BinaryOpIC::BOTH_STRING) && |
| 2405 op != Token::ADD) { | 2349 op != Token::ADD) { |
| 2406 type = BinaryOpIC::GENERIC; | 2350 type = BinaryOpIC::GENERIC; |
| 2407 } | 2351 } |
| 2408 if (type == BinaryOpIC::SMI && previous_type == BinaryOpIC::SMI) { | 2352 if (type == BinaryOpIC::SMI && previous_type == BinaryOpIC::SMI) { |
| 2409 if (op == Token::DIV || | 2353 if (op == Token::DIV || |
| 2410 op == Token::MUL || | 2354 op == Token::MUL || |
| 2411 op == Token::SHR || | 2355 op == Token::SHR || |
| 2412 kSmiValueSize == 32) { | 2356 kSmiValueSize == 32) { |
| 2413 // Arithmetic on two Smi inputs has yielded a heap number. | 2357 // Arithmetic on two Smi inputs has yielded a heap number. |
| 2414 // That is the only way to get here from the Smi stub. | 2358 // That is the only way to get here from the Smi stub. |
| 2415 // With 32-bit Smis, all overflows give heap numbers, but with | 2359 // With 32-bit Smis, all overflows give heap numbers, but with |
| 2416 // 31-bit Smis, most operations overflow to int32 results. | 2360 // 31-bit Smis, most operations overflow to int32 results. |
| 2417 result_type = BinaryOpIC::HEAP_NUMBER; | 2361 result_type = BinaryOpIC::HEAP_NUMBER; |
| 2418 } else { | 2362 } else { |
| 2419 // Other operations on SMIs that overflow yield int32s. | 2363 // Other operations on SMIs that overflow yield int32s. |
| 2420 result_type = BinaryOpIC::INT32; | 2364 result_type = BinaryOpIC::INT32; |
| 2421 } | 2365 } |
| 2422 } | 2366 } |
| 2423 if (type == BinaryOpIC::INT32 && previous_type == BinaryOpIC::INT32) { | 2367 if (type == BinaryOpIC::INT32 && previous_type == BinaryOpIC::INT32) { |
| 2424 // We must be here because an operation on two INT32 types overflowed. | 2368 // We must be here because an operation on two INT32 types overflowed. |
| 2425 result_type = BinaryOpIC::HEAP_NUMBER; | 2369 result_type = BinaryOpIC::HEAP_NUMBER; |
| 2426 } | 2370 } |
| 2427 | 2371 |
| 2428 Handle<Code> code = GetBinaryOpStub(key, type, result_type); | 2372 BinaryOpStub stub(key, type, result_type); |
| 2373 Handle<Code> code = stub.GetCode(); |
| 2429 if (!code.is_null()) { | 2374 if (!code.is_null()) { |
| 2430 if (FLAG_trace_ic) { | 2375 if (FLAG_trace_ic) { |
| 2431 PrintF("[BinaryOpIC (%s->(%s->%s))#%s]\n", | 2376 PrintF("[BinaryOpIC (%s->(%s->%s))#%s]\n", |
| 2432 BinaryOpIC::GetName(previous_type), | 2377 BinaryOpIC::GetName(previous_type), |
| 2433 BinaryOpIC::GetName(type), | 2378 BinaryOpIC::GetName(type), |
| 2434 BinaryOpIC::GetName(result_type), | 2379 BinaryOpIC::GetName(result_type), |
| 2435 Token::Name(op)); | 2380 Token::Name(op)); |
| 2436 } | 2381 } |
| 2437 BinaryOpIC ic(isolate); | 2382 BinaryOpIC ic(isolate); |
| 2438 ic.patch(*code); | 2383 ic.patch(*code); |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2548 if (state == UNINITIALIZED && | 2493 if (state == UNINITIALIZED && |
| 2549 x->IsJSObject() && y->IsJSObject()) return OBJECTS; | 2494 x->IsJSObject() && y->IsJSObject()) return OBJECTS; |
| 2550 return GENERIC; | 2495 return GENERIC; |
| 2551 } | 2496 } |
| 2552 | 2497 |
| 2553 | 2498 |
| 2554 // Used from ic_<arch>.cc. | 2499 // Used from ic_<arch>.cc. |
| 2555 RUNTIME_FUNCTION(Code*, CompareIC_Miss) { | 2500 RUNTIME_FUNCTION(Code*, CompareIC_Miss) { |
| 2556 NoHandleAllocation na; | 2501 NoHandleAllocation na; |
| 2557 ASSERT(args.length() == 3); | 2502 ASSERT(args.length() == 3); |
| 2558 CompareIC ic(isolate, static_cast<Token::Value>(Smi::cast(args[2])->value())); | 2503 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2))); |
| 2559 ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); | 2504 ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); |
| 2560 return ic.target(); | 2505 return ic.target(); |
| 2561 } | 2506 } |
| 2562 | 2507 |
| 2563 | 2508 |
| 2564 static const Address IC_utilities[] = { | 2509 static const Address IC_utilities[] = { |
| 2565 #define ADDR(name) FUNCTION_ADDR(name), | 2510 #define ADDR(name) FUNCTION_ADDR(name), |
| 2566 IC_UTIL_LIST(ADDR) | 2511 IC_UTIL_LIST(ADDR) |
| 2567 NULL | 2512 NULL |
| 2568 #undef ADDR | 2513 #undef ADDR |
| 2569 }; | 2514 }; |
| 2570 | 2515 |
| 2571 | 2516 |
| 2572 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2517 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2573 return IC_utilities[id]; | 2518 return IC_utilities[id]; |
| 2574 } | 2519 } |
| 2575 | 2520 |
| 2576 | 2521 |
| 2577 } } // namespace v8::internal | 2522 } } // namespace v8::internal |
| OLD | NEW |