mem.c 7.41 KB
Newer Older
1
/*
2
 * default memory allocator for libavutil
3
 * Copyright (c) 2002 Fabrice Bellard
4
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav is free software; you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * Libav is distributed in the hope that it will be useful,
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with Libav; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21

Michael Niedermayer's avatar
Michael Niedermayer committed
22
/**
23
 * @file
24
 * default memory allocator for libavutil
Michael Niedermayer's avatar
Michael Niedermayer committed
25
 */
26

27
#include "config.h"
28

29
#include <limits.h>
30
#include <stdint.h>
31
#include <stdlib.h>
32
#include <string.h>
33
#if HAVE_MALLOC_H
34 35 36
#include <malloc.h>
#endif

37
#include "avutil.h"
38
#include "intreadwrite.h"
39 40
#include "mem.h"

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
#ifdef MALLOC_PREFIX

#define malloc         AV_JOIN(MALLOC_PREFIX, malloc)
#define memalign       AV_JOIN(MALLOC_PREFIX, memalign)
#define posix_memalign AV_JOIN(MALLOC_PREFIX, posix_memalign)
#define realloc        AV_JOIN(MALLOC_PREFIX, realloc)
#define free           AV_JOIN(MALLOC_PREFIX, free)

void *malloc(size_t size);
void *memalign(size_t align, size_t size);
int   posix_memalign(void **ptr, size_t align, size_t size);
void *realloc(void *ptr, size_t size);
void  free(void *ptr);

#endif /* MALLOC_PREFIX */

57
/* You can redefine av_malloc and av_free in your project to use your
58 59
 * memory allocator. You do not need to suppress this file because the
 * linker will do it automatically. */
60

61
void *av_malloc(size_t size)
62
{
63
    void *ptr = NULL;
64
#if CONFIG_MEMALIGN_HACK
65
    long diff;
66
#endif
67

68
    /* let's disallow possible ambiguous cases */
69
    if (size > (INT_MAX - 32) || !size)
70
        return NULL;
71

72
#if CONFIG_MEMALIGN_HACK
73 74
    ptr = malloc(size + 32);
    if (!ptr)
75
        return ptr;
76 77 78
    diff              = ((-(long)ptr - 1) & 31) + 1;
    ptr               = (char *)ptr + diff;
    ((char *)ptr)[-1] = diff;
79
#elif HAVE_POSIX_MEMALIGN
80
    if (posix_memalign(&ptr, 32, size))
81
        ptr = NULL;
82 83
#elif HAVE_ALIGNED_MALLOC
    ptr = _aligned_malloc(size, 32);
84
#elif HAVE_MEMALIGN
85
    ptr = memalign(32, size);
86
    /* Why 64?
87 88 89 90 91 92 93
     * Indeed, we should align it:
     *   on  4 for 386
     *   on 16 for 486
     *   on 32 for 586, PPro - K6-III
     *   on 64 for K7 (maybe for P3 too).
     * Because L1 and L2 caches are aligned on those values.
     * But I don't want to code such logic here!
94
     */
95 96 97
    /* Why 32?
     * For AVX ASM. SSE / NEON needs only 16.
     * Why not larger? Because I did not see a difference in benchmarks ...
Michael Niedermayer's avatar
Michael Niedermayer committed
98
     */
99 100 101 102 103 104 105 106 107 108
    /* benchmarks with P3
     * memalign(64) + 1          3071, 3051, 3032
     * memalign(64) + 2          3051, 3032, 3041
     * memalign(64) + 4          2911, 2896, 2915
     * memalign(64) + 8          2545, 2554, 2550
     * memalign(64) + 16         2543, 2572, 2563
     * memalign(64) + 32         2546, 2545, 2571
     * memalign(64) + 64         2570, 2533, 2558
     *
     * BTW, malloc seems to do 8-byte alignment by default here.
Michael Niedermayer's avatar
Michael Niedermayer committed
109
     */
110 111 112 113 114 115
#else
    ptr = malloc(size);
#endif
    return ptr;
}

116
void *av_realloc(void *ptr, size_t size)
117
{
118
#if CONFIG_MEMALIGN_HACK
119 120
    int diff;
#endif
121

122
    /* let's disallow possible ambiguous cases */
123
    if (size > (INT_MAX - 16))
124 125
        return NULL;

126
#if CONFIG_MEMALIGN_HACK
127
    //FIXME this isn't aligned correctly, though it probably isn't needed
128 129 130 131
    if (!ptr)
        return av_malloc(size);
    diff = ((char *)ptr)[-1];
    return (char *)realloc((char *)ptr - diff, size + diff) + diff;
132 133
#elif HAVE_ALIGNED_MALLOC
    return _aligned_realloc(ptr, size, 32);
134 135
#else
    return realloc(ptr, size);
136
#endif
Michael Niedermayer's avatar
Michael Niedermayer committed
137 138
}

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
void *av_realloc_array(void *ptr, size_t nmemb, size_t size)
{
    if (size <= 0 || nmemb >= INT_MAX / size)
        return NULL;
    return av_realloc(ptr, nmemb * size);
}

int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
{
    void **ptrptr = ptr;
    void *ret;
    if (size <= 0 || nmemb >= INT_MAX / size)
        return AVERROR(ENOMEM);
    if (nmemb <= 0) {
        av_freep(ptr);
        return 0;
    }
    ret = av_realloc(*ptrptr, nmemb * size);
    if (!ret) {
        av_freep(ptr);
        return AVERROR(ENOMEM);
    }
    *ptrptr = ret;
    return 0;
}

165 166
void av_free(void *ptr)
{
167
#if CONFIG_MEMALIGN_HACK
168
    if (ptr)
169
        free((char *)ptr - ((char *)ptr)[-1]);
170 171
#elif HAVE_ALIGNED_MALLOC
    _aligned_free(ptr);
172
#else
173
    free(ptr);
174
#endif
175 176
}

177 178
void av_freep(void *arg)
{
179
    void **ptr = (void **)arg;
180 181 182 183
    av_free(*ptr);
    *ptr = NULL;
}

184
void *av_mallocz(size_t size)
185
{
186
    void *ptr = av_malloc(size);
187 188 189 190 191 192 193
    if (ptr)
        memset(ptr, 0, size);
    return ptr;
}

char *av_strdup(const char *s)
{
194 195
    char *ptr = NULL;
    if (s) {
Michael Niedermayer's avatar
Michael Niedermayer committed
196 197 198 199
        int len = strlen(s) + 1;
        ptr = av_malloc(len);
        if (ptr)
            memcpy(ptr, s, len);
200
    }
201 202
    return ptr;
}
203

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
static void fill16(uint8_t *dst, int len)
{
    uint32_t v = AV_RN16(dst - 2);

    v |= v << 16;

    while (len >= 4) {
        AV_WN32(dst, v);
        dst += 4;
        len -= 4;
    }

    while (len--) {
        *dst = dst[-2];
        dst++;
    }
}

static void fill24(uint8_t *dst, int len)
{
#if HAVE_BIGENDIAN
    uint32_t v = AV_RB24(dst - 3);
    uint32_t a = v << 8  | v >> 16;
    uint32_t b = v << 16 | v >> 8;
    uint32_t c = v << 24 | v;
#else
    uint32_t v = AV_RL24(dst - 3);
    uint32_t a = v       | v << 24;
    uint32_t b = v >> 8  | v << 16;
    uint32_t c = v >> 16 | v << 8;
#endif

    while (len >= 12) {
        AV_WN32(dst,     a);
        AV_WN32(dst + 4, b);
        AV_WN32(dst + 8, c);
        dst += 12;
        len -= 12;
    }

    if (len >= 4) {
        AV_WN32(dst, a);
        dst += 4;
        len -= 4;
    }

    if (len >= 4) {
        AV_WN32(dst, b);
        dst += 4;
        len -= 4;
    }

    while (len--) {
        *dst = dst[-3];
        dst++;
    }
}

static void fill32(uint8_t *dst, int len)
{
    uint32_t v = AV_RN32(dst - 4);

    while (len >= 4) {
        AV_WN32(dst, v);
        dst += 4;
        len -= 4;
    }

    while (len--) {
        *dst = dst[-4];
        dst++;
    }
}

278 279 280
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
{
    const uint8_t *src = &dst[-back];
281 282 283
    if (!back)
        return;

284 285
    if (back == 1) {
        memset(dst, *src, cnt);
286 287 288 289 290 291
    } else if (back == 2) {
        fill16(dst, cnt);
    } else if (back == 3) {
        fill24(dst, cnt);
    } else if (back == 4) {
        fill32(dst, cnt);
292
    } else {
293
        if (cnt >= 16) {
294 295 296 297 298 299 300 301
            int blocklen = back;
            while (cnt > blocklen) {
                memcpy(dst, src, blocklen);
                dst       += blocklen;
                cnt       -= blocklen;
                blocklen <<= 1;
            }
            memcpy(dst, src, cnt);
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
            return;
        }
        if (cnt >= 8) {
            AV_COPY32U(dst,     src);
            AV_COPY32U(dst + 4, src + 4);
            src += 8;
            dst += 8;
            cnt -= 8;
        }
        if (cnt >= 4) {
            AV_COPY32U(dst, src);
            src += 4;
            dst += 4;
            cnt -= 4;
        }
        if (cnt >= 2) {
            AV_COPY16U(dst, src);
            src += 2;
            dst += 2;
            cnt -= 2;
322
        }
323 324
        if (cnt)
            *dst = *src;
325 326
    }
}