OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/heap/object-stats.h" | 5 #include "src/heap/object-stats.h" |
6 | 6 |
7 #include "src/counters.h" | 7 #include "src/counters.h" |
8 #include "src/heap/heap-inl.h" | 8 #include "src/heap/heap-inl.h" |
9 #include "src/isolate.h" | 9 #include "src/isolate.h" |
10 #include "src/macro-assembler.h" | 10 #include "src/macro-assembler.h" |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 #undef ADJUST_LAST_TIME_OBJECT_COUNT | 154 #undef ADJUST_LAST_TIME_OBJECT_COUNT |
155 | 155 |
156 MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_)); | 156 MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_)); |
157 MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_)); | 157 MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_)); |
158 ClearObjectStats(); | 158 ClearObjectStats(); |
159 } | 159 } |
160 | 160 |
161 | 161 |
162 Isolate* ObjectStats::isolate() { return heap()->isolate(); } | 162 Isolate* ObjectStats::isolate() { return heap()->isolate(); } |
163 | 163 |
164 void ObjectStatsCollector::CollectStatistics(ObjectStats* stats, | 164 void ObjectStatsCollector::CollectStatistics(HeapObject* obj) { |
165 HeapObject* obj) { | |
166 Map* map = obj->map(); | 165 Map* map = obj->map(); |
167 Heap* heap = obj->GetHeap(); | |
168 | 166 |
169 // Record for the InstanceType. | 167 // Record for the InstanceType. |
170 int object_size = obj->Size(); | 168 int object_size = obj->Size(); |
171 stats->RecordObjectStats(map->instance_type(), object_size); | 169 stats_->RecordObjectStats(map->instance_type(), object_size); |
172 | 170 |
173 // Record specific sub types where possible. | 171 // Record specific sub types where possible. |
174 if (obj->IsMap()) { | 172 if (obj->IsMap()) RecordMapDetails(Map::cast(obj)); |
175 RecordMapDetails(stats, heap, obj); | 173 if (obj->IsCode()) RecordCodeDetails(Code::cast(obj)); |
| 174 if (obj->IsSharedFunctionInfo()) { |
| 175 RecordSharedFunctionInfoDetails(SharedFunctionInfo::cast(obj)); |
176 } | 176 } |
177 if (obj->IsCode()) { | 177 if (obj->IsFixedArray()) RecordFixedArrayDetails(FixedArray::cast(obj)); |
178 RecordCodeDetails(stats, heap, obj); | 178 if (obj->IsJSObject()) RecordJSObjectDetails(JSObject::cast(obj)); |
| 179 if (obj->IsJSWeakCollection()) { |
| 180 RecordJSWeakCollectionDetails(JSWeakCollection::cast(obj)); |
179 } | 181 } |
180 if (obj->IsSharedFunctionInfo()) { | 182 if (obj->IsJSCollection()) { |
181 RecordSharedFunctionInfoDetails(stats, heap, obj); | 183 RecordJSCollectionDetails(JSObject::cast(obj)); |
182 } | 184 } |
183 if (obj->IsFixedArray()) { | 185 if (obj->IsJSFunction()) RecordJSFunctionDetails(JSFunction::cast(obj)); |
184 RecordFixedArrayDetails(stats, heap, obj); | 186 if (obj->IsScript()) RecordScriptDetails(Script::cast(obj)); |
185 } | 187 } |
186 if (obj->IsJSObject()) { | 188 |
187 RecordJSObjectDetails(stats, heap, JSObject::cast(obj)); | 189 void ObjectStatsCollector::CollectGlobalStatistics() { |
188 } | 190 // Global FixedArrays. |
189 if (obj->IsJSWeakCollection()) { | 191 RecordFixedArrayHelper(nullptr, heap_->weak_new_space_object_to_code_list(), |
190 RecordJSWeakCollectionDetails(stats, heap, JSWeakCollection::cast(obj)); | 192 WEAK_NEW_SPACE_OBJECT_TO_CODE_SUB_TYPE, 0); |
191 } | 193 RecordFixedArrayHelper(nullptr, heap_->serialized_templates(), |
192 if (obj->IsScript()) { | 194 SERIALIZED_TEMPLATES_SUB_TYPE, 0); |
193 RecordScriptDetails(stats, heap, Script::cast(obj)); | 195 RecordFixedArrayHelper(nullptr, heap_->number_string_cache(), |
194 } | 196 NUMBER_STRING_CACHE_SUB_TYPE, 0); |
| 197 RecordFixedArrayHelper(nullptr, heap_->single_character_string_cache(), |
| 198 SINGLE_CHARACTER_STRING_CACHE_SUB_TYPE, 0); |
| 199 RecordFixedArrayHelper(nullptr, heap_->string_split_cache(), |
| 200 STRING_SPLIT_CACHE_SUB_TYPE, 0); |
| 201 RecordFixedArrayHelper(nullptr, heap_->regexp_multiple_cache(), |
| 202 REGEXP_MULTIPLE_CACHE_SUB_TYPE, 0); |
| 203 RecordFixedArrayHelper(nullptr, heap_->retained_maps(), |
| 204 RETAINED_MAPS_SUB_TYPE, 0); |
| 205 |
| 206 // Global weak FixedArrays. |
| 207 RecordFixedArrayHelper( |
| 208 nullptr, WeakFixedArray::cast(heap_->noscript_shared_function_infos()), |
| 209 NOSCRIPT_SHARED_FUNCTION_INFOS_SUB_TYPE, 0); |
| 210 RecordFixedArrayHelper(nullptr, WeakFixedArray::cast(heap_->script_list()), |
| 211 SCRIPT_LIST_SUB_TYPE, 0); |
| 212 |
| 213 // Global hash tables. |
| 214 RecordHashTableHelper(nullptr, heap_->string_table(), STRING_TABLE_SUB_TYPE); |
| 215 RecordHashTableHelper(nullptr, heap_->weak_object_to_code_table(), |
| 216 OBJECT_TO_CODE_SUB_TYPE); |
| 217 RecordHashTableHelper(nullptr, heap_->code_stubs(), |
| 218 CODE_STUBS_TABLE_SUB_TYPE); |
| 219 RecordHashTableHelper(nullptr, heap_->intrinsic_function_names(), |
| 220 INTRINSIC_FUNCTION_NAMES_SUB_TYPE); |
| 221 RecordHashTableHelper(nullptr, heap_->empty_properties_dictionary(), |
| 222 EMPTY_PROPERTIES_DICTIONARY_SUB_TYPE); |
195 } | 223 } |
196 | 224 |
197 static bool CanRecordFixedArray(Heap* heap, FixedArrayBase* array) { | 225 static bool CanRecordFixedArray(Heap* heap, FixedArrayBase* array) { |
198 return array->map()->instance_type() == FIXED_ARRAY_TYPE && | 226 return array->map()->instance_type() == FIXED_ARRAY_TYPE && |
199 array->map() != heap->fixed_cow_array_map() && | |
200 array->map() != heap->fixed_double_array_map() && | 227 array->map() != heap->fixed_double_array_map() && |
201 array != heap->empty_fixed_array() && | 228 array != heap->empty_fixed_array() && |
202 array != heap->empty_byte_array() && | 229 array != heap->empty_byte_array() && |
203 array != heap->empty_literals_array() && | 230 array != heap->empty_literals_array() && |
204 array != heap->empty_sloppy_arguments_elements() && | 231 array != heap->empty_sloppy_arguments_elements() && |
205 array != heap->empty_slow_element_dictionary() && | 232 array != heap->empty_slow_element_dictionary() && |
206 array != heap->empty_descriptor_array() && | 233 array != heap->empty_descriptor_array() && |
207 array != heap->empty_properties_dictionary(); | 234 array != heap->empty_properties_dictionary(); |
208 } | 235 } |
209 | 236 |
210 static bool SameLiveness(HeapObject* obj1, HeapObject* obj2) { | 237 static bool IsCowArray(Heap* heap, FixedArrayBase* array) { |
211 return ObjectMarking::Color(obj1) == ObjectMarking::Color(obj2); | 238 return array->map() == heap->fixed_cow_array_map(); |
212 } | 239 } |
213 | 240 |
214 void ObjectStatsCollector::RecordFixedArrayHelper( | 241 static bool SameLiveness(HeapObject* obj1, HeapObject* obj2) { |
215 ObjectStats* stats, Heap* heap, HeapObject* parent, FixedArray* array, | 242 return obj1 == nullptr || obj2 == nullptr || |
216 int subtype, size_t overhead) { | 243 ObjectMarking::Color(obj1) == ObjectMarking::Color(obj2); |
217 if (SameLiveness(parent, array) && CanRecordFixedArray(heap, array)) { | 244 } |
218 stats->RecordFixedArraySubTypeStats(array, subtype, array->Size(), | 245 |
219 overhead); | 246 bool ObjectStatsCollector::RecordFixedArrayHelper(HeapObject* parent, |
| 247 FixedArray* array, |
| 248 int subtype, |
| 249 size_t overhead) { |
| 250 if (SameLiveness(parent, array) && CanRecordFixedArray(heap_, array) && |
| 251 !IsCowArray(heap_, array)) { |
| 252 return stats_->RecordFixedArraySubTypeStats(array, subtype, array->Size(), |
| 253 overhead); |
| 254 } |
| 255 return false; |
| 256 } |
| 257 |
| 258 void ObjectStatsCollector::RecursivelyRecordFixedArrayHelper(HeapObject* parent, |
| 259 FixedArray* array, |
| 260 int subtype) { |
| 261 if (RecordFixedArrayHelper(parent, array, subtype, 0)) { |
| 262 for (int i = 0; i < array->length(); i++) { |
| 263 if (array->get(i)->IsFixedArray()) { |
| 264 RecursivelyRecordFixedArrayHelper( |
| 265 parent, FixedArray::cast(array->get(i)), subtype); |
| 266 } |
| 267 } |
220 } | 268 } |
221 } | 269 } |
222 | 270 |
223 void ObjectStatsCollector::RecordJSObjectDetails(ObjectStats* stats, Heap* heap, | 271 template <class HashTable> |
224 JSObject* object) { | 272 void ObjectStatsCollector::RecordHashTableHelper(HeapObject* parent, |
225 DCHECK(object->IsJSObject()); | 273 HashTable* array, |
| 274 int subtype) { |
| 275 int used = array->NumberOfElements() * HashTable::kEntrySize; |
| 276 CHECK_GE(array->Size(), used); |
| 277 size_t overhead = array->Size() - used; |
| 278 RecordFixedArrayHelper(parent, array, subtype, overhead); |
| 279 } |
226 | 280 |
| 281 void ObjectStatsCollector::RecordJSObjectDetails(JSObject* object) { |
227 size_t overhead = 0; | 282 size_t overhead = 0; |
228 FixedArrayBase* elements = object->elements(); | 283 FixedArrayBase* elements = object->elements(); |
229 if (CanRecordFixedArray(heap, elements)) { | 284 if (CanRecordFixedArray(heap_, elements) && !IsCowArray(heap_, elements)) { |
230 if (elements->IsDictionary() && SameLiveness(object, elements)) { | 285 if (elements->IsDictionary() && SameLiveness(object, elements)) { |
231 SeededNumberDictionary* dict = SeededNumberDictionary::cast(elements); | 286 SeededNumberDictionary* dict = SeededNumberDictionary::cast(elements); |
232 int used = dict->NumberOfElements() * SeededNumberDictionary::kEntrySize; | 287 RecordHashTableHelper(object, dict, DICTIONARY_ELEMENTS_SUB_TYPE); |
233 CHECK_GE(elements->Size(), used); | |
234 overhead = elements->Size() - used; | |
235 stats->RecordFixedArraySubTypeStats( | |
236 elements, DICTIONARY_ELEMENTS_SUB_TYPE, elements->Size(), overhead); | |
237 } else { | 288 } else { |
238 if (IsFastHoleyElementsKind(object->GetElementsKind())) { | 289 if (IsFastHoleyElementsKind(object->GetElementsKind())) { |
239 int used = object->GetFastElementsUsage() * kPointerSize; | 290 int used = object->GetFastElementsUsage() * kPointerSize; |
240 if (object->GetElementsKind() == FAST_HOLEY_DOUBLE_ELEMENTS) used *= 2; | 291 if (object->GetElementsKind() == FAST_HOLEY_DOUBLE_ELEMENTS) used *= 2; |
241 CHECK_GE(elements->Size(), used); | 292 CHECK_GE(elements->Size(), used); |
242 overhead = elements->Size() - used; | 293 overhead = elements->Size() - used; |
243 } | 294 } |
244 stats->RecordFixedArraySubTypeStats(elements, FAST_ELEMENTS_SUB_TYPE, | 295 stats_->RecordFixedArraySubTypeStats(elements, FAST_ELEMENTS_SUB_TYPE, |
245 elements->Size(), overhead); | 296 elements->Size(), overhead); |
246 } | 297 } |
247 } | 298 } |
248 | 299 |
249 overhead = 0; | 300 overhead = 0; |
250 FixedArrayBase* properties = object->properties(); | 301 FixedArrayBase* properties = object->properties(); |
251 if (CanRecordFixedArray(heap, properties) && | 302 if (CanRecordFixedArray(heap_, properties) && |
252 SameLiveness(object, properties)) { | 303 SameLiveness(object, properties) && !IsCowArray(heap_, properties)) { |
253 if (properties->IsDictionary()) { | 304 if (properties->IsDictionary()) { |
254 NameDictionary* dict = NameDictionary::cast(properties); | 305 NameDictionary* dict = NameDictionary::cast(properties); |
255 int used = dict->NumberOfElements() * NameDictionary::kEntrySize; | 306 RecordHashTableHelper(object, dict, DICTIONARY_PROPERTIES_SUB_TYPE); |
256 CHECK_GE(properties->Size(), used); | |
257 overhead = properties->Size() - used; | |
258 stats->RecordFixedArraySubTypeStats(properties, | |
259 DICTIONARY_PROPERTIES_SUB_TYPE, | |
260 properties->Size(), overhead); | |
261 } else { | 307 } else { |
262 stats->RecordFixedArraySubTypeStats(properties, FAST_PROPERTIES_SUB_TYPE, | 308 stats_->RecordFixedArraySubTypeStats(properties, FAST_PROPERTIES_SUB_TYPE, |
263 properties->Size(), overhead); | 309 properties->Size(), overhead); |
264 } | 310 } |
265 } | 311 } |
266 } | 312 } |
267 | 313 |
268 void ObjectStatsCollector::RecordJSWeakCollectionDetails( | 314 void ObjectStatsCollector::RecordJSWeakCollectionDetails( |
269 ObjectStats* stats, Heap* heap, JSWeakCollection* obj) { | 315 JSWeakCollection* obj) { |
270 if (obj->table()->IsHashTable()) { | 316 if (obj->table()->IsHashTable()) { |
271 ObjectHashTable* table = ObjectHashTable::cast(obj->table()); | 317 ObjectHashTable* table = ObjectHashTable::cast(obj->table()); |
272 int used = table->NumberOfElements() * ObjectHashTable::kEntrySize; | 318 int used = table->NumberOfElements() * ObjectHashTable::kEntrySize; |
273 size_t overhead = table->Size() - used; | 319 size_t overhead = table->Size() - used; |
274 RecordFixedArrayHelper(stats, heap, obj, table, WEAK_COLLECTION_SUB_TYPE, | 320 RecordFixedArrayHelper(obj, table, JS_WEAK_COLLECTION_SUB_TYPE, overhead); |
275 overhead); | |
276 } | 321 } |
277 } | 322 } |
278 | 323 |
279 void ObjectStatsCollector::RecordScriptDetails(ObjectStats* stats, Heap* heap, | 324 void ObjectStatsCollector::RecordJSCollectionDetails(JSObject* obj) { |
280 Script* obj) { | 325 if (obj->IsJSMap()) { |
| 326 RecordHashTableHelper(nullptr, |
| 327 OrderedHashMap::cast(JSMap::cast(obj)->table()), |
| 328 JS_COLLECTION_SUB_TYPE); |
| 329 } |
| 330 if (obj->IsJSSet()) { |
| 331 RecordHashTableHelper(nullptr, |
| 332 OrderedHashSet::cast(JSSet::cast(obj)->table()), |
| 333 JS_COLLECTION_SUB_TYPE); |
| 334 } |
| 335 } |
| 336 |
| 337 void ObjectStatsCollector::RecordScriptDetails(Script* obj) { |
281 Object* infos = WeakFixedArray::cast(obj->shared_function_infos()); | 338 Object* infos = WeakFixedArray::cast(obj->shared_function_infos()); |
282 if (infos->IsWeakFixedArray()) | 339 if (infos->IsWeakFixedArray()) |
283 RecordFixedArrayHelper(stats, heap, obj, WeakFixedArray::cast(infos), | 340 RecordFixedArrayHelper(obj, WeakFixedArray::cast(infos), |
284 SHARED_FUNCTION_INFOS_SUB_TYPE, 0); | 341 SHARED_FUNCTION_INFOS_SUB_TYPE, 0); |
285 } | 342 } |
286 | 343 |
287 void ObjectStatsCollector::RecordMapDetails(ObjectStats* stats, Heap* heap, | 344 void ObjectStatsCollector::RecordMapDetails(Map* map_obj) { |
288 HeapObject* obj) { | |
289 Map* map_obj = Map::cast(obj); | |
290 DCHECK(obj->map()->instance_type() == MAP_TYPE); | |
291 DescriptorArray* array = map_obj->instance_descriptors(); | 345 DescriptorArray* array = map_obj->instance_descriptors(); |
292 if (map_obj->owns_descriptors() && array != heap->empty_descriptor_array() && | 346 if (map_obj->owns_descriptors() && array != heap_->empty_descriptor_array() && |
293 SameLiveness(map_obj, array)) { | 347 SameLiveness(map_obj, array)) { |
294 RecordFixedArrayHelper(stats, heap, map_obj, array, | 348 RecordFixedArrayHelper(map_obj, array, DESCRIPTOR_ARRAY_SUB_TYPE, 0); |
295 DESCRIPTOR_ARRAY_SUB_TYPE, 0); | |
296 if (array->HasEnumCache()) { | 349 if (array->HasEnumCache()) { |
297 RecordFixedArrayHelper(stats, heap, array, array->GetEnumCache(), | 350 RecordFixedArrayHelper(array, array->GetEnumCache(), ENUM_CACHE_SUB_TYPE, |
298 ENUM_CACHE_SUB_TYPE, 0); | 351 0); |
299 } | 352 } |
300 if (array->HasEnumIndicesCache()) { | 353 if (array->HasEnumIndicesCache()) { |
301 RecordFixedArrayHelper(stats, heap, array, array->GetEnumIndicesCache(), | 354 RecordFixedArrayHelper(array, array->GetEnumIndicesCache(), |
302 ENUM_INDICES_CACHE_SUB_TYPE, 0); | 355 ENUM_INDICES_CACHE_SUB_TYPE, 0); |
303 } | 356 } |
304 } | 357 } |
305 | 358 |
306 if (map_obj->has_code_cache()) { | 359 if (map_obj->has_code_cache()) { |
307 RecordFixedArrayHelper(stats, heap, map_obj, map_obj->code_cache(), | 360 RecordFixedArrayHelper(map_obj, map_obj->code_cache(), |
308 MAP_CODE_CACHE_SUB_TYPE, 0); | 361 MAP_CODE_CACHE_SUB_TYPE, 0); |
309 } | 362 } |
310 } | |
311 | 363 |
312 void ObjectStatsCollector::RecordCodeDetails(ObjectStats* stats, Heap* heap, | 364 for (DependentCode* cur_dependent_code = map_obj->dependent_code(); |
313 HeapObject* obj) { | 365 cur_dependent_code != heap_->empty_fixed_array(); |
314 int object_size = obj->Size(); | 366 cur_dependent_code = DependentCode::cast( |
315 DCHECK(obj->map()->instance_type() == CODE_TYPE); | 367 cur_dependent_code->get(DependentCode::kNextLinkIndex))) { |
316 Code* code_obj = Code::cast(obj); | 368 RecordFixedArrayHelper(map_obj, cur_dependent_code, DEPENDENT_CODE_SUB_TYPE, |
317 stats->RecordCodeSubTypeStats(code_obj->kind(), code_obj->GetAge(), | 369 0); |
318 object_size); | 370 } |
319 Code* code = Code::cast(obj); | 371 |
320 RecordFixedArrayHelper(stats, heap, code, code->deoptimization_data(), | 372 if (map_obj->is_prototype_map()) { |
321 DEOPTIMIZATION_DATA_SUB_TYPE, 0); | 373 if (map_obj->prototype_info()->IsPrototypeInfo()) { |
322 for (RelocIterator it(code); !it.done(); it.next()) { | 374 PrototypeInfo* info = PrototypeInfo::cast(map_obj->prototype_info()); |
323 RelocInfo::Mode mode = it.rinfo()->rmode(); | 375 Object* users = info->prototype_users(); |
324 if (mode == RelocInfo::EMBEDDED_OBJECT) { | 376 if (users->IsWeakFixedArray()) { |
325 Object* target = it.rinfo()->target_object(); | 377 RecordFixedArrayHelper(map_obj, WeakFixedArray::cast(users), |
326 if (target->IsFixedArray()) { | 378 PROTOTYPE_USERS_SUB_TYPE, 0); |
327 RecordFixedArrayHelper(stats, heap, code, FixedArray::cast(target), | |
328 EMBEDDED_OBJECT_SUB_TYPE, 0); | |
329 } | 379 } |
330 } | 380 } |
331 } | 381 } |
332 } | 382 } |
333 | 383 |
334 void ObjectStatsCollector::RecordSharedFunctionInfoDetails(ObjectStats* stats, | 384 void ObjectStatsCollector::RecordCodeDetails(Code* code) { |
335 Heap* heap, | 385 stats_->RecordCodeSubTypeStats(code->kind(), code->GetAge(), code->Size()); |
336 HeapObject* obj) { | 386 RecordFixedArrayHelper(code, code->deoptimization_data(), |
337 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj); | 387 DEOPTIMIZATION_DATA_SUB_TYPE, 0); |
| 388 RecordFixedArrayHelper(code, code->handler_table(), HANDLER_TABLE_SUB_TYPE, |
| 389 0); |
| 390 int const mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); |
| 391 for (RelocIterator it(code, mode_mask); !it.done(); it.next()) { |
| 392 RelocInfo::Mode mode = it.rinfo()->rmode(); |
| 393 if (mode == RelocInfo::EMBEDDED_OBJECT) { |
| 394 Object* target = it.rinfo()->target_object(); |
| 395 if (target->IsFixedArray()) { |
| 396 RecursivelyRecordFixedArrayHelper(code, FixedArray::cast(target), |
| 397 EMBEDDED_OBJECT_SUB_TYPE); |
| 398 } |
| 399 } |
| 400 } |
| 401 } |
| 402 |
| 403 void ObjectStatsCollector::RecordSharedFunctionInfoDetails( |
| 404 SharedFunctionInfo* sfi) { |
338 FixedArray* scope_info = sfi->scope_info(); | 405 FixedArray* scope_info = sfi->scope_info(); |
339 RecordFixedArrayHelper(stats, heap, sfi, scope_info, SCOPE_INFO_SUB_TYPE, 0); | 406 RecordFixedArrayHelper(sfi, scope_info, SCOPE_INFO_SUB_TYPE, 0); |
340 FixedArray* feedback_metadata = sfi->feedback_metadata(); | 407 TypeFeedbackMetadata* feedback_metadata = sfi->feedback_metadata(); |
341 RecordFixedArrayHelper(stats, heap, sfi, feedback_metadata, | 408 if (!feedback_metadata->is_empty()) { |
342 TYPE_FEEDBACK_METADATA_SUB_TYPE, 0); | 409 RecordFixedArrayHelper(sfi, feedback_metadata, |
| 410 TYPE_FEEDBACK_METADATA_SUB_TYPE, 0); |
| 411 UnseededNumberDictionary* names = UnseededNumberDictionary::cast( |
| 412 feedback_metadata->get(TypeFeedbackMetadata::kNamesTableIndex)); |
| 413 RecordHashTableHelper(sfi, names, TYPE_FEEDBACK_METADATA_SUB_TYPE); |
| 414 } |
343 | 415 |
344 if (!sfi->OptimizedCodeMapIsCleared()) { | 416 if (!sfi->OptimizedCodeMapIsCleared()) { |
345 FixedArray* optimized_code_map = sfi->optimized_code_map(); | 417 FixedArray* optimized_code_map = sfi->optimized_code_map(); |
| 418 RecordFixedArrayHelper(sfi, optimized_code_map, OPTIMIZED_CODE_MAP_SUB_TYPE, |
| 419 0); |
346 // Optimized code map should be small, so skip accounting. | 420 // Optimized code map should be small, so skip accounting. |
347 int len = optimized_code_map->length(); | 421 int len = optimized_code_map->length(); |
348 for (int i = SharedFunctionInfo::kEntriesStart; i < len; | 422 for (int i = SharedFunctionInfo::kEntriesStart; i < len; |
349 i += SharedFunctionInfo::kEntryLength) { | 423 i += SharedFunctionInfo::kEntryLength) { |
350 Object* slot = | 424 Object* slot = |
351 optimized_code_map->get(i + SharedFunctionInfo::kLiteralsOffset); | 425 optimized_code_map->get(i + SharedFunctionInfo::kLiteralsOffset); |
352 LiteralsArray* literals = nullptr; | 426 LiteralsArray* literals = nullptr; |
353 if (slot->IsWeakCell()) { | 427 if (slot->IsWeakCell()) { |
354 WeakCell* cell = WeakCell::cast(slot); | 428 WeakCell* cell = WeakCell::cast(slot); |
355 if (!cell->cleared()) { | 429 if (!cell->cleared()) { |
356 literals = LiteralsArray::cast(cell->value()); | 430 literals = LiteralsArray::cast(cell->value()); |
357 } | 431 } |
358 } else { | 432 } else { |
359 literals = LiteralsArray::cast(slot); | 433 literals = LiteralsArray::cast(slot); |
360 } | 434 } |
361 if (literals != nullptr) { | 435 if (literals != nullptr) { |
362 RecordFixedArrayHelper(stats, heap, sfi, literals, | 436 RecordFixedArrayHelper(sfi, literals, LITERALS_ARRAY_SUB_TYPE, 0); |
363 LITERALS_ARRAY_SUB_TYPE, 0); | 437 RecordFixedArrayHelper(sfi, literals->feedback_vector(), |
364 RecordFixedArrayHelper(stats, heap, sfi, literals->feedback_vector(), | |
365 TYPE_FEEDBACK_VECTOR_SUB_TYPE, 0); | 438 TYPE_FEEDBACK_VECTOR_SUB_TYPE, 0); |
366 } | 439 } |
367 } | 440 } |
368 } | 441 } |
369 } | 442 } |
370 | 443 |
371 void ObjectStatsCollector::RecordFixedArrayDetails(ObjectStats* stats, | 444 void ObjectStatsCollector::RecordJSFunctionDetails(JSFunction* function) { |
372 Heap* heap, | 445 LiteralsArray* literals = function->literals(); |
373 HeapObject* obj) { | 446 RecordFixedArrayHelper(function, literals, LITERALS_ARRAY_SUB_TYPE, 0); |
374 FixedArray* array = FixedArray::cast(obj); | 447 RecordFixedArrayHelper(function, literals->feedback_vector(), |
| 448 TYPE_FEEDBACK_VECTOR_SUB_TYPE, 0); |
| 449 } |
375 | 450 |
376 // Special fixed arrays. | 451 void ObjectStatsCollector::RecordFixedArrayDetails(FixedArray* array) { |
377 int subtype = -1; | 452 if (array->IsContext()) { |
378 if (array == heap->weak_new_space_object_to_code_list()) | 453 RecordFixedArrayHelper(nullptr, array, CONTEXT_SUB_TYPE, 0); |
379 subtype = WEAK_NEW_SPACE_OBJECT_TO_CODE_SUB_TYPE; | |
380 if (array == heap->serialized_templates()) | |
381 subtype = SERIALIZED_TEMPLATES_SUB_TYPE; | |
382 if (array == heap->string_table()) subtype = STRING_TABLE_SUB_TYPE; | |
383 if (array == heap->number_string_cache()) | |
384 subtype = NUMBER_STRING_CACHE_SUB_TYPE; | |
385 if (array == heap->single_character_string_cache()) | |
386 subtype = SINGLE_CHARACTER_STRING_CACHE_SUB_TYPE; | |
387 if (array == heap->string_split_cache()) | |
388 subtype = STRING_SPLIT_CACHE_SUB_TYPE; | |
389 if (array == heap->regexp_multiple_cache()) | |
390 subtype = REGEXP_MULTIPLE_CACHE_SUB_TYPE; | |
391 if (array->IsContext()) subtype = CONTEXT_SUB_TYPE; | |
392 if (array->map() == heap->fixed_cow_array_map()) | |
393 subtype = COPY_ON_WRITE_SUB_TYPE; | |
394 if (subtype != -1) { | |
395 stats->RecordFixedArraySubTypeStats(array, subtype, array->Size(), 0); | |
396 } | 454 } |
397 | 455 if (IsCowArray(heap_, array) && CanRecordFixedArray(heap_, array)) { |
398 // Special hash maps. | 456 stats_->RecordFixedArraySubTypeStats(array, COPY_ON_WRITE_SUB_TYPE, |
399 if (array == heap->weak_object_to_code_table()) { | 457 array->Size(), 0); |
400 WeakHashTable* table = reinterpret_cast<WeakHashTable*>(array); | |
401 int used = table->NumberOfElements() * WeakHashTable::kEntrySize; | |
402 CHECK_GE(array->Size(), used); | |
403 size_t overhead = array->Size() - used; | |
404 stats->RecordFixedArraySubTypeStats(table, OBJECT_TO_CODE_SUB_TYPE, | |
405 table->Size(), overhead); | |
406 } | 458 } |
407 if (array->IsNativeContext()) { | 459 if (array->IsNativeContext()) { |
408 Context* native_ctx = Context::cast(array); | 460 Context* native_ctx = Context::cast(array); |
409 UnseededNumberDictionary* dict = | 461 RecordHashTableHelper(array, native_ctx->template_instantiations_cache(), |
410 native_ctx->template_instantiations_cache(); | 462 TEMPLATE_INSTANTIATIONS_CACHE_SUB_TYPE); |
411 int used = dict->NumberOfElements() * UnseededNumberDictionary::kEntrySize; | |
412 size_t overhead = dict->Size() - used; | |
413 RecordFixedArrayHelper(stats, heap, array, dict, | |
414 TEMPLATE_INSTANTIATIONS_CACHE_SUB_TYPE, overhead); | |
415 } | |
416 if (array == heap->code_stubs()) { | |
417 UnseededNumberDictionary* dict = UnseededNumberDictionary::cast(array); | |
418 int used = dict->NumberOfElements() * UnseededNumberDictionary::kEntrySize; | |
419 size_t overhead = dict->Size() - used; | |
420 stats->RecordFixedArraySubTypeStats(dict, CODE_STUBS_TABLE_SUB_TYPE, | |
421 dict->Size(), overhead); | |
422 } | |
423 if (array == heap->intrinsic_function_names()) { | |
424 NameDictionary* dict = NameDictionary::cast(array); | |
425 int used = dict->NumberOfElements() * NameDictionary::kEntrySize; | |
426 size_t overhead = dict->Size() - used; | |
427 stats->RecordFixedArraySubTypeStats(dict, INTRINSIC_FUNCTION_NAMES_SUB_TYPE, | |
428 dict->Size(), overhead); | |
429 } | 463 } |
430 } | 464 } |
431 | 465 |
432 } // namespace internal | 466 } // namespace internal |
433 } // namespace v8 | 467 } // namespace v8 |
OLD | NEW |