OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 Handle<String> name_handle(name); | 378 Handle<String> name_handle(name); |
379 Handle<Object> value_handle(value); | 379 Handle<Object> value_handle(value); |
380 bool pending_exception; | 380 bool pending_exception; |
381 LoadLazy(Handle<JSObject>(JSObject::cast(result->GetLazyValue())), | 381 LoadLazy(Handle<JSObject>(JSObject::cast(result->GetLazyValue())), |
382 &pending_exception); | 382 &pending_exception); |
383 if (pending_exception) return Failure::Exception(); | 383 if (pending_exception) return Failure::Exception(); |
384 return this_handle->SetProperty(*name_handle, *value_handle, attributes); | 384 return this_handle->SetProperty(*name_handle, *value_handle, attributes); |
385 } | 385 } |
386 | 386 |
387 | 387 |
388 Object* JSObject::DeleteLazyProperty(LookupResult* result, String* name) { | 388 Object* JSObject::DeleteLazyProperty(LookupResult* result, |
| 389 String* name, |
| 390 DeleteMode mode) { |
389 HandleScope scope; | 391 HandleScope scope; |
390 Handle<JSObject> this_handle(this); | 392 Handle<JSObject> this_handle(this); |
391 Handle<String> name_handle(name); | 393 Handle<String> name_handle(name); |
392 bool pending_exception; | 394 bool pending_exception; |
393 LoadLazy(Handle<JSObject>(JSObject::cast(result->GetLazyValue())), | 395 LoadLazy(Handle<JSObject>(JSObject::cast(result->GetLazyValue())), |
394 &pending_exception); | 396 &pending_exception); |
395 if (pending_exception) return Failure::Exception(); | 397 if (pending_exception) return Failure::Exception(); |
396 return this_handle->DeleteProperty(*name_handle); | 398 return this_handle->DeleteProperty(*name_handle, mode); |
397 } | 399 } |
398 | 400 |
399 | 401 |
400 Object* Object::GetProperty(Object* receiver, | 402 Object* Object::GetProperty(Object* receiver, |
401 LookupResult* result, | 403 LookupResult* result, |
402 String* name, | 404 String* name, |
403 PropertyAttributes* attributes) { | 405 PropertyAttributes* attributes) { |
404 // Make sure that the top context does not change when doing | 406 // Make sure that the top context does not change when doing |
405 // callbacks or interceptor calls. | 407 // callbacks or interceptor calls. |
406 AssertNoContextChange ncc; | 408 AssertNoContextChange ncc; |
(...skipping 1706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2113 if (FLAG_trace_normalization) { | 2115 if (FLAG_trace_normalization) { |
2114 PrintF("Object elements have been normalized:\n"); | 2116 PrintF("Object elements have been normalized:\n"); |
2115 Print(); | 2117 Print(); |
2116 } | 2118 } |
2117 #endif | 2119 #endif |
2118 | 2120 |
2119 return this; | 2121 return this; |
2120 } | 2122 } |
2121 | 2123 |
2122 | 2124 |
2123 Object* JSObject::DeletePropertyPostInterceptor(String* name) { | 2125 Object* JSObject::DeletePropertyPostInterceptor(String* name, DeleteMode mode) { |
2124 // Check local property, ignore interceptor. | 2126 // Check local property, ignore interceptor. |
2125 LookupResult result; | 2127 LookupResult result; |
2126 LocalLookupRealNamedProperty(name, &result); | 2128 LocalLookupRealNamedProperty(name, &result); |
2127 if (!result.IsValid()) return Heap::true_value(); | 2129 if (!result.IsValid()) return Heap::true_value(); |
2128 | 2130 |
2129 // Normalize object if needed. | 2131 // Normalize object if needed. |
2130 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES); | 2132 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES); |
2131 if (obj->IsFailure()) return obj; | 2133 if (obj->IsFailure()) return obj; |
2132 | 2134 |
2133 ASSERT(!HasFastProperties()); | 2135 ASSERT(!HasFastProperties()); |
2134 // Attempt to remove the property from the property dictionary. | 2136 // Attempt to remove the property from the property dictionary. |
2135 Dictionary* dictionary = property_dictionary(); | 2137 Dictionary* dictionary = property_dictionary(); |
2136 int entry = dictionary->FindStringEntry(name); | 2138 int entry = dictionary->FindStringEntry(name); |
2137 if (entry != -1) return dictionary->DeleteProperty(entry); | 2139 if (entry != -1) return dictionary->DeleteProperty(entry, mode); |
2138 return Heap::true_value(); | 2140 return Heap::true_value(); |
2139 } | 2141 } |
2140 | 2142 |
2141 | 2143 |
2142 Object* JSObject::DeletePropertyWithInterceptor(String* name) { | 2144 Object* JSObject::DeletePropertyWithInterceptor(String* name) { |
2143 HandleScope scope; | 2145 HandleScope scope; |
2144 Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); | 2146 Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); |
2145 Handle<String> name_handle(name); | 2147 Handle<String> name_handle(name); |
2146 Handle<JSObject> this_handle(this); | 2148 Handle<JSObject> this_handle(this); |
2147 if (!interceptor->deleter()->IsUndefined()) { | 2149 if (!interceptor->deleter()->IsUndefined()) { |
2148 v8::NamedPropertyDeleter deleter = | 2150 v8::NamedPropertyDeleter deleter = |
2149 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter()); | 2151 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter()); |
2150 Handle<Object> data_handle(interceptor->data()); | 2152 Handle<Object> data_handle(interceptor->data()); |
2151 LOG(ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name)); | 2153 LOG(ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name)); |
2152 v8::AccessorInfo info(v8::Utils::ToLocal(this_handle), | 2154 v8::AccessorInfo info(v8::Utils::ToLocal(this_handle), |
2153 v8::Utils::ToLocal(data_handle), | 2155 v8::Utils::ToLocal(data_handle), |
2154 v8::Utils::ToLocal(this_handle)); | 2156 v8::Utils::ToLocal(this_handle)); |
2155 v8::Handle<v8::Boolean> result; | 2157 v8::Handle<v8::Boolean> result; |
2156 { | 2158 { |
2157 // Leaving JavaScript. | 2159 // Leaving JavaScript. |
2158 VMState state(EXTERNAL); | 2160 VMState state(EXTERNAL); |
2159 result = deleter(v8::Utils::ToLocal(name_handle), info); | 2161 result = deleter(v8::Utils::ToLocal(name_handle), info); |
2160 } | 2162 } |
2161 RETURN_IF_SCHEDULED_EXCEPTION(); | 2163 RETURN_IF_SCHEDULED_EXCEPTION(); |
2162 if (!result.IsEmpty()) { | 2164 if (!result.IsEmpty()) { |
2163 ASSERT(result->IsBoolean()); | 2165 ASSERT(result->IsBoolean()); |
2164 return *v8::Utils::OpenHandle(*result); | 2166 return *v8::Utils::OpenHandle(*result); |
2165 } | 2167 } |
2166 } | 2168 } |
2167 Object* raw_result = this_handle->DeletePropertyPostInterceptor(*name_handle); | 2169 Object* raw_result = |
| 2170 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION); |
2168 RETURN_IF_SCHEDULED_EXCEPTION(); | 2171 RETURN_IF_SCHEDULED_EXCEPTION(); |
2169 return raw_result; | 2172 return raw_result; |
2170 } | 2173 } |
2171 | 2174 |
2172 | 2175 |
2173 Object* JSObject::DeleteElementPostInterceptor(uint32_t index) { | 2176 Object* JSObject::DeleteElementPostInterceptor(uint32_t index, |
| 2177 DeleteMode mode) { |
2174 if (HasFastElements()) { | 2178 if (HasFastElements()) { |
2175 uint32_t length = IsJSArray() ? | 2179 uint32_t length = IsJSArray() ? |
2176 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : | 2180 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : |
2177 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 2181 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
2178 if (index < length) { | 2182 if (index < length) { |
2179 FixedArray::cast(elements())->set_the_hole(index); | 2183 FixedArray::cast(elements())->set_the_hole(index); |
2180 } | 2184 } |
2181 return Heap::true_value(); | 2185 return Heap::true_value(); |
2182 } | 2186 } |
2183 ASSERT(!HasFastElements()); | 2187 ASSERT(!HasFastElements()); |
2184 Dictionary* dictionary = element_dictionary(); | 2188 Dictionary* dictionary = element_dictionary(); |
2185 int entry = dictionary->FindNumberEntry(index); | 2189 int entry = dictionary->FindNumberEntry(index); |
2186 if (entry != -1) return dictionary->DeleteProperty(entry); | 2190 if (entry != -1) return dictionary->DeleteProperty(entry, mode); |
2187 return Heap::true_value(); | 2191 return Heap::true_value(); |
2188 } | 2192 } |
2189 | 2193 |
2190 | 2194 |
2191 Object* JSObject::DeleteElementWithInterceptor(uint32_t index) { | 2195 Object* JSObject::DeleteElementWithInterceptor(uint32_t index) { |
2192 // Make sure that the top context does not change when doing | 2196 // Make sure that the top context does not change when doing |
2193 // callbacks or interceptor calls. | 2197 // callbacks or interceptor calls. |
2194 AssertNoContextChange ncc; | 2198 AssertNoContextChange ncc; |
2195 HandleScope scope; | 2199 HandleScope scope; |
2196 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); | 2200 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); |
(...skipping 10 matching lines...) Expand all Loading... |
2207 { | 2211 { |
2208 // Leaving JavaScript. | 2212 // Leaving JavaScript. |
2209 VMState state(EXTERNAL); | 2213 VMState state(EXTERNAL); |
2210 result = deleter(index, info); | 2214 result = deleter(index, info); |
2211 } | 2215 } |
2212 RETURN_IF_SCHEDULED_EXCEPTION(); | 2216 RETURN_IF_SCHEDULED_EXCEPTION(); |
2213 if (!result.IsEmpty()) { | 2217 if (!result.IsEmpty()) { |
2214 ASSERT(result->IsBoolean()); | 2218 ASSERT(result->IsBoolean()); |
2215 return *v8::Utils::OpenHandle(*result); | 2219 return *v8::Utils::OpenHandle(*result); |
2216 } | 2220 } |
2217 Object* raw_result = this_handle->DeleteElementPostInterceptor(index); | 2221 Object* raw_result = |
| 2222 this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION); |
2218 RETURN_IF_SCHEDULED_EXCEPTION(); | 2223 RETURN_IF_SCHEDULED_EXCEPTION(); |
2219 return raw_result; | 2224 return raw_result; |
2220 } | 2225 } |
2221 | 2226 |
2222 | 2227 |
2223 Object* JSObject::DeleteElement(uint32_t index) { | 2228 Object* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { |
2224 // Check access rights if needed. | 2229 // Check access rights if needed. |
2225 if (IsAccessCheckNeeded() && | 2230 if (IsAccessCheckNeeded() && |
2226 !Top::MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { | 2231 !Top::MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { |
2227 Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE); | 2232 Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE); |
2228 return Heap::false_value(); | 2233 return Heap::false_value(); |
2229 } | 2234 } |
2230 | 2235 |
2231 if (IsJSGlobalProxy()) { | 2236 if (IsJSGlobalProxy()) { |
2232 Object* proto = GetPrototype(); | 2237 Object* proto = GetPrototype(); |
2233 if (proto->IsNull()) return Heap::false_value(); | 2238 if (proto->IsNull()) return Heap::false_value(); |
2234 ASSERT(proto->IsJSGlobalObject()); | 2239 ASSERT(proto->IsJSGlobalObject()); |
2235 return JSGlobalObject::cast(proto)->DeleteElement(index); | 2240 return JSGlobalObject::cast(proto)->DeleteElement(index, mode); |
2236 } | 2241 } |
2237 | 2242 |
2238 if (HasIndexedInterceptor()) { | 2243 if (HasIndexedInterceptor()) { |
| 2244 // Skip interceptor if forcing deletion. |
| 2245 if (mode == FORCE_DELETION) { |
| 2246 return DeleteElementPostInterceptor(index, mode); |
| 2247 } |
2239 return DeleteElementWithInterceptor(index); | 2248 return DeleteElementWithInterceptor(index); |
2240 } | 2249 } |
2241 | 2250 |
2242 if (HasFastElements()) { | 2251 if (HasFastElements()) { |
2243 uint32_t length = IsJSArray() ? | 2252 uint32_t length = IsJSArray() ? |
2244 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : | 2253 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : |
2245 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 2254 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
2246 if (index < length) { | 2255 if (index < length) { |
2247 FixedArray::cast(elements())->set_the_hole(index); | 2256 FixedArray::cast(elements())->set_the_hole(index); |
2248 } | 2257 } |
2249 return Heap::true_value(); | 2258 return Heap::true_value(); |
2250 } else { | 2259 } else { |
2251 Dictionary* dictionary = element_dictionary(); | 2260 Dictionary* dictionary = element_dictionary(); |
2252 int entry = dictionary->FindNumberEntry(index); | 2261 int entry = dictionary->FindNumberEntry(index); |
2253 if (entry != -1) return dictionary->DeleteProperty(entry); | 2262 if (entry != -1) return dictionary->DeleteProperty(entry, mode); |
2254 } | 2263 } |
2255 return Heap::true_value(); | 2264 return Heap::true_value(); |
2256 } | 2265 } |
2257 | 2266 |
2258 | 2267 |
2259 Object* JSObject::DeleteProperty(String* name) { | 2268 Object* JSObject::DeleteProperty(String* name, DeleteMode mode) { |
2260 // ECMA-262, 3rd, 8.6.2.5 | 2269 // ECMA-262, 3rd, 8.6.2.5 |
2261 ASSERT(name->IsString()); | 2270 ASSERT(name->IsString()); |
2262 | 2271 |
2263 // Check access rights if needed. | 2272 // Check access rights if needed. |
2264 if (IsAccessCheckNeeded() && | 2273 if (IsAccessCheckNeeded() && |
2265 !Top::MayNamedAccess(this, name, v8::ACCESS_DELETE)) { | 2274 !Top::MayNamedAccess(this, name, v8::ACCESS_DELETE)) { |
2266 Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE); | 2275 Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE); |
2267 return Heap::false_value(); | 2276 return Heap::false_value(); |
2268 } | 2277 } |
2269 | 2278 |
2270 if (IsJSGlobalProxy()) { | 2279 if (IsJSGlobalProxy()) { |
2271 Object* proto = GetPrototype(); | 2280 Object* proto = GetPrototype(); |
2272 if (proto->IsNull()) return Heap::false_value(); | 2281 if (proto->IsNull()) return Heap::false_value(); |
2273 ASSERT(proto->IsJSGlobalObject()); | 2282 ASSERT(proto->IsJSGlobalObject()); |
2274 return JSGlobalObject::cast(proto)->DeleteProperty(name); | 2283 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode); |
2275 } | 2284 } |
2276 | 2285 |
2277 uint32_t index = 0; | 2286 uint32_t index = 0; |
2278 if (name->AsArrayIndex(&index)) { | 2287 if (name->AsArrayIndex(&index)) { |
2279 return DeleteElement(index); | 2288 return DeleteElement(index, mode); |
2280 } else { | 2289 } else { |
2281 LookupResult result; | 2290 LookupResult result; |
2282 LocalLookup(name, &result); | 2291 LocalLookup(name, &result); |
2283 if (!result.IsValid()) return Heap::true_value(); | 2292 if (!result.IsValid()) return Heap::true_value(); |
2284 if (result.IsDontDelete()) return Heap::false_value(); | 2293 // Ignore attributes if forcing a deletion. |
| 2294 if (result.IsDontDelete() && mode != FORCE_DELETION) { |
| 2295 return Heap::false_value(); |
| 2296 } |
2285 // Check for interceptor. | 2297 // Check for interceptor. |
2286 if (result.type() == INTERCEPTOR) { | 2298 if (result.type() == INTERCEPTOR) { |
| 2299 // Skip interceptor if forcing a deletion. |
| 2300 if (mode == FORCE_DELETION) { |
| 2301 return DeletePropertyPostInterceptor(name, mode); |
| 2302 } |
2287 return DeletePropertyWithInterceptor(name); | 2303 return DeletePropertyWithInterceptor(name); |
2288 } | 2304 } |
2289 if (!result.IsLoaded()) { | 2305 if (!result.IsLoaded()) { |
2290 return JSObject::cast(this)->DeleteLazyProperty(&result, name); | 2306 return JSObject::cast(this)->DeleteLazyProperty(&result, |
| 2307 name, |
| 2308 mode); |
2291 } | 2309 } |
2292 // Normalize object if needed. | 2310 // Normalize object if needed. |
2293 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES); | 2311 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES); |
2294 if (obj->IsFailure()) return obj; | 2312 if (obj->IsFailure()) return obj; |
2295 // Make sure the properties are normalized before removing the entry. | 2313 // Make sure the properties are normalized before removing the entry. |
2296 Dictionary* dictionary = property_dictionary(); | 2314 Dictionary* dictionary = property_dictionary(); |
2297 int entry = dictionary->FindStringEntry(name); | 2315 int entry = dictionary->FindStringEntry(name); |
2298 if (entry != -1) return dictionary->DeleteProperty(entry); | 2316 if (entry != -1) return dictionary->DeleteProperty(entry, mode); |
2299 return Heap::true_value(); | 2317 return Heap::true_value(); |
2300 } | 2318 } |
2301 } | 2319 } |
2302 | 2320 |
2303 | 2321 |
2304 // Check whether this object references another object. | 2322 // Check whether this object references another object. |
2305 bool JSObject::ReferencesObject(Object* obj) { | 2323 bool JSObject::ReferencesObject(Object* obj) { |
2306 AssertNoAllocation no_alloc; | 2324 AssertNoAllocation no_alloc; |
2307 | 2325 |
2308 // Is the object the constructor for this object? | 2326 // Is the object the constructor for this object? |
(...skipping 4627 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6936 removed_entries++; | 6954 removed_entries++; |
6937 } | 6955 } |
6938 } | 6956 } |
6939 } | 6957 } |
6940 | 6958 |
6941 // Update the number of elements. | 6959 // Update the number of elements. |
6942 SetNumberOfElements(NumberOfElements() - removed_entries); | 6960 SetNumberOfElements(NumberOfElements() - removed_entries); |
6943 } | 6961 } |
6944 | 6962 |
6945 | 6963 |
6946 Object* Dictionary::DeleteProperty(int entry) { | 6964 Object* Dictionary::DeleteProperty(int entry, JSObject::DeleteMode mode) { |
6947 PropertyDetails details = DetailsAt(entry); | 6965 PropertyDetails details = DetailsAt(entry); |
6948 if (details.IsDontDelete()) return Heap::false_value(); | 6966 // Ignore attributes if forcing a deletion. |
| 6967 if (details.IsDontDelete() && mode == JSObject::NORMAL_DELETION) { |
| 6968 return Heap::false_value(); |
| 6969 } |
6949 SetEntry(entry, Heap::null_value(), Heap::null_value(), Smi::FromInt(0)); | 6970 SetEntry(entry, Heap::null_value(), Heap::null_value(), Smi::FromInt(0)); |
6950 ElementRemoved(); | 6971 ElementRemoved(); |
6951 return Heap::true_value(); | 6972 return Heap::true_value(); |
6952 } | 6973 } |
6953 | 6974 |
6954 | 6975 |
6955 int Dictionary::FindStringEntry(String* key) { | 6976 int Dictionary::FindStringEntry(String* key) { |
6956 StringKey k(key); | 6977 StringKey k(key); |
6957 return FindEntry(&k); | 6978 return FindEntry(&k); |
6958 } | 6979 } |
(...skipping 578 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7537 // No break point. | 7558 // No break point. |
7538 if (break_point_objects()->IsUndefined()) return 0; | 7559 if (break_point_objects()->IsUndefined()) return 0; |
7539 // Single beak point. | 7560 // Single beak point. |
7540 if (!break_point_objects()->IsFixedArray()) return 1; | 7561 if (!break_point_objects()->IsFixedArray()) return 1; |
7541 // Multiple break points. | 7562 // Multiple break points. |
7542 return FixedArray::cast(break_point_objects())->length(); | 7563 return FixedArray::cast(break_point_objects())->length(); |
7543 } | 7564 } |
7544 #endif | 7565 #endif |
7545 | 7566 |
7546 } } // namespace v8::internal | 7567 } } // namespace v8::internal |
OLD | NEW |