| 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 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 if (getter->IsSpecFunction()) { | 455 if (getter->IsSpecFunction()) { |
| 456 // TODO(rossberg): nicer would be to cast to some JSCallable here... | 456 // TODO(rossberg): nicer would be to cast to some JSCallable here... |
| 457 return Object::GetPropertyWithDefinedGetter( | 457 return Object::GetPropertyWithDefinedGetter( |
| 458 receiver, Handle<JSReceiver>::cast(getter)); | 458 receiver, Handle<JSReceiver>::cast(getter)); |
| 459 } | 459 } |
| 460 // Getter is not a function. | 460 // Getter is not a function. |
| 461 return isolate->factory()->undefined_value(); | 461 return isolate->factory()->undefined_value(); |
| 462 } | 462 } |
| 463 | 463 |
| 464 | 464 |
| 465 MaybeHandle<Object> Object::SetPropertyWithCallback(Handle<Object> receiver, | 465 MaybeHandle<Object> Object::SetPropertyWithAccessor( |
| 466 Handle<Name> name, | 466 Handle<Object> receiver, Handle<Name> name, Handle<Object> value, |
| 467 Handle<Object> value, | 467 Handle<JSObject> holder, Handle<Object> structure, StrictMode strict_mode) { |
| 468 Handle<JSObject> holder, | |
| 469 Handle<Object> structure, | |
| 470 StrictMode strict_mode) { | |
| 471 Isolate* isolate = name->GetIsolate(); | 468 Isolate* isolate = name->GetIsolate(); |
| 472 | 469 |
| 473 // We should never get here to initialize a const with the hole | 470 // We should never get here to initialize a const with the hole |
| 474 // value since a const declaration would conflict with the setter. | 471 // value since a const declaration would conflict with the setter. |
| 475 ASSERT(!structure->IsForeign()); | 472 ASSERT(!structure->IsForeign()); |
| 476 if (structure->IsExecutableAccessorInfo()) { | 473 if (structure->IsExecutableAccessorInfo()) { |
| 477 // api style callbacks | 474 // api style callbacks |
| 478 ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(*structure); | 475 ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(*structure); |
| 479 if (!data->IsCompatibleReceiver(*receiver)) { | 476 if (!data->IsCompatibleReceiver(*receiver)) { |
| 480 Handle<Object> args[2] = { name, receiver }; | 477 Handle<Object> args[2] = { name, receiver }; |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 PropertyAttributes JSObject::GetPropertyAttributesWithFailedAccessCheck( | 595 PropertyAttributes JSObject::GetPropertyAttributesWithFailedAccessCheck( |
| 599 LookupIterator* it) { | 596 LookupIterator* it) { |
| 600 Handle<JSObject> checked = Handle<JSObject>::cast(it->GetHolder()); | 597 Handle<JSObject> checked = Handle<JSObject>::cast(it->GetHolder()); |
| 601 if (FindAllCanReadHolder(it)) return it->property_details().attributes(); | 598 if (FindAllCanReadHolder(it)) return it->property_details().attributes(); |
| 602 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS); | 599 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS); |
| 603 // TODO(yangguo): Issue 3269, check for scheduled exception missing? | 600 // TODO(yangguo): Issue 3269, check for scheduled exception missing? |
| 604 return ABSENT; | 601 return ABSENT; |
| 605 } | 602 } |
| 606 | 603 |
| 607 | 604 |
| 608 static bool FindAllCanWriteHolder(LookupResult* result, | 605 static bool FindAllCanWriteHolder(LookupIterator* it) { |
| 609 Handle<Name> name, | 606 it->skip_interceptor(); |
| 610 bool check_prototype) { | 607 it->skip_access_check(); |
| 611 if (result->IsInterceptor()) { | 608 for (; it->IsFound(); it->Next()) { |
| 612 result->holder()->LookupOwnRealNamedProperty(name, result); | 609 if (it->state() == LookupIterator::PROPERTY && it->HasProperty() && |
| 613 } | 610 it->property_kind() == LookupIterator::ACCESSOR) { |
| 614 | 611 Handle<Object> accessors = it->GetAccessors(); |
| 615 while (result->IsProperty()) { | 612 if (accessors->IsAccessorInfo()) { |
| 616 if (result->type() == CALLBACKS) { | 613 if (AccessorInfo::cast(*accessors)->all_can_write()) return true; |
| 617 Object* callback_obj = result->GetCallbackObject(); | |
| 618 if (callback_obj->IsAccessorInfo()) { | |
| 619 if (AccessorInfo::cast(callback_obj)->all_can_write()) return true; | |
| 620 } | 614 } |
| 621 } | 615 } |
| 622 if (!check_prototype) break; | |
| 623 result->holder()->LookupRealNamedPropertyInPrototypes(name, result); | |
| 624 } | 616 } |
| 625 return false; | 617 return false; |
| 626 } | 618 } |
| 627 | 619 |
| 628 | 620 |
| 629 MaybeHandle<Object> JSObject::SetPropertyWithFailedAccessCheck( | 621 MaybeHandle<Object> JSObject::SetPropertyWithFailedAccessCheck( |
| 630 Handle<JSObject> object, | 622 LookupIterator* it, Handle<Object> value, StrictMode strict_mode) { |
| 631 LookupResult* result, | 623 Handle<JSObject> checked = Handle<JSObject>::cast(it->GetHolder()); |
| 632 Handle<Name> name, | 624 if (FindAllCanWriteHolder(it)) { |
| 633 Handle<Object> value, | 625 return SetPropertyWithAccessor(it->GetReceiver(), it->name(), value, |
| 634 bool check_prototype, | 626 it->GetHolder(), it->GetAccessors(), |
| 635 StrictMode strict_mode) { | 627 strict_mode); |
| 636 if (check_prototype && !result->IsProperty()) { | |
| 637 object->LookupRealNamedPropertyInPrototypes(name, result); | |
| 638 } | 628 } |
| 639 | 629 |
| 640 if (FindAllCanWriteHolder(result, name, check_prototype)) { | 630 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_SET); |
| 641 Handle<JSObject> holder(result->holder()); | 631 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object); |
| 642 Handle<Object> callbacks(result->GetCallbackObject(), result->isolate()); | |
| 643 return SetPropertyWithCallback( | |
| 644 object, name, value, holder, callbacks, strict_mode); | |
| 645 } | |
| 646 | |
| 647 Isolate* isolate = object->GetIsolate(); | |
| 648 isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET); | |
| 649 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
| 650 return value; | 632 return value; |
| 651 } | 633 } |
| 652 | 634 |
| 653 | 635 |
| 654 Object* JSObject::GetNormalizedProperty(const LookupResult* result) { | 636 Object* JSObject::GetNormalizedProperty(const LookupResult* result) { |
| 655 ASSERT(!HasFastProperties()); | 637 ASSERT(!HasFastProperties()); |
| 656 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry()); | 638 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry()); |
| 657 if (IsGlobalObject()) { | 639 if (IsGlobalObject()) { |
| 658 value = PropertyCell::cast(value)->value(); | 640 value = PropertyCell::cast(value)->value(); |
| 659 } | 641 } |
| (...skipping 1168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1828 Handle<Object> value, | 1810 Handle<Object> value, |
| 1829 PropertyAttributes attributes, | 1811 PropertyAttributes attributes, |
| 1830 StoreFromKeyed store_mode, | 1812 StoreFromKeyed store_mode, |
| 1831 TransitionFlag flag) { | 1813 TransitionFlag flag) { |
| 1832 ASSERT(!object->IsJSGlobalProxy()); | 1814 ASSERT(!object->IsJSGlobalProxy()); |
| 1833 | 1815 |
| 1834 MaybeHandle<Map> maybe_map; | 1816 MaybeHandle<Map> maybe_map; |
| 1835 if (value->IsJSFunction()) { | 1817 if (value->IsJSFunction()) { |
| 1836 maybe_map = Map::CopyWithConstant( | 1818 maybe_map = Map::CopyWithConstant( |
| 1837 handle(object->map()), name, value, attributes, flag); | 1819 handle(object->map()), name, value, attributes, flag); |
| 1838 } else if (!object->TooManyFastProperties(store_mode)) { | 1820 } else if (!object->map()->TooManyFastProperties(store_mode)) { |
| 1839 Isolate* isolate = object->GetIsolate(); | 1821 Isolate* isolate = object->GetIsolate(); |
| 1840 Representation representation = value->OptimalRepresentation(); | 1822 Representation representation = value->OptimalRepresentation(); |
| 1841 maybe_map = Map::CopyWithField( | 1823 maybe_map = Map::CopyWithField( |
| 1842 handle(object->map(), isolate), name, | 1824 handle(object->map(), isolate), name, |
| 1843 value->OptimalType(isolate, representation), | 1825 value->OptimalType(isolate, representation), |
| 1844 attributes, representation, flag); | 1826 attributes, representation, flag); |
| 1845 } | 1827 } |
| 1846 | 1828 |
| 1847 Handle<Map> new_map; | 1829 Handle<Map> new_map; |
| 1848 if (!maybe_map.ToHandle(&new_map)) { | 1830 if (!maybe_map.ToHandle(&new_map)) { |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1962 Handle<Object> args[] = { type, object, name, old_value }; | 1944 Handle<Object> args[] = { type, object, name, old_value }; |
| 1963 int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4; | 1945 int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4; |
| 1964 | 1946 |
| 1965 Execution::Call(isolate, | 1947 Execution::Call(isolate, |
| 1966 Handle<JSFunction>(isolate->observers_notify_change()), | 1948 Handle<JSFunction>(isolate->observers_notify_change()), |
| 1967 isolate->factory()->undefined_value(), | 1949 isolate->factory()->undefined_value(), |
| 1968 argc, args).Assert(); | 1950 argc, args).Assert(); |
| 1969 } | 1951 } |
| 1970 | 1952 |
| 1971 | 1953 |
| 1972 MaybeHandle<Object> JSObject::SetPropertyPostInterceptor( | |
| 1973 Handle<JSObject> object, | |
| 1974 Handle<Name> name, | |
| 1975 Handle<Object> value, | |
| 1976 StrictMode strict_mode) { | |
| 1977 // Check own property, ignore interceptor. | |
| 1978 Isolate* isolate = object->GetIsolate(); | |
| 1979 LookupResult result(isolate); | |
| 1980 object->LookupOwnRealNamedProperty(name, &result); | |
| 1981 if (!result.IsFound()) { | |
| 1982 object->map()->LookupTransition(*object, *name, &result); | |
| 1983 } | |
| 1984 return SetPropertyForResult(object, &result, name, value, strict_mode, | |
| 1985 MAY_BE_STORE_FROM_KEYED); | |
| 1986 } | |
| 1987 | |
| 1988 | |
| 1989 static void ReplaceSlowProperty(Handle<JSObject> object, | 1954 static void ReplaceSlowProperty(Handle<JSObject> object, |
| 1990 Handle<Name> name, | 1955 Handle<Name> name, |
| 1991 Handle<Object> value, | 1956 Handle<Object> value, |
| 1992 PropertyAttributes attributes) { | 1957 PropertyAttributes attributes) { |
| 1993 NameDictionary* dictionary = object->property_dictionary(); | 1958 NameDictionary* dictionary = object->property_dictionary(); |
| 1994 int old_index = dictionary->FindEntry(name); | 1959 int old_index = dictionary->FindEntry(name); |
| 1995 int new_enumeration_index = 0; // 0 means "Use the next available index." | 1960 int new_enumeration_index = 0; // 0 means "Use the next available index." |
| 1996 if (old_index != -1) { | 1961 if (old_index != -1) { |
| 1997 // All calls to ReplaceSlowProperty have had all transitions removed. | 1962 // All calls to ReplaceSlowProperty have had all transitions removed. |
| 1998 new_enumeration_index = dictionary->DetailsAt(old_index).dictionary_index(); | 1963 new_enumeration_index = dictionary->DetailsAt(old_index).dictionary_index(); |
| (...skipping 966 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2965 case INTERCEPTOR: | 2930 case INTERCEPTOR: |
| 2966 case NONEXISTENT: | 2931 case NONEXISTENT: |
| 2967 UNREACHABLE(); | 2932 UNREACHABLE(); |
| 2968 } | 2933 } |
| 2969 } | 2934 } |
| 2970 if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>(); | 2935 if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>(); |
| 2971 return handle(new_map); | 2936 return handle(new_map); |
| 2972 } | 2937 } |
| 2973 | 2938 |
| 2974 | 2939 |
| 2975 MaybeHandle<Object> JSObject::SetPropertyWithInterceptor( | 2940 MaybeHandle<Object> JSObject::SetPropertyWithInterceptor(LookupIterator* it, |
| 2976 Handle<JSObject> object, | 2941 Handle<Object> value) { |
| 2977 Handle<Name> name, | |
| 2978 Handle<Object> value, | |
| 2979 StrictMode strict_mode) { | |
| 2980 // TODO(rossberg): Support symbols in the API. | 2942 // TODO(rossberg): Support symbols in the API. |
| 2981 if (name->IsSymbol()) return value; | 2943 if (it->name()->IsSymbol()) return value; |
| 2982 Isolate* isolate = object->GetIsolate(); | 2944 |
| 2983 Handle<String> name_string = Handle<String>::cast(name); | 2945 Handle<String> name_string = Handle<String>::cast(it->name()); |
| 2984 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor()); | 2946 Handle<JSObject> holder = it->GetHolder(); |
| 2985 if (!interceptor->setter()->IsUndefined()) { | 2947 Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor()); |
| 2986 LOG(isolate, | 2948 if (interceptor->setter()->IsUndefined()) return MaybeHandle<Object>(); |
| 2987 ApiNamedPropertyAccess("interceptor-named-set", *object, *name)); | 2949 |
| 2988 PropertyCallbackArguments args( | 2950 LOG(it->isolate(), |
| 2989 isolate, interceptor->data(), *object, *object); | 2951 ApiNamedPropertyAccess("interceptor-named-set", *holder, *name_string)); |
| 2990 v8::NamedPropertySetterCallback setter = | 2952 PropertyCallbackArguments args(it->isolate(), interceptor->data(), *holder, |
| 2991 v8::ToCData<v8::NamedPropertySetterCallback>(interceptor->setter()); | 2953 *holder); |
| 2992 v8::Handle<v8::Value> result = args.Call( | 2954 v8::NamedPropertySetterCallback setter = |
| 2993 setter, v8::Utils::ToLocal(name_string), v8::Utils::ToLocal(value)); | 2955 v8::ToCData<v8::NamedPropertySetterCallback>(interceptor->setter()); |
| 2994 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | 2956 v8::Handle<v8::Value> result = args.Call( |
| 2995 if (!result.IsEmpty()) return value; | 2957 setter, v8::Utils::ToLocal(name_string), v8::Utils::ToLocal(value)); |
| 2996 } | 2958 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object); |
| 2997 return SetPropertyPostInterceptor(object, name, value, strict_mode); | 2959 if (!result.IsEmpty()) return value; |
| 2960 |
| 2961 return MaybeHandle<Object>(); |
| 2998 } | 2962 } |
| 2999 | 2963 |
| 3000 | 2964 |
| 3001 MaybeHandle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object, | 2965 MaybeHandle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object, |
| 3002 Handle<Name> name, | 2966 Handle<Name> name, |
| 3003 Handle<Object> value, | 2967 Handle<Object> value, |
| 3004 StrictMode strict_mode, | 2968 StrictMode strict_mode, |
| 3005 StoreFromKeyed store_mode) { | 2969 StoreFromKeyed store_mode) { |
| 3006 LookupResult result(object->GetIsolate()); | 2970 LookupIterator it(object, name); |
| 3007 object->LookupOwn(name, &result, true); | 2971 return Object::SetProperty(&it, value, strict_mode, store_mode); |
| 3008 if (!result.IsFound()) { | |
| 3009 object->map()->LookupTransition(JSObject::cast(*object), *name, &result); | |
| 3010 } | |
| 3011 return SetProperty(object, &result, name, value, strict_mode, store_mode); | |
| 3012 } | 2972 } |
| 3013 | 2973 |
| 3014 | 2974 |
| 2975 MaybeHandle<Object> Object::SetProperty(LookupIterator* it, |
| 2976 Handle<Object> value, |
| 2977 StrictMode strict_mode, |
| 2978 StoreFromKeyed store_mode) { |
| 2979 // Make sure that the top context does not change when doing callbacks or |
| 2980 // interceptor calls. |
| 2981 AssertNoContextChange ncc(it->isolate()); |
| 2982 |
| 2983 bool done = false; |
| 2984 for (; it->IsFound(); it->Next()) { |
| 2985 switch (it->state()) { |
| 2986 case LookupIterator::NOT_FOUND: |
| 2987 UNREACHABLE(); |
| 2988 |
| 2989 case LookupIterator::ACCESS_CHECK: |
| 2990 // TODO(verwaest): Remove the distinction. This is mostly bogus since we |
| 2991 // don't know whether we'll want to fetch attributes or call a setter |
| 2992 // until we find the property. |
| 2993 if (it->HasAccess(v8::ACCESS_SET)) break; |
| 2994 return JSObject::SetPropertyWithFailedAccessCheck(it, value, |
| 2995 strict_mode); |
| 2996 |
| 2997 case LookupIterator::JSPROXY: |
| 2998 if (it->HolderIsReceiver()) { |
| 2999 return JSProxy::SetPropertyWithHandler(it->GetJSProxy(), |
| 3000 it->GetReceiver(), it->name(), |
| 3001 value, strict_mode); |
| 3002 } else { |
| 3003 // TODO(verwaest): Use the MaybeHandle to indicate result. |
| 3004 bool has_result = false; |
| 3005 MaybeHandle<Object> maybe_result = |
| 3006 JSProxy::SetPropertyViaPrototypesWithHandler( |
| 3007 it->GetJSProxy(), it->GetReceiver(), it->name(), value, |
| 3008 strict_mode, &has_result); |
| 3009 if (has_result) return maybe_result; |
| 3010 done = true; |
| 3011 } |
| 3012 break; |
| 3013 |
| 3014 case LookupIterator::INTERCEPTOR: |
| 3015 if (it->HolderIsReceiver()) { |
| 3016 MaybeHandle<Object> maybe_result = |
| 3017 JSObject::SetPropertyWithInterceptor(it, value); |
| 3018 if (!maybe_result.is_null()) return maybe_result; |
| 3019 if (it->isolate()->has_pending_exception()) return maybe_result; |
| 3020 } else { |
| 3021 Maybe<PropertyAttributes> maybe_attributes = |
| 3022 JSObject::GetPropertyAttributesWithInterceptor( |
| 3023 it->GetHolder(), it->GetReceiver(), it->name()); |
| 3024 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object); |
| 3025 done = maybe_attributes.has_value; |
| 3026 if (done && (maybe_attributes.value & READ_ONLY) != 0) { |
| 3027 return WriteToReadOnlyProperty(it, value, strict_mode); |
| 3028 } |
| 3029 } |
| 3030 break; |
| 3031 |
| 3032 case LookupIterator::PROPERTY: |
| 3033 if (!it->HasProperty()) break; |
| 3034 if (it->property_details().IsReadOnly()) { |
| 3035 return WriteToReadOnlyProperty(it, value, strict_mode); |
| 3036 } |
| 3037 switch (it->property_kind()) { |
| 3038 case LookupIterator::ACCESSOR: |
| 3039 if (it->HolderIsReceiver() || |
| 3040 !it->GetAccessors()->IsDeclaredAccessorInfo()) { |
| 3041 return SetPropertyWithAccessor(it->GetReceiver(), it->name(), |
| 3042 value, it->GetHolder(), |
| 3043 it->GetAccessors(), strict_mode); |
| 3044 } |
| 3045 break; |
| 3046 case LookupIterator::DATA: |
| 3047 if (it->HolderIsReceiver()) return SetDataProperty(it, value); |
| 3048 } |
| 3049 done = true; |
| 3050 break; |
| 3051 } |
| 3052 |
| 3053 if (done) break; |
| 3054 } |
| 3055 |
| 3056 return AddDataProperty(it, value, NONE, strict_mode, store_mode); |
| 3057 } |
| 3058 |
| 3059 |
| 3060 MaybeHandle<Object> Object::WriteToReadOnlyProperty(LookupIterator* it, |
| 3061 Handle<Object> value, |
| 3062 StrictMode strict_mode) { |
| 3063 if (strict_mode != STRICT) return value; |
| 3064 |
| 3065 Handle<Object> args[] = {it->name(), it->GetReceiver()}; |
| 3066 Handle<Object> error = it->factory()->NewTypeError( |
| 3067 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))); |
| 3068 return it->isolate()->Throw<Object>(error); |
| 3069 } |
| 3070 |
| 3071 |
| 3072 MaybeHandle<Object> Object::SetDataProperty(LookupIterator* it, |
| 3073 Handle<Object> value) { |
| 3074 // Proxies are handled on the WithHandler path. Other non-JSObjects cannot |
| 3075 // have own properties. |
| 3076 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); |
| 3077 |
| 3078 // Store on the holder which may be hidden behind the receiver. |
| 3079 ASSERT(it->HolderIsReceiver()); |
| 3080 |
| 3081 // Old value for the observation change record. |
| 3082 // Fetch before transforming the object since the encoding may become |
| 3083 // incompatible with what's cached in |it|. |
| 3084 bool is_observed = |
| 3085 receiver->map()->is_observed() && |
| 3086 !it->name().is_identical_to(it->factory()->hidden_string()); |
| 3087 MaybeHandle<Object> maybe_old; |
| 3088 if (is_observed) maybe_old = it->GetDataValue(); |
| 3089 |
| 3090 // Possibly migrate to the most up-to-date map that will be able to store |
| 3091 // |value| under it->name(). |
| 3092 it->PrepareForDataProperty(value); |
| 3093 |
| 3094 // Write the property value. |
| 3095 it->WriteDataValue(value); |
| 3096 |
| 3097 // Send the change record if there are observers. |
| 3098 if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) { |
| 3099 JSObject::EnqueueChangeRecord(receiver, "update", it->name(), |
| 3100 maybe_old.ToHandleChecked()); |
| 3101 } |
| 3102 |
| 3103 return value; |
| 3104 } |
| 3105 |
| 3106 |
| 3107 MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it, |
| 3108 Handle<Object> value, |
| 3109 PropertyAttributes attributes, |
| 3110 StrictMode strict_mode, |
| 3111 StoreFromKeyed store_mode) { |
| 3112 ASSERT(!it->GetReceiver()->IsJSProxy()); |
| 3113 // Transitions to data properties of value wrappers are not observable. |
| 3114 if (!it->GetReceiver()->IsJSObject()) return value; |
| 3115 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); |
| 3116 |
| 3117 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject) |
| 3118 // instead. If the prototype is Null, the proxy is detached. |
| 3119 if (receiver->IsJSGlobalProxy()) { |
| 3120 // Trying to assign to a detached proxy. |
| 3121 PrototypeIterator iter(it->isolate(), receiver); |
| 3122 if (iter.IsAtEnd()) return value; |
| 3123 receiver = |
| 3124 Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter)); |
| 3125 } |
| 3126 |
| 3127 if (!receiver->map()->is_extensible()) { |
| 3128 if (strict_mode == SLOPPY) return value; |
| 3129 |
| 3130 Handle<Object> args[1] = {it->name()}; |
| 3131 Handle<Object> error = it->factory()->NewTypeError( |
| 3132 "object_not_extensible", HandleVector(args, ARRAY_SIZE(args))); |
| 3133 return it->isolate()->Throw<Object>(error); |
| 3134 } |
| 3135 |
| 3136 // Possibly migrate to the most up-to-date map that will be able to store |
| 3137 // |value| under it->name() with |attributes|. |
| 3138 it->TransitionToDataProperty(value, attributes, store_mode); |
| 3139 |
| 3140 // TODO(verwaest): Encapsulate dictionary handling better. |
| 3141 if (receiver->map()->is_dictionary_map()) { |
| 3142 // TODO(verwaest): Probably should ensure this is done beforehand. |
| 3143 it->InternalizeName(); |
| 3144 JSObject::AddSlowProperty(receiver, it->name(), value, attributes); |
| 3145 } else { |
| 3146 // Write the property value. |
| 3147 it->WriteDataValue(value); |
| 3148 } |
| 3149 |
| 3150 // Send the change record if there are observers. |
| 3151 if (receiver->map()->is_observed() && |
| 3152 !it->name().is_identical_to(it->factory()->hidden_string())) { |
| 3153 JSObject::EnqueueChangeRecord(receiver, "add", it->name(), |
| 3154 it->factory()->the_hole_value()); |
| 3155 } |
| 3156 |
| 3157 return value; |
| 3158 } |
| 3159 |
| 3160 |
| 3015 MaybeHandle<Object> JSObject::SetElementWithCallbackSetterInPrototypes( | 3161 MaybeHandle<Object> JSObject::SetElementWithCallbackSetterInPrototypes( |
| 3016 Handle<JSObject> object, | 3162 Handle<JSObject> object, |
| 3017 uint32_t index, | 3163 uint32_t index, |
| 3018 Handle<Object> value, | 3164 Handle<Object> value, |
| 3019 bool* found, | 3165 bool* found, |
| 3020 StrictMode strict_mode) { | 3166 StrictMode strict_mode) { |
| 3021 Isolate *isolate = object->GetIsolate(); | 3167 Isolate *isolate = object->GetIsolate(); |
| 3022 for (PrototypeIterator iter(isolate, object); !iter.IsAtEnd(); | 3168 for (PrototypeIterator iter(isolate, object); !iter.IsAtEnd(); |
| 3023 iter.Advance()) { | 3169 iter.Advance()) { |
| 3024 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | 3170 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3042 return SetElementWithCallback(object, structure, index, value, js_proto, | 3188 return SetElementWithCallback(object, structure, index, value, js_proto, |
| 3043 strict_mode); | 3189 strict_mode); |
| 3044 } | 3190 } |
| 3045 } | 3191 } |
| 3046 } | 3192 } |
| 3047 *found = false; | 3193 *found = false; |
| 3048 return isolate->factory()->the_hole_value(); | 3194 return isolate->factory()->the_hole_value(); |
| 3049 } | 3195 } |
| 3050 | 3196 |
| 3051 | 3197 |
| 3052 MaybeHandle<Object> JSObject::SetPropertyViaPrototypes( | |
| 3053 Handle<JSObject> object, | |
| 3054 Handle<Name> name, | |
| 3055 Handle<Object> value, | |
| 3056 StrictMode strict_mode, | |
| 3057 bool* done) { | |
| 3058 Isolate* isolate = object->GetIsolate(); | |
| 3059 | |
| 3060 *done = false; | |
| 3061 // We could not find an own property, so let's check whether there is an | |
| 3062 // accessor that wants to handle the property, or whether the property is | |
| 3063 // read-only on the prototype chain. | |
| 3064 LookupResult result(isolate); | |
| 3065 object->LookupRealNamedPropertyInPrototypes(name, &result); | |
| 3066 if (result.IsFound()) { | |
| 3067 switch (result.type()) { | |
| 3068 case NORMAL: | |
| 3069 case FIELD: | |
| 3070 case CONSTANT: | |
| 3071 *done = result.IsReadOnly(); | |
| 3072 break; | |
| 3073 case INTERCEPTOR: { | |
| 3074 LookupIterator it(object, name, handle(result.holder())); | |
| 3075 PropertyAttributes attr = GetPropertyAttributes(&it); | |
| 3076 *done = !!(attr & READ_ONLY); | |
| 3077 break; | |
| 3078 } | |
| 3079 case CALLBACKS: { | |
| 3080 *done = true; | |
| 3081 if (!result.IsReadOnly()) { | |
| 3082 Handle<Object> callback_object(result.GetCallbackObject(), isolate); | |
| 3083 return SetPropertyWithCallback(object, name, value, | |
| 3084 handle(result.holder()), | |
| 3085 callback_object, strict_mode); | |
| 3086 } | |
| 3087 break; | |
| 3088 } | |
| 3089 case HANDLER: { | |
| 3090 Handle<JSProxy> proxy(result.proxy()); | |
| 3091 return JSProxy::SetPropertyViaPrototypesWithHandler( | |
| 3092 proxy, object, name, value, strict_mode, done); | |
| 3093 } | |
| 3094 case NONEXISTENT: | |
| 3095 UNREACHABLE(); | |
| 3096 break; | |
| 3097 } | |
| 3098 } | |
| 3099 | |
| 3100 // If we get here with *done true, we have encountered a read-only property. | |
| 3101 if (*done) { | |
| 3102 if (strict_mode == SLOPPY) return value; | |
| 3103 Handle<Object> args[] = { name, object }; | |
| 3104 Handle<Object> error = isolate->factory()->NewTypeError( | |
| 3105 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))); | |
| 3106 return isolate->Throw<Object>(error); | |
| 3107 } | |
| 3108 return isolate->factory()->the_hole_value(); | |
| 3109 } | |
| 3110 | |
| 3111 | |
| 3112 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { | 3198 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { |
| 3113 // Only supports adding slack to owned descriptors. | 3199 // Only supports adding slack to owned descriptors. |
| 3114 ASSERT(map->owns_descriptors()); | 3200 ASSERT(map->owns_descriptors()); |
| 3115 | 3201 |
| 3116 Handle<DescriptorArray> descriptors(map->instance_descriptors()); | 3202 Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
| 3117 int old_size = map->NumberOfOwnDescriptors(); | 3203 int old_size = map->NumberOfOwnDescriptors(); |
| 3118 if (slack <= descriptors->NumberOfSlackDescriptors()) return; | 3204 if (slack <= descriptors->NumberOfSlackDescriptors()) return; |
| 3119 | 3205 |
| 3120 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( | 3206 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( |
| 3121 descriptors, old_size, slack); | 3207 descriptors, old_size, slack); |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3501 return result->HandlerResult(JSProxy::cast(iter.GetCurrent())); | 3587 return result->HandlerResult(JSProxy::cast(iter.GetCurrent())); |
| 3502 } | 3588 } |
| 3503 JSObject::cast(iter.GetCurrent())->LookupOwnRealNamedProperty(name, result); | 3589 JSObject::cast(iter.GetCurrent())->LookupOwnRealNamedProperty(name, result); |
| 3504 ASSERT(!(result->IsFound() && result->type() == INTERCEPTOR)); | 3590 ASSERT(!(result->IsFound() && result->type() == INTERCEPTOR)); |
| 3505 if (result->IsFound()) return; | 3591 if (result->IsFound()) return; |
| 3506 } | 3592 } |
| 3507 result->NotFound(); | 3593 result->NotFound(); |
| 3508 } | 3594 } |
| 3509 | 3595 |
| 3510 | 3596 |
| 3511 MaybeHandle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object, | |
| 3512 LookupResult* result, | |
| 3513 Handle<Name> key, | |
| 3514 Handle<Object> value, | |
| 3515 StrictMode strict_mode, | |
| 3516 StoreFromKeyed store_mode) { | |
| 3517 if (result->IsHandler()) { | |
| 3518 return JSProxy::SetPropertyWithHandler(handle(result->proxy()), object, key, | |
| 3519 value, strict_mode); | |
| 3520 } else { | |
| 3521 return JSObject::SetPropertyForResult(Handle<JSObject>::cast(object), | |
| 3522 result, key, value, strict_mode, | |
| 3523 store_mode); | |
| 3524 } | |
| 3525 } | |
| 3526 | |
| 3527 | |
| 3528 bool JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy, Handle<Name> name) { | 3597 bool JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy, Handle<Name> name) { |
| 3529 Isolate* isolate = proxy->GetIsolate(); | 3598 Isolate* isolate = proxy->GetIsolate(); |
| 3530 | 3599 |
| 3531 // TODO(rossberg): adjust once there is a story for symbols vs proxies. | 3600 // TODO(rossberg): adjust once there is a story for symbols vs proxies. |
| 3532 if (name->IsSymbol()) return false; | 3601 if (name->IsSymbol()) return false; |
| 3533 | 3602 |
| 3534 Handle<Object> args[] = { name }; | 3603 Handle<Object> args[] = { name }; |
| 3535 Handle<Object> result; | 3604 Handle<Object> result; |
| 3536 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 3605 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 3537 isolate, result, | 3606 isolate, result, |
| 3538 CallTrap(proxy, | 3607 CallTrap(proxy, |
| 3539 "has", | 3608 "has", |
| 3540 isolate->derived_has_trap(), | 3609 isolate->derived_has_trap(), |
| 3541 ARRAY_SIZE(args), | 3610 ARRAY_SIZE(args), |
| 3542 args), | 3611 args), |
| 3543 false); | 3612 false); |
| 3544 | 3613 |
| 3545 return result->BooleanValue(); | 3614 return result->BooleanValue(); |
| 3546 } | 3615 } |
| 3547 | 3616 |
| 3548 | 3617 |
| 3549 MaybeHandle<Object> JSProxy::SetPropertyWithHandler( | 3618 MaybeHandle<Object> JSProxy::SetPropertyWithHandler(Handle<JSProxy> proxy, |
| 3550 Handle<JSProxy> proxy, | 3619 Handle<Object> receiver, |
| 3551 Handle<JSReceiver> receiver, | 3620 Handle<Name> name, |
| 3552 Handle<Name> name, | 3621 Handle<Object> value, |
| 3553 Handle<Object> value, | 3622 StrictMode strict_mode) { |
| 3554 StrictMode strict_mode) { | |
| 3555 Isolate* isolate = proxy->GetIsolate(); | 3623 Isolate* isolate = proxy->GetIsolate(); |
| 3556 | 3624 |
| 3557 // TODO(rossberg): adjust once there is a story for symbols vs proxies. | 3625 // TODO(rossberg): adjust once there is a story for symbols vs proxies. |
| 3558 if (name->IsSymbol()) return value; | 3626 if (name->IsSymbol()) return value; |
| 3559 | 3627 |
| 3560 Handle<Object> args[] = { receiver, name, value }; | 3628 Handle<Object> args[] = { receiver, name, value }; |
| 3561 RETURN_ON_EXCEPTION( | 3629 RETURN_ON_EXCEPTION( |
| 3562 isolate, | 3630 isolate, |
| 3563 CallTrap(proxy, | 3631 CallTrap(proxy, |
| 3564 "set", | 3632 "set", |
| 3565 isolate->derived_set_trap(), | 3633 isolate->derived_set_trap(), |
| 3566 ARRAY_SIZE(args), | 3634 ARRAY_SIZE(args), |
| 3567 args), | 3635 args), |
| 3568 Object); | 3636 Object); |
| 3569 | 3637 |
| 3570 return value; | 3638 return value; |
| 3571 } | 3639 } |
| 3572 | 3640 |
| 3573 | 3641 |
| 3574 MaybeHandle<Object> JSProxy::SetPropertyViaPrototypesWithHandler( | 3642 MaybeHandle<Object> JSProxy::SetPropertyViaPrototypesWithHandler( |
| 3575 Handle<JSProxy> proxy, | 3643 Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name, |
| 3576 Handle<JSReceiver> receiver, | 3644 Handle<Object> value, StrictMode strict_mode, bool* done) { |
| 3577 Handle<Name> name, | |
| 3578 Handle<Object> value, | |
| 3579 StrictMode strict_mode, | |
| 3580 bool* done) { | |
| 3581 Isolate* isolate = proxy->GetIsolate(); | 3645 Isolate* isolate = proxy->GetIsolate(); |
| 3582 Handle<Object> handler(proxy->handler(), isolate); // Trap might morph proxy. | 3646 Handle<Object> handler(proxy->handler(), isolate); // Trap might morph proxy. |
| 3583 | 3647 |
| 3584 // TODO(rossberg): adjust once there is a story for symbols vs proxies. | 3648 // TODO(rossberg): adjust once there is a story for symbols vs proxies. |
| 3585 if (name->IsSymbol()) { | 3649 if (name->IsSymbol()) { |
| 3586 *done = false; | 3650 *done = false; |
| 3587 return isolate->factory()->the_hole_value(); | 3651 return isolate->factory()->the_hole_value(); |
| 3588 } | 3652 } |
| 3589 | 3653 |
| 3590 *done = true; // except where redefined... | 3654 *done = true; // except where redefined... |
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3989 } | 4053 } |
| 3990 lookup->holder()->WriteToField(lookup->GetDescriptorIndex(), *value); | 4054 lookup->holder()->WriteToField(lookup->GetDescriptorIndex(), *value); |
| 3991 } | 4055 } |
| 3992 | 4056 |
| 3993 | 4057 |
| 3994 void JSObject::ConvertAndSetOwnProperty(LookupResult* lookup, | 4058 void JSObject::ConvertAndSetOwnProperty(LookupResult* lookup, |
| 3995 Handle<Name> name, | 4059 Handle<Name> name, |
| 3996 Handle<Object> value, | 4060 Handle<Object> value, |
| 3997 PropertyAttributes attributes) { | 4061 PropertyAttributes attributes) { |
| 3998 Handle<JSObject> object(lookup->holder()); | 4062 Handle<JSObject> object(lookup->holder()); |
| 3999 if (object->TooManyFastProperties()) { | 4063 if (object->map()->TooManyFastProperties(Object::MAY_BE_STORE_FROM_KEYED)) { |
| 4000 JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); | 4064 JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); |
| 4001 } | 4065 } |
| 4002 | 4066 |
| 4003 if (!object->HasFastProperties()) { | 4067 if (!object->HasFastProperties()) { |
| 4004 ReplaceSlowProperty(object, name, value, attributes); | 4068 ReplaceSlowProperty(object, name, value, attributes); |
| 4005 return; | 4069 return; |
| 4006 } | 4070 } |
| 4007 | 4071 |
| 4008 int descriptor_index = lookup->GetDescriptorIndex(); | 4072 int descriptor_index = lookup->GetDescriptorIndex(); |
| 4009 if (lookup->GetAttributes() == attributes) { | 4073 if (lookup->GetAttributes() == attributes) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 4027 PropertyAttributes attributes) { | 4091 PropertyAttributes attributes) { |
| 4028 if (lookup->GetAttributes() == attributes) { | 4092 if (lookup->GetAttributes() == attributes) { |
| 4029 if (value->IsUninitialized()) return; | 4093 if (value->IsUninitialized()) return; |
| 4030 SetPropertyToField(lookup, value); | 4094 SetPropertyToField(lookup, value); |
| 4031 } else { | 4095 } else { |
| 4032 ConvertAndSetOwnProperty(lookup, name, value, attributes); | 4096 ConvertAndSetOwnProperty(lookup, name, value, attributes); |
| 4033 } | 4097 } |
| 4034 } | 4098 } |
| 4035 | 4099 |
| 4036 | 4100 |
| 4037 MaybeHandle<Object> JSObject::SetPropertyForResult( | |
| 4038 Handle<JSObject> object, | |
| 4039 LookupResult* lookup, | |
| 4040 Handle<Name> name, | |
| 4041 Handle<Object> value, | |
| 4042 StrictMode strict_mode, | |
| 4043 StoreFromKeyed store_mode) { | |
| 4044 ASSERT(!value->IsTheHole()); | |
| 4045 Isolate* isolate = object->GetIsolate(); | |
| 4046 | |
| 4047 // Make sure that the top context does not change when doing callbacks or | |
| 4048 // interceptor calls. | |
| 4049 AssertNoContextChange ncc(isolate); | |
| 4050 | |
| 4051 // Optimization for 2-byte strings often used as keys in a decompression | |
| 4052 // dictionary. We internalize these short keys to avoid constantly | |
| 4053 // reallocating them. | |
| 4054 if (name->IsString() && !name->IsInternalizedString() && | |
| 4055 Handle<String>::cast(name)->length() <= 2) { | |
| 4056 name = isolate->factory()->InternalizeString(Handle<String>::cast(name)); | |
| 4057 } | |
| 4058 | |
| 4059 // Check access rights if needed. | |
| 4060 if (object->IsAccessCheckNeeded()) { | |
| 4061 if (!isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) { | |
| 4062 return SetPropertyWithFailedAccessCheck(object, lookup, name, value, | |
| 4063 true, strict_mode); | |
| 4064 } | |
| 4065 } | |
| 4066 | |
| 4067 if (object->IsJSGlobalProxy()) { | |
| 4068 PrototypeIterator iter(isolate, object); | |
| 4069 if (iter.IsAtEnd()) return value; | |
| 4070 ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); | |
| 4071 return SetPropertyForResult( | |
| 4072 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), lookup, | |
| 4073 name, value, strict_mode, store_mode); | |
| 4074 } | |
| 4075 | |
| 4076 ASSERT(!lookup->IsFound() || lookup->holder() == *object || | |
| 4077 lookup->holder()->map()->is_hidden_prototype()); | |
| 4078 | |
| 4079 if (!lookup->IsProperty() && !object->IsJSContextExtensionObject()) { | |
| 4080 bool done = false; | |
| 4081 Handle<Object> result_object; | |
| 4082 ASSIGN_RETURN_ON_EXCEPTION( | |
| 4083 isolate, result_object, | |
| 4084 SetPropertyViaPrototypes(object, name, value, strict_mode, &done), | |
| 4085 Object); | |
| 4086 if (done) return result_object; | |
| 4087 } | |
| 4088 | |
| 4089 if (!lookup->IsFound()) { | |
| 4090 // Neither properties nor transitions found. | |
| 4091 return AddPropertyInternal(object, name, value, NONE, strict_mode, | |
| 4092 store_mode); | |
| 4093 } | |
| 4094 | |
| 4095 if (lookup->IsProperty() && lookup->IsReadOnly()) { | |
| 4096 if (strict_mode == STRICT) { | |
| 4097 Handle<Object> args[] = { name, object }; | |
| 4098 Handle<Object> error = isolate->factory()->NewTypeError( | |
| 4099 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))); | |
| 4100 return isolate->Throw<Object>(error); | |
| 4101 } else { | |
| 4102 return value; | |
| 4103 } | |
| 4104 } | |
| 4105 | |
| 4106 Handle<Object> old_value = isolate->factory()->the_hole_value(); | |
| 4107 bool is_observed = object->map()->is_observed() && | |
| 4108 *name != isolate->heap()->hidden_string(); | |
| 4109 if (is_observed && lookup->IsDataProperty()) { | |
| 4110 old_value = Object::GetPropertyOrElement(object, name).ToHandleChecked(); | |
| 4111 } | |
| 4112 | |
| 4113 // This is a real property that is not read-only, or it is a | |
| 4114 // transition or null descriptor and there are no setters in the prototypes. | |
| 4115 MaybeHandle<Object> maybe_result = value; | |
| 4116 if (lookup->IsTransition()) { | |
| 4117 maybe_result = SetPropertyUsingTransition(handle(lookup->holder()), lookup, | |
| 4118 name, value, NONE); | |
| 4119 } else { | |
| 4120 switch (lookup->type()) { | |
| 4121 case NORMAL: | |
| 4122 SetNormalizedProperty(handle(lookup->holder()), lookup, value); | |
| 4123 break; | |
| 4124 case FIELD: | |
| 4125 SetPropertyToField(lookup, value); | |
| 4126 break; | |
| 4127 case CONSTANT: | |
| 4128 // Only replace the constant if necessary. | |
| 4129 if (*value == lookup->GetConstant()) return value; | |
| 4130 SetPropertyToField(lookup, value); | |
| 4131 break; | |
| 4132 case CALLBACKS: { | |
| 4133 Handle<Object> callback_object(lookup->GetCallbackObject(), isolate); | |
| 4134 return SetPropertyWithCallback(object, name, value, | |
| 4135 handle(lookup->holder()), | |
| 4136 callback_object, strict_mode); | |
| 4137 } | |
| 4138 case INTERCEPTOR: | |
| 4139 maybe_result = SetPropertyWithInterceptor(handle(lookup->holder()), | |
| 4140 name, value, strict_mode); | |
| 4141 break; | |
| 4142 case HANDLER: | |
| 4143 case NONEXISTENT: | |
| 4144 UNREACHABLE(); | |
| 4145 } | |
| 4146 } | |
| 4147 | |
| 4148 Handle<Object> result; | |
| 4149 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, maybe_result, Object); | |
| 4150 | |
| 4151 if (is_observed) { | |
| 4152 if (lookup->IsTransition()) { | |
| 4153 EnqueueChangeRecord(object, "add", name, old_value); | |
| 4154 } else { | |
| 4155 LookupResult new_lookup(isolate); | |
| 4156 object->LookupOwn(name, &new_lookup, true); | |
| 4157 if (new_lookup.IsDataProperty()) { | |
| 4158 Handle<Object> new_value = | |
| 4159 Object::GetPropertyOrElement(object, name).ToHandleChecked(); | |
| 4160 if (!new_value->SameValue(*old_value)) { | |
| 4161 EnqueueChangeRecord(object, "update", name, old_value); | |
| 4162 } | |
| 4163 } | |
| 4164 } | |
| 4165 } | |
| 4166 | |
| 4167 return result; | |
| 4168 } | |
| 4169 | |
| 4170 | |
| 4171 void JSObject::AddProperty( | 4101 void JSObject::AddProperty( |
| 4172 Handle<JSObject> object, | 4102 Handle<JSObject> object, |
| 4173 Handle<Name> name, | 4103 Handle<Name> name, |
| 4174 Handle<Object> value, | 4104 Handle<Object> value, |
| 4175 PropertyAttributes attributes, | 4105 PropertyAttributes attributes, |
| 4176 StoreMode store_mode) { | 4106 StoreMode store_mode) { |
| 4177 #ifdef DEBUG | 4107 #ifdef DEBUG |
| 4178 uint32_t index; | 4108 uint32_t index; |
| 4179 ASSERT(!object->IsJSProxy()); | 4109 ASSERT(!object->IsJSProxy()); |
| 4180 ASSERT(!name->AsArrayIndex(&index)); | 4110 ASSERT(!name->AsArrayIndex(&index)); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 4208 | 4138 |
| 4209 LookupResult lookup(isolate); | 4139 LookupResult lookup(isolate); |
| 4210 object->LookupOwn(name, &lookup, true); | 4140 object->LookupOwn(name, &lookup, true); |
| 4211 if (!lookup.IsFound()) { | 4141 if (!lookup.IsFound()) { |
| 4212 object->map()->LookupTransition(*object, *name, &lookup); | 4142 object->map()->LookupTransition(*object, *name, &lookup); |
| 4213 } | 4143 } |
| 4214 | 4144 |
| 4215 // Check access rights if needed. | 4145 // Check access rights if needed. |
| 4216 if (object->IsAccessCheckNeeded()) { | 4146 if (object->IsAccessCheckNeeded()) { |
| 4217 if (!isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) { | 4147 if (!isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) { |
| 4218 return SetPropertyWithFailedAccessCheck(object, &lookup, name, value, | 4148 LookupIterator it(object, name, LookupIterator::CHECK_OWN); |
| 4219 false, SLOPPY); | 4149 return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY); |
| 4220 } | 4150 } |
| 4221 } | 4151 } |
| 4222 | 4152 |
| 4223 if (object->IsJSGlobalProxy()) { | 4153 if (object->IsJSGlobalProxy()) { |
| 4224 PrototypeIterator iter(isolate, object); | 4154 PrototypeIterator iter(isolate, object); |
| 4225 if (iter.IsAtEnd()) return value; | 4155 if (iter.IsAtEnd()) return value; |
| 4226 ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); | 4156 ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); |
| 4227 return SetOwnPropertyIgnoreAttributes( | 4157 return SetOwnPropertyIgnoreAttributes( |
| 4228 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), name, | 4158 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), name, |
| 4229 value, attributes, mode, extensibility_check); | 4159 value, attributes, mode, extensibility_check); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4281 SetPropertyToFieldWithAttributes(&lookup, name, value, attributes); | 4211 SetPropertyToFieldWithAttributes(&lookup, name, value, attributes); |
| 4282 } | 4212 } |
| 4283 break; | 4213 break; |
| 4284 case CALLBACKS: | 4214 case CALLBACKS: |
| 4285 { | 4215 { |
| 4286 Handle<Object> callback(lookup.GetCallbackObject(), isolate); | 4216 Handle<Object> callback(lookup.GetCallbackObject(), isolate); |
| 4287 if (callback->IsExecutableAccessorInfo() && | 4217 if (callback->IsExecutableAccessorInfo() && |
| 4288 handling == DONT_FORCE_FIELD) { | 4218 handling == DONT_FORCE_FIELD) { |
| 4289 Handle<Object> result; | 4219 Handle<Object> result; |
| 4290 ASSIGN_RETURN_ON_EXCEPTION( | 4220 ASSIGN_RETURN_ON_EXCEPTION( |
| 4291 isolate, result, | 4221 isolate, result, JSObject::SetPropertyWithAccessor( |
| 4292 JSObject::SetPropertyWithCallback(object, | 4222 object, name, value, handle(lookup.holder()), |
| 4293 name, | 4223 callback, STRICT), |
| 4294 value, | |
| 4295 handle(lookup.holder()), | |
| 4296 callback, | |
| 4297 STRICT), | |
| 4298 Object); | 4224 Object); |
| 4299 | 4225 |
| 4300 if (attributes != lookup.GetAttributes()) { | 4226 if (attributes != lookup.GetAttributes()) { |
| 4301 Handle<ExecutableAccessorInfo> new_data = | 4227 Handle<ExecutableAccessorInfo> new_data = |
| 4302 Accessors::CloneAccessor( | 4228 Accessors::CloneAccessor( |
| 4303 isolate, Handle<ExecutableAccessorInfo>::cast(callback)); | 4229 isolate, Handle<ExecutableAccessorInfo>::cast(callback)); |
| 4304 new_data->set_property_attributes(attributes); | 4230 new_data->set_property_attributes(attributes); |
| 4305 if (attributes & READ_ONLY) { | 4231 if (attributes & READ_ONLY) { |
| 4306 // This way we don't have to introduce a lookup to the setter, | 4232 // This way we don't have to introduce a lookup to the setter, |
| 4307 // simply make it unavailable to reflect the attributes. | 4233 // simply make it unavailable to reflect the attributes. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4356 | 4282 |
| 4357 return value; | 4283 return value; |
| 4358 } | 4284 } |
| 4359 | 4285 |
| 4360 | 4286 |
| 4361 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( | 4287 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( |
| 4362 Handle<JSObject> holder, | 4288 Handle<JSObject> holder, |
| 4363 Handle<Object> receiver, | 4289 Handle<Object> receiver, |
| 4364 Handle<Name> name) { | 4290 Handle<Name> name) { |
| 4365 // TODO(rossberg): Support symbols in the API. | 4291 // TODO(rossberg): Support symbols in the API. |
| 4366 if (name->IsSymbol()) return Maybe<PropertyAttributes>(ABSENT); | 4292 if (name->IsSymbol()) return Maybe<PropertyAttributes>(); |
| 4367 | 4293 |
| 4368 Isolate* isolate = holder->GetIsolate(); | 4294 Isolate* isolate = holder->GetIsolate(); |
| 4369 HandleScope scope(isolate); | 4295 HandleScope scope(isolate); |
| 4370 | 4296 |
| 4371 // Make sure that the top context does not change when doing | 4297 // Make sure that the top context does not change when doing |
| 4372 // callbacks or interceptor calls. | 4298 // callbacks or interceptor calls. |
| 4373 AssertNoContextChange ncc(isolate); | 4299 AssertNoContextChange ncc(isolate); |
| 4374 | 4300 |
| 4375 Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor()); | 4301 Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor()); |
| 4376 PropertyCallbackArguments args( | 4302 PropertyCallbackArguments args( |
| (...skipping 2983 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7360 handle(map->instance_descriptors(), isolate), num_descriptors, FROZEN); | 7286 handle(map->instance_descriptors(), isolate), num_descriptors, FROZEN); |
| 7361 Handle<Map> new_map = CopyReplaceDescriptors( | 7287 Handle<Map> new_map = CopyReplaceDescriptors( |
| 7362 map, new_desc, INSERT_TRANSITION, isolate->factory()->frozen_symbol()); | 7288 map, new_desc, INSERT_TRANSITION, isolate->factory()->frozen_symbol()); |
| 7363 new_map->freeze(); | 7289 new_map->freeze(); |
| 7364 new_map->set_is_extensible(false); | 7290 new_map->set_is_extensible(false); |
| 7365 new_map->set_elements_kind(DICTIONARY_ELEMENTS); | 7291 new_map->set_elements_kind(DICTIONARY_ELEMENTS); |
| 7366 return new_map; | 7292 return new_map; |
| 7367 } | 7293 } |
| 7368 | 7294 |
| 7369 | 7295 |
| 7296 bool DescriptorArray::CanHoldValue(int descriptor, Object* value) { |
| 7297 PropertyDetails details = GetDetails(descriptor); |
| 7298 switch (details.type()) { |
| 7299 case FIELD: |
| 7300 return value->FitsRepresentation(details.representation()) && |
| 7301 GetFieldType(descriptor)->NowContains(value); |
| 7302 |
| 7303 case CONSTANT: |
| 7304 ASSERT(GetConstant(descriptor) != value || |
| 7305 value->FitsRepresentation(details.representation())); |
| 7306 return GetConstant(descriptor) == value; |
| 7307 |
| 7308 case CALLBACKS: |
| 7309 return false; |
| 7310 |
| 7311 case NORMAL: |
| 7312 case INTERCEPTOR: |
| 7313 case HANDLER: |
| 7314 case NONEXISTENT: |
| 7315 break; |
| 7316 } |
| 7317 |
| 7318 UNREACHABLE(); |
| 7319 return false; |
| 7320 } |
| 7321 |
| 7322 |
| 7323 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor, |
| 7324 Handle<Object> value) { |
| 7325 // Dictionaries can store any property value. |
| 7326 if (map->is_dictionary_map()) return map; |
| 7327 |
| 7328 Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
| 7329 |
| 7330 if (descriptors->CanHoldValue(descriptor, *value)) return map; |
| 7331 |
| 7332 Isolate* isolate = map->GetIsolate(); |
| 7333 Representation representation = value->OptimalRepresentation(); |
| 7334 Handle<HeapType> type = value->OptimalType(isolate, representation); |
| 7335 |
| 7336 return GeneralizeRepresentation(map, descriptor, representation, type, |
| 7337 FORCE_FIELD); |
| 7338 } |
| 7339 |
| 7340 |
| 7341 Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name, |
| 7342 Handle<Object> value, |
| 7343 PropertyAttributes attributes, |
| 7344 StoreFromKeyed store_mode) { |
| 7345 // Cannot currently handle deprecated maps. |
| 7346 ASSERT(!map->is_deprecated()); |
| 7347 // Dictionary maps can always have additional data properties. |
| 7348 if (map->is_dictionary_map()) return map; |
| 7349 |
| 7350 int index = map->SearchTransition(*name); |
| 7351 if (index != TransitionArray::kNotFound) { |
| 7352 Handle<Map> transition(map->GetTransition(index)); |
| 7353 int descriptor = transition->LastAdded(); |
| 7354 |
| 7355 // TODO(verwaest): Handle attributes better. |
| 7356 DescriptorArray* descriptors = transition->instance_descriptors(); |
| 7357 if (descriptors->GetDetails(descriptor).attributes() != attributes) { |
| 7358 return CopyGeneralizeAllRepresentations(transition, descriptor, |
| 7359 FORCE_FIELD, attributes, |
| 7360 "attributes mismatch"); |
| 7361 } |
| 7362 |
| 7363 return Map::PrepareForDataProperty(transition, descriptor, value); |
| 7364 } |
| 7365 |
| 7366 TransitionFlag flag = INSERT_TRANSITION; |
| 7367 MaybeHandle<Map> maybe_map; |
| 7368 if (value->IsJSFunction()) { |
| 7369 maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag); |
| 7370 } else if (!map->TooManyFastProperties(store_mode)) { |
| 7371 Isolate* isolate = name->GetIsolate(); |
| 7372 Representation representation = value->OptimalRepresentation(); |
| 7373 Handle<HeapType> type = value->OptimalType(isolate, representation); |
| 7374 maybe_map = |
| 7375 Map::CopyWithField(map, name, type, attributes, representation, flag); |
| 7376 } |
| 7377 |
| 7378 Handle<Map> result; |
| 7379 if (!maybe_map.ToHandle(&result)) { |
| 7380 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES); |
| 7381 } |
| 7382 |
| 7383 return result; |
| 7384 } |
| 7385 |
| 7386 |
| 7370 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map, | 7387 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map, |
| 7371 Descriptor* descriptor, | 7388 Descriptor* descriptor, |
| 7372 TransitionFlag flag) { | 7389 TransitionFlag flag) { |
| 7373 Handle<DescriptorArray> descriptors(map->instance_descriptors()); | 7390 Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
| 7374 | 7391 |
| 7375 // Ensure the key is unique. | 7392 // Ensure the key is unique. |
| 7376 descriptor->KeyToUniqueName(); | 7393 descriptor->KeyToUniqueName(); |
| 7377 | 7394 |
| 7378 if (flag == INSERT_TRANSITION && | 7395 if (flag == INSERT_TRANSITION && |
| 7379 map->owns_descriptors() && | 7396 map->owns_descriptors() && |
| (...skipping 9530 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 16910 #define ERROR_MESSAGES_TEXTS(C, T) T, | 16927 #define ERROR_MESSAGES_TEXTS(C, T) T, |
| 16911 static const char* error_messages_[] = { | 16928 static const char* error_messages_[] = { |
| 16912 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) | 16929 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) |
| 16913 }; | 16930 }; |
| 16914 #undef ERROR_MESSAGES_TEXTS | 16931 #undef ERROR_MESSAGES_TEXTS |
| 16915 return error_messages_[reason]; | 16932 return error_messages_[reason]; |
| 16916 } | 16933 } |
| 16917 | 16934 |
| 16918 | 16935 |
| 16919 } } // namespace v8::internal | 16936 } } // namespace v8::internal |
| OLD | NEW |