1 /*===========================================================================
2 * Filename : alloc.c
3 * About : memory allocators
4 *
5 * Copyright (C) 2005 Kazuki Ohta <mover AT hct.zaq.ne.jp>
6 * Copyright (C) 2005 Jun Inoue <jun.lambda AT gmail.com>
7 * Copyright (C) 2005-2006 YAMAMOTO Kengo <yamaken AT bp.iij4u.or.jp>
8 * Copyright (c) 2007-2008 SigScheme Project <uim-en AT googlegroups.com>
9 *
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of authors nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
26 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
27 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
29 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
32 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 ===========================================================================*/
37
38 #include <config.h>
39
40 #include <stdlib.h>
41 #include <string.h>
42 #if (HAVE_MEMALIGN && HAVE_MALLOC_H)
43 #include <malloc.h>
44 #endif
45 #if HAVE_GETPAGESIZE
46 #include <unistd.h>
47 #endif
48
49 #include "sigscheme.h"
50 #include "sigschemeinternal.h"
51
52 /*=======================================
53 File Local Macro Definitions
54 =======================================*/
55
56 /*=======================================
57 File Local Type Definitions
58 =======================================*/
59
60 /*=======================================
61 Variable Definitions
62 =======================================*/
63
64 /*=======================================
65 File Local Function Declarations
66 =======================================*/
67
68 /*=======================================
69 Function Definitions
70 =======================================*/
71 /* Allocates sizeof(ScmCell)-byte aligned memory for heaps. */
72 /* TODO: Align to more large size to fit better to cache, MMU and DRAM pages */
73 SCM_EXPORT void *
scm_malloc_aligned(size_t size)74 scm_malloc_aligned(size_t size)
75 {
76 void *p;
77
78 #if HAVE_POSIX_MEMALIGN
79 int err;
80
81 /*
82 * Cited from manpage of posix_memalign(3) of glibc:
83 *
84 * CONFORMING TO
85 * The function valloc() appeared in 3.0 BSD. It is documented as being
86 * obsolete in BSD 4.3, and as legacy in SUSv2. It no longer occurs in
87 * SUSv3. The function memalign() appears in SunOS 4.1.3 but not in
88 * BSD 4.4. The function posix_memalign() comes from POSIX 1003.1d.
89 */
90 err = posix_memalign(&p, sizeof(ScmCell), size);
91 if (err)
92 p = NULL;
93 #elif HAVE_MEMALIGN
94 SCM_ASSERT(!(sizeof(ScmCell) % sizeof(void *)));
95 SCM_ASSERT(sizeof(ScmCell) == 8
96 || sizeof(ScmCell) == 16
97 || sizeof(ScmCell) == 32);
98 p = memalign(sizeof(ScmCell), size);
99 #elif (HAVE_PAGE_ALIGNED_MALLOC && HAVE_GETPAGESIZE)
100 if ((size_t)getpagesize() <= size)
101 p = scm_malloc(size);
102 else
103 PLAIN_ERR("cannot ensure memory alignment");
104 #elif defined(__APPLE__)
105 /*
106 * malloc in Mac OS X guarantees 16 byte alignment. And large
107 * memory allocations are guaranteed to be page-aligned. See
108 * http://developer.apple.com/documentation/Performance/Conceptual/
109 * ManagingMemory/Articles/MemoryAlloc.html
110 * --
111 * ekato Jan 23 2006
112 */
113 if (sizeof(ScmCell) <= 16)
114 p = malloc(size);
115 else
116 PLAIN_ERR("cannot ensure memory alignment");
117 #else
118 /* Assumes that malloc(3) returns at least 8-byte aligned pointer. 64-bit
119 * pointers cannot be handled by this method. */
120 if (sizeof(ScmCell) <= 8)
121 p = malloc(size);
122 else
123 PLAIN_ERR("cannot ensure memory alignment");
124 #endif
125 ENSURE_ALLOCATED(p);
126 /* heaps must be aligned to ScmCell */
127 SCM_ASSERT(!((uintptr_t)p % sizeof(ScmCell)));
128
129 return p;
130 }
131
132 SCM_EXPORT void *
scm_malloc(size_t size)133 scm_malloc(size_t size)
134 {
135 void *p;
136
137 p = malloc(size);
138 ENSURE_ALLOCATED(p);
139
140 return p;
141 }
142
143 SCM_EXPORT void *
scm_calloc(size_t number,size_t size)144 scm_calloc(size_t number, size_t size)
145 {
146 void *p;
147
148 p = calloc(number, size);
149 ENSURE_ALLOCATED(p);
150
151 return p;
152 }
153
154 SCM_EXPORT void *
scm_realloc(void * ptr,size_t size)155 scm_realloc(void *ptr, size_t size)
156 {
157 void *p;
158
159 p = realloc(ptr, size);
160 ENSURE_ALLOCATED(p);
161
162 return p;
163 }
164
165 SCM_EXPORT char *
scm_strdup(const char * str)166 scm_strdup(const char *str)
167 {
168 char *copied;
169
170 #if HAVE_STRDUP
171 copied = strdup(str);
172 ENSURE_ALLOCATED(copied);
173 #else
174 size_t size;
175
176 size = strlen(str) + sizeof("");
177 copied = scm_malloc(size);
178 strcpy(copied, str);
179 #endif
180
181 return copied;
182 }
183
184 /* For 'name' slot of symbol object on storage-compact. If your malloc(3) does
185 * not ensure 8-bytes alignment, Complete this function and hook this into
186 * symbol object creation and modification. -- YamaKen 2006-05-30
187 *
188 * At least strdup(3) with short string in FreeBSD Release 7.0 BETA1.5
189 * and 8.0-CURRENT x86 returns unaligned address -- ekato 2007-11-04 */
190 SCM_EXPORT char *
scm_align_str(char * str)191 scm_align_str(char *str)
192 {
193 char *copied;
194 size_t size;
195
196 /* Use ScmCell-alignment to ensure at least 8-bytes aligned. */
197 if ((uintptr_t)str % sizeof(ScmCell)) {
198 size = strlen(str) + sizeof("");
199 copied = scm_malloc_aligned(size);
200 strcpy(copied, str);
201 free(str);
202 return copied;
203 } else {
204 return str;
205 }
206 }
207
208 /*=======================================
209 Extendable Local Buffer
210 =======================================*/
211 SCM_EXPORT void
scm_lbuf_init(struct ScmLBuf_void_ * lbuf,void * init_buf,size_t init_size)212 scm_lbuf_init(struct ScmLBuf_void_ *lbuf, void *init_buf, size_t init_size)
213 {
214 lbuf->buf = lbuf->init_buf = init_buf;
215 lbuf->size = lbuf->init_size = init_size;
216 lbuf->extended_cnt = 0;
217 }
218
219 SCM_EXPORT void
scm_lbuf_free(struct ScmLBuf_void_ * lbuf)220 scm_lbuf_free(struct ScmLBuf_void_ *lbuf)
221 {
222 if (lbuf->buf != lbuf->init_buf)
223 free(lbuf->buf);
224 }
225
226 SCM_EXPORT void
scm_lbuf_alloc(struct ScmLBuf_void_ * lbuf,size_t size)227 scm_lbuf_alloc(struct ScmLBuf_void_ *lbuf, size_t size)
228 {
229 lbuf->buf = scm_malloc(size);
230 lbuf->size = size;
231 }
232
233 SCM_EXPORT void
scm_lbuf_realloc(struct ScmLBuf_void_ * lbuf,size_t size)234 scm_lbuf_realloc(struct ScmLBuf_void_ *lbuf, size_t size)
235 {
236 if (lbuf->buf == lbuf->init_buf) {
237 if (size < lbuf->size)
238 lbuf->size = size;
239 lbuf->buf = memcpy(scm_malloc(size), lbuf->buf, lbuf->size);
240 } else {
241 lbuf->buf = scm_realloc(lbuf->buf, size);
242 }
243 lbuf->size = size;
244 }
245
246 SCM_EXPORT void
scm_lbuf_extend(struct ScmLBuf_void_ * lbuf,size_t (* f)(struct ScmLBuf_void_ *),size_t least_size)247 scm_lbuf_extend(struct ScmLBuf_void_ *lbuf,
248 size_t (*f)(struct ScmLBuf_void_ *), size_t least_size)
249 {
250 size_t new_size;
251
252 if (lbuf->size < least_size) {
253 new_size = (*f)(lbuf);
254 if (new_size < lbuf->size)
255 PLAIN_ERR("local buffer exceeded");
256 if (new_size < least_size)
257 new_size = least_size;
258 scm_lbuf_realloc(lbuf, new_size);
259 lbuf->extended_cnt++;
260 }
261 }
262
263 SCM_EXPORT size_t
scm_lbuf_f_linear(struct ScmLBuf_void_ * lbuf)264 scm_lbuf_f_linear(struct ScmLBuf_void_ *lbuf)
265 {
266 return (lbuf->size + lbuf->init_size);
267 }
268
269 SCM_EXPORT size_t
scm_lbuf_f_exponential(struct ScmLBuf_void_ * lbuf)270 scm_lbuf_f_exponential(struct ScmLBuf_void_ *lbuf)
271 {
272 return (lbuf->size << 1);
273 }
274