Chromium Code Reviews| 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 |