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 611 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
622 return result->holder()->GetPropertyWithCallback( | 622 return result->holder()->GetPropertyWithCallback( |
623 receiver, result->GetCallbackObject(), name); | 623 receiver, result->GetCallbackObject(), name); |
624 case HANDLER: | 624 case HANDLER: |
625 return result->proxy()->GetPropertyWithHandler(receiver, name); | 625 return result->proxy()->GetPropertyWithHandler(receiver, name); |
626 case INTERCEPTOR: { | 626 case INTERCEPTOR: { |
627 JSObject* recvr = JSObject::cast(receiver); | 627 JSObject* recvr = JSObject::cast(receiver); |
628 return result->holder()->GetPropertyWithInterceptor( | 628 return result->holder()->GetPropertyWithInterceptor( |
629 recvr, name, attributes); | 629 recvr, name, attributes); |
630 } | 630 } |
631 case MAP_TRANSITION: | 631 case MAP_TRANSITION: |
632 case ELEMENTS_TRANSITION: | |
633 case CONSTANT_TRANSITION: | 632 case CONSTANT_TRANSITION: |
634 case NULL_DESCRIPTOR: | 633 case NULL_DESCRIPTOR: |
635 break; | 634 break; |
636 } | 635 } |
637 UNREACHABLE(); | 636 UNREACHABLE(); |
638 return NULL; | 637 return NULL; |
639 } | 638 } |
640 | 639 |
641 | 640 |
642 MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { | 641 MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { |
(...skipping 902 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1545 } | 1544 } |
1546 } | 1545 } |
1547 | 1546 |
1548 // Only allow map transition if the object isn't the global object and there | 1547 // Only allow map transition if the object isn't the global object and there |
1549 // is not a transition for the name, or there's a transition for the name but | 1548 // is not a transition for the name, or there's a transition for the name but |
1550 // it's unrelated to properties. | 1549 // it's unrelated to properties. |
1551 int descriptor_index = old_descriptors->Search(name); | 1550 int descriptor_index = old_descriptors->Search(name); |
1552 | 1551 |
1553 // Element transitions are stored in the descriptor for property "", which is | 1552 // Element transitions are stored in the descriptor for property "", which is |
1554 // not a identifier and should have forced a switch to slow properties above. | 1553 // not a identifier and should have forced a switch to slow properties above. |
1555 ASSERT(descriptor_index == DescriptorArray::kNotFound || | 1554 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound; |
1556 old_descriptors->GetType(descriptor_index) != ELEMENTS_TRANSITION); | |
1557 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound || | |
1558 old_descriptors->GetType(descriptor_index) == ELEMENTS_TRANSITION; | |
1559 bool allow_map_transition = | 1555 bool allow_map_transition = |
1560 can_insert_transition && | 1556 can_insert_transition && |
1561 (isolate->context()->global_context()->object_function()->map() != map()); | 1557 (isolate->context()->global_context()->object_function()->map() != map()); |
1562 | 1558 |
1563 ASSERT(index < map()->inobject_properties() || | 1559 ASSERT(index < map()->inobject_properties() || |
1564 (index - map()->inobject_properties()) < properties()->length() || | 1560 (index - map()->inobject_properties()) < properties()->length() || |
1565 map()->unused_property_fields() == 0); | 1561 map()->unused_property_fields() == 0); |
1566 // Allocate a new map for the object. | 1562 // Allocate a new map for the object. |
1567 Object* r; | 1563 Object* r; |
1568 { MaybeObject* maybe_r = map()->CopyDropDescriptors(); | 1564 { MaybeObject* maybe_r = map()->CopyDropDescriptors(); |
(...skipping 25 matching lines...) Expand all Loading... | |
1594 properties()->CopySize(properties()->length() + kFieldsAdded); | 1590 properties()->CopySize(properties()->length() + kFieldsAdded); |
1595 if (!maybe_values->ToObject(&values)) return maybe_values; | 1591 if (!maybe_values->ToObject(&values)) return maybe_values; |
1596 } | 1592 } |
1597 set_properties(FixedArray::cast(values)); | 1593 set_properties(FixedArray::cast(values)); |
1598 new_map->set_unused_property_fields(kFieldsAdded - 1); | 1594 new_map->set_unused_property_fields(kFieldsAdded - 1); |
1599 } else { | 1595 } else { |
1600 new_map->set_unused_property_fields(map()->unused_property_fields() - 1); | 1596 new_map->set_unused_property_fields(map()->unused_property_fields() - 1); |
1601 } | 1597 } |
1602 // We have now allocated all the necessary objects. | 1598 // We have now allocated all the necessary objects. |
1603 // 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. |
1604 map()->set_instance_descriptors(old_descriptors); | 1600 if (allow_map_transition) { |
1601 map()->set_instance_descriptors(old_descriptors); | |
1602 } | |
1605 new_map->SetBackPointer(map()); | 1603 new_map->SetBackPointer(map()); |
1606 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); | 1604 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
1607 set_map(new_map); | 1605 set_map(new_map); |
1608 return FastPropertyAtPut(index, value); | 1606 return FastPropertyAtPut(index, value); |
1609 } | 1607 } |
1610 | 1608 |
1611 | 1609 |
1612 MaybeObject* JSObject::AddConstantFunctionProperty( | 1610 MaybeObject* JSObject::AddConstantFunctionProperty( |
1613 String* name, | 1611 String* name, |
1614 JSFunction* function, | 1612 JSFunction* function, |
(...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2121 return SetPropertyWithCallback(result.GetCallbackObject(), | 2119 return SetPropertyWithCallback(result.GetCallbackObject(), |
2122 name, value, result.holder(), strict_mode); | 2120 name, value, result.holder(), strict_mode); |
2123 } | 2121 } |
2124 case HANDLER: { | 2122 case HANDLER: { |
2125 return result.proxy()->SetPropertyViaPrototypesWithHandler( | 2123 return result.proxy()->SetPropertyViaPrototypesWithHandler( |
2126 this, name, value, attributes, strict_mode, done); | 2124 this, name, value, attributes, strict_mode, done); |
2127 } | 2125 } |
2128 case MAP_TRANSITION: | 2126 case MAP_TRANSITION: |
2129 case CONSTANT_TRANSITION: | 2127 case CONSTANT_TRANSITION: |
2130 case NULL_DESCRIPTOR: | 2128 case NULL_DESCRIPTOR: |
2131 case ELEMENTS_TRANSITION: | |
2132 break; | 2129 break; |
2133 } | 2130 } |
2134 } | 2131 } |
2135 | 2132 |
2136 // If we get here with *done true, we have encountered a read-only property. | 2133 // If we get here with *done true, we have encountered a read-only property. |
2137 if (*done) { | 2134 if (*done) { |
2138 if (strict_mode == kNonStrictMode) return value; | 2135 if (strict_mode == kNonStrictMode) return value; |
2139 Handle<Object> args[] = { Handle<Object>(name), Handle<Object>(this)}; | 2136 Handle<Object> args[] = { Handle<Object>(name), Handle<Object>(this)}; |
2140 return isolate->Throw(*isolate->factory()->NewTypeError( | 2137 return isolate->Throw(*isolate->factory()->NewTypeError( |
2141 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)))); | 2138 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)))); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2191 | 2188 |
2192 | 2189 |
2193 Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) { | 2190 Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) { |
2194 ElementsKind kind = elements_kind(); | 2191 ElementsKind kind = elements_kind(); |
2195 Handle<Map> transitioned_map = Handle<Map>::null(); | 2192 Handle<Map> transitioned_map = Handle<Map>::null(); |
2196 Handle<Map> current_map(this); | 2193 Handle<Map> current_map(this); |
2197 bool packed = IsFastPackedElementsKind(kind); | 2194 bool packed = IsFastPackedElementsKind(kind); |
2198 if (IsTransitionableFastElementsKind(kind)) { | 2195 if (IsTransitionableFastElementsKind(kind)) { |
2199 while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) { | 2196 while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) { |
2200 kind = GetNextMoreGeneralFastElementsKind(kind, false); | 2197 kind = GetNextMoreGeneralFastElementsKind(kind, false); |
2201 bool dummy = true; | |
2202 Handle<Map> maybe_transitioned_map = | 2198 Handle<Map> maybe_transitioned_map = |
2203 MaybeNull(current_map->LookupElementsTransitionMap(kind, &dummy)); | 2199 MaybeNull(current_map->LookupElementsTransitionMap(kind)); |
2204 if (maybe_transitioned_map.is_null()) break; | 2200 if (maybe_transitioned_map.is_null()) break; |
2205 if (ContainsMap(candidates, maybe_transitioned_map) && | 2201 if (ContainsMap(candidates, maybe_transitioned_map) && |
2206 (packed || !IsFastPackedElementsKind(kind))) { | 2202 (packed || !IsFastPackedElementsKind(kind))) { |
2207 transitioned_map = maybe_transitioned_map; | 2203 transitioned_map = maybe_transitioned_map; |
2208 if (!IsFastPackedElementsKind(kind)) packed = false; | 2204 if (!IsFastPackedElementsKind(kind)) packed = false; |
2209 } | 2205 } |
2210 current_map = maybe_transitioned_map; | 2206 current_map = maybe_transitioned_map; |
2211 } | 2207 } |
2212 } | 2208 } |
2213 return transitioned_map; | 2209 return transitioned_map; |
2214 } | 2210 } |
2215 | 2211 |
2216 | 2212 |
2217 static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents, | 2213 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) { |
2218 ElementsKind elements_kind) { | 2214 Map* current_map = map; |
2219 if (descriptor_contents->IsMap()) { | 2215 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind()); |
2220 Map* map = Map::cast(descriptor_contents); | 2216 int to_index = GetSequenceIndexFromFastElementsKind(to_kind); |
2221 if (map->elements_kind() == elements_kind) { | 2217 for (; index < to_index; ++index) { |
2222 return map; | 2218 Map* next_map = current_map->elements_transition_map(); |
2219 if (next_map == NULL) { | |
2220 return current_map; | |
2223 } | 2221 } |
2224 return NULL; | 2222 current_map = next_map; |
2225 } | 2223 } |
2226 | 2224 ASSERT(current_map->elements_kind() == to_kind); |
2227 FixedArray* map_array = FixedArray::cast(descriptor_contents); | 2225 return current_map; |
2228 for (int i = 0; i < map_array->length(); ++i) { | |
2229 Object* current = map_array->get(i); | |
2230 // Skip undefined slots, they are sentinels for reclaimed maps. | |
2231 if (!current->IsUndefined()) { | |
2232 Map* current_map = Map::cast(map_array->get(i)); | |
2233 if (current_map->elements_kind() == elements_kind) { | |
2234 return current_map; | |
2235 } | |
2236 } | |
2237 } | |
2238 | |
2239 return NULL; | |
2240 } | 2226 } |
2241 | 2227 |
2242 | 2228 |
2243 static MaybeObject* AddElementsTransitionMapToDescriptor( | 2229 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) { |
2244 Object* descriptor_contents, | 2230 if (this->instance_descriptors()->MayContainTransitions() && |
2245 Map* new_map) { | 2231 IsMoreGeneralElementsKindTransition(this->elements_kind(), to_kind)) { |
2246 // Nothing was in the descriptor for an ELEMENTS_TRANSITION, | 2232 Map* to_map = FindClosestElementsTransition(this, to_kind); |
2247 // simply add the map. | 2233 if (to_map->elements_kind() == to_kind) { |
2248 if (descriptor_contents == NULL) { | 2234 return to_map; |
2249 return new_map; | |
2250 } | |
2251 | |
2252 // There was already a map in the descriptor, create a 2-element FixedArray | |
2253 // to contain the existing map plus the new one. | |
2254 FixedArray* new_array; | |
2255 Heap* heap = new_map->GetHeap(); | |
2256 if (descriptor_contents->IsMap()) { | |
2257 // Must tenure, DescriptorArray expects no new-space objects. | |
2258 MaybeObject* maybe_new_array = heap->AllocateFixedArray(2, TENURED); | |
2259 if (!maybe_new_array->To<FixedArray>(&new_array)) { | |
2260 return maybe_new_array; | |
2261 } | |
2262 new_array->set(0, descriptor_contents); | |
2263 new_array->set(1, new_map); | |
2264 return new_array; | |
2265 } | |
2266 | |
2267 // The descriptor already contained a list of maps for different ElementKinds | |
2268 // of ELEMENTS_TRANSITION, first check the existing array for an undefined | |
2269 // slot, and if that's not available, create a FixedArray to hold the existing | |
2270 // maps plus the new one and fill it in. | |
2271 FixedArray* array = FixedArray::cast(descriptor_contents); | |
2272 for (int i = 0; i < array->length(); ++i) { | |
2273 if (array->get(i)->IsUndefined()) { | |
2274 array->set(i, new_map); | |
2275 return array; | |
2276 } | |
2277 } | |
2278 | |
2279 // Must tenure, DescriptorArray expects no new-space objects. | |
2280 MaybeObject* maybe_new_array = | |
2281 heap->AllocateFixedArray(array->length() + 1, TENURED); | |
2282 if (!maybe_new_array->To<FixedArray>(&new_array)) { | |
2283 return maybe_new_array; | |
2284 } | |
2285 int i = 0; | |
2286 while (i < array->length()) { | |
2287 new_array->set(i, array->get(i)); | |
2288 ++i; | |
2289 } | |
2290 new_array->set(i, new_map); | |
2291 return new_array; | |
2292 } | |
2293 | |
2294 | |
2295 String* Map::elements_transition_sentinel_name() { | |
2296 return GetHeap()->empty_symbol(); | |
2297 } | |
2298 | |
2299 | |
2300 Object* Map::GetDescriptorContents(String* sentinel_name, | |
2301 bool* safe_to_add_transition) { | |
2302 // Get the cached index for the descriptors lookup, or find and cache it. | |
2303 DescriptorArray* descriptors = instance_descriptors(); | |
2304 DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache(); | |
2305 int index = cache->Lookup(descriptors, sentinel_name); | |
2306 if (index == DescriptorLookupCache::kAbsent) { | |
2307 index = descriptors->Search(sentinel_name); | |
2308 cache->Update(descriptors, sentinel_name, index); | |
2309 } | |
2310 // If the transition already exists, return its descriptor. | |
2311 if (index != DescriptorArray::kNotFound) { | |
2312 PropertyDetails details = descriptors->GetDetails(index); | |
2313 if (details.type() == ELEMENTS_TRANSITION) { | |
2314 return descriptors->GetValue(index); | |
2315 } else { | |
2316 if (safe_to_add_transition != NULL) { | |
2317 *safe_to_add_transition = false; | |
2318 } | |
2319 } | 2235 } |
2320 } | 2236 } |
2321 return NULL; | 2237 return NULL; |
2322 } | 2238 } |
2323 | 2239 |
2324 | 2240 |
2325 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind, | 2241 MaybeObject* Map::CreateNextElementsTransition(ElementsKind next_kind) { |
2326 bool* safe_to_add_transition) { | 2242 ASSERT(elements_transition_map() == NULL); |
2327 ElementsKind from_kind = elements_kind(); | 2243 ASSERT(GetSequenceIndexFromFastElementsKind(elements_kind()) == |
2328 if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) { | 2244 (GetSequenceIndexFromFastElementsKind(next_kind) - 1)); |
2329 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) { | |
2330 if (safe_to_add_transition) *safe_to_add_transition = false; | |
2331 return NULL; | |
2332 } | |
2333 ElementsKind transitioned_from_kind = | |
2334 GetNextMoreGeneralFastElementsKind(from_kind, false); | |
2335 | 2245 |
2246 Map* next_map; | |
2247 MaybeObject* maybe_next_map = | |
2248 this->CopyDropTransitions(DescriptorArray::CANNOT_BE_SHARED); | |
2249 if (!maybe_next_map->To(&next_map)) return maybe_next_map; | |
2336 | 2250 |
2337 // If the transition is a single step in the transition sequence, fall | 2251 next_map->set_elements_kind(next_kind); |
2338 // through to looking it up and returning it. If it requires several steps, | 2252 next_map->SetBackPointer(this); |
2339 // divide and conquer. | 2253 this->set_elements_transition_map(next_map); |
2340 if (transitioned_from_kind != to_kind) { | 2254 return next_map; |
2341 // If the transition is several steps in the lattice, divide and conquer. | |
2342 Map* from_map = LookupElementsTransitionMap(transitioned_from_kind, | |
2343 safe_to_add_transition); | |
2344 if (from_map == NULL) return NULL; | |
2345 return from_map->LookupElementsTransitionMap(to_kind, | |
2346 safe_to_add_transition); | |
2347 } | |
2348 } | |
2349 Object* descriptor_contents = GetDescriptorContents( | |
2350 elements_transition_sentinel_name(), safe_to_add_transition); | |
2351 if (descriptor_contents != NULL) { | |
2352 Map* maybe_transition_map = | |
2353 GetElementsTransitionMapFromDescriptor(descriptor_contents, | |
2354 to_kind); | |
2355 ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap()); | |
2356 return maybe_transition_map; | |
2357 } | |
2358 return NULL; | |
2359 } | 2255 } |
2360 | 2256 |
2361 | 2257 |
2362 MaybeObject* Map::AddElementsTransition(ElementsKind to_kind, | 2258 static MaybeObject* AddMissingElementsTransitions(Map* map, |
2363 Map* transitioned_map) { | 2259 ElementsKind to_kind) { |
2364 ElementsKind from_kind = elements_kind(); | 2260 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind()) + 1; |
2365 if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) { | 2261 int to_index = GetSequenceIndexFromFastElementsKind(to_kind); |
2366 ASSERT(IsMoreGeneralElementsKindTransition(from_kind, to_kind)); | 2262 ASSERT(index <= to_index); |
2367 ElementsKind transitioned_from_kind = | |
2368 GetNextMoreGeneralFastElementsKind(from_kind, false); | |
2369 // The map transitions graph should be a tree, therefore transitions to | |
2370 // ElementsKind that are not adjacent in the ElementsKind sequence are not | |
2371 // done directly, but instead by going through intermediate ElementsKinds | |
2372 // first. | |
2373 if (to_kind != transitioned_from_kind) { | |
2374 bool safe_to_add = true; | |
2375 Map* intermediate_map = LookupElementsTransitionMap( | |
2376 transitioned_from_kind, &safe_to_add); | |
2377 // This method is only called when safe_to_add has been found to be true | |
2378 // earlier. | |
2379 ASSERT(safe_to_add); | |
2380 | 2263 |
2381 if (intermediate_map == NULL) { | 2264 Map* current_map = map; |
2382 MaybeObject* maybe_map = CopyDropTransitions(); | 2265 |
2383 if (!maybe_map->To(&intermediate_map)) return maybe_map; | 2266 for (; index <= to_index; ++index) { |
2384 intermediate_map->set_elements_kind(transitioned_from_kind); | 2267 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index); |
2385 MaybeObject* maybe_transition = AddElementsTransition( | 2268 MaybeObject* maybe_next_map = |
2386 transitioned_from_kind, intermediate_map); | 2269 current_map->CreateNextElementsTransition(next_kind); |
2387 if (maybe_transition->IsFailure()) return maybe_transition; | 2270 if (!maybe_next_map->To(¤t_map)) return maybe_next_map; |
2388 } | |
2389 return intermediate_map->AddElementsTransition(to_kind, transitioned_map); | |
2390 } | |
2391 } | 2271 } |
2392 | 2272 |
2393 bool safe_to_add_transition = true; | 2273 ASSERT(current_map->elements_kind() == to_kind); |
2394 Object* descriptor_contents = GetDescriptorContents( | 2274 return current_map; |
2395 elements_transition_sentinel_name(), &safe_to_add_transition); | |
2396 // This method is only called when safe_to_add_transition has been found | |
2397 // to be true earlier. | |
2398 ASSERT(safe_to_add_transition); | |
2399 MaybeObject* maybe_new_contents = | |
2400 AddElementsTransitionMapToDescriptor(descriptor_contents, | |
2401 transitioned_map); | |
2402 Object* new_contents; | |
2403 if (!maybe_new_contents->ToObject(&new_contents)) { | |
2404 return maybe_new_contents; | |
2405 } | |
2406 | |
2407 ElementsTransitionDescriptor desc(elements_transition_sentinel_name(), | |
2408 new_contents); | |
2409 Object* new_descriptors; | |
2410 MaybeObject* maybe_new_descriptors = | |
2411 instance_descriptors()->CopyInsert(&desc, KEEP_TRANSITIONS); | |
2412 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { | |
2413 return maybe_new_descriptors; | |
2414 } | |
2415 set_instance_descriptors(DescriptorArray::cast(new_descriptors)); | |
2416 transitioned_map->SetBackPointer(this); | |
2417 return this; | |
2418 } | 2275 } |
2419 | 2276 |
2420 | 2277 |
2421 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object, | 2278 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object, |
2422 ElementsKind to_kind) { | 2279 ElementsKind to_kind) { |
2423 Isolate* isolate = object->GetIsolate(); | 2280 Isolate* isolate = object->GetIsolate(); |
2424 CALL_HEAP_FUNCTION(isolate, | 2281 CALL_HEAP_FUNCTION(isolate, |
2425 object->GetElementsTransitionMap(isolate, to_kind), | 2282 object->GetElementsTransitionMap(isolate, to_kind), |
2426 Map); | 2283 Map); |
2427 } | 2284 } |
2428 | 2285 |
2429 | 2286 |
2287 // If the map is using the empty descriptor array, install a new empty | |
2288 // descriptor array that will contain an element transition. | |
2289 // TODO(verwaest) Goes away once the descriptor array is immutable. | |
2290 static MaybeObject* EnsureMayContainTransitions(Map* map) { | |
2291 if (map->instance_descriptors()->MayContainTransitions()) return map; | |
2292 DescriptorArray* descriptor_array; | |
2293 MaybeObject* maybe_descriptor_array = | |
2294 DescriptorArray::Allocate(0, DescriptorArray::CANNOT_BE_SHARED); | |
2295 if (!maybe_descriptor_array->To(&descriptor_array)) { | |
2296 return maybe_descriptor_array; | |
2297 } | |
2298 map->set_instance_descriptors(descriptor_array); | |
2299 return map; | |
2300 } | |
2301 | |
2302 | |
2430 MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) { | 2303 MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) { |
2431 Map* current_map = map(); | 2304 Map* start_map = map(); |
2432 ElementsKind from_kind = current_map->elements_kind(); | 2305 ElementsKind from_kind = start_map->elements_kind(); |
2433 | 2306 |
2434 if (from_kind == to_kind) return current_map; | 2307 if (from_kind == to_kind) { |
2435 | 2308 return start_map; |
2436 // Only objects with FastProperties can have DescriptorArrays and can track | |
2437 // element-related maps. Also don't add descriptors to maps that are shared. | |
2438 bool safe_to_add_transition = HasFastProperties() && | |
2439 !current_map->IsUndefined() && | |
2440 !current_map->is_shared(); | |
2441 | |
2442 // Prevent long chains of DICTIONARY -> FAST_*_ELEMENTS maps caused by objects | |
2443 // with elements that switch back and forth between dictionary and fast | |
2444 // element modes. | |
2445 if (from_kind == DICTIONARY_ELEMENTS && | |
2446 IsFastElementsKind(to_kind)) { | |
2447 safe_to_add_transition = false; | |
2448 } | 2309 } |
2449 | 2310 |
2450 if (safe_to_add_transition) { | 2311 Context* global_context = GetIsolate()->context()->global_context(); |
2451 // It's only safe to manipulate the descriptor array if it would be | 2312 bool allow_store_transition = |
2452 // safe to add a transition. | 2313 // Only remember the map transition if the object's map is NOT equal to |
2453 Map* maybe_transition_map = current_map->LookupElementsTransitionMap( | 2314 // the global object_function's map and there is not an already existing |
2454 to_kind, &safe_to_add_transition); | 2315 // non-matching element transition. |
2455 if (maybe_transition_map != NULL) { | 2316 (global_context->object_function()->map() != map()) && |
2456 return maybe_transition_map; | 2317 !start_map->IsUndefined() && !start_map->is_shared() && |
2457 } | 2318 // Only store fast element maps in ascending generality. |
2319 IsTransitionableFastElementsKind(from_kind) && | |
2320 IsFastElementsKind(to_kind) && | |
2321 IsMoreGeneralElementsKindTransition(from_kind, to_kind); | |
2322 | |
2323 if (!allow_store_transition) { | |
2324 // Create a new free-floating map only if we are not allowed to store it. | |
2325 Map* new_map = NULL; | |
2326 MaybeObject* maybe_new_map = | |
2327 start_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); | |
2328 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | |
2329 new_map->set_elements_kind(to_kind); | |
2330 return new_map; | |
2458 } | 2331 } |
2459 | 2332 |
2460 Map* new_map = NULL; | 2333 EnsureMayContainTransitions(start_map); |
2334 Map* closest_map = FindClosestElementsTransition(start_map, to_kind); | |
2461 | 2335 |
2462 // No transition to an existing map for the given ElementsKind. Make a new | 2336 if (closest_map->elements_kind() == to_kind) { |
2463 // one. | 2337 return closest_map; |
2464 { MaybeObject* maybe_map = current_map->CopyDropTransitions(); | |
2465 if (!maybe_map->To(&new_map)) return maybe_map; | |
2466 } | 2338 } |
2467 | 2339 |
2468 new_map->set_elements_kind(to_kind); | 2340 return AddMissingElementsTransitions(closest_map, to_kind); |
2469 | |
2470 // Only remember the map transition if the object's map is NOT equal to the | |
2471 // global object_function's map and there is not an already existing | |
2472 // non-matching element transition. | |
2473 Context* global_context = GetIsolate()->context()->global_context(); | |
2474 bool allow_map_transition = safe_to_add_transition && | |
2475 (global_context->object_function()->map() != map()); | |
2476 if (allow_map_transition) { | |
2477 MaybeObject* maybe_transition = | |
2478 current_map->AddElementsTransition(to_kind, new_map); | |
2479 if (maybe_transition->IsFailure()) return maybe_transition; | |
2480 } | |
2481 return new_map; | |
2482 } | 2341 } |
2483 | 2342 |
2484 | 2343 |
2485 void JSObject::LocalLookupRealNamedProperty(String* name, | 2344 void JSObject::LocalLookupRealNamedProperty(String* name, |
2486 LookupResult* result) { | 2345 LookupResult* result) { |
2487 if (IsJSGlobalProxy()) { | 2346 if (IsJSGlobalProxy()) { |
2488 Object* proto = GetPrototype(); | 2347 Object* proto = GetPrototype(); |
2489 if (proto->IsNull()) return result->NotFound(); | 2348 if (proto->IsNull()) return result->NotFound(); |
2490 ASSERT(proto->IsJSGlobalObject()); | 2349 ASSERT(proto->IsJSGlobalObject()); |
2491 // A GlobalProxy's prototype should always be a proper JSObject. | 2350 // A GlobalProxy's prototype should always be a proper JSObject. |
(...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3008 JSFunction::cast(target_descriptors->GetValue(number)); | 2867 JSFunction::cast(target_descriptors->GetValue(number)); |
3009 if (value == function) { | 2868 if (value == function) { |
3010 set_map(target_map); | 2869 set_map(target_map); |
3011 return value; | 2870 return value; |
3012 } | 2871 } |
3013 // Otherwise, replace with a MAP_TRANSITION to a new map with a | 2872 // Otherwise, replace with a MAP_TRANSITION to a new map with a |
3014 // FIELD, even if the value is a constant function. | 2873 // FIELD, even if the value is a constant function. |
3015 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); | 2874 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
3016 } | 2875 } |
3017 case NULL_DESCRIPTOR: | 2876 case NULL_DESCRIPTOR: |
3018 case ELEMENTS_TRANSITION: | |
3019 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); | 2877 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
3020 case HANDLER: | 2878 case HANDLER: |
3021 UNREACHABLE(); | 2879 UNREACHABLE(); |
3022 return value; | 2880 return value; |
3023 } | 2881 } |
3024 UNREACHABLE(); // keep the compiler happy | 2882 UNREACHABLE(); // keep the compiler happy |
3025 return value; | 2883 return value; |
3026 } | 2884 } |
3027 | 2885 |
3028 | 2886 |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3106 // Preserve the attributes of this existing property. | 2964 // Preserve the attributes of this existing property. |
3107 attributes = result.GetAttributes(); | 2965 attributes = result.GetAttributes(); |
3108 return ConvertDescriptorToField(name, value, attributes); | 2966 return ConvertDescriptorToField(name, value, attributes); |
3109 case CALLBACKS: | 2967 case CALLBACKS: |
3110 case INTERCEPTOR: | 2968 case INTERCEPTOR: |
3111 // Override callback in clone | 2969 // Override callback in clone |
3112 return ConvertDescriptorToField(name, value, attributes); | 2970 return ConvertDescriptorToField(name, value, attributes); |
3113 case CONSTANT_TRANSITION: | 2971 case CONSTANT_TRANSITION: |
3114 // Replace with a MAP_TRANSITION to a new map with a FIELD, even | 2972 // Replace with a MAP_TRANSITION to a new map with a FIELD, even |
3115 // if the value is a function. | 2973 // if the value is a function. |
3116 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); | |
3117 case NULL_DESCRIPTOR: | 2974 case NULL_DESCRIPTOR: |
3118 case ELEMENTS_TRANSITION: | |
3119 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); | 2975 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
3120 case HANDLER: | 2976 case HANDLER: |
3121 UNREACHABLE(); | 2977 UNREACHABLE(); |
3122 } | 2978 } |
3123 UNREACHABLE(); // keep the compiler happy | 2979 UNREACHABLE(); // keep the compiler happy |
3124 return value; | 2980 return value; |
3125 } | 2981 } |
3126 | 2982 |
3127 | 2983 |
3128 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor( | 2984 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor( |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3399 } | 3255 } |
3400 MaybeObject* maybe_dictionary = | 3256 MaybeObject* maybe_dictionary = |
3401 dictionary->Add(descs->GetKey(i), value, details); | 3257 dictionary->Add(descs->GetKey(i), value, details); |
3402 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | 3258 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; |
3403 break; | 3259 break; |
3404 } | 3260 } |
3405 case MAP_TRANSITION: | 3261 case MAP_TRANSITION: |
3406 case CONSTANT_TRANSITION: | 3262 case CONSTANT_TRANSITION: |
3407 case NULL_DESCRIPTOR: | 3263 case NULL_DESCRIPTOR: |
3408 case INTERCEPTOR: | 3264 case INTERCEPTOR: |
3409 case ELEMENTS_TRANSITION: | |
3410 break; | 3265 break; |
3411 case HANDLER: | 3266 case HANDLER: |
3412 case NORMAL: | 3267 case NORMAL: |
3413 UNREACHABLE(); | 3268 UNREACHABLE(); |
3414 break; | 3269 break; |
3415 } | 3270 } |
3416 } | 3271 } |
3417 | 3272 |
3418 Heap* current_heap = GetHeap(); | 3273 Heap* current_heap = GetHeap(); |
3419 | 3274 |
(...skipping 765 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4185 { MaybeObject* maybe = NormalizeElements(); | 4040 { MaybeObject* maybe = NormalizeElements(); |
4186 if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe; | 4041 if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe; |
4187 } | 4042 } |
4188 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); | 4043 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); |
4189 // Make sure that we never go back to fast case. | 4044 // Make sure that we never go back to fast case. |
4190 dictionary->set_requires_slow_elements(); | 4045 dictionary->set_requires_slow_elements(); |
4191 | 4046 |
4192 // Do a map transition, other objects with this map may still | 4047 // Do a map transition, other objects with this map may still |
4193 // be extensible. | 4048 // be extensible. |
4194 Map* new_map; | 4049 Map* new_map; |
4195 { MaybeObject* maybe = map()->CopyDropTransitions(); | 4050 { MaybeObject* maybe = |
4051 map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); | |
4196 if (!maybe->To<Map>(&new_map)) return maybe; | 4052 if (!maybe->To<Map>(&new_map)) return maybe; |
4197 } | 4053 } |
4198 new_map->set_is_extensible(false); | 4054 new_map->set_is_extensible(false); |
4199 set_map(new_map); | 4055 set_map(new_map); |
4200 ASSERT(!map()->is_extensible()); | 4056 ASSERT(!map()->is_extensible()); |
4201 return new_map; | 4057 return new_map; |
4202 } | 4058 } |
4203 | 4059 |
4204 | 4060 |
4205 // Tests for the fast common case for property enumeration: | 4061 // Tests for the fast common case for property enumeration: |
(...skipping 759 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4965 Map::cast(result)->set_inobject_properties(inobject_properties()); | 4821 Map::cast(result)->set_inobject_properties(inobject_properties()); |
4966 Map::cast(result)->set_unused_property_fields(unused_property_fields()); | 4822 Map::cast(result)->set_unused_property_fields(unused_property_fields()); |
4967 | 4823 |
4968 // If the map has pre-allocated properties always start out with a descriptor | 4824 // If the map has pre-allocated properties always start out with a descriptor |
4969 // array describing these properties. | 4825 // array describing these properties. |
4970 if (pre_allocated_property_fields() > 0) { | 4826 if (pre_allocated_property_fields() > 0) { |
4971 ASSERT(constructor()->IsJSFunction()); | 4827 ASSERT(constructor()->IsJSFunction()); |
4972 JSFunction* ctor = JSFunction::cast(constructor()); | 4828 JSFunction* ctor = JSFunction::cast(constructor()); |
4973 Object* descriptors; | 4829 Object* descriptors; |
4974 { MaybeObject* maybe_descriptors = | 4830 { MaybeObject* maybe_descriptors = |
4975 ctor->initial_map()->instance_descriptors()->RemoveTransitions(); | 4831 ctor->initial_map()->instance_descriptors()->RemoveTransitions( |
4832 DescriptorArray::MAY_BE_SHARED); | |
4976 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors; | 4833 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors; |
4977 } | 4834 } |
4978 Map::cast(result)->set_instance_descriptors( | 4835 Map::cast(result)->set_instance_descriptors( |
4979 DescriptorArray::cast(descriptors)); | 4836 DescriptorArray::cast(descriptors)); |
4980 Map::cast(result)->set_pre_allocated_property_fields( | 4837 Map::cast(result)->set_pre_allocated_property_fields( |
4981 pre_allocated_property_fields()); | 4838 pre_allocated_property_fields()); |
4982 } | 4839 } |
4983 Map::cast(result)->set_bit_field(bit_field()); | 4840 Map::cast(result)->set_bit_field(bit_field()); |
4984 Map::cast(result)->set_bit_field2(bit_field2()); | 4841 Map::cast(result)->set_bit_field2(bit_field2()); |
4985 Map::cast(result)->set_bit_field3(bit_field3()); | 4842 Map::cast(result)->set_bit_field3(bit_field3()); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5018 #ifdef DEBUG | 4875 #ifdef DEBUG |
5019 if (FLAG_verify_heap && Map::cast(result)->is_shared()) { | 4876 if (FLAG_verify_heap && Map::cast(result)->is_shared()) { |
5020 Map::cast(result)->SharedMapVerify(); | 4877 Map::cast(result)->SharedMapVerify(); |
5021 } | 4878 } |
5022 #endif | 4879 #endif |
5023 | 4880 |
5024 return result; | 4881 return result; |
5025 } | 4882 } |
5026 | 4883 |
5027 | 4884 |
5028 MaybeObject* Map::CopyDropTransitions() { | 4885 MaybeObject* Map::CopyDropTransitions( |
4886 DescriptorArray::SharedMode shared_mode) { | |
5029 Object* new_map; | 4887 Object* new_map; |
5030 { MaybeObject* maybe_new_map = CopyDropDescriptors(); | 4888 { MaybeObject* maybe_new_map = CopyDropDescriptors(); |
5031 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; | 4889 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; |
5032 } | 4890 } |
5033 Object* descriptors; | 4891 Object* descriptors; |
5034 { MaybeObject* maybe_descriptors = | 4892 { MaybeObject* maybe_descriptors = |
5035 instance_descriptors()->RemoveTransitions(); | 4893 instance_descriptors()->RemoveTransitions(shared_mode); |
5036 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors; | 4894 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors; |
5037 } | 4895 } |
5038 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors)); | 4896 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors)); |
5039 return new_map; | 4897 return new_map; |
5040 } | 4898 } |
5041 | 4899 |
5042 void Map::UpdateCodeCache(Handle<Map> map, | 4900 void Map::UpdateCodeCache(Handle<Map> map, |
5043 Handle<String> name, | 4901 Handle<String> name, |
5044 Handle<Code> code) { | 4902 Handle<Code> code) { |
5045 Isolate* isolate = map->GetIsolate(); | 4903 Isolate* isolate = map->GetIsolate(); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5091 | 4949 |
5092 // An iterator over all map transitions in an descriptor array, reusing the map | 4950 // An iterator over all map transitions in an descriptor array, reusing the map |
5093 // field of the contens array while it is running. | 4951 // field of the contens array while it is running. |
5094 class IntrusiveMapTransitionIterator { | 4952 class IntrusiveMapTransitionIterator { |
5095 public: | 4953 public: |
5096 explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array) | 4954 explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array) |
5097 : descriptor_array_(descriptor_array) { } | 4955 : descriptor_array_(descriptor_array) { } |
5098 | 4956 |
5099 void Start() { | 4957 void Start() { |
5100 ASSERT(!IsIterating()); | 4958 ASSERT(!IsIterating()); |
5101 if (HasDescriptors()) *DescriptorArrayHeader() = Smi::FromInt(0); | 4959 if (descriptor_array_->MayContainTransitions()) |
4960 *DescriptorArrayHeader() = Smi::FromInt(0); | |
5102 } | 4961 } |
5103 | 4962 |
5104 bool IsIterating() { | 4963 bool IsIterating() { |
5105 return HasDescriptors() && (*DescriptorArrayHeader())->IsSmi(); | 4964 return descriptor_array_->MayContainTransitions() && |
4965 (*DescriptorArrayHeader())->IsSmi(); | |
5106 } | 4966 } |
5107 | 4967 |
5108 Map* Next() { | 4968 Map* Next() { |
5109 ASSERT(IsIterating()); | 4969 ASSERT(IsIterating()); |
5110 // Attention, tricky index manipulation ahead: Two consecutive indices are | 4970 // Attention, tricky index manipulation ahead: Two consecutive indices are |
5111 // assigned to each descriptor. Most descriptors directly advance to the | 4971 // assigned to each descriptor. Most descriptors directly advance to the |
5112 // next descriptor by adding 2 to the index. The exceptions are the | 4972 // next descriptor by adding 2 to the index. The exceptions are the |
5113 // CALLBACKS entries: An even index means we look at its getter, and an odd | 4973 // CALLBACKS entries: An even index means we look at its getter, and an odd |
5114 // index means we look at its setter. | 4974 // index means we look at its setter. |
5115 int raw_index = Smi::cast(*DescriptorArrayHeader())->value(); | 4975 int raw_index = Smi::cast(*DescriptorArrayHeader())->value(); |
5116 int index = raw_index / 2; | 4976 int index = raw_index / 2; |
5117 int number_of_descriptors = descriptor_array_->number_of_descriptors(); | 4977 int number_of_descriptors = descriptor_array_->number_of_descriptors(); |
5118 while (index < number_of_descriptors) { | 4978 while (index < number_of_descriptors) { |
5119 PropertyDetails details(descriptor_array_->GetDetails(index)); | 4979 PropertyDetails details(descriptor_array_->GetDetails(index)); |
5120 switch (details.type()) { | 4980 switch (details.type()) { |
5121 case MAP_TRANSITION: | 4981 case MAP_TRANSITION: |
5122 case CONSTANT_TRANSITION: | 4982 case CONSTANT_TRANSITION: |
5123 case ELEMENTS_TRANSITION: | |
5124 // We definitely have a map transition. | 4983 // We definitely have a map transition. |
5125 *DescriptorArrayHeader() = Smi::FromInt(raw_index + 2); | 4984 *DescriptorArrayHeader() = Smi::FromInt(raw_index + 2); |
5126 return static_cast<Map*>(descriptor_array_->GetValue(index)); | 4985 return static_cast<Map*>(descriptor_array_->GetValue(index)); |
5127 case CALLBACKS: { | 4986 case CALLBACKS: { |
5128 // We might have a map transition in a getter or in a setter. | 4987 // We might have a map transition in a getter or in a setter. |
5129 AccessorPair* accessors = | 4988 AccessorPair* accessors = |
5130 static_cast<AccessorPair*>(descriptor_array_->GetValue(index)); | 4989 static_cast<AccessorPair*>(descriptor_array_->GetValue(index)); |
5131 Object* accessor; | 4990 Object* accessor; |
5132 if ((raw_index & 1) == 0) { | 4991 if ((raw_index & 1) == 0) { |
5133 accessor = accessors->setter(); | 4992 accessor = accessors->setter(); |
(...skipping 13 matching lines...) Expand all Loading... | |
5147 case CONSTANT_FUNCTION: | 5006 case CONSTANT_FUNCTION: |
5148 case HANDLER: | 5007 case HANDLER: |
5149 case INTERCEPTOR: | 5008 case INTERCEPTOR: |
5150 case NULL_DESCRIPTOR: | 5009 case NULL_DESCRIPTOR: |
5151 // We definitely have no map transition. | 5010 // We definitely have no map transition. |
5152 raw_index += 2; | 5011 raw_index += 2; |
5153 ++index; | 5012 ++index; |
5154 break; | 5013 break; |
5155 } | 5014 } |
5156 } | 5015 } |
5016 if (index == descriptor_array_->number_of_descriptors()) { | |
5017 Map* elements_transition = descriptor_array_->elements_transition_map(); | |
5018 if (elements_transition != NULL) { | |
5019 *DescriptorArrayHeader() = Smi::FromInt(index + 1); | |
5020 return elements_transition; | |
5021 } | |
5022 } | |
5157 *DescriptorArrayHeader() = descriptor_array_->GetHeap()->fixed_array_map(); | 5023 *DescriptorArrayHeader() = descriptor_array_->GetHeap()->fixed_array_map(); |
5158 return NULL; | 5024 return NULL; |
5159 } | 5025 } |
5160 | 5026 |
5161 private: | 5027 private: |
5162 bool HasDescriptors() { | |
5163 return descriptor_array_->length() > DescriptorArray::kFirstIndex; | |
5164 } | |
5165 | |
5166 Object** DescriptorArrayHeader() { | 5028 Object** DescriptorArrayHeader() { |
5167 return HeapObject::RawField(descriptor_array_, DescriptorArray::kMapOffset); | 5029 return HeapObject::RawField(descriptor_array_, DescriptorArray::kMapOffset); |
5168 } | 5030 } |
5169 | 5031 |
5170 DescriptorArray* descriptor_array_; | 5032 DescriptorArray* descriptor_array_; |
5171 }; | 5033 }; |
5172 | 5034 |
5173 | 5035 |
5174 // An iterator over all prototype transitions, reusing the map field of the | 5036 // An iterator over all prototype transitions, reusing the map field of the |
5175 // underlying array while it is running. | 5037 // underlying array while it is running. |
(...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5844 bool FixedArray::IsEqualTo(FixedArray* other) { | 5706 bool FixedArray::IsEqualTo(FixedArray* other) { |
5845 if (length() != other->length()) return false; | 5707 if (length() != other->length()) return false; |
5846 for (int i = 0 ; i < length(); ++i) { | 5708 for (int i = 0 ; i < length(); ++i) { |
5847 if (get(i) != other->get(i)) return false; | 5709 if (get(i) != other->get(i)) return false; |
5848 } | 5710 } |
5849 return true; | 5711 return true; |
5850 } | 5712 } |
5851 #endif | 5713 #endif |
5852 | 5714 |
5853 | 5715 |
5854 MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) { | 5716 MaybeObject* DescriptorArray::Allocate(int number_of_descriptors, |
5717 SharedMode shared_mode) { | |
5855 Heap* heap = Isolate::Current()->heap(); | 5718 Heap* heap = Isolate::Current()->heap(); |
5719 // Do not use DescriptorArray::cast on incomplete object. | |
5720 FixedArray* result; | |
5856 if (number_of_descriptors == 0) { | 5721 if (number_of_descriptors == 0) { |
5857 return heap->empty_descriptor_array(); | 5722 if (shared_mode == MAY_BE_SHARED) { |
5723 return heap->empty_descriptor_array(); | |
5724 } | |
5725 { MaybeObject* maybe_array = | |
5726 heap->AllocateFixedArray(kTransitionsIndex + 1); | |
5727 if (!maybe_array->To(&result)) return maybe_array; | |
5728 } | |
5729 } else { | |
5730 // Allocate the array of keys. | |
5731 { MaybeObject* maybe_array = | |
5732 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors)); | |
5733 if (!maybe_array->To(&result)) return maybe_array; | |
5734 } | |
5735 result->set(kEnumerationIndexIndex, | |
5736 Smi::FromInt(PropertyDetails::kInitialIndex)); | |
5858 } | 5737 } |
5859 // Allocate the array of keys. | |
5860 Object* array; | |
5861 { MaybeObject* maybe_array = | |
5862 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors)); | |
5863 if (!maybe_array->ToObject(&array)) return maybe_array; | |
5864 } | |
5865 // Do not use DescriptorArray::cast on incomplete object. | |
5866 FixedArray* result = FixedArray::cast(array); | |
5867 | |
5868 result->set(kBitField3StorageIndex, Smi::FromInt(0)); | 5738 result->set(kBitField3StorageIndex, Smi::FromInt(0)); |
5869 result->set(kEnumerationIndexIndex, | 5739 result->set(kTransitionsIndex, Smi::FromInt(0)); |
5870 Smi::FromInt(PropertyDetails::kInitialIndex)); | |
5871 return result; | 5740 return result; |
5872 } | 5741 } |
5873 | 5742 |
5874 | 5743 |
5875 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, | 5744 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, |
5876 FixedArray* new_cache, | 5745 FixedArray* new_cache, |
5877 Object* new_index_cache) { | 5746 Object* new_index_cache) { |
5878 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength); | 5747 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength); |
5879 ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray()); | 5748 ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray()); |
5880 if (HasEnumCache()) { | 5749 if (HasEnumCache()) { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5962 // We are replacing an existing descriptor. We keep the enumeration index | 5831 // We are replacing an existing descriptor. We keep the enumeration index |
5963 // of a visible property. | 5832 // of a visible property. |
5964 keep_enumeration_index = true; | 5833 keep_enumeration_index = true; |
5965 } else if (remove_transitions) { | 5834 } else if (remove_transitions) { |
5966 // Replaced descriptor has been counted as removed if it is a transition | 5835 // Replaced descriptor has been counted as removed if it is a transition |
5967 // that will be replaced. Adjust count in this case. | 5836 // that will be replaced. Adjust count in this case. |
5968 ++new_size; | 5837 ++new_size; |
5969 } | 5838 } |
5970 | 5839 |
5971 DescriptorArray* new_descriptors; | 5840 DescriptorArray* new_descriptors; |
5972 { MaybeObject* maybe_result = Allocate(new_size); | 5841 { MaybeObject* maybe_result = Allocate(new_size, remove_transitions |
5842 ? MAY_BE_SHARED | |
5843 : CANNOT_BE_SHARED); | |
danno
2012/06/06 09:25:12
nit: strange formatting. Put the *_SHARED value in
| |
5973 if (!maybe_result->To(&new_descriptors)) return maybe_result; | 5844 if (!maybe_result->To(&new_descriptors)) return maybe_result; |
5974 } | 5845 } |
5975 | 5846 |
5976 DescriptorArray::WhitenessWitness witness(new_descriptors); | 5847 DescriptorArray::WhitenessWitness witness(new_descriptors); |
5977 | 5848 |
5978 // Set the enumeration index in the descriptors and set the enumeration index | 5849 // Set the enumeration index in the descriptors and set the enumeration index |
5979 // in the result. | 5850 // in the result. |
5980 int enumeration_index = NextEnumerationIndex(); | 5851 int enumeration_index = NextEnumerationIndex(); |
5981 if (!descriptor->ContainsTransition()) { | 5852 if (!descriptor->ContainsTransition()) { |
5982 if (keep_enumeration_index) { | 5853 if (keep_enumeration_index) { |
5983 descriptor->SetEnumerationIndex(GetDetails(index).index()); | 5854 descriptor->SetEnumerationIndex(GetDetails(index).index()); |
5984 } else { | 5855 } else { |
5985 descriptor->SetEnumerationIndex(enumeration_index); | 5856 descriptor->SetEnumerationIndex(enumeration_index); |
5986 ++enumeration_index; | 5857 ++enumeration_index; |
5987 } | 5858 } |
5988 } | 5859 } |
5860 Map* old_elements_transition = elements_transition_map(); | |
5861 if ((!remove_transitions) && (old_elements_transition != NULL)) { | |
5862 new_descriptors->set_elements_transition_map(old_elements_transition); | |
5863 } | |
5989 new_descriptors->SetNextEnumerationIndex(enumeration_index); | 5864 new_descriptors->SetNextEnumerationIndex(enumeration_index); |
5990 | 5865 |
5991 // Copy the descriptors, filtering out transitions and null descriptors, | 5866 // Copy the descriptors, filtering out transitions and null descriptors, |
5992 // and inserting or replacing a descriptor. | 5867 // and inserting or replacing a descriptor. |
5993 int to_index = 0; | 5868 int to_index = 0; |
5994 int insertion_index = -1; | 5869 int insertion_index = -1; |
5995 int from_index = 0; | 5870 int from_index = 0; |
5996 while (from_index < number_of_descriptors()) { | 5871 while (from_index < number_of_descriptors()) { |
5997 if (insertion_index < 0 && | 5872 if (insertion_index < 0 && |
5998 InsertionPointFound(GetKey(from_index), descriptor->GetKey())) { | 5873 InsertionPointFound(GetKey(from_index), descriptor->GetKey())) { |
5999 insertion_index = to_index++; | 5874 insertion_index = to_index++; |
6000 if (replacing) from_index++; | 5875 if (replacing) from_index++; |
6001 } else { | 5876 } else { |
6002 if (!(IsNullDescriptor(from_index) || | 5877 if (!(IsNullDescriptor(from_index) || |
6003 (remove_transitions && IsTransitionOnly(from_index)))) { | 5878 (remove_transitions && IsTransitionOnly(from_index)))) { |
6004 MaybeObject* copy_result = | 5879 MaybeObject* copy_result = |
6005 new_descriptors->CopyFrom(to_index++, this, from_index, witness); | 5880 new_descriptors->CopyFrom(to_index++, this, from_index, witness); |
6006 if (copy_result->IsFailure()) return copy_result; | 5881 if (copy_result->IsFailure()) return copy_result; |
6007 } | 5882 } |
6008 from_index++; | 5883 from_index++; |
6009 } | 5884 } |
6010 } | 5885 } |
6011 if (insertion_index < 0) insertion_index = to_index++; | 5886 if (insertion_index < 0) insertion_index = to_index++; |
5887 | |
5888 ASSERT(insertion_index < new_descriptors->number_of_descriptors()); | |
6012 new_descriptors->Set(insertion_index, descriptor, witness); | 5889 new_descriptors->Set(insertion_index, descriptor, witness); |
6013 | 5890 |
6014 ASSERT(to_index == new_descriptors->number_of_descriptors()); | 5891 ASSERT(to_index == new_descriptors->number_of_descriptors()); |
6015 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); | 5892 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); |
6016 | 5893 |
6017 return new_descriptors; | 5894 return new_descriptors; |
6018 } | 5895 } |
6019 | 5896 |
6020 | 5897 |
6021 MaybeObject* DescriptorArray::RemoveTransitions() { | 5898 MaybeObject* DescriptorArray::RemoveTransitions(SharedMode shared_mode) { |
6022 // Allocate the new descriptor array. | 5899 // Allocate the new descriptor array. |
6023 int new_number_of_descriptors = 0; | 5900 int new_number_of_descriptors = 0; |
6024 for (int i = 0; i < number_of_descriptors(); i++) { | 5901 for (int i = 0; i < number_of_descriptors(); i++) { |
6025 if (IsProperty(i)) new_number_of_descriptors++; | 5902 if (IsProperty(i)) new_number_of_descriptors++; |
6026 } | 5903 } |
6027 DescriptorArray* new_descriptors; | 5904 DescriptorArray* new_descriptors; |
6028 { MaybeObject* maybe_result = Allocate(new_number_of_descriptors); | 5905 { MaybeObject* maybe_result = Allocate(new_number_of_descriptors, |
5906 shared_mode); | |
6029 if (!maybe_result->To(&new_descriptors)) return maybe_result; | 5907 if (!maybe_result->To(&new_descriptors)) return maybe_result; |
6030 } | 5908 } |
6031 | 5909 |
6032 // Copy the content. | 5910 // Copy the content. |
6033 DescriptorArray::WhitenessWitness witness(new_descriptors); | 5911 DescriptorArray::WhitenessWitness witness(new_descriptors); |
6034 int next_descriptor = 0; | 5912 int next_descriptor = 0; |
6035 for (int i = 0; i < number_of_descriptors(); i++) { | 5913 for (int i = 0; i < number_of_descriptors(); i++) { |
6036 if (IsProperty(i)) { | 5914 if (IsProperty(i)) { |
6037 MaybeObject* copy_result = | 5915 MaybeObject* copy_result = |
6038 new_descriptors->CopyFrom(next_descriptor++, this, i, witness); | 5916 new_descriptors->CopyFrom(next_descriptor++, this, i, witness); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6102 | 5980 |
6103 | 5981 |
6104 void DescriptorArray::Sort(const WhitenessWitness& witness) { | 5982 void DescriptorArray::Sort(const WhitenessWitness& witness) { |
6105 SortUnchecked(witness); | 5983 SortUnchecked(witness); |
6106 SLOW_ASSERT(IsSortedNoDuplicates()); | 5984 SLOW_ASSERT(IsSortedNoDuplicates()); |
6107 } | 5985 } |
6108 | 5986 |
6109 | 5987 |
6110 int DescriptorArray::BinarySearch(String* name, int low, int high) { | 5988 int DescriptorArray::BinarySearch(String* name, int low, int high) { |
6111 uint32_t hash = name->Hash(); | 5989 uint32_t hash = name->Hash(); |
5990 int limit = high; | |
6112 | 5991 |
6113 while (low <= high) { | 5992 ASSERT(low <= high); |
5993 | |
5994 while (low != high) { | |
6114 int mid = (low + high) / 2; | 5995 int mid = (low + high) / 2; |
6115 String* mid_name = GetKey(mid); | 5996 String* mid_name = GetKey(mid); |
6116 uint32_t mid_hash = mid_name->Hash(); | 5997 uint32_t mid_hash = mid_name->Hash(); |
6117 | 5998 |
6118 if (mid_hash > hash) { | 5999 if (mid_hash >= hash) { |
6119 high = mid - 1; | 6000 high = mid; |
6120 continue; | 6001 } else { |
6002 low = mid + 1; | |
6121 } | 6003 } |
6122 if (mid_hash < hash) { | |
6123 low = mid + 1; | |
6124 continue; | |
6125 } | |
6126 // Found an element with the same hash-code. | |
6127 ASSERT(hash == mid_hash); | |
6128 // There might be more, so we find the first one and | |
6129 // check them all to see if we have a match. | |
6130 if (name == mid_name && !IsNullDescriptor(mid)) return mid; | |
6131 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--; | |
6132 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) { | |
6133 if (GetKey(mid)->Equals(name) && !IsNullDescriptor(mid)) return mid; | |
6134 } | |
6135 break; | |
6136 } | 6004 } |
6005 | |
6006 for (; low <= limit && GetKey(low)->Hash() == hash; ++low) { | |
6007 if (GetKey(low)->Equals(name) && !IsNullDescriptor(low)) | |
6008 return low; | |
6009 } | |
6010 | |
6137 return kNotFound; | 6011 return kNotFound; |
6138 } | 6012 } |
6139 | 6013 |
6140 | 6014 |
6141 int DescriptorArray::LinearSearch(String* name, int len) { | 6015 int DescriptorArray::LinearSearch(SearchMode mode, String* name, int len) { |
6142 uint32_t hash = name->Hash(); | 6016 uint32_t hash = name->Hash(); |
6143 for (int number = 0; number < len; number++) { | 6017 for (int number = 0; number < len; number++) { |
6144 String* entry = GetKey(number); | 6018 String* entry = GetKey(number); |
6145 if ((entry->Hash() == hash) && | 6019 if (mode == EXPECT_SORTED && entry->Hash() > hash) break; |
6146 name->Equals(entry) && | 6020 if (name->Equals(entry) && !IsNullDescriptor(number)) { |
6147 !IsNullDescriptor(number)) { | |
6148 return number; | 6021 return number; |
6149 } | 6022 } |
6150 } | 6023 } |
6151 return kNotFound; | 6024 return kNotFound; |
6152 } | 6025 } |
6153 | 6026 |
6154 | 6027 |
6155 MaybeObject* AccessorPair::CopyWithoutTransitions() { | 6028 MaybeObject* AccessorPair::CopyWithoutTransitions() { |
6156 Heap* heap = GetHeap(); | 6029 Heap* heap = GetHeap(); |
6157 AccessorPair* copy; | 6030 AccessorPair* copy; |
(...skipping 1263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7421 // live. If not, null the descriptor. Also drop the back pointer for that | 7294 // live. If not, null the descriptor. Also drop the back pointer for that |
7422 // map transition, so that this map is not reached again by following a back | 7295 // map transition, so that this map is not reached again by following a back |
7423 // pointer from that non-live map. | 7296 // pointer from that non-live map. |
7424 bool keep_entry = false; | 7297 bool keep_entry = false; |
7425 PropertyDetails details(d->GetDetails(i)); | 7298 PropertyDetails details(d->GetDetails(i)); |
7426 switch (details.type()) { | 7299 switch (details.type()) { |
7427 case MAP_TRANSITION: | 7300 case MAP_TRANSITION: |
7428 case CONSTANT_TRANSITION: | 7301 case CONSTANT_TRANSITION: |
7429 ClearBackPointer(heap, d->GetValue(i), &keep_entry); | 7302 ClearBackPointer(heap, d->GetValue(i), &keep_entry); |
7430 break; | 7303 break; |
7431 case ELEMENTS_TRANSITION: { | |
7432 Object* object = d->GetValue(i); | |
7433 if (object->IsMap()) { | |
7434 ClearBackPointer(heap, object, &keep_entry); | |
7435 } else { | |
7436 FixedArray* array = FixedArray::cast(object); | |
7437 for (int j = 0; j < array->length(); ++j) { | |
7438 if (ClearBackPointer(heap, array->get(j), &keep_entry)) { | |
7439 array->set_undefined(j); | |
7440 } | |
7441 } | |
7442 } | |
7443 break; | |
7444 } | |
7445 case CALLBACKS: { | 7304 case CALLBACKS: { |
7446 Object* object = d->GetValue(i); | 7305 Object* object = d->GetValue(i); |
7447 if (object->IsAccessorPair()) { | 7306 if (object->IsAccessorPair()) { |
7448 AccessorPair* accessors = AccessorPair::cast(object); | 7307 AccessorPair* accessors = AccessorPair::cast(object); |
7449 if (ClearBackPointer(heap, accessors->getter(), &keep_entry)) { | 7308 if (ClearBackPointer(heap, accessors->getter(), &keep_entry)) { |
7450 accessors->set_getter(heap->the_hole_value()); | 7309 accessors->set_getter(heap->the_hole_value()); |
7451 } | 7310 } |
7452 if (ClearBackPointer(heap, accessors->setter(), &keep_entry)) { | 7311 if (ClearBackPointer(heap, accessors->setter(), &keep_entry)) { |
7453 accessors->set_setter(heap->the_hole_value()); | 7312 accessors->set_setter(heap->the_hole_value()); |
7454 } | 7313 } |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7594 } | 7453 } |
7595 | 7454 |
7596 | 7455 |
7597 MaybeObject* JSFunction::SetInstancePrototype(Object* value) { | 7456 MaybeObject* JSFunction::SetInstancePrototype(Object* value) { |
7598 ASSERT(value->IsJSReceiver()); | 7457 ASSERT(value->IsJSReceiver()); |
7599 Heap* heap = GetHeap(); | 7458 Heap* heap = GetHeap(); |
7600 if (has_initial_map()) { | 7459 if (has_initial_map()) { |
7601 // If the function has allocated the initial map | 7460 // If the function has allocated the initial map |
7602 // replace it with a copy containing the new prototype. | 7461 // replace it with a copy containing the new prototype. |
7603 Map* new_map; | 7462 Map* new_map; |
7604 MaybeObject* maybe_new_map = initial_map()->CopyDropTransitions(); | 7463 MaybeObject* maybe_new_map = |
7464 initial_map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); | |
7605 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | 7465 if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
7606 new_map->set_prototype(value); | 7466 new_map->set_prototype(value); |
7607 MaybeObject* maybe_object = | 7467 MaybeObject* maybe_object = |
7608 set_initial_map_and_cache_transitions(new_map); | 7468 set_initial_map_and_cache_transitions(new_map); |
7609 if (maybe_object->IsFailure()) return maybe_object; | 7469 if (maybe_object->IsFailure()) return maybe_object; |
7610 } else { | 7470 } else { |
7611 // Put the value in the initial map field until an initial map is | 7471 // Put the value in the initial map field until an initial map is |
7612 // needed. At that point, a new initial map is created and the | 7472 // needed. At that point, a new initial map is created and the |
7613 // prototype is put into the initial map where it belongs. | 7473 // prototype is put into the initial map where it belongs. |
7614 set_prototype_or_initial_map(value); | 7474 set_prototype_or_initial_map(value); |
7615 } | 7475 } |
7616 heap->ClearInstanceofCache(); | 7476 heap->ClearInstanceofCache(); |
7617 return value; | 7477 return value; |
7618 } | 7478 } |
7619 | 7479 |
7620 | 7480 |
7621 MaybeObject* JSFunction::SetPrototype(Object* value) { | 7481 MaybeObject* JSFunction::SetPrototype(Object* value) { |
7622 ASSERT(should_have_prototype()); | 7482 ASSERT(should_have_prototype()); |
7623 Object* construct_prototype = value; | 7483 Object* construct_prototype = value; |
7624 | 7484 |
7625 // If the value is not a JSReceiver, store the value in the map's | 7485 // If the value is not a JSReceiver, store the value in the map's |
7626 // constructor field so it can be accessed. Also, set the prototype | 7486 // constructor field so it can be accessed. Also, set the prototype |
7627 // used for constructing objects to the original object prototype. | 7487 // used for constructing objects to the original object prototype. |
7628 // See ECMA-262 13.2.2. | 7488 // See ECMA-262 13.2.2. |
7629 if (!value->IsJSReceiver()) { | 7489 if (!value->IsJSReceiver()) { |
7630 // Copy the map so this does not affect unrelated functions. | 7490 // Copy the map so this does not affect unrelated functions. |
7631 // Remove map transitions because they point to maps with a | 7491 // Remove map transitions because they point to maps with a |
7632 // different prototype. | 7492 // different prototype. |
7633 Map* new_map; | 7493 Map* new_map; |
7634 { MaybeObject* maybe_new_map = map()->CopyDropTransitions(); | 7494 { MaybeObject* maybe_new_map = |
7495 map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); | |
7635 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | 7496 if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
7636 } | 7497 } |
7637 Heap* heap = new_map->GetHeap(); | 7498 Heap* heap = new_map->GetHeap(); |
7638 set_map(new_map); | 7499 set_map(new_map); |
7639 new_map->set_constructor(value); | 7500 new_map->set_constructor(value); |
7640 new_map->set_non_instance_prototype(true); | 7501 new_map->set_non_instance_prototype(true); |
7641 construct_prototype = | 7502 construct_prototype = |
7642 heap->isolate()->context()->global_context()-> | 7503 heap->isolate()->context()->global_context()-> |
7643 initial_object_prototype(); | 7504 initial_object_prototype(); |
7644 } else { | 7505 } else { |
(...skipping 846 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8491 | 8352 |
8492 const char* Code::PropertyType2String(PropertyType type) { | 8353 const char* Code::PropertyType2String(PropertyType type) { |
8493 switch (type) { | 8354 switch (type) { |
8494 case NORMAL: return "NORMAL"; | 8355 case NORMAL: return "NORMAL"; |
8495 case FIELD: return "FIELD"; | 8356 case FIELD: return "FIELD"; |
8496 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION"; | 8357 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION"; |
8497 case CALLBACKS: return "CALLBACKS"; | 8358 case CALLBACKS: return "CALLBACKS"; |
8498 case HANDLER: return "HANDLER"; | 8359 case HANDLER: return "HANDLER"; |
8499 case INTERCEPTOR: return "INTERCEPTOR"; | 8360 case INTERCEPTOR: return "INTERCEPTOR"; |
8500 case MAP_TRANSITION: return "MAP_TRANSITION"; | 8361 case MAP_TRANSITION: return "MAP_TRANSITION"; |
8501 case ELEMENTS_TRANSITION: return "ELEMENTS_TRANSITION"; | |
8502 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION"; | 8362 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION"; |
8503 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR"; | 8363 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR"; |
8504 } | 8364 } |
8505 UNREACHABLE(); // keep the compiler happy | 8365 UNREACHABLE(); // keep the compiler happy |
8506 return NULL; | 8366 return NULL; |
8507 } | 8367 } |
8508 | 8368 |
8509 | 8369 |
8510 void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) { | 8370 void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) { |
8511 const char* name = NULL; | 8371 const char* name = NULL; |
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8882 } | 8742 } |
8883 | 8743 |
8884 // Set the new prototype of the object. | 8744 // Set the new prototype of the object. |
8885 Map* map = real_receiver->map(); | 8745 Map* map = real_receiver->map(); |
8886 | 8746 |
8887 // Nothing to do if prototype is already set. | 8747 // Nothing to do if prototype is already set. |
8888 if (map->prototype() == value) return value; | 8748 if (map->prototype() == value) return value; |
8889 | 8749 |
8890 Object* new_map = map->GetPrototypeTransition(value); | 8750 Object* new_map = map->GetPrototypeTransition(value); |
8891 if (new_map == NULL) { | 8751 if (new_map == NULL) { |
8892 { MaybeObject* maybe_new_map = map->CopyDropTransitions(); | 8752 { MaybeObject* maybe_new_map = |
8753 map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); | |
8893 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; | 8754 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; |
8894 } | 8755 } |
8895 | 8756 |
8896 { MaybeObject* maybe_new_cache = | 8757 { MaybeObject* maybe_new_cache = |
8897 map->PutPrototypeTransition(value, Map::cast(new_map)); | 8758 map->PutPrototypeTransition(value, Map::cast(new_map)); |
8898 if (maybe_new_cache->IsFailure()) return maybe_new_cache; | 8759 if (maybe_new_cache->IsFailure()) return maybe_new_cache; |
8899 } | 8760 } |
8900 | 8761 |
8901 Map::cast(new_map)->set_prototype(value); | 8762 Map::cast(new_map)->set_prototype(value); |
8902 } | 8763 } |
(...skipping 2260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
11163 entry = NextProbe(entry, count++, capacity); | 11024 entry = NextProbe(entry, count++, capacity); |
11164 } | 11025 } |
11165 return kNotFound; | 11026 return kNotFound; |
11166 } | 11027 } |
11167 | 11028 |
11168 | 11029 |
11169 bool StringDictionary::ContainsTransition(int entry) { | 11030 bool StringDictionary::ContainsTransition(int entry) { |
11170 switch (DetailsAt(entry).type()) { | 11031 switch (DetailsAt(entry).type()) { |
11171 case MAP_TRANSITION: | 11032 case MAP_TRANSITION: |
11172 case CONSTANT_TRANSITION: | 11033 case CONSTANT_TRANSITION: |
11173 case ELEMENTS_TRANSITION: | |
11174 return true; | 11034 return true; |
11175 case CALLBACKS: { | 11035 case CALLBACKS: { |
11176 Object* value = ValueAt(entry); | 11036 Object* value = ValueAt(entry); |
11177 if (!value->IsAccessorPair()) return false; | 11037 if (!value->IsAccessorPair()) return false; |
11178 AccessorPair* accessors = AccessorPair::cast(value); | 11038 AccessorPair* accessors = AccessorPair::cast(value); |
11179 return accessors->getter()->IsMap() || accessors->setter()->IsMap(); | 11039 return accessors->getter()->IsMap() || accessors->setter()->IsMap(); |
11180 } | 11040 } |
11181 case NORMAL: | 11041 case NORMAL: |
11182 case FIELD: | 11042 case FIELD: |
11183 case CONSTANT_FUNCTION: | 11043 case CONSTANT_FUNCTION: |
(...skipping 1429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12613 if (type == NORMAL && | 12473 if (type == NORMAL && |
12614 (!value->IsJSFunction() || heap->InNewSpace(value))) { | 12474 (!value->IsJSFunction() || heap->InNewSpace(value))) { |
12615 number_of_fields += 1; | 12475 number_of_fields += 1; |
12616 } | 12476 } |
12617 } | 12477 } |
12618 } | 12478 } |
12619 | 12479 |
12620 // Allocate the instance descriptor. | 12480 // Allocate the instance descriptor. |
12621 DescriptorArray* descriptors; | 12481 DescriptorArray* descriptors; |
12622 { MaybeObject* maybe_descriptors = | 12482 { MaybeObject* maybe_descriptors = |
12623 DescriptorArray::Allocate(instance_descriptor_length); | 12483 DescriptorArray::Allocate(instance_descriptor_length, |
12484 DescriptorArray::MAY_BE_SHARED); | |
12624 if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) { | 12485 if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) { |
12625 return maybe_descriptors; | 12486 return maybe_descriptors; |
12626 } | 12487 } |
12627 } | 12488 } |
12628 | 12489 |
12629 DescriptorArray::WhitenessWitness witness(descriptors); | 12490 DescriptorArray::WhitenessWitness witness(descriptors); |
12630 | 12491 |
12631 int inobject_props = obj->map()->inobject_properties(); | 12492 int inobject_props = obj->map()->inobject_properties(); |
12632 int number_of_allocated_fields = | 12493 int number_of_allocated_fields = |
12633 number_of_fields + unused_property_fields - inobject_props; | 12494 number_of_fields + unused_property_fields - inobject_props; |
(...skipping 583 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
13217 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); | 13078 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); |
13218 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); | 13079 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); |
13219 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); | 13080 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); |
13220 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); | 13081 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); |
13221 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); | 13082 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); |
13222 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); | 13083 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); |
13223 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); | 13084 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); |
13224 } | 13085 } |
13225 | 13086 |
13226 } } // namespace v8::internal | 13087 } } // namespace v8::internal |
OLD | NEW |