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 |