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 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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()); |
2903 if (FLAG_harmony_observation && map()->is_observed()) { | 2905 if (FLAG_harmony_observation && map()->is_observed()) { |
2904 // TODO(observe): save oldValue | 2906 old_value = handle(lookup->GetLazyValue()); |
2905 } | 2907 } |
2906 | 2908 |
2907 // This is a real property that is not read-only, or it is a | 2909 // 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. | 2910 // transition or null descriptor and there are no setters in the prototypes. |
2909 MaybeObject* result = *value; | 2911 MaybeObject* result = *value; |
2910 switch (lookup->type()) { | 2912 switch (lookup->type()) { |
2911 case NORMAL: | 2913 case NORMAL: |
2912 result = self->SetNormalizedProperty(lookup, *value); | 2914 result = self->SetNormalizedProperty(lookup, *value); |
2913 break; | 2915 break; |
2914 case FIELD: | 2916 case FIELD: |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2946 if (attributes == details.attributes()) { | 2948 if (attributes == details.attributes()) { |
2947 int field_index = descriptors->GetFieldIndex(descriptor); | 2949 int field_index = descriptors->GetFieldIndex(descriptor); |
2948 result = self->AddFastPropertyUsingMap(transition_map, | 2950 result = self->AddFastPropertyUsingMap(transition_map, |
2949 *name, | 2951 *name, |
2950 *value, | 2952 *value, |
2951 field_index); | 2953 field_index); |
2952 } else { | 2954 } else { |
2953 result = self->ConvertDescriptorToField(*name, *value, attributes); | 2955 result = self->ConvertDescriptorToField(*name, *value, attributes); |
2954 } | 2956 } |
2955 } else if (details.type() == CALLBACKS) { | 2957 } else if (details.type() == CALLBACKS) { |
2956 result = ConvertDescriptorToField(*name, *value, attributes); | 2958 result = self->ConvertDescriptorToField(*name, *value, attributes); |
2957 } else { | 2959 } else { |
2958 ASSERT(details.type() == CONSTANT_FUNCTION); | 2960 ASSERT(details.type() == CONSTANT_FUNCTION); |
2959 | 2961 |
2960 Object* constant_function = descriptors->GetValue(descriptor); | 2962 Object* constant_function = descriptors->GetValue(descriptor); |
2961 if (constant_function == *value) { | 2963 if (constant_function == *value) { |
2962 // If the same constant function is being added we can simply | 2964 // If the same constant function is being added we can simply |
2963 // transition to the target map. | 2965 // transition to the target map. |
2964 self->set_map(transition_map); | 2966 self->set_map(transition_map); |
2965 result = constant_function; | 2967 result = constant_function; |
2966 } else { | 2968 } else { |
2967 // Otherwise, replace with a map transition to a new map with a FIELD, | 2969 // Otherwise, replace with a map transition to a new map with a FIELD, |
2968 // even if the value is a constant function. | 2970 // even if the value is a constant function. |
2969 result = ConvertTransitionToMapTransition( | 2971 result = self->ConvertTransitionToMapTransition( |
2970 lookup->GetTransitionIndex(), *name, *value, attributes); | 2972 lookup->GetTransitionIndex(), *name, *value, attributes); |
2971 } | 2973 } |
2972 } | 2974 } |
2973 break; | 2975 break; |
2974 } | 2976 } |
2975 case HANDLER: | 2977 case HANDLER: |
2976 case NONEXISTENT: | 2978 case NONEXISTENT: |
2977 UNREACHABLE(); | 2979 UNREACHABLE(); |
2978 } | 2980 } |
2979 | 2981 |
2980 Handle<Object> hresult; | 2982 Handle<Object> hresult; |
2981 if (!result->ToHandle(&hresult)) return result; | 2983 if (!result->ToHandle(&hresult)) return result; |
2982 | 2984 |
2983 if (FLAG_harmony_observation && map()->is_observed()) { | 2985 if (FLAG_harmony_observation && map()->is_observed()) { |
2984 this->EnqueueChangeRecord("updated", name, old_value); | 2986 if (lookup->IsTransition()) { |
| 2987 self->EnqueueChangeRecord("new", name, old_value); |
| 2988 } else { |
| 2989 LookupResult new_lookup(self->GetIsolate()); |
| 2990 self->LocalLookup(*name, &new_lookup); |
| 2991 ASSERT(!new_lookup.GetLazyValue()->IsTheHole()); |
| 2992 if (!new_lookup.GetLazyValue()->SameValue(*old_value)) { |
| 2993 self->EnqueueChangeRecord("updated", name, old_value); |
| 2994 } |
| 2995 } |
2985 } | 2996 } |
2986 | 2997 |
2987 return *hresult; | 2998 return *hresult; |
2988 } | 2999 } |
2989 | 3000 |
2990 | 3001 |
2991 // Set a real local property, even if it is READ_ONLY. If the property is not | 3002 // 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 | 3003 // 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 | 3004 // SetProperty, with the check for IsReadOnly and the check for a |
2994 // callback setter removed. The two lines looking up the LookupResult | 3005 // callback setter removed. The two lines looking up the LookupResult |
2995 // result are also added. If one of the functions is changed, the other | 3006 // result are also added. If one of the functions is changed, the other |
2996 // should be. | 3007 // should be. |
2997 // Note that this method cannot be used to set the prototype of a function | 3008 // Note that this method cannot be used to set the prototype of a function |
2998 // because ConvertDescriptorToField() which is called in "case CALLBACKS:" | 3009 // because ConvertDescriptorToField() which is called in "case CALLBACKS:" |
2999 // doesn't handle function prototypes correctly. | 3010 // doesn't handle function prototypes correctly. |
3000 Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes( | 3011 Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes( |
3001 Handle<JSObject> object, | 3012 Handle<JSObject> object, |
3002 Handle<String> key, | 3013 Handle<String> key, |
3003 Handle<Object> value, | 3014 Handle<Object> value, |
3004 PropertyAttributes attributes) { | 3015 PropertyAttributes attributes) { |
3005 CALL_HEAP_FUNCTION( | 3016 CALL_HEAP_FUNCTION( |
3006 object->GetIsolate(), | 3017 object->GetIsolate(), |
3007 object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes), | 3018 object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes), |
3008 Object); | 3019 Object); |
3009 } | 3020 } |
3010 | 3021 |
3011 | 3022 |
3012 MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( | 3023 MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( |
3013 String* name, | 3024 String* name_raw, |
3014 Object* value, | 3025 Object* value_raw, |
3015 PropertyAttributes attributes) { | 3026 PropertyAttributes attributes) { |
3016 // Make sure that the top context does not change when doing callbacks or | 3027 // Make sure that the top context does not change when doing callbacks or |
3017 // interceptor calls. | 3028 // interceptor calls. |
3018 AssertNoContextChange ncc; | 3029 AssertNoContextChange ncc; |
3019 Isolate* isolate = GetIsolate(); | 3030 Isolate* isolate = GetIsolate(); |
3020 LookupResult lookup(isolate); | 3031 LookupResult lookup(isolate); |
3021 LocalLookup(name, &lookup); | 3032 LocalLookup(name_raw, &lookup); |
3022 if (!lookup.IsFound()) map()->LookupTransition(this, name, &lookup); | 3033 if (!lookup.IsFound()) map()->LookupTransition(this, name_raw, &lookup); |
3023 // Check access rights if needed. | 3034 // Check access rights if needed. |
3024 if (IsAccessCheckNeeded()) { | 3035 if (IsAccessCheckNeeded()) { |
3025 if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { | 3036 if (!isolate->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) { |
3026 return SetPropertyWithFailedAccessCheck(&lookup, | 3037 return SetPropertyWithFailedAccessCheck(&lookup, |
3027 name, | 3038 name_raw, |
3028 value, | 3039 value_raw, |
3029 false, | 3040 false, |
3030 kNonStrictMode); | 3041 kNonStrictMode); |
3031 } | 3042 } |
3032 } | 3043 } |
3033 | 3044 |
3034 if (IsJSGlobalProxy()) { | 3045 if (IsJSGlobalProxy()) { |
3035 Object* proto = GetPrototype(); | 3046 Object* proto = GetPrototype(); |
3036 if (proto->IsNull()) return value; | 3047 if (proto->IsNull()) return value_raw; |
3037 ASSERT(proto->IsJSGlobalObject()); | 3048 ASSERT(proto->IsJSGlobalObject()); |
3038 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes( | 3049 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes( |
3039 name, | 3050 name_raw, |
3040 value, | 3051 value_raw, |
3041 attributes); | 3052 attributes); |
3042 } | 3053 } |
3043 | 3054 |
3044 // Check for accessor in prototype chain removed here in clone. | 3055 // Check for accessor in prototype chain removed here in clone. |
3045 if (!lookup.IsFound()) { | 3056 if (!lookup.IsFound()) { |
3046 // Neither properties nor transitions found. | 3057 // Neither properties nor transitions found. |
3047 return AddProperty(name, value, attributes, kNonStrictMode); | 3058 return AddProperty(name_raw, value_raw, attributes, kNonStrictMode); |
3048 } | 3059 } |
3049 | 3060 |
| 3061 // From this point on everything needs to be handlified. |
| 3062 HandleScope scope(GetIsolate()); |
| 3063 Handle<JSObject> self(this); |
| 3064 Handle<String> name(name_raw); |
| 3065 Handle<Object> value(value_raw); |
| 3066 |
3050 Handle<Object> old_value(isolate->heap()->the_hole_value()); | 3067 Handle<Object> old_value(isolate->heap()->the_hole_value()); |
| 3068 PropertyAttributes old_attributes; |
3051 if (FLAG_harmony_observation && map()->is_observed()) { | 3069 if (FLAG_harmony_observation && map()->is_observed()) { |
3052 // TODO(observe): save oldValue | 3070 old_value = handle(lookup.GetLazyValue()); |
| 3071 old_attributes = lookup.GetAttributes(); |
3053 } | 3072 } |
3054 | 3073 |
3055 // Check of IsReadOnly removed from here in clone. | 3074 // Check of IsReadOnly removed from here in clone. |
3056 MaybeObject* result = value; | 3075 MaybeObject* result = *value; |
3057 switch (lookup.type()) { | 3076 switch (lookup.type()) { |
3058 case NORMAL: { | 3077 case NORMAL: { |
3059 PropertyDetails details = PropertyDetails(attributes, NORMAL); | 3078 PropertyDetails details = PropertyDetails(attributes, NORMAL); |
3060 result = SetNormalizedProperty(name, value, details); | 3079 result = self->SetNormalizedProperty(*name, *value, details); |
3061 break; | 3080 break; |
3062 } | 3081 } |
3063 case FIELD: | 3082 case FIELD: |
3064 result = FastPropertyAtPut(lookup.GetFieldIndex(), value); | 3083 result = self->FastPropertyAtPut(lookup.GetFieldIndex(), *value); |
3065 break; | 3084 break; |
3066 case CONSTANT_FUNCTION: | 3085 case CONSTANT_FUNCTION: |
3067 // Only replace the function if necessary. | 3086 // Only replace the function if necessary. |
3068 if (value == lookup.GetConstantFunction()) return value; | 3087 if (*value != lookup.GetConstantFunction()) { |
3069 // Preserve the attributes of this existing property. | 3088 // Preserve the attributes of this existing property. |
3070 attributes = lookup.GetAttributes(); | 3089 attributes = lookup.GetAttributes(); |
3071 result = ConvertDescriptorToField(name, value, attributes); | 3090 result = self->ConvertDescriptorToField(*name, *value, attributes); |
| 3091 } |
3072 break; | 3092 break; |
3073 case CALLBACKS: | 3093 case CALLBACKS: |
3074 case INTERCEPTOR: | 3094 case INTERCEPTOR: |
3075 // Override callback in clone | 3095 // Override callback in clone |
3076 result = ConvertDescriptorToField(name, value, attributes); | 3096 result = self->ConvertDescriptorToField(*name, *value, attributes); |
3077 break; | 3097 break; |
3078 case TRANSITION: { | 3098 case TRANSITION: { |
3079 Map* transition_map = lookup.GetTransitionTarget(); | 3099 Map* transition_map = lookup.GetTransitionTarget(); |
3080 int descriptor = transition_map->LastAdded(); | 3100 int descriptor = transition_map->LastAdded(); |
3081 | 3101 |
3082 DescriptorArray* descriptors = transition_map->instance_descriptors(); | 3102 DescriptorArray* descriptors = transition_map->instance_descriptors(); |
3083 PropertyDetails details = descriptors->GetDetails(descriptor); | 3103 PropertyDetails details = descriptors->GetDetails(descriptor); |
3084 | 3104 |
3085 if (details.type() == FIELD) { | 3105 if (details.type() == FIELD) { |
3086 if (attributes == details.attributes()) { | 3106 if (attributes == details.attributes()) { |
3087 int field_index = descriptors->GetFieldIndex(descriptor); | 3107 int field_index = descriptors->GetFieldIndex(descriptor); |
3088 result = AddFastPropertyUsingMap(transition_map, | 3108 result = self->AddFastPropertyUsingMap( |
3089 name, | 3109 transition_map, *name, *value, field_index); |
3090 value, | |
3091 field_index); | |
3092 } else { | 3110 } else { |
3093 result = ConvertDescriptorToField(name, value, attributes); | 3111 result = self->ConvertDescriptorToField(*name, *value, attributes); |
3094 } | 3112 } |
3095 } else if (details.type() == CALLBACKS) { | 3113 } else if (details.type() == CALLBACKS) { |
3096 result = ConvertDescriptorToField(name, value, attributes); | 3114 result = self->ConvertDescriptorToField(*name, *value, attributes); |
3097 } else { | 3115 } else { |
3098 ASSERT(details.type() == CONSTANT_FUNCTION); | 3116 ASSERT(details.type() == CONSTANT_FUNCTION); |
3099 | 3117 |
3100 // Replace transition to CONSTANT FUNCTION with a map transition to a | 3118 // Replace transition to CONSTANT FUNCTION with a map transition to a |
3101 // new map with a FIELD, even if the value is a function. | 3119 // new map with a FIELD, even if the value is a function. |
3102 result = ConvertTransitionToMapTransition( | 3120 result = self->ConvertTransitionToMapTransition( |
3103 lookup.GetTransitionIndex(), name, value, attributes); | 3121 lookup.GetTransitionIndex(), *name, *value, attributes); |
3104 } | 3122 } |
3105 break; | 3123 break; |
3106 } | 3124 } |
3107 case HANDLER: | 3125 case HANDLER: |
3108 case NONEXISTENT: | 3126 case NONEXISTENT: |
3109 UNREACHABLE(); | 3127 UNREACHABLE(); |
3110 } | 3128 } |
3111 | 3129 |
3112 Handle<Object> hresult; | 3130 Handle<Object> hresult; |
3113 if (!result->ToHandle(&hresult)) return result; | 3131 if (!result->ToHandle(&hresult)) return result; |
3114 | 3132 |
3115 if (FLAG_harmony_observation && map()->is_observed()) { | 3133 if (FLAG_harmony_observation && map()->is_observed()) { |
3116 const char* type = | 3134 if (lookup.IsTransition()) { |
3117 attributes == lookup.GetAttributes() ? "updated" : "reconfigured"; | 3135 self->EnqueueChangeRecord("new", name, old_value); |
3118 this->EnqueueChangeRecord(type, handle(name), old_value); | 3136 } else { |
| 3137 LookupResult new_lookup(isolate); |
| 3138 self->LocalLookup(*name, &new_lookup); |
| 3139 ASSERT(!new_lookup.GetLazyValue()->IsTheHole()); |
| 3140 if (old_value->IsTheHole() || |
| 3141 new_lookup.GetAttributes() != old_attributes) { |
| 3142 self->EnqueueChangeRecord("reconfigured", name, old_value); |
| 3143 } else if (!new_lookup.GetLazyValue()->SameValue(*old_value)) { |
| 3144 self->EnqueueChangeRecord("updated", name, old_value); |
| 3145 } |
| 3146 } |
3119 } | 3147 } |
3120 | 3148 |
3121 return *hresult; | 3149 return *hresult; |
3122 } | 3150 } |
3123 | 3151 |
3124 | 3152 |
3125 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor( | 3153 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor( |
3126 JSObject* receiver, | 3154 JSObject* receiver, |
3127 String* name, | 3155 String* name, |
3128 bool continue_search) { | 3156 bool continue_search) { |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3196 | 3224 |
3197 PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver( | 3225 PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver( |
3198 JSReceiver* receiver, | 3226 JSReceiver* receiver, |
3199 String* key) { | 3227 String* key) { |
3200 uint32_t index = 0; | 3228 uint32_t index = 0; |
3201 if (IsJSObject() && key->AsArrayIndex(&index)) { | 3229 if (IsJSObject() && key->AsArrayIndex(&index)) { |
3202 return JSObject::cast(this)->HasElementWithReceiver(receiver, index) | 3230 return JSObject::cast(this)->HasElementWithReceiver(receiver, index) |
3203 ? NONE : ABSENT; | 3231 ? NONE : ABSENT; |
3204 } | 3232 } |
3205 // Named property. | 3233 // Named property. |
3206 LookupResult result(GetIsolate()); | 3234 LookupResult lookup(GetIsolate()); |
3207 Lookup(key, &result); | 3235 Lookup(key, &lookup); |
3208 return GetPropertyAttribute(receiver, &result, key, true); | 3236 return GetPropertyAttributeForResult(receiver, &lookup, key, true); |
3209 } | 3237 } |
3210 | 3238 |
3211 | 3239 |
3212 PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver, | 3240 PropertyAttributes JSReceiver::GetPropertyAttributeForResult( |
3213 LookupResult* result, | 3241 JSReceiver* receiver, |
3214 String* name, | 3242 LookupResult* lookup, |
3215 bool continue_search) { | 3243 String* name, |
| 3244 bool continue_search) { |
3216 // Check access rights if needed. | 3245 // Check access rights if needed. |
3217 if (IsAccessCheckNeeded()) { | 3246 if (IsAccessCheckNeeded()) { |
3218 JSObject* this_obj = JSObject::cast(this); | 3247 JSObject* this_obj = JSObject::cast(this); |
3219 Heap* heap = GetHeap(); | 3248 Heap* heap = GetHeap(); |
3220 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) { | 3249 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) { |
3221 return this_obj->GetPropertyAttributeWithFailedAccessCheck( | 3250 return this_obj->GetPropertyAttributeWithFailedAccessCheck( |
3222 receiver, result, name, continue_search); | 3251 receiver, lookup, name, continue_search); |
3223 } | 3252 } |
3224 } | 3253 } |
3225 if (result->IsFound()) { | 3254 if (lookup->IsFound()) { |
3226 switch (result->type()) { | 3255 switch (lookup->type()) { |
3227 case NORMAL: // fall through | 3256 case NORMAL: // fall through |
3228 case FIELD: | 3257 case FIELD: |
3229 case CONSTANT_FUNCTION: | 3258 case CONSTANT_FUNCTION: |
3230 case CALLBACKS: | 3259 case CALLBACKS: |
3231 return result->GetAttributes(); | 3260 return lookup->GetAttributes(); |
3232 case HANDLER: { | 3261 case HANDLER: { |
3233 return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler( | 3262 return JSProxy::cast(lookup->proxy())->GetPropertyAttributeWithHandler( |
3234 receiver, name); | 3263 receiver, name); |
3235 } | 3264 } |
3236 case INTERCEPTOR: | 3265 case INTERCEPTOR: |
3237 return result->holder()->GetPropertyAttributeWithInterceptor( | 3266 return lookup->holder()->GetPropertyAttributeWithInterceptor( |
3238 JSObject::cast(receiver), name, continue_search); | 3267 JSObject::cast(receiver), name, continue_search); |
3239 case TRANSITION: | 3268 case TRANSITION: |
3240 case NONEXISTENT: | 3269 case NONEXISTENT: |
3241 UNREACHABLE(); | 3270 UNREACHABLE(); |
3242 } | 3271 } |
3243 } | 3272 } |
3244 return ABSENT; | 3273 return ABSENT; |
3245 } | 3274 } |
3246 | 3275 |
3247 | 3276 |
3248 PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) { | 3277 PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) { |
3249 // Check whether the name is an array index. | 3278 // Check whether the name is an array index. |
3250 uint32_t index = 0; | 3279 uint32_t index = 0; |
3251 if (IsJSObject() && name->AsArrayIndex(&index)) { | 3280 if (IsJSObject() && name->AsArrayIndex(&index)) { |
3252 if (JSObject::cast(this)->HasLocalElement(index)) return NONE; | 3281 if (JSObject::cast(this)->HasLocalElement(index)) return NONE; |
3253 return ABSENT; | 3282 return ABSENT; |
3254 } | 3283 } |
3255 // Named property. | 3284 // Named property. |
3256 LookupResult result(GetIsolate()); | 3285 LookupResult lookup(GetIsolate()); |
3257 LocalLookup(name, &result); | 3286 LocalLookup(name, &lookup); |
3258 return GetPropertyAttribute(this, &result, name, false); | 3287 return GetPropertyAttributeForResult(this, &lookup, name, false); |
3259 } | 3288 } |
3260 | 3289 |
3261 | 3290 |
3262 MaybeObject* NormalizedMapCache::Get(JSObject* obj, | 3291 MaybeObject* NormalizedMapCache::Get(JSObject* obj, |
3263 PropertyNormalizationMode mode) { | 3292 PropertyNormalizationMode mode) { |
3264 Isolate* isolate = obj->GetIsolate(); | 3293 Isolate* isolate = obj->GetIsolate(); |
3265 Map* fast = obj->map(); | 3294 Map* fast = obj->map(); |
3266 int index = fast->Hash() % kEntries; | 3295 int index = fast->Hash() % kEntries; |
3267 Object* result = get(index); | 3296 Object* result = get(index); |
3268 if (result->IsMap() && | 3297 if (result->IsMap() && |
(...skipping 763 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4032 if (mode == STRICT_DELETION) { | 4061 if (mode == STRICT_DELETION) { |
4033 // Deleting a non-configurable property in strict mode. | 4062 // Deleting a non-configurable property in strict mode. |
4034 HandleScope scope(isolate); | 4063 HandleScope scope(isolate); |
4035 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) }; | 4064 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) }; |
4036 return isolate->Throw(*isolate->factory()->NewTypeError( | 4065 return isolate->Throw(*isolate->factory()->NewTypeError( |
4037 "strict_delete_property", HandleVector(args, 2))); | 4066 "strict_delete_property", HandleVector(args, 2))); |
4038 } | 4067 } |
4039 return isolate->heap()->false_value(); | 4068 return isolate->heap()->false_value(); |
4040 } | 4069 } |
4041 | 4070 |
| 4071 // From this point on everything needs to be handlified. |
4042 HandleScope scope(isolate); | 4072 HandleScope scope(isolate); |
| 4073 Handle<JSObject> self(this); |
| 4074 Handle<String> hname(name); |
| 4075 |
4043 Handle<Object> old_value(isolate->heap()->the_hole_value()); | 4076 Handle<Object> old_value(isolate->heap()->the_hole_value()); |
4044 if (FLAG_harmony_observation && map()->is_observed()) { | 4077 if (FLAG_harmony_observation && map()->is_observed()) { |
4045 // TODO(observe): save oldValue | 4078 old_value = handle(lookup.GetLazyValue()); |
4046 } | 4079 } |
4047 MaybeObject* result; | 4080 MaybeObject* result; |
4048 | 4081 |
4049 // Check for interceptor. | 4082 // Check for interceptor. |
4050 if (lookup.IsInterceptor()) { | 4083 if (lookup.IsInterceptor()) { |
4051 // Skip interceptor if forcing a deletion. | 4084 // Skip interceptor if forcing a deletion. |
4052 if (mode == FORCE_DELETION) { | 4085 if (mode == FORCE_DELETION) { |
4053 result = DeletePropertyPostInterceptor(name, mode); | 4086 result = self->DeletePropertyPostInterceptor(*hname, mode); |
4054 } else { | 4087 } else { |
4055 result = DeletePropertyWithInterceptor(name); | 4088 result = self->DeletePropertyWithInterceptor(*hname); |
4056 } | 4089 } |
4057 } else { | 4090 } else { |
4058 // Normalize object if needed. | 4091 // Normalize object if needed. |
4059 Object* obj; | 4092 Object* obj; |
4060 result = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | 4093 result = self->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
4061 if (!result->ToObject(&obj)) return result; | 4094 if (!result->To(&obj)) return result; |
4062 // Make sure the properties are normalized before removing the entry. | 4095 // Make sure the properties are normalized before removing the entry. |
4063 result = DeleteNormalizedProperty(name, mode); | 4096 result = self->DeleteNormalizedProperty(*hname, mode); |
4064 } | 4097 } |
4065 | 4098 |
4066 Handle<Object> hresult; | 4099 Handle<Object> hresult; |
4067 if (!result->ToHandle(&hresult)) return result; | 4100 if (!result->ToHandle(&hresult)) return result; |
4068 | 4101 |
4069 if (FLAG_harmony_observation && map()->is_observed()) { | 4102 if (FLAG_harmony_observation && map()->is_observed()) { |
4070 this->EnqueueChangeRecord("deleted", handle(name), old_value); | 4103 if (!self->HasLocalProperty(*hname)) |
| 4104 self->EnqueueChangeRecord("deleted", hname, old_value); |
4071 } | 4105 } |
4072 | 4106 |
4073 return *hresult; | 4107 return *hresult; |
4074 } | 4108 } |
4075 | 4109 |
4076 | 4110 |
4077 MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) { | 4111 MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) { |
4078 if (IsJSProxy()) { | 4112 if (IsJSProxy()) { |
4079 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode); | 4113 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode); |
4080 } | 4114 } |
(...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4662 void JSObject::DefineAccessor(Handle<JSObject> object, | 4696 void JSObject::DefineAccessor(Handle<JSObject> object, |
4663 Handle<String> name, | 4697 Handle<String> name, |
4664 Handle<Object> getter, | 4698 Handle<Object> getter, |
4665 Handle<Object> setter, | 4699 Handle<Object> setter, |
4666 PropertyAttributes attributes) { | 4700 PropertyAttributes attributes) { |
4667 CALL_HEAP_FUNCTION_VOID( | 4701 CALL_HEAP_FUNCTION_VOID( |
4668 object->GetIsolate(), | 4702 object->GetIsolate(), |
4669 object->DefineAccessor(*name, *getter, *setter, attributes)); | 4703 object->DefineAccessor(*name, *getter, *setter, attributes)); |
4670 } | 4704 } |
4671 | 4705 |
4672 MaybeObject* JSObject::DefineAccessor(String* name, | 4706 MaybeObject* JSObject::DefineAccessor(String* name_raw, |
4673 Object* getter, | 4707 Object* getter_raw, |
4674 Object* setter, | 4708 Object* setter_raw, |
4675 PropertyAttributes attributes) { | 4709 PropertyAttributes attributes) { |
4676 Isolate* isolate = GetIsolate(); | 4710 Isolate* isolate = GetIsolate(); |
4677 // Check access rights if needed. | 4711 // Check access rights if needed. |
4678 if (IsAccessCheckNeeded() && | 4712 if (IsAccessCheckNeeded() && |
4679 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { | 4713 !isolate->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) { |
4680 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); | 4714 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); |
4681 return isolate->heap()->undefined_value(); | 4715 return isolate->heap()->undefined_value(); |
4682 } | 4716 } |
4683 | 4717 |
4684 if (IsJSGlobalProxy()) { | 4718 if (IsJSGlobalProxy()) { |
4685 Object* proto = GetPrototype(); | 4719 Object* proto = GetPrototype(); |
4686 if (proto->IsNull()) return this; | 4720 if (proto->IsNull()) return this; |
4687 ASSERT(proto->IsJSGlobalObject()); | 4721 ASSERT(proto->IsJSGlobalObject()); |
4688 return JSObject::cast(proto)->DefineAccessor( | 4722 return JSObject::cast(proto)->DefineAccessor( |
4689 name, getter, setter, attributes); | 4723 name_raw, getter_raw, setter_raw, attributes); |
4690 } | 4724 } |
4691 | 4725 |
4692 // Make sure that the top context does not change when doing callbacks or | 4726 // Make sure that the top context does not change when doing callbacks or |
4693 // interceptor calls. | 4727 // interceptor calls. |
4694 AssertNoContextChange ncc; | 4728 AssertNoContextChange ncc; |
4695 | 4729 |
4696 // Try to flatten before operating on the string. | 4730 // Try to flatten before operating on the string. |
4697 name->TryFlatten(); | 4731 name_raw->TryFlatten(); |
4698 | 4732 |
4699 if (!CanSetCallback(name)) return isolate->heap()->undefined_value(); | 4733 if (!CanSetCallback(name_raw)) return isolate->heap()->undefined_value(); |
| 4734 |
| 4735 // From this point on everything needs to be handlified. |
| 4736 HandleScope scope(GetIsolate()); |
| 4737 Handle<JSObject> self(this); |
| 4738 Handle<String> name(name_raw); |
| 4739 Handle<Object> getter(getter_raw); |
| 4740 Handle<Object> setter(setter_raw); |
| 4741 |
| 4742 uint32_t index = 0; |
| 4743 bool is_element = name->AsArrayIndex(&index); |
4700 | 4744 |
4701 Handle<Object> old_value(isolate->heap()->the_hole_value()); | 4745 Handle<Object> old_value(isolate->heap()->the_hole_value()); |
4702 bool preexists = false; | 4746 bool preexists = false; |
4703 if (FLAG_harmony_observation && map()->is_observed()) { | 4747 if (FLAG_harmony_observation && map()->is_observed()) { |
4704 LookupResult result(isolate); | 4748 if (is_element) { |
4705 LocalLookup(name, &result); | 4749 preexists = HasLocalElement(index); |
4706 preexists = result.IsFound(); | 4750 if (preexists) { |
4707 // TODO(observe): save oldValue | 4751 // TODO(observe): distinguish the case where it's an accessor |
| 4752 old_value = Object::GetElement(self, index); |
| 4753 } |
| 4754 } else { |
| 4755 LookupResult lookup(isolate); |
| 4756 LocalLookup(*name, &lookup); |
| 4757 preexists = lookup.IsProperty(); |
| 4758 if (preexists) old_value = handle(lookup.GetLazyValue()); |
| 4759 } |
4708 } | 4760 } |
4709 | 4761 |
4710 uint32_t index = 0; | 4762 MaybeObject* result = is_element ? |
4711 MaybeObject* result = name->AsArrayIndex(&index) | 4763 self->DefineElementAccessor(index, *getter, *setter, attributes) : |
4712 ? DefineElementAccessor(index, getter, setter, attributes) | 4764 self->DefinePropertyAccessor(*name, *getter, *setter, attributes); |
4713 : DefinePropertyAccessor(name, getter, setter, attributes); | |
4714 | 4765 |
4715 Handle<Object> hresult; | 4766 Handle<Object> hresult; |
4716 if (!result->ToHandle(&hresult)) return result; | 4767 if (!result->ToHandle(&hresult)) return result; |
4717 | 4768 |
4718 if (FLAG_harmony_observation && map()->is_observed()) { | 4769 if (FLAG_harmony_observation && map()->is_observed()) { |
4719 const char* type = preexists ? "reconfigured" : "new"; | 4770 const char* type = preexists ? "reconfigured" : "new"; |
4720 this->EnqueueChangeRecord(type, handle(name), old_value); | 4771 self->EnqueueChangeRecord(type, name, old_value); |
4721 } | 4772 } |
4722 | 4773 |
4723 return *hresult; | 4774 return *hresult; |
4724 } | 4775 } |
4725 | 4776 |
4726 | 4777 |
4727 static MaybeObject* TryAccessorTransition(JSObject* self, | 4778 static MaybeObject* TryAccessorTransition(JSObject* self, |
4728 Map* transitioned_map, | 4779 Map* transitioned_map, |
4729 int target_descriptor, | 4780 int target_descriptor, |
4730 AccessorComponent component, | 4781 AccessorComponent component, |
(...skipping 8846 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13577 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); | 13628 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); |
13578 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); | 13629 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); |
13579 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); | 13630 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); |
13580 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); | 13631 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); |
13581 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); | 13632 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); |
13582 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); | 13633 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); |
13583 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); | 13634 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); |
13584 } | 13635 } |
13585 | 13636 |
13586 } } // namespace v8::internal | 13637 } } // namespace v8::internal |
OLD | NEW |