Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Side by Side Diff: src/objects.cc

Issue 11365111: Object.observe: generate change records for indexed properties. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressing comments; simplifications. Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698