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 |