[amd64] Remove the callee saved registers from MonoLMF, save/restore them normally...
[mono-project.git] / mono / metadata / gc-memfuncs.c
blob1b3d6b29e1ebe79b76105148d803a6900cce588b
1 /*
2 * test-sgen-qsort.c: Our own bzero/memmove.
4 * Copyright (C) 2013 Xamarin Inc
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;
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.
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.
21 * SGen cannot deal with invalid pointers on the heap or in registered roots. Sometimes we
22 * need to copy or zero out memory in code that might be interrupted by collections. To
23 * guarantee that those operations will not result in invalid pointers, we must do it
24 * word-atomically.
26 * libc's bzero() and memcpy()/memmove() functions do not guarantee word-atomicity, even in
27 * cases where one would assume so. For instance, some implementations (like Darwin's on
28 * x86) have variants of memcpy() using vector instructions. Those may copy bytewise for
29 * the region preceding the first vector-aligned address. That region could be
30 * word-aligned, but it would still be copied byte-wise.
32 * All our memory writes here are to "volatile" locations. This is so that C compilers
33 * don't "optimize" our code back to calls to bzero()/memmove(). LLVM, specifically, will
34 * do that.
37 #include <config.h>
39 #include "metadata/gc-internal.h"
41 #define ptr_mask ((sizeof (void*) - 1))
42 #define _toi(ptr) ((size_t)ptr)
43 #define unaligned_bytes(ptr) (_toi(ptr) & ptr_mask)
44 #define align_down(ptr) ((void*)(_toi(ptr) & ~ptr_mask))
45 #define align_up(ptr) ((void*) ((_toi(ptr) + ptr_mask) & ~ptr_mask))
46 #if SIZEOF_VOID_P == 4
47 #define bytes_to_words(n) ((size_t)(n) >> 2)
48 #elif SIZEOF_VOID_P == 8
49 #define bytes_to_words(n) ((size_t)(n) >> 3)
50 #else
51 #error We only support 32 and 64 bit architectures.
52 #endif
54 #define BZERO_WORDS(dest,words) do { \
55 void * volatile *__d = (void* volatile*)(dest); \
56 int __n = (words); \
57 int __i; \
58 for (__i = 0; __i < __n; ++__i) \
59 __d [__i] = NULL; \
60 } while (0)
63 /**
64 * mono_gc_bzero_aligned:
65 * @dest: address to start to clear
66 * @size: size of the region to clear
68 * Zero @size bytes starting at @dest.
69 * The address of @dest MUST be aligned to word boundaries
71 * FIXME borrow faster code from some BSD libc or bionic
73 void
74 mono_gc_bzero_aligned (void *dest, size_t size)
76 volatile char *d = (char*)dest;
77 size_t tail_bytes, word_bytes;
79 g_assert (unaligned_bytes (dest) == 0);
81 /* copy all words with memmove */
82 word_bytes = (size_t)align_down (size);
83 switch (word_bytes) {
84 case sizeof (void*) * 1:
85 BZERO_WORDS (d, 1);
86 break;
87 case sizeof (void*) * 2:
88 BZERO_WORDS (d, 2);
89 break;
90 case sizeof (void*) * 3:
91 BZERO_WORDS (d, 3);
92 break;
93 case sizeof (void*) * 4:
94 BZERO_WORDS (d, 4);
95 break;
96 default:
97 BZERO_WORDS (d, bytes_to_words (word_bytes));
100 tail_bytes = unaligned_bytes (size);
101 if (tail_bytes) {
102 d += word_bytes;
103 do {
104 *d++ = 0;
105 } while (--tail_bytes);
110 * mono_gc_bzero_atomic:
111 * @dest: address to start to clear
112 * @size: size of the region to clear
114 * Zero @size bytes starting at @dest.
116 * Use this to zero memory without word tearing when dest is aligned.
118 void
119 mono_gc_bzero_atomic (void *dest, size_t size)
121 if (unaligned_bytes (dest))
122 memset (dest, 0, size);
123 else
124 mono_gc_bzero_aligned (dest, size);
127 #define MEMMOVE_WORDS_UPWARD(dest,src,words) do { \
128 void * volatile *__d = (void* volatile*)(dest); \
129 void **__s = (void**)(src); \
130 int __n = (int)(words); \
131 int __i; \
132 for (__i = 0; __i < __n; ++__i) \
133 __d [__i] = __s [__i]; \
134 } while (0)
136 #define MEMMOVE_WORDS_DOWNWARD(dest,src,words) do { \
137 void * volatile *__d = (void* volatile*)(dest); \
138 void **__s = (void**)(src); \
139 int __n = (int)(words); \
140 int __i; \
141 for (__i = __n - 1; __i >= 0; --__i) \
142 __d [__i] = __s [__i]; \
143 } while (0)
147 * mono_gc_memmove_aligned:
148 * @dest: destination of the move
149 * @src: source
150 * @size: size of the block to move
152 * Move @size bytes from @src to @dest.
154 * Use this to copy memory without word tearing when both pointers are aligned
155 */void
156 mono_gc_memmove_aligned (void *dest, const void *src, size_t size)
158 g_assert (unaligned_bytes (dest) == 0);
159 g_assert (unaligned_bytes (src) == 0);
162 If we're copying less than a word we don't need to worry about word tearing
163 so we bailout to memmove early.
165 if (size < sizeof(void*)) {
166 memmove (dest, src, size);
167 return;
171 * A bit of explanation on why we align only dest before doing word copies.
172 * Pointers to managed objects must always be stored in word aligned addresses, so
173 * even if dest is misaligned, src will be by the same amount - this ensure proper atomicity of reads.
175 * We don't need to case when source and destination have different alignments since we only do word stores
176 * using memmove, which must handle it.
178 if (dest > src && ((size_t)((char*)dest - (char*)src) < size)) { /*backward copy*/
179 volatile char *p = (char*)dest + size;
180 char *s = (char*)src + size;
181 char *start = (char*)dest;
182 char *align_end = MAX((char*)dest, (char*)align_down (p));
183 char *word_start;
184 size_t bytes_to_memmove;
186 while (p > align_end)
187 *--p = *--s;
189 word_start = align_up (start);
190 bytes_to_memmove = p - word_start;
191 p -= bytes_to_memmove;
192 s -= bytes_to_memmove;
193 MEMMOVE_WORDS_DOWNWARD (p, s, bytes_to_words (bytes_to_memmove));
194 } else {
195 volatile char *d = (char*)dest;
196 const char *s = (const char*)src;
197 size_t tail_bytes;
199 /* copy all words with memmove */
200 MEMMOVE_WORDS_UPWARD (d, s, bytes_to_words (align_down (size)));
202 tail_bytes = unaligned_bytes (size);
203 if (tail_bytes) {
204 d += (size_t)align_down (size);
205 s += (size_t)align_down (size);
206 do {
207 *d++ = *s++;
208 } while (--tail_bytes);
214 * mono_gc_memmove_atomic:
215 * @dest: destination of the move
216 * @src: source
217 * @size: size of the block to move
219 * Move @size bytes from @src to @dest.
221 * Use this to copy memory without word tearing when both pointers are aligned
223 void
224 mono_gc_memmove_atomic (void *dest, const void *src, size_t size)
226 if (unaligned_bytes (_toi (dest) | _toi (src)))
227 memmove (dest, src, size);
228 else
229 mono_gc_memmove_aligned (dest, src, size);