| 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 |