yading@11: /* yading@11: * default memory allocator for libavutil yading@11: * Copyright (c) 2002 Fabrice Bellard yading@11: * yading@11: * This file is part of FFmpeg. yading@11: * yading@11: * FFmpeg is free software; you can redistribute it and/or yading@11: * modify it under the terms of the GNU Lesser General Public yading@11: * License as published by the Free Software Foundation; either yading@11: * version 2.1 of the License, or (at your option) any later version. yading@11: * yading@11: * FFmpeg is distributed in the hope that it will be useful, yading@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@11: * Lesser General Public License for more details. yading@11: * yading@11: * You should have received a copy of the GNU Lesser General Public yading@11: * License along with FFmpeg; if not, write to the Free Software yading@11: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@11: */ yading@11: yading@11: /** yading@11: * @file yading@11: * default memory allocator for libavutil yading@11: */ yading@11: yading@11: #define _XOPEN_SOURCE 600 yading@11: yading@11: #include "config.h" yading@11: yading@11: #include yading@11: #include yading@11: #include yading@11: #include yading@11: #if HAVE_MALLOC_H yading@11: #include yading@11: #endif yading@11: yading@11: #include "avassert.h" yading@11: #include "avutil.h" yading@11: #include "intreadwrite.h" yading@11: #include "mem.h" yading@11: yading@11: #ifdef MALLOC_PREFIX yading@11: yading@11: #define malloc AV_JOIN(MALLOC_PREFIX, malloc) yading@11: #define memalign AV_JOIN(MALLOC_PREFIX, memalign) yading@11: #define posix_memalign AV_JOIN(MALLOC_PREFIX, posix_memalign) yading@11: #define realloc AV_JOIN(MALLOC_PREFIX, realloc) yading@11: #define free AV_JOIN(MALLOC_PREFIX, free) yading@11: yading@11: void *malloc(size_t size); yading@11: void *memalign(size_t align, size_t size); yading@11: int posix_memalign(void **ptr, size_t align, size_t size); yading@11: void *realloc(void *ptr, size_t size); yading@11: void free(void *ptr); yading@11: yading@11: #endif /* MALLOC_PREFIX */ yading@11: yading@11: #define ALIGN (HAVE_AVX ? 32 : 16) yading@11: yading@11: /* NOTE: if you want to override these functions with your own yading@11: * implementations (not recommended) you have to link libav* as yading@11: * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags. yading@11: * Note that this will cost performance. */ yading@11: yading@11: static size_t max_alloc_size= INT_MAX; yading@11: yading@11: void av_max_alloc(size_t max){ yading@11: max_alloc_size = max; yading@11: } yading@11: yading@11: void *av_malloc(size_t size) yading@11: { yading@11: void *ptr = NULL; yading@11: #if CONFIG_MEMALIGN_HACK yading@11: long diff; yading@11: #endif yading@11: yading@11: /* let's disallow possible ambiguous cases */ yading@11: if (size > (max_alloc_size - 32)) yading@11: return NULL; yading@11: yading@11: #if CONFIG_MEMALIGN_HACK yading@11: ptr = malloc(size + ALIGN); yading@11: if (!ptr) yading@11: return ptr; yading@11: diff = ((~(long)ptr)&(ALIGN - 1)) + 1; yading@11: ptr = (char *)ptr + diff; yading@11: ((char *)ptr)[-1] = diff; yading@11: #elif HAVE_POSIX_MEMALIGN yading@11: if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation yading@11: if (posix_memalign(&ptr, ALIGN, size)) yading@11: ptr = NULL; yading@11: #elif HAVE_ALIGNED_MALLOC yading@11: ptr = _aligned_malloc(size, ALIGN); yading@11: #elif HAVE_MEMALIGN yading@11: #ifndef __DJGPP__ yading@11: ptr = memalign(ALIGN, size); yading@11: #else yading@11: ptr = memalign(size, ALIGN); yading@11: #endif yading@11: /* Why 64? yading@11: * Indeed, we should align it: yading@11: * on 4 for 386 yading@11: * on 16 for 486 yading@11: * on 32 for 586, PPro - K6-III yading@11: * on 64 for K7 (maybe for P3 too). yading@11: * Because L1 and L2 caches are aligned on those values. yading@11: * But I don't want to code such logic here! yading@11: */ yading@11: /* Why 32? yading@11: * For AVX ASM. SSE / NEON needs only 16. yading@11: * Why not larger? Because I did not see a difference in benchmarks ... yading@11: */ yading@11: /* benchmarks with P3 yading@11: * memalign(64) + 1 3071, 3051, 3032 yading@11: * memalign(64) + 2 3051, 3032, 3041 yading@11: * memalign(64) + 4 2911, 2896, 2915 yading@11: * memalign(64) + 8 2545, 2554, 2550 yading@11: * memalign(64) + 16 2543, 2572, 2563 yading@11: * memalign(64) + 32 2546, 2545, 2571 yading@11: * memalign(64) + 64 2570, 2533, 2558 yading@11: * yading@11: * BTW, malloc seems to do 8-byte alignment by default here. yading@11: */ yading@11: #else yading@11: ptr = malloc(size); yading@11: #endif yading@11: if(!ptr && !size) { yading@11: size = 1; yading@11: ptr= av_malloc(1); yading@11: } yading@11: #if CONFIG_MEMORY_POISONING yading@11: if (ptr) yading@11: memset(ptr, 0x2a, size); yading@11: #endif yading@11: return ptr; yading@11: } yading@11: yading@11: void *av_realloc(void *ptr, size_t size) yading@11: { yading@11: #if CONFIG_MEMALIGN_HACK yading@11: int diff; yading@11: #endif yading@11: yading@11: /* let's disallow possible ambiguous cases */ yading@11: if (size > (max_alloc_size - 32)) yading@11: return NULL; yading@11: yading@11: #if CONFIG_MEMALIGN_HACK yading@11: //FIXME this isn't aligned correctly, though it probably isn't needed yading@11: if (!ptr) yading@11: return av_malloc(size); yading@11: diff = ((char *)ptr)[-1]; yading@11: av_assert0(diff>0 && diff<=ALIGN); yading@11: ptr = realloc((char *)ptr - diff, size + diff); yading@11: if (ptr) yading@11: ptr = (char *)ptr + diff; yading@11: return ptr; yading@11: #elif HAVE_ALIGNED_MALLOC yading@11: return _aligned_realloc(ptr, size + !size, ALIGN); yading@11: #else yading@11: return realloc(ptr, size + !size); yading@11: #endif yading@11: } yading@11: yading@11: void *av_realloc_f(void *ptr, size_t nelem, size_t elsize) yading@11: { yading@11: size_t size; yading@11: void *r; yading@11: yading@11: if (av_size_mult(elsize, nelem, &size)) { yading@11: av_free(ptr); yading@11: return NULL; yading@11: } yading@11: r = av_realloc(ptr, size); yading@11: if (!r && size) yading@11: av_free(ptr); yading@11: return r; yading@11: } yading@11: yading@11: void av_free(void *ptr) yading@11: { yading@11: #if CONFIG_MEMALIGN_HACK yading@11: if (ptr) { yading@11: int v= ((char *)ptr)[-1]; yading@11: av_assert0(v>0 && v<=ALIGN); yading@11: free((char *)ptr - v); yading@11: } yading@11: #elif HAVE_ALIGNED_MALLOC yading@11: _aligned_free(ptr); yading@11: #else yading@11: free(ptr); yading@11: #endif yading@11: } yading@11: yading@11: void av_freep(void *arg) yading@11: { yading@11: void **ptr = (void **)arg; yading@11: av_free(*ptr); yading@11: *ptr = NULL; yading@11: } yading@11: yading@11: void *av_mallocz(size_t size) yading@11: { yading@11: void *ptr = av_malloc(size); yading@11: if (ptr) yading@11: memset(ptr, 0, size); yading@11: return ptr; yading@11: } yading@11: yading@11: void *av_calloc(size_t nmemb, size_t size) yading@11: { yading@11: if (size <= 0 || nmemb >= INT_MAX / size) yading@11: return NULL; yading@11: return av_mallocz(nmemb * size); yading@11: } yading@11: yading@11: char *av_strdup(const char *s) yading@11: { yading@11: char *ptr = NULL; yading@11: if (s) { yading@11: int len = strlen(s) + 1; yading@11: ptr = av_malloc(len); yading@11: if (ptr) yading@11: memcpy(ptr, s, len); yading@11: } yading@11: return ptr; yading@11: } yading@11: yading@11: /* add one element to a dynamic array */ yading@11: void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem) yading@11: { yading@11: /* see similar ffmpeg.c:grow_array() */ yading@11: int nb, nb_alloc; yading@11: intptr_t *tab; yading@11: yading@11: nb = *nb_ptr; yading@11: tab = *(intptr_t**)tab_ptr; yading@11: if ((nb & (nb - 1)) == 0) { yading@11: if (nb == 0) yading@11: nb_alloc = 1; yading@11: else yading@11: nb_alloc = nb * 2; yading@11: tab = av_realloc(tab, nb_alloc * sizeof(intptr_t)); yading@11: *(intptr_t**)tab_ptr = tab; yading@11: } yading@11: tab[nb++] = (intptr_t)elem; yading@11: *nb_ptr = nb; yading@11: } yading@11: yading@11: static void fill16(uint8_t *dst, int len) yading@11: { yading@11: uint32_t v = AV_RN16(dst - 2); yading@11: yading@11: v |= v << 16; yading@11: yading@11: while (len >= 4) { yading@11: AV_WN32(dst, v); yading@11: dst += 4; yading@11: len -= 4; yading@11: } yading@11: yading@11: while (len--) { yading@11: *dst = dst[-2]; yading@11: dst++; yading@11: } yading@11: } yading@11: yading@11: static void fill24(uint8_t *dst, int len) yading@11: { yading@11: #if HAVE_BIGENDIAN yading@11: uint32_t v = AV_RB24(dst - 3); yading@11: uint32_t a = v << 8 | v >> 16; yading@11: uint32_t b = v << 16 | v >> 8; yading@11: uint32_t c = v << 24 | v; yading@11: #else yading@11: uint32_t v = AV_RL24(dst - 3); yading@11: uint32_t a = v | v << 24; yading@11: uint32_t b = v >> 8 | v << 16; yading@11: uint32_t c = v >> 16 | v << 8; yading@11: #endif yading@11: yading@11: while (len >= 12) { yading@11: AV_WN32(dst, a); yading@11: AV_WN32(dst + 4, b); yading@11: AV_WN32(dst + 8, c); yading@11: dst += 12; yading@11: len -= 12; yading@11: } yading@11: yading@11: if (len >= 4) { yading@11: AV_WN32(dst, a); yading@11: dst += 4; yading@11: len -= 4; yading@11: } yading@11: yading@11: if (len >= 4) { yading@11: AV_WN32(dst, b); yading@11: dst += 4; yading@11: len -= 4; yading@11: } yading@11: yading@11: while (len--) { yading@11: *dst = dst[-3]; yading@11: dst++; yading@11: } yading@11: } yading@11: yading@11: static void fill32(uint8_t *dst, int len) yading@11: { yading@11: uint32_t v = AV_RN32(dst - 4); yading@11: yading@11: while (len >= 4) { yading@11: AV_WN32(dst, v); yading@11: dst += 4; yading@11: len -= 4; yading@11: } yading@11: yading@11: while (len--) { yading@11: *dst = dst[-4]; yading@11: dst++; yading@11: } yading@11: } yading@11: yading@11: void av_memcpy_backptr(uint8_t *dst, int back, int cnt) yading@11: { yading@11: const uint8_t *src = &dst[-back]; yading@11: if (!back) yading@11: return; yading@11: yading@11: if (back == 1) { yading@11: memset(dst, *src, cnt); yading@11: } else if (back == 2) { yading@11: fill16(dst, cnt); yading@11: } else if (back == 3) { yading@11: fill24(dst, cnt); yading@11: } else if (back == 4) { yading@11: fill32(dst, cnt); yading@11: } else { yading@11: if (cnt >= 16) { yading@11: int blocklen = back; yading@11: while (cnt > blocklen) { yading@11: memcpy(dst, src, blocklen); yading@11: dst += blocklen; yading@11: cnt -= blocklen; yading@11: blocklen <<= 1; yading@11: } yading@11: memcpy(dst, src, cnt); yading@11: return; yading@11: } yading@11: if (cnt >= 8) { yading@11: AV_COPY32U(dst, src); yading@11: AV_COPY32U(dst + 4, src + 4); yading@11: src += 8; yading@11: dst += 8; yading@11: cnt -= 8; yading@11: } yading@11: if (cnt >= 4) { yading@11: AV_COPY32U(dst, src); yading@11: src += 4; yading@11: dst += 4; yading@11: cnt -= 4; yading@11: } yading@11: if (cnt >= 2) { yading@11: AV_COPY16U(dst, src); yading@11: src += 2; yading@11: dst += 2; yading@11: cnt -= 2; yading@11: } yading@11: if (cnt) yading@11: *dst = *src; yading@11: } yading@11: } yading@11: