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 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
621 return result->holder()->GetPropertyWithCallback( | 621 return result->holder()->GetPropertyWithCallback( |
622 receiver, result->GetCallbackObject(), name); | 622 receiver, result->GetCallbackObject(), name); |
623 case HANDLER: | 623 case HANDLER: |
624 return result->proxy()->GetPropertyWithHandler(receiver, name); | 624 return result->proxy()->GetPropertyWithHandler(receiver, name); |
625 case INTERCEPTOR: { | 625 case INTERCEPTOR: { |
626 JSObject* recvr = JSObject::cast(receiver); | 626 JSObject* recvr = JSObject::cast(receiver); |
627 return result->holder()->GetPropertyWithInterceptor( | 627 return result->holder()->GetPropertyWithInterceptor( |
628 recvr, name, attributes); | 628 recvr, name, attributes); |
629 } | 629 } |
630 case MAP_TRANSITION: | 630 case MAP_TRANSITION: |
631 case ELEMENTS_TRANSITION: | |
632 case CONSTANT_TRANSITION: | 631 case CONSTANT_TRANSITION: |
633 case NULL_DESCRIPTOR: | 632 case NULL_DESCRIPTOR: |
634 break; | 633 break; |
635 } | 634 } |
636 UNREACHABLE(); | 635 UNREACHABLE(); |
637 return NULL; | 636 return NULL; |
638 } | 637 } |
639 | 638 |
640 | 639 |
641 MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { | 640 MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { |
(...skipping 902 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1544 } | 1543 } |
1545 } | 1544 } |
1546 | 1545 |
1547 // Only allow map transition if the object isn't the global object and there | 1546 // Only allow map transition if the object isn't the global object and there |
1548 // is not a transition for the name, or there's a transition for the name but | 1547 // is not a transition for the name, or there's a transition for the name but |
1549 // it's unrelated to properties. | 1548 // it's unrelated to properties. |
1550 int descriptor_index = old_descriptors->Search(name); | 1549 int descriptor_index = old_descriptors->Search(name); |
1551 | 1550 |
1552 // Element transitions are stored in the descriptor for property "", which is | 1551 // Element transitions are stored in the descriptor for property "", which is |
1553 // not a identifier and should have forced a switch to slow properties above. | 1552 // not a identifier and should have forced a switch to slow properties above. |
1554 ASSERT(descriptor_index == DescriptorArray::kNotFound || | 1553 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound; |
1555 old_descriptors->GetType(descriptor_index) != ELEMENTS_TRANSITION); | |
1556 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound || | |
1557 old_descriptors->GetType(descriptor_index) == ELEMENTS_TRANSITION; | |
1558 bool allow_map_transition = | 1554 bool allow_map_transition = |
1559 can_insert_transition && | 1555 can_insert_transition && |
1560 (isolate->context()->global_context()->object_function()->map() != map()); | 1556 (isolate->context()->global_context()->object_function()->map() != map()); |
1561 | 1557 |
1562 ASSERT(index < map()->inobject_properties() || | 1558 ASSERT(index < map()->inobject_properties() || |
1563 (index - map()->inobject_properties()) < properties()->length() || | 1559 (index - map()->inobject_properties()) < properties()->length() || |
1564 map()->unused_property_fields() == 0); | 1560 map()->unused_property_fields() == 0); |
1565 // Allocate a new map for the object. | 1561 // Allocate a new map for the object. |
1566 Object* r; | 1562 Object* r; |
1567 { MaybeObject* maybe_r = map()->CopyDropDescriptors(); | 1563 { MaybeObject* maybe_r = map()->CopyDropDescriptors(); |
1568 if (!maybe_r->ToObject(&r)) return maybe_r; | 1564 if (!maybe_r->ToObject(&r)) return maybe_r; |
1569 } | 1565 } |
1570 Map* new_map = Map::cast(r); | 1566 Map* new_map = Map::cast(r); |
1571 if (allow_map_transition) { | 1567 if (allow_map_transition) { |
1572 // Allocate new instance descriptors for the old map with map transition. | 1568 // Allocate new instance descriptors for the old map with map transition. |
1573 MapTransitionDescriptor d(name, Map::cast(new_map), attributes); | 1569 MapTransitionDescriptor d(name, Map::cast(new_map), attributes); |
1574 Object* r; | 1570 Object* r; |
1575 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS); | 1571 { |
danno
2012/06/01 13:49:55
nit: No need for this whitespace change.
Toon Verwaest
2012/06/04 09:17:48
Done.
| |
1572 MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS); | |
1576 if (!maybe_r->ToObject(&r)) return maybe_r; | 1573 if (!maybe_r->ToObject(&r)) return maybe_r; |
1577 } | 1574 } |
1578 old_descriptors = DescriptorArray::cast(r); | 1575 old_descriptors = DescriptorArray::cast(r); |
1579 } | 1576 } |
1580 | 1577 |
1581 if (map()->unused_property_fields() == 0) { | 1578 if (map()->unused_property_fields() == 0) { |
1582 if (properties()->length() > MaxFastProperties()) { | 1579 if (properties()->length() > MaxFastProperties()) { |
1583 Object* obj; | 1580 Object* obj; |
1584 { MaybeObject* maybe_obj = | 1581 { MaybeObject* maybe_obj = |
1585 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | 1582 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
1586 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 1583 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
1587 } | 1584 } |
1588 return AddSlowProperty(name, value, attributes); | 1585 return AddSlowProperty(name, value, attributes); |
1589 } | 1586 } |
1590 // Make room for the new value | 1587 // Make room for the new value |
1591 Object* values; | 1588 Object* values; |
1592 { MaybeObject* maybe_values = | 1589 { MaybeObject* maybe_values = |
1593 properties()->CopySize(properties()->length() + kFieldsAdded); | 1590 properties()->CopySize(properties()->length() + kFieldsAdded); |
1594 if (!maybe_values->ToObject(&values)) return maybe_values; | 1591 if (!maybe_values->ToObject(&values)) return maybe_values; |
1595 } | 1592 } |
1596 set_properties(FixedArray::cast(values)); | 1593 set_properties(FixedArray::cast(values)); |
1597 new_map->set_unused_property_fields(kFieldsAdded - 1); | 1594 new_map->set_unused_property_fields(kFieldsAdded - 1); |
1598 } else { | 1595 } else { |
1599 new_map->set_unused_property_fields(map()->unused_property_fields() - 1); | 1596 new_map->set_unused_property_fields(map()->unused_property_fields() - 1); |
1600 } | 1597 } |
1601 // We have now allocated all the necessary objects. | 1598 // We have now allocated all the necessary objects. |
1602 // All the changes can be applied at once, so they are atomic. | 1599 // All the changes can be applied at once, so they are atomic. |
1603 map()->set_instance_descriptors(old_descriptors); | 1600 if (allow_map_transition) { |
1601 map()->set_instance_descriptors(old_descriptors); | |
1602 } | |
1604 new_map->SetBackPointer(map()); | 1603 new_map->SetBackPointer(map()); |
1605 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); | 1604 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
1606 set_map(new_map); | 1605 set_map(new_map); |
1607 return FastPropertyAtPut(index, value); | 1606 return FastPropertyAtPut(index, value); |
1608 } | 1607 } |
1609 | 1608 |
1610 | 1609 |
1611 MaybeObject* JSObject::AddConstantFunctionProperty( | 1610 MaybeObject* JSObject::AddConstantFunctionProperty( |
1612 String* name, | 1611 String* name, |
1613 JSFunction* function, | 1612 JSFunction* function, |
(...skipping 585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2199 | 2198 |
2200 | 2199 |
2201 Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) { | 2200 Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) { |
2202 ElementsKind kind = elements_kind(); | 2201 ElementsKind kind = elements_kind(); |
2203 Handle<Map> transitioned_map = Handle<Map>::null(); | 2202 Handle<Map> transitioned_map = Handle<Map>::null(); |
2204 Handle<Map> current_map(this); | 2203 Handle<Map> current_map(this); |
2205 bool packed = IsFastPackedElementsKind(kind); | 2204 bool packed = IsFastPackedElementsKind(kind); |
2206 if (IsTransitionableFastElementsKind(kind)) { | 2205 if (IsTransitionableFastElementsKind(kind)) { |
2207 while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) { | 2206 while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) { |
2208 kind = GetNextMoreGeneralFastElementsKind(kind, false); | 2207 kind = GetNextMoreGeneralFastElementsKind(kind, false); |
2209 bool dummy = true; | |
2210 Handle<Map> maybe_transitioned_map = | 2208 Handle<Map> maybe_transitioned_map = |
2211 MaybeNull(current_map->LookupElementsTransitionMap(kind, &dummy)); | 2209 MaybeNull(current_map->LookupElementsTransitionMap(kind)); |
2212 if (maybe_transitioned_map.is_null()) break; | 2210 if (maybe_transitioned_map.is_null()) break; |
2213 if (ContainsMap(candidates, maybe_transitioned_map) && | 2211 if (ContainsMap(candidates, maybe_transitioned_map) && |
2214 (packed || !IsFastPackedElementsKind(kind))) { | 2212 (packed || !IsFastPackedElementsKind(kind))) { |
2215 transitioned_map = maybe_transitioned_map; | 2213 transitioned_map = maybe_transitioned_map; |
2216 if (!IsFastPackedElementsKind(kind)) packed = false; | 2214 if (!IsFastPackedElementsKind(kind)) packed = false; |
2217 } | 2215 } |
2218 current_map = maybe_transitioned_map; | 2216 current_map = maybe_transitioned_map; |
2219 } | 2217 } |
2220 } | 2218 } |
2221 return transitioned_map; | 2219 return transitioned_map; |
2222 } | 2220 } |
2223 | 2221 |
2224 | 2222 |
2225 static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents, | 2223 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) { |
2226 ElementsKind elements_kind) { | 2224 Map* current_map = map; |
2227 if (descriptor_contents->IsMap()) { | 2225 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind()); |
2228 Map* map = Map::cast(descriptor_contents); | 2226 int to_index = GetSequenceIndexFromFastElementsKind(to_kind); |
2229 if (map->elements_kind() == elements_kind) { | 2227 for (; index < to_index; ++index) { |
2230 return map; | 2228 Map* next_map = current_map->elements_transition(); |
2229 if (next_map == NULL) { | |
2230 return current_map; | |
2231 } | 2231 } |
2232 return NULL; | 2232 current_map = next_map; |
2233 } | 2233 } |
2234 | 2234 ASSERT(current_map->elements_kind() == to_kind); |
2235 FixedArray* map_array = FixedArray::cast(descriptor_contents); | 2235 return current_map; |
2236 for (int i = 0; i < map_array->length(); ++i) { | |
2237 Object* current = map_array->get(i); | |
2238 // Skip undefined slots, they are sentinels for reclaimed maps. | |
2239 if (!current->IsUndefined()) { | |
2240 Map* current_map = Map::cast(map_array->get(i)); | |
2241 if (current_map->elements_kind() == elements_kind) { | |
2242 return current_map; | |
2243 } | |
2244 } | |
2245 } | |
2246 | |
2247 return NULL; | |
2248 } | 2236 } |
2249 | 2237 |
2250 | 2238 |
2251 static MaybeObject* AddElementsTransitionMapToDescriptor( | 2239 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) { |
2252 Object* descriptor_contents, | 2240 if (this->instance_descriptors()->MayContainTransitions() && |
2253 Map* new_map) { | 2241 IsMoreGeneralElementsKindTransition(this->elements_kind(), to_kind)) { |
2254 // Nothing was in the descriptor for an ELEMENTS_TRANSITION, | 2242 Map* to_map = FindClosestElementsTransition(this, to_kind); |
2255 // simply add the map. | 2243 if (to_map->elements_kind() == to_kind) { |
2256 if (descriptor_contents == NULL) { | 2244 return to_map; |
2257 return new_map; | |
2258 } | |
2259 | |
2260 // There was already a map in the descriptor, create a 2-element FixedArray | |
2261 // to contain the existing map plus the new one. | |
2262 FixedArray* new_array; | |
2263 Heap* heap = new_map->GetHeap(); | |
2264 if (descriptor_contents->IsMap()) { | |
2265 // Must tenure, DescriptorArray expects no new-space objects. | |
2266 MaybeObject* maybe_new_array = heap->AllocateFixedArray(2, TENURED); | |
2267 if (!maybe_new_array->To<FixedArray>(&new_array)) { | |
2268 return maybe_new_array; | |
2269 } | |
2270 new_array->set(0, descriptor_contents); | |
2271 new_array->set(1, new_map); | |
2272 return new_array; | |
2273 } | |
2274 | |
2275 // The descriptor already contained a list of maps for different ElementKinds | |
2276 // of ELEMENTS_TRANSITION, first check the existing array for an undefined | |
2277 // slot, and if that's not available, create a FixedArray to hold the existing | |
2278 // maps plus the new one and fill it in. | |
2279 FixedArray* array = FixedArray::cast(descriptor_contents); | |
2280 for (int i = 0; i < array->length(); ++i) { | |
2281 if (array->get(i)->IsUndefined()) { | |
2282 array->set(i, new_map); | |
2283 return array; | |
2284 } | |
2285 } | |
2286 | |
2287 // Must tenure, DescriptorArray expects no new-space objects. | |
2288 MaybeObject* maybe_new_array = | |
2289 heap->AllocateFixedArray(array->length() + 1, TENURED); | |
2290 if (!maybe_new_array->To<FixedArray>(&new_array)) { | |
2291 return maybe_new_array; | |
2292 } | |
2293 int i = 0; | |
2294 while (i < array->length()) { | |
2295 new_array->set(i, array->get(i)); | |
2296 ++i; | |
2297 } | |
2298 new_array->set(i, new_map); | |
2299 return new_array; | |
2300 } | |
2301 | |
2302 | |
2303 String* Map::elements_transition_sentinel_name() { | |
2304 return GetHeap()->empty_symbol(); | |
2305 } | |
2306 | |
2307 | |
2308 Object* Map::GetDescriptorContents(String* sentinel_name, | |
2309 bool* safe_to_add_transition) { | |
2310 // Get the cached index for the descriptors lookup, or find and cache it. | |
2311 DescriptorArray* descriptors = instance_descriptors(); | |
2312 DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache(); | |
2313 int index = cache->Lookup(descriptors, sentinel_name); | |
2314 if (index == DescriptorLookupCache::kAbsent) { | |
2315 index = descriptors->Search(sentinel_name); | |
2316 cache->Update(descriptors, sentinel_name, index); | |
2317 } | |
2318 // If the transition already exists, return its descriptor. | |
2319 if (index != DescriptorArray::kNotFound) { | |
2320 PropertyDetails details = descriptors->GetDetails(index); | |
2321 if (details.type() == ELEMENTS_TRANSITION) { | |
2322 return descriptors->GetValue(index); | |
2323 } else { | |
2324 if (safe_to_add_transition != NULL) { | |
2325 *safe_to_add_transition = false; | |
2326 } | |
2327 } | 2245 } |
2328 } | 2246 } |
2329 return NULL; | 2247 return NULL; |
2330 } | 2248 } |
2331 | 2249 |
2332 | 2250 |
2333 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind, | 2251 MaybeObject* Map::CreateNextElementsTransition(ElementsKind next_kind) { |
2334 bool* safe_to_add_transition) { | 2252 ASSERT(elements_transition() == NULL); |
2335 ElementsKind from_kind = elements_kind(); | 2253 ASSERT(GetSequenceIndexFromFastElementsKind(elements_kind()) == |
2336 if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) { | 2254 (GetSequenceIndexFromFastElementsKind(next_kind) - 1)); |
2337 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) { | |
2338 if (safe_to_add_transition) *safe_to_add_transition = false; | |
2339 return NULL; | |
2340 } | |
2341 ElementsKind transitioned_from_kind = | |
2342 GetNextMoreGeneralFastElementsKind(from_kind, false); | |
2343 | 2255 |
2256 Map* next_map; | |
2257 MaybeObject* maybe_next_map = this->CopyDropTransitions(true); | |
2258 if (!maybe_next_map->To(&next_map)) return maybe_next_map; | |
2344 | 2259 |
2345 // If the transition is a single step in the transition sequence, fall | 2260 next_map->set_elements_kind(next_kind); |
2346 // through to looking it up and returning it. If it requires several steps, | 2261 next_map->SetBackPointer(this); |
2347 // divide and conquer. | 2262 this->set_elements_transition(next_map); |
2348 if (transitioned_from_kind != to_kind) { | 2263 return next_map; |
2349 // If the transition is several steps in the lattice, divide and conquer. | |
2350 Map* from_map = LookupElementsTransitionMap(transitioned_from_kind, | |
2351 safe_to_add_transition); | |
2352 if (from_map == NULL) return NULL; | |
2353 return from_map->LookupElementsTransitionMap(to_kind, | |
2354 safe_to_add_transition); | |
2355 } | |
2356 } | |
2357 Object* descriptor_contents = GetDescriptorContents( | |
2358 elements_transition_sentinel_name(), safe_to_add_transition); | |
2359 if (descriptor_contents != NULL) { | |
2360 Map* maybe_transition_map = | |
2361 GetElementsTransitionMapFromDescriptor(descriptor_contents, | |
2362 to_kind); | |
2363 ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap()); | |
2364 return maybe_transition_map; | |
2365 } | |
2366 return NULL; | |
2367 } | 2264 } |
2368 | 2265 |
2369 | 2266 |
2370 MaybeObject* Map::AddElementsTransition(ElementsKind to_kind, | 2267 static MaybeObject* AddMissingElementsTransitions(Map* map, |
2371 Map* transitioned_map) { | 2268 ElementsKind to_kind) { |
2372 ElementsKind from_kind = elements_kind(); | 2269 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind()) + 1; |
2373 if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) { | 2270 int to_index = GetSequenceIndexFromFastElementsKind(to_kind); |
2374 ASSERT(IsMoreGeneralElementsKindTransition(from_kind, to_kind)); | 2271 ASSERT(index <= to_index); |
2375 ElementsKind transitioned_from_kind = | |
2376 GetNextMoreGeneralFastElementsKind(from_kind, false); | |
2377 // The map transitions graph should be a tree, therefore transitions to | |
2378 // ElementsKind that are not adjacent in the ElementsKind sequence are not | |
2379 // done directly, but instead by going through intermediate ElementsKinds | |
2380 // first. | |
2381 if (to_kind != transitioned_from_kind) { | |
2382 bool safe_to_add = true; | |
2383 Map* intermediate_map = LookupElementsTransitionMap( | |
2384 transitioned_from_kind, &safe_to_add); | |
2385 // This method is only called when safe_to_add has been found to be true | |
2386 // earlier. | |
2387 ASSERT(safe_to_add); | |
2388 | 2272 |
2389 if (intermediate_map == NULL) { | 2273 Map* current_map = map; |
2390 MaybeObject* maybe_map = CopyDropTransitions(); | 2274 |
2391 if (!maybe_map->To(&intermediate_map)) return maybe_map; | 2275 for (; index <= to_index; ++index) { |
2392 intermediate_map->set_elements_kind(transitioned_from_kind); | 2276 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index); |
2393 MaybeObject* maybe_transition = AddElementsTransition( | 2277 MaybeObject* maybe_next_map = |
2394 transitioned_from_kind, intermediate_map); | 2278 current_map->CreateNextElementsTransition(next_kind); |
2395 if (maybe_transition->IsFailure()) return maybe_transition; | 2279 if (!maybe_next_map->To(¤t_map)) return maybe_next_map; |
2396 } | |
2397 return intermediate_map->AddElementsTransition(to_kind, transitioned_map); | |
2398 } | |
2399 } | 2280 } |
2400 | 2281 |
2401 bool safe_to_add_transition = true; | 2282 ASSERT(current_map->elements_kind() == to_kind); |
2402 Object* descriptor_contents = GetDescriptorContents( | 2283 return current_map; |
2403 elements_transition_sentinel_name(), &safe_to_add_transition); | |
2404 // This method is only called when safe_to_add_transition has been found | |
2405 // to be true earlier. | |
2406 ASSERT(safe_to_add_transition); | |
2407 MaybeObject* maybe_new_contents = | |
2408 AddElementsTransitionMapToDescriptor(descriptor_contents, | |
2409 transitioned_map); | |
2410 Object* new_contents; | |
2411 if (!maybe_new_contents->ToObject(&new_contents)) { | |
2412 return maybe_new_contents; | |
2413 } | |
2414 | |
2415 ElementsTransitionDescriptor desc(elements_transition_sentinel_name(), | |
2416 new_contents); | |
2417 Object* new_descriptors; | |
2418 MaybeObject* maybe_new_descriptors = | |
2419 instance_descriptors()->CopyInsert(&desc, KEEP_TRANSITIONS); | |
2420 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { | |
2421 return maybe_new_descriptors; | |
2422 } | |
2423 set_instance_descriptors(DescriptorArray::cast(new_descriptors)); | |
2424 transitioned_map->SetBackPointer(this); | |
2425 return this; | |
2426 } | 2284 } |
2427 | 2285 |
2428 | 2286 |
2429 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object, | 2287 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object, |
2430 ElementsKind to_kind) { | 2288 ElementsKind to_kind) { |
2431 Isolate* isolate = object->GetIsolate(); | 2289 Isolate* isolate = object->GetIsolate(); |
2432 CALL_HEAP_FUNCTION(isolate, | 2290 CALL_HEAP_FUNCTION(isolate, |
2433 object->GetElementsTransitionMap(isolate, to_kind), | 2291 object->GetElementsTransitionMap(isolate, to_kind), |
2434 Map); | 2292 Map); |
2435 } | 2293 } |
2436 | 2294 |
2437 | 2295 |
2296 // If the map is using the empty descriptor array, install a new empty | |
2297 // descriptor array that will contain an element transition. | |
2298 // TODO(verwaest) Goes away once the descriptor array is immutable. | |
2299 static MaybeObject* EnsureMayContainTransitions(Map* map) { | |
2300 if (map->instance_descriptors()->MayContainTransitions()) return map; | |
2301 DescriptorArray* descriptor_array; | |
2302 MaybeObject* maybe_descriptor_array = DescriptorArray::Allocate(0, true); | |
2303 if (!maybe_descriptor_array->To(&descriptor_array)) { | |
2304 return maybe_descriptor_array; | |
2305 } | |
2306 map->set_instance_descriptors(descriptor_array); | |
2307 return map; | |
2308 } | |
2309 | |
2310 | |
2438 MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) { | 2311 MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) { |
2439 Map* current_map = map(); | 2312 Map* start_map = map(); |
2440 ElementsKind from_kind = current_map->elements_kind(); | 2313 ElementsKind from_kind = start_map->elements_kind(); |
2441 | 2314 |
2442 if (from_kind == to_kind) return current_map; | 2315 if (from_kind == to_kind) { |
2443 | 2316 return start_map; |
2444 // Only objects with FastProperties can have DescriptorArrays and can track | |
2445 // element-related maps. Also don't add descriptors to maps that are shared. | |
2446 bool safe_to_add_transition = HasFastProperties() && | |
2447 !current_map->IsUndefined() && | |
2448 !current_map->is_shared(); | |
2449 | |
2450 // Prevent long chains of DICTIONARY -> FAST_*_ELEMENTS maps caused by objects | |
2451 // with elements that switch back and forth between dictionary and fast | |
2452 // element modes. | |
2453 if (from_kind == DICTIONARY_ELEMENTS && | |
2454 IsFastElementsKind(to_kind)) { | |
2455 safe_to_add_transition = false; | |
2456 } | 2317 } |
2457 | 2318 |
2458 if (safe_to_add_transition) { | 2319 Context* global_context = GetIsolate()->context()->global_context(); |
2459 // It's only safe to manipulate the descriptor array if it would be | 2320 bool allow_store_transition = |
2460 // safe to add a transition. | 2321 // Only remember the map transition if the object's map is NOT equal to |
danno
2012/06/01 13:49:55
nit: indentation
Toon Verwaest
2012/06/04 09:17:48
Done.
| |
2461 Map* maybe_transition_map = current_map->LookupElementsTransitionMap( | 2322 // the global object_function's map and there is not an already existing |
2462 to_kind, &safe_to_add_transition); | 2323 // non-matching element transition. |
2463 if (maybe_transition_map != NULL) { | 2324 (global_context->object_function()->map() != map()) && |
2464 return maybe_transition_map; | 2325 !start_map->IsUndefined() && !start_map->is_shared() && |
2465 } | 2326 // Only store fast element maps in ascending generality. |
2327 IsTransitionableFastElementsKind(from_kind) && | |
2328 IsFastElementsKind(to_kind) && | |
2329 IsMoreGeneralElementsKindTransition(from_kind, to_kind); | |
2330 | |
2331 if (!allow_store_transition) { | |
2332 // Create a new free-floating map only if we are not allowed to store it. | |
2333 Map* new_map = NULL; | |
2334 MaybeObject* maybe_new_map = start_map->CopyDropTransitions(false); | |
2335 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | |
2336 new_map->set_elements_kind(to_kind); | |
2337 return new_map; | |
2466 } | 2338 } |
2467 | 2339 |
2468 Map* new_map = NULL; | 2340 EnsureMayContainTransitions(start_map); |
2341 Map* closest_map = FindClosestElementsTransition(start_map, to_kind); | |
2469 | 2342 |
2470 // No transition to an existing map for the given ElementsKind. Make a new | 2343 if (closest_map->elements_kind() == to_kind) { |
2471 // one. | 2344 return closest_map; |
2472 { MaybeObject* maybe_map = current_map->CopyDropTransitions(); | |
2473 if (!maybe_map->To(&new_map)) return maybe_map; | |
2474 } | 2345 } |
2475 | 2346 |
2476 new_map->set_elements_kind(to_kind); | 2347 return AddMissingElementsTransitions(closest_map, to_kind); |
2477 | |
2478 // Only remember the map transition if the object's map is NOT equal to the | |
2479 // global object_function's map and there is not an already existing | |
2480 // non-matching element transition. | |
2481 Context* global_context = GetIsolate()->context()->global_context(); | |
2482 bool allow_map_transition = safe_to_add_transition && | |
2483 (global_context->object_function()->map() != map()); | |
2484 if (allow_map_transition) { | |
2485 MaybeObject* maybe_transition = | |
2486 current_map->AddElementsTransition(to_kind, new_map); | |
2487 if (maybe_transition->IsFailure()) return maybe_transition; | |
2488 } | |
2489 return new_map; | |
2490 } | 2348 } |
2491 | 2349 |
2492 | 2350 |
2493 void JSObject::LocalLookupRealNamedProperty(String* name, | 2351 void JSObject::LocalLookupRealNamedProperty(String* name, |
2494 LookupResult* result) { | 2352 LookupResult* result) { |
2495 if (IsJSGlobalProxy()) { | 2353 if (IsJSGlobalProxy()) { |
2496 Object* proto = GetPrototype(); | 2354 Object* proto = GetPrototype(); |
2497 if (proto->IsNull()) return result->NotFound(); | 2355 if (proto->IsNull()) return result->NotFound(); |
2498 ASSERT(proto->IsJSGlobalObject()); | 2356 ASSERT(proto->IsJSGlobalObject()); |
2499 // A GlobalProxy's prototype should always be a proper JSObject. | 2357 // A GlobalProxy's prototype should always be a proper JSObject. |
(...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2998 JSFunction::cast(target_descriptors->GetValue(number)); | 2856 JSFunction::cast(target_descriptors->GetValue(number)); |
2999 if (value == function) { | 2857 if (value == function) { |
3000 set_map(target_map); | 2858 set_map(target_map); |
3001 return value; | 2859 return value; |
3002 } | 2860 } |
3003 // Otherwise, replace with a MAP_TRANSITION to a new map with a | 2861 // Otherwise, replace with a MAP_TRANSITION to a new map with a |
3004 // FIELD, even if the value is a constant function. | 2862 // FIELD, even if the value is a constant function. |
3005 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); | 2863 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
3006 } | 2864 } |
3007 case NULL_DESCRIPTOR: | 2865 case NULL_DESCRIPTOR: |
3008 case ELEMENTS_TRANSITION: | |
3009 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); | 2866 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
3010 case HANDLER: | 2867 case HANDLER: |
3011 UNREACHABLE(); | 2868 UNREACHABLE(); |
3012 return value; | 2869 return value; |
3013 } | 2870 } |
3014 UNREACHABLE(); // keep the compiler happy | 2871 UNREACHABLE(); // keep the compiler happy |
3015 return value; | 2872 return value; |
3016 } | 2873 } |
3017 | 2874 |
3018 | 2875 |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3096 // Preserve the attributes of this existing property. | 2953 // Preserve the attributes of this existing property. |
3097 attributes = result.GetAttributes(); | 2954 attributes = result.GetAttributes(); |
3098 return ConvertDescriptorToField(name, value, attributes); | 2955 return ConvertDescriptorToField(name, value, attributes); |
3099 case CALLBACKS: | 2956 case CALLBACKS: |
3100 case INTERCEPTOR: | 2957 case INTERCEPTOR: |
3101 // Override callback in clone | 2958 // Override callback in clone |
3102 return ConvertDescriptorToField(name, value, attributes); | 2959 return ConvertDescriptorToField(name, value, attributes); |
3103 case CONSTANT_TRANSITION: | 2960 case CONSTANT_TRANSITION: |
3104 // Replace with a MAP_TRANSITION to a new map with a FIELD, even | 2961 // Replace with a MAP_TRANSITION to a new map with a FIELD, even |
3105 // if the value is a function. | 2962 // if the value is a function. |
3106 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); | |
3107 case NULL_DESCRIPTOR: | 2963 case NULL_DESCRIPTOR: |
3108 case ELEMENTS_TRANSITION: | |
3109 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); | 2964 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
3110 case HANDLER: | 2965 case HANDLER: |
3111 UNREACHABLE(); | 2966 UNREACHABLE(); |
3112 } | 2967 } |
3113 UNREACHABLE(); // keep the compiler happy | 2968 UNREACHABLE(); // keep the compiler happy |
3114 return value; | 2969 return value; |
3115 } | 2970 } |
3116 | 2971 |
3117 | 2972 |
3118 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor( | 2973 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor( |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3389 } | 3244 } |
3390 MaybeObject* maybe_dictionary = | 3245 MaybeObject* maybe_dictionary = |
3391 dictionary->Add(descs->GetKey(i), value, details); | 3246 dictionary->Add(descs->GetKey(i), value, details); |
3392 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | 3247 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; |
3393 break; | 3248 break; |
3394 } | 3249 } |
3395 case MAP_TRANSITION: | 3250 case MAP_TRANSITION: |
3396 case CONSTANT_TRANSITION: | 3251 case CONSTANT_TRANSITION: |
3397 case NULL_DESCRIPTOR: | 3252 case NULL_DESCRIPTOR: |
3398 case INTERCEPTOR: | 3253 case INTERCEPTOR: |
3399 case ELEMENTS_TRANSITION: | |
3400 break; | 3254 break; |
3401 case HANDLER: | 3255 case HANDLER: |
3402 case NORMAL: | 3256 case NORMAL: |
3403 UNREACHABLE(); | 3257 UNREACHABLE(); |
3404 break; | 3258 break; |
3405 } | 3259 } |
3406 } | 3260 } |
3407 | 3261 |
3408 Heap* current_heap = GetHeap(); | 3262 Heap* current_heap = GetHeap(); |
3409 | 3263 |
(...skipping 765 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4175 { MaybeObject* maybe = NormalizeElements(); | 4029 { MaybeObject* maybe = NormalizeElements(); |
4176 if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe; | 4030 if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe; |
4177 } | 4031 } |
4178 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); | 4032 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); |
4179 // Make sure that we never go back to fast case. | 4033 // Make sure that we never go back to fast case. |
4180 dictionary->set_requires_slow_elements(); | 4034 dictionary->set_requires_slow_elements(); |
4181 | 4035 |
4182 // Do a map transition, other objects with this map may still | 4036 // Do a map transition, other objects with this map may still |
4183 // be extensible. | 4037 // be extensible. |
4184 Map* new_map; | 4038 Map* new_map; |
4185 { MaybeObject* maybe = map()->CopyDropTransitions(); | 4039 { MaybeObject* maybe = map()->CopyDropTransitions(false); |
danno
2012/06/01 13:49:55
This should be an enum rather than a bool, it's re
Toon Verwaest
2012/06/04 09:17:48
Done.
| |
4186 if (!maybe->To<Map>(&new_map)) return maybe; | 4040 if (!maybe->To<Map>(&new_map)) return maybe; |
4187 } | 4041 } |
4188 new_map->set_is_extensible(false); | 4042 new_map->set_is_extensible(false); |
4189 set_map(new_map); | 4043 set_map(new_map); |
4190 ASSERT(!map()->is_extensible()); | 4044 ASSERT(!map()->is_extensible()); |
4191 return new_map; | 4045 return new_map; |
4192 } | 4046 } |
4193 | 4047 |
4194 | 4048 |
4195 // Tests for the fast common case for property enumeration: | 4049 // Tests for the fast common case for property enumeration: |
(...skipping 759 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4955 Map::cast(result)->set_inobject_properties(inobject_properties()); | 4809 Map::cast(result)->set_inobject_properties(inobject_properties()); |
4956 Map::cast(result)->set_unused_property_fields(unused_property_fields()); | 4810 Map::cast(result)->set_unused_property_fields(unused_property_fields()); |
4957 | 4811 |
4958 // If the map has pre-allocated properties always start out with a descriptor | 4812 // If the map has pre-allocated properties always start out with a descriptor |
4959 // array describing these properties. | 4813 // array describing these properties. |
4960 if (pre_allocated_property_fields() > 0) { | 4814 if (pre_allocated_property_fields() > 0) { |
4961 ASSERT(constructor()->IsJSFunction()); | 4815 ASSERT(constructor()->IsJSFunction()); |
4962 JSFunction* ctor = JSFunction::cast(constructor()); | 4816 JSFunction* ctor = JSFunction::cast(constructor()); |
4963 Object* descriptors; | 4817 Object* descriptors; |
4964 { MaybeObject* maybe_descriptors = | 4818 { MaybeObject* maybe_descriptors = |
4965 ctor->initial_map()->instance_descriptors()->RemoveTransitions(); | 4819 ctor->initial_map()->instance_descriptors()->RemoveTransitions(false); |
4966 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors; | 4820 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors; |
4967 } | 4821 } |
4968 Map::cast(result)->set_instance_descriptors( | 4822 Map::cast(result)->set_instance_descriptors( |
4969 DescriptorArray::cast(descriptors)); | 4823 DescriptorArray::cast(descriptors)); |
4970 Map::cast(result)->set_pre_allocated_property_fields( | 4824 Map::cast(result)->set_pre_allocated_property_fields( |
4971 pre_allocated_property_fields()); | 4825 pre_allocated_property_fields()); |
4972 } | 4826 } |
4973 Map::cast(result)->set_bit_field(bit_field()); | 4827 Map::cast(result)->set_bit_field(bit_field()); |
4974 Map::cast(result)->set_bit_field2(bit_field2()); | 4828 Map::cast(result)->set_bit_field2(bit_field2()); |
4975 Map::cast(result)->set_bit_field3(bit_field3()); | 4829 Map::cast(result)->set_bit_field3(bit_field3()); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5008 #ifdef DEBUG | 4862 #ifdef DEBUG |
5009 if (FLAG_verify_heap && Map::cast(result)->is_shared()) { | 4863 if (FLAG_verify_heap && Map::cast(result)->is_shared()) { |
5010 Map::cast(result)->SharedMapVerify(); | 4864 Map::cast(result)->SharedMapVerify(); |
5011 } | 4865 } |
5012 #endif | 4866 #endif |
5013 | 4867 |
5014 return result; | 4868 return result; |
5015 } | 4869 } |
5016 | 4870 |
5017 | 4871 |
5018 MaybeObject* Map::CopyDropTransitions() { | 4872 MaybeObject* Map::CopyDropTransitions(bool mutable_transitions) { |
5019 Object* new_map; | 4873 Object* new_map; |
5020 { MaybeObject* maybe_new_map = CopyDropDescriptors(); | 4874 { MaybeObject* maybe_new_map = CopyDropDescriptors(); |
5021 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; | 4875 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; |
5022 } | 4876 } |
5023 Object* descriptors; | 4877 Object* descriptors; |
5024 { MaybeObject* maybe_descriptors = | 4878 { MaybeObject* maybe_descriptors = |
5025 instance_descriptors()->RemoveTransitions(); | 4879 instance_descriptors()->RemoveTransitions(mutable_transitions); |
5026 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors; | 4880 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors; |
5027 } | 4881 } |
5028 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors)); | 4882 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors)); |
5029 return new_map; | 4883 return new_map; |
5030 } | 4884 } |
5031 | 4885 |
5032 void Map::UpdateCodeCache(Handle<Map> map, | 4886 void Map::UpdateCodeCache(Handle<Map> map, |
5033 Handle<String> name, | 4887 Handle<String> name, |
5034 Handle<Code> code) { | 4888 Handle<Code> code) { |
5035 Isolate* isolate = map->GetIsolate(); | 4889 Isolate* isolate = map->GetIsolate(); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5081 | 4935 |
5082 // An iterator over all map transitions in an descriptor array, reusing the map | 4936 // An iterator over all map transitions in an descriptor array, reusing the map |
5083 // field of the contens array while it is running. | 4937 // field of the contens array while it is running. |
5084 class IntrusiveMapTransitionIterator { | 4938 class IntrusiveMapTransitionIterator { |
5085 public: | 4939 public: |
5086 explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array) | 4940 explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array) |
5087 : descriptor_array_(descriptor_array) { } | 4941 : descriptor_array_(descriptor_array) { } |
5088 | 4942 |
5089 void Start() { | 4943 void Start() { |
5090 ASSERT(!IsIterating()); | 4944 ASSERT(!IsIterating()); |
5091 if (HasDescriptors()) *DescriptorArrayHeader() = Smi::FromInt(0); | 4945 if (descriptor_array_->MayContainTransitions()) |
danno
2012/06/01 13:49:55
This is confusing. What does descriptor iteration
Toon Verwaest
2012/06/04 09:17:48
As discussed offline, won't change since it is act
| |
4946 *DescriptorArrayHeader() = Smi::FromInt(0); | |
5092 } | 4947 } |
5093 | 4948 |
5094 bool IsIterating() { | 4949 bool IsIterating() { |
5095 return HasDescriptors() && (*DescriptorArrayHeader())->IsSmi(); | 4950 return descriptor_array_->MayContainTransitions() && |
4951 (*DescriptorArrayHeader())->IsSmi(); | |
5096 } | 4952 } |
5097 | 4953 |
5098 Map* Next() { | 4954 Map* Next() { |
5099 ASSERT(IsIterating()); | 4955 ASSERT(IsIterating()); |
5100 // Attention, tricky index manipulation ahead: Two consecutive indices are | 4956 // Attention, tricky index manipulation ahead: Two consecutive indices are |
5101 // assigned to each descriptor. Most descriptors directly advance to the | 4957 // assigned to each descriptor. Most descriptors directly advance to the |
5102 // next descriptor by adding 2 to the index. The exceptions are the | 4958 // next descriptor by adding 2 to the index. The exceptions are the |
5103 // CALLBACKS entries: An even index means we look at its getter, and an odd | 4959 // CALLBACKS entries: An even index means we look at its getter, and an odd |
5104 // index means we look at its setter. | 4960 // index means we look at its setter. |
5105 int raw_index = Smi::cast(*DescriptorArrayHeader())->value(); | 4961 int raw_index = Smi::cast(*DescriptorArrayHeader())->value(); |
5106 int index = raw_index / 2; | 4962 int index = raw_index / 2; |
5107 int number_of_descriptors = descriptor_array_->number_of_descriptors(); | 4963 int number_of_descriptors = descriptor_array_->number_of_descriptors(); |
5108 while (index < number_of_descriptors) { | 4964 while (index < number_of_descriptors) { |
5109 PropertyDetails details(descriptor_array_->GetDetails(index)); | 4965 PropertyDetails details(descriptor_array_->GetDetails(index)); |
5110 switch (details.type()) { | 4966 switch (details.type()) { |
5111 case MAP_TRANSITION: | 4967 case MAP_TRANSITION: |
5112 case CONSTANT_TRANSITION: | 4968 case CONSTANT_TRANSITION: |
5113 case ELEMENTS_TRANSITION: | |
5114 // We definitely have a map transition. | 4969 // We definitely have a map transition. |
5115 *DescriptorArrayHeader() = Smi::FromInt(raw_index + 2); | 4970 *DescriptorArrayHeader() = Smi::FromInt(raw_index + 2); |
5116 return static_cast<Map*>(descriptor_array_->GetValue(index)); | 4971 return static_cast<Map*>(descriptor_array_->GetValue(index)); |
5117 case CALLBACKS: { | 4972 case CALLBACKS: { |
5118 // We might have a map transition in a getter or in a setter. | 4973 // We might have a map transition in a getter or in a setter. |
5119 AccessorPair* accessors = | 4974 AccessorPair* accessors = |
5120 static_cast<AccessorPair*>(descriptor_array_->GetValue(index)); | 4975 static_cast<AccessorPair*>(descriptor_array_->GetValue(index)); |
5121 Object* accessor; | 4976 Object* accessor; |
5122 if ((raw_index & 1) == 0) { | 4977 if ((raw_index & 1) == 0) { |
5123 accessor = accessors->setter(); | 4978 accessor = accessors->setter(); |
(...skipping 13 matching lines...) Expand all Loading... | |
5137 case CONSTANT_FUNCTION: | 4992 case CONSTANT_FUNCTION: |
5138 case HANDLER: | 4993 case HANDLER: |
5139 case INTERCEPTOR: | 4994 case INTERCEPTOR: |
5140 case NULL_DESCRIPTOR: | 4995 case NULL_DESCRIPTOR: |
5141 // We definitely have no map transition. | 4996 // We definitely have no map transition. |
5142 raw_index += 2; | 4997 raw_index += 2; |
5143 ++index; | 4998 ++index; |
5144 break; | 4999 break; |
5145 } | 5000 } |
5146 } | 5001 } |
5002 if (index == descriptor_array_->number_of_descriptors()) { | |
5003 Map* elements_transition = descriptor_array_->elements_transition(); | |
5004 if (elements_transition != NULL) { | |
5005 *DescriptorArrayHeader() = Smi::FromInt(index + 1); | |
5006 return elements_transition; | |
5007 } | |
5008 } | |
5147 *DescriptorArrayHeader() = descriptor_array_->GetHeap()->fixed_array_map(); | 5009 *DescriptorArrayHeader() = descriptor_array_->GetHeap()->fixed_array_map(); |
5148 return NULL; | 5010 return NULL; |
5149 } | 5011 } |
5150 | 5012 |
5151 private: | 5013 private: |
5152 bool HasDescriptors() { | |
5153 return descriptor_array_->length() > DescriptorArray::kFirstIndex; | |
5154 } | |
5155 | |
5156 Object** DescriptorArrayHeader() { | 5014 Object** DescriptorArrayHeader() { |
5157 return HeapObject::RawField(descriptor_array_, DescriptorArray::kMapOffset); | 5015 return HeapObject::RawField(descriptor_array_, DescriptorArray::kMapOffset); |
5158 } | 5016 } |
5159 | 5017 |
5160 DescriptorArray* descriptor_array_; | 5018 DescriptorArray* descriptor_array_; |
5161 }; | 5019 }; |
5162 | 5020 |
5163 | 5021 |
5164 // An iterator over all prototype transitions, reusing the map field of the | 5022 // An iterator over all prototype transitions, reusing the map field of the |
5165 // underlying array while it is running. | 5023 // underlying array while it is running. |
(...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5834 bool FixedArray::IsEqualTo(FixedArray* other) { | 5692 bool FixedArray::IsEqualTo(FixedArray* other) { |
5835 if (length() != other->length()) return false; | 5693 if (length() != other->length()) return false; |
5836 for (int i = 0 ; i < length(); ++i) { | 5694 for (int i = 0 ; i < length(); ++i) { |
5837 if (get(i) != other->get(i)) return false; | 5695 if (get(i) != other->get(i)) return false; |
5838 } | 5696 } |
5839 return true; | 5697 return true; |
5840 } | 5698 } |
5841 #endif | 5699 #endif |
5842 | 5700 |
5843 | 5701 |
5844 MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) { | 5702 MaybeObject* DescriptorArray::Allocate(int number_of_descriptors, |
5703 bool mutable_transition) { | |
5845 Heap* heap = Isolate::Current()->heap(); | 5704 Heap* heap = Isolate::Current()->heap(); |
5846 if (number_of_descriptors == 0) { | 5705 if (number_of_descriptors == 0 && !mutable_transition) { |
5847 return heap->empty_descriptor_array(); | 5706 return heap->empty_descriptor_array(); |
5848 } | 5707 } |
5849 // Allocate the array of keys. | 5708 // Allocate the array of keys. |
5850 Object* array; | 5709 Object* array; |
5851 { MaybeObject* maybe_array = | 5710 { MaybeObject* maybe_array = |
5852 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors)); | 5711 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors)); |
5853 if (!maybe_array->ToObject(&array)) return maybe_array; | 5712 if (!maybe_array->ToObject(&array)) return maybe_array; |
5854 } | 5713 } |
5855 // Do not use DescriptorArray::cast on incomplete object. | 5714 // Do not use DescriptorArray::cast on incomplete object. |
5856 FixedArray* result = FixedArray::cast(array); | 5715 FixedArray* result = FixedArray::cast(array); |
5857 | 5716 |
5858 result->set(kBitField3StorageIndex, Smi::FromInt(0)); | 5717 result->set(kBitField3StorageIndex, Smi::FromInt(0)); |
5718 result->set(kTransitionsIndex, Smi::FromInt(0)); | |
5859 result->set(kEnumerationIndexIndex, | 5719 result->set(kEnumerationIndexIndex, |
5860 Smi::FromInt(PropertyDetails::kInitialIndex)); | 5720 Smi::FromInt(PropertyDetails::kInitialIndex)); |
5861 return result; | 5721 return result; |
5862 } | 5722 } |
5863 | 5723 |
5864 | 5724 |
5865 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, | 5725 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, |
5866 FixedArray* new_cache, | 5726 FixedArray* new_cache, |
5867 Object* new_index_cache) { | 5727 Object* new_index_cache) { |
5868 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength); | 5728 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5952 // We are replacing an existing descriptor. We keep the enumeration index | 5812 // We are replacing an existing descriptor. We keep the enumeration index |
5953 // of a visible property. | 5813 // of a visible property. |
5954 keep_enumeration_index = true; | 5814 keep_enumeration_index = true; |
5955 } else if (remove_transitions) { | 5815 } else if (remove_transitions) { |
5956 // Replaced descriptor has been counted as removed if it is a transition | 5816 // Replaced descriptor has been counted as removed if it is a transition |
5957 // that will be replaced. Adjust count in this case. | 5817 // that will be replaced. Adjust count in this case. |
5958 ++new_size; | 5818 ++new_size; |
5959 } | 5819 } |
5960 | 5820 |
5961 DescriptorArray* new_descriptors; | 5821 DescriptorArray* new_descriptors; |
5962 { MaybeObject* maybe_result = Allocate(new_size); | 5822 { MaybeObject* maybe_result = Allocate(new_size, !remove_transitions); |
5963 if (!maybe_result->To(&new_descriptors)) return maybe_result; | 5823 if (!maybe_result->To(&new_descriptors)) return maybe_result; |
5964 } | 5824 } |
5965 | 5825 |
5966 DescriptorArray::WhitenessWitness witness(new_descriptors); | 5826 DescriptorArray::WhitenessWitness witness(new_descriptors); |
5967 | 5827 |
5968 // Set the enumeration index in the descriptors and set the enumeration index | 5828 // Set the enumeration index in the descriptors and set the enumeration index |
5969 // in the result. | 5829 // in the result. |
5970 int enumeration_index = NextEnumerationIndex(); | 5830 int enumeration_index = NextEnumerationIndex(); |
5971 if (!descriptor->ContainsTransition()) { | 5831 if (!descriptor->ContainsTransition()) { |
5972 if (keep_enumeration_index) { | 5832 if (keep_enumeration_index) { |
5973 descriptor->SetEnumerationIndex(GetDetails(index).index()); | 5833 descriptor->SetEnumerationIndex(GetDetails(index).index()); |
5974 } else { | 5834 } else { |
5975 descriptor->SetEnumerationIndex(enumeration_index); | 5835 descriptor->SetEnumerationIndex(enumeration_index); |
5976 ++enumeration_index; | 5836 ++enumeration_index; |
5977 } | 5837 } |
5978 } | 5838 } |
5839 Map* old_elements_transition = elements_transition(); | |
5840 if ((!remove_transitions) && (old_elements_transition != NULL)) { | |
5841 new_descriptors->set_elements_transition(old_elements_transition); | |
5842 } | |
5979 new_descriptors->SetNextEnumerationIndex(enumeration_index); | 5843 new_descriptors->SetNextEnumerationIndex(enumeration_index); |
5980 | 5844 |
5981 // Copy the descriptors, filtering out transitions and null descriptors, | 5845 // Copy the descriptors, filtering out transitions and null descriptors, |
5982 // and inserting or replacing a descriptor. | 5846 // and inserting or replacing a descriptor. |
5983 int to_index = 0; | 5847 int to_index = 0; |
5984 int insertion_index = -1; | 5848 int insertion_index = -1; |
5985 int from_index = 0; | 5849 int from_index = 0; |
5986 while (from_index < number_of_descriptors()) { | 5850 while (from_index < number_of_descriptors()) { |
5987 if (insertion_index < 0 && | 5851 if (insertion_index < 0 && |
5988 InsertionPointFound(GetKey(from_index), descriptor->GetKey())) { | 5852 InsertionPointFound(GetKey(from_index), descriptor->GetKey())) { |
5989 insertion_index = to_index++; | 5853 insertion_index = to_index++; |
5990 if (replacing) from_index++; | 5854 if (replacing) from_index++; |
5991 } else { | 5855 } else { |
5992 if (!(IsNullDescriptor(from_index) || | 5856 if (!(IsNullDescriptor(from_index) || |
5993 (remove_transitions && IsTransitionOnly(from_index)))) { | 5857 (remove_transitions && IsTransitionOnly(from_index)))) { |
5994 MaybeObject* copy_result = | 5858 MaybeObject* copy_result = |
5995 new_descriptors->CopyFrom(to_index++, this, from_index, witness); | 5859 new_descriptors->CopyFrom(to_index++, this, from_index, witness); |
5996 if (copy_result->IsFailure()) return copy_result; | 5860 if (copy_result->IsFailure()) return copy_result; |
5997 } | 5861 } |
5998 from_index++; | 5862 from_index++; |
5999 } | 5863 } |
6000 } | 5864 } |
6001 if (insertion_index < 0) insertion_index = to_index++; | 5865 if (insertion_index < 0) insertion_index = to_index++; |
5866 | |
5867 ASSERT(insertion_index < new_descriptors->number_of_descriptors()); | |
6002 new_descriptors->Set(insertion_index, descriptor, witness); | 5868 new_descriptors->Set(insertion_index, descriptor, witness); |
6003 | 5869 |
6004 ASSERT(to_index == new_descriptors->number_of_descriptors()); | 5870 ASSERT(to_index == new_descriptors->number_of_descriptors()); |
6005 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); | 5871 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); |
6006 | 5872 |
6007 return new_descriptors; | 5873 return new_descriptors; |
6008 } | 5874 } |
6009 | 5875 |
6010 | 5876 |
6011 MaybeObject* DescriptorArray::RemoveTransitions() { | 5877 MaybeObject* DescriptorArray::RemoveTransitions(bool mutable_transitions) { |
6012 // Allocate the new descriptor array. | 5878 // Allocate the new descriptor array. |
6013 int new_number_of_descriptors = 0; | 5879 int new_number_of_descriptors = 0; |
6014 for (int i = 0; i < number_of_descriptors(); i++) { | 5880 for (int i = 0; i < number_of_descriptors(); i++) { |
6015 if (IsProperty(i)) new_number_of_descriptors++; | 5881 if (IsProperty(i)) new_number_of_descriptors++; |
6016 } | 5882 } |
6017 DescriptorArray* new_descriptors; | 5883 DescriptorArray* new_descriptors; |
6018 { MaybeObject* maybe_result = Allocate(new_number_of_descriptors); | 5884 { MaybeObject* maybe_result = Allocate(new_number_of_descriptors, |
5885 mutable_transitions); | |
6019 if (!maybe_result->To(&new_descriptors)) return maybe_result; | 5886 if (!maybe_result->To(&new_descriptors)) return maybe_result; |
6020 } | 5887 } |
6021 | 5888 |
6022 // Copy the content. | 5889 // Copy the content. |
6023 DescriptorArray::WhitenessWitness witness(new_descriptors); | 5890 DescriptorArray::WhitenessWitness witness(new_descriptors); |
6024 int next_descriptor = 0; | 5891 int next_descriptor = 0; |
6025 for (int i = 0; i < number_of_descriptors(); i++) { | 5892 for (int i = 0; i < number_of_descriptors(); i++) { |
6026 if (IsProperty(i)) { | 5893 if (IsProperty(i)) { |
6027 MaybeObject* copy_result = | 5894 MaybeObject* copy_result = |
6028 new_descriptors->CopyFrom(next_descriptor++, this, i, witness); | 5895 new_descriptors->CopyFrom(next_descriptor++, this, i, witness); |
6029 if (copy_result->IsFailure()) return copy_result; | 5896 if (copy_result->IsFailure()) return copy_result; |
6030 } | 5897 } |
6031 } | 5898 } |
6032 ASSERT(next_descriptor == new_descriptors->number_of_descriptors()); | 5899 ASSERT(next_descriptor == new_descriptors->number_of_descriptors()); |
6033 | 5900 |
6034 return new_descriptors; | 5901 return new_descriptors; |
6035 } | 5902 } |
6036 | 5903 |
5904 | |
6037 // The whiteness witness is needed since sort will reshuffle the entries in the | 5905 // The whiteness witness is needed since sort will reshuffle the entries in the |
6038 // descriptor array. If the descriptor array were to be were to be black, the | 5906 // descriptor array. If the descriptor array were to be were to be black, the |
6039 // shuffling would move a slot that was already recorded as pointing into an | 5907 // shuffling would move a slot that was already recorded as pointing into an |
6040 // evacuation candidate. This would result in missing updates upon evacuation. | 5908 // evacuation candidate. This would result in missing updates upon evacuation. |
6041 void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) { | 5909 void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) { |
6042 // In-place heap sort. | 5910 // In-place heap sort. |
6043 int len = number_of_descriptors(); | 5911 int len = number_of_descriptors(); |
6044 | 5912 |
6045 // Bottom-up max-heap construction. | 5913 // Bottom-up max-heap construction. |
6046 // Index of the last node with children | 5914 // Index of the last node with children |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6092 | 5960 |
6093 | 5961 |
6094 void DescriptorArray::Sort(const WhitenessWitness& witness) { | 5962 void DescriptorArray::Sort(const WhitenessWitness& witness) { |
6095 SortUnchecked(witness); | 5963 SortUnchecked(witness); |
6096 SLOW_ASSERT(IsSortedNoDuplicates()); | 5964 SLOW_ASSERT(IsSortedNoDuplicates()); |
6097 } | 5965 } |
6098 | 5966 |
6099 | 5967 |
6100 int DescriptorArray::BinarySearch(String* name, int low, int high) { | 5968 int DescriptorArray::BinarySearch(String* name, int low, int high) { |
6101 uint32_t hash = name->Hash(); | 5969 uint32_t hash = name->Hash(); |
5970 int limit = high; | |
6102 | 5971 |
6103 while (low <= high) { | 5972 ASSERT(low <= high); |
5973 | |
5974 while (low != high) { | |
6104 int mid = (low + high) / 2; | 5975 int mid = (low + high) / 2; |
6105 String* mid_name = GetKey(mid); | 5976 String* mid_name = GetKey(mid); |
6106 uint32_t mid_hash = mid_name->Hash(); | 5977 uint32_t mid_hash = mid_name->Hash(); |
6107 | 5978 |
6108 if (mid_hash > hash) { | 5979 if (mid_hash >= hash) { |
6109 high = mid - 1; | 5980 high = mid; |
6110 continue; | 5981 } else { |
5982 low = mid + 1; | |
6111 } | 5983 } |
6112 if (mid_hash < hash) { | |
6113 low = mid + 1; | |
6114 continue; | |
6115 } | |
6116 // Found an element with the same hash-code. | |
6117 ASSERT(hash == mid_hash); | |
6118 // There might be more, so we find the first one and | |
6119 // check them all to see if we have a match. | |
6120 if (name == mid_name && !IsNullDescriptor(mid)) return mid; | |
6121 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--; | |
6122 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) { | |
6123 if (GetKey(mid)->Equals(name) && !IsNullDescriptor(mid)) return mid; | |
6124 } | |
6125 break; | |
6126 } | 5984 } |
5985 | |
5986 for (; low <= limit && GetKey(low)->Hash() == hash; ++low) { | |
5987 if (GetKey(low)->Equals(name) && !IsNullDescriptor(low)) | |
5988 return low; | |
5989 } | |
5990 | |
6127 return kNotFound; | 5991 return kNotFound; |
6128 } | 5992 } |
6129 | 5993 |
6130 | 5994 |
6131 int DescriptorArray::LinearSearch(String* name, int len) { | 5995 int DescriptorArray::LinearSearch(String* name, int len) { |
6132 uint32_t hash = name->Hash(); | 5996 uint32_t hash = name->Hash(); |
6133 for (int number = 0; number < len; number++) { | 5997 for (int number = 0; number < len; number++) { |
6134 String* entry = GetKey(number); | 5998 String* entry = GetKey(number); |
6135 if ((entry->Hash() == hash) && | 5999 if (entry->Hash() > hash) break; |
6136 name->Equals(entry) && | 6000 if (name->Equals(entry) && !IsNullDescriptor(number)) { |
6137 !IsNullDescriptor(number)) { | |
6138 return number; | 6001 return number; |
6139 } | 6002 } |
6140 } | 6003 } |
6141 return kNotFound; | 6004 return kNotFound; |
6142 } | 6005 } |
6143 | 6006 |
6144 | 6007 |
6145 MaybeObject* AccessorPair::CopyWithoutTransitions() { | 6008 MaybeObject* AccessorPair::CopyWithoutTransitions() { |
6146 Heap* heap = GetHeap(); | 6009 Heap* heap = GetHeap(); |
6147 AccessorPair* copy; | 6010 AccessorPair* copy; |
(...skipping 1263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7411 // live. If not, null the descriptor. Also drop the back pointer for that | 7274 // live. If not, null the descriptor. Also drop the back pointer for that |
7412 // map transition, so that this map is not reached again by following a back | 7275 // map transition, so that this map is not reached again by following a back |
7413 // pointer from that non-live map. | 7276 // pointer from that non-live map. |
7414 bool keep_entry = false; | 7277 bool keep_entry = false; |
7415 PropertyDetails details(d->GetDetails(i)); | 7278 PropertyDetails details(d->GetDetails(i)); |
7416 switch (details.type()) { | 7279 switch (details.type()) { |
7417 case MAP_TRANSITION: | 7280 case MAP_TRANSITION: |
7418 case CONSTANT_TRANSITION: | 7281 case CONSTANT_TRANSITION: |
7419 ClearBackPointer(heap, d->GetValue(i), &keep_entry); | 7282 ClearBackPointer(heap, d->GetValue(i), &keep_entry); |
7420 break; | 7283 break; |
7421 case ELEMENTS_TRANSITION: { | |
7422 Object* object = d->GetValue(i); | |
7423 if (object->IsMap()) { | |
7424 ClearBackPointer(heap, object, &keep_entry); | |
7425 } else { | |
7426 FixedArray* array = FixedArray::cast(object); | |
7427 for (int j = 0; j < array->length(); ++j) { | |
7428 if (ClearBackPointer(heap, array->get(j), &keep_entry)) { | |
7429 array->set_undefined(j); | |
7430 } | |
7431 } | |
7432 } | |
7433 break; | |
7434 } | |
7435 case CALLBACKS: { | 7284 case CALLBACKS: { |
7436 Object* object = d->GetValue(i); | 7285 Object* object = d->GetValue(i); |
7437 if (object->IsAccessorPair()) { | 7286 if (object->IsAccessorPair()) { |
7438 AccessorPair* accessors = AccessorPair::cast(object); | 7287 AccessorPair* accessors = AccessorPair::cast(object); |
7439 if (ClearBackPointer(heap, accessors->getter(), &keep_entry)) { | 7288 if (ClearBackPointer(heap, accessors->getter(), &keep_entry)) { |
7440 accessors->set_getter(heap->the_hole_value()); | 7289 accessors->set_getter(heap->the_hole_value()); |
7441 } | 7290 } |
7442 if (ClearBackPointer(heap, accessors->setter(), &keep_entry)) { | 7291 if (ClearBackPointer(heap, accessors->setter(), &keep_entry)) { |
7443 accessors->set_setter(heap->the_hole_value()); | 7292 accessors->set_setter(heap->the_hole_value()); |
7444 } | 7293 } |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7584 } | 7433 } |
7585 | 7434 |
7586 | 7435 |
7587 MaybeObject* JSFunction::SetInstancePrototype(Object* value) { | 7436 MaybeObject* JSFunction::SetInstancePrototype(Object* value) { |
7588 ASSERT(value->IsJSReceiver()); | 7437 ASSERT(value->IsJSReceiver()); |
7589 Heap* heap = GetHeap(); | 7438 Heap* heap = GetHeap(); |
7590 if (has_initial_map()) { | 7439 if (has_initial_map()) { |
7591 // If the function has allocated the initial map | 7440 // If the function has allocated the initial map |
7592 // replace it with a copy containing the new prototype. | 7441 // replace it with a copy containing the new prototype. |
7593 Map* new_map; | 7442 Map* new_map; |
7594 MaybeObject* maybe_new_map = initial_map()->CopyDropTransitions(); | 7443 MaybeObject* maybe_new_map = initial_map()->CopyDropTransitions(false); |
7595 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | 7444 if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
7596 new_map->set_prototype(value); | 7445 new_map->set_prototype(value); |
7597 MaybeObject* maybe_object = | 7446 MaybeObject* maybe_object = |
7598 set_initial_map_and_cache_transitions(new_map); | 7447 set_initial_map_and_cache_transitions(new_map); |
7599 if (maybe_object->IsFailure()) return maybe_object; | 7448 if (maybe_object->IsFailure()) return maybe_object; |
7600 } else { | 7449 } else { |
7601 // Put the value in the initial map field until an initial map is | 7450 // Put the value in the initial map field until an initial map is |
7602 // needed. At that point, a new initial map is created and the | 7451 // needed. At that point, a new initial map is created and the |
7603 // prototype is put into the initial map where it belongs. | 7452 // prototype is put into the initial map where it belongs. |
7604 set_prototype_or_initial_map(value); | 7453 set_prototype_or_initial_map(value); |
7605 } | 7454 } |
7606 heap->ClearInstanceofCache(); | 7455 heap->ClearInstanceofCache(); |
7607 return value; | 7456 return value; |
7608 } | 7457 } |
7609 | 7458 |
7610 | 7459 |
7611 MaybeObject* JSFunction::SetPrototype(Object* value) { | 7460 MaybeObject* JSFunction::SetPrototype(Object* value) { |
7612 ASSERT(should_have_prototype()); | 7461 ASSERT(should_have_prototype()); |
7613 Object* construct_prototype = value; | 7462 Object* construct_prototype = value; |
7614 | 7463 |
7615 // If the value is not a JSReceiver, store the value in the map's | 7464 // If the value is not a JSReceiver, store the value in the map's |
7616 // constructor field so it can be accessed. Also, set the prototype | 7465 // constructor field so it can be accessed. Also, set the prototype |
7617 // used for constructing objects to the original object prototype. | 7466 // used for constructing objects to the original object prototype. |
7618 // See ECMA-262 13.2.2. | 7467 // See ECMA-262 13.2.2. |
7619 if (!value->IsJSReceiver()) { | 7468 if (!value->IsJSReceiver()) { |
7620 // Copy the map so this does not affect unrelated functions. | 7469 // Copy the map so this does not affect unrelated functions. |
7621 // Remove map transitions because they point to maps with a | 7470 // Remove map transitions because they point to maps with a |
7622 // different prototype. | 7471 // different prototype. |
7623 Map* new_map; | 7472 Map* new_map; |
7624 { MaybeObject* maybe_new_map = map()->CopyDropTransitions(); | 7473 { MaybeObject* maybe_new_map = map()->CopyDropTransitions(false); |
7625 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | 7474 if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
7626 } | 7475 } |
7627 Heap* heap = new_map->GetHeap(); | 7476 Heap* heap = new_map->GetHeap(); |
7628 set_map(new_map); | 7477 set_map(new_map); |
7629 new_map->set_constructor(value); | 7478 new_map->set_constructor(value); |
7630 new_map->set_non_instance_prototype(true); | 7479 new_map->set_non_instance_prototype(true); |
7631 construct_prototype = | 7480 construct_prototype = |
7632 heap->isolate()->context()->global_context()-> | 7481 heap->isolate()->context()->global_context()-> |
7633 initial_object_prototype(); | 7482 initial_object_prototype(); |
7634 } else { | 7483 } else { |
(...skipping 846 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8481 | 8330 |
8482 const char* Code::PropertyType2String(PropertyType type) { | 8331 const char* Code::PropertyType2String(PropertyType type) { |
8483 switch (type) { | 8332 switch (type) { |
8484 case NORMAL: return "NORMAL"; | 8333 case NORMAL: return "NORMAL"; |
8485 case FIELD: return "FIELD"; | 8334 case FIELD: return "FIELD"; |
8486 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION"; | 8335 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION"; |
8487 case CALLBACKS: return "CALLBACKS"; | 8336 case CALLBACKS: return "CALLBACKS"; |
8488 case HANDLER: return "HANDLER"; | 8337 case HANDLER: return "HANDLER"; |
8489 case INTERCEPTOR: return "INTERCEPTOR"; | 8338 case INTERCEPTOR: return "INTERCEPTOR"; |
8490 case MAP_TRANSITION: return "MAP_TRANSITION"; | 8339 case MAP_TRANSITION: return "MAP_TRANSITION"; |
8491 case ELEMENTS_TRANSITION: return "ELEMENTS_TRANSITION"; | |
8492 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION"; | 8340 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION"; |
8493 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR"; | 8341 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR"; |
8494 } | 8342 } |
8495 UNREACHABLE(); // keep the compiler happy | 8343 UNREACHABLE(); // keep the compiler happy |
8496 return NULL; | 8344 return NULL; |
8497 } | 8345 } |
8498 | 8346 |
8499 | 8347 |
8500 void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) { | 8348 void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) { |
8501 const char* name = NULL; | 8349 const char* name = NULL; |
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8872 } | 8720 } |
8873 | 8721 |
8874 // Set the new prototype of the object. | 8722 // Set the new prototype of the object. |
8875 Map* map = real_receiver->map(); | 8723 Map* map = real_receiver->map(); |
8876 | 8724 |
8877 // Nothing to do if prototype is already set. | 8725 // Nothing to do if prototype is already set. |
8878 if (map->prototype() == value) return value; | 8726 if (map->prototype() == value) return value; |
8879 | 8727 |
8880 Object* new_map = map->GetPrototypeTransition(value); | 8728 Object* new_map = map->GetPrototypeTransition(value); |
8881 if (new_map == NULL) { | 8729 if (new_map == NULL) { |
8882 { MaybeObject* maybe_new_map = map->CopyDropTransitions(); | 8730 { MaybeObject* maybe_new_map = map->CopyDropTransitions(false); |
8883 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; | 8731 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; |
8884 } | 8732 } |
8885 | 8733 |
8886 { MaybeObject* maybe_new_cache = | 8734 { MaybeObject* maybe_new_cache = |
8887 map->PutPrototypeTransition(value, Map::cast(new_map)); | 8735 map->PutPrototypeTransition(value, Map::cast(new_map)); |
8888 if (maybe_new_cache->IsFailure()) return maybe_new_cache; | 8736 if (maybe_new_cache->IsFailure()) return maybe_new_cache; |
8889 } | 8737 } |
8890 | 8738 |
8891 Map::cast(new_map)->set_prototype(value); | 8739 Map::cast(new_map)->set_prototype(value); |
8892 } | 8740 } |
(...skipping 2260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
11153 entry = NextProbe(entry, count++, capacity); | 11001 entry = NextProbe(entry, count++, capacity); |
11154 } | 11002 } |
11155 return kNotFound; | 11003 return kNotFound; |
11156 } | 11004 } |
11157 | 11005 |
11158 | 11006 |
11159 bool StringDictionary::ContainsTransition(int entry) { | 11007 bool StringDictionary::ContainsTransition(int entry) { |
11160 switch (DetailsAt(entry).type()) { | 11008 switch (DetailsAt(entry).type()) { |
11161 case MAP_TRANSITION: | 11009 case MAP_TRANSITION: |
11162 case CONSTANT_TRANSITION: | 11010 case CONSTANT_TRANSITION: |
11163 case ELEMENTS_TRANSITION: | |
11164 return true; | 11011 return true; |
11165 case CALLBACKS: { | 11012 case CALLBACKS: { |
11166 Object* value = ValueAt(entry); | 11013 Object* value = ValueAt(entry); |
11167 if (!value->IsAccessorPair()) return false; | 11014 if (!value->IsAccessorPair()) return false; |
11168 AccessorPair* accessors = AccessorPair::cast(value); | 11015 AccessorPair* accessors = AccessorPair::cast(value); |
11169 return accessors->getter()->IsMap() || accessors->setter()->IsMap(); | 11016 return accessors->getter()->IsMap() || accessors->setter()->IsMap(); |
11170 } | 11017 } |
11171 case NORMAL: | 11018 case NORMAL: |
11172 case FIELD: | 11019 case FIELD: |
11173 case CONSTANT_FUNCTION: | 11020 case CONSTANT_FUNCTION: |
(...skipping 1429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12603 if (type == NORMAL && | 12450 if (type == NORMAL && |
12604 (!value->IsJSFunction() || heap->InNewSpace(value))) { | 12451 (!value->IsJSFunction() || heap->InNewSpace(value))) { |
12605 number_of_fields += 1; | 12452 number_of_fields += 1; |
12606 } | 12453 } |
12607 } | 12454 } |
12608 } | 12455 } |
12609 | 12456 |
12610 // Allocate the instance descriptor. | 12457 // Allocate the instance descriptor. |
12611 DescriptorArray* descriptors; | 12458 DescriptorArray* descriptors; |
12612 { MaybeObject* maybe_descriptors = | 12459 { MaybeObject* maybe_descriptors = |
12613 DescriptorArray::Allocate(instance_descriptor_length); | 12460 DescriptorArray::Allocate(instance_descriptor_length, false); |
12614 if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) { | 12461 if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) { |
12615 return maybe_descriptors; | 12462 return maybe_descriptors; |
12616 } | 12463 } |
12617 } | 12464 } |
12618 | 12465 |
12619 DescriptorArray::WhitenessWitness witness(descriptors); | 12466 DescriptorArray::WhitenessWitness witness(descriptors); |
12620 | 12467 |
12621 int inobject_props = obj->map()->inobject_properties(); | 12468 int inobject_props = obj->map()->inobject_properties(); |
12622 int number_of_allocated_fields = | 12469 int number_of_allocated_fields = |
12623 number_of_fields + unused_property_fields - inobject_props; | 12470 number_of_fields + unused_property_fields - inobject_props; |
(...skipping 583 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
13207 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); | 13054 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); |
13208 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); | 13055 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); |
13209 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); | 13056 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); |
13210 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); | 13057 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); |
13211 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); | 13058 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); |
13212 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); | 13059 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); |
13213 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); | 13060 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); |
13214 } | 13061 } |
13215 | 13062 |
13216 } } // namespace v8::internal | 13063 } } // namespace v8::internal |
OLD | NEW |