| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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/spaces.h" | 5 #include "src/heap/spaces.h" |
| 6 | 6 |
| 7 #include "src/base/bits.h" | 7 #include "src/base/bits.h" |
| 8 #include "src/base/platform/platform.h" | 8 #include "src/base/platform/platform.h" |
| 9 #include "src/base/platform/semaphore.h" | 9 #include "src/base/platform/semaphore.h" |
| 10 #include "src/full-codegen/full-codegen.h" | 10 #include "src/full-codegen/full-codegen.h" |
| (...skipping 2028 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2039 INSTANCE_TYPE_LIST(DEF_TYPE_NAME) | 2039 INSTANCE_TYPE_LIST(DEF_TYPE_NAME) |
| 2040 #undef DEF_TYPE_NAME | 2040 #undef DEF_TYPE_NAME |
| 2041 | 2041 |
| 2042 #define CLEAR_HISTOGRAM(name) isolate->heap_histograms()[name].clear(); | 2042 #define CLEAR_HISTOGRAM(name) isolate->heap_histograms()[name].clear(); |
| 2043 INSTANCE_TYPE_LIST(CLEAR_HISTOGRAM) | 2043 INSTANCE_TYPE_LIST(CLEAR_HISTOGRAM) |
| 2044 #undef CLEAR_HISTOGRAM | 2044 #undef CLEAR_HISTOGRAM |
| 2045 | 2045 |
| 2046 isolate->js_spill_information()->Clear(); | 2046 isolate->js_spill_information()->Clear(); |
| 2047 } | 2047 } |
| 2048 | 2048 |
| 2049 | |
| 2050 static void ClearCodeKindStatistics(int* code_kind_statistics) { | |
| 2051 for (int i = 0; i < AbstractCode::NUMBER_OF_KINDS; i++) { | |
| 2052 code_kind_statistics[i] = 0; | |
| 2053 } | |
| 2054 } | |
| 2055 static void ReportCodeKindStatistics(int* code_kind_statistics) { | |
| 2056 PrintF("\n Code kind histograms: \n"); | |
| 2057 for (int i = 0; i < AbstractCode::NUMBER_OF_KINDS; i++) { | |
| 2058 if (code_kind_statistics[i] > 0) { | |
| 2059 PrintF(" %-20s: %10d bytes\n", | |
| 2060 AbstractCode::Kind2String(static_cast<AbstractCode::Kind>(i)), | |
| 2061 code_kind_statistics[i]); | |
| 2062 } | |
| 2063 } | |
| 2064 PrintF("\n"); | |
| 2065 } | |
| 2066 | |
| 2067 static int CollectHistogramInfo(HeapObject* obj) { | 2049 static int CollectHistogramInfo(HeapObject* obj) { |
| 2068 Isolate* isolate = obj->GetIsolate(); | 2050 Isolate* isolate = obj->GetIsolate(); |
| 2069 InstanceType type = obj->map()->instance_type(); | 2051 InstanceType type = obj->map()->instance_type(); |
| 2070 DCHECK(0 <= type && type <= LAST_TYPE); | 2052 DCHECK(0 <= type && type <= LAST_TYPE); |
| 2071 DCHECK(isolate->heap_histograms()[type].name() != NULL); | 2053 DCHECK(isolate->heap_histograms()[type].name() != NULL); |
| 2072 isolate->heap_histograms()[type].increment_number(1); | 2054 isolate->heap_histograms()[type].increment_number(1); |
| 2073 isolate->heap_histograms()[type].increment_bytes(obj->Size()); | 2055 isolate->heap_histograms()[type].increment_bytes(obj->Size()); |
| 2074 | 2056 |
| 2075 if (FLAG_collect_heap_spill_statistics && obj->IsJSObject()) { | 2057 if (FLAG_collect_heap_spill_statistics && obj->IsJSObject()) { |
| 2076 JSObject::cast(obj) | 2058 JSObject::cast(obj) |
| (...skipping 677 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2754 return free_list_.Allocate(size_in_bytes); | 2736 return free_list_.Allocate(size_in_bytes); |
| 2755 } | 2737 } |
| 2756 | 2738 |
| 2757 // If sweeper threads are active, wait for them at that point and steal | 2739 // If sweeper threads are active, wait for them at that point and steal |
| 2758 // elements form their free-lists. Allocation may still fail their which | 2740 // elements form their free-lists. Allocation may still fail their which |
| 2759 // would indicate that there is not enough memory for the given allocation. | 2741 // would indicate that there is not enough memory for the given allocation. |
| 2760 return SweepAndRetryAllocation(size_in_bytes); | 2742 return SweepAndRetryAllocation(size_in_bytes); |
| 2761 } | 2743 } |
| 2762 | 2744 |
| 2763 #ifdef DEBUG | 2745 #ifdef DEBUG |
| 2764 void PagedSpace::ReportCodeStatistics(Isolate* isolate) { | |
| 2765 CommentStatistic* comments_statistics = | |
| 2766 isolate->paged_space_comments_statistics(); | |
| 2767 ReportCodeKindStatistics(isolate->code_kind_statistics()); | |
| 2768 PrintF("Code size including metadata : %10d bytes\n", | |
| 2769 isolate->code_and_metadata_size()); | |
| 2770 PrintF("Bytecode size including metadata: %10d bytes\n", | |
| 2771 isolate->bytecode_and_metadata_size()); | |
| 2772 PrintF( | |
| 2773 "Code comment statistics (\" [ comment-txt : size/ " | |
| 2774 "count (average)\"):\n"); | |
| 2775 for (int i = 0; i <= CommentStatistic::kMaxComments; i++) { | |
| 2776 const CommentStatistic& cs = comments_statistics[i]; | |
| 2777 if (cs.size > 0) { | |
| 2778 PrintF(" %-30s: %10d/%6d (%d)\n", cs.comment, cs.size, cs.count, | |
| 2779 cs.size / cs.count); | |
| 2780 } | |
| 2781 } | |
| 2782 PrintF("\n"); | |
| 2783 } | |
| 2784 | |
| 2785 void PagedSpace::ResetCodeStatistics(Isolate* isolate) { | |
| 2786 CommentStatistic* comments_statistics = | |
| 2787 isolate->paged_space_comments_statistics(); | |
| 2788 ClearCodeKindStatistics(isolate->code_kind_statistics()); | |
| 2789 for (int i = 0; i < CommentStatistic::kMaxComments; i++) { | |
| 2790 comments_statistics[i].Clear(); | |
| 2791 } | |
| 2792 comments_statistics[CommentStatistic::kMaxComments].comment = "Unknown"; | |
| 2793 comments_statistics[CommentStatistic::kMaxComments].size = 0; | |
| 2794 comments_statistics[CommentStatistic::kMaxComments].count = 0; | |
| 2795 } | |
| 2796 | |
| 2797 | |
| 2798 // Adds comment to 'comment_statistics' table. Performance OK as long as | |
| 2799 // 'kMaxComments' is small | |
| 2800 static void EnterComment(Isolate* isolate, const char* comment, int delta) { | |
| 2801 CommentStatistic* comments_statistics = | |
| 2802 isolate->paged_space_comments_statistics(); | |
| 2803 // Do not count empty comments | |
| 2804 if (delta <= 0) return; | |
| 2805 CommentStatistic* cs = &comments_statistics[CommentStatistic::kMaxComments]; | |
| 2806 // Search for a free or matching entry in 'comments_statistics': 'cs' | |
| 2807 // points to result. | |
| 2808 for (int i = 0; i < CommentStatistic::kMaxComments; i++) { | |
| 2809 if (comments_statistics[i].comment == NULL) { | |
| 2810 cs = &comments_statistics[i]; | |
| 2811 cs->comment = comment; | |
| 2812 break; | |
| 2813 } else if (strcmp(comments_statistics[i].comment, comment) == 0) { | |
| 2814 cs = &comments_statistics[i]; | |
| 2815 break; | |
| 2816 } | |
| 2817 } | |
| 2818 // Update entry for 'comment' | |
| 2819 cs->size += delta; | |
| 2820 cs->count += 1; | |
| 2821 } | |
| 2822 | |
| 2823 | |
| 2824 // Call for each nested comment start (start marked with '[ xxx', end marked | |
| 2825 // with ']'. RelocIterator 'it' must point to a comment reloc info. | |
| 2826 static void CollectCommentStatistics(Isolate* isolate, RelocIterator* it) { | |
| 2827 DCHECK(!it->done()); | |
| 2828 DCHECK(it->rinfo()->rmode() == RelocInfo::COMMENT); | |
| 2829 const char* tmp = reinterpret_cast<const char*>(it->rinfo()->data()); | |
| 2830 if (tmp[0] != '[') { | |
| 2831 // Not a nested comment; skip | |
| 2832 return; | |
| 2833 } | |
| 2834 | |
| 2835 // Search for end of nested comment or a new nested comment | |
| 2836 const char* const comment_txt = | |
| 2837 reinterpret_cast<const char*>(it->rinfo()->data()); | |
| 2838 const byte* prev_pc = it->rinfo()->pc(); | |
| 2839 int flat_delta = 0; | |
| 2840 it->next(); | |
| 2841 while (true) { | |
| 2842 // All nested comments must be terminated properly, and therefore exit | |
| 2843 // from loop. | |
| 2844 DCHECK(!it->done()); | |
| 2845 if (it->rinfo()->rmode() == RelocInfo::COMMENT) { | |
| 2846 const char* const txt = | |
| 2847 reinterpret_cast<const char*>(it->rinfo()->data()); | |
| 2848 flat_delta += static_cast<int>(it->rinfo()->pc() - prev_pc); | |
| 2849 if (txt[0] == ']') break; // End of nested comment | |
| 2850 // A new comment | |
| 2851 CollectCommentStatistics(isolate, it); | |
| 2852 // Skip code that was covered with previous comment | |
| 2853 prev_pc = it->rinfo()->pc(); | |
| 2854 } | |
| 2855 it->next(); | |
| 2856 } | |
| 2857 EnterComment(isolate, comment_txt, flat_delta); | |
| 2858 } | |
| 2859 | |
| 2860 // Collects code comment statistics | |
| 2861 static void CollectCodeCommentStatistics(HeapObject* obj, Isolate* isolate) { | |
| 2862 if (!obj->IsCode()) { | |
| 2863 return; | |
| 2864 } | |
| 2865 Code* code = Code::cast(obj); | |
| 2866 RelocIterator it(code); | |
| 2867 int delta = 0; | |
| 2868 const byte* prev_pc = code->instruction_start(); | |
| 2869 while (!it.done()) { | |
| 2870 if (it.rinfo()->rmode() == RelocInfo::COMMENT) { | |
| 2871 delta += static_cast<int>(it.rinfo()->pc() - prev_pc); | |
| 2872 CollectCommentStatistics(isolate, &it); | |
| 2873 prev_pc = it.rinfo()->pc(); | |
| 2874 } | |
| 2875 it.next(); | |
| 2876 } | |
| 2877 | |
| 2878 DCHECK(code->instruction_start() <= prev_pc && | |
| 2879 prev_pc <= code->instruction_end()); | |
| 2880 delta += static_cast<int>(code->instruction_end() - prev_pc); | |
| 2881 EnterComment(isolate, "NoComment", delta); | |
| 2882 } | |
| 2883 | |
| 2884 | |
| 2885 void PagedSpace::ReportStatistics() { | 2746 void PagedSpace::ReportStatistics() { |
| 2886 int pct = static_cast<int>(Available() * 100 / Capacity()); | 2747 int pct = static_cast<int>(Available() * 100 / Capacity()); |
| 2887 PrintF(" capacity: %" V8PRIdPTR ", waste: %" V8PRIdPTR | 2748 PrintF(" capacity: %" V8PRIdPTR ", waste: %" V8PRIdPTR |
| 2888 ", available: %" V8PRIdPTR ", %%%d\n", | 2749 ", available: %" V8PRIdPTR ", %%%d\n", |
| 2889 Capacity(), Waste(), Available(), pct); | 2750 Capacity(), Waste(), Available(), pct); |
| 2890 | 2751 |
| 2891 if (heap()->mark_compact_collector()->sweeping_in_progress()) { | 2752 if (heap()->mark_compact_collector()->sweeping_in_progress()) { |
| 2892 heap()->mark_compact_collector()->EnsureSweepingCompleted(); | 2753 heap()->mark_compact_collector()->EnsureSweepingCompleted(); |
| 2893 } | 2754 } |
| 2894 ClearHistograms(heap()->isolate()); | 2755 ClearHistograms(heap()->isolate()); |
| 2895 HeapObjectIterator obj_it(this); | 2756 HeapObjectIterator obj_it(this); |
| 2896 for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) | 2757 for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) |
| 2897 CollectHistogramInfo(obj); | 2758 CollectHistogramInfo(obj); |
| 2898 ReportHistogram(heap()->isolate(), true); | 2759 ReportHistogram(heap()->isolate(), true); |
| 2899 } | 2760 } |
| 2900 #endif | 2761 #endif |
| 2901 | 2762 |
| 2902 static void RecordCodeSizeIncludingMetadata(AbstractCode* abstract_code, | |
| 2903 Isolate* isolate) { | |
| 2904 int size = abstract_code->SizeIncludingMetadata(); | |
| 2905 if (abstract_code->IsCode()) { | |
| 2906 size += isolate->code_and_metadata_size(); | |
| 2907 isolate->set_code_and_metadata_size(size); | |
| 2908 } else { | |
| 2909 size += isolate->bytecode_and_metadata_size(); | |
| 2910 isolate->set_bytecode_and_metadata_size(size); | |
| 2911 } | |
| 2912 } | |
| 2913 | |
| 2914 // Collects code size statistics: | |
| 2915 // - code and metadata size | |
| 2916 // - by code kind (only in debug mode) | |
| 2917 // - by code comment (only in debug mode) | |
| 2918 void PagedSpace::CollectCodeStatistics() { | |
| 2919 Isolate* isolate = heap()->isolate(); | |
| 2920 HeapObjectIterator obj_it(this); | |
| 2921 for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) { | |
| 2922 if (obj->IsAbstractCode()) { | |
| 2923 AbstractCode* code = AbstractCode::cast(obj); | |
| 2924 RecordCodeSizeIncludingMetadata(code, isolate); | |
| 2925 #ifdef DEBUG | |
| 2926 isolate->code_kind_statistics()[code->kind()] += code->Size(); | |
| 2927 CollectCodeCommentStatistics(obj, isolate); | |
| 2928 #endif | |
| 2929 } | |
| 2930 } | |
| 2931 } | |
| 2932 | |
| 2933 void PagedSpace::ResetCodeAndMetadataStatistics(Isolate* isolate) { | |
| 2934 isolate->set_code_and_metadata_size(0); | |
| 2935 isolate->set_bytecode_and_metadata_size(0); | |
| 2936 #ifdef DEBUG | |
| 2937 ResetCodeStatistics(isolate); | |
| 2938 #endif | |
| 2939 } | |
| 2940 | 2763 |
| 2941 // ----------------------------------------------------------------------------- | 2764 // ----------------------------------------------------------------------------- |
| 2942 // MapSpace implementation | 2765 // MapSpace implementation |
| 2943 | 2766 |
| 2944 #ifdef VERIFY_HEAP | 2767 #ifdef VERIFY_HEAP |
| 2945 void MapSpace::VerifyObject(HeapObject* object) { CHECK(object->IsMap()); } | 2768 void MapSpace::VerifyObject(HeapObject* object) { CHECK(object->IsMap()); } |
| 2946 #endif | 2769 #endif |
| 2947 | 2770 |
| 2948 | 2771 |
| 2949 // ----------------------------------------------------------------------------- | 2772 // ----------------------------------------------------------------------------- |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3190 HeapObject* element_object = HeapObject::cast(element); | 3013 HeapObject* element_object = HeapObject::cast(element); |
| 3191 CHECK(heap()->Contains(element_object)); | 3014 CHECK(heap()->Contains(element_object)); |
| 3192 CHECK(element_object->map()->IsMap()); | 3015 CHECK(element_object->map()->IsMap()); |
| 3193 } | 3016 } |
| 3194 } | 3017 } |
| 3195 } | 3018 } |
| 3196 } | 3019 } |
| 3197 } | 3020 } |
| 3198 #endif | 3021 #endif |
| 3199 | 3022 |
| 3200 void LargeObjectSpace::CollectCodeStatistics() { | |
| 3201 Isolate* isolate = heap()->isolate(); | |
| 3202 LargeObjectIterator obj_it(this); | |
| 3203 for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) { | |
| 3204 if (obj->IsAbstractCode()) { | |
| 3205 AbstractCode* code = AbstractCode::cast(obj); | |
| 3206 RecordCodeSizeIncludingMetadata(code, isolate); | |
| 3207 #ifdef DEBUG | |
| 3208 isolate->code_kind_statistics()[code->kind()] += code->Size(); | |
| 3209 CollectCodeCommentStatistics(obj, isolate); | |
| 3210 #endif | |
| 3211 } | |
| 3212 } | |
| 3213 } | |
| 3214 | |
| 3215 #ifdef DEBUG | 3023 #ifdef DEBUG |
| 3216 void LargeObjectSpace::Print() { | 3024 void LargeObjectSpace::Print() { |
| 3217 OFStream os(stdout); | 3025 OFStream os(stdout); |
| 3218 LargeObjectIterator it(this); | 3026 LargeObjectIterator it(this); |
| 3219 for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) { | 3027 for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) { |
| 3220 obj->Print(os); | 3028 obj->Print(os); |
| 3221 } | 3029 } |
| 3222 } | 3030 } |
| 3223 | 3031 |
| 3224 | 3032 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3257 object->ShortPrint(); | 3065 object->ShortPrint(); |
| 3258 PrintF("\n"); | 3066 PrintF("\n"); |
| 3259 } | 3067 } |
| 3260 printf(" --------------------------------------\n"); | 3068 printf(" --------------------------------------\n"); |
| 3261 printf(" Marked: %x, LiveCount: %x\n", mark_size, LiveBytes()); | 3069 printf(" Marked: %x, LiveCount: %x\n", mark_size, LiveBytes()); |
| 3262 } | 3070 } |
| 3263 | 3071 |
| 3264 #endif // DEBUG | 3072 #endif // DEBUG |
| 3265 } // namespace internal | 3073 } // namespace internal |
| 3266 } // namespace v8 | 3074 } // namespace v8 |
| OLD | NEW |