| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 if (state == UNINITIALIZED) return; | 297 if (state == UNINITIALIZED) return; |
| 298 Code* code = | 298 Code* code = |
| 299 Isolate::Current()->stub_cache()->FindCallInitialize( | 299 Isolate::Current()->stub_cache()->FindCallInitialize( |
| 300 target->arguments_count(), | 300 target->arguments_count(), |
| 301 target->ic_in_loop(), | 301 target->ic_in_loop(), |
| 302 target->kind()); | 302 target->kind()); |
| 303 SetTargetAtAddress(address, code); | 303 SetTargetAtAddress(address, code); |
| 304 } | 304 } |
| 305 | 305 |
| 306 | 306 |
| 307 void KeyedLoadIC::ClearInlinedVersion(Address address) { | |
| 308 // Insert null as the map to check for to make sure the map check fails | |
| 309 // sending control flow to the IC instead of the inlined version. | |
| 310 PatchInlinedLoad(address, HEAP->null_value()); | |
| 311 } | |
| 312 | |
| 313 | |
| 314 void KeyedLoadIC::Clear(Address address, Code* target) { | 307 void KeyedLoadIC::Clear(Address address, Code* target) { |
| 315 if (target->ic_state() == UNINITIALIZED) return; | 308 if (target->ic_state() == UNINITIALIZED) return; |
| 316 // Make sure to also clear the map used in inline fast cases. If we | 309 // Make sure to also clear the map used in inline fast cases. If we |
| 317 // do not clear these maps, cached code can keep objects alive | 310 // do not clear these maps, cached code can keep objects alive |
| 318 // through the embedded maps. | 311 // through the embedded maps. |
| 319 ClearInlinedVersion(address); | |
| 320 SetTargetAtAddress(address, initialize_stub()); | 312 SetTargetAtAddress(address, initialize_stub()); |
| 321 } | 313 } |
| 322 | 314 |
| 323 | 315 |
| 324 void LoadIC::ClearInlinedVersion(Address address) { | |
| 325 // Reset the map check of the inlined inobject property load (if | |
| 326 // present) to guarantee failure by holding an invalid map (the null | |
| 327 // value). The offset can be patched to anything. | |
| 328 Heap* heap = HEAP; | |
| 329 PatchInlinedLoad(address, heap->null_value(), 0); | |
| 330 PatchInlinedContextualLoad(address, | |
| 331 heap->null_value(), | |
| 332 heap->null_value(), | |
| 333 true); | |
| 334 } | |
| 335 | |
| 336 | |
| 337 void LoadIC::Clear(Address address, Code* target) { | 316 void LoadIC::Clear(Address address, Code* target) { |
| 338 if (target->ic_state() == UNINITIALIZED) return; | 317 if (target->ic_state() == UNINITIALIZED) return; |
| 339 ClearInlinedVersion(address); | |
| 340 SetTargetAtAddress(address, initialize_stub()); | 318 SetTargetAtAddress(address, initialize_stub()); |
| 341 } | 319 } |
| 342 | 320 |
| 343 | 321 |
| 344 void StoreIC::ClearInlinedVersion(Address address) { | |
| 345 // Reset the map check of the inlined inobject property store (if | |
| 346 // present) to guarantee failure by holding an invalid map (the null | |
| 347 // value). The offset can be patched to anything. | |
| 348 PatchInlinedStore(address, HEAP->null_value(), 0); | |
| 349 } | |
| 350 | |
| 351 | |
| 352 void StoreIC::Clear(Address address, Code* target) { | 322 void StoreIC::Clear(Address address, Code* target) { |
| 353 if (target->ic_state() == UNINITIALIZED) return; | 323 if (target->ic_state() == UNINITIALIZED) return; |
| 354 ClearInlinedVersion(address); | |
| 355 SetTargetAtAddress(address, | 324 SetTargetAtAddress(address, |
| 356 (target->extra_ic_state() == kStrictMode) | 325 (target->extra_ic_state() == kStrictMode) |
| 357 ? initialize_stub_strict() | 326 ? initialize_stub_strict() |
| 358 : initialize_stub()); | 327 : initialize_stub()); |
| 359 } | 328 } |
| 360 | 329 |
| 361 | 330 |
| 362 void KeyedStoreIC::ClearInlinedVersion(Address address) { | |
| 363 // Insert null as the elements map to check for. This will make | |
| 364 // sure that the elements fast-case map check fails so that control | |
| 365 // flows to the IC instead of the inlined version. | |
| 366 PatchInlinedStore(address, HEAP->null_value()); | |
| 367 } | |
| 368 | |
| 369 | |
| 370 void KeyedStoreIC::RestoreInlinedVersion(Address address) { | |
| 371 // Restore the fast-case elements map check so that the inlined | |
| 372 // version can be used again. | |
| 373 PatchInlinedStore(address, HEAP->fixed_array_map()); | |
| 374 } | |
| 375 | |
| 376 | |
| 377 void KeyedStoreIC::Clear(Address address, Code* target) { | 331 void KeyedStoreIC::Clear(Address address, Code* target) { |
| 378 if (target->ic_state() == UNINITIALIZED) return; | 332 if (target->ic_state() == UNINITIALIZED) return; |
| 379 SetTargetAtAddress(address, | 333 SetTargetAtAddress(address, |
| 380 (target->extra_ic_state() == kStrictMode) | 334 (target->extra_ic_state() == kStrictMode) |
| 381 ? initialize_stub_strict() | 335 ? initialize_stub_strict() |
| 382 : initialize_stub()); | 336 : initialize_stub()); |
| 383 } | 337 } |
| 384 | 338 |
| 385 | 339 |
| 386 static bool HasInterceptorGetter(JSObject* object) { | 340 static bool HasInterceptorGetter(JSObject* object) { |
| (...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 866 // objects is read-only and therefore always returns the length of | 820 // objects is read-only and therefore always returns the length of |
| 867 // the underlying string value. See ECMA-262 15.5.5.1. | 821 // the underlying string value. See ECMA-262 15.5.5.1. |
| 868 if ((object->IsString() || object->IsStringWrapper()) && | 822 if ((object->IsString() || object->IsStringWrapper()) && |
| 869 name->Equals(isolate()->heap()->length_symbol())) { | 823 name->Equals(isolate()->heap()->length_symbol())) { |
| 870 HandleScope scope(isolate()); | 824 HandleScope scope(isolate()); |
| 871 #ifdef DEBUG | 825 #ifdef DEBUG |
| 872 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); | 826 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); |
| 873 #endif | 827 #endif |
| 874 if (state == PREMONOMORPHIC) { | 828 if (state == PREMONOMORPHIC) { |
| 875 if (object->IsString()) { | 829 if (object->IsString()) { |
| 876 Map* map = HeapObject::cast(*object)->map(); | |
| 877 const int offset = String::kLengthOffset; | |
| 878 PatchInlinedLoad(address(), map, offset); | |
| 879 set_target(isolate()->builtins()->builtin( | 830 set_target(isolate()->builtins()->builtin( |
| 880 Builtins::kLoadIC_StringLength)); | 831 Builtins::kLoadIC_StringLength)); |
| 881 } else { | 832 } else { |
| 882 set_target(isolate()->builtins()->builtin( | 833 set_target(isolate()->builtins()->builtin( |
| 883 Builtins::kLoadIC_StringWrapperLength)); | 834 Builtins::kLoadIC_StringWrapperLength)); |
| 884 } | 835 } |
| 885 } else if (state == MONOMORPHIC && object->IsStringWrapper()) { | 836 } else if (state == MONOMORPHIC && object->IsStringWrapper()) { |
| 886 set_target(isolate()->builtins()->builtin( | 837 set_target(isolate()->builtins()->builtin( |
| 887 Builtins::kLoadIC_StringWrapperLength)); | 838 Builtins::kLoadIC_StringWrapperLength)); |
| 888 } else { | 839 } else { |
| 889 set_target(non_monomorphic_stub); | 840 set_target(non_monomorphic_stub); |
| 890 } | 841 } |
| 891 // Get the string if we have a string wrapper object. | 842 // Get the string if we have a string wrapper object. |
| 892 if (object->IsJSValue()) { | 843 if (object->IsJSValue()) { |
| 893 object = Handle<Object>(Handle<JSValue>::cast(object)->value(), | 844 object = Handle<Object>(Handle<JSValue>::cast(object)->value(), |
| 894 isolate()); | 845 isolate()); |
| 895 } | 846 } |
| 896 return Smi::FromInt(String::cast(*object)->length()); | 847 return Smi::FromInt(String::cast(*object)->length()); |
| 897 } | 848 } |
| 898 | 849 |
| 899 // Use specialized code for getting the length of arrays. | 850 // Use specialized code for getting the length of arrays. |
| 900 if (object->IsJSArray() && | 851 if (object->IsJSArray() && |
| 901 name->Equals(isolate()->heap()->length_symbol())) { | 852 name->Equals(isolate()->heap()->length_symbol())) { |
| 902 #ifdef DEBUG | 853 #ifdef DEBUG |
| 903 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); | 854 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); |
| 904 #endif | 855 #endif |
| 905 if (state == PREMONOMORPHIC) { | 856 if (state == PREMONOMORPHIC) { |
| 906 Map* map = HeapObject::cast(*object)->map(); | |
| 907 const int offset = JSArray::kLengthOffset; | |
| 908 PatchInlinedLoad(address(), map, offset); | |
| 909 set_target(isolate()->builtins()->builtin( | 857 set_target(isolate()->builtins()->builtin( |
| 910 Builtins::kLoadIC_ArrayLength)); | 858 Builtins::kLoadIC_ArrayLength)); |
| 911 } else { | 859 } else { |
| 912 set_target(non_monomorphic_stub); | 860 set_target(non_monomorphic_stub); |
| 913 } | 861 } |
| 914 return JSArray::cast(*object)->length(); | 862 return JSArray::cast(*object)->length(); |
| 915 } | 863 } |
| 916 | 864 |
| 917 // Use specialized code for getting prototype of functions. | 865 // Use specialized code for getting prototype of functions. |
| 918 if (object->IsJSFunction() && | 866 if (object->IsJSFunction() && |
| (...skipping 22 matching lines...) Expand all Loading... |
| 941 LookupForRead(*object, *name, &lookup); | 889 LookupForRead(*object, *name, &lookup); |
| 942 | 890 |
| 943 // If we did not find a property, check if we need to throw an exception. | 891 // If we did not find a property, check if we need to throw an exception. |
| 944 if (!lookup.IsProperty()) { | 892 if (!lookup.IsProperty()) { |
| 945 if (FLAG_strict || IsContextual(object)) { | 893 if (FLAG_strict || IsContextual(object)) { |
| 946 return ReferenceError("not_defined", name); | 894 return ReferenceError("not_defined", name); |
| 947 } | 895 } |
| 948 LOG(isolate(), SuspectReadEvent(*name, *object)); | 896 LOG(isolate(), SuspectReadEvent(*name, *object)); |
| 949 } | 897 } |
| 950 | 898 |
| 951 bool can_be_inlined_precheck = | |
| 952 FLAG_use_ic && | |
| 953 lookup.IsProperty() && | |
| 954 lookup.IsCacheable() && | |
| 955 lookup.holder() == *object && | |
| 956 !object->IsAccessCheckNeeded(); | |
| 957 | |
| 958 bool can_be_inlined = | |
| 959 can_be_inlined_precheck && | |
| 960 state == PREMONOMORPHIC && | |
| 961 lookup.type() == FIELD; | |
| 962 | |
| 963 bool can_be_inlined_contextual = | |
| 964 can_be_inlined_precheck && | |
| 965 state == UNINITIALIZED && | |
| 966 lookup.holder()->IsGlobalObject() && | |
| 967 lookup.type() == NORMAL; | |
| 968 | |
| 969 if (can_be_inlined) { | |
| 970 Map* map = lookup.holder()->map(); | |
| 971 // Property's index in the properties array. If negative we have | |
| 972 // an inobject property. | |
| 973 int index = lookup.GetFieldIndex() - map->inobject_properties(); | |
| 974 if (index < 0) { | |
| 975 // Index is an offset from the end of the object. | |
| 976 int offset = map->instance_size() + (index * kPointerSize); | |
| 977 if (PatchInlinedLoad(address(), map, offset)) { | |
| 978 set_target(megamorphic_stub()); | |
| 979 TRACE_IC_NAMED("[LoadIC : inline patch %s]\n", name); | |
| 980 return lookup.holder()->FastPropertyAt(lookup.GetFieldIndex()); | |
| 981 } else { | |
| 982 TRACE_IC_NAMED("[LoadIC : no inline patch %s (patching failed)]\n", | |
| 983 name); | |
| 984 } | |
| 985 } else { | |
| 986 TRACE_IC_NAMED("[LoadIC : no inline patch %s (not inobject)]\n", name); | |
| 987 } | |
| 988 } else if (can_be_inlined_contextual) { | |
| 989 Map* map = lookup.holder()->map(); | |
| 990 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast( | |
| 991 lookup.holder()->property_dictionary()->ValueAt( | |
| 992 lookup.GetDictionaryEntry())); | |
| 993 if (PatchInlinedContextualLoad(address(), | |
| 994 map, | |
| 995 cell, | |
| 996 lookup.IsDontDelete())) { | |
| 997 set_target(megamorphic_stub()); | |
| 998 TRACE_IC_NAMED("[LoadIC : inline contextual patch %s]\n", name); | |
| 999 ASSERT(cell->value() != isolate()->heap()->the_hole_value()); | |
| 1000 return cell->value(); | |
| 1001 } | |
| 1002 } else { | |
| 1003 if (FLAG_use_ic && state == PREMONOMORPHIC) { | |
| 1004 TRACE_IC_NAMED("[LoadIC : no inline patch %s (not inlinable)]\n", name); | |
| 1005 } | |
| 1006 } | |
| 1007 | |
| 1008 // Update inline cache and stub cache. | 899 // Update inline cache and stub cache. |
| 1009 if (FLAG_use_ic) { | 900 if (FLAG_use_ic) { |
| 1010 UpdateCaches(&lookup, state, object, name); | 901 UpdateCaches(&lookup, state, object, name); |
| 1011 } | 902 } |
| 1012 | 903 |
| 1013 PropertyAttributes attr; | 904 PropertyAttributes attr; |
| 1014 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) { | 905 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) { |
| 1015 // Get the property. | 906 // Get the property. |
| 1016 Object* result; | 907 Object* result; |
| 1017 { MaybeObject* maybe_result = | 908 { MaybeObject* maybe_result = |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1287 stub = probe->IsFailure() ? | 1178 stub = probe->IsFailure() ? |
| 1288 NULL : Code::cast(probe->ToObjectUnchecked()); | 1179 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1289 } | 1180 } |
| 1290 } | 1181 } |
| 1291 } | 1182 } |
| 1292 if (stub != NULL) set_target(stub); | 1183 if (stub != NULL) set_target(stub); |
| 1293 | 1184 |
| 1294 #ifdef DEBUG | 1185 #ifdef DEBUG |
| 1295 TraceIC("KeyedLoadIC", key, state, target()); | 1186 TraceIC("KeyedLoadIC", key, state, target()); |
| 1296 #endif // DEBUG | 1187 #endif // DEBUG |
| 1297 | |
| 1298 // For JSObjects with fast elements that are not value wrappers | |
| 1299 // and that do not have indexed interceptors, we initialize the | |
| 1300 // inlined fast case (if present) by patching the inlined map | |
| 1301 // check. | |
| 1302 if (object->IsJSObject() && | |
| 1303 !object->IsJSValue() && | |
| 1304 !JSObject::cast(*object)->HasIndexedInterceptor() && | |
| 1305 JSObject::cast(*object)->HasFastElements()) { | |
| 1306 Map* map = JSObject::cast(*object)->map(); | |
| 1307 PatchInlinedLoad(address(), map); | |
| 1308 } | |
| 1309 } | 1188 } |
| 1310 | 1189 |
| 1311 // Get the property. | 1190 // Get the property. |
| 1312 return Runtime::GetObjectProperty(isolate(), object, key); | 1191 return Runtime::GetObjectProperty(isolate(), object, key); |
| 1313 } | 1192 } |
| 1314 | 1193 |
| 1315 | 1194 |
| 1316 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, | 1195 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, |
| 1317 Handle<Object> object, Handle<String> name) { | 1196 Handle<Object> object, Handle<String> name) { |
| 1318 // Bail out if we didn't find a result. | 1197 // Bail out if we didn't find a result. |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1464 : Builtins::kStoreIC_ArrayLength; | 1343 : Builtins::kStoreIC_ArrayLength; |
| 1465 set_target(isolate()->builtins()->builtin(target)); | 1344 set_target(isolate()->builtins()->builtin(target)); |
| 1466 return receiver->SetProperty(*name, *value, NONE, strict_mode); | 1345 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1467 } | 1346 } |
| 1468 | 1347 |
| 1469 // Lookup the property locally in the receiver. | 1348 // Lookup the property locally in the receiver. |
| 1470 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { | 1349 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { |
| 1471 LookupResult lookup; | 1350 LookupResult lookup; |
| 1472 | 1351 |
| 1473 if (LookupForWrite(*receiver, *name, &lookup)) { | 1352 if (LookupForWrite(*receiver, *name, &lookup)) { |
| 1474 bool can_be_inlined = | 1353 // Generate a stub for this store. |
| 1475 state == UNINITIALIZED && | |
| 1476 lookup.IsProperty() && | |
| 1477 lookup.holder() == *receiver && | |
| 1478 lookup.type() == FIELD && | |
| 1479 !receiver->IsAccessCheckNeeded(); | |
| 1480 | |
| 1481 if (can_be_inlined) { | |
| 1482 Map* map = lookup.holder()->map(); | |
| 1483 // Property's index in the properties array. If negative we have | |
| 1484 // an inobject property. | |
| 1485 int index = lookup.GetFieldIndex() - map->inobject_properties(); | |
| 1486 if (index < 0) { | |
| 1487 // Index is an offset from the end of the object. | |
| 1488 int offset = map->instance_size() + (index * kPointerSize); | |
| 1489 if (PatchInlinedStore(address(), map, offset)) { | |
| 1490 set_target((strict_mode == kStrictMode) | |
| 1491 ? megamorphic_stub_strict() | |
| 1492 : megamorphic_stub()); | |
| 1493 #ifdef DEBUG | |
| 1494 if (FLAG_trace_ic) { | |
| 1495 PrintF("[StoreIC : inline patch %s]\n", *name->ToCString()); | |
| 1496 } | |
| 1497 #endif | |
| 1498 return receiver->SetProperty(*name, *value, NONE, strict_mode); | |
| 1499 #ifdef DEBUG | |
| 1500 | |
| 1501 } else { | |
| 1502 if (FLAG_trace_ic) { | |
| 1503 PrintF("[StoreIC : no inline patch %s (patching failed)]\n", | |
| 1504 *name->ToCString()); | |
| 1505 } | |
| 1506 } | |
| 1507 } else { | |
| 1508 if (FLAG_trace_ic) { | |
| 1509 PrintF("[StoreIC : no inline patch %s (not inobject)]\n", | |
| 1510 *name->ToCString()); | |
| 1511 } | |
| 1512 } | |
| 1513 } else { | |
| 1514 if (state == PREMONOMORPHIC) { | |
| 1515 if (FLAG_trace_ic) { | |
| 1516 PrintF("[StoreIC : no inline patch %s (not inlinable)]\n", | |
| 1517 *name->ToCString()); | |
| 1518 #endif | |
| 1519 } | |
| 1520 } | |
| 1521 } | |
| 1522 | |
| 1523 // If no inlined store ic was patched, generate a stub for this | |
| 1524 // store. | |
| 1525 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); | 1354 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
| 1526 } else { | 1355 } else { |
| 1527 // Strict mode doesn't allow setting non-existent global property | 1356 // Strict mode doesn't allow setting non-existent global property |
| 1528 // or an assignment to a read only property. | 1357 // or an assignment to a read only property. |
| 1529 if (strict_mode == kStrictMode) { | 1358 if (strict_mode == kStrictMode) { |
| 1530 if (lookup.IsFound() && lookup.IsReadOnly()) { | 1359 if (lookup.IsFound() && lookup.IsReadOnly()) { |
| 1531 return TypeError("strict_read_only_property", object, name); | 1360 return TypeError("strict_read_only_property", object, name); |
| 1532 } else if (IsContextual(object)) { | 1361 } else if (IsContextual(object)) { |
| 1533 return ReferenceError("not_defined", name); | 1362 return ReferenceError("not_defined", name); |
| 1534 } | 1363 } |
| (...skipping 703 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2238 #undef ADDR | 2067 #undef ADDR |
| 2239 }; | 2068 }; |
| 2240 | 2069 |
| 2241 | 2070 |
| 2242 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2071 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2243 return IC_utilities[id]; | 2072 return IC_utilities[id]; |
| 2244 } | 2073 } |
| 2245 | 2074 |
| 2246 | 2075 |
| 2247 } } // namespace v8::internal | 2076 } } // namespace v8::internal |
| OLD | NEW |