Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 2743 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2754 | 2754 |
| 2755 int attributes = NONE; | 2755 int attributes = NONE; |
| 2756 if (enumerable->ToBoolean()->IsFalse()) attributes |= DONT_ENUM; | 2756 if (enumerable->ToBoolean()->IsFalse()) attributes |= DONT_ENUM; |
| 2757 if (configurable->ToBoolean()->IsFalse()) attributes |= DONT_DELETE; | 2757 if (configurable->ToBoolean()->IsFalse()) attributes |= DONT_DELETE; |
| 2758 if (writable->ToBoolean()->IsFalse()) attributes |= READ_ONLY; | 2758 if (writable->ToBoolean()->IsFalse()) attributes |= READ_ONLY; |
| 2759 return static_cast<PropertyAttributes>(attributes); | 2759 return static_cast<PropertyAttributes>(attributes); |
| 2760 } | 2760 } |
| 2761 | 2761 |
| 2762 | 2762 |
| 2763 MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler( | 2763 MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler( |
| 2764 JSReceiver* receiver, | 2764 JSReceiver* receiver_raw, |
| 2765 uint32_t index) { | 2765 uint32_t index) { |
| 2766 Isolate* isolate = GetIsolate(); | 2766 Isolate* isolate = GetIsolate(); |
| 2767 HandleScope scope(isolate); | 2767 HandleScope scope(isolate); |
| 2768 Handle<JSProxy> proxy(this); | |
| 2769 Handle<JSReceiver> receiver(receiver_raw); | |
| 2768 Handle<String> name = isolate->factory()->Uint32ToString(index); | 2770 Handle<String> name = isolate->factory()->Uint32ToString(index); |
| 2769 return GetPropertyAttributeWithHandler(receiver, *name); | 2771 return proxy->GetPropertyAttributeWithHandler(*receiver, *name); |
| 2770 } | 2772 } |
| 2771 | 2773 |
| 2772 | 2774 |
| 2773 void JSProxy::Fix() { | 2775 void JSProxy::Fix() { |
| 2774 Isolate* isolate = GetIsolate(); | 2776 Isolate* isolate = GetIsolate(); |
| 2775 HandleScope scope(isolate); | 2777 HandleScope scope(isolate); |
| 2776 Handle<JSProxy> self(this); | 2778 Handle<JSProxy> self(this); |
| 2777 | 2779 |
| 2778 // Save identity hash. | 2780 // Save identity hash. |
| 2779 MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION); | 2781 MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2893 if (strict_mode == kStrictMode) { | 2895 if (strict_mode == kStrictMode) { |
| 2894 Handle<Object> args[] = { name, self }; | 2896 Handle<Object> args[] = { name, self }; |
| 2895 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError( | 2897 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError( |
| 2896 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)))); | 2898 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)))); |
| 2897 } else { | 2899 } else { |
| 2898 return *value; | 2900 return *value; |
| 2899 } | 2901 } |
| 2900 } | 2902 } |
| 2901 | 2903 |
| 2902 Handle<Object> old_value(heap->the_hole_value()); | 2904 Handle<Object> old_value(heap->the_hole_value()); |
| 2905 PropertyAttributes old_attributes; | |
| 2903 if (FLAG_harmony_observation && map()->is_observed()) { | 2906 if (FLAG_harmony_observation && map()->is_observed()) { |
| 2904 // TODO(observe): save oldValue | 2907 switch (lookup->type()) { |
| 2908 case NORMAL: | |
| 2909 case FIELD: | |
| 2910 case CONSTANT_FUNCTION: | |
| 2911 case INTERCEPTOR: | |
|
adamk
2012/11/06 14:08:53
Asking for oldValues for interceptors (or in fact
rossberg
2012/11/07 14:05:54
Changed.
| |
| 2912 old_value = | |
| 2913 Object::GetProperty(self, self, lookup, name, &old_attributes); | |
|
rafaelw
2012/11/07 10:26:20
Consider using lookup.GetLazyValue()? Note: this w
adamk
2012/11/07 10:30:29
Might also bypass access checks, though, which I d
rossberg
2012/11/07 14:05:54
Access checks are already handled further up, I th
rossberg
2012/11/07 14:05:54
Done, here and elsewhere. With a little tweak to t
| |
| 2914 case CALLBACKS: | |
| 2915 case TRANSITION: | |
| 2916 case HANDLER: | |
| 2917 case NONEXISTENT: | |
| 2918 break; | |
| 2919 } | |
| 2905 } | 2920 } |
| 2906 | 2921 |
| 2907 // This is a real property that is not read-only, or it is a | 2922 // This is a real property that is not read-only, or it is a |
| 2908 // transition or null descriptor and there are no setters in the prototypes. | 2923 // transition or null descriptor and there are no setters in the prototypes. |
| 2909 MaybeObject* result = *value; | 2924 MaybeObject* result = *value; |
| 2910 switch (lookup->type()) { | 2925 switch (lookup->type()) { |
| 2911 case NORMAL: | 2926 case NORMAL: |
| 2912 result = self->SetNormalizedProperty(lookup, *value); | 2927 result = self->SetNormalizedProperty(lookup, *value); |
| 2913 break; | 2928 break; |
| 2914 case FIELD: | 2929 case FIELD: |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2946 if (attributes == details.attributes()) { | 2961 if (attributes == details.attributes()) { |
| 2947 int field_index = descriptors->GetFieldIndex(descriptor); | 2962 int field_index = descriptors->GetFieldIndex(descriptor); |
| 2948 result = self->AddFastPropertyUsingMap(transition_map, | 2963 result = self->AddFastPropertyUsingMap(transition_map, |
| 2949 *name, | 2964 *name, |
| 2950 *value, | 2965 *value, |
| 2951 field_index); | 2966 field_index); |
| 2952 } else { | 2967 } else { |
| 2953 result = self->ConvertDescriptorToField(*name, *value, attributes); | 2968 result = self->ConvertDescriptorToField(*name, *value, attributes); |
| 2954 } | 2969 } |
| 2955 } else if (details.type() == CALLBACKS) { | 2970 } else if (details.type() == CALLBACKS) { |
| 2956 result = ConvertDescriptorToField(*name, *value, attributes); | 2971 result = ConvertDescriptorToField(*name, *value, attributes); |
|
Toon Verwaest
2012/11/06 17:35:47
self->
rossberg
2012/11/07 14:05:54
Done.
| |
| 2957 } else { | 2972 } else { |
| 2958 ASSERT(details.type() == CONSTANT_FUNCTION); | 2973 ASSERT(details.type() == CONSTANT_FUNCTION); |
| 2959 | 2974 |
| 2960 Object* constant_function = descriptors->GetValue(descriptor); | 2975 Object* constant_function = descriptors->GetValue(descriptor); |
| 2961 if (constant_function == *value) { | 2976 if (constant_function == *value) { |
| 2962 // If the same constant function is being added we can simply | 2977 // If the same constant function is being added we can simply |
| 2963 // transition to the target map. | 2978 // transition to the target map. |
| 2964 self->set_map(transition_map); | 2979 self->set_map(transition_map); |
| 2965 result = constant_function; | 2980 result = constant_function; |
| 2966 } else { | 2981 } else { |
| 2967 // Otherwise, replace with a map transition to a new map with a FIELD, | 2982 // Otherwise, replace with a map transition to a new map with a FIELD, |
| 2968 // even if the value is a constant function. | 2983 // even if the value is a constant function. |
| 2969 result = ConvertTransitionToMapTransition( | 2984 result = ConvertTransitionToMapTransition( |
|
Toon Verwaest
2012/11/06 17:35:47
self->
rossberg
2012/11/07 14:05:54
Done.
| |
| 2970 lookup->GetTransitionIndex(), *name, *value, attributes); | 2985 lookup->GetTransitionIndex(), *name, *value, attributes); |
| 2971 } | 2986 } |
| 2972 } | 2987 } |
| 2973 break; | 2988 break; |
| 2974 } | 2989 } |
| 2975 case HANDLER: | 2990 case HANDLER: |
| 2976 case NONEXISTENT: | 2991 case NONEXISTENT: |
| 2977 UNREACHABLE(); | 2992 UNREACHABLE(); |
| 2978 } | 2993 } |
| 2979 | 2994 |
| 2980 Handle<Object> hresult; | 2995 Handle<Object> hresult; |
| 2981 if (!result->ToHandle(&hresult)) return result; | 2996 if (!result->ToHandle(&hresult)) return result; |
| 2982 | 2997 |
| 2983 if (FLAG_harmony_observation && map()->is_observed()) { | 2998 if (FLAG_harmony_observation && map()->is_observed()) { |
| 2984 this->EnqueueChangeRecord("updated", name, old_value); | 2999 PropertyAttributes new_attributes = self->GetLocalPropertyAttribute(*name); |
| 3000 if (lookup->IsTransition()) { | |
| 3001 self->EnqueueChangeRecord("new", name, old_value); | |
| 3002 } else if (new_attributes != old_attributes) { | |
|
rafaelw
2012/11/07 10:26:20
out of curiosity: how can it happen that new_attri
rossberg
2012/11/07 14:05:54
Right, I think it cannot in this case. Removed.
| |
| 3003 self->EnqueueChangeRecord("reconfigured", name, old_value); | |
| 3004 } else { | |
| 3005 PropertyAttributes attributes; | |
| 3006 Handle<Object> new_value = | |
| 3007 Object::GetProperty(self, self, lookup, name, &attributes); | |
| 3008 if (!new_value->SameValue(*old_value)) | |
| 3009 self->EnqueueChangeRecord("updated", name, old_value); | |
|
Toon Verwaest
2012/11/06 17:35:47
Wouldn't it be less error-prone to make EnqueueCha
rossberg
2012/11/07 14:05:54
Probably, but the same is true for quite a few oth
| |
| 3010 } | |
| 2985 } | 3011 } |
| 2986 | 3012 |
| 2987 return *hresult; | 3013 return *hresult; |
| 2988 } | 3014 } |
| 2989 | 3015 |
| 2990 | 3016 |
| 2991 // Set a real local property, even if it is READ_ONLY. If the property is not | 3017 // Set a real local property, even if it is READ_ONLY. If the property is not |
| 2992 // present, add it with attributes NONE. This code is an exact clone of | 3018 // present, add it with attributes NONE. This code is an exact clone of |
| 2993 // SetProperty, with the check for IsReadOnly and the check for a | 3019 // SetProperty, with the check for IsReadOnly and the check for a |
| 2994 // callback setter removed. The two lines looking up the LookupResult | 3020 // callback setter removed. The two lines looking up the LookupResult |
| 2995 // result are also added. If one of the functions is changed, the other | 3021 // result are also added. If one of the functions is changed, the other |
| 2996 // should be. | 3022 // should be. |
| 2997 // Note that this method cannot be used to set the prototype of a function | 3023 // Note that this method cannot be used to set the prototype of a function |
| 2998 // because ConvertDescriptorToField() which is called in "case CALLBACKS:" | 3024 // because ConvertDescriptorToField() which is called in "case CALLBACKS:" |
| 2999 // doesn't handle function prototypes correctly. | 3025 // doesn't handle function prototypes correctly. |
| 3000 Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes( | 3026 Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes( |
| 3001 Handle<JSObject> object, | 3027 Handle<JSObject> object, |
| 3002 Handle<String> key, | 3028 Handle<String> key, |
| 3003 Handle<Object> value, | 3029 Handle<Object> value, |
| 3004 PropertyAttributes attributes) { | 3030 PropertyAttributes attributes) { |
| 3005 CALL_HEAP_FUNCTION( | 3031 CALL_HEAP_FUNCTION( |
| 3006 object->GetIsolate(), | 3032 object->GetIsolate(), |
| 3007 object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes), | 3033 object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes), |
| 3008 Object); | 3034 Object); |
| 3009 } | 3035 } |
| 3010 | 3036 |
| 3011 | 3037 |
| 3012 MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( | 3038 MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( |
| 3013 String* name, | 3039 String* name_raw, |
| 3014 Object* value, | 3040 Object* value_raw, |
| 3015 PropertyAttributes attributes) { | 3041 PropertyAttributes attributes) { |
| 3016 // Make sure that the top context does not change when doing callbacks or | 3042 // Make sure that the top context does not change when doing callbacks or |
| 3017 // interceptor calls. | 3043 // interceptor calls. |
| 3018 AssertNoContextChange ncc; | 3044 AssertNoContextChange ncc; |
| 3019 Isolate* isolate = GetIsolate(); | 3045 Isolate* isolate = GetIsolate(); |
| 3020 LookupResult lookup(isolate); | 3046 LookupResult lookup(isolate); |
| 3021 LocalLookup(name, &lookup); | 3047 LocalLookup(name_raw, &lookup); |
| 3022 if (!lookup.IsFound()) map()->LookupTransition(this, name, &lookup); | 3048 if (!lookup.IsFound()) map()->LookupTransition(this, name_raw, &lookup); |
| 3023 // Check access rights if needed. | 3049 // Check access rights if needed. |
| 3024 if (IsAccessCheckNeeded()) { | 3050 if (IsAccessCheckNeeded()) { |
| 3025 if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { | 3051 if (!isolate->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) { |
| 3026 return SetPropertyWithFailedAccessCheck(&lookup, | 3052 return SetPropertyWithFailedAccessCheck(&lookup, |
| 3027 name, | 3053 name_raw, |
| 3028 value, | 3054 value_raw, |
| 3029 false, | 3055 false, |
| 3030 kNonStrictMode); | 3056 kNonStrictMode); |
| 3031 } | 3057 } |
| 3032 } | 3058 } |
| 3033 | 3059 |
| 3034 if (IsJSGlobalProxy()) { | 3060 if (IsJSGlobalProxy()) { |
| 3035 Object* proto = GetPrototype(); | 3061 Object* proto = GetPrototype(); |
| 3036 if (proto->IsNull()) return value; | 3062 if (proto->IsNull()) return value_raw; |
| 3037 ASSERT(proto->IsJSGlobalObject()); | 3063 ASSERT(proto->IsJSGlobalObject()); |
| 3038 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes( | 3064 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes( |
| 3039 name, | 3065 name_raw, |
| 3040 value, | 3066 value_raw, |
| 3041 attributes); | 3067 attributes); |
| 3042 } | 3068 } |
| 3043 | 3069 |
| 3044 // Check for accessor in prototype chain removed here in clone. | 3070 // Check for accessor in prototype chain removed here in clone. |
| 3045 if (!lookup.IsFound()) { | 3071 if (!lookup.IsFound()) { |
| 3046 // Neither properties nor transitions found. | 3072 // Neither properties nor transitions found. |
| 3047 return AddProperty(name, value, attributes, kNonStrictMode); | 3073 return AddProperty(name_raw, value_raw, attributes, kNonStrictMode); |
| 3048 } | 3074 } |
| 3049 | 3075 |
| 3076 // From this point on everything needs to be handlified. | |
| 3077 HandleScope scope(GetIsolate()); | |
| 3078 Handle<JSObject> self(this); | |
| 3079 Handle<String> name(name_raw); | |
| 3080 Handle<Object> value(value_raw); | |
| 3081 | |
| 3050 Handle<Object> old_value(isolate->heap()->the_hole_value()); | 3082 Handle<Object> old_value(isolate->heap()->the_hole_value()); |
| 3083 PropertyAttributes old_attributes; | |
| 3051 if (FLAG_harmony_observation && map()->is_observed()) { | 3084 if (FLAG_harmony_observation && map()->is_observed()) { |
| 3052 // TODO(observe): save oldValue | 3085 switch (lookup.type()) { |
| 3086 case NORMAL: | |
| 3087 case FIELD: | |
| 3088 case CONSTANT_FUNCTION: | |
| 3089 case INTERCEPTOR: | |
| 3090 old_value = | |
| 3091 Object::GetProperty(self, self, &lookup, name, &old_attributes); | |
|
rafaelw
2012/11/07 10:26:20
ditto: GetLazyValue()
rossberg
2012/11/07 14:05:54
Done.
| |
| 3092 case CALLBACKS: | |
| 3093 case TRANSITION: | |
| 3094 case HANDLER: | |
| 3095 case NONEXISTENT: | |
| 3096 break; | |
| 3097 } | |
| 3053 } | 3098 } |
| 3054 | 3099 |
| 3055 // Check of IsReadOnly removed from here in clone. | 3100 // Check of IsReadOnly removed from here in clone. |
| 3056 MaybeObject* result = value; | 3101 MaybeObject* result = *value; |
| 3057 switch (lookup.type()) { | 3102 switch (lookup.type()) { |
| 3058 case NORMAL: { | 3103 case NORMAL: { |
| 3059 PropertyDetails details = PropertyDetails(attributes, NORMAL); | 3104 PropertyDetails details = PropertyDetails(attributes, NORMAL); |
| 3060 result = SetNormalizedProperty(name, value, details); | 3105 result = self->SetNormalizedProperty(*name, *value, details); |
| 3061 break; | 3106 break; |
| 3062 } | 3107 } |
| 3063 case FIELD: | 3108 case FIELD: |
| 3064 result = FastPropertyAtPut(lookup.GetFieldIndex(), value); | 3109 result = self->FastPropertyAtPut(lookup.GetFieldIndex(), *value); |
| 3065 break; | 3110 break; |
| 3066 case CONSTANT_FUNCTION: | 3111 case CONSTANT_FUNCTION: |
| 3067 // Only replace the function if necessary. | 3112 // Only replace the function if necessary. |
| 3068 if (value == lookup.GetConstantFunction()) return value; | 3113 if (*value != lookup.GetConstantFunction()) { |
| 3069 // Preserve the attributes of this existing property. | 3114 // Preserve the attributes of this existing property. |
| 3070 attributes = lookup.GetAttributes(); | 3115 attributes = lookup.GetAttributes(); |
| 3071 result = ConvertDescriptorToField(name, value, attributes); | 3116 result = self->ConvertDescriptorToField(*name, *value, attributes); |
| 3117 } | |
| 3072 break; | 3118 break; |
| 3073 case CALLBACKS: | 3119 case CALLBACKS: |
| 3074 case INTERCEPTOR: | 3120 case INTERCEPTOR: |
| 3075 // Override callback in clone | 3121 // Override callback in clone |
| 3076 result = ConvertDescriptorToField(name, value, attributes); | 3122 result = self->ConvertDescriptorToField(*name, *value, attributes); |
| 3077 break; | 3123 break; |
| 3078 case TRANSITION: { | 3124 case TRANSITION: { |
| 3079 Map* transition_map = lookup.GetTransitionTarget(); | 3125 Map* transition_map = lookup.GetTransitionTarget(); |
| 3080 int descriptor = transition_map->LastAdded(); | 3126 int descriptor = transition_map->LastAdded(); |
| 3081 | 3127 |
| 3082 DescriptorArray* descriptors = transition_map->instance_descriptors(); | 3128 DescriptorArray* descriptors = transition_map->instance_descriptors(); |
| 3083 PropertyDetails details = descriptors->GetDetails(descriptor); | 3129 PropertyDetails details = descriptors->GetDetails(descriptor); |
| 3084 | 3130 |
| 3085 if (details.type() == FIELD) { | 3131 if (details.type() == FIELD) { |
| 3086 if (attributes == details.attributes()) { | 3132 if (attributes == details.attributes()) { |
| 3087 int field_index = descriptors->GetFieldIndex(descriptor); | 3133 int field_index = descriptors->GetFieldIndex(descriptor); |
| 3088 result = AddFastPropertyUsingMap(transition_map, | 3134 result = self->AddFastPropertyUsingMap( |
| 3089 name, | 3135 transition_map, *name, *value, field_index); |
| 3090 value, | |
| 3091 field_index); | |
| 3092 } else { | 3136 } else { |
| 3093 result = ConvertDescriptorToField(name, value, attributes); | 3137 result = self->ConvertDescriptorToField(*name, *value, attributes); |
| 3094 } | 3138 } |
| 3095 } else if (details.type() == CALLBACKS) { | 3139 } else if (details.type() == CALLBACKS) { |
| 3096 result = ConvertDescriptorToField(name, value, attributes); | 3140 result = self->ConvertDescriptorToField(*name, *value, attributes); |
| 3097 } else { | 3141 } else { |
| 3098 ASSERT(details.type() == CONSTANT_FUNCTION); | 3142 ASSERT(details.type() == CONSTANT_FUNCTION); |
| 3099 | 3143 |
| 3100 // Replace transition to CONSTANT FUNCTION with a map transition to a | 3144 // Replace transition to CONSTANT FUNCTION with a map transition to a |
| 3101 // new map with a FIELD, even if the value is a function. | 3145 // new map with a FIELD, even if the value is a function. |
| 3102 result = ConvertTransitionToMapTransition( | 3146 result = self->ConvertTransitionToMapTransition( |
| 3103 lookup.GetTransitionIndex(), name, value, attributes); | 3147 lookup.GetTransitionIndex(), *name, *value, attributes); |
| 3104 } | 3148 } |
| 3105 break; | 3149 break; |
| 3106 } | 3150 } |
| 3107 case HANDLER: | 3151 case HANDLER: |
| 3108 case NONEXISTENT: | 3152 case NONEXISTENT: |
| 3109 UNREACHABLE(); | 3153 UNREACHABLE(); |
| 3110 } | 3154 } |
| 3111 | 3155 |
| 3112 Handle<Object> hresult; | 3156 Handle<Object> hresult; |
| 3113 if (!result->ToHandle(&hresult)) return result; | 3157 if (!result->ToHandle(&hresult)) return result; |
| 3114 | 3158 |
| 3115 if (FLAG_harmony_observation && map()->is_observed()) { | 3159 if (FLAG_harmony_observation && map()->is_observed()) { |
| 3116 const char* type = | 3160 PropertyAttributes new_attributes = self->GetLocalPropertyAttribute(*name); |
| 3117 attributes == lookup.GetAttributes() ? "updated" : "reconfigured"; | 3161 if (lookup.IsTransition()) { |
| 3118 this->EnqueueChangeRecord(type, handle(name), old_value); | 3162 self->EnqueueChangeRecord("new", name, old_value); |
| 3163 } else if (new_attributes != old_attributes) { | |
| 3164 self->EnqueueChangeRecord("reconfigured", name, old_value); | |
| 3165 } else { | |
| 3166 Handle<Object> new_value = | |
| 3167 Object::GetProperty(self, self, &lookup, name, &old_attributes); | |
| 3168 if (!new_value->SameValue(*old_value)) | |
| 3169 self->EnqueueChangeRecord("updated", name, old_value); | |
| 3170 } | |
| 3119 } | 3171 } |
| 3120 | 3172 |
| 3121 return *hresult; | 3173 return *hresult; |
| 3122 } | 3174 } |
| 3123 | 3175 |
| 3124 | 3176 |
| 3125 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor( | 3177 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor( |
| 3126 JSObject* receiver, | 3178 JSObject* receiver, |
| 3127 String* name, | 3179 String* name, |
| 3128 bool continue_search) { | 3180 bool continue_search) { |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3196 | 3248 |
| 3197 PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver( | 3249 PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver( |
| 3198 JSReceiver* receiver, | 3250 JSReceiver* receiver, |
| 3199 String* key) { | 3251 String* key) { |
| 3200 uint32_t index = 0; | 3252 uint32_t index = 0; |
| 3201 if (IsJSObject() && key->AsArrayIndex(&index)) { | 3253 if (IsJSObject() && key->AsArrayIndex(&index)) { |
| 3202 return JSObject::cast(this)->HasElementWithReceiver(receiver, index) | 3254 return JSObject::cast(this)->HasElementWithReceiver(receiver, index) |
| 3203 ? NONE : ABSENT; | 3255 ? NONE : ABSENT; |
| 3204 } | 3256 } |
| 3205 // Named property. | 3257 // Named property. |
| 3206 LookupResult result(GetIsolate()); | 3258 LookupResult lookup(GetIsolate()); |
| 3207 Lookup(key, &result); | 3259 Lookup(key, &lookup); |
| 3208 return GetPropertyAttribute(receiver, &result, key, true); | 3260 return GetPropertyAttributeForResult(receiver, &lookup, key, true); |
| 3209 } | 3261 } |
| 3210 | 3262 |
| 3211 | 3263 |
| 3212 PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver, | 3264 PropertyAttributes JSReceiver::GetPropertyAttributeForResult( |
| 3213 LookupResult* result, | 3265 JSReceiver* receiver, |
| 3214 String* name, | 3266 LookupResult* lookup, |
| 3215 bool continue_search) { | 3267 String* name, |
| 3268 bool continue_search) { | |
| 3216 // Check access rights if needed. | 3269 // Check access rights if needed. |
| 3217 if (IsAccessCheckNeeded()) { | 3270 if (IsAccessCheckNeeded()) { |
| 3218 JSObject* this_obj = JSObject::cast(this); | 3271 JSObject* this_obj = JSObject::cast(this); |
| 3219 Heap* heap = GetHeap(); | 3272 Heap* heap = GetHeap(); |
| 3220 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) { | 3273 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) { |
| 3221 return this_obj->GetPropertyAttributeWithFailedAccessCheck( | 3274 return this_obj->GetPropertyAttributeWithFailedAccessCheck( |
| 3222 receiver, result, name, continue_search); | 3275 receiver, lookup, name, continue_search); |
| 3223 } | 3276 } |
| 3224 } | 3277 } |
| 3225 if (result->IsFound()) { | 3278 if (lookup->IsFound()) { |
| 3226 switch (result->type()) { | 3279 switch (lookup->type()) { |
| 3227 case NORMAL: // fall through | 3280 case NORMAL: // fall through |
| 3228 case FIELD: | 3281 case FIELD: |
| 3229 case CONSTANT_FUNCTION: | 3282 case CONSTANT_FUNCTION: |
| 3230 case CALLBACKS: | 3283 case CALLBACKS: |
| 3231 return result->GetAttributes(); | 3284 return lookup->GetAttributes(); |
| 3232 case HANDLER: { | 3285 case HANDLER: { |
| 3233 return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler( | 3286 return JSProxy::cast(lookup->proxy())->GetPropertyAttributeWithHandler( |
| 3234 receiver, name); | 3287 receiver, name); |
| 3235 } | 3288 } |
| 3236 case INTERCEPTOR: | 3289 case INTERCEPTOR: |
| 3237 return result->holder()->GetPropertyAttributeWithInterceptor( | 3290 return lookup->holder()->GetPropertyAttributeWithInterceptor( |
| 3238 JSObject::cast(receiver), name, continue_search); | 3291 JSObject::cast(receiver), name, continue_search); |
| 3239 case TRANSITION: | 3292 case TRANSITION: |
| 3240 case NONEXISTENT: | 3293 case NONEXISTENT: |
| 3241 UNREACHABLE(); | 3294 UNREACHABLE(); |
| 3242 } | 3295 } |
| 3243 } | 3296 } |
| 3244 return ABSENT; | 3297 return ABSENT; |
| 3245 } | 3298 } |
| 3246 | 3299 |
| 3247 | 3300 |
| 3248 PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) { | 3301 PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) { |
| 3249 // Check whether the name is an array index. | 3302 // Check whether the name is an array index. |
| 3250 uint32_t index = 0; | 3303 uint32_t index = 0; |
| 3251 if (IsJSObject() && name->AsArrayIndex(&index)) { | 3304 if (IsJSObject() && name->AsArrayIndex(&index)) { |
| 3252 if (JSObject::cast(this)->HasLocalElement(index)) return NONE; | 3305 if (JSObject::cast(this)->HasLocalElement(index)) return NONE; |
| 3253 return ABSENT; | 3306 return ABSENT; |
| 3254 } | 3307 } |
| 3255 // Named property. | 3308 // Named property. |
| 3256 LookupResult result(GetIsolate()); | 3309 LookupResult lookup(GetIsolate()); |
| 3257 LocalLookup(name, &result); | 3310 LocalLookup(name, &lookup); |
| 3258 return GetPropertyAttribute(this, &result, name, false); | 3311 return GetPropertyAttributeForResult(this, &lookup, name, false); |
| 3259 } | 3312 } |
| 3260 | 3313 |
| 3261 | 3314 |
| 3262 MaybeObject* NormalizedMapCache::Get(JSObject* obj, | 3315 MaybeObject* NormalizedMapCache::Get(JSObject* obj, |
| 3263 PropertyNormalizationMode mode) { | 3316 PropertyNormalizationMode mode) { |
| 3264 Isolate* isolate = obj->GetIsolate(); | 3317 Isolate* isolate = obj->GetIsolate(); |
| 3265 Map* fast = obj->map(); | 3318 Map* fast = obj->map(); |
| 3266 int index = fast->Hash() % kEntries; | 3319 int index = fast->Hash() % kEntries; |
| 3267 Object* result = get(index); | 3320 Object* result = get(index); |
| 3268 if (result->IsMap() && | 3321 if (result->IsMap() && |
| (...skipping 763 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4032 if (mode == STRICT_DELETION) { | 4085 if (mode == STRICT_DELETION) { |
| 4033 // Deleting a non-configurable property in strict mode. | 4086 // Deleting a non-configurable property in strict mode. |
| 4034 HandleScope scope(isolate); | 4087 HandleScope scope(isolate); |
| 4035 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) }; | 4088 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) }; |
| 4036 return isolate->Throw(*isolate->factory()->NewTypeError( | 4089 return isolate->Throw(*isolate->factory()->NewTypeError( |
| 4037 "strict_delete_property", HandleVector(args, 2))); | 4090 "strict_delete_property", HandleVector(args, 2))); |
| 4038 } | 4091 } |
| 4039 return isolate->heap()->false_value(); | 4092 return isolate->heap()->false_value(); |
| 4040 } | 4093 } |
| 4041 | 4094 |
| 4095 // From this point on everything needs to be handlified. | |
| 4042 HandleScope scope(isolate); | 4096 HandleScope scope(isolate); |
| 4097 Handle<JSObject> self(this); | |
| 4098 Handle<String> hname(name); | |
| 4099 | |
| 4043 Handle<Object> old_value(isolate->heap()->the_hole_value()); | 4100 Handle<Object> old_value(isolate->heap()->the_hole_value()); |
| 4044 if (FLAG_harmony_observation && map()->is_observed()) { | 4101 if (FLAG_harmony_observation && map()->is_observed()) { |
| 4045 // TODO(observe): save oldValue | 4102 switch (lookup.type()) { |
| 4103 case NORMAL: | |
| 4104 case FIELD: | |
| 4105 case CONSTANT_FUNCTION: | |
| 4106 case INTERCEPTOR: { | |
| 4107 PropertyAttributes old_attributes; | |
| 4108 old_value = | |
| 4109 Object::GetProperty(self, self, &lookup, hname, &old_attributes); | |
| 4110 } | |
| 4111 case CALLBACKS: | |
| 4112 case TRANSITION: | |
| 4113 case HANDLER: | |
| 4114 case NONEXISTENT: | |
| 4115 break; | |
| 4116 } | |
| 4046 } | 4117 } |
| 4047 MaybeObject* result; | 4118 MaybeObject* result; |
| 4048 | 4119 |
| 4049 // Check for interceptor. | 4120 // Check for interceptor. |
| 4050 if (lookup.IsInterceptor()) { | 4121 if (lookup.IsInterceptor()) { |
| 4051 // Skip interceptor if forcing a deletion. | 4122 // Skip interceptor if forcing a deletion. |
| 4052 if (mode == FORCE_DELETION) { | 4123 if (mode == FORCE_DELETION) { |
| 4053 result = DeletePropertyPostInterceptor(name, mode); | 4124 result = self->DeletePropertyPostInterceptor(*hname, mode); |
| 4054 } else { | 4125 } else { |
| 4055 result = DeletePropertyWithInterceptor(name); | 4126 result = self->DeletePropertyWithInterceptor(*hname); |
| 4056 } | 4127 } |
| 4057 } else { | 4128 } else { |
| 4058 // Normalize object if needed. | 4129 // Normalize object if needed. |
| 4059 Object* obj; | 4130 Object* obj; |
| 4060 result = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | 4131 result = self->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
| 4061 if (!result->ToObject(&obj)) return result; | 4132 if (!result->To(&obj)) return result; |
| 4062 // Make sure the properties are normalized before removing the entry. | 4133 // Make sure the properties are normalized before removing the entry. |
| 4063 result = DeleteNormalizedProperty(name, mode); | 4134 result = self->DeleteNormalizedProperty(*hname, mode); |
| 4064 } | 4135 } |
| 4065 | 4136 |
| 4066 Handle<Object> hresult; | 4137 Handle<Object> hresult; |
| 4067 if (!result->ToHandle(&hresult)) return result; | 4138 if (!result->ToHandle(&hresult)) return result; |
| 4068 | 4139 |
| 4069 if (FLAG_harmony_observation && map()->is_observed()) { | 4140 if (FLAG_harmony_observation && map()->is_observed()) { |
| 4070 this->EnqueueChangeRecord("deleted", handle(name), old_value); | 4141 if (!self->HasLocalProperty(*hname)) |
| 4142 self->EnqueueChangeRecord("deleted", hname, old_value); | |
| 4071 } | 4143 } |
| 4072 | 4144 |
| 4073 return *hresult; | 4145 return *hresult; |
| 4074 } | 4146 } |
| 4075 | 4147 |
| 4076 | 4148 |
| 4077 MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) { | 4149 MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) { |
| 4078 if (IsJSProxy()) { | 4150 if (IsJSProxy()) { |
| 4079 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode); | 4151 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode); |
| 4080 } | 4152 } |
| (...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4662 void JSObject::DefineAccessor(Handle<JSObject> object, | 4734 void JSObject::DefineAccessor(Handle<JSObject> object, |
| 4663 Handle<String> name, | 4735 Handle<String> name, |
| 4664 Handle<Object> getter, | 4736 Handle<Object> getter, |
| 4665 Handle<Object> setter, | 4737 Handle<Object> setter, |
| 4666 PropertyAttributes attributes) { | 4738 PropertyAttributes attributes) { |
| 4667 CALL_HEAP_FUNCTION_VOID( | 4739 CALL_HEAP_FUNCTION_VOID( |
| 4668 object->GetIsolate(), | 4740 object->GetIsolate(), |
| 4669 object->DefineAccessor(*name, *getter, *setter, attributes)); | 4741 object->DefineAccessor(*name, *getter, *setter, attributes)); |
| 4670 } | 4742 } |
| 4671 | 4743 |
| 4672 MaybeObject* JSObject::DefineAccessor(String* name, | 4744 MaybeObject* JSObject::DefineAccessor(String* name_raw, |
| 4673 Object* getter, | 4745 Object* getter_raw, |
| 4674 Object* setter, | 4746 Object* setter_raw, |
| 4675 PropertyAttributes attributes) { | 4747 PropertyAttributes attributes) { |
| 4676 Isolate* isolate = GetIsolate(); | 4748 Isolate* isolate = GetIsolate(); |
| 4677 // Check access rights if needed. | 4749 // Check access rights if needed. |
| 4678 if (IsAccessCheckNeeded() && | 4750 if (IsAccessCheckNeeded() && |
| 4679 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { | 4751 !isolate->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) { |
| 4680 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); | 4752 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); |
| 4681 return isolate->heap()->undefined_value(); | 4753 return isolate->heap()->undefined_value(); |
| 4682 } | 4754 } |
| 4683 | 4755 |
| 4684 if (IsJSGlobalProxy()) { | 4756 if (IsJSGlobalProxy()) { |
| 4685 Object* proto = GetPrototype(); | 4757 Object* proto = GetPrototype(); |
| 4686 if (proto->IsNull()) return this; | 4758 if (proto->IsNull()) return this; |
| 4687 ASSERT(proto->IsJSGlobalObject()); | 4759 ASSERT(proto->IsJSGlobalObject()); |
| 4688 return JSObject::cast(proto)->DefineAccessor( | 4760 return JSObject::cast(proto)->DefineAccessor( |
| 4689 name, getter, setter, attributes); | 4761 name_raw, getter_raw, setter_raw, attributes); |
| 4690 } | 4762 } |
| 4691 | 4763 |
| 4692 // Make sure that the top context does not change when doing callbacks or | 4764 // Make sure that the top context does not change when doing callbacks or |
| 4693 // interceptor calls. | 4765 // interceptor calls. |
| 4694 AssertNoContextChange ncc; | 4766 AssertNoContextChange ncc; |
| 4695 | 4767 |
| 4696 // Try to flatten before operating on the string. | 4768 // Try to flatten before operating on the string. |
| 4697 name->TryFlatten(); | 4769 name_raw->TryFlatten(); |
| 4698 | 4770 |
| 4699 if (!CanSetCallback(name)) return isolate->heap()->undefined_value(); | 4771 if (!CanSetCallback(name_raw)) return isolate->heap()->undefined_value(); |
| 4772 | |
| 4773 // From this point on everything needs to be handlified. | |
| 4774 HandleScope scope(GetIsolate()); | |
| 4775 Handle<JSObject> self(this); | |
| 4776 Handle<String> name(name_raw); | |
| 4777 Handle<Object> getter(getter_raw); | |
| 4778 Handle<Object> setter(setter_raw); | |
| 4779 | |
| 4780 uint32_t index = 0; | |
| 4781 bool is_element = name->AsArrayIndex(&index); | |
| 4700 | 4782 |
| 4701 Handle<Object> old_value(isolate->heap()->the_hole_value()); | 4783 Handle<Object> old_value(isolate->heap()->the_hole_value()); |
| 4702 bool preexists = false; | 4784 bool preexists = false; |
| 4703 if (FLAG_harmony_observation && map()->is_observed()) { | 4785 if (FLAG_harmony_observation && map()->is_observed()) { |
| 4704 LookupResult result(isolate); | 4786 if (is_element) { |
| 4705 LocalLookup(name, &result); | 4787 preexists = HasLocalElement(index); |
| 4706 preexists = result.IsFound(); | 4788 if (preexists) { |
| 4707 // TODO(observe): save oldValue | 4789 // TODO(observe): distinguish the case where it's an accessor |
| 4790 old_value = Object::GetElement(self, index); | |
| 4791 } | |
| 4792 } else { | |
| 4793 LookupResult lookup(isolate); | |
| 4794 LocalLookup(*name, &lookup); | |
| 4795 preexists = lookup.IsProperty(); | |
| 4796 if (preexists) { | |
| 4797 switch (lookup.type()) { | |
| 4798 case NORMAL: | |
| 4799 case FIELD: | |
| 4800 case CONSTANT_FUNCTION: | |
| 4801 case INTERCEPTOR: { | |
| 4802 PropertyAttributes old_attributes; | |
| 4803 old_value = | |
| 4804 Object::GetProperty(self, self, &lookup, name, &old_attributes); | |
| 4805 } | |
| 4806 case CALLBACKS: | |
| 4807 case TRANSITION: | |
| 4808 case HANDLER: | |
| 4809 case NONEXISTENT: | |
| 4810 break; | |
| 4811 } | |
| 4812 } | |
| 4813 } | |
| 4708 } | 4814 } |
| 4709 | 4815 |
| 4710 uint32_t index = 0; | 4816 MaybeObject* result = is_element ? |
| 4711 MaybeObject* result = name->AsArrayIndex(&index) | 4817 self->DefineElementAccessor(index, *getter, *setter, attributes) : |
| 4712 ? DefineElementAccessor(index, getter, setter, attributes) | 4818 self->DefinePropertyAccessor(*name, *getter, *setter, attributes); |
| 4713 : DefinePropertyAccessor(name, getter, setter, attributes); | |
| 4714 | 4819 |
| 4715 Handle<Object> hresult; | 4820 Handle<Object> hresult; |
| 4716 if (!result->ToHandle(&hresult)) return result; | 4821 if (!result->ToHandle(&hresult)) return result; |
| 4717 | 4822 |
| 4718 if (FLAG_harmony_observation && map()->is_observed()) { | 4823 if (FLAG_harmony_observation && map()->is_observed()) { |
| 4719 const char* type = preexists ? "reconfigured" : "new"; | 4824 const char* type = preexists ? "reconfigured" : "new"; |
| 4720 this->EnqueueChangeRecord(type, handle(name), old_value); | 4825 self->EnqueueChangeRecord(type, name, old_value); |
| 4721 } | 4826 } |
| 4722 | 4827 |
| 4723 return *hresult; | 4828 return *hresult; |
| 4724 } | 4829 } |
| 4725 | 4830 |
| 4726 | 4831 |
| 4727 static MaybeObject* TryAccessorTransition(JSObject* self, | 4832 static MaybeObject* TryAccessorTransition(JSObject* self, |
| 4728 Map* transitioned_map, | 4833 Map* transitioned_map, |
| 4729 int target_descriptor, | 4834 int target_descriptor, |
| 4730 AccessorComponent component, | 4835 AccessorComponent component, |
| (...skipping 8846 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 13577 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); | 13682 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); |
| 13578 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); | 13683 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); |
| 13579 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); | 13684 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); |
| 13580 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); | 13685 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); |
| 13581 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); | 13686 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); |
| 13582 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); | 13687 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); |
| 13583 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); | 13688 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); |
| 13584 } | 13689 } |
| 13585 | 13690 |
| 13586 } } // namespace v8::internal | 13691 } } // namespace v8::internal |
| OLD | NEW |