| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 637 if (!result->IsProperty()) { | 637 if (!result->IsProperty()) { |
| 638 Object* proto = obj->GetPrototype(); | 638 Object* proto = obj->GetPrototype(); |
| 639 if (proto->IsJSObject() && | 639 if (proto->IsJSObject() && |
| 640 JSObject::cast(proto)->map()->is_hidden_prototype()) | 640 JSObject::cast(proto)->map()->is_hidden_prototype()) |
| 641 GetOwnPropertyImplementation(JSObject::cast(proto), | 641 GetOwnPropertyImplementation(JSObject::cast(proto), |
| 642 name, result); | 642 name, result); |
| 643 } | 643 } |
| 644 } | 644 } |
| 645 | 645 |
| 646 | 646 |
| 647 static bool CheckAccessException(LookupResult* result, |
| 648 v8::AccessType access_type) { |
| 649 if (result->type() == CALLBACKS) { |
| 650 Object* callback = result->GetCallbackObject(); |
| 651 if (callback->IsAccessorInfo()) { |
| 652 AccessorInfo* info = AccessorInfo::cast(callback); |
| 653 bool can_access = |
| 654 (access_type == v8::ACCESS_HAS && |
| 655 (info->all_can_read() || info->all_can_write())) || |
| 656 (access_type == v8::ACCESS_GET && info->all_can_read()) || |
| 657 (access_type == v8::ACCESS_SET && info->all_can_write()); |
| 658 return can_access; |
| 659 } |
| 660 } |
| 661 |
| 662 return false; |
| 663 } |
| 664 |
| 665 |
| 666 static bool CheckAccess(JSObject* obj, |
| 667 String* name, |
| 668 LookupResult* result, |
| 669 v8::AccessType access_type) { |
| 670 ASSERT(result->IsProperty()); |
| 671 |
| 672 JSObject* holder = result->holder(); |
| 673 JSObject* current = obj; |
| 674 while (true) { |
| 675 if (current->IsAccessCheckNeeded() && |
| 676 !Top::MayNamedAccess(current, name, access_type)) { |
| 677 // Access check callback denied the access, but some properties |
| 678 // can have a special permissions which override callbacks descision |
| 679 // (currently see v8::AccessControl). |
| 680 break; |
| 681 } |
| 682 |
| 683 if (current == holder) { |
| 684 return true; |
| 685 } |
| 686 |
| 687 current = JSObject::cast(current->GetPrototype()); |
| 688 } |
| 689 |
| 690 // API callbacks can have per callback access exceptions. |
| 691 switch (result->type()) { |
| 692 case CALLBACKS: { |
| 693 if (CheckAccessException(result, access_type)) { |
| 694 return true; |
| 695 } |
| 696 break; |
| 697 } |
| 698 case INTERCEPTOR: { |
| 699 // If the object has an interceptor, try real named properties. |
| 700 // Overwrite the result to fetch the correct property later. |
| 701 holder->LookupRealNamedProperty(name, result); |
| 702 if (result->IsProperty()) { |
| 703 if (CheckAccessException(result, access_type)) { |
| 704 return true; |
| 705 } |
| 706 } |
| 707 break; |
| 708 } |
| 709 default: |
| 710 break; |
| 711 } |
| 712 |
| 713 Top::ReportFailedAccessCheck(current, access_type); |
| 714 return false; |
| 715 } |
| 716 |
| 717 |
| 718 // TODO(1095): we should traverse hidden prototype hierachy as well. |
| 719 static bool CheckElementAccess(JSObject* obj, |
| 720 uint32_t index, |
| 721 v8::AccessType access_type) { |
| 722 if (obj->IsAccessCheckNeeded() && |
| 723 !Top::MayIndexedAccess(obj, index, access_type)) { |
| 724 return false; |
| 725 } |
| 726 |
| 727 return true; |
| 728 } |
| 729 |
| 730 |
| 647 // Enumerator used as indices into the array returned from GetOwnProperty | 731 // Enumerator used as indices into the array returned from GetOwnProperty |
| 648 enum PropertyDescriptorIndices { | 732 enum PropertyDescriptorIndices { |
| 649 IS_ACCESSOR_INDEX, | 733 IS_ACCESSOR_INDEX, |
| 650 VALUE_INDEX, | 734 VALUE_INDEX, |
| 651 GETTER_INDEX, | 735 GETTER_INDEX, |
| 652 SETTER_INDEX, | 736 SETTER_INDEX, |
| 653 WRITABLE_INDEX, | 737 WRITABLE_INDEX, |
| 654 ENUMERABLE_INDEX, | 738 ENUMERABLE_INDEX, |
| 655 CONFIGURABLE_INDEX, | 739 CONFIGURABLE_INDEX, |
| 656 DESCRIPTOR_SIZE | 740 DESCRIPTOR_SIZE |
| (...skipping 22 matching lines...) Expand all Loading... |
| 679 case JSObject::UNDEFINED_ELEMENT: | 763 case JSObject::UNDEFINED_ELEMENT: |
| 680 return Heap::undefined_value(); | 764 return Heap::undefined_value(); |
| 681 | 765 |
| 682 case JSObject::STRING_CHARACTER_ELEMENT: { | 766 case JSObject::STRING_CHARACTER_ELEMENT: { |
| 683 // Special handling of string objects according to ECMAScript 5 | 767 // Special handling of string objects according to ECMAScript 5 |
| 684 // 15.5.5.2. Note that this might be a string object with elements | 768 // 15.5.5.2. Note that this might be a string object with elements |
| 685 // other than the actual string value. This is covered by the | 769 // other than the actual string value. This is covered by the |
| 686 // subsequent cases. | 770 // subsequent cases. |
| 687 Handle<JSValue> js_value = Handle<JSValue>::cast(obj); | 771 Handle<JSValue> js_value = Handle<JSValue>::cast(obj); |
| 688 Handle<String> str(String::cast(js_value->value())); | 772 Handle<String> str(String::cast(js_value->value())); |
| 689 Handle<String> substr = SubString(str, index, index+1, NOT_TENURED); | 773 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED); |
| 690 | 774 |
| 691 elms->set(IS_ACCESSOR_INDEX, Heap::false_value()); | 775 elms->set(IS_ACCESSOR_INDEX, Heap::false_value()); |
| 692 elms->set(VALUE_INDEX, *substr); | 776 elms->set(VALUE_INDEX, *substr); |
| 693 elms->set(WRITABLE_INDEX, Heap::false_value()); | 777 elms->set(WRITABLE_INDEX, Heap::false_value()); |
| 694 elms->set(ENUMERABLE_INDEX, Heap::false_value()); | 778 elms->set(ENUMERABLE_INDEX, Heap::false_value()); |
| 695 elms->set(CONFIGURABLE_INDEX, Heap::false_value()); | 779 elms->set(CONFIGURABLE_INDEX, Heap::false_value()); |
| 696 return *desc; | 780 return *desc; |
| 697 } | 781 } |
| 698 | 782 |
| 699 case JSObject::INTERCEPTED_ELEMENT: | 783 case JSObject::INTERCEPTED_ELEMENT: |
| 700 case JSObject::FAST_ELEMENT: { | 784 case JSObject::FAST_ELEMENT: { |
| 701 elms->set(IS_ACCESSOR_INDEX, Heap::false_value()); | 785 elms->set(IS_ACCESSOR_INDEX, Heap::false_value()); |
| 702 Handle<Object> element = GetElement(Handle<Object>(obj), index); | 786 elms->set(VALUE_INDEX, *GetElement(obj, index)); |
| 703 elms->set(VALUE_INDEX, *element); | |
| 704 elms->set(WRITABLE_INDEX, Heap::true_value()); | 787 elms->set(WRITABLE_INDEX, Heap::true_value()); |
| 705 elms->set(ENUMERABLE_INDEX, Heap::true_value()); | 788 elms->set(ENUMERABLE_INDEX, Heap::true_value()); |
| 706 elms->set(CONFIGURABLE_INDEX, Heap::true_value()); | 789 elms->set(CONFIGURABLE_INDEX, Heap::true_value()); |
| 707 return *desc; | 790 return *desc; |
| 708 } | 791 } |
| 709 | 792 |
| 710 case JSObject::DICTIONARY_ELEMENT: { | 793 case JSObject::DICTIONARY_ELEMENT: { |
| 711 NumberDictionary* dictionary = obj->element_dictionary(); | 794 Handle<JSObject> holder = obj; |
| 795 if (obj->IsJSGlobalProxy()) { |
| 796 Object* proto = obj->GetPrototype(); |
| 797 if (proto->IsNull()) return Heap::undefined_value(); |
| 798 ASSERT(proto->IsJSGlobalObject()); |
| 799 holder = Handle<JSObject>(JSObject::cast(proto)); |
| 800 } |
| 801 NumberDictionary* dictionary = holder->element_dictionary(); |
| 712 int entry = dictionary->FindEntry(index); | 802 int entry = dictionary->FindEntry(index); |
| 713 ASSERT(entry != NumberDictionary::kNotFound); | 803 ASSERT(entry != NumberDictionary::kNotFound); |
| 714 PropertyDetails details = dictionary->DetailsAt(entry); | 804 PropertyDetails details = dictionary->DetailsAt(entry); |
| 715 switch (details.type()) { | 805 switch (details.type()) { |
| 716 case CALLBACKS: { | 806 case CALLBACKS: { |
| 717 // This is an accessor property with getter and/or setter. | 807 // This is an accessor property with getter and/or setter. |
| 718 FixedArray* callbacks = | 808 FixedArray* callbacks = |
| 719 FixedArray::cast(dictionary->ValueAt(entry)); | 809 FixedArray::cast(dictionary->ValueAt(entry)); |
| 720 elms->set(IS_ACCESSOR_INDEX, Heap::true_value()); | 810 elms->set(IS_ACCESSOR_INDEX, Heap::true_value()); |
| 721 elms->set(GETTER_INDEX, callbacks->get(0)); | 811 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) { |
| 722 elms->set(SETTER_INDEX, callbacks->get(1)); | 812 elms->set(GETTER_INDEX, callbacks->get(0)); |
| 813 } |
| 814 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) { |
| 815 elms->set(SETTER_INDEX, callbacks->get(1)); |
| 816 } |
| 723 break; | 817 break; |
| 724 } | 818 } |
| 725 case NORMAL: | 819 case NORMAL: |
| 726 // This is a data property. | 820 // This is a data property. |
| 727 elms->set(IS_ACCESSOR_INDEX, Heap::false_value()); | 821 elms->set(IS_ACCESSOR_INDEX, Heap::false_value()); |
| 728 elms->set(VALUE_INDEX, dictionary->ValueAt(entry)); | 822 elms->set(VALUE_INDEX, *GetElement(obj, index)); |
| 729 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly())); | 823 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly())); |
| 730 break; | 824 break; |
| 731 default: | 825 default: |
| 732 UNREACHABLE(); | 826 UNREACHABLE(); |
| 733 break; | 827 break; |
| 734 } | 828 } |
| 735 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum())); | 829 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum())); |
| 736 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete())); | 830 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete())); |
| 737 return *desc; | 831 return *desc; |
| 738 } | 832 } |
| 739 } | 833 } |
| 740 } | 834 } |
| 741 | 835 |
| 742 // Use recursive implementation to also traverse hidden prototypes | 836 // Use recursive implementation to also traverse hidden prototypes |
| 743 GetOwnPropertyImplementation(*obj, *name, &result); | 837 GetOwnPropertyImplementation(*obj, *name, &result); |
| 744 | 838 |
| 745 if (!result.IsProperty()) { | 839 if (!result.IsProperty()) { |
| 746 return Heap::undefined_value(); | 840 return Heap::undefined_value(); |
| 747 } | 841 } |
| 748 | 842 |
| 843 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) { |
| 844 return Heap::false_value(); |
| 845 } |
| 846 |
| 749 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum())); | 847 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum())); |
| 750 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete())); | 848 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete())); |
| 751 | 849 |
| 752 bool is_js_accessor = (result.type() == CALLBACKS) && | 850 bool is_js_accessor = (result.type() == CALLBACKS) && |
| 753 (result.GetCallbackObject()->IsFixedArray()); | 851 (result.GetCallbackObject()->IsFixedArray()); |
| 754 | 852 |
| 755 if (is_js_accessor) { | 853 if (is_js_accessor) { |
| 756 // __defineGetter__/__defineSetter__ callback. | 854 // __defineGetter__/__defineSetter__ callback. |
| 855 elms->set(IS_ACCESSOR_INDEX, Heap::true_value()); |
| 856 |
| 757 FixedArray* structure = FixedArray::cast(result.GetCallbackObject()); | 857 FixedArray* structure = FixedArray::cast(result.GetCallbackObject()); |
| 758 elms->set(IS_ACCESSOR_INDEX, Heap::true_value()); | 858 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) { |
| 759 elms->set(GETTER_INDEX, structure->get(0)); | 859 elms->set(GETTER_INDEX, structure->get(0)); |
| 760 elms->set(SETTER_INDEX, structure->get(1)); | 860 } |
| 861 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) { |
| 862 elms->set(SETTER_INDEX, structure->get(1)); |
| 863 } |
| 761 } else { | 864 } else { |
| 762 elms->set(IS_ACCESSOR_INDEX, Heap::false_value()); | 865 elms->set(IS_ACCESSOR_INDEX, Heap::false_value()); |
| 763 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly())); | 866 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly())); |
| 764 | 867 |
| 765 PropertyAttributes attrs; | 868 PropertyAttributes attrs; |
| 766 Object* value; | 869 Object* value; |
| 870 // GetProperty will check access and report any violations. |
| 767 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs); | 871 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs); |
| 768 if (!maybe_value->ToObject(&value)) return maybe_value; | 872 if (!maybe_value->ToObject(&value)) return maybe_value; |
| 769 } | 873 } |
| 770 elms->set(VALUE_INDEX, value); | 874 elms->set(VALUE_INDEX, value); |
| 771 } | 875 } |
| 772 | 876 |
| 773 return *desc; | 877 return *desc; |
| 774 } | 878 } |
| 775 | 879 |
| 776 | 880 |
| (...skipping 10132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10909 } else { | 11013 } else { |
| 10910 // Handle last resort GC and make sure to allow future allocations | 11014 // Handle last resort GC and make sure to allow future allocations |
| 10911 // to grow the heap without causing GCs (if possible). | 11015 // to grow the heap without causing GCs (if possible). |
| 10912 Counters::gc_last_resort_from_js.Increment(); | 11016 Counters::gc_last_resort_from_js.Increment(); |
| 10913 Heap::CollectAllGarbage(false); | 11017 Heap::CollectAllGarbage(false); |
| 10914 } | 11018 } |
| 10915 } | 11019 } |
| 10916 | 11020 |
| 10917 | 11021 |
| 10918 } } // namespace v8::internal | 11022 } } // namespace v8::internal |
| OLD | NEW |