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
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
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)
51 #error We only support 32 and 64 bit architectures.
54 #define BZERO_WORDS(dest,words) do { \
55 void * volatile *__d = (void* volatile*)(dest); \
58 for (__i = 0; __i < __n; ++__i) \
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
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
);
84 case sizeof (void*) * 1:
87 case sizeof (void*) * 2:
90 case sizeof (void*) * 3:
93 case sizeof (void*) * 4:
97 BZERO_WORDS (d
, bytes_to_words (word_bytes
));
100 tail_bytes
= unaligned_bytes (size
);
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.
119 mono_gc_bzero_atomic (void *dest
, size_t size
)
121 if (unaligned_bytes (dest
))
122 memset (dest
, 0, size
);
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); \
132 for (__i = 0; __i < __n; ++__i) \
133 __d [__i] = __s [__i]; \
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); \
141 for (__i = __n - 1; __i >= 0; --__i) \
142 __d [__i] = __s [__i]; \
147 * mono_gc_memmove_aligned:
148 * @dest: destination of the move
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
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
);
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
));
184 size_t bytes_to_memmove
;
186 while (p
> align_end
)
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
));
195 volatile char *d
= (char*)dest
;
196 const char *s
= (const char*)src
;
199 /* copy all words with memmove */
200 MEMMOVE_WORDS_UPWARD (d
, s
, bytes_to_words (align_down (size
)));
202 tail_bytes
= unaligned_bytes (size
);
204 d
+= (size_t)align_down (size
);
205 s
+= (size_t)align_down (size
);
208 } while (--tail_bytes
);
214 * mono_gc_memmove_atomic:
215 * @dest: destination of the move
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
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
);
229 mono_gc_memmove_aligned (dest
, src
, size
);