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