Chromium Code Reviews| 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(!value->IsTheHole()); | 472 ASSERT(!value->IsTheHole()); |
| 476 ASSERT(!structure->IsForeign()); | 473 ASSERT(!structure->IsForeign()); |
| 477 if (structure->IsExecutableAccessorInfo()) { | 474 if (structure->IsExecutableAccessorInfo()) { |
| 478 // api style callbacks | 475 // api style callbacks |
| 479 ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(*structure); | 476 ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(*structure); |
| 480 if (!data->IsCompatibleReceiver(*receiver)) { | 477 if (!data->IsCompatibleReceiver(*receiver)) { |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 599 PropertyAttributes JSObject::GetPropertyAttributesWithFailedAccessCheck( | 596 PropertyAttributes JSObject::GetPropertyAttributesWithFailedAccessCheck( |
| 600 LookupIterator* it) { | 597 LookupIterator* it) { |
| 601 Handle<JSObject> checked = Handle<JSObject>::cast(it->GetHolder()); | 598 Handle<JSObject> checked = Handle<JSObject>::cast(it->GetHolder()); |
| 602 if (FindAllCanReadHolder(it)) return it->property_details().attributes(); | 599 if (FindAllCanReadHolder(it)) return it->property_details().attributes(); |
| 603 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS); | 600 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS); |
| 604 // TODO(yangguo): Issue 3269, check for scheduled exception missing? | 601 // TODO(yangguo): Issue 3269, check for scheduled exception missing? |
| 605 return ABSENT; | 602 return ABSENT; |
| 606 } | 603 } |
| 607 | 604 |
| 608 | 605 |
| 609 static bool FindAllCanWriteHolder(LookupResult* result, | 606 static bool FindAllCanWriteHolder(LookupIterator* it) { |
| 610 Handle<Name> name, | 607 it->skip_interceptor(); |
| 611 bool check_prototype) { | 608 it->skip_access_check(); |
| 612 if (result->IsInterceptor()) { | 609 for (; it->IsFound(); it->Next()) { |
| 613 result->holder()->LookupOwnRealNamedProperty(name, result); | 610 if (it->state() == LookupIterator::PROPERTY && it->HasProperty() && |
| 614 } | 611 it->property_kind() == LookupIterator::ACCESSOR) { |
| 615 | 612 Handle<Object> accessors = it->GetAccessors(); |
| 616 while (result->IsProperty()) { | 613 if (accessors->IsAccessorInfo()) { |
| 617 if (result->type() == CALLBACKS) { | 614 if (AccessorInfo::cast(*accessors)->all_can_write()) return true; |
| 618 Object* callback_obj = result->GetCallbackObject(); | |
| 619 if (callback_obj->IsAccessorInfo()) { | |
| 620 if (AccessorInfo::cast(callback_obj)->all_can_write()) return true; | |
| 621 } | 615 } |
| 622 } | 616 } |
| 623 if (!check_prototype) break; | |
| 624 result->holder()->LookupRealNamedPropertyInPrototypes(name, result); | |
| 625 } | 617 } |
| 626 return false; | 618 return false; |
| 627 } | 619 } |
| 628 | 620 |
| 629 | 621 |
| 630 MaybeHandle<Object> JSObject::SetPropertyWithFailedAccessCheck( | 622 MaybeHandle<Object> JSObject::SetPropertyWithFailedAccessCheck( |
| 631 Handle<JSObject> object, | 623 LookupIterator* it, Handle<Object> value, StrictMode strict_mode) { |
| 632 LookupResult* result, | 624 Handle<JSObject> checked = Handle<JSObject>::cast(it->GetHolder()); |
| 633 Handle<Name> name, | 625 if (FindAllCanWriteHolder(it)) { |
| 634 Handle<Object> value, | 626 return SetPropertyWithAccessor(it->GetReceiver(), it->name(), value, |
| 635 bool check_prototype, | 627 it->GetHolder(), it->GetAccessors(), |
| 636 StrictMode strict_mode) { | 628 strict_mode); |
| 637 if (check_prototype && !result->IsProperty()) { | |
| 638 object->LookupRealNamedPropertyInPrototypes(name, result); | |
| 639 } | 629 } |
| 640 | 630 |
| 641 if (FindAllCanWriteHolder(result, name, check_prototype)) { | 631 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_SET); |
| 642 Handle<JSObject> holder(result->holder()); | 632 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object); |
| 643 Handle<Object> callbacks(result->GetCallbackObject(), result->isolate()); | |
| 644 return SetPropertyWithCallback( | |
| 645 object, name, value, holder, callbacks, strict_mode); | |
| 646 } | |
| 647 | |
| 648 Isolate* isolate = object->GetIsolate(); | |
| 649 isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET); | |
| 650 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
| 651 return value; | 633 return value; |
| 652 } | 634 } |
| 653 | 635 |
| 654 | 636 |
| 655 Object* JSObject::GetNormalizedProperty(const LookupResult* result) { | 637 Object* JSObject::GetNormalizedProperty(const LookupResult* result) { |
| 656 ASSERT(!HasFastProperties()); | 638 ASSERT(!HasFastProperties()); |
| 657 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry()); | 639 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry()); |
| 658 if (IsGlobalObject()) { | 640 if (IsGlobalObject()) { |
| 659 value = PropertyCell::cast(value)->value(); | 641 value = PropertyCell::cast(value)->value(); |
| 660 } | 642 } |
| (...skipping 1167 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 Handle<Object> value_unhole = value->IsTheHole() | 2954 v8::NamedPropertySetterCallback setter = |
| 2993 ? Handle<Object>(isolate->factory()->undefined_value()) : value; | 2955 v8::ToCData<v8::NamedPropertySetterCallback>(interceptor->setter()); |
| 2994 v8::Handle<v8::Value> result = args.Call(setter, | 2956 Handle<Object> value_unhole = |
| 2995 v8::Utils::ToLocal(name_string), | 2957 value->IsTheHole() |
| 2996 v8::Utils::ToLocal(value_unhole)); | 2958 ? Handle<Object>::cast(it->factory()->undefined_value()) |
| 2997 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | 2959 : value; |
| 2998 if (!result.IsEmpty()) return value; | 2960 v8::Handle<v8::Value> result = |
| 2999 } | 2961 args.Call(setter, v8::Utils::ToLocal(name_string), |
| 3000 return SetPropertyPostInterceptor(object, name, value, strict_mode); | 2962 v8::Utils::ToLocal(value_unhole)); |
| 2963 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object); | |
| 2964 if (!result.IsEmpty()) return value; | |
| 2965 | |
| 2966 return MaybeHandle<Object>(); | |
| 3001 } | 2967 } |
| 3002 | 2968 |
| 3003 | 2969 |
| 3004 MaybeHandle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object, | 2970 MaybeHandle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object, |
| 3005 Handle<Name> name, | 2971 Handle<Name> name, |
| 3006 Handle<Object> value, | 2972 Handle<Object> value, |
| 3007 StrictMode strict_mode, | 2973 StrictMode strict_mode, |
| 3008 StoreFromKeyed store_mode) { | 2974 StoreFromKeyed store_mode) { |
| 3009 LookupResult result(object->GetIsolate()); | 2975 LookupIterator it(object, name); |
| 3010 object->LookupOwn(name, &result, true); | 2976 return Object::SetProperty(&it, value, strict_mode, store_mode); |
| 3011 if (!result.IsFound()) { | |
| 3012 object->map()->LookupTransition(JSObject::cast(*object), *name, &result); | |
| 3013 } | |
| 3014 return SetProperty(object, &result, name, value, strict_mode, store_mode); | |
| 3015 } | 2977 } |
| 3016 | 2978 |
| 3017 | 2979 |
| 2980 MaybeHandle<Object> Object::SetProperty(LookupIterator* it, | |
| 2981 Handle<Object> value, | |
| 2982 StrictMode strict_mode, | |
| 2983 StoreFromKeyed store_mode) { | |
| 2984 // Make sure that the top context does not change when doing callbacks or | |
| 2985 // interceptor calls. | |
| 2986 AssertNoContextChange ncc(it->isolate()); | |
| 2987 | |
| 2988 bool done = false; | |
| 2989 for (; it->IsFound(); it->Next()) { | |
| 2990 switch (it->state()) { | |
| 2991 case LookupIterator::NOT_FOUND: | |
| 2992 UNREACHABLE(); | |
| 2993 | |
| 2994 case LookupIterator::ACCESS_CHECK: | |
| 2995 // TODO(verwaest): Remove the distinction. This is mostly bogus since we | |
| 2996 // don't know whether we'll want to fetch attributes or call a setter | |
| 2997 // until we find the property. | |
| 2998 if (it->HasAccess(v8::ACCESS_SET)) break; | |
| 2999 return JSObject::SetPropertyWithFailedAccessCheck(it, value, | |
| 3000 strict_mode); | |
| 3001 | |
| 3002 case LookupIterator::JSPROXY: | |
| 3003 if (it->HolderIsReceiver()) { | |
| 3004 return JSProxy::SetPropertyWithHandler(it->GetJSProxy(), | |
| 3005 it->GetReceiver(), it->name(), | |
| 3006 value, strict_mode); | |
| 3007 } else { | |
| 3008 // TODO(verwaest): Use the MaybeHandle to indicate result. | |
| 3009 bool has_result = false; | |
| 3010 MaybeHandle<Object> maybe_result = | |
| 3011 JSProxy::SetPropertyViaPrototypesWithHandler( | |
| 3012 it->GetJSProxy(), it->GetReceiver(), it->name(), value, | |
| 3013 strict_mode, &has_result); | |
| 3014 if (has_result) return maybe_result; | |
| 3015 done = true; | |
| 3016 } | |
| 3017 break; | |
| 3018 | |
| 3019 case LookupIterator::INTERCEPTOR: | |
| 3020 if (it->HolderIsReceiver()) { | |
| 3021 MaybeHandle<Object> maybe_result = | |
| 3022 JSObject::SetPropertyWithInterceptor(it, value); | |
| 3023 if (!maybe_result.is_null()) return maybe_result; | |
| 3024 if (it->isolate()->has_pending_exception()) return maybe_result; | |
| 3025 } else { | |
| 3026 Maybe<PropertyAttributes> maybe_attributes = | |
| 3027 JSObject::GetPropertyAttributesWithInterceptor( | |
| 3028 it->GetHolder(), it->GetReceiver(), it->name()); | |
| 3029 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object); | |
| 3030 done = maybe_attributes.has_value; | |
| 3031 if (done && (maybe_attributes.value & READ_ONLY) != 0) { | |
| 3032 return WriteToReadOnlyProperty(it, value, strict_mode); | |
| 3033 } | |
| 3034 } | |
| 3035 break; | |
| 3036 | |
| 3037 case LookupIterator::PROPERTY: | |
| 3038 if (!it->HasProperty()) break; | |
| 3039 if (it->property_details().IsReadOnly()) { | |
| 3040 return WriteToReadOnlyProperty(it, value, strict_mode); | |
| 3041 } | |
| 3042 switch (it->property_kind()) { | |
| 3043 case LookupIterator::ACCESSOR: | |
| 3044 if (it->HolderIsReceiver() || | |
|
Igor Sheludko
2014/07/18 13:08:31
&&
Toon Verwaest
2014/07/18 13:45:22
The original was actually correct. If the holder-i
| |
| 3045 !it->GetAccessors()->IsDeclaredAccessorInfo()) { | |
| 3046 return SetPropertyWithAccessor(it->GetReceiver(), it->name(), | |
| 3047 value, it->GetHolder(), | |
| 3048 it->GetAccessors(), strict_mode); | |
| 3049 } | |
| 3050 // Fall through. | |
|
Igor Sheludko
2014/07/18 13:08:31
Wrong identation.
| |
| 3051 case LookupIterator::DATA: | |
| 3052 if (it->HolderIsReceiver()) return SetDataProperty(it, value); | |
| 3053 done = true; | |
| 3054 } | |
| 3055 break; | |
| 3056 } | |
| 3057 | |
| 3058 if (done) break; | |
| 3059 } | |
| 3060 | |
| 3061 return AddDataProperty(it, value, NONE, strict_mode, store_mode); | |
| 3062 } | |
| 3063 | |
| 3064 | |
| 3065 MaybeHandle<Object> Object::WriteToReadOnlyProperty(LookupIterator* it, | |
| 3066 Handle<Object> value, | |
| 3067 StrictMode strict_mode) { | |
| 3068 if (strict_mode != STRICT) return value; | |
| 3069 | |
| 3070 Handle<Object> args[] = {it->name(), it->GetReceiver()}; | |
| 3071 Handle<Object> error = it->factory()->NewTypeError( | |
| 3072 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))); | |
| 3073 return it->isolate()->Throw<Object>(error); | |
| 3074 } | |
| 3075 | |
| 3076 | |
| 3077 MaybeHandle<Object> Object::SetDataProperty(LookupIterator* it, | |
| 3078 Handle<Object> value) { | |
| 3079 // Proxies are handled on the WithHandler path. Other non-JSObjects cannot | |
| 3080 // have own properties. | |
| 3081 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); | |
| 3082 | |
| 3083 // Store on the holder which may be hidden behind the receiver. | |
| 3084 ASSERT(it->HolderIsReceiver()); | |
| 3085 | |
| 3086 // Old value for the observation change record. | |
| 3087 // Fetch before transforming the object since the encoding may become | |
| 3088 // incompatible with what's cached in |it|. | |
| 3089 bool is_observed = receiver->map()->is_observed(); | |
|
Igor Sheludko
2014/07/18 13:08:31
Should we observe modifications of "hidden_string"
| |
| 3090 MaybeHandle<Object> maybe_old; | |
| 3091 if (is_observed) maybe_old = it->GetDataValue(); | |
| 3092 | |
| 3093 // Possibly migrate to the most up-to-date map that will be able to store | |
| 3094 // |value| under it->name(). | |
| 3095 it->PrepareForDataProperty(value); | |
| 3096 | |
| 3097 // Write the property value. | |
| 3098 it->WriteDataValue(value); | |
| 3099 | |
| 3100 // Send the change record if there are observers. | |
| 3101 if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) { | |
| 3102 JSObject::EnqueueChangeRecord(receiver, "update", it->name(), | |
| 3103 maybe_old.ToHandleChecked()); | |
| 3104 } | |
| 3105 | |
| 3106 return value; | |
| 3107 } | |
| 3108 | |
| 3109 | |
| 3110 MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it, | |
| 3111 Handle<Object> value, | |
| 3112 PropertyAttributes attributes, | |
| 3113 StrictMode strict_mode, | |
| 3114 StoreFromKeyed store_mode) { | |
| 3115 ASSERT(!it->GetReceiver()->IsJSProxy()); | |
| 3116 // Transitions to data properties of value wrappers are not observable. | |
| 3117 if (!it->GetReceiver()->IsJSObject()) return value; | |
| 3118 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); | |
| 3119 | |
| 3120 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject) | |
| 3121 // instead. If the prototype is Null, the proxy is detached. | |
| 3122 if (receiver->IsJSGlobalProxy()) { | |
| 3123 // Trying to assign to a detached proxy. | |
| 3124 if (receiver->GetPrototype()->IsNull()) return value; | |
| 3125 receiver = handle(JSGlobalObject::cast(receiver->GetPrototype())); | |
| 3126 } | |
| 3127 | |
| 3128 if (!receiver->map()->is_extensible()) { | |
| 3129 if (strict_mode == SLOPPY) return value; | |
| 3130 | |
| 3131 Handle<Object> args[1] = {it->name()}; | |
| 3132 Handle<Object> error = it->factory()->NewTypeError( | |
| 3133 "object_not_extensible", HandleVector(args, ARRAY_SIZE(args))); | |
| 3134 return it->isolate()->Throw<Object>(error); | |
| 3135 } | |
| 3136 | |
| 3137 // Possibly migrate to the most up-to-date map that will be able to store | |
| 3138 // |value| under it->name() with |attributes|. | |
| 3139 it->TransitionToDataProperty(value, attributes, store_mode); | |
| 3140 | |
| 3141 // TODO(verwaest): Encapsulate dictionary handling better. | |
| 3142 if (receiver->map()->is_dictionary_map()) { | |
| 3143 // TODO(verwaest): Probably should ensure this is done beforehand. | |
| 3144 it->InternalizeName(); | |
| 3145 JSObject::AddSlowProperty(receiver, it->name(), value, attributes); | |
| 3146 } else { | |
| 3147 // Write the property value. | |
| 3148 it->WriteDataValue(value); | |
| 3149 } | |
| 3150 | |
| 3151 // Send the change record if there are observers. | |
| 3152 if (receiver->map()->is_observed()) { | |
|
Igor Sheludko
2014/07/18 13:08:31
Same here.
| |
| 3153 JSObject::EnqueueChangeRecord(receiver, "add", it->name(), | |
| 3154 it->factory()->the_hole_value()); | |
| 3155 } | |
| 3156 | |
| 3157 return value; | |
| 3158 } | |
| 3159 | |
| 3160 | |
| 3018 MaybeHandle<Object> JSObject::SetElementWithCallbackSetterInPrototypes( | 3161 MaybeHandle<Object> JSObject::SetElementWithCallbackSetterInPrototypes( |
| 3019 Handle<JSObject> object, | 3162 Handle<JSObject> object, |
| 3020 uint32_t index, | 3163 uint32_t index, |
| 3021 Handle<Object> value, | 3164 Handle<Object> value, |
| 3022 bool* found, | 3165 bool* found, |
| 3023 StrictMode strict_mode) { | 3166 StrictMode strict_mode) { |
| 3024 Isolate *isolate = object->GetIsolate(); | 3167 Isolate *isolate = object->GetIsolate(); |
| 3025 for (PrototypeIterator iter(isolate, object); !iter.IsAtEnd(); | 3168 for (PrototypeIterator iter(isolate, object); !iter.IsAtEnd(); |
| 3026 iter.Advance()) { | 3169 iter.Advance()) { |
| 3027 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | 3170 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 3045 return SetElementWithCallback(object, structure, index, value, js_proto, | 3188 return SetElementWithCallback(object, structure, index, value, js_proto, |
| 3046 strict_mode); | 3189 strict_mode); |
| 3047 } | 3190 } |
| 3048 } | 3191 } |
| 3049 } | 3192 } |
| 3050 *found = false; | 3193 *found = false; |
| 3051 return isolate->factory()->the_hole_value(); | 3194 return isolate->factory()->the_hole_value(); |
| 3052 } | 3195 } |
| 3053 | 3196 |
| 3054 | 3197 |
| 3055 MaybeHandle<Object> JSObject::SetPropertyViaPrototypes( | |
| 3056 Handle<JSObject> object, | |
| 3057 Handle<Name> name, | |
| 3058 Handle<Object> value, | |
| 3059 StrictMode strict_mode, | |
| 3060 bool* done) { | |
| 3061 Isolate* isolate = object->GetIsolate(); | |
| 3062 | |
| 3063 *done = false; | |
| 3064 // We could not find an own property, so let's check whether there is an | |
| 3065 // accessor that wants to handle the property, or whether the property is | |
| 3066 // read-only on the prototype chain. | |
| 3067 LookupResult result(isolate); | |
| 3068 object->LookupRealNamedPropertyInPrototypes(name, &result); | |
| 3069 if (result.IsFound()) { | |
| 3070 switch (result.type()) { | |
| 3071 case NORMAL: | |
| 3072 case FIELD: | |
| 3073 case CONSTANT: | |
| 3074 *done = result.IsReadOnly(); | |
| 3075 break; | |
| 3076 case INTERCEPTOR: { | |
| 3077 LookupIterator it(object, name, handle(result.holder())); | |
| 3078 PropertyAttributes attr = GetPropertyAttributes(&it); | |
| 3079 *done = !!(attr & READ_ONLY); | |
| 3080 break; | |
| 3081 } | |
| 3082 case CALLBACKS: { | |
| 3083 *done = true; | |
| 3084 if (!result.IsReadOnly()) { | |
| 3085 Handle<Object> callback_object(result.GetCallbackObject(), isolate); | |
| 3086 return SetPropertyWithCallback(object, name, value, | |
| 3087 handle(result.holder()), | |
| 3088 callback_object, strict_mode); | |
| 3089 } | |
| 3090 break; | |
| 3091 } | |
| 3092 case HANDLER: { | |
| 3093 Handle<JSProxy> proxy(result.proxy()); | |
| 3094 return JSProxy::SetPropertyViaPrototypesWithHandler( | |
| 3095 proxy, object, name, value, strict_mode, done); | |
| 3096 } | |
| 3097 case NONEXISTENT: | |
| 3098 UNREACHABLE(); | |
| 3099 break; | |
| 3100 } | |
| 3101 } | |
| 3102 | |
| 3103 // If we get here with *done true, we have encountered a read-only property. | |
| 3104 if (*done) { | |
| 3105 if (strict_mode == SLOPPY) return value; | |
| 3106 Handle<Object> args[] = { name, object }; | |
| 3107 Handle<Object> error = isolate->factory()->NewTypeError( | |
| 3108 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))); | |
| 3109 return isolate->Throw<Object>(error); | |
| 3110 } | |
| 3111 return isolate->factory()->the_hole_value(); | |
| 3112 } | |
| 3113 | |
| 3114 | |
| 3115 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { | 3198 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { |
| 3116 // Only supports adding slack to owned descriptors. | 3199 // Only supports adding slack to owned descriptors. |
| 3117 ASSERT(map->owns_descriptors()); | 3200 ASSERT(map->owns_descriptors()); |
| 3118 | 3201 |
| 3119 Handle<DescriptorArray> descriptors(map->instance_descriptors()); | 3202 Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
| 3120 int old_size = map->NumberOfOwnDescriptors(); | 3203 int old_size = map->NumberOfOwnDescriptors(); |
| 3121 if (slack <= descriptors->NumberOfSlackDescriptors()) return; | 3204 if (slack <= descriptors->NumberOfSlackDescriptors()) return; |
| 3122 | 3205 |
| 3123 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( | 3206 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( |
| 3124 descriptors, old_size, slack); | 3207 descriptors, old_size, slack); |
| (...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3513 return result->HandlerResult(JSProxy::cast(iter.GetCurrent())); | 3596 return result->HandlerResult(JSProxy::cast(iter.GetCurrent())); |
| 3514 } | 3597 } |
| 3515 JSObject::cast(iter.GetCurrent())->LookupOwnRealNamedProperty(name, result); | 3598 JSObject::cast(iter.GetCurrent())->LookupOwnRealNamedProperty(name, result); |
| 3516 ASSERT(!(result->IsFound() && result->type() == INTERCEPTOR)); | 3599 ASSERT(!(result->IsFound() && result->type() == INTERCEPTOR)); |
| 3517 if (result->IsFound()) return; | 3600 if (result->IsFound()) return; |
| 3518 } | 3601 } |
| 3519 result->NotFound(); | 3602 result->NotFound(); |
| 3520 } | 3603 } |
| 3521 | 3604 |
| 3522 | 3605 |
| 3523 MaybeHandle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object, | |
| 3524 LookupResult* result, | |
| 3525 Handle<Name> key, | |
| 3526 Handle<Object> value, | |
| 3527 StrictMode strict_mode, | |
| 3528 StoreFromKeyed store_mode) { | |
| 3529 if (result->IsHandler()) { | |
| 3530 return JSProxy::SetPropertyWithHandler(handle(result->proxy()), object, key, | |
| 3531 value, strict_mode); | |
| 3532 } else { | |
| 3533 return JSObject::SetPropertyForResult(Handle<JSObject>::cast(object), | |
| 3534 result, key, value, strict_mode, | |
| 3535 store_mode); | |
| 3536 } | |
| 3537 } | |
| 3538 | |
| 3539 | |
| 3540 bool JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy, Handle<Name> name) { | 3606 bool JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy, Handle<Name> name) { |
| 3541 Isolate* isolate = proxy->GetIsolate(); | 3607 Isolate* isolate = proxy->GetIsolate(); |
| 3542 | 3608 |
| 3543 // TODO(rossberg): adjust once there is a story for symbols vs proxies. | 3609 // TODO(rossberg): adjust once there is a story for symbols vs proxies. |
| 3544 if (name->IsSymbol()) return false; | 3610 if (name->IsSymbol()) return false; |
| 3545 | 3611 |
| 3546 Handle<Object> args[] = { name }; | 3612 Handle<Object> args[] = { name }; |
| 3547 Handle<Object> result; | 3613 Handle<Object> result; |
| 3548 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 3614 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 3549 isolate, result, | 3615 isolate, result, |
| 3550 CallTrap(proxy, | 3616 CallTrap(proxy, |
| 3551 "has", | 3617 "has", |
| 3552 isolate->derived_has_trap(), | 3618 isolate->derived_has_trap(), |
| 3553 ARRAY_SIZE(args), | 3619 ARRAY_SIZE(args), |
| 3554 args), | 3620 args), |
| 3555 false); | 3621 false); |
| 3556 | 3622 |
| 3557 return result->BooleanValue(); | 3623 return result->BooleanValue(); |
| 3558 } | 3624 } |
| 3559 | 3625 |
| 3560 | 3626 |
| 3561 MaybeHandle<Object> JSProxy::SetPropertyWithHandler( | 3627 MaybeHandle<Object> JSProxy::SetPropertyWithHandler(Handle<JSProxy> proxy, |
| 3562 Handle<JSProxy> proxy, | 3628 Handle<Object> receiver, |
| 3563 Handle<JSReceiver> receiver, | 3629 Handle<Name> name, |
| 3564 Handle<Name> name, | 3630 Handle<Object> value, |
| 3565 Handle<Object> value, | 3631 StrictMode strict_mode) { |
| 3566 StrictMode strict_mode) { | |
| 3567 Isolate* isolate = proxy->GetIsolate(); | 3632 Isolate* isolate = proxy->GetIsolate(); |
| 3568 | 3633 |
| 3569 // TODO(rossberg): adjust once there is a story for symbols vs proxies. | 3634 // TODO(rossberg): adjust once there is a story for symbols vs proxies. |
| 3570 if (name->IsSymbol()) return value; | 3635 if (name->IsSymbol()) return value; |
| 3571 | 3636 |
| 3572 Handle<Object> args[] = { receiver, name, value }; | 3637 Handle<Object> args[] = { receiver, name, value }; |
| 3573 RETURN_ON_EXCEPTION( | 3638 RETURN_ON_EXCEPTION( |
| 3574 isolate, | 3639 isolate, |
| 3575 CallTrap(proxy, | 3640 CallTrap(proxy, |
| 3576 "set", | 3641 "set", |
| 3577 isolate->derived_set_trap(), | 3642 isolate->derived_set_trap(), |
| 3578 ARRAY_SIZE(args), | 3643 ARRAY_SIZE(args), |
| 3579 args), | 3644 args), |
| 3580 Object); | 3645 Object); |
| 3581 | 3646 |
| 3582 return value; | 3647 return value; |
| 3583 } | 3648 } |
| 3584 | 3649 |
| 3585 | 3650 |
| 3586 MaybeHandle<Object> JSProxy::SetPropertyViaPrototypesWithHandler( | 3651 MaybeHandle<Object> JSProxy::SetPropertyViaPrototypesWithHandler( |
| 3587 Handle<JSProxy> proxy, | 3652 Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name, |
| 3588 Handle<JSReceiver> receiver, | 3653 Handle<Object> value, StrictMode strict_mode, bool* done) { |
| 3589 Handle<Name> name, | |
| 3590 Handle<Object> value, | |
| 3591 StrictMode strict_mode, | |
| 3592 bool* done) { | |
| 3593 Isolate* isolate = proxy->GetIsolate(); | 3654 Isolate* isolate = proxy->GetIsolate(); |
| 3594 Handle<Object> handler(proxy->handler(), isolate); // Trap might morph proxy. | 3655 Handle<Object> handler(proxy->handler(), isolate); // Trap might morph proxy. |
| 3595 | 3656 |
| 3596 // TODO(rossberg): adjust once there is a story for symbols vs proxies. | 3657 // TODO(rossberg): adjust once there is a story for symbols vs proxies. |
| 3597 if (name->IsSymbol()) { | 3658 if (name->IsSymbol()) { |
| 3598 *done = false; | 3659 *done = false; |
| 3599 return isolate->factory()->the_hole_value(); | 3660 return isolate->factory()->the_hole_value(); |
| 3600 } | 3661 } |
| 3601 | 3662 |
| 3602 *done = true; // except where redefined... | 3663 *done = true; // except where redefined... |
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4001 } | 4062 } |
| 4002 lookup->holder()->WriteToField(lookup->GetDescriptorIndex(), *value); | 4063 lookup->holder()->WriteToField(lookup->GetDescriptorIndex(), *value); |
| 4003 } | 4064 } |
| 4004 | 4065 |
| 4005 | 4066 |
| 4006 void JSObject::ConvertAndSetOwnProperty(LookupResult* lookup, | 4067 void JSObject::ConvertAndSetOwnProperty(LookupResult* lookup, |
| 4007 Handle<Name> name, | 4068 Handle<Name> name, |
| 4008 Handle<Object> value, | 4069 Handle<Object> value, |
| 4009 PropertyAttributes attributes) { | 4070 PropertyAttributes attributes) { |
| 4010 Handle<JSObject> object(lookup->holder()); | 4071 Handle<JSObject> object(lookup->holder()); |
| 4011 if (object->TooManyFastProperties()) { | 4072 if (object->map()->TooManyFastProperties(Object::MAY_BE_STORE_FROM_KEYED)) { |
| 4012 JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); | 4073 JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); |
| 4013 } | 4074 } |
| 4014 | 4075 |
| 4015 if (!object->HasFastProperties()) { | 4076 if (!object->HasFastProperties()) { |
| 4016 ReplaceSlowProperty(object, name, value, attributes); | 4077 ReplaceSlowProperty(object, name, value, attributes); |
| 4017 return; | 4078 return; |
| 4018 } | 4079 } |
| 4019 | 4080 |
| 4020 int descriptor_index = lookup->GetDescriptorIndex(); | 4081 int descriptor_index = lookup->GetDescriptorIndex(); |
| 4021 if (lookup->GetAttributes() == attributes) { | 4082 if (lookup->GetAttributes() == attributes) { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 4039 PropertyAttributes attributes) { | 4100 PropertyAttributes attributes) { |
| 4040 if (lookup->GetAttributes() == attributes) { | 4101 if (lookup->GetAttributes() == attributes) { |
| 4041 if (value->IsUninitialized()) return; | 4102 if (value->IsUninitialized()) return; |
| 4042 SetPropertyToField(lookup, value); | 4103 SetPropertyToField(lookup, value); |
| 4043 } else { | 4104 } else { |
| 4044 ConvertAndSetOwnProperty(lookup, name, value, attributes); | 4105 ConvertAndSetOwnProperty(lookup, name, value, attributes); |
| 4045 } | 4106 } |
| 4046 } | 4107 } |
| 4047 | 4108 |
| 4048 | 4109 |
| 4049 MaybeHandle<Object> JSObject::SetPropertyForResult( | |
| 4050 Handle<JSObject> object, | |
| 4051 LookupResult* lookup, | |
| 4052 Handle<Name> name, | |
| 4053 Handle<Object> value, | |
| 4054 StrictMode strict_mode, | |
| 4055 StoreFromKeyed store_mode) { | |
| 4056 Isolate* isolate = object->GetIsolate(); | |
| 4057 | |
| 4058 // Make sure that the top context does not change when doing callbacks or | |
| 4059 // interceptor calls. | |
| 4060 AssertNoContextChange ncc(isolate); | |
| 4061 | |
| 4062 // Optimization for 2-byte strings often used as keys in a decompression | |
| 4063 // dictionary. We internalize these short keys to avoid constantly | |
| 4064 // reallocating them. | |
| 4065 if (name->IsString() && !name->IsInternalizedString() && | |
| 4066 Handle<String>::cast(name)->length() <= 2) { | |
| 4067 name = isolate->factory()->InternalizeString(Handle<String>::cast(name)); | |
| 4068 } | |
| 4069 | |
| 4070 // Check access rights if needed. | |
| 4071 if (object->IsAccessCheckNeeded()) { | |
| 4072 if (!isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) { | |
| 4073 return SetPropertyWithFailedAccessCheck(object, lookup, name, value, | |
| 4074 true, strict_mode); | |
| 4075 } | |
| 4076 } | |
| 4077 | |
| 4078 if (object->IsJSGlobalProxy()) { | |
| 4079 Handle<Object> proto(object->GetPrototype(), isolate); | |
| 4080 if (proto->IsNull()) return value; | |
| 4081 ASSERT(proto->IsJSGlobalObject()); | |
| 4082 return SetPropertyForResult(Handle<JSObject>::cast(proto), lookup, name, | |
| 4083 value, strict_mode, store_mode); | |
| 4084 } | |
| 4085 | |
| 4086 ASSERT(!lookup->IsFound() || lookup->holder() == *object || | |
| 4087 lookup->holder()->map()->is_hidden_prototype()); | |
| 4088 | |
| 4089 if (!lookup->IsProperty() && !object->IsJSContextExtensionObject()) { | |
| 4090 bool done = false; | |
| 4091 Handle<Object> result_object; | |
| 4092 ASSIGN_RETURN_ON_EXCEPTION( | |
| 4093 isolate, result_object, | |
| 4094 SetPropertyViaPrototypes(object, name, value, strict_mode, &done), | |
| 4095 Object); | |
| 4096 if (done) return result_object; | |
| 4097 } | |
| 4098 | |
| 4099 if (!lookup->IsFound()) { | |
| 4100 // Neither properties nor transitions found. | |
| 4101 return AddPropertyInternal(object, name, value, NONE, strict_mode, | |
| 4102 store_mode); | |
| 4103 } | |
| 4104 | |
| 4105 if (lookup->IsProperty() && lookup->IsReadOnly()) { | |
| 4106 if (strict_mode == STRICT) { | |
| 4107 Handle<Object> args[] = { name, object }; | |
| 4108 Handle<Object> error = isolate->factory()->NewTypeError( | |
| 4109 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))); | |
| 4110 return isolate->Throw<Object>(error); | |
| 4111 } else { | |
| 4112 return value; | |
| 4113 } | |
| 4114 } | |
| 4115 | |
| 4116 Handle<Object> old_value = isolate->factory()->the_hole_value(); | |
| 4117 bool is_observed = object->map()->is_observed() && | |
| 4118 *name != isolate->heap()->hidden_string(); | |
| 4119 if (is_observed && lookup->IsDataProperty()) { | |
| 4120 old_value = Object::GetPropertyOrElement(object, name).ToHandleChecked(); | |
| 4121 } | |
| 4122 | |
| 4123 // This is a real property that is not read-only, or it is a | |
| 4124 // transition or null descriptor and there are no setters in the prototypes. | |
| 4125 MaybeHandle<Object> maybe_result = value; | |
| 4126 if (lookup->IsTransition()) { | |
| 4127 maybe_result = SetPropertyUsingTransition(handle(lookup->holder()), lookup, | |
| 4128 name, value, NONE); | |
| 4129 } else { | |
| 4130 switch (lookup->type()) { | |
| 4131 case NORMAL: | |
| 4132 SetNormalizedProperty(handle(lookup->holder()), lookup, value); | |
| 4133 break; | |
| 4134 case FIELD: | |
| 4135 SetPropertyToField(lookup, value); | |
| 4136 break; | |
| 4137 case CONSTANT: | |
| 4138 // Only replace the constant if necessary. | |
| 4139 if (*value == lookup->GetConstant()) return value; | |
| 4140 SetPropertyToField(lookup, value); | |
| 4141 break; | |
| 4142 case CALLBACKS: { | |
| 4143 Handle<Object> callback_object(lookup->GetCallbackObject(), isolate); | |
| 4144 return SetPropertyWithCallback(object, name, value, | |
| 4145 handle(lookup->holder()), | |
| 4146 callback_object, strict_mode); | |
| 4147 } | |
| 4148 case INTERCEPTOR: | |
| 4149 maybe_result = SetPropertyWithInterceptor(handle(lookup->holder()), | |
| 4150 name, value, strict_mode); | |
| 4151 break; | |
| 4152 case HANDLER: | |
| 4153 case NONEXISTENT: | |
| 4154 UNREACHABLE(); | |
| 4155 } | |
| 4156 } | |
| 4157 | |
| 4158 Handle<Object> result; | |
| 4159 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, maybe_result, Object); | |
| 4160 | |
| 4161 if (is_observed) { | |
| 4162 if (lookup->IsTransition()) { | |
| 4163 EnqueueChangeRecord(object, "add", name, old_value); | |
| 4164 } else { | |
| 4165 LookupResult new_lookup(isolate); | |
| 4166 object->LookupOwn(name, &new_lookup, true); | |
| 4167 if (new_lookup.IsDataProperty()) { | |
| 4168 Handle<Object> new_value = | |
| 4169 Object::GetPropertyOrElement(object, name).ToHandleChecked(); | |
| 4170 if (!new_value->SameValue(*old_value)) { | |
| 4171 EnqueueChangeRecord(object, "update", name, old_value); | |
| 4172 } | |
| 4173 } | |
| 4174 } | |
| 4175 } | |
| 4176 | |
| 4177 return result; | |
| 4178 } | |
| 4179 | |
| 4180 | |
| 4181 void JSObject::AddProperty( | 4110 void JSObject::AddProperty( |
| 4182 Handle<JSObject> object, | 4111 Handle<JSObject> object, |
| 4183 Handle<Name> name, | 4112 Handle<Name> name, |
| 4184 Handle<Object> value, | 4113 Handle<Object> value, |
| 4185 PropertyAttributes attributes, | 4114 PropertyAttributes attributes, |
| 4186 StoreMode store_mode) { | 4115 StoreMode store_mode) { |
| 4187 #ifdef DEBUG | 4116 #ifdef DEBUG |
| 4188 uint32_t index; | 4117 uint32_t index; |
| 4189 ASSERT(!object->IsJSProxy()); | 4118 ASSERT(!object->IsJSProxy()); |
| 4190 ASSERT(!name->AsArrayIndex(&index)); | 4119 ASSERT(!name->AsArrayIndex(&index)); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 4217 | 4146 |
| 4218 LookupResult lookup(isolate); | 4147 LookupResult lookup(isolate); |
| 4219 object->LookupOwn(name, &lookup, true); | 4148 object->LookupOwn(name, &lookup, true); |
| 4220 if (!lookup.IsFound()) { | 4149 if (!lookup.IsFound()) { |
| 4221 object->map()->LookupTransition(*object, *name, &lookup); | 4150 object->map()->LookupTransition(*object, *name, &lookup); |
| 4222 } | 4151 } |
| 4223 | 4152 |
| 4224 // Check access rights if needed. | 4153 // Check access rights if needed. |
| 4225 if (object->IsAccessCheckNeeded()) { | 4154 if (object->IsAccessCheckNeeded()) { |
| 4226 if (!isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) { | 4155 if (!isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) { |
| 4227 return SetPropertyWithFailedAccessCheck(object, &lookup, name, value, | 4156 LookupIterator it(object, name, LookupIterator::CHECK_OWN); |
| 4228 false, SLOPPY); | 4157 return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY); |
| 4229 } | 4158 } |
| 4230 } | 4159 } |
| 4231 | 4160 |
| 4232 if (object->IsJSGlobalProxy()) { | 4161 if (object->IsJSGlobalProxy()) { |
| 4233 Handle<Object> proto(object->GetPrototype(), isolate); | 4162 Handle<Object> proto(object->GetPrototype(), isolate); |
| 4234 if (proto->IsNull()) return value; | 4163 if (proto->IsNull()) return value; |
| 4235 ASSERT(proto->IsJSGlobalObject()); | 4164 ASSERT(proto->IsJSGlobalObject()); |
| 4236 return SetOwnPropertyIgnoreAttributes(Handle<JSObject>::cast(proto), name, | 4165 return SetOwnPropertyIgnoreAttributes(Handle<JSObject>::cast(proto), name, |
| 4237 value, attributes, mode, | 4166 value, attributes, mode, |
| 4238 extensibility_check); | 4167 extensibility_check); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4290 SetPropertyToFieldWithAttributes(&lookup, name, value, attributes); | 4219 SetPropertyToFieldWithAttributes(&lookup, name, value, attributes); |
| 4291 } | 4220 } |
| 4292 break; | 4221 break; |
| 4293 case CALLBACKS: | 4222 case CALLBACKS: |
| 4294 { | 4223 { |
| 4295 Handle<Object> callback(lookup.GetCallbackObject(), isolate); | 4224 Handle<Object> callback(lookup.GetCallbackObject(), isolate); |
| 4296 if (callback->IsExecutableAccessorInfo() && | 4225 if (callback->IsExecutableAccessorInfo() && |
| 4297 handling == DONT_FORCE_FIELD) { | 4226 handling == DONT_FORCE_FIELD) { |
| 4298 Handle<Object> result; | 4227 Handle<Object> result; |
| 4299 ASSIGN_RETURN_ON_EXCEPTION( | 4228 ASSIGN_RETURN_ON_EXCEPTION( |
| 4300 isolate, result, | 4229 isolate, result, JSObject::SetPropertyWithAccessor( |
| 4301 JSObject::SetPropertyWithCallback(object, | 4230 object, name, value, handle(lookup.holder()), |
| 4302 name, | 4231 callback, STRICT), |
| 4303 value, | |
| 4304 handle(lookup.holder()), | |
| 4305 callback, | |
| 4306 STRICT), | |
| 4307 Object); | 4232 Object); |
| 4308 | 4233 |
| 4309 if (attributes != lookup.GetAttributes()) { | 4234 if (attributes != lookup.GetAttributes()) { |
| 4310 Handle<ExecutableAccessorInfo> new_data = | 4235 Handle<ExecutableAccessorInfo> new_data = |
| 4311 Accessors::CloneAccessor( | 4236 Accessors::CloneAccessor( |
| 4312 isolate, Handle<ExecutableAccessorInfo>::cast(callback)); | 4237 isolate, Handle<ExecutableAccessorInfo>::cast(callback)); |
| 4313 new_data->set_property_attributes(attributes); | 4238 new_data->set_property_attributes(attributes); |
| 4314 if (attributes & READ_ONLY) { | 4239 if (attributes & READ_ONLY) { |
| 4315 // This way we don't have to introduce a lookup to the setter, | 4240 // This way we don't have to introduce a lookup to the setter, |
| 4316 // simply make it unavailable to reflect the attributes. | 4241 // simply make it unavailable to reflect the attributes. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4365 | 4290 |
| 4366 return value; | 4291 return value; |
| 4367 } | 4292 } |
| 4368 | 4293 |
| 4369 | 4294 |
| 4370 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( | 4295 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( |
| 4371 Handle<JSObject> holder, | 4296 Handle<JSObject> holder, |
| 4372 Handle<Object> receiver, | 4297 Handle<Object> receiver, |
| 4373 Handle<Name> name) { | 4298 Handle<Name> name) { |
| 4374 // TODO(rossberg): Support symbols in the API. | 4299 // TODO(rossberg): Support symbols in the API. |
| 4375 if (name->IsSymbol()) return Maybe<PropertyAttributes>(ABSENT); | 4300 if (name->IsSymbol()) return Maybe<PropertyAttributes>(); |
| 4376 | 4301 |
| 4377 Isolate* isolate = holder->GetIsolate(); | 4302 Isolate* isolate = holder->GetIsolate(); |
| 4378 HandleScope scope(isolate); | 4303 HandleScope scope(isolate); |
| 4379 | 4304 |
| 4380 // Make sure that the top context does not change when doing | 4305 // Make sure that the top context does not change when doing |
| 4381 // callbacks or interceptor calls. | 4306 // callbacks or interceptor calls. |
| 4382 AssertNoContextChange ncc(isolate); | 4307 AssertNoContextChange ncc(isolate); |
| 4383 | 4308 |
| 4384 Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor()); | 4309 Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor()); |
| 4385 PropertyCallbackArguments args( | 4310 PropertyCallbackArguments args( |
| (...skipping 2974 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7360 handle(map->instance_descriptors(), isolate), num_descriptors, FROZEN); | 7285 handle(map->instance_descriptors(), isolate), num_descriptors, FROZEN); |
| 7361 Handle<Map> new_map = CopyReplaceDescriptors( | 7286 Handle<Map> new_map = CopyReplaceDescriptors( |
| 7362 map, new_desc, INSERT_TRANSITION, isolate->factory()->frozen_symbol()); | 7287 map, new_desc, INSERT_TRANSITION, isolate->factory()->frozen_symbol()); |
| 7363 new_map->freeze(); | 7288 new_map->freeze(); |
| 7364 new_map->set_is_extensible(false); | 7289 new_map->set_is_extensible(false); |
| 7365 new_map->set_elements_kind(DICTIONARY_ELEMENTS); | 7290 new_map->set_elements_kind(DICTIONARY_ELEMENTS); |
| 7366 return new_map; | 7291 return new_map; |
| 7367 } | 7292 } |
| 7368 | 7293 |
| 7369 | 7294 |
| 7295 bool DescriptorArray::CanHoldValue(int descriptor, Object* value) { | |
| 7296 PropertyDetails details = GetDetails(descriptor); | |
| 7297 switch (details.type()) { | |
| 7298 case FIELD: | |
| 7299 return value->FitsRepresentation(details.representation()) && | |
| 7300 GetFieldType(descriptor)->NowContains(value); | |
| 7301 | |
| 7302 case CONSTANT: | |
| 7303 ASSERT(GetConstant(descriptor) != value || | |
| 7304 value->FitsRepresentation(details.representation())); | |
| 7305 return GetConstant(descriptor) == value; | |
| 7306 | |
| 7307 case CALLBACKS: | |
| 7308 return false; | |
| 7309 | |
| 7310 case NORMAL: | |
| 7311 case INTERCEPTOR: | |
| 7312 case HANDLER: | |
| 7313 case NONEXISTENT: | |
| 7314 break; | |
| 7315 } | |
| 7316 | |
| 7317 UNREACHABLE(); | |
| 7318 return false; | |
| 7319 } | |
| 7320 | |
| 7321 | |
| 7322 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor, | |
| 7323 Handle<Object> value) { | |
| 7324 // Dictionaries can store any property value. | |
| 7325 if (map->is_dictionary_map()) return map; | |
| 7326 | |
| 7327 Handle<DescriptorArray> descriptors(map->instance_descriptors()); | |
| 7328 | |
| 7329 if (descriptors->CanHoldValue(descriptor, *value)) return map; | |
| 7330 | |
| 7331 Isolate* isolate = map->GetIsolate(); | |
| 7332 Representation representation = value->OptimalRepresentation(); | |
| 7333 Handle<HeapType> type = value->OptimalType(isolate, representation); | |
| 7334 | |
| 7335 return GeneralizeRepresentation(map, descriptor, representation, type, | |
| 7336 FORCE_FIELD); | |
| 7337 } | |
| 7338 | |
| 7339 | |
| 7340 Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name, | |
| 7341 Handle<Object> value, | |
| 7342 PropertyAttributes attributes, | |
| 7343 StoreFromKeyed store_mode) { | |
| 7344 // Cannot currently handle deprecated maps. | |
| 7345 ASSERT(!map->is_deprecated()); | |
| 7346 // Dictionary maps can always have additional data properties. | |
| 7347 if (map->is_dictionary_map()) return map; | |
| 7348 | |
| 7349 int index = map->SearchTransition(*name); | |
| 7350 if (index != TransitionArray::kNotFound) { | |
| 7351 Handle<Map> transition(map->GetTransition(index)); | |
| 7352 int descriptor = transition->LastAdded(); | |
| 7353 | |
| 7354 // TODO(verwaest): Handle attributes better. | |
| 7355 DescriptorArray* descriptors = transition->instance_descriptors(); | |
| 7356 if (descriptors->GetDetails(descriptor).attributes() != attributes) { | |
| 7357 return CopyGeneralizeAllRepresentations(transition, descriptor, | |
| 7358 FORCE_FIELD, attributes, | |
| 7359 "attributes mismatch"); | |
| 7360 } | |
| 7361 | |
| 7362 return Map::PrepareForDataProperty(transition, descriptor, value); | |
| 7363 } | |
| 7364 | |
| 7365 TransitionFlag flag = INSERT_TRANSITION; | |
| 7366 MaybeHandle<Map> maybe_map; | |
| 7367 if (value->IsJSFunction()) { | |
| 7368 maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag); | |
| 7369 } else if (!map->TooManyFastProperties(store_mode)) { | |
| 7370 Isolate* isolate = name->GetIsolate(); | |
| 7371 Representation representation = value->OptimalRepresentation(); | |
| 7372 Handle<HeapType> type = value->OptimalType(isolate, representation); | |
| 7373 maybe_map = | |
| 7374 Map::CopyWithField(map, name, type, attributes, representation, flag); | |
| 7375 } | |
| 7376 | |
| 7377 Handle<Map> result; | |
| 7378 if (!maybe_map.ToHandle(&result)) { | |
| 7379 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES); | |
| 7380 } | |
| 7381 | |
| 7382 return result; | |
| 7383 } | |
| 7384 | |
| 7385 | |
| 7370 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map, | 7386 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map, |
| 7371 Descriptor* descriptor, | 7387 Descriptor* descriptor, |
| 7372 TransitionFlag flag) { | 7388 TransitionFlag flag) { |
| 7373 Handle<DescriptorArray> descriptors(map->instance_descriptors()); | 7389 Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
| 7374 | 7390 |
| 7375 // Ensure the key is unique. | 7391 // Ensure the key is unique. |
| 7376 descriptor->KeyToUniqueName(); | 7392 descriptor->KeyToUniqueName(); |
| 7377 | 7393 |
| 7378 if (flag == INSERT_TRANSITION && | 7394 if (flag == INSERT_TRANSITION && |
| 7379 map->owns_descriptors() && | 7395 map->owns_descriptors() && |
| (...skipping 9535 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 16915 #define ERROR_MESSAGES_TEXTS(C, T) T, | 16931 #define ERROR_MESSAGES_TEXTS(C, T) T, |
| 16916 static const char* error_messages_[] = { | 16932 static const char* error_messages_[] = { |
| 16917 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) | 16933 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) |
| 16918 }; | 16934 }; |
| 16919 #undef ERROR_MESSAGES_TEXTS | 16935 #undef ERROR_MESSAGES_TEXTS |
| 16920 return error_messages_[reason]; | 16936 return error_messages_[reason]; |
| 16921 } | 16937 } |
| 16922 | 16938 |
| 16923 | 16939 |
| 16924 } } // namespace v8::internal | 16940 } } // namespace v8::internal |
| OLD | NEW |