Added time format with only offset. Fixes #22558.
[mono.git] / mono / metadata / sgen-internal.c
1 /*
2  * sgen-internal.c: Internal lock-free memory allocator.
3  *
4  * Copyright (C) 2012 Xamarin Inc
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License 2.0 as published by the Free Software Foundation;
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License 2.0 along with this library; if not, write to the Free
17  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 #include "config.h"
21
22 #ifdef HAVE_SGEN_GC
23
24 #include "utils/mono-counters.h"
25 #include "metadata/sgen-gc.h"
26 #include "utils/lock-free-alloc.h"
27 #include "metadata/sgen-memory-governor.h"
28
29 /* keep each size a multiple of ALLOC_ALIGN */
30 static const int allocator_sizes [] = {
31            8,   16,   24,   32,   40,   48,   64,   80,
32           96,  128,  160,  192,  224,  248,  320,  384,
33          448,  528,  584,  680,  816, 1088, 1360, 2040,
34         2336, 2728, 3272, 4088, 5456, 8184 };
35
36 #define NUM_ALLOCATORS  (sizeof (allocator_sizes) / sizeof (int))
37
38 static MonoLockFreeAllocSizeClass size_classes [NUM_ALLOCATORS];
39 static MonoLockFreeAllocator allocators [NUM_ALLOCATORS];
40
41 /*
42  * Find the allocator index for memory chunks that can contain @size
43  * objects.
44  */
45 static int
46 index_for_size (size_t size)
47 {
48         int slot;
49         /* do a binary search or lookup table later. */
50         for (slot = 0; slot < NUM_ALLOCATORS; ++slot) {
51                 if (allocator_sizes [slot] >= size)
52                         return slot;
53         }
54         g_assert_not_reached ();
55         return -1;
56 }
57
58 /*
59  * Allocator indexes for the fixed INTERNAL_MEM_XXX types.  -1 if that
60  * type is dynamic.
61  */
62 static int fixed_type_allocator_indexes [INTERNAL_MEM_MAX];
63
64 void
65 sgen_register_fixed_internal_mem_type (int type, size_t size)
66 {
67         int slot;
68
69         g_assert (type >= 0 && type < INTERNAL_MEM_MAX);
70
71         slot = index_for_size (size);
72         g_assert (slot >= 0);
73
74         if (fixed_type_allocator_indexes [type] == -1)
75                 fixed_type_allocator_indexes [type] = slot;
76         else
77                 g_assert (fixed_type_allocator_indexes [type] == slot);
78 }
79
80 static const char*
81 description_for_type (int type)
82 {
83         switch (type) {
84         case INTERNAL_MEM_PIN_QUEUE: return "pin-queue";
85         case INTERNAL_MEM_FRAGMENT: return "fragment";
86         case INTERNAL_MEM_SECTION: return "section";
87         case INTERNAL_MEM_SCAN_STARTS: return "scan-starts";
88         case INTERNAL_MEM_FIN_TABLE: return "fin-table";
89         case INTERNAL_MEM_FINALIZE_ENTRY: return "finalize-entry";
90         case INTERNAL_MEM_FINALIZE_READY_ENTRY: return "finalize-ready-entry";
91         case INTERNAL_MEM_DISLINK_TABLE: return "dislink-table";
92         case INTERNAL_MEM_DISLINK: return "dislink";
93         case INTERNAL_MEM_ROOTS_TABLE: return "roots-table";
94         case INTERNAL_MEM_ROOT_RECORD: return "root-record";
95         case INTERNAL_MEM_STATISTICS: return "statistics";
96         case INTERNAL_MEM_STAT_PINNED_CLASS: return "pinned-class";
97         case INTERNAL_MEM_STAT_REMSET_CLASS: return "remset-class";
98         case INTERNAL_MEM_GRAY_QUEUE: return "gray-queue";
99         case INTERNAL_MEM_MS_TABLES: return "marksweep-tables";
100         case INTERNAL_MEM_MS_BLOCK_INFO: return "marksweep-block-info";
101         case INTERNAL_MEM_MS_BLOCK_INFO_SORT: return "marksweep-block-info-sort";
102         case INTERNAL_MEM_EPHEMERON_LINK: return "ephemeron-link";
103         case INTERNAL_MEM_WORKER_DATA: return "worker-data";
104         case INTERNAL_MEM_WORKER_JOB_DATA: return "worker-job-data";
105         case INTERNAL_MEM_BRIDGE_DATA: return "bridge-data";
106         case INTERNAL_MEM_OLD_BRIDGE_HASH_TABLE: return "old-bridge-hash-table";
107         case INTERNAL_MEM_OLD_BRIDGE_HASH_TABLE_ENTRY: return "old-bridge-hash-table-entry";
108         case INTERNAL_MEM_BRIDGE_HASH_TABLE: return "bridge-hash-table";
109         case INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY: return "bridge-hash-table-entry";
110         case INTERNAL_MEM_TARJAN_BRIDGE_HASH_TABLE: return "tarjan-bridge-hash-table";
111         case INTERNAL_MEM_TARJAN_BRIDGE_HASH_TABLE_ENTRY: return "tarjan-bridge-hash-table-entry";
112         case INTERNAL_MEM_TARJAN_OBJ_BUCKET: return "tarjan-bridge-object-buckets";
113         case INTERNAL_MEM_BRIDGE_ALIVE_HASH_TABLE: return "bridge-alive-hash-table";
114         case INTERNAL_MEM_BRIDGE_ALIVE_HASH_TABLE_ENTRY: return "bridge-alive-hash-table-entry";
115         case INTERNAL_MEM_BRIDGE_DEBUG: return "bridge-debug";
116         case INTERNAL_MEM_JOB_QUEUE_ENTRY: return "job-queue-entry";
117         case INTERNAL_MEM_TOGGLEREF_DATA: return "toggleref-data";
118         case INTERNAL_MEM_CARDTABLE_MOD_UNION: return "cardtable-mod-union";
119         case INTERNAL_MEM_BINARY_PROTOCOL: return "binary-protocol";
120         default:
121                 g_assert_not_reached ();
122         }
123 }
124
125 void*
126 sgen_alloc_internal_dynamic (size_t size, int type, gboolean assert_on_failure)
127 {
128         int index;
129         void *p;
130
131         if (size > allocator_sizes [NUM_ALLOCATORS - 1]) {
132                 p = sgen_alloc_os_memory (size, SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE, NULL);
133                 if (!p)
134                         sgen_assert_memory_alloc (NULL, size, description_for_type (type));
135         } else {
136                 index = index_for_size (size);
137
138                 p = mono_lock_free_alloc (&allocators [index]);
139                 if (!p)
140                         sgen_assert_memory_alloc (NULL, size, description_for_type (type));
141                 memset (p, 0, size);
142         }
143
144         MONO_GC_INTERNAL_ALLOC ((mword)p, size, type);
145         return p;
146 }
147
148 void
149 sgen_free_internal_dynamic (void *addr, size_t size, int type)
150 {
151         if (!addr)
152                 return;
153
154         if (size > allocator_sizes [NUM_ALLOCATORS - 1])
155                 sgen_free_os_memory (addr, size, SGEN_ALLOC_INTERNAL);
156         else
157                 mono_lock_free_free (addr);
158
159         MONO_GC_INTERNAL_DEALLOC ((mword)addr, size, type);
160 }
161
162 void*
163 sgen_alloc_internal (int type)
164 {
165         int index = fixed_type_allocator_indexes [type];
166         int size = allocator_sizes [index];
167         void *p;
168         g_assert (index >= 0 && index < NUM_ALLOCATORS);
169         p = mono_lock_free_alloc (&allocators [index]);
170         memset (p, 0, size);
171
172         MONO_GC_INTERNAL_ALLOC ((mword)p, size, type);
173
174         return p;
175 }
176
177 void
178 sgen_free_internal (void *addr, int type)
179 {
180         int index;
181
182         if (!addr)
183                 return;
184
185         index = fixed_type_allocator_indexes [type];
186         g_assert (index >= 0 && index < NUM_ALLOCATORS);
187
188         mono_lock_free_free (addr);
189
190         if (MONO_GC_INTERNAL_DEALLOC_ENABLED ()) {
191                 int size G_GNUC_UNUSED = allocator_sizes [index];
192                 MONO_GC_INTERNAL_DEALLOC ((mword)addr, size, type);
193         }
194 }
195
196 void
197 sgen_dump_internal_mem_usage (FILE *heap_dump_file)
198 {
199         /*
200         int i;
201
202         fprintf (heap_dump_file, "<other-mem-usage type=\"large-internal\" size=\"%lld\"/>\n", large_internal_bytes_alloced);
203         fprintf (heap_dump_file, "<other-mem-usage type=\"pinned-chunks\" size=\"%lld\"/>\n", pinned_chunk_bytes_alloced);
204         for (i = 0; i < INTERNAL_MEM_MAX; ++i) {
205                 fprintf (heap_dump_file, "<other-mem-usage type=\"%s\" size=\"%ld\"/>\n",
206                                 description_for_type (i), unmanaged_allocator.small_internal_mem_bytes [i]);
207         }
208         */
209 }
210
211 void
212 sgen_report_internal_mem_usage (void)
213 {
214         /* FIXME: implement */
215         printf ("not implemented yet\n");
216 }
217
218 void
219 sgen_init_internal_allocator (void)
220 {
221         int i;
222
223         for (i = 0; i < INTERNAL_MEM_MAX; ++i)
224                 fixed_type_allocator_indexes [i] = -1;
225
226         for (i = 0; i < NUM_ALLOCATORS; ++i) {
227                 mono_lock_free_allocator_init_size_class (&size_classes [i], allocator_sizes [i]);
228                 mono_lock_free_allocator_init_allocator (&allocators [i], &size_classes [i]);
229         }
230 }
231
232 #endif