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 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
323 static void LookupForRead(Object* object, | 323 static void LookupForRead(Object* object, |
324 String* name, | 324 String* name, |
325 LookupResult* lookup) { | 325 LookupResult* lookup) { |
326 AssertNoAllocation no_gc; // pointers must stay valid | 326 AssertNoAllocation no_gc; // pointers must stay valid |
327 | 327 |
328 // Skip all the objects with named interceptors, but | 328 // Skip all the objects with named interceptors, but |
329 // without actual getter. | 329 // without actual getter. |
330 while (true) { | 330 while (true) { |
331 object->Lookup(name, lookup); | 331 object->Lookup(name, lookup); |
332 // Besides normal conditions (property not found or it's not | 332 // Besides normal conditions (property not found or it's not |
333 // an interceptor), bail out of lookup is not cacheable: we won't | 333 // an interceptor), bail out if lookup is not cacheable: we won't |
334 // be able to IC it anyway and regular lookup should work fine. | 334 // be able to IC it anyway and regular lookup should work fine. |
335 if (lookup->IsNotFound() || lookup->type() != INTERCEPTOR || | 335 if (!lookup->IsFound() |
336 !lookup->IsCacheable()) { | 336 || (lookup->type() != INTERCEPTOR) |
| 337 || !lookup->IsCacheable()) { |
337 return; | 338 return; |
338 } | 339 } |
339 | 340 |
340 JSObject* holder = lookup->holder(); | 341 JSObject* holder = lookup->holder(); |
341 if (HasInterceptorGetter(holder)) { | 342 if (HasInterceptorGetter(holder)) { |
342 return; | 343 return; |
343 } | 344 } |
344 | 345 |
345 holder->LocalLookupRealNamedProperty(name, lookup); | 346 holder->LocalLookupRealNamedProperty(name, lookup); |
346 if (lookup->IsValid()) { | 347 if (lookup->IsProperty()) { |
347 ASSERT(lookup->type() != INTERCEPTOR); | 348 ASSERT(lookup->type() != INTERCEPTOR); |
348 return; | 349 return; |
349 } | 350 } |
350 | 351 |
351 Object* proto = holder->GetPrototype(); | 352 Object* proto = holder->GetPrototype(); |
352 if (proto->IsNull()) { | 353 if (proto->IsNull()) { |
353 lookup->NotFound(); | 354 lookup->NotFound(); |
354 return; | 355 return; |
355 } | 356 } |
356 | 357 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
415 result = TryCallAsFunction(result); | 416 result = TryCallAsFunction(result); |
416 if (result->IsJSFunction()) return result; | 417 if (result->IsJSFunction()) return result; |
417 | 418 |
418 // Otherwise, it will fail in the lookup step. | 419 // Otherwise, it will fail in the lookup step. |
419 } | 420 } |
420 | 421 |
421 // Lookup the property in the object. | 422 // Lookup the property in the object. |
422 LookupResult lookup; | 423 LookupResult lookup; |
423 LookupForRead(*object, *name, &lookup); | 424 LookupForRead(*object, *name, &lookup); |
424 | 425 |
425 if (!lookup.IsValid()) { | 426 if (!lookup.IsProperty()) { |
426 // If the object does not have the requested property, check which | 427 // If the object does not have the requested property, check which |
427 // exception we need to throw. | 428 // exception we need to throw. |
428 if (IsContextual(object)) { | 429 if (IsContextual(object)) { |
429 return ReferenceError("not_defined", name); | 430 return ReferenceError("not_defined", name); |
430 } | 431 } |
431 return TypeError("undefined_method", object, name); | 432 return TypeError("undefined_method", object, name); |
432 } | 433 } |
433 | 434 |
434 // Lookup is valid: Update inline cache and stub cache. | 435 // Lookup is valid: Update inline cache and stub cache. |
435 if (FLAG_use_ic && lookup.IsLoaded()) { | 436 if (FLAG_use_ic && lookup.IsLoaded()) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
486 result : TypeError("property_not_function", object, name); | 487 result : TypeError("property_not_function", object, name); |
487 } | 488 } |
488 | 489 |
489 | 490 |
490 void CallIC::UpdateCaches(LookupResult* lookup, | 491 void CallIC::UpdateCaches(LookupResult* lookup, |
491 State state, | 492 State state, |
492 Handle<Object> object, | 493 Handle<Object> object, |
493 Handle<String> name) { | 494 Handle<String> name) { |
494 ASSERT(lookup->IsLoaded()); | 495 ASSERT(lookup->IsLoaded()); |
495 // Bail out if we didn't find a result. | 496 // Bail out if we didn't find a result. |
496 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | 497 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
497 | 498 |
498 // Compute the number of arguments. | 499 // Compute the number of arguments. |
499 int argc = target()->arguments_count(); | 500 int argc = target()->arguments_count(); |
500 InLoopFlag in_loop = target()->ic_in_loop(); | 501 InLoopFlag in_loop = target()->ic_in_loop(); |
501 Object* code = NULL; | 502 Object* code = NULL; |
502 | 503 |
503 if (state == UNINITIALIZED) { | 504 if (state == UNINITIALIZED) { |
504 // This is the first time we execute this inline cache. | 505 // This is the first time we execute this inline cache. |
505 // Set the target to the pre monomorphic stub to delay | 506 // Set the target to the pre monomorphic stub to delay |
506 // setting the monomorphic state. | 507 // setting the monomorphic state. |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
635 | 636 |
636 // Check if the name is trivially convertible to an index and get | 637 // Check if the name is trivially convertible to an index and get |
637 // the element if so. | 638 // the element if so. |
638 uint32_t index; | 639 uint32_t index; |
639 if (name->AsArrayIndex(&index)) return object->GetElement(index); | 640 if (name->AsArrayIndex(&index)) return object->GetElement(index); |
640 | 641 |
641 // Named lookup in the object. | 642 // Named lookup in the object. |
642 LookupResult lookup; | 643 LookupResult lookup; |
643 LookupForRead(*object, *name, &lookup); | 644 LookupForRead(*object, *name, &lookup); |
644 | 645 |
645 // If lookup is invalid, check if we need to throw an exception. | 646 // If we did not find a property, check if we need to throw an exception. |
646 if (!lookup.IsValid()) { | 647 if (!lookup.IsProperty()) { |
647 if (FLAG_strict || IsContextual(object)) { | 648 if (FLAG_strict || IsContextual(object)) { |
648 return ReferenceError("not_defined", name); | 649 return ReferenceError("not_defined", name); |
649 } | 650 } |
650 LOG(SuspectReadEvent(*name, *object)); | 651 LOG(SuspectReadEvent(*name, *object)); |
651 } | 652 } |
652 | 653 |
653 bool can_be_inlined = | 654 bool can_be_inlined = |
654 FLAG_use_ic && | 655 FLAG_use_ic && |
655 state == PREMONOMORPHIC && | 656 state == PREMONOMORPHIC && |
656 lookup.IsValid() && | 657 lookup.IsProperty() && |
657 lookup.IsLoaded() && | 658 lookup.IsLoaded() && |
658 lookup.IsCacheable() && | 659 lookup.IsCacheable() && |
659 lookup.holder() == *object && | 660 lookup.holder() == *object && |
660 lookup.type() == FIELD && | 661 lookup.type() == FIELD && |
661 !object->IsAccessCheckNeeded(); | 662 !object->IsAccessCheckNeeded(); |
662 | 663 |
663 if (can_be_inlined) { | 664 if (can_be_inlined) { |
664 Map* map = lookup.holder()->map(); | 665 Map* map = lookup.holder()->map(); |
665 // Property's index in the properties array. If negative we have | 666 // Property's index in the properties array. If negative we have |
666 // an inobject property. | 667 // an inobject property. |
667 int index = lookup.GetFieldIndex() - map->inobject_properties(); | 668 int index = lookup.GetFieldIndex() - map->inobject_properties(); |
668 if (index < 0) { | 669 if (index < 0) { |
669 // Index is an offset from the end of the object. | 670 // Index is an offset from the end of the object. |
670 int offset = map->instance_size() + (index * kPointerSize); | 671 int offset = map->instance_size() + (index * kPointerSize); |
671 if (PatchInlinedLoad(address(), map, offset)) { | 672 if (PatchInlinedLoad(address(), map, offset)) { |
672 set_target(megamorphic_stub()); | 673 set_target(megamorphic_stub()); |
673 return lookup.holder()->FastPropertyAt(lookup.GetFieldIndex()); | 674 return lookup.holder()->FastPropertyAt(lookup.GetFieldIndex()); |
674 } | 675 } |
675 } | 676 } |
676 } | 677 } |
677 | 678 |
678 // Update inline cache and stub cache. | 679 // Update inline cache and stub cache. |
679 if (FLAG_use_ic && lookup.IsLoaded()) { | 680 if (FLAG_use_ic && lookup.IsLoaded()) { |
680 UpdateCaches(&lookup, state, object, name); | 681 UpdateCaches(&lookup, state, object, name); |
681 } | 682 } |
682 | 683 |
683 PropertyAttributes attr; | 684 PropertyAttributes attr; |
684 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) { | 685 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) { |
685 // Get the property. | 686 // Get the property. |
686 Object* result = object->GetProperty(*object, &lookup, *name, &attr); | 687 Object* result = object->GetProperty(*object, &lookup, *name, &attr); |
687 if (result->IsFailure()) return result; | 688 if (result->IsFailure()) return result; |
688 // If the property is not present, check if we need to throw an | 689 // If the property is not present, check if we need to throw an |
689 // exception. | 690 // exception. |
690 if (attr == ABSENT && IsContextual(object)) { | 691 if (attr == ABSENT && IsContextual(object)) { |
691 return ReferenceError("not_defined", name); | 692 return ReferenceError("not_defined", name); |
692 } | 693 } |
693 return result; | 694 return result; |
694 } | 695 } |
695 | 696 |
696 // Get the property. | 697 // Get the property. |
697 return object->GetProperty(*object, &lookup, *name, &attr); | 698 return object->GetProperty(*object, &lookup, *name, &attr); |
698 } | 699 } |
699 | 700 |
700 | 701 |
701 void LoadIC::UpdateCaches(LookupResult* lookup, | 702 void LoadIC::UpdateCaches(LookupResult* lookup, |
702 State state, | 703 State state, |
703 Handle<Object> object, | 704 Handle<Object> object, |
704 Handle<String> name) { | 705 Handle<String> name) { |
705 ASSERT(lookup->IsLoaded()); | 706 ASSERT(lookup->IsLoaded()); |
706 // Bail out if we didn't find a result. | 707 // Bail out if we didn't find a result. |
707 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | 708 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
708 | 709 |
709 // Loading properties from values is not common, so don't try to | 710 // Loading properties from values is not common, so don't try to |
710 // deal with non-JS objects here. | 711 // deal with non-JS objects here. |
711 if (!object->IsJSObject()) return; | 712 if (!object->IsJSObject()) return; |
712 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 713 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
713 | 714 |
714 // Compute the code stub for this load. | 715 // Compute the code stub for this load. |
715 Object* code = NULL; | 716 Object* code = NULL; |
716 if (state == UNINITIALIZED) { | 717 if (state == UNINITIALIZED) { |
717 // This is the first time we execute this inline cache. | 718 // This is the first time we execute this inline cache. |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
850 HandleScope scope; | 851 HandleScope scope; |
851 // Rewrite to the generic keyed load stub. | 852 // Rewrite to the generic keyed load stub. |
852 if (FLAG_use_ic) set_target(generic_stub()); | 853 if (FLAG_use_ic) set_target(generic_stub()); |
853 return Runtime::GetElementOrCharAt(object, index); | 854 return Runtime::GetElementOrCharAt(object, index); |
854 } | 855 } |
855 | 856 |
856 // Named lookup. | 857 // Named lookup. |
857 LookupResult lookup; | 858 LookupResult lookup; |
858 LookupForRead(*object, *name, &lookup); | 859 LookupForRead(*object, *name, &lookup); |
859 | 860 |
860 // If lookup is invalid, check if we need to throw an exception. | 861 // If we did not find a property, check if we need to throw an exception. |
861 if (!lookup.IsValid()) { | 862 if (!lookup.IsProperty()) { |
862 if (FLAG_strict || IsContextual(object)) { | 863 if (FLAG_strict || IsContextual(object)) { |
863 return ReferenceError("not_defined", name); | 864 return ReferenceError("not_defined", name); |
864 } | 865 } |
865 } | 866 } |
866 | 867 |
867 if (FLAG_use_ic && lookup.IsLoaded()) { | 868 if (FLAG_use_ic && lookup.IsLoaded()) { |
868 UpdateCaches(&lookup, state, object, name); | 869 UpdateCaches(&lookup, state, object, name); |
869 } | 870 } |
870 | 871 |
871 PropertyAttributes attr; | 872 PropertyAttributes attr; |
872 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) { | 873 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) { |
873 // Get the property. | 874 // Get the property. |
874 Object* result = object->GetProperty(*object, &lookup, *name, &attr); | 875 Object* result = object->GetProperty(*object, &lookup, *name, &attr); |
875 if (result->IsFailure()) return result; | 876 if (result->IsFailure()) return result; |
876 // If the property is not present, check if we need to throw an | 877 // If the property is not present, check if we need to throw an |
877 // exception. | 878 // exception. |
878 if (attr == ABSENT && IsContextual(object)) { | 879 if (attr == ABSENT && IsContextual(object)) { |
879 return ReferenceError("not_defined", name); | 880 return ReferenceError("not_defined", name); |
880 } | 881 } |
881 return result; | 882 return result; |
882 } | 883 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
914 | 915 |
915 // Get the property. | 916 // Get the property. |
916 return Runtime::GetObjectProperty(object, key); | 917 return Runtime::GetObjectProperty(object, key); |
917 } | 918 } |
918 | 919 |
919 | 920 |
920 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, | 921 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, |
921 Handle<Object> object, Handle<String> name) { | 922 Handle<Object> object, Handle<String> name) { |
922 ASSERT(lookup->IsLoaded()); | 923 ASSERT(lookup->IsLoaded()); |
923 // Bail out if we didn't find a result. | 924 // Bail out if we didn't find a result. |
924 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | 925 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
925 | 926 |
926 if (!object->IsJSObject()) return; | 927 if (!object->IsJSObject()) return; |
927 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 928 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
928 | 929 |
929 // Compute the code stub for this load. | 930 // Compute the code stub for this load. |
930 Object* code = NULL; | 931 Object* code = NULL; |
931 | 932 |
932 if (state == UNINITIALIZED) { | 933 if (state == UNINITIALIZED) { |
933 // This is the first time we execute this inline cache. | 934 // This is the first time we execute this inline cache. |
934 // Set the target to the pre monomorphic stub to delay | 935 // Set the target to the pre monomorphic stub to delay |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
987 } | 988 } |
988 | 989 |
989 #ifdef DEBUG | 990 #ifdef DEBUG |
990 TraceIC("KeyedLoadIC", name, state, target()); | 991 TraceIC("KeyedLoadIC", name, state, target()); |
991 #endif | 992 #endif |
992 } | 993 } |
993 | 994 |
994 | 995 |
995 static bool StoreICableLookup(LookupResult* lookup) { | 996 static bool StoreICableLookup(LookupResult* lookup) { |
996 // Bail out if we didn't find a result. | 997 // Bail out if we didn't find a result. |
997 if (!lookup->IsValid() || !lookup->IsCacheable()) return false; | 998 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return false; |
998 | 999 |
999 // If the property is read-only, we leave the IC in its current | 1000 // If the property is read-only, we leave the IC in its current |
1000 // state. | 1001 // state. |
1001 if (lookup->IsReadOnly()) return false; | 1002 if (lookup->IsReadOnly()) return false; |
1002 | 1003 |
1003 if (!lookup->IsLoaded()) return false; | 1004 if (!lookup->IsLoaded()) return false; |
1004 | 1005 |
1005 return true; | 1006 return true; |
1006 } | 1007 } |
1007 | 1008 |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1207 State state, | 1208 State state, |
1208 Handle<JSObject> receiver, | 1209 Handle<JSObject> receiver, |
1209 Handle<String> name, | 1210 Handle<String> name, |
1210 Handle<Object> value) { | 1211 Handle<Object> value) { |
1211 ASSERT(lookup->IsLoaded()); | 1212 ASSERT(lookup->IsLoaded()); |
1212 | 1213 |
1213 // Skip JSGlobalProxy. | 1214 // Skip JSGlobalProxy. |
1214 if (receiver->IsJSGlobalProxy()) return; | 1215 if (receiver->IsJSGlobalProxy()) return; |
1215 | 1216 |
1216 // Bail out if we didn't find a result. | 1217 // Bail out if we didn't find a result. |
1217 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | 1218 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return; |
1218 | 1219 |
1219 // If the property is read-only, we leave the IC in its current | 1220 // If the property is read-only, we leave the IC in its current |
1220 // state. | 1221 // state. |
1221 if (lookup->IsReadOnly()) return; | 1222 if (lookup->IsReadOnly()) return; |
1222 | 1223 |
1223 // If the property has a non-field type allowing map transitions | 1224 // If the property has a non-field type allowing map transitions |
1224 // where there is extra room in the object, we leave the IC in its | 1225 // where there is extra room in the object, we leave the IC in its |
1225 // current state. | 1226 // current state. |
1226 PropertyType type = lookup->type(); | 1227 PropertyType type = lookup->type(); |
1227 | 1228 |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1395 #undef ADDR | 1396 #undef ADDR |
1396 }; | 1397 }; |
1397 | 1398 |
1398 | 1399 |
1399 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 1400 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
1400 return IC_utilities[id]; | 1401 return IC_utilities[id]; |
1401 } | 1402 } |
1402 | 1403 |
1403 | 1404 |
1404 } } // namespace v8::internal | 1405 } } // namespace v8::internal |
OLD | NEW |