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