Add [Category ("NotWorking")] to failing test.
[mono.git] / mono / metadata / gc-memfuncs.c
1 /*
2  * test-sgen-qsort.c: Our own bzero/memmove.
3  *
4  * Copyright (C) 2013 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 #include "metadata/gc-internal.h"
23
24 #define ptr_mask ((sizeof (void*) - 1))
25 #define _toi(ptr) ((size_t)ptr)
26 #define unaligned_bytes(ptr) (_toi(ptr) & ptr_mask)
27 #define align_down(ptr) ((void*)(_toi(ptr) & ~ptr_mask))
28 #define align_up(ptr) ((void*) ((_toi(ptr) + ptr_mask) & ~ptr_mask))
29 #if SIZEOF_VOID_P == 4
30 #define bytes_to_words(n)       ((size_t)(n) >> 2)
31 #elif SIZEOF_VOID_P == 8
32 #define bytes_to_words(n)       ((size_t)(n) >> 3)
33 #else
34 #error We only support 32 and 64 bit architectures.
35 #endif
36
37 #define BZERO_WORDS(dest,words) do {                    \
38                 void **__d = (void**)(dest);            \
39                 int __n = (words);                      \
40                 int __i;                                \
41                 for (__i = 0; __i < __n; ++__i)         \
42                         __d [__i] = NULL;               \
43         } while (0)
44
45 /**
46  * mono_gc_bzero:
47  * @dest: address to start to clear
48  * @size: size of the region to clear
49  *
50  * Zero @size bytes starting at @dest.
51  *
52  * Use this to zero memory that can hold managed pointers.
53  *
54  * FIXME borrow faster code from some BSD libc or bionic
55  */
56 void
57 mono_gc_bzero (void *dest, size_t size)
58 {
59         char *d = (char*)dest;
60         size_t tail_bytes, word_bytes;
61
62         /*
63         If we're copying less than a word, just use memset.
64
65         We cannot bail out early if both are aligned because some implementations
66         use byte copying for sizes smaller than 16. OSX, on this case.
67         */
68         if (size < sizeof(void*)) {
69                 memset (dest, 0, size);
70                 return;
71         }
72
73         /*align to word boundary */
74         while (unaligned_bytes (d) && size) {
75                 *d++ = 0;
76                 --size;
77         }
78
79         /* copy all words with memmove */
80         word_bytes = (size_t)align_down (size);
81         switch (word_bytes) {
82         case sizeof (void*) * 1:
83                 BZERO_WORDS (d, 1);
84                 break;
85         case sizeof (void*) * 2:
86                 BZERO_WORDS (d, 2);
87                 break;
88         case sizeof (void*) * 3:
89                 BZERO_WORDS (d, 3);
90                 break;
91         case sizeof (void*) * 4:
92                 BZERO_WORDS (d, 4);
93                 break;
94         default:
95                 BZERO_WORDS (d, bytes_to_words (word_bytes));
96         }
97
98         tail_bytes = unaligned_bytes (size);
99         if (tail_bytes) {
100                 d += word_bytes;
101                 do {
102                         *d++ = 0;
103                 } while (--tail_bytes);
104         }
105 }
106
107 #define MEMMOVE_WORDS_UPWARD(dest,src,words) do {       \
108                 void **__d = (void**)(dest);            \
109                 void **__s = (void**)(src);             \
110                 int __n = (int)(words);                 \
111                 int __i;                                \
112                 for (__i = 0; __i < __n; ++__i)         \
113                         __d [__i] = __s [__i];          \
114         } while (0)
115
116 #define MEMMOVE_WORDS_DOWNWARD(dest,src,words) do {     \
117                 void **__d = (void**)(dest);            \
118                 void **__s = (void**)(src);             \
119                 int __n = (int)(words);                 \
120                 int __i;                                \
121                 for (__i = __n - 1; __i >= 0; --__i)    \
122                         __d [__i] = __s [__i];          \
123         } while (0)
124
125 /**
126  * mono_gc_memmove:
127  * @dest: destination of the move
128  * @src: source
129  * @size: size of the block to move
130  *
131  * Move @size bytes from @src to @dest.
132  * size MUST be a multiple of sizeof (gpointer)
133  *
134  */
135 void
136 mono_gc_memmove (void *dest, const void *src, size_t size)
137 {
138         /*
139         If we're copying less than a word we don't need to worry about word tearing
140         so we bailout to memmove early.
141         */
142         if (size < sizeof(void*)) {
143                 memmove (dest, src, size);
144                 return;
145         }
146
147         /*
148          * A bit of explanation on why we align only dest before doing word copies.
149          * Pointers to managed objects must always be stored in word aligned addresses, so
150          * even if dest is misaligned, src will be by the same amount - this ensure proper atomicity of reads.
151          *
152          * We don't need to case when source and destination have different alignments since we only do word stores
153          * using memmove, which must handle it.
154          */
155         if (dest > src && ((size_t)((char*)dest - (char*)src) < size)) { /*backward copy*/
156                 char *p = (char*)dest + size;
157                         char *s = (char*)src + size;
158                         char *start = (char*)dest;
159                         char *align_end = MAX((char*)dest, (char*)align_down (p));
160                         char *word_start;
161                         size_t bytes_to_memmove;
162
163                         while (p > align_end)
164                                 *--p = *--s;
165
166                         word_start = align_up (start);
167                         bytes_to_memmove = p - word_start;
168                         p -= bytes_to_memmove;
169                         s -= bytes_to_memmove;
170                         MEMMOVE_WORDS_DOWNWARD (p, s, bytes_to_words (bytes_to_memmove));
171
172                         while (p > start)
173                                 *--p = *--s;
174         } else {
175                 char *d = (char*)dest;
176                 const char *s = (const char*)src;
177                 size_t tail_bytes;
178
179                 /*align to word boundary */
180                 while (unaligned_bytes (d)) {
181                         *d++ = *s++;
182                         --size;
183                 }
184
185                 /* copy all words with memmove */
186                 MEMMOVE_WORDS_UPWARD (d, s, bytes_to_words (align_down (size)));
187
188                 tail_bytes = unaligned_bytes (size);
189                 if (tail_bytes) {
190                         d += (size_t)align_down (size);
191                         s += (size_t)align_down (size);
192                         do {
193                                 *d++ = *s++;
194                         } while (--tail_bytes);
195                 }
196         }
197 }