OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 1077 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |