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