| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 2145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2156 int i = 0; | 2156 int i = 0; |
| 2157 while (i < array->length()) { | 2157 while (i < array->length()) { |
| 2158 new_array->set(i, array->get(i)); | 2158 new_array->set(i, array->get(i)); |
| 2159 ++i; | 2159 ++i; |
| 2160 } | 2160 } |
| 2161 new_array->set(i, new_map); | 2161 new_array->set(i, new_map); |
| 2162 return new_array; | 2162 return new_array; |
| 2163 } | 2163 } |
| 2164 | 2164 |
| 2165 | 2165 |
| 2166 // Returns the contents of |map|'s descriptor array for the given string | 2166 String* Map::elements_transition_sentinel_name() { |
| 2167 // (which might be NULL). |safe_to_add_transition| is set to false and NULL | 2167 return GetHeap()->empty_symbol(); |
| 2168 // is returned if adding transitions is not allowed. | 2168 } |
| 2169 static Object* GetDescriptorContents(Map* map, | 2169 |
| 2170 String* sentinel_name, | 2170 |
| 2171 bool* safe_to_add_transition) { | 2171 Object* Map::GetDescriptorContents(String* sentinel_name, |
| 2172 bool* safe_to_add_transition) { |
| 2172 // Get the cached index for the descriptors lookup, or find and cache it. | 2173 // Get the cached index for the descriptors lookup, or find and cache it. |
| 2173 DescriptorArray* descriptors = map->instance_descriptors(); | 2174 DescriptorArray* descriptors = instance_descriptors(); |
| 2174 DescriptorLookupCache* cache = map->GetIsolate()->descriptor_lookup_cache(); | 2175 DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache(); |
| 2175 int index = cache->Lookup(descriptors, sentinel_name); | 2176 int index = cache->Lookup(descriptors, sentinel_name); |
| 2176 if (index == DescriptorLookupCache::kAbsent) { | 2177 if (index == DescriptorLookupCache::kAbsent) { |
| 2177 index = descriptors->Search(sentinel_name); | 2178 index = descriptors->Search(sentinel_name); |
| 2178 cache->Update(descriptors, sentinel_name, index); | 2179 cache->Update(descriptors, sentinel_name, index); |
| 2179 } | 2180 } |
| 2180 // If the transition already exists, return its descriptor. | 2181 // If the transition already exists, return its descriptor. |
| 2181 if (index != DescriptorArray::kNotFound) { | 2182 if (index != DescriptorArray::kNotFound) { |
| 2182 PropertyDetails details(descriptors->GetDetails(index)); | 2183 PropertyDetails details(descriptors->GetDetails(index)); |
| 2183 if (details.type() == ELEMENTS_TRANSITION) { | 2184 if (details.type() == ELEMENTS_TRANSITION) { |
| 2184 return descriptors->GetValue(index); | 2185 return descriptors->GetValue(index); |
| 2185 } else { | 2186 } else { |
| 2186 *safe_to_add_transition = false; | 2187 *safe_to_add_transition = false; |
| 2187 } | 2188 } |
| 2188 } | 2189 } |
| 2189 return NULL; | 2190 return NULL; |
| 2190 } | 2191 } |
| 2191 | 2192 |
| 2192 | 2193 |
| 2193 // Returns the map that |original_map| transitions to if its elements_kind | 2194 Map* Map::LookupElementsTransitionMap(ElementsKind elements_kind, |
| 2194 // is changed to |elements_kind|, or NULL if no such map is cached yet. | 2195 bool* safe_to_add_transition) { |
| 2195 // |safe_to_add_transitions| is set to false if adding transitions is not | |
| 2196 // allowed. | |
| 2197 static Map* LookupElementsTransitionMap(Map* original_map, | |
| 2198 ElementsKind elements_kind, | |
| 2199 String* sentinel_name, | |
| 2200 bool* safe_to_add_transition) { | |
| 2201 // Special case: indirect SMI->FAST transition (cf. comment in | 2196 // Special case: indirect SMI->FAST transition (cf. comment in |
| 2202 // AddElementsTransition()). | 2197 // AddElementsTransition()). |
| 2203 if (original_map->elements_kind() == FAST_SMI_ONLY_ELEMENTS && | 2198 if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS && |
| 2204 elements_kind == FAST_ELEMENTS) { | 2199 elements_kind == FAST_ELEMENTS) { |
| 2205 Map* double_map = LookupElementsTransitionMap( | 2200 Map* double_map = this->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, |
| 2206 original_map, | 2201 safe_to_add_transition); |
| 2207 FAST_DOUBLE_ELEMENTS, | |
| 2208 sentinel_name, | |
| 2209 safe_to_add_transition); | |
| 2210 if (double_map == NULL) return double_map; | 2202 if (double_map == NULL) return double_map; |
| 2211 return LookupElementsTransitionMap(double_map, | 2203 return double_map->LookupElementsTransitionMap(FAST_ELEMENTS, |
| 2212 FAST_ELEMENTS, | 2204 safe_to_add_transition); |
| 2213 sentinel_name, | |
| 2214 safe_to_add_transition); | |
| 2215 } | 2205 } |
| 2216 Object* descriptor_contents = GetDescriptorContents( | 2206 Object* descriptor_contents = GetDescriptorContents( |
| 2217 original_map, sentinel_name, safe_to_add_transition); | 2207 elements_transition_sentinel_name(), safe_to_add_transition); |
| 2218 if (descriptor_contents != NULL) { | 2208 if (descriptor_contents != NULL) { |
| 2219 Map* maybe_transition_map = | 2209 Map* maybe_transition_map = |
| 2220 GetElementsTransitionMapFromDescriptor(descriptor_contents, | 2210 GetElementsTransitionMapFromDescriptor(descriptor_contents, |
| 2221 elements_kind); | 2211 elements_kind); |
| 2222 ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap()); | 2212 ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap()); |
| 2223 return maybe_transition_map; | 2213 return maybe_transition_map; |
| 2224 } | 2214 } |
| 2225 return NULL; | 2215 return NULL; |
| 2226 } | 2216 } |
| 2227 | 2217 |
| 2228 | 2218 |
| 2229 // Adds an entry to |original_map|'s descriptor array for a transition to | 2219 MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind, |
| 2230 // |transitioned_map| when its elements_kind is changed to |elements_kind|, | 2220 Map* transitioned_map) { |
| 2231 // using |sentinel_name| as key for the entry. | |
| 2232 static MaybeObject* AddElementsTransition(Map* original_map, | |
| 2233 ElementsKind elements_kind, | |
| 2234 Map* transitioned_map, | |
| 2235 String* sentinel_name) { | |
| 2236 // The map transition graph should be a tree, therefore the transition | 2221 // The map transition graph should be a tree, therefore the transition |
| 2237 // from SMI to FAST elements is not done directly, but by going through | 2222 // from SMI to FAST elements is not done directly, but by going through |
| 2238 // DOUBLE elements first. | 2223 // DOUBLE elements first. |
| 2239 if (original_map->elements_kind() == FAST_SMI_ONLY_ELEMENTS && | 2224 if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS && |
| 2240 elements_kind == FAST_ELEMENTS) { | 2225 elements_kind == FAST_ELEMENTS) { |
| 2241 bool safe_to_add = true; | 2226 bool safe_to_add = true; |
| 2242 Map* double_map = LookupElementsTransitionMap( | 2227 Map* double_map = this->LookupElementsTransitionMap( |
| 2243 original_map, FAST_DOUBLE_ELEMENTS, sentinel_name, &safe_to_add); | 2228 FAST_DOUBLE_ELEMENTS, &safe_to_add); |
| 2244 // This method is only called when safe_to_add_transition has been found | 2229 // This method is only called when safe_to_add_transition has been found |
| 2245 // to be true earlier. | 2230 // to be true earlier. |
| 2246 ASSERT(safe_to_add); | 2231 ASSERT(safe_to_add); |
| 2247 | 2232 |
| 2248 if (double_map == NULL) { | 2233 if (double_map == NULL) { |
| 2249 MaybeObject* maybe_map = original_map->CopyDropTransitions(); | 2234 MaybeObject* maybe_map = this->CopyDropTransitions(); |
| 2250 if (!maybe_map->To(&double_map)) return maybe_map; | 2235 if (!maybe_map->To(&double_map)) return maybe_map; |
| 2251 double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS); | 2236 double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS); |
| 2252 MaybeObject* maybe_double_transition = AddElementsTransition( | 2237 MaybeObject* maybe_double_transition = this->AddElementsTransition( |
| 2253 original_map, FAST_DOUBLE_ELEMENTS, double_map, sentinel_name); | 2238 FAST_DOUBLE_ELEMENTS, double_map); |
| 2254 if (maybe_double_transition->IsFailure()) return maybe_double_transition; | 2239 if (maybe_double_transition->IsFailure()) return maybe_double_transition; |
| 2255 } | 2240 } |
| 2256 return AddElementsTransition( | 2241 return double_map->AddElementsTransition(FAST_ELEMENTS, transitioned_map); |
| 2257 double_map, FAST_ELEMENTS, transitioned_map, sentinel_name); | |
| 2258 } | 2242 } |
| 2259 | 2243 |
| 2260 DescriptorArray* descriptors = original_map->instance_descriptors(); | |
| 2261 bool safe_to_add_transition = true; | 2244 bool safe_to_add_transition = true; |
| 2262 Object* descriptor_contents = GetDescriptorContents( | 2245 Object* descriptor_contents = GetDescriptorContents( |
| 2263 original_map, sentinel_name, &safe_to_add_transition); | 2246 elements_transition_sentinel_name(), &safe_to_add_transition); |
| 2264 // This method is only called when safe_to_add_transition has been found | 2247 // This method is only called when safe_to_add_transition has been found |
| 2265 // to be true earlier. | 2248 // to be true earlier. |
| 2266 ASSERT(safe_to_add_transition); | 2249 ASSERT(safe_to_add_transition); |
| 2267 MaybeObject* maybe_new_contents = | 2250 MaybeObject* maybe_new_contents = |
| 2268 AddElementsTransitionMapToDescriptor(descriptor_contents, | 2251 AddElementsTransitionMapToDescriptor(descriptor_contents, |
| 2269 transitioned_map); | 2252 transitioned_map); |
| 2270 Object* new_contents; | 2253 Object* new_contents; |
| 2271 if (!maybe_new_contents->ToObject(&new_contents)) { | 2254 if (!maybe_new_contents->ToObject(&new_contents)) { |
| 2272 return maybe_new_contents; | 2255 return maybe_new_contents; |
| 2273 } | 2256 } |
| 2274 | 2257 |
| 2275 ElementsTransitionDescriptor desc(sentinel_name, new_contents); | 2258 ElementsTransitionDescriptor desc(elements_transition_sentinel_name(), |
| 2259 new_contents); |
| 2276 Object* new_descriptors; | 2260 Object* new_descriptors; |
| 2277 MaybeObject* maybe_new_descriptors = | 2261 MaybeObject* maybe_new_descriptors = |
| 2278 descriptors->CopyInsert(&desc, KEEP_TRANSITIONS); | 2262 instance_descriptors()->CopyInsert(&desc, KEEP_TRANSITIONS); |
| 2279 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { | 2263 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { |
| 2280 return maybe_new_descriptors; | 2264 return maybe_new_descriptors; |
| 2281 } | 2265 } |
| 2282 descriptors = DescriptorArray::cast(new_descriptors); | 2266 set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
| 2283 original_map->set_instance_descriptors(descriptors); | 2267 return this; |
| 2284 return original_map; | |
| 2285 } | 2268 } |
| 2286 | 2269 |
| 2287 | 2270 |
| 2288 MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind to_kind) { | 2271 MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind to_kind) { |
| 2289 Heap* current_heap = GetHeap(); | |
| 2290 Map* current_map = map(); | 2272 Map* current_map = map(); |
| 2291 ElementsKind from_kind = current_map->elements_kind(); | 2273 ElementsKind from_kind = current_map->elements_kind(); |
| 2292 String* elements_transition_sentinel_name = current_heap->empty_symbol(); | |
| 2293 | 2274 |
| 2294 if (from_kind == to_kind) return current_map; | 2275 if (from_kind == to_kind) return current_map; |
| 2295 | 2276 |
| 2296 // Only objects with FastProperties can have DescriptorArrays and can track | 2277 // Only objects with FastProperties can have DescriptorArrays and can track |
| 2297 // element-related maps. Also don't add descriptors to maps that are shared. | 2278 // element-related maps. Also don't add descriptors to maps that are shared. |
| 2298 bool safe_to_add_transition = HasFastProperties() && | 2279 bool safe_to_add_transition = HasFastProperties() && |
| 2299 !current_map->IsUndefined() && | 2280 !current_map->IsUndefined() && |
| 2300 !current_map->is_shared(); | 2281 !current_map->is_shared(); |
| 2301 | 2282 |
| 2302 // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps caused by objects | 2283 // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps caused by objects |
| 2303 // with elements that switch back and forth between dictionary and fast | 2284 // with elements that switch back and forth between dictionary and fast |
| 2304 // element mode. | 2285 // element mode. |
| 2305 if (from_kind == DICTIONARY_ELEMENTS && to_kind == FAST_ELEMENTS) { | 2286 if (from_kind == DICTIONARY_ELEMENTS && to_kind == FAST_ELEMENTS) { |
| 2306 safe_to_add_transition = false; | 2287 safe_to_add_transition = false; |
| 2307 } | 2288 } |
| 2308 | 2289 |
| 2309 if (safe_to_add_transition) { | 2290 if (safe_to_add_transition) { |
| 2310 // It's only safe to manipulate the descriptor array if it would be | 2291 // It's only safe to manipulate the descriptor array if it would be |
| 2311 // safe to add a transition. | 2292 // safe to add a transition. |
| 2312 Map* maybe_transition_map = LookupElementsTransitionMap( | 2293 Map* maybe_transition_map = current_map->LookupElementsTransitionMap( |
| 2313 current_map, to_kind, elements_transition_sentinel_name, | 2294 to_kind, &safe_to_add_transition); |
| 2314 &safe_to_add_transition); | |
| 2315 if (maybe_transition_map != NULL) { | 2295 if (maybe_transition_map != NULL) { |
| 2316 return maybe_transition_map; | 2296 return maybe_transition_map; |
| 2317 } | 2297 } |
| 2318 } | 2298 } |
| 2319 | 2299 |
| 2320 Map* new_map = NULL; | 2300 Map* new_map = NULL; |
| 2321 | 2301 |
| 2322 // No transition to an existing map for the given ElementsKind. Make a new | 2302 // No transition to an existing map for the given ElementsKind. Make a new |
| 2323 // one. | 2303 // one. |
| 2324 { MaybeObject* maybe_map = current_map->CopyDropTransitions(); | 2304 { MaybeObject* maybe_map = current_map->CopyDropTransitions(); |
| 2325 if (!maybe_map->To(&new_map)) return maybe_map; | 2305 if (!maybe_map->To(&new_map)) return maybe_map; |
| 2326 } | 2306 } |
| 2327 | 2307 |
| 2328 new_map->set_elements_kind(to_kind); | 2308 new_map->set_elements_kind(to_kind); |
| 2329 | 2309 |
| 2330 // Only remember the map transition if the object's map is NOT equal to the | 2310 // Only remember the map transition if the object's map is NOT equal to the |
| 2331 // global object_function's map and there is not an already existing | 2311 // global object_function's map and there is not an already existing |
| 2332 // non-matching element transition. | 2312 // non-matching element transition. |
| 2333 bool allow_map_transition = safe_to_add_transition && | 2313 bool allow_map_transition = safe_to_add_transition && |
| 2334 (GetIsolate()->context()->global_context()->object_function()->map() != | 2314 (GetIsolate()->context()->global_context()->object_function()->map() != |
| 2335 map()); | 2315 map()); |
| 2336 if (allow_map_transition) { | 2316 if (allow_map_transition) { |
| 2337 MaybeObject* maybe_transition = AddElementsTransition( | 2317 MaybeObject* maybe_transition = |
| 2338 current_map, to_kind, new_map, elements_transition_sentinel_name); | 2318 current_map->AddElementsTransition(to_kind, new_map); |
| 2339 if (maybe_transition->IsFailure()) return maybe_transition; | 2319 if (maybe_transition->IsFailure()) return maybe_transition; |
| 2340 } | 2320 } |
| 2341 return new_map; | 2321 return new_map; |
| 2342 } | 2322 } |
| 2343 | 2323 |
| 2344 | 2324 |
| 2345 void JSObject::LocalLookupRealNamedProperty(String* name, | 2325 void JSObject::LocalLookupRealNamedProperty(String* name, |
| 2346 LookupResult* result) { | 2326 LookupResult* result) { |
| 2347 if (IsJSGlobalProxy()) { | 2327 if (IsJSGlobalProxy()) { |
| 2348 Object* proto = GetPrototype(); | 2328 Object* proto = GetPrototype(); |
| (...skipping 9911 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12260 if (break_point_objects()->IsUndefined()) return 0; | 12240 if (break_point_objects()->IsUndefined()) return 0; |
| 12261 // Single break point. | 12241 // Single break point. |
| 12262 if (!break_point_objects()->IsFixedArray()) return 1; | 12242 if (!break_point_objects()->IsFixedArray()) return 1; |
| 12263 // Multiple break points. | 12243 // Multiple break points. |
| 12264 return FixedArray::cast(break_point_objects())->length(); | 12244 return FixedArray::cast(break_point_objects())->length(); |
| 12265 } | 12245 } |
| 12266 #endif // ENABLE_DEBUGGER_SUPPORT | 12246 #endif // ENABLE_DEBUGGER_SUPPORT |
| 12267 | 12247 |
| 12268 | 12248 |
| 12269 } } // namespace v8::internal | 12249 } } // namespace v8::internal |
| OLD | NEW |