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: |
| 2912 old_value = |
| 2913 Object::GetProperty(self, self, lookup, name, &old_attributes); |
| 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 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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) { |
| 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); |
| 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); |
| 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 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3192 *name_handle, | 3244 *name_handle, |
3193 continue_search); | 3245 continue_search); |
3194 } | 3246 } |
3195 | 3247 |
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)->GetElementAttributeWithReceiver( |
3203 ? NONE : ABSENT; | 3255 receiver, index, true); |
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 return GetLocalElementAttribute(index); |
3253 return ABSENT; | |
3254 } | 3306 } |
3255 // Named property. | 3307 // Named property. |
3256 LookupResult result(GetIsolate()); | 3308 LookupResult lookup(GetIsolate()); |
3257 LocalLookup(name, &result); | 3309 LocalLookup(name, &lookup); |
3258 return GetPropertyAttribute(this, &result, name, false); | 3310 return GetPropertyAttributeForResult(this, &lookup, name, false); |
3259 } | 3311 } |
3260 | 3312 |
3261 | 3313 |
| 3314 PropertyAttributes JSObject::GetElementAttributeWithReceiver( |
| 3315 JSReceiver* receiver, uint32_t index, bool continue_search) { |
| 3316 Isolate* isolate = GetIsolate(); |
| 3317 |
| 3318 // Check access rights if needed. |
| 3319 if (IsAccessCheckNeeded()) { |
| 3320 if (!isolate->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { |
| 3321 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS); |
| 3322 return ABSENT; |
| 3323 } |
| 3324 } |
| 3325 |
| 3326 if (IsJSGlobalProxy()) { |
| 3327 Object* proto = GetPrototype(); |
| 3328 if (proto->IsNull()) return ABSENT; |
| 3329 ASSERT(proto->IsJSGlobalObject()); |
| 3330 return JSReceiver::cast(proto)->GetElementAttributeWithReceiver( |
| 3331 receiver, index, continue_search); |
| 3332 } |
| 3333 |
| 3334 // Check for lookup interceptor except when bootstrapping. |
| 3335 if (HasIndexedInterceptor() && !isolate->bootstrapper()->IsActive()) { |
| 3336 return GetElementAttributeWithInterceptor(receiver, index, continue_search); |
| 3337 } |
| 3338 |
| 3339 return GetElementAttributeWithoutInterceptor( |
| 3340 receiver, index, continue_search); |
| 3341 } |
| 3342 |
| 3343 |
| 3344 PropertyAttributes JSObject::GetElementAttributeWithInterceptor( |
| 3345 JSReceiver* receiver, uint32_t index, bool continue_search) { |
| 3346 Isolate* isolate = GetIsolate(); |
| 3347 // Make sure that the top context does not change when doing |
| 3348 // callbacks or interceptor calls. |
| 3349 AssertNoContextChange ncc; |
| 3350 HandleScope scope(isolate); |
| 3351 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); |
| 3352 Handle<JSReceiver> hreceiver(receiver); |
| 3353 Handle<JSObject> holder(this); |
| 3354 CustomArguments args(isolate, interceptor->data(), receiver, this); |
| 3355 v8::AccessorInfo info(args.end()); |
| 3356 if (!interceptor->query()->IsUndefined()) { |
| 3357 v8::IndexedPropertyQuery query = |
| 3358 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query()); |
| 3359 LOG(isolate, |
| 3360 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index)); |
| 3361 v8::Handle<v8::Integer> result; |
| 3362 { |
| 3363 // Leaving JavaScript. |
| 3364 VMState state(isolate, EXTERNAL); |
| 3365 result = query(index, info); |
| 3366 } |
| 3367 if (!result.IsEmpty()) |
| 3368 return static_cast<PropertyAttributes>(result->Int32Value()); |
| 3369 } else if (!interceptor->getter()->IsUndefined()) { |
| 3370 v8::IndexedPropertyGetter getter = |
| 3371 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter()); |
| 3372 LOG(isolate, |
| 3373 ApiIndexedPropertyAccess("interceptor-indexed-get-has", this, index)); |
| 3374 v8::Handle<v8::Value> result; |
| 3375 { |
| 3376 // Leaving JavaScript. |
| 3377 VMState state(isolate, EXTERNAL); |
| 3378 result = getter(index, info); |
| 3379 } |
| 3380 if (!result.IsEmpty()) return DONT_ENUM; |
| 3381 } |
| 3382 |
| 3383 return holder->GetElementAttributeWithoutInterceptor( |
| 3384 *hreceiver, index, continue_search); |
| 3385 } |
| 3386 |
| 3387 |
| 3388 PropertyAttributes JSObject::GetElementAttributeWithoutInterceptor( |
| 3389 JSReceiver* receiver, uint32_t index, bool continue_search) { |
| 3390 Isolate* isolate = GetIsolate(); |
| 3391 HandleScope scope(isolate); |
| 3392 Handle<JSReceiver> hreceiver(receiver); |
| 3393 Handle<JSObject> holder(this); |
| 3394 PropertyAttributes attr = holder->GetElementsAccessor()->GetAttributes( |
| 3395 *hreceiver, *holder, index); |
| 3396 if (attr != ABSENT) return attr; |
| 3397 |
| 3398 if (holder->IsStringObjectWithCharacterAt(index)) { |
| 3399 return static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE); |
| 3400 } |
| 3401 |
| 3402 if (!continue_search) return ABSENT; |
| 3403 |
| 3404 Object* pt = holder->GetPrototype(); |
| 3405 if (pt->IsJSProxy()) { |
| 3406 // We need to follow the spec and simulate a call to [[GetOwnProperty]]. |
| 3407 return JSProxy::cast(pt)->GetElementAttributeWithHandler(*hreceiver, index); |
| 3408 } |
| 3409 if (pt->IsNull()) return ABSENT; |
| 3410 return JSObject::cast(pt)->GetElementAttributeWithReceiver( |
| 3411 *hreceiver, index, true); |
| 3412 } |
| 3413 |
| 3414 |
3262 MaybeObject* NormalizedMapCache::Get(JSObject* obj, | 3415 MaybeObject* NormalizedMapCache::Get(JSObject* obj, |
3263 PropertyNormalizationMode mode) { | 3416 PropertyNormalizationMode mode) { |
3264 Isolate* isolate = obj->GetIsolate(); | 3417 Isolate* isolate = obj->GetIsolate(); |
3265 Map* fast = obj->map(); | 3418 Map* fast = obj->map(); |
3266 int index = fast->Hash() % kEntries; | 3419 int index = fast->Hash() % kEntries; |
3267 Object* result = get(index); | 3420 Object* result = get(index); |
3268 if (result->IsMap() && | 3421 if (result->IsMap() && |
3269 Map::cast(result)->EquivalentToForNormalization(fast, mode)) { | 3422 Map::cast(result)->EquivalentToForNormalization(fast, mode)) { |
3270 #ifdef VERIFY_HEAP | 3423 #ifdef VERIFY_HEAP |
3271 if (FLAG_verify_heap) { | 3424 if (FLAG_verify_heap) { |
(...skipping 701 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3973 return isolate->heap()->false_value(); | 4126 return isolate->heap()->false_value(); |
3974 } | 4127 } |
3975 | 4128 |
3976 if (IsJSGlobalProxy()) { | 4129 if (IsJSGlobalProxy()) { |
3977 Object* proto = GetPrototype(); | 4130 Object* proto = GetPrototype(); |
3978 if (proto->IsNull()) return isolate->heap()->false_value(); | 4131 if (proto->IsNull()) return isolate->heap()->false_value(); |
3979 ASSERT(proto->IsJSGlobalObject()); | 4132 ASSERT(proto->IsJSGlobalObject()); |
3980 return JSGlobalObject::cast(proto)->DeleteElement(index, mode); | 4133 return JSGlobalObject::cast(proto)->DeleteElement(index, mode); |
3981 } | 4134 } |
3982 | 4135 |
3983 if (HasIndexedInterceptor()) { | 4136 // From this point on everything needs to be handlified. |
3984 // Skip interceptor if forcing deletion. | 4137 HandleScope scope(isolate); |
3985 if (mode != FORCE_DELETION) { | 4138 Handle<JSObject> self(this); |
3986 return DeleteElementWithInterceptor(index); | 4139 |
| 4140 Handle<String> name; |
| 4141 Handle<Object> old_value(isolate->heap()->the_hole_value()); |
| 4142 bool preexists = false; |
| 4143 if (FLAG_harmony_observation && map()->is_observed()) { |
| 4144 name = isolate->factory()->Uint32ToString(index); |
| 4145 preexists = self->HasLocalElement(index); |
| 4146 if (preexists) { |
| 4147 // TODO(observe): only read & set old_value if it's not an accessor |
| 4148 old_value = Object::GetElement(self, index); |
3987 } | 4149 } |
3988 mode = JSReceiver::FORCE_DELETION; | |
3989 } | 4150 } |
3990 | 4151 |
3991 return GetElementsAccessor()->Delete(this, index, mode); | 4152 MaybeObject* result; |
| 4153 // Skip interceptor if forcing deletion. |
| 4154 if (self->HasIndexedInterceptor() && mode != FORCE_DELETION) { |
| 4155 result = self->DeleteElementWithInterceptor(index); |
| 4156 } else { |
| 4157 result = self->GetElementsAccessor()->Delete(*self, index, mode); |
| 4158 } |
| 4159 |
| 4160 Handle<Object> hresult; |
| 4161 if (!result->ToHandle(&hresult)) return result; |
| 4162 |
| 4163 if (FLAG_harmony_observation && map()->is_observed()) { |
| 4164 if (preexists && !self->HasLocalElement(index)) |
| 4165 self->EnqueueChangeRecord("deleted", name, old_value); |
| 4166 } |
| 4167 |
| 4168 return *hresult; |
3992 } | 4169 } |
3993 | 4170 |
3994 | 4171 |
3995 Handle<Object> JSObject::DeleteProperty(Handle<JSObject> obj, | 4172 Handle<Object> JSObject::DeleteProperty(Handle<JSObject> obj, |
3996 Handle<String> prop) { | 4173 Handle<String> prop) { |
3997 CALL_HEAP_FUNCTION(obj->GetIsolate(), | 4174 CALL_HEAP_FUNCTION(obj->GetIsolate(), |
3998 obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION), | 4175 obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION), |
3999 Object); | 4176 Object); |
4000 } | 4177 } |
4001 | 4178 |
(...skipping 30 matching lines...) Expand all Loading... |
4032 if (mode == STRICT_DELETION) { | 4209 if (mode == STRICT_DELETION) { |
4033 // Deleting a non-configurable property in strict mode. | 4210 // Deleting a non-configurable property in strict mode. |
4034 HandleScope scope(isolate); | 4211 HandleScope scope(isolate); |
4035 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) }; | 4212 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) }; |
4036 return isolate->Throw(*isolate->factory()->NewTypeError( | 4213 return isolate->Throw(*isolate->factory()->NewTypeError( |
4037 "strict_delete_property", HandleVector(args, 2))); | 4214 "strict_delete_property", HandleVector(args, 2))); |
4038 } | 4215 } |
4039 return isolate->heap()->false_value(); | 4216 return isolate->heap()->false_value(); |
4040 } | 4217 } |
4041 | 4218 |
| 4219 // From this point on everything needs to be handlified. |
4042 HandleScope scope(isolate); | 4220 HandleScope scope(isolate); |
| 4221 Handle<JSObject> self(this); |
| 4222 Handle<String> hname(name); |
| 4223 |
4043 Handle<Object> old_value(isolate->heap()->the_hole_value()); | 4224 Handle<Object> old_value(isolate->heap()->the_hole_value()); |
4044 if (FLAG_harmony_observation && map()->is_observed()) { | 4225 if (FLAG_harmony_observation && map()->is_observed()) { |
4045 // TODO(observe): save oldValue | 4226 switch (lookup.type()) { |
| 4227 case NORMAL: |
| 4228 case FIELD: |
| 4229 case CONSTANT_FUNCTION: |
| 4230 case INTERCEPTOR: { |
| 4231 PropertyAttributes old_attributes; |
| 4232 old_value = |
| 4233 Object::GetProperty(self, self, &lookup, hname, &old_attributes); |
| 4234 } |
| 4235 case CALLBACKS: |
| 4236 case TRANSITION: |
| 4237 case HANDLER: |
| 4238 case NONEXISTENT: |
| 4239 break; |
| 4240 } |
4046 } | 4241 } |
4047 MaybeObject* result; | 4242 MaybeObject* result; |
4048 | 4243 |
4049 // Check for interceptor. | 4244 // Check for interceptor. |
4050 if (lookup.IsInterceptor()) { | 4245 if (lookup.IsInterceptor()) { |
4051 // Skip interceptor if forcing a deletion. | 4246 // Skip interceptor if forcing a deletion. |
4052 if (mode == FORCE_DELETION) { | 4247 if (mode == FORCE_DELETION) { |
4053 result = DeletePropertyPostInterceptor(name, mode); | 4248 result = self->DeletePropertyPostInterceptor(*hname, mode); |
4054 } else { | 4249 } else { |
4055 result = DeletePropertyWithInterceptor(name); | 4250 result = self->DeletePropertyWithInterceptor(*hname); |
4056 } | 4251 } |
4057 } else { | 4252 } else { |
4058 // Normalize object if needed. | 4253 // Normalize object if needed. |
4059 Object* obj; | 4254 Object* obj; |
4060 result = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | 4255 result = self->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
4061 if (!result->ToObject(&obj)) return result; | 4256 if (!result->To(&obj)) return result; |
4062 // Make sure the properties are normalized before removing the entry. | 4257 // Make sure the properties are normalized before removing the entry. |
4063 result = DeleteNormalizedProperty(name, mode); | 4258 result = self->DeleteNormalizedProperty(*hname, mode); |
4064 } | 4259 } |
4065 | 4260 |
4066 Handle<Object> hresult; | 4261 Handle<Object> hresult; |
4067 if (!result->ToHandle(&hresult)) return result; | 4262 if (!result->ToHandle(&hresult)) return result; |
4068 | 4263 |
4069 if (FLAG_harmony_observation && map()->is_observed()) { | 4264 if (FLAG_harmony_observation && map()->is_observed()) { |
4070 this->EnqueueChangeRecord("deleted", handle(name), old_value); | 4265 if (!self->HasLocalProperty(*hname)) |
| 4266 self->EnqueueChangeRecord("deleted", hname, old_value); |
4071 } | 4267 } |
4072 | 4268 |
4073 return *hresult; | 4269 return *hresult; |
4074 } | 4270 } |
4075 | 4271 |
4076 | 4272 |
4077 MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) { | 4273 MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) { |
4078 if (IsJSProxy()) { | 4274 if (IsJSProxy()) { |
4079 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode); | 4275 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode); |
4080 } | 4276 } |
(...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4662 void JSObject::DefineAccessor(Handle<JSObject> object, | 4858 void JSObject::DefineAccessor(Handle<JSObject> object, |
4663 Handle<String> name, | 4859 Handle<String> name, |
4664 Handle<Object> getter, | 4860 Handle<Object> getter, |
4665 Handle<Object> setter, | 4861 Handle<Object> setter, |
4666 PropertyAttributes attributes) { | 4862 PropertyAttributes attributes) { |
4667 CALL_HEAP_FUNCTION_VOID( | 4863 CALL_HEAP_FUNCTION_VOID( |
4668 object->GetIsolate(), | 4864 object->GetIsolate(), |
4669 object->DefineAccessor(*name, *getter, *setter, attributes)); | 4865 object->DefineAccessor(*name, *getter, *setter, attributes)); |
4670 } | 4866 } |
4671 | 4867 |
4672 MaybeObject* JSObject::DefineAccessor(String* name, | 4868 MaybeObject* JSObject::DefineAccessor(String* name_raw, |
4673 Object* getter, | 4869 Object* getter_raw, |
4674 Object* setter, | 4870 Object* setter_raw, |
4675 PropertyAttributes attributes) { | 4871 PropertyAttributes attributes) { |
4676 Isolate* isolate = GetIsolate(); | 4872 Isolate* isolate = GetIsolate(); |
4677 // Check access rights if needed. | 4873 // Check access rights if needed. |
4678 if (IsAccessCheckNeeded() && | 4874 if (IsAccessCheckNeeded() && |
4679 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { | 4875 !isolate->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) { |
4680 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); | 4876 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); |
4681 return isolate->heap()->undefined_value(); | 4877 return isolate->heap()->undefined_value(); |
4682 } | 4878 } |
4683 | 4879 |
4684 if (IsJSGlobalProxy()) { | 4880 if (IsJSGlobalProxy()) { |
4685 Object* proto = GetPrototype(); | 4881 Object* proto = GetPrototype(); |
4686 if (proto->IsNull()) return this; | 4882 if (proto->IsNull()) return this; |
4687 ASSERT(proto->IsJSGlobalObject()); | 4883 ASSERT(proto->IsJSGlobalObject()); |
4688 return JSObject::cast(proto)->DefineAccessor( | 4884 return JSObject::cast(proto)->DefineAccessor( |
4689 name, getter, setter, attributes); | 4885 name_raw, getter_raw, setter_raw, attributes); |
4690 } | 4886 } |
4691 | 4887 |
4692 // Make sure that the top context does not change when doing callbacks or | 4888 // Make sure that the top context does not change when doing callbacks or |
4693 // interceptor calls. | 4889 // interceptor calls. |
4694 AssertNoContextChange ncc; | 4890 AssertNoContextChange ncc; |
4695 | 4891 |
4696 // Try to flatten before operating on the string. | 4892 // Try to flatten before operating on the string. |
4697 name->TryFlatten(); | 4893 name_raw->TryFlatten(); |
4698 | 4894 |
4699 if (!CanSetCallback(name)) return isolate->heap()->undefined_value(); | 4895 if (!CanSetCallback(name_raw)) return isolate->heap()->undefined_value(); |
| 4896 |
| 4897 // From this point on everything needs to be handlified. |
| 4898 HandleScope scope(GetIsolate()); |
| 4899 Handle<JSObject> self(this); |
| 4900 Handle<String> name(name_raw); |
| 4901 Handle<Object> getter(getter_raw); |
| 4902 Handle<Object> setter(setter_raw); |
| 4903 |
| 4904 uint32_t index = 0; |
| 4905 bool is_element = name->AsArrayIndex(&index); |
4700 | 4906 |
4701 Handle<Object> old_value(isolate->heap()->the_hole_value()); | 4907 Handle<Object> old_value(isolate->heap()->the_hole_value()); |
4702 bool preexists = false; | 4908 bool preexists = false; |
4703 if (FLAG_harmony_observation && map()->is_observed()) { | 4909 if (FLAG_harmony_observation && map()->is_observed()) { |
4704 LookupResult result(isolate); | 4910 if (is_element) { |
4705 LocalLookup(name, &result); | 4911 preexists = HasLocalElement(index); |
4706 preexists = result.IsFound(); | 4912 if (preexists) { |
4707 // TODO(observe): save oldValue | 4913 // TODO(observe): distinguish the case where it's an accessor |
| 4914 old_value = Object::GetElement(self, index); |
| 4915 } |
| 4916 } else { |
| 4917 LookupResult lookup(isolate); |
| 4918 LocalLookup(*name, &lookup); |
| 4919 preexists = lookup.IsProperty(); |
| 4920 if (preexists) { |
| 4921 switch (lookup.type()) { |
| 4922 case NORMAL: |
| 4923 case FIELD: |
| 4924 case CONSTANT_FUNCTION: |
| 4925 case INTERCEPTOR: { |
| 4926 PropertyAttributes old_attributes; |
| 4927 old_value = |
| 4928 Object::GetProperty(self, self, &lookup, name, &old_attributes); |
| 4929 } |
| 4930 case CALLBACKS: |
| 4931 case TRANSITION: |
| 4932 case HANDLER: |
| 4933 case NONEXISTENT: |
| 4934 break; |
| 4935 } |
| 4936 } |
| 4937 } |
4708 } | 4938 } |
4709 | 4939 |
4710 uint32_t index = 0; | 4940 MaybeObject* result = is_element ? |
4711 MaybeObject* result = name->AsArrayIndex(&index) | 4941 self->DefineElementAccessor(index, *getter, *setter, attributes) : |
4712 ? DefineElementAccessor(index, getter, setter, attributes) | 4942 self->DefinePropertyAccessor(*name, *getter, *setter, attributes); |
4713 : DefinePropertyAccessor(name, getter, setter, attributes); | |
4714 | 4943 |
4715 Handle<Object> hresult; | 4944 Handle<Object> hresult; |
4716 if (!result->ToHandle(&hresult)) return result; | 4945 if (!result->ToHandle(&hresult)) return result; |
4717 | 4946 |
4718 if (FLAG_harmony_observation && map()->is_observed()) { | 4947 if (FLAG_harmony_observation && map()->is_observed()) { |
4719 const char* type = preexists ? "reconfigured" : "new"; | 4948 const char* type = preexists ? "reconfigured" : "new"; |
4720 this->EnqueueChangeRecord(type, handle(name), old_value); | 4949 self->EnqueueChangeRecord(type, name, old_value); |
4721 } | 4950 } |
4722 | 4951 |
4723 return *hresult; | 4952 return *hresult; |
4724 } | 4953 } |
4725 | 4954 |
4726 | 4955 |
4727 static MaybeObject* TryAccessorTransition(JSObject* self, | 4956 static MaybeObject* TryAccessorTransition(JSObject* self, |
4728 Map* transitioned_map, | 4957 Map* transitioned_map, |
4729 int target_descriptor, | 4958 int target_descriptor, |
4730 AccessorComponent component, | 4959 AccessorComponent component, |
(...skipping 4474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9205 EnsureElementsMode mode) { | 9434 EnsureElementsMode mode) { |
9206 // Elements in |Arguments| are ordered backwards (because they're on the | 9435 // Elements in |Arguments| are ordered backwards (because they're on the |
9207 // stack), but the method that's called here iterates over them in forward | 9436 // stack), but the method that's called here iterates over them in forward |
9208 // direction. | 9437 // direction. |
9209 return EnsureCanContainElements( | 9438 return EnsureCanContainElements( |
9210 args->arguments() - first_arg - (arg_count - 1), | 9439 args->arguments() - first_arg - (arg_count - 1), |
9211 arg_count, mode); | 9440 arg_count, mode); |
9212 } | 9441 } |
9213 | 9442 |
9214 | 9443 |
9215 bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) { | 9444 JSObject::LocalElementType JSObject::GetLocalElementType(uint32_t index) { |
9216 Isolate* isolate = GetIsolate(); | |
9217 // Make sure that the top context does not change when doing | |
9218 // callbacks or interceptor calls. | |
9219 AssertNoContextChange ncc; | |
9220 HandleScope scope(isolate); | |
9221 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); | |
9222 Handle<JSReceiver> receiver_handle(receiver); | |
9223 Handle<JSObject> holder_handle(this); | |
9224 CustomArguments args(isolate, interceptor->data(), receiver, this); | |
9225 v8::AccessorInfo info(args.end()); | |
9226 if (!interceptor->query()->IsUndefined()) { | |
9227 v8::IndexedPropertyQuery query = | |
9228 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query()); | |
9229 LOG(isolate, | |
9230 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index)); | |
9231 v8::Handle<v8::Integer> result; | |
9232 { | |
9233 // Leaving JavaScript. | |
9234 VMState state(isolate, EXTERNAL); | |
9235 result = query(index, info); | |
9236 } | |
9237 if (!result.IsEmpty()) { | |
9238 ASSERT(result->IsInt32()); | |
9239 return true; // absence of property is signaled by empty handle. | |
9240 } | |
9241 } else if (!interceptor->getter()->IsUndefined()) { | |
9242 v8::IndexedPropertyGetter getter = | |
9243 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter()); | |
9244 LOG(isolate, | |
9245 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index)); | |
9246 v8::Handle<v8::Value> result; | |
9247 { | |
9248 // Leaving JavaScript. | |
9249 VMState state(isolate, EXTERNAL); | |
9250 result = getter(index, info); | |
9251 } | |
9252 if (!result.IsEmpty()) return true; | |
9253 } | |
9254 | |
9255 if (holder_handle->GetElementsAccessor()->HasElement( | |
9256 *receiver_handle, *holder_handle, index)) { | |
9257 return true; | |
9258 } | |
9259 | |
9260 if (holder_handle->IsStringObjectWithCharacterAt(index)) return true; | |
9261 Object* pt = holder_handle->GetPrototype(); | |
9262 if (pt->IsJSProxy()) { | |
9263 // We need to follow the spec and simulate a call to [[GetOwnProperty]]. | |
9264 return JSProxy::cast(pt)->GetElementAttributeWithHandler( | |
9265 receiver, index) != ABSENT; | |
9266 } | |
9267 if (pt->IsNull()) return false; | |
9268 return JSObject::cast(pt)->HasElementWithReceiver(*receiver_handle, index); | |
9269 } | |
9270 | |
9271 | |
9272 JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) { | |
9273 // Check access rights if needed. | 9445 // Check access rights if needed. |
9274 if (IsAccessCheckNeeded()) { | 9446 if (IsAccessCheckNeeded()) { |
9275 Heap* heap = GetHeap(); | 9447 Heap* heap = GetHeap(); |
9276 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { | 9448 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { |
9277 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); | 9449 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); |
9278 return UNDEFINED_ELEMENT; | 9450 return UNDEFINED_ELEMENT; |
9279 } | 9451 } |
9280 } | 9452 } |
9281 | 9453 |
9282 if (IsJSGlobalProxy()) { | 9454 if (IsJSGlobalProxy()) { |
9283 Object* proto = GetPrototype(); | 9455 Object* proto = GetPrototype(); |
9284 if (proto->IsNull()) return UNDEFINED_ELEMENT; | 9456 if (proto->IsNull()) return UNDEFINED_ELEMENT; |
9285 ASSERT(proto->IsJSGlobalObject()); | 9457 ASSERT(proto->IsJSGlobalObject()); |
9286 return JSObject::cast(proto)->HasLocalElement(index); | 9458 return JSObject::cast(proto)->GetLocalElementType(index); |
9287 } | 9459 } |
9288 | 9460 |
9289 // Check for lookup interceptor | 9461 // Check for lookup interceptor |
9290 if (HasIndexedInterceptor()) { | 9462 if (HasIndexedInterceptor()) { |
9291 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT | 9463 return GetElementAttributeWithInterceptor(this, index, false) != ABSENT |
9292 : UNDEFINED_ELEMENT; | 9464 ? INTERCEPTED_ELEMENT : UNDEFINED_ELEMENT; |
9293 } | 9465 } |
9294 | 9466 |
9295 // Handle [] on String objects. | 9467 // Handle [] on String objects. |
9296 if (this->IsStringObjectWithCharacterAt(index)) { | 9468 if (this->IsStringObjectWithCharacterAt(index)) { |
9297 return STRING_CHARACTER_ELEMENT; | 9469 return STRING_CHARACTER_ELEMENT; |
9298 } | 9470 } |
9299 | 9471 |
9300 switch (GetElementsKind()) { | 9472 switch (GetElementsKind()) { |
9301 case FAST_SMI_ELEMENTS: | 9473 case FAST_SMI_ELEMENTS: |
9302 case FAST_ELEMENTS: | 9474 case FAST_ELEMENTS: |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9371 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT; | 9543 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT; |
9372 } | 9544 } |
9373 break; | 9545 break; |
9374 } | 9546 } |
9375 } | 9547 } |
9376 | 9548 |
9377 return UNDEFINED_ELEMENT; | 9549 return UNDEFINED_ELEMENT; |
9378 } | 9550 } |
9379 | 9551 |
9380 | 9552 |
9381 bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) { | |
9382 // Check access rights if needed. | |
9383 if (IsAccessCheckNeeded()) { | |
9384 Heap* heap = GetHeap(); | |
9385 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { | |
9386 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); | |
9387 return false; | |
9388 } | |
9389 } | |
9390 | |
9391 // Check for lookup interceptor | |
9392 if (HasIndexedInterceptor()) { | |
9393 return HasElementWithInterceptor(receiver, index); | |
9394 } | |
9395 | |
9396 ElementsAccessor* accessor = GetElementsAccessor(); | |
9397 if (accessor->HasElement(receiver, this, index)) { | |
9398 return true; | |
9399 } | |
9400 | |
9401 // Handle [] on String objects. | |
9402 if (this->IsStringObjectWithCharacterAt(index)) return true; | |
9403 | |
9404 Object* pt = GetPrototype(); | |
9405 if (pt->IsNull()) return false; | |
9406 if (pt->IsJSProxy()) { | |
9407 // We need to follow the spec and simulate a call to [[GetOwnProperty]]. | |
9408 return JSProxy::cast(pt)->GetElementAttributeWithHandler( | |
9409 receiver, index) != ABSENT; | |
9410 } | |
9411 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); | |
9412 } | |
9413 | |
9414 | |
9415 MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index, | 9553 MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index, |
9416 Object* value, | 9554 Object* value, |
9417 PropertyAttributes attributes, | 9555 PropertyAttributes attributes, |
9418 StrictModeFlag strict_mode, | 9556 StrictModeFlag strict_mode, |
9419 bool check_prototype, | 9557 bool check_prototype, |
9420 SetPropertyMode set_mode) { | 9558 SetPropertyMode set_mode) { |
9421 Isolate* isolate = GetIsolate(); | 9559 Isolate* isolate = GetIsolate(); |
9422 // Make sure that the top context does not change when doing | 9560 // Make sure that the top context does not change when doing |
9423 // callbacks or interceptor calls. | 9561 // callbacks or interceptor calls. |
9424 AssertNoContextChange ncc; | 9562 AssertNoContextChange ncc; |
(...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10002 } | 10140 } |
10003 } | 10141 } |
10004 CALL_HEAP_FUNCTION( | 10142 CALL_HEAP_FUNCTION( |
10005 object->GetIsolate(), | 10143 object->GetIsolate(), |
10006 object->SetElement(index, *value, attr, strict_mode, true, set_mode), | 10144 object->SetElement(index, *value, attr, strict_mode, true, set_mode), |
10007 Object); | 10145 Object); |
10008 } | 10146 } |
10009 | 10147 |
10010 | 10148 |
10011 MaybeObject* JSObject::SetElement(uint32_t index, | 10149 MaybeObject* JSObject::SetElement(uint32_t index, |
10012 Object* value, | 10150 Object* value_raw, |
10013 PropertyAttributes attributes, | 10151 PropertyAttributes attributes, |
10014 StrictModeFlag strict_mode, | 10152 StrictModeFlag strict_mode, |
10015 bool check_prototype, | 10153 bool check_prototype, |
10016 SetPropertyMode set_mode) { | 10154 SetPropertyMode set_mode) { |
| 10155 Isolate* isolate = GetIsolate(); |
| 10156 HandleScope scope(isolate); |
| 10157 Handle<JSObject> self(this); |
| 10158 Handle<Object> value(value_raw); |
| 10159 |
10017 // Check access rights if needed. | 10160 // Check access rights if needed. |
10018 if (IsAccessCheckNeeded()) { | 10161 if (IsAccessCheckNeeded()) { |
10019 Heap* heap = GetHeap(); | 10162 Heap* heap = GetHeap(); |
10020 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) { | 10163 if (!heap->isolate()->MayIndexedAccess(*self, index, v8::ACCESS_SET)) { |
10021 HandleScope scope(heap->isolate()); | 10164 heap->isolate()->ReportFailedAccessCheck(*self, v8::ACCESS_SET); |
10022 Handle<Object> value_handle(value); | 10165 return *value; |
10023 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET); | |
10024 return *value_handle; | |
10025 } | 10166 } |
10026 } | 10167 } |
10027 | 10168 |
10028 if (IsJSGlobalProxy()) { | 10169 if (IsJSGlobalProxy()) { |
10029 Object* proto = GetPrototype(); | 10170 Object* proto = GetPrototype(); |
10030 if (proto->IsNull()) return value; | 10171 if (proto->IsNull()) return *value; |
10031 ASSERT(proto->IsJSGlobalObject()); | 10172 ASSERT(proto->IsJSGlobalObject()); |
10032 return JSObject::cast(proto)->SetElement(index, | 10173 return JSObject::cast(proto)->SetElement(index, |
10033 value, | 10174 *value, |
10034 attributes, | 10175 attributes, |
10035 strict_mode, | 10176 strict_mode, |
10036 check_prototype, | 10177 check_prototype, |
10037 set_mode); | 10178 set_mode); |
10038 } | 10179 } |
10039 | 10180 |
10040 // Don't allow element properties to be redefined for external arrays. | 10181 // Don't allow element properties to be redefined for external arrays. |
10041 if (HasExternalArrayElements() && set_mode == DEFINE_PROPERTY) { | 10182 if (HasExternalArrayElements() && set_mode == DEFINE_PROPERTY) { |
10042 Isolate* isolate = GetHeap()->isolate(); | |
10043 Handle<Object> receiver(this); | |
10044 Handle<Object> number = isolate->factory()->NewNumberFromUint(index); | 10183 Handle<Object> number = isolate->factory()->NewNumberFromUint(index); |
10045 Handle<Object> args[] = { receiver, number }; | 10184 Handle<Object> args[] = { self, number }; |
10046 Handle<Object> error = isolate->factory()->NewTypeError( | 10185 Handle<Object> error = isolate->factory()->NewTypeError( |
10047 "redef_external_array_element", HandleVector(args, ARRAY_SIZE(args))); | 10186 "redef_external_array_element", HandleVector(args, ARRAY_SIZE(args))); |
10048 return isolate->Throw(*error); | 10187 return isolate->Throw(*error); |
10049 } | 10188 } |
10050 | 10189 |
10051 // Normalize the elements to enable attributes on the property. | 10190 // Normalize the elements to enable attributes on the property. |
10052 if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) { | 10191 if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) { |
10053 SeededNumberDictionary* dictionary; | 10192 SeededNumberDictionary* dictionary; |
10054 MaybeObject* maybe_object = NormalizeElements(); | 10193 MaybeObject* maybe_object = NormalizeElements(); |
10055 if (!maybe_object->To(&dictionary)) return maybe_object; | 10194 if (!maybe_object->To(&dictionary)) return maybe_object; |
10056 // Make sure that we never go back to fast case. | 10195 // Make sure that we never go back to fast case. |
10057 dictionary->set_requires_slow_elements(); | 10196 dictionary->set_requires_slow_elements(); |
10058 } | 10197 } |
10059 | 10198 |
10060 // Check for lookup interceptor | 10199 // From here on, everything has to be handlified. |
10061 if (HasIndexedInterceptor()) { | 10200 Handle<String> name; |
10062 return SetElementWithInterceptor(index, | 10201 Handle<Object> old_value(isolate->heap()->the_hole_value()); |
10063 value, | 10202 PropertyAttributes old_attributes; |
10064 attributes, | 10203 bool preexists = false; |
10065 strict_mode, | 10204 if (FLAG_harmony_observation && map()->is_observed()) { |
10066 check_prototype, | 10205 name = isolate->factory()->Uint32ToString(index); |
10067 set_mode); | 10206 preexists = self->HasLocalElement(index); |
| 10207 if (preexists) { |
| 10208 old_attributes = self->GetLocalPropertyAttribute(*name); |
| 10209 // TODO(observe): only read & set old_value if we have a data property |
| 10210 old_value = Object::GetElement(self, index); |
| 10211 } |
10068 } | 10212 } |
10069 | 10213 |
10070 return SetElementWithoutInterceptor(index, | 10214 // Check for lookup interceptor |
10071 value, | 10215 MaybeObject* result = self->HasIndexedInterceptor() |
10072 attributes, | 10216 ? self->SetElementWithInterceptor( |
10073 strict_mode, | 10217 index, *value, attributes, strict_mode, check_prototype, set_mode) |
10074 check_prototype, | 10218 : self->SetElementWithoutInterceptor( |
10075 set_mode); | 10219 index, *value, attributes, strict_mode, check_prototype, set_mode); |
| 10220 |
| 10221 Handle<Object> hresult; |
| 10222 if (!result->ToHandle(&hresult)) return result; |
| 10223 |
| 10224 if (FLAG_harmony_observation && map()->is_observed()) { |
| 10225 PropertyAttributes new_attributes = self->GetLocalPropertyAttribute(*name); |
| 10226 if (!preexists) { |
| 10227 self->EnqueueChangeRecord("new", name, old_value); |
| 10228 } else if (new_attributes != old_attributes || old_value->IsTheHole()) { |
| 10229 self->EnqueueChangeRecord("reconfigured", name, old_value); |
| 10230 } else { |
| 10231 Handle<Object> newValue = Object::GetElement(self, index); |
| 10232 if (!newValue->SameValue(*old_value)) |
| 10233 self->EnqueueChangeRecord("updated", name, old_value); |
| 10234 } |
| 10235 } |
| 10236 |
| 10237 return *hresult; |
10076 } | 10238 } |
10077 | 10239 |
10078 | 10240 |
10079 MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, | 10241 MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, |
10080 Object* value, | 10242 Object* value, |
10081 PropertyAttributes attr, | 10243 PropertyAttributes attr, |
10082 StrictModeFlag strict_mode, | 10244 StrictModeFlag strict_mode, |
10083 bool check_prototype, | 10245 bool check_prototype, |
10084 SetPropertyMode set_mode) { | 10246 SetPropertyMode set_mode) { |
10085 ASSERT(HasDictionaryElements() || | 10247 ASSERT(HasDictionaryElements() || |
(...skipping 3491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13577 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); | 13739 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); |
13578 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); | 13740 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); |
13579 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); | 13741 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); |
13580 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); | 13742 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); |
13581 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); | 13743 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); |
13582 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); | 13744 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); |
13583 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); | 13745 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); |
13584 } | 13746 } |
13585 | 13747 |
13586 } } // namespace v8::internal | 13748 } } // namespace v8::internal |
OLD | NEW |