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 |