OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
8 #include "src/allocation-site-scopes.h" | 8 #include "src/allocation-site-scopes.h" |
9 #include "src/api.h" | 9 #include "src/api.h" |
10 #include "src/arguments.h" | 10 #include "src/arguments.h" |
(...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
568 | 568 |
569 Handle<Object> argv[] = { value }; | 569 Handle<Object> argv[] = { value }; |
570 RETURN_ON_EXCEPTION(isolate, Execution::Call(isolate, setter, receiver, | 570 RETURN_ON_EXCEPTION(isolate, Execution::Call(isolate, setter, receiver, |
571 ARRAY_SIZE(argv), argv, true), | 571 ARRAY_SIZE(argv), argv, true), |
572 Object); | 572 Object); |
573 return value; | 573 return value; |
574 } | 574 } |
575 | 575 |
576 | 576 |
577 static bool FindAllCanReadHolder(LookupIterator* it) { | 577 static bool FindAllCanReadHolder(LookupIterator* it) { |
578 it->skip_interceptor(); | |
579 it->skip_access_check(); | |
580 for (; it->IsFound(); it->Next()) { | 578 for (; it->IsFound(); it->Next()) { |
581 if (it->state() == LookupIterator::PROPERTY && | 579 if (it->state() == LookupIterator::PROPERTY && |
582 it->HasProperty() && | 580 it->HasProperty() && |
583 it->property_kind() == LookupIterator::ACCESSOR) { | 581 it->property_kind() == LookupIterator::ACCESSOR) { |
584 Handle<Object> accessors = it->GetAccessors(); | 582 Handle<Object> accessors = it->GetAccessors(); |
585 if (accessors->IsAccessorInfo()) { | 583 if (accessors->IsAccessorInfo()) { |
586 if (AccessorInfo::cast(*accessors)->all_can_read()) return true; | 584 if (AccessorInfo::cast(*accessors)->all_can_read()) return true; |
587 } | 585 } |
588 } | 586 } |
589 } | 587 } |
(...skipping 21 matching lines...) Expand all Loading... |
611 if (FindAllCanReadHolder(it)) | 609 if (FindAllCanReadHolder(it)) |
612 return maybe(it->property_details().attributes()); | 610 return maybe(it->property_details().attributes()); |
613 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS); | 611 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS); |
614 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), | 612 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), |
615 Maybe<PropertyAttributes>()); | 613 Maybe<PropertyAttributes>()); |
616 return maybe(ABSENT); | 614 return maybe(ABSENT); |
617 } | 615 } |
618 | 616 |
619 | 617 |
620 static bool FindAllCanWriteHolder(LookupIterator* it) { | 618 static bool FindAllCanWriteHolder(LookupIterator* it) { |
621 it->skip_interceptor(); | |
622 it->skip_access_check(); | |
623 for (; it->IsFound(); it->Next()) { | 619 for (; it->IsFound(); it->Next()) { |
624 if (it->state() == LookupIterator::PROPERTY && it->HasProperty() && | 620 if (it->state() == LookupIterator::PROPERTY && it->HasProperty() && |
625 it->property_kind() == LookupIterator::ACCESSOR) { | 621 it->property_kind() == LookupIterator::ACCESSOR) { |
626 Handle<Object> accessors = it->GetAccessors(); | 622 Handle<Object> accessors = it->GetAccessors(); |
627 if (accessors->IsAccessorInfo()) { | 623 if (accessors->IsAccessorInfo()) { |
628 if (AccessorInfo::cast(*accessors)->all_can_write()) return true; | 624 if (AccessorInfo::cast(*accessors)->all_can_write()) return true; |
629 } | 625 } |
630 } | 626 } |
631 } | 627 } |
632 return false; | 628 return false; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
668 if (object->IsGlobalObject()) { | 664 if (object->IsGlobalObject()) { |
669 value = handle(Handle<PropertyCell>::cast(value)->value(), isolate); | 665 value = handle(Handle<PropertyCell>::cast(value)->value(), isolate); |
670 DCHECK(!value->IsTheHole()); | 666 DCHECK(!value->IsTheHole()); |
671 } | 667 } |
672 DCHECK(!value->IsPropertyCell() && !value->IsCell()); | 668 DCHECK(!value->IsPropertyCell() && !value->IsCell()); |
673 return value; | 669 return value; |
674 } | 670 } |
675 | 671 |
676 | 672 |
677 void JSObject::SetNormalizedProperty(Handle<JSObject> object, | 673 void JSObject::SetNormalizedProperty(Handle<JSObject> object, |
678 const LookupResult* result, | |
679 Handle<Object> value) { | |
680 DCHECK(!object->HasFastProperties()); | |
681 NameDictionary* property_dictionary = object->property_dictionary(); | |
682 if (object->IsGlobalObject()) { | |
683 Handle<PropertyCell> cell(PropertyCell::cast( | |
684 property_dictionary->ValueAt(result->GetDictionaryEntry()))); | |
685 PropertyCell::SetValueInferType(cell, value); | |
686 } else { | |
687 property_dictionary->ValueAtPut(result->GetDictionaryEntry(), *value); | |
688 } | |
689 } | |
690 | |
691 | |
692 void JSObject::SetNormalizedProperty(Handle<JSObject> object, | |
693 Handle<Name> name, | 674 Handle<Name> name, |
694 Handle<Object> value, | 675 Handle<Object> value, |
695 PropertyDetails details) { | 676 PropertyDetails details) { |
696 DCHECK(!object->HasFastProperties()); | 677 DCHECK(!object->HasFastProperties()); |
697 Handle<NameDictionary> property_dictionary(object->property_dictionary()); | 678 Handle<NameDictionary> property_dictionary(object->property_dictionary()); |
698 | 679 |
699 if (!name->IsUniqueName()) { | 680 if (!name->IsUniqueName()) { |
700 name = object->GetIsolate()->factory()->InternalizeString( | 681 name = object->GetIsolate()->factory()->InternalizeString( |
701 Handle<String>::cast(name)); | 682 Handle<String>::cast(name)); |
702 } | 683 } |
(...skipping 1113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1816 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) { | 1797 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) { |
1817 return MaybeHandle<Map>(); | 1798 return MaybeHandle<Map>(); |
1818 } | 1799 } |
1819 | 1800 |
1820 // Allocate new instance descriptors with (name, constant) added. | 1801 // Allocate new instance descriptors with (name, constant) added. |
1821 ConstantDescriptor new_constant_desc(name, constant, attributes); | 1802 ConstantDescriptor new_constant_desc(name, constant, attributes); |
1822 return Map::CopyAddDescriptor(map, &new_constant_desc, flag); | 1803 return Map::CopyAddDescriptor(map, &new_constant_desc, flag); |
1823 } | 1804 } |
1824 | 1805 |
1825 | 1806 |
1826 void JSObject::AddFastProperty(Handle<JSObject> object, | |
1827 Handle<Name> name, | |
1828 Handle<Object> value, | |
1829 PropertyAttributes attributes, | |
1830 StoreFromKeyed store_mode, | |
1831 TransitionFlag flag) { | |
1832 DCHECK(!object->IsJSGlobalProxy()); | |
1833 | |
1834 MaybeHandle<Map> maybe_map; | |
1835 if (value->IsJSFunction()) { | |
1836 maybe_map = Map::CopyWithConstant( | |
1837 handle(object->map()), name, value, attributes, flag); | |
1838 } else if (!object->map()->TooManyFastProperties(store_mode)) { | |
1839 Isolate* isolate = object->GetIsolate(); | |
1840 Representation representation = value->OptimalRepresentation(); | |
1841 maybe_map = Map::CopyWithField( | |
1842 handle(object->map(), isolate), name, | |
1843 value->OptimalType(isolate, representation), | |
1844 attributes, representation, flag); | |
1845 } | |
1846 | |
1847 Handle<Map> new_map; | |
1848 if (!maybe_map.ToHandle(&new_map)) { | |
1849 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); | |
1850 return; | |
1851 } | |
1852 | |
1853 JSObject::MigrateToNewProperty(object, new_map, value); | |
1854 } | |
1855 | |
1856 | |
1857 void JSObject::AddSlowProperty(Handle<JSObject> object, | 1807 void JSObject::AddSlowProperty(Handle<JSObject> object, |
1858 Handle<Name> name, | 1808 Handle<Name> name, |
1859 Handle<Object> value, | 1809 Handle<Object> value, |
1860 PropertyAttributes attributes) { | 1810 PropertyAttributes attributes) { |
1861 DCHECK(!object->HasFastProperties()); | 1811 DCHECK(!object->HasFastProperties()); |
1862 Isolate* isolate = object->GetIsolate(); | 1812 Isolate* isolate = object->GetIsolate(); |
1863 Handle<NameDictionary> dict(object->property_dictionary()); | 1813 Handle<NameDictionary> dict(object->property_dictionary()); |
1864 if (object->IsGlobalObject()) { | 1814 if (object->IsGlobalObject()) { |
1865 // In case name is an orphaned property reuse the cell. | 1815 // In case name is an orphaned property reuse the cell. |
1866 int entry = dict->FindEntry(name); | 1816 int entry = dict->FindEntry(name); |
(...skipping 12 matching lines...) Expand all Loading... |
1879 PropertyCell::SetValueInferType(cell, value); | 1829 PropertyCell::SetValueInferType(cell, value); |
1880 value = cell; | 1830 value = cell; |
1881 } | 1831 } |
1882 PropertyDetails details = PropertyDetails(attributes, NORMAL, 0); | 1832 PropertyDetails details = PropertyDetails(attributes, NORMAL, 0); |
1883 Handle<NameDictionary> result = | 1833 Handle<NameDictionary> result = |
1884 NameDictionary::Add(dict, name, value, details); | 1834 NameDictionary::Add(dict, name, value, details); |
1885 if (*dict != *result) object->set_properties(*result); | 1835 if (*dict != *result) object->set_properties(*result); |
1886 } | 1836 } |
1887 | 1837 |
1888 | 1838 |
1889 MaybeHandle<Object> JSObject::AddPropertyInternal( | |
1890 Handle<JSObject> object, Handle<Name> name, Handle<Object> value, | |
1891 PropertyAttributes attributes, JSReceiver::StoreFromKeyed store_mode, | |
1892 ExtensibilityCheck extensibility_check, TransitionFlag transition_flag) { | |
1893 DCHECK(!object->IsJSGlobalProxy()); | |
1894 Isolate* isolate = object->GetIsolate(); | |
1895 | |
1896 if (!name->IsUniqueName()) { | |
1897 name = isolate->factory()->InternalizeString( | |
1898 Handle<String>::cast(name)); | |
1899 } | |
1900 | |
1901 if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK && | |
1902 !object->map()->is_extensible()) { | |
1903 Handle<Object> args[1] = {name}; | |
1904 Handle<Object> error = isolate->factory()->NewTypeError( | |
1905 "object_not_extensible", HandleVector(args, ARRAY_SIZE(args))); | |
1906 return isolate->Throw<Object>(error); | |
1907 } | |
1908 | |
1909 if (object->HasFastProperties()) { | |
1910 AddFastProperty(object, name, value, attributes, store_mode, | |
1911 transition_flag); | |
1912 } | |
1913 | |
1914 if (!object->HasFastProperties()) { | |
1915 AddSlowProperty(object, name, value, attributes); | |
1916 } | |
1917 | |
1918 if (object->map()->is_observed() && | |
1919 *name != isolate->heap()->hidden_string()) { | |
1920 Handle<Object> old_value = isolate->factory()->the_hole_value(); | |
1921 EnqueueChangeRecord(object, "add", name, old_value); | |
1922 } | |
1923 | |
1924 return value; | |
1925 } | |
1926 | |
1927 | |
1928 Context* JSObject::GetCreationContext() { | 1839 Context* JSObject::GetCreationContext() { |
1929 Object* constructor = this->map()->constructor(); | 1840 Object* constructor = this->map()->constructor(); |
1930 JSFunction* function; | 1841 JSFunction* function; |
1931 if (!constructor->IsJSFunction()) { | 1842 if (!constructor->IsJSFunction()) { |
1932 // Functions have null as a constructor, | 1843 // Functions have null as a constructor, |
1933 // but any JSFunction knows its context immediately. | 1844 // but any JSFunction knows its context immediately. |
1934 function = JSFunction::cast(this); | 1845 function = JSFunction::cast(this); |
1935 } else { | 1846 } else { |
1936 function = JSFunction::cast(constructor); | 1847 function = JSFunction::cast(constructor); |
1937 } | 1848 } |
(...skipping 14 matching lines...) Expand all Loading... |
1952 Handle<Object> args[] = { type, object, name, old_value }; | 1863 Handle<Object> args[] = { type, object, name, old_value }; |
1953 int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4; | 1864 int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4; |
1954 | 1865 |
1955 Execution::Call(isolate, | 1866 Execution::Call(isolate, |
1956 Handle<JSFunction>(isolate->observers_notify_change()), | 1867 Handle<JSFunction>(isolate->observers_notify_change()), |
1957 isolate->factory()->undefined_value(), | 1868 isolate->factory()->undefined_value(), |
1958 argc, args).Assert(); | 1869 argc, args).Assert(); |
1959 } | 1870 } |
1960 | 1871 |
1961 | 1872 |
1962 static void ReplaceSlowProperty(Handle<JSObject> object, | |
1963 Handle<Name> name, | |
1964 Handle<Object> value, | |
1965 PropertyAttributes attributes) { | |
1966 NameDictionary* dictionary = object->property_dictionary(); | |
1967 int old_index = dictionary->FindEntry(name); | |
1968 int new_enumeration_index = 0; // 0 means "Use the next available index." | |
1969 if (old_index != -1) { | |
1970 // All calls to ReplaceSlowProperty have had all transitions removed. | |
1971 new_enumeration_index = dictionary->DetailsAt(old_index).dictionary_index(); | |
1972 } | |
1973 | |
1974 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index); | |
1975 JSObject::SetNormalizedProperty(object, name, value, new_details); | |
1976 } | |
1977 | |
1978 | |
1979 const char* Representation::Mnemonic() const { | 1873 const char* Representation::Mnemonic() const { |
1980 switch (kind_) { | 1874 switch (kind_) { |
1981 case kNone: return "v"; | 1875 case kNone: return "v"; |
1982 case kTagged: return "t"; | 1876 case kTagged: return "t"; |
1983 case kSmi: return "s"; | 1877 case kSmi: return "s"; |
1984 case kDouble: return "d"; | 1878 case kDouble: return "d"; |
1985 case kInteger32: return "i"; | 1879 case kInteger32: return "i"; |
1986 case kHeapObject: return "h"; | 1880 case kHeapObject: return "h"; |
1987 case kExternal: return "x"; | 1881 case kExternal: return "x"; |
1988 default: | 1882 default: |
(...skipping 1033 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3022 return SetDataProperty(it, value); | 2916 return SetDataProperty(it, value); |
3023 } | 2917 } |
3024 } | 2918 } |
3025 done = true; | 2919 done = true; |
3026 break; | 2920 break; |
3027 } | 2921 } |
3028 | 2922 |
3029 if (done) break; | 2923 if (done) break; |
3030 } | 2924 } |
3031 | 2925 |
3032 return AddDataProperty(it, value, NONE, strict_mode, store_mode); | 2926 return AddDataProperty(it, value, NONE, strict_mode, store_mode, |
| 2927 PERFORM_EXTENSIBILITY_CHECK); |
3033 } | 2928 } |
3034 | 2929 |
3035 | 2930 |
3036 MaybeHandle<Object> Object::WriteToReadOnlyProperty(LookupIterator* it, | 2931 MaybeHandle<Object> Object::WriteToReadOnlyProperty(LookupIterator* it, |
3037 Handle<Object> value, | 2932 Handle<Object> value, |
3038 StrictMode strict_mode) { | 2933 StrictMode strict_mode) { |
3039 if (strict_mode != STRICT) return value; | 2934 if (strict_mode != STRICT) return value; |
3040 | 2935 |
3041 Handle<Object> args[] = {it->name(), it->GetReceiver()}; | 2936 Handle<Object> args[] = {it->name(), it->GetReceiver()}; |
3042 Handle<Object> error = it->factory()->NewTypeError( | 2937 Handle<Object> error = it->factory()->NewTypeError( |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3077 } | 2972 } |
3078 | 2973 |
3079 return value; | 2974 return value; |
3080 } | 2975 } |
3081 | 2976 |
3082 | 2977 |
3083 MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it, | 2978 MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it, |
3084 Handle<Object> value, | 2979 Handle<Object> value, |
3085 PropertyAttributes attributes, | 2980 PropertyAttributes attributes, |
3086 StrictMode strict_mode, | 2981 StrictMode strict_mode, |
3087 StoreFromKeyed store_mode) { | 2982 StoreFromKeyed store_mode, |
| 2983 ExtensibilityCheck check) { |
3088 DCHECK(!it->GetReceiver()->IsJSProxy()); | 2984 DCHECK(!it->GetReceiver()->IsJSProxy()); |
3089 if (!it->GetReceiver()->IsJSObject()) { | 2985 if (!it->GetReceiver()->IsJSObject()) { |
3090 // TODO(verwaest): Throw a TypeError with a more specific message. | 2986 // TODO(verwaest): Throw a TypeError with a more specific message. |
3091 return WriteToReadOnlyProperty(it, value, strict_mode); | 2987 return WriteToReadOnlyProperty(it, value, strict_mode); |
3092 } | 2988 } |
3093 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); | 2989 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); |
3094 | 2990 |
3095 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject) | 2991 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject) |
3096 // instead. If the prototype is Null, the proxy is detached. | 2992 // instead. If the prototype is Null, the proxy is detached. |
3097 if (receiver->IsJSGlobalProxy()) { | 2993 if (receiver->IsJSGlobalProxy()) { |
3098 // Trying to assign to a detached proxy. | 2994 // Trying to assign to a detached proxy. |
3099 PrototypeIterator iter(it->isolate(), receiver); | 2995 PrototypeIterator iter(it->isolate(), receiver); |
3100 if (iter.IsAtEnd()) return value; | 2996 if (iter.IsAtEnd()) return value; |
3101 receiver = | 2997 receiver = |
3102 Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter)); | 2998 Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter)); |
3103 } | 2999 } |
3104 | 3000 |
3105 if (!receiver->map()->is_extensible()) { | 3001 if (check == PERFORM_EXTENSIBILITY_CHECK && |
| 3002 !receiver->map()->is_extensible()) { |
3106 if (strict_mode == SLOPPY) return value; | 3003 if (strict_mode == SLOPPY) return value; |
3107 | 3004 |
3108 Handle<Object> args[1] = {it->name()}; | 3005 Handle<Object> args[1] = {it->name()}; |
3109 Handle<Object> error = it->factory()->NewTypeError( | 3006 Handle<Object> error = it->factory()->NewTypeError( |
3110 "object_not_extensible", HandleVector(args, ARRAY_SIZE(args))); | 3007 "object_not_extensible", HandleVector(args, ARRAY_SIZE(args))); |
3111 return it->isolate()->Throw<Object>(error); | 3008 return it->isolate()->Throw<Object>(error); |
3112 } | 3009 } |
3113 | 3010 |
3114 // Possibly migrate to the most up-to-date map that will be able to store | 3011 // Possibly migrate to the most up-to-date map that will be able to store |
3115 // |value| under it->name() with |attributes|. | 3012 // |value| under it->name() with |attributes|. |
(...skipping 820 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3936 return false; | 3833 return false; |
3937 } | 3834 } |
3938 JSObject::MigrateToMap(object, new_map); | 3835 JSObject::MigrateToMap(object, new_map); |
3939 if (FLAG_trace_migration) { | 3836 if (FLAG_trace_migration) { |
3940 object->PrintInstanceMigration(stdout, *original_map, object->map()); | 3837 object->PrintInstanceMigration(stdout, *original_map, object->map()); |
3941 } | 3838 } |
3942 return true; | 3839 return true; |
3943 } | 3840 } |
3944 | 3841 |
3945 | 3842 |
3946 MaybeHandle<Object> JSObject::SetPropertyUsingTransition( | |
3947 Handle<JSObject> object, | |
3948 LookupResult* lookup, | |
3949 Handle<Name> name, | |
3950 Handle<Object> value, | |
3951 PropertyAttributes attributes) { | |
3952 Handle<Map> transition_map(lookup->GetTransitionTarget()); | |
3953 int descriptor = transition_map->LastAdded(); | |
3954 | |
3955 Handle<DescriptorArray> descriptors(transition_map->instance_descriptors()); | |
3956 PropertyDetails details = descriptors->GetDetails(descriptor); | |
3957 | |
3958 if (details.type() == CALLBACKS || attributes != details.attributes()) { | |
3959 // AddPropertyInternal will either normalize the object, or create a new | |
3960 // fast copy of the map. If we get a fast copy of the map, all field | |
3961 // representations will be tagged since the transition is omitted. | |
3962 return JSObject::AddPropertyInternal( | |
3963 object, name, value, attributes, | |
3964 JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED, | |
3965 JSReceiver::OMIT_EXTENSIBILITY_CHECK, OMIT_TRANSITION); | |
3966 } | |
3967 | |
3968 // Keep the target CONSTANT if the same value is stored. | |
3969 // TODO(verwaest): Also support keeping the placeholder | |
3970 // (value->IsUninitialized) as constant. | |
3971 if (!lookup->CanHoldValue(value)) { | |
3972 Representation field_representation = value->OptimalRepresentation(); | |
3973 Handle<HeapType> field_type = value->OptimalType( | |
3974 lookup->isolate(), field_representation); | |
3975 transition_map = Map::GeneralizeRepresentation( | |
3976 transition_map, descriptor, | |
3977 field_representation, field_type, FORCE_FIELD); | |
3978 } | |
3979 | |
3980 JSObject::MigrateToNewProperty(object, transition_map, value); | |
3981 return value; | |
3982 } | |
3983 | |
3984 | |
3985 void JSObject::MigrateToNewProperty(Handle<JSObject> object, | 3843 void JSObject::MigrateToNewProperty(Handle<JSObject> object, |
3986 Handle<Map> map, | 3844 Handle<Map> map, |
3987 Handle<Object> value) { | 3845 Handle<Object> value) { |
3988 JSObject::MigrateToMap(object, map); | 3846 JSObject::MigrateToMap(object, map); |
3989 if (map->GetLastDescriptorDetails().type() != FIELD) return; | 3847 if (map->GetLastDescriptorDetails().type() != FIELD) return; |
3990 object->WriteToField(map->LastAdded(), *value); | 3848 object->WriteToField(map->LastAdded(), *value); |
3991 } | 3849 } |
3992 | 3850 |
3993 | 3851 |
3994 void JSObject::WriteToField(int descriptor, Object* value) { | 3852 void JSObject::WriteToField(int descriptor, Object* value) { |
(...skipping 10 matching lines...) Expand all Loading... |
4005 if (value->IsUninitialized()) return; | 3863 if (value->IsUninitialized()) return; |
4006 HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index)); | 3864 HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index)); |
4007 DCHECK(box->IsMutableHeapNumber()); | 3865 DCHECK(box->IsMutableHeapNumber()); |
4008 box->set_value(value->Number()); | 3866 box->set_value(value->Number()); |
4009 } else { | 3867 } else { |
4010 FastPropertyAtPut(index, value); | 3868 FastPropertyAtPut(index, value); |
4011 } | 3869 } |
4012 } | 3870 } |
4013 | 3871 |
4014 | 3872 |
4015 void JSObject::SetPropertyToField(LookupResult* lookup, Handle<Object> value) { | |
4016 if (lookup->type() == CONSTANT || !lookup->CanHoldValue(value)) { | |
4017 Representation field_representation = value->OptimalRepresentation(); | |
4018 Handle<HeapType> field_type = value->OptimalType( | |
4019 lookup->isolate(), field_representation); | |
4020 JSObject::GeneralizeFieldRepresentation(handle(lookup->holder()), | |
4021 lookup->GetDescriptorIndex(), | |
4022 field_representation, field_type); | |
4023 } | |
4024 lookup->holder()->WriteToField(lookup->GetDescriptorIndex(), *value); | |
4025 } | |
4026 | |
4027 | |
4028 void JSObject::ConvertAndSetOwnProperty(LookupResult* lookup, | |
4029 Handle<Name> name, | |
4030 Handle<Object> value, | |
4031 PropertyAttributes attributes) { | |
4032 Handle<JSObject> object(lookup->holder()); | |
4033 if (object->map()->TooManyFastProperties(Object::MAY_BE_STORE_FROM_KEYED)) { | |
4034 JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); | |
4035 } else if (object->map()->is_prototype_map()) { | |
4036 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0); | |
4037 } | |
4038 | |
4039 if (!object->HasFastProperties()) { | |
4040 ReplaceSlowProperty(object, name, value, attributes); | |
4041 ReoptimizeIfPrototype(object); | |
4042 return; | |
4043 } | |
4044 | |
4045 int descriptor_index = lookup->GetDescriptorIndex(); | |
4046 if (lookup->GetAttributes() == attributes) { | |
4047 JSObject::GeneralizeFieldRepresentation(object, descriptor_index, | |
4048 Representation::Tagged(), | |
4049 HeapType::Any(lookup->isolate())); | |
4050 } else { | |
4051 Handle<Map> old_map(object->map()); | |
4052 Handle<Map> new_map = Map::CopyGeneralizeAllRepresentations(old_map, | |
4053 descriptor_index, FORCE_FIELD, attributes, "attributes mismatch"); | |
4054 JSObject::MigrateToMap(object, new_map); | |
4055 } | |
4056 | |
4057 object->WriteToField(descriptor_index, *value); | |
4058 } | |
4059 | |
4060 | |
4061 void JSObject::SetPropertyToFieldWithAttributes(LookupResult* lookup, | |
4062 Handle<Name> name, | |
4063 Handle<Object> value, | |
4064 PropertyAttributes attributes) { | |
4065 if (lookup->GetAttributes() == attributes) { | |
4066 if (value->IsUninitialized()) return; | |
4067 SetPropertyToField(lookup, value); | |
4068 } else { | |
4069 ConvertAndSetOwnProperty(lookup, name, value, attributes); | |
4070 } | |
4071 } | |
4072 | |
4073 | |
4074 void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name, | 3873 void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name, |
4075 Handle<Object> value, | 3874 Handle<Object> value, |
4076 PropertyAttributes attributes) { | 3875 PropertyAttributes attributes) { |
4077 #ifdef DEBUG | 3876 #ifdef DEBUG |
4078 uint32_t index; | 3877 uint32_t index; |
4079 DCHECK(!object->IsJSProxy()); | 3878 DCHECK(!object->IsJSProxy()); |
4080 DCHECK(!name->AsArrayIndex(&index)); | 3879 DCHECK(!name->AsArrayIndex(&index)); |
4081 LookupIterator it(object, name, LookupIterator::CHECK_OWN_REAL); | 3880 LookupIterator it(object, name, LookupIterator::CHECK_OWN_REAL); |
4082 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it); | 3881 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it); |
4083 DCHECK(maybe.has_value); | 3882 DCHECK(maybe.has_value); |
4084 DCHECK(!it.IsFound()); | 3883 DCHECK(!it.IsFound()); |
4085 DCHECK(object->map()->is_extensible()); | 3884 DCHECK(object->map()->is_extensible()); |
4086 #endif | 3885 #endif |
4087 SetOwnPropertyIgnoreAttributes(object, name, value, attributes, | 3886 SetOwnPropertyIgnoreAttributes(object, name, value, attributes, |
4088 OMIT_EXTENSIBILITY_CHECK).Check(); | 3887 OMIT_EXTENSIBILITY_CHECK).Check(); |
4089 } | 3888 } |
4090 | 3889 |
4091 | 3890 |
4092 // Reconfigures a property to a data property with attributes, even if it is not | 3891 // Reconfigures a property to a data property with attributes, even if it is not |
4093 // reconfigurable. | 3892 // reconfigurable. |
4094 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes( | 3893 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes( |
4095 Handle<JSObject> object, | 3894 Handle<JSObject> object, |
4096 Handle<Name> name, | 3895 Handle<Name> name, |
4097 Handle<Object> value, | 3896 Handle<Object> value, |
4098 PropertyAttributes attributes, | 3897 PropertyAttributes attributes, |
4099 ExtensibilityCheck extensibility_check, | 3898 ExtensibilityCheck extensibility_check, |
4100 StoreFromKeyed store_from_keyed, | 3899 StoreFromKeyed store_from_keyed, |
4101 ExecutableAccessorInfoHandling handling) { | 3900 ExecutableAccessorInfoHandling handling) { |
4102 DCHECK(!value->IsTheHole()); | 3901 DCHECK(!value->IsTheHole()); |
4103 Isolate* isolate = object->GetIsolate(); | 3902 LookupIterator it(object, name, LookupIterator::CHECK_HIDDEN_ACCESS); |
| 3903 bool is_observed = object->map()->is_observed() && |
| 3904 *name != it.isolate()->heap()->hidden_string(); |
| 3905 for (; it.IsFound(); it.Next()) { |
| 3906 switch (it.state()) { |
| 3907 case LookupIterator::NOT_FOUND: |
| 3908 case LookupIterator::JSPROXY: |
| 3909 case LookupIterator::INTERCEPTOR: |
| 3910 UNREACHABLE(); |
4104 | 3911 |
4105 // Make sure that the top context does not change when doing callbacks or | 3912 case LookupIterator::ACCESS_CHECK: |
4106 // interceptor calls. | 3913 if (!it.isolate()->MayNamedAccess(object, name, v8::ACCESS_SET)) { |
4107 AssertNoContextChange ncc(isolate); | 3914 return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY); |
4108 | |
4109 LookupResult lookup(isolate); | |
4110 object->LookupOwn(name, &lookup, true); | |
4111 if (!lookup.IsFound()) { | |
4112 object->map()->LookupTransition(*object, *name, &lookup); | |
4113 } | |
4114 | |
4115 // Check access rights if needed. | |
4116 if (object->IsAccessCheckNeeded()) { | |
4117 if (!isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) { | |
4118 LookupIterator it(object, name, LookupIterator::CHECK_OWN); | |
4119 return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY); | |
4120 } | |
4121 } | |
4122 | |
4123 if (object->IsJSGlobalProxy()) { | |
4124 PrototypeIterator iter(isolate, object); | |
4125 if (iter.IsAtEnd()) return value; | |
4126 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); | |
4127 return SetOwnPropertyIgnoreAttributes( | |
4128 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), name, | |
4129 value, attributes, extensibility_check); | |
4130 } | |
4131 | |
4132 if (lookup.IsInterceptor() || | |
4133 (lookup.IsDescriptorOrDictionary() && lookup.type() == CALLBACKS)) { | |
4134 object->LookupOwnRealNamedProperty(name, &lookup); | |
4135 } | |
4136 | |
4137 // Check for accessor in prototype chain removed here in clone. | |
4138 if (!lookup.IsFound()) { | |
4139 object->map()->LookupTransition(*object, *name, &lookup); | |
4140 TransitionFlag flag = lookup.IsFound() | |
4141 ? OMIT_TRANSITION : INSERT_TRANSITION; | |
4142 // Neither properties nor transitions found. | |
4143 return AddPropertyInternal(object, name, value, attributes, | |
4144 store_from_keyed, extensibility_check, flag); | |
4145 } | |
4146 | |
4147 Handle<Object> old_value = isolate->factory()->the_hole_value(); | |
4148 PropertyAttributes old_attributes = ABSENT; | |
4149 bool is_observed = object->map()->is_observed() && | |
4150 *name != isolate->heap()->hidden_string(); | |
4151 if (is_observed && lookup.IsProperty()) { | |
4152 if (lookup.IsDataProperty()) { | |
4153 old_value = Object::GetPropertyOrElement(object, name).ToHandleChecked(); | |
4154 } | |
4155 old_attributes = lookup.GetAttributes(); | |
4156 } | |
4157 | |
4158 bool executed_set_prototype = false; | |
4159 | |
4160 // Check of IsReadOnly removed from here in clone. | |
4161 if (lookup.IsTransition()) { | |
4162 Handle<Object> result; | |
4163 ASSIGN_RETURN_ON_EXCEPTION( | |
4164 isolate, result, | |
4165 SetPropertyUsingTransition( | |
4166 handle(lookup.holder()), &lookup, name, value, attributes), | |
4167 Object); | |
4168 } else { | |
4169 switch (lookup.type()) { | |
4170 case NORMAL: | |
4171 ReplaceSlowProperty(object, name, value, attributes); | |
4172 break; | |
4173 case FIELD: | |
4174 SetPropertyToFieldWithAttributes(&lookup, name, value, attributes); | |
4175 break; | |
4176 case CONSTANT: | |
4177 // Only replace the constant if necessary. | |
4178 if (lookup.GetAttributes() != attributes || | |
4179 *value != lookup.GetConstant()) { | |
4180 SetPropertyToFieldWithAttributes(&lookup, name, value, attributes); | |
4181 } | 3915 } |
4182 break; | 3916 break; |
4183 case CALLBACKS: | |
4184 { | |
4185 Handle<Object> callback(lookup.GetCallbackObject(), isolate); | |
4186 if (callback->IsExecutableAccessorInfo() && | |
4187 handling == DONT_FORCE_FIELD) { | |
4188 Handle<Object> result; | |
4189 ASSIGN_RETURN_ON_EXCEPTION( | |
4190 isolate, result, JSObject::SetPropertyWithAccessor( | |
4191 object, name, value, handle(lookup.holder()), | |
4192 callback, STRICT), | |
4193 Object); | |
4194 | 3917 |
4195 if (attributes != lookup.GetAttributes()) { | 3918 case LookupIterator::PROPERTY: { |
4196 Handle<ExecutableAccessorInfo> new_data = | 3919 if (!it.HasProperty()) break; |
4197 Accessors::CloneAccessor( | 3920 if (it.HolderIsNonGlobalHiddenPrototype()) break; |
4198 isolate, Handle<ExecutableAccessorInfo>::cast(callback)); | 3921 PropertyDetails details = it.property_details(); |
4199 new_data->set_property_attributes(attributes); | 3922 Handle<Object> old_value = it.isolate()->factory()->the_hole_value(); |
4200 if (attributes & READ_ONLY) { | 3923 switch (it.property_kind()) { |
4201 // This way we don't have to introduce a lookup to the setter, | 3924 case LookupIterator::ACCESSOR: { |
4202 // simply make it unavailable to reflect the attributes. | 3925 // Ensure the context isn't changed after calling into accessors. |
4203 new_data->clear_setter(); | 3926 AssertNoContextChange ncc(it.isolate()); |
| 3927 |
| 3928 Handle<Object> accessors = it.GetAccessors(); |
| 3929 |
| 3930 if (is_observed && accessors->IsAccessorInfo()) { |
| 3931 ASSIGN_RETURN_ON_EXCEPTION( |
| 3932 it.isolate(), old_value, |
| 3933 GetPropertyWithAccessor(it.GetReceiver(), it.name(), |
| 3934 it.GetHolder<JSObject>(), accessors), |
| 3935 Object); |
4204 } | 3936 } |
4205 | 3937 |
4206 SetPropertyCallback(object, name, new_data, attributes); | 3938 // Special handling for ExecutableAccessorInfo, which behaves like a |
| 3939 // data property. |
| 3940 if (handling == DONT_FORCE_FIELD && |
| 3941 accessors->IsExecutableAccessorInfo()) { |
| 3942 Handle<Object> result; |
| 3943 ASSIGN_RETURN_ON_EXCEPTION( |
| 3944 it.isolate(), result, |
| 3945 JSObject::SetPropertyWithAccessor( |
| 3946 it.GetReceiver(), it.name(), value, |
| 3947 it.GetHolder<JSObject>(), accessors, STRICT), |
| 3948 Object); |
| 3949 DCHECK(result->SameValue(*value)); |
| 3950 |
| 3951 if (details.attributes() == attributes) { |
| 3952 // Regular property update if the attributes match. |
| 3953 if (is_observed && !old_value->SameValue(*value)) { |
| 3954 // If we are setting the prototype of a function and are |
| 3955 // observed, don't send change records because the prototype |
| 3956 // handles that itself. |
| 3957 if (!object->IsJSFunction() || |
| 3958 !Name::Equals(it.isolate()->factory()->prototype_string(), |
| 3959 name) || |
| 3960 !Handle<JSFunction>::cast(object) |
| 3961 ->should_have_prototype()) { |
| 3962 EnqueueChangeRecord(object, "update", name, old_value); |
| 3963 } |
| 3964 } |
| 3965 return value; |
| 3966 } |
| 3967 |
| 3968 // Reconfigure the accessor if attributes mismatch. |
| 3969 Handle<ExecutableAccessorInfo> new_data = |
| 3970 Accessors::CloneAccessor( |
| 3971 it.isolate(), |
| 3972 Handle<ExecutableAccessorInfo>::cast(accessors)); |
| 3973 new_data->set_property_attributes(attributes); |
| 3974 // By clearing the setter we don't have to introduce a lookup to |
| 3975 // the setter, simply make it unavailable to reflect the |
| 3976 // attributes. |
| 3977 if (attributes & READ_ONLY) new_data->clear_setter(); |
| 3978 SetPropertyCallback(object, name, new_data, attributes); |
| 3979 if (is_observed) { |
| 3980 if (old_value->SameValue(*value)) { |
| 3981 old_value = it.isolate()->factory()->the_hole_value(); |
| 3982 } |
| 3983 EnqueueChangeRecord(object, "reconfigure", name, old_value); |
| 3984 } |
| 3985 return value; |
| 3986 } |
| 3987 |
| 3988 // Regular accessor. Reconfigure to data property. |
| 3989 break; |
4207 } | 3990 } |
4208 if (is_observed) { | 3991 |
4209 // If we are setting the prototype of a function and are observed, | 3992 case LookupIterator::DATA: |
4210 // don't send change records because the prototype handles that | 3993 // Regular property update if the attributes match. |
4211 // itself. | 3994 if (details.attributes() == attributes) { |
4212 executed_set_prototype = object->IsJSFunction() && | 3995 return SetDataProperty(&it, value); |
4213 String::Equals(isolate->factory()->prototype_string(), | 3996 } |
4214 Handle<String>::cast(name)) && | 3997 // Reconfigure the data property if the attributes mismatch. |
4215 Handle<JSFunction>::cast(object)->should_have_prototype(); | 3998 if (is_observed) old_value = it.GetDataValue(); |
| 3999 } |
| 4000 |
| 4001 it.ReconfigureDataProperty(value, attributes); |
| 4002 it.PrepareForDataProperty(value); |
| 4003 it.WriteDataValue(value); |
| 4004 |
| 4005 if (is_observed) { |
| 4006 if (old_value->SameValue(*value)) { |
| 4007 old_value = it.isolate()->factory()->the_hole_value(); |
4216 } | 4008 } |
4217 } else { | 4009 EnqueueChangeRecord(object, "reconfigure", name, old_value); |
4218 ConvertAndSetOwnProperty(&lookup, name, value, attributes); | |
4219 } | 4010 } |
4220 break; | |
4221 } | |
4222 case NONEXISTENT: | |
4223 case HANDLER: | |
4224 case INTERCEPTOR: | |
4225 UNREACHABLE(); | |
4226 } | |
4227 } | |
4228 | 4011 |
4229 if (is_observed && !executed_set_prototype) { | 4012 return value; |
4230 if (lookup.IsTransition()) { | |
4231 EnqueueChangeRecord(object, "add", name, old_value); | |
4232 } else if (old_value->IsTheHole()) { | |
4233 EnqueueChangeRecord(object, "reconfigure", name, old_value); | |
4234 } else { | |
4235 LookupResult new_lookup(isolate); | |
4236 object->LookupOwn(name, &new_lookup, true); | |
4237 bool value_changed = false; | |
4238 if (new_lookup.IsDataProperty()) { | |
4239 Handle<Object> new_value = | |
4240 Object::GetPropertyOrElement(object, name).ToHandleChecked(); | |
4241 value_changed = !old_value->SameValue(*new_value); | |
4242 } | |
4243 if (new_lookup.GetAttributes() != old_attributes) { | |
4244 if (!value_changed) old_value = isolate->factory()->the_hole_value(); | |
4245 EnqueueChangeRecord(object, "reconfigure", name, old_value); | |
4246 } else if (value_changed) { | |
4247 EnqueueChangeRecord(object, "update", name, old_value); | |
4248 } | 4013 } |
4249 } | 4014 } |
4250 } | 4015 } |
4251 | 4016 |
4252 return value; | 4017 return AddDataProperty(&it, value, attributes, STRICT, store_from_keyed, |
| 4018 extensibility_check); |
4253 } | 4019 } |
4254 | 4020 |
4255 | 4021 |
4256 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( | 4022 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( |
4257 Handle<JSObject> holder, | 4023 Handle<JSObject> holder, |
4258 Handle<Object> receiver, | 4024 Handle<Object> receiver, |
4259 Handle<Name> name) { | 4025 Handle<Name> name) { |
4260 // TODO(rossberg): Support symbols in the API. | 4026 // TODO(rossberg): Support symbols in the API. |
4261 if (name->IsSymbol()) return maybe(ABSENT); | 4027 if (name->IsSymbol()) return maybe(ABSENT); |
4262 | 4028 |
(...skipping 3124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7387 | 7153 |
7388 Handle<Map> result; | 7154 Handle<Map> result; |
7389 if (!maybe_map.ToHandle(&result)) { | 7155 if (!maybe_map.ToHandle(&result)) { |
7390 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES); | 7156 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES); |
7391 } | 7157 } |
7392 | 7158 |
7393 return result; | 7159 return result; |
7394 } | 7160 } |
7395 | 7161 |
7396 | 7162 |
| 7163 Handle<Map> Map::ReconfigureDataProperty(Handle<Map> map, int descriptor, |
| 7164 PropertyAttributes attributes) { |
| 7165 // Dictionaries have to be reconfigured in-place. |
| 7166 DCHECK(!map->is_dictionary_map()); |
| 7167 |
| 7168 // For now, give up on transitioning and just create a unique map. |
| 7169 // TODO(verwaest/ishell): Cache transitions with different attributes. |
| 7170 return CopyGeneralizeAllRepresentations(map, descriptor, FORCE_FIELD, |
| 7171 attributes, "attributes mismatch"); |
| 7172 } |
| 7173 |
| 7174 |
7397 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map, | 7175 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map, |
7398 Descriptor* descriptor, | 7176 Descriptor* descriptor, |
7399 TransitionFlag flag) { | 7177 TransitionFlag flag) { |
7400 Handle<DescriptorArray> descriptors(map->instance_descriptors()); | 7178 Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
7401 | 7179 |
7402 // Ensure the key is unique. | 7180 // Ensure the key is unique. |
7403 descriptor->KeyToUniqueName(); | 7181 descriptor->KeyToUniqueName(); |
7404 | 7182 |
7405 if (flag == INSERT_TRANSITION && | 7183 if (flag == INSERT_TRANSITION && |
7406 map->owns_descriptors() && | 7184 map->owns_descriptors() && |
(...skipping 9522 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16929 #define ERROR_MESSAGES_TEXTS(C, T) T, | 16707 #define ERROR_MESSAGES_TEXTS(C, T) T, |
16930 static const char* error_messages_[] = { | 16708 static const char* error_messages_[] = { |
16931 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) | 16709 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) |
16932 }; | 16710 }; |
16933 #undef ERROR_MESSAGES_TEXTS | 16711 #undef ERROR_MESSAGES_TEXTS |
16934 return error_messages_[reason]; | 16712 return error_messages_[reason]; |
16935 } | 16713 } |
16936 | 16714 |
16937 | 16715 |
16938 } } // namespace v8::internal | 16716 } } // namespace v8::internal |
OLD | NEW |