Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(603)

Side by Side Diff: src/objects.cc

Issue 8166017: Track elements_kind transitions in KeyedStoreICs. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: fix nits Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ic.cc ('k') | src/runtime.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 1077 matching lines...) Expand 10 before | Expand all | Expand 10 after
1088 if (IsString()) { 1088 if (IsString()) {
1089 String::cast(this)->StringShortPrint(accumulator); 1089 String::cast(this)->StringShortPrint(accumulator);
1090 return; 1090 return;
1091 } 1091 }
1092 if (IsJSObject()) { 1092 if (IsJSObject()) {
1093 JSObject::cast(this)->JSObjectShortPrint(accumulator); 1093 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1094 return; 1094 return;
1095 } 1095 }
1096 switch (map()->instance_type()) { 1096 switch (map()->instance_type()) {
1097 case MAP_TYPE: 1097 case MAP_TYPE:
1098 accumulator->Add("<Map>"); 1098 accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
1099 break; 1099 break;
1100 case FIXED_ARRAY_TYPE: 1100 case FIXED_ARRAY_TYPE:
1101 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length()); 1101 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1102 break; 1102 break;
1103 case BYTE_ARRAY_TYPE: 1103 case BYTE_ARRAY_TYPE:
1104 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length()); 1104 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1105 break; 1105 break;
1106 case FREE_SPACE_TYPE: 1106 case FREE_SPACE_TYPE:
1107 accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size()); 1107 accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size());
1108 break; 1108 break;
(...skipping 1045 matching lines...) Expand 10 before | Expand all | Expand 10 after
2154 int i = 0; 2154 int i = 0;
2155 while (i < array->length()) { 2155 while (i < array->length()) {
2156 new_array->set(i, array->get(i)); 2156 new_array->set(i, array->get(i));
2157 ++i; 2157 ++i;
2158 } 2158 }
2159 new_array->set(i, new_map); 2159 new_array->set(i, new_map);
2160 return new_array; 2160 return new_array;
2161 } 2161 }
2162 2162
2163 2163
2164 MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind elements_kind) { 2164 // Returns the contents of |map|'s descriptor array for the given string
2165 // (which might be NULL). |safe_to_add_transition| is set to false and NULL
2166 // is returned if adding transitions is not allowed.
2167 static Object* GetDescriptorContents(Map* map,
2168 String* sentinel_name,
2169 bool* safe_to_add_transition) {
2170 // Get the cached index for the descriptors lookup, or find and cache it.
2171 DescriptorArray* descriptors = map->instance_descriptors();
2172 DescriptorLookupCache* cache = map->GetIsolate()->descriptor_lookup_cache();
2173 int index = cache->Lookup(descriptors, sentinel_name);
2174 if (index == DescriptorLookupCache::kAbsent) {
2175 index = descriptors->Search(sentinel_name);
2176 cache->Update(descriptors, sentinel_name, index);
2177 }
2178 // If the transition already exists, return its descriptor.
2179 if (index != DescriptorArray::kNotFound) {
2180 PropertyDetails details(descriptors->GetDetails(index));
2181 if (details.type() == ELEMENTS_TRANSITION) {
2182 return descriptors->GetValue(index);
2183 } else {
2184 *safe_to_add_transition = false;
2185 }
2186 }
2187 return NULL;
2188 }
2189
2190
2191 // Returns the map that |original_map| transitions to if its elements_kind
2192 // is changed to |elements_kind|, or NULL if no such map is cached yet.
2193 // |safe_to_add_transitions| is set to false if adding transitions is not
2194 // allowed.
2195 static Map* LookupElementsTransitionMap(Map* original_map,
2196 ElementsKind elements_kind,
2197 String* sentinel_name,
2198 bool* safe_to_add_transition) {
2199 // Special case: indirect SMI->FAST transition (cf. comment in
2200 // AddElementsTransition()).
2201 if (original_map->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2202 elements_kind == FAST_ELEMENTS) {
2203 Map* double_map = LookupElementsTransitionMap(
2204 original_map,
2205 FAST_DOUBLE_ELEMENTS,
2206 sentinel_name,
2207 safe_to_add_transition);
2208 if (double_map == NULL) return double_map;
2209 return LookupElementsTransitionMap(double_map,
2210 FAST_ELEMENTS,
2211 sentinel_name,
2212 safe_to_add_transition);
2213 }
2214 Object* descriptor_contents = GetDescriptorContents(
2215 original_map, sentinel_name, safe_to_add_transition);
2216 if (descriptor_contents != NULL) {
2217 Map* maybe_transition_map =
2218 GetElementsTransitionMapFromDescriptor(descriptor_contents,
2219 elements_kind);
2220 ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap());
2221 return maybe_transition_map;
2222 }
2223 return NULL;
2224 }
2225
2226
2227 // Adds an entry to |original_map|'s descriptor array for a transition to
2228 // |transitioned_map| when its elements_kind is changed to |elements_kind|,
2229 // using |sentinel_name| as key for the entry.
2230 static MaybeObject* AddElementsTransition(Map* original_map,
2231 ElementsKind elements_kind,
2232 Map* transitioned_map,
2233 String* sentinel_name) {
2234 // The map transition graph should be a tree, therefore the transition
2235 // from SMI to FAST elements is not done directly, but by going through
2236 // DOUBLE elements first.
2237 if (original_map->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2238 elements_kind == FAST_ELEMENTS) {
2239 bool safe_to_add = true;
2240 Map* double_map = LookupElementsTransitionMap(
2241 original_map, FAST_DOUBLE_ELEMENTS, sentinel_name, &safe_to_add);
2242 // This method is only called when safe_to_add_transition has been found
2243 // to be true earlier.
2244 ASSERT(safe_to_add);
2245
2246 if (double_map == NULL) {
2247 MaybeObject* maybe_map = original_map->CopyDropTransitions();
2248 if (!maybe_map->To(&double_map)) return maybe_map;
2249 double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
2250 MaybeObject* maybe_double_transition = AddElementsTransition(
2251 original_map, FAST_DOUBLE_ELEMENTS, double_map, sentinel_name);
2252 if (maybe_double_transition->IsFailure()) return maybe_double_transition;
2253 }
2254 return AddElementsTransition(
2255 double_map, FAST_ELEMENTS, transitioned_map, sentinel_name);
2256 }
2257
2258 DescriptorArray* descriptors = original_map->instance_descriptors();
2259 bool safe_to_add_transition = true;
2260 Object* descriptor_contents = GetDescriptorContents(
2261 original_map, sentinel_name, &safe_to_add_transition);
2262 // This method is only called when safe_to_add_transition has been found
2263 // to be true earlier.
2264 ASSERT(safe_to_add_transition);
2265 MaybeObject* maybe_new_contents =
2266 AddElementsTransitionMapToDescriptor(descriptor_contents,
2267 transitioned_map);
2268 Object* new_contents;
2269 if (!maybe_new_contents->ToObject(&new_contents)) {
2270 return maybe_new_contents;
2271 }
2272
2273 ElementsTransitionDescriptor desc(sentinel_name, new_contents);
2274 Object* new_descriptors;
2275 MaybeObject* maybe_new_descriptors =
2276 descriptors->CopyInsert(&desc, KEEP_TRANSITIONS);
2277 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2278 return maybe_new_descriptors;
2279 }
2280 descriptors = DescriptorArray::cast(new_descriptors);
2281 original_map->set_instance_descriptors(descriptors);
2282 return original_map;
2283 }
2284
2285
2286 MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind to_kind) {
2165 Heap* current_heap = GetHeap(); 2287 Heap* current_heap = GetHeap();
2166 Map* current_map = map(); 2288 Map* current_map = map();
2167 DescriptorArray* descriptors = current_map->instance_descriptors(); 2289 ElementsKind from_kind = current_map->elements_kind();
2168 String* elements_transition_sentinel_name = current_heap->empty_symbol(); 2290 String* elements_transition_sentinel_name = current_heap->empty_symbol();
2169 2291
2170 if (current_map->elements_kind() == elements_kind) return current_map; 2292 if (from_kind == to_kind) return current_map;
2171 2293
2172 // Only objects with FastProperties can have DescriptorArrays and can track 2294 // Only objects with FastProperties can have DescriptorArrays and can track
2173 // element-related maps. Also don't add descriptors to maps that are shared. 2295 // element-related maps. Also don't add descriptors to maps that are shared.
2174 bool safe_to_add_transition = HasFastProperties() && 2296 bool safe_to_add_transition = HasFastProperties() &&
2175 !current_map->IsUndefined() && 2297 !current_map->IsUndefined() &&
2176 !current_map->is_shared(); 2298 !current_map->is_shared();
2177 2299
2178 // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps cause by objects 2300 // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps caused by objects
2179 // with elements that switch back and forth between dictionary and fast 2301 // with elements that switch back and forth between dictionary and fast
2180 // element mode. 2302 // element mode.
2181 if ((current_map->elements_kind() == DICTIONARY_ELEMENTS && 2303 if (from_kind == DICTIONARY_ELEMENTS && to_kind == FAST_ELEMENTS) {
2182 elements_kind == FAST_ELEMENTS)) {
2183 safe_to_add_transition = false; 2304 safe_to_add_transition = false;
2184 } 2305 }
2185 2306
2186 Object* descriptor_contents = NULL;
2187 if (safe_to_add_transition) { 2307 if (safe_to_add_transition) {
2188 // It's only safe to manipulate the descriptor array if it would be 2308 // It's only safe to manipulate the descriptor array if it would be
2189 // safe to add a transition. 2309 // safe to add a transition.
2190 2310 Map* maybe_transition_map = LookupElementsTransitionMap(
2191 // Check if the elements transition already exists. 2311 current_map, to_kind, elements_transition_sentinel_name,
2192 DescriptorLookupCache* cache = 2312 &safe_to_add_transition);
2193 current_heap->isolate()->descriptor_lookup_cache(); 2313 if (maybe_transition_map != NULL) {
2194 int index = cache->Lookup(descriptors, elements_transition_sentinel_name); 2314 return maybe_transition_map;
2195 if (index == DescriptorLookupCache::kAbsent) {
2196 index = descriptors->Search(elements_transition_sentinel_name);
2197 cache->Update(descriptors,
2198 elements_transition_sentinel_name,
2199 index);
2200 }
2201
2202 // If the transition already exists, check the type. If there is a match,
2203 // return it.
2204 if (index != DescriptorArray::kNotFound) {
2205 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index)));
2206 if (details.type() == ELEMENTS_TRANSITION) {
2207 descriptor_contents = descriptors->GetValue(index);
2208 Map* maybe_transition_map =
2209 GetElementsTransitionMapFromDescriptor(descriptor_contents,
2210 elements_kind);
2211 if (maybe_transition_map != NULL) {
2212 ASSERT(maybe_transition_map->IsMap());
2213 return maybe_transition_map;
2214 }
2215 } else {
2216 safe_to_add_transition = false;
2217 }
2218 } 2315 }
2219 } 2316 }
2220 2317
2318 Map* new_map = NULL;
2319
2221 // No transition to an existing map for the given ElementsKind. Make a new 2320 // No transition to an existing map for the given ElementsKind. Make a new
2222 // one. 2321 // one.
2223 Object* obj;
2224 { MaybeObject* maybe_map = current_map->CopyDropTransitions(); 2322 { MaybeObject* maybe_map = current_map->CopyDropTransitions();
2225 if (!maybe_map->ToObject(&obj)) return maybe_map; 2323 if (!maybe_map->To(&new_map)) return maybe_map;
2226 } 2324 }
2227 Map* new_map = Map::cast(obj);
2228 2325
2229 new_map->set_elements_kind(elements_kind); 2326 new_map->set_elements_kind(to_kind);
2230 2327
2231 // Only remember the map transition if the object's map is NOT equal to the 2328 // Only remember the map transition if the object's map is NOT equal to the
2232 // global object_function's map and there is not an already existing 2329 // global object_function's map and there is not an already existing
2233 // non-matching element transition. 2330 // non-matching element transition.
2234 bool allow_map_transition = safe_to_add_transition && 2331 bool allow_map_transition = safe_to_add_transition &&
2235 (GetIsolate()->context()->global_context()->object_function()->map() != 2332 (GetIsolate()->context()->global_context()->object_function()->map() !=
2236 map()); 2333 map());
2237 if (allow_map_transition) { 2334 if (allow_map_transition) {
2238 MaybeObject* maybe_new_contents = 2335 MaybeObject* maybe_transition = AddElementsTransition(
2239 AddElementsTransitionMapToDescriptor(descriptor_contents, new_map); 2336 current_map, to_kind, new_map, elements_transition_sentinel_name);
2240 Object* new_contents; 2337 if (maybe_transition->IsFailure()) return maybe_transition;
2241 if (!maybe_new_contents->ToObject(&new_contents)) {
2242 return maybe_new_contents;
2243 }
2244
2245 ElementsTransitionDescriptor desc(elements_transition_sentinel_name,
2246 new_contents);
2247 Object* new_descriptors;
2248 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert(
2249 &desc,
2250 KEEP_TRANSITIONS);
2251 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2252 return maybe_new_descriptors;
2253 }
2254 descriptors = DescriptorArray::cast(new_descriptors);
2255 current_map->set_instance_descriptors(descriptors);
2256 } 2338 }
2257
2258 return new_map; 2339 return new_map;
2259 } 2340 }
2260 2341
2261 2342
2262 void JSObject::LocalLookupRealNamedProperty(String* name, 2343 void JSObject::LocalLookupRealNamedProperty(String* name,
2263 LookupResult* result) { 2344 LookupResult* result) {
2264 if (IsJSGlobalProxy()) { 2345 if (IsJSGlobalProxy()) {
2265 Object* proto = GetPrototype(); 2346 Object* proto = GetPrototype();
2266 if (proto->IsNull()) return result->NotFound(); 2347 if (proto->IsNull()) return result->NotFound();
2267 ASSERT(proto->IsJSGlobalObject()); 2348 ASSERT(proto->IsJSGlobalObject());
(...skipping 4434 matching lines...) Expand 10 before | Expand all | Expand 10 after
6702 contents->set_unchecked(i + 1, NullDescriptorDetails); 6783 contents->set_unchecked(i + 1, NullDescriptorDetails);
6703 contents->set_null_unchecked(heap, i); 6784 contents->set_null_unchecked(heap, i);
6704 ASSERT(target->prototype() == this || 6785 ASSERT(target->prototype() == this ||
6705 target->prototype() == real_prototype); 6786 target->prototype() == real_prototype);
6706 // Getter prototype() is read-only, set_prototype() has side effects. 6787 // Getter prototype() is read-only, set_prototype() has side effects.
6707 *RawField(target, Map::kPrototypeOffset) = real_prototype; 6788 *RawField(target, Map::kPrototypeOffset) = real_prototype;
6708 } 6789 }
6709 } else { 6790 } else {
6710 ASSERT(object->IsFixedArray()); 6791 ASSERT(object->IsFixedArray());
6711 ASSERT(details.type() == ELEMENTS_TRANSITION); 6792 ASSERT(details.type() == ELEMENTS_TRANSITION);
6712 FixedArray* array = reinterpret_cast<FixedArray*>(contents->get(i)); 6793 FixedArray* array = reinterpret_cast<FixedArray*>(object);
6713 bool reachable_map_found = false; 6794 bool reachable_map_found = false;
6714 for (int j = 0; j < array->length(); ++j) { 6795 for (int j = 0; j < array->length(); ++j) {
6715 Map* target = reinterpret_cast<Map*>(array->get(j)); 6796 Map* target = reinterpret_cast<Map*>(array->get(j));
6716 ASSERT(target->IsHeapObject()); 6797 ASSERT(target->IsHeapObject());
6717 MarkBit map_mark = Marking::MarkBitFrom(target); 6798 MarkBit map_mark = Marking::MarkBitFrom(target);
6718 if (!map_mark.Get()) { 6799 if (!map_mark.Get()) {
6719 ASSERT(target->IsMap()); 6800 ASSERT(target->IsMap());
6720 array->set_undefined(j); 6801 array->set_undefined(j);
6721 ASSERT(target->prototype() == this || 6802 ASSERT(target->prototype() == this ||
6722 target->prototype() == real_prototype); 6803 target->prototype() == real_prototype);
6723 // Getter prototype() is read-only, set_prototype() has side 6804 // Getter prototype() is read-only, set_prototype() has side
6724 // effects. 6805 // effects.
6725 *RawField(target, Map::kPrototypeOffset) = real_prototype; 6806 *RawField(target, Map::kPrototypeOffset) = real_prototype;
6726 } else { 6807 } else if (target->IsMap()) {
6727 reachable_map_found = true; 6808 reachable_map_found = true;
6728 } 6809 }
6729 } 6810 }
6730 // If no map was found, make sure the FixedArray also gets collected. 6811 // If no map was found, make sure the FixedArray also gets collected.
6731 if (!reachable_map_found) { 6812 if (!reachable_map_found) {
6732 contents->set_unchecked(i + 1, NullDescriptorDetails); 6813 contents->set_unchecked(i + 1, NullDescriptorDetails);
6733 contents->set_null_unchecked(heap, i); 6814 contents->set_null_unchecked(heap, i);
6734 } 6815 }
6735 } 6816 }
6736 } 6817 }
(...skipping 5443 matching lines...) Expand 10 before | Expand all | Expand 10 after
12180 if (break_point_objects()->IsUndefined()) return 0; 12261 if (break_point_objects()->IsUndefined()) return 0;
12181 // Single break point. 12262 // Single break point.
12182 if (!break_point_objects()->IsFixedArray()) return 1; 12263 if (!break_point_objects()->IsFixedArray()) return 1;
12183 // Multiple break points. 12264 // Multiple break points.
12184 return FixedArray::cast(break_point_objects())->length(); 12265 return FixedArray::cast(break_point_objects())->length();
12185 } 12266 }
12186 #endif 12267 #endif
12187 12268
12188 12269
12189 } } // namespace v8::internal 12270 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/ic.cc ('k') | src/runtime.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698