20 #include FT_CONFIG_CONFIG_H 21 #include FT_INTERNAL_DEBUG_H 22 #include FT_INTERNAL_MEMORY_H 28 #ifdef FT_DEBUG_MEMORY 36 #include FT_CONFIG_STANDARD_LIBRARY_H 45 typedef struct FT_MemSourceRec_* FT_MemSource;
46 typedef struct FT_MemNodeRec_* FT_MemNode;
47 typedef struct FT_MemTableRec_* FT_MemTable;
50 #define FT_MEM_VAL( addr ) ((FT_PtrDist)(FT_Pointer)( addr )) 57 typedef struct FT_MemSourceRec_
59 const char* file_name;
82 #define FT_MEM_SOURCE_BUCKETS 128 91 typedef struct FT_MemNodeRec_
99 const char* free_file_name;
112 typedef struct FT_MemTableRec_
129 FT_MemSource
sources[FT_MEM_SOURCE_BUCKETS];
142 #define FT_MEM_SIZE_MIN 7 143 #define FT_MEM_SIZE_MAX 13845163 145 #define FT_FILENAME( x ) ((x) ? (x) : "unknown file") 152 static const FT_UInt ft_mem_primes[] =
199 i <
sizeof ( ft_mem_primes ) /
sizeof ( ft_mem_primes[0] ); i++ )
200 if ( ft_mem_primes[i] > num )
201 return ft_mem_primes[
i];
203 return FT_MEM_SIZE_MAX;
208 ft_mem_debug_panic(
const char* fmt,
214 printf(
"FreeType.Debug: " );
226 ft_mem_table_alloc( FT_MemTable
table,
233 memory->user = table->memory_user;
234 block = table->alloc( memory, size );
235 memory->user =
table;
242 ft_mem_table_free( FT_MemTable table,
248 memory->user = table->memory_user;
249 table->free( memory, block );
250 memory->user =
table;
255 ft_mem_table_resize( FT_MemTable table )
260 new_size = ft_mem_closest_prime( table->nodes );
261 if ( new_size != table->size )
263 FT_MemNode* new_buckets;
267 new_buckets = (FT_MemNode *)
268 ft_mem_table_alloc( table,
269 new_size *
sizeof ( FT_MemNode ) );
270 if ( new_buckets ==
NULL )
275 for ( i = 0; i < table->size; i++ )
277 FT_MemNode node, next, *pnode;
281 node = table->buckets[
i];
285 hash = FT_MEM_VAL( node->address ) % new_size;
286 pnode = new_buckets + hash;
288 node->link = pnode[0];
295 if ( table->buckets )
296 ft_mem_table_free( table, table->buckets );
298 table->buckets = new_buckets;
299 table->size = new_size;
310 table = (FT_MemTable)memory->alloc( memory,
sizeof ( *table ) );
316 table->size = FT_MEM_SIZE_MIN;
319 table->memory = memory;
321 table->memory_user = memory->user;
323 table->alloc = memory->alloc;
324 table->realloc = memory->realloc;
325 table->free = memory->free;
327 table->buckets = (FT_MemNode *)
328 memory->alloc( memory,
329 table->size *
sizeof ( FT_MemNode ) );
330 if ( table->buckets )
334 memory->free( memory, table );
344 ft_mem_table_destroy( FT_MemTable table )
349 FT_DumpMemory( table->memory );
358 for ( i = 0; i < table->size; i++ )
360 FT_MemNode *pnode = table->buckets +
i, next, node = *pnode;
368 if ( node->size > 0 )
371 "leaked memory block at address %p, size %8ld in (%s:%ld)\n",
372 node->address, node->size,
373 FT_FILENAME( node->source->file_name ),
374 node->source->line_no );
379 ft_mem_table_free( table, node->address );
382 node->address =
NULL;
385 ft_mem_table_free( table, node );
388 table->buckets[
i] = 0;
391 ft_mem_table_free( table, table->buckets );
392 table->buckets =
NULL;
398 for ( i = 0; i < FT_MEM_SOURCE_BUCKETS; i++ )
400 FT_MemSource
source, next;
403 for ( source = table->sources[i]; source !=
NULL; source = next )
406 ft_mem_table_free( table, source );
409 table->sources[
i] =
NULL;
413 "FreeType: total memory allocations = %ld\n", table->alloc_total );
415 "FreeType: maximum memory footprint = %ld\n", table->alloc_max );
417 ft_mem_table_free( table, table );
419 if ( leak_count > 0 )
421 "FreeType: %ld bytes of memory leaked in %ld blocks\n",
424 printf(
"FreeType: no memory leaks detected\n" );
430 ft_mem_table_get_nodep( FT_MemTable table,
434 FT_MemNode *pnode, node;
437 hash = FT_MEM_VAL( address );
438 pnode = table->buckets + ( hash % table->size );
446 if ( node->address == address )
456 ft_mem_table_get_source( FT_MemTable table )
459 FT_MemSource node, *pnode;
466 pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS];
474 if ( node->file_name == _ft_debug_file &&
475 node->line_no == _ft_debug_lineno )
481 node = (FT_MemSource)ft_mem_table_alloc( table,
sizeof ( *node ) );
484 "not enough memory to perform memory debugging\n" );
486 node->file_name = _ft_debug_file;
487 node->line_no = _ft_debug_lineno;
489 node->cur_blocks = 0;
490 node->max_blocks = 0;
491 node->all_blocks = 0;
509 ft_mem_table_set( FT_MemTable table,
514 FT_MemNode *pnode, node;
522 pnode = ft_mem_table_get_nodep( table, address );
526 if ( node->size < 0 )
532 "memory heap corrupted (allocating freed block)" );
539 "memory heap corrupted (re-allocating allocated block at" 540 " %p, of size %ld)\n" 541 "org=%s:%d new=%s:%d\n",
542 node->address, node->size,
543 FT_FILENAME( node->source->file_name ), node->source->line_no,
544 FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
549 node = (FT_MemNode)ft_mem_table_alloc( table,
sizeof ( *node ) );
551 ft_mem_debug_panic(
"not enough memory to run memory tests" );
555 node->source = source = ft_mem_table_get_source( table );
560 source->all_blocks++;
561 source->cur_blocks++;
562 if ( source->cur_blocks > source->max_blocks )
563 source->max_blocks = source->cur_blocks;
566 if ( size > (
FT_ULong)source->cur_max )
567 source->cur_max =
size;
572 source->cur_size += delta;
573 table->alloc_current += delta;
578 source->cur_size +=
size;
579 table->alloc_current +=
size;
582 source->all_size +=
size;
584 if ( source->cur_size > source->max_size )
585 source->max_size = source->cur_size;
587 node->free_file_name =
NULL;
588 node->free_line_no = 0;
590 node->link = pnode[0];
595 table->alloc_total +=
size;
597 if ( table->alloc_current > table->alloc_max )
598 table->alloc_max = table->alloc_current;
600 if ( table->nodes * 3 < table->size ||
601 table->size * 3 < table->nodes )
602 ft_mem_table_resize( table );
608 ft_mem_table_remove( FT_MemTable table,
614 FT_MemNode *pnode, node;
617 pnode = ft_mem_table_get_nodep( table, address );
624 if ( node->size < 0 )
626 "freeing memory block at %p more than once at (%s:%ld)\n" 627 "block allocated at (%s:%ld) and released at (%s:%ld)",
629 FT_FILENAME( _ft_debug_file ), _ft_debug_lineno,
630 FT_FILENAME( node->source->file_name ), node->source->line_no,
631 FT_FILENAME( node->free_file_name ), node->free_line_no );
638 source = node->source;
640 source->cur_blocks--;
641 source->cur_size -= node->size;
643 table->alloc_current -= node->size;
646 if ( table->keep_alive )
650 node->size = -node->size;
651 node->free_file_name = _ft_debug_file;
652 node->free_line_no = _ft_debug_lineno;
663 ft_mem_table_free( table, node );
665 if ( table->nodes * 3 < table->size ||
666 table->size * 3 < table->nodes )
667 ft_mem_table_resize( table );
672 "trying to free unknown block at %p in (%s:%ld)\n",
674 FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
683 FT_MemTable table = (FT_MemTable)memory->user;
688 ft_mem_debug_panic(
"negative block size allocation (%ld)", size );
691 if ( table->bound_count &&
692 table->alloc_count >= table->alloc_count_max )
696 if ( table->bound_total &&
697 table->alloc_total_max - table->alloc_current > (
FT_ULong)size )
700 block = (
FT_Byte *)ft_mem_table_alloc( table, size );
703 ft_mem_table_set( table, block, (
FT_ULong)size, 0 );
705 table->alloc_count++;
708 _ft_debug_file =
"<unknown>";
709 _ft_debug_lineno = 0;
719 FT_MemTable table = (FT_MemTable)memory->user;
723 ft_mem_debug_panic(
"trying to free NULL in (%s:%ld)",
724 FT_FILENAME( _ft_debug_file ),
727 ft_mem_table_remove( table, (
FT_Byte*)block, 0 );
729 if ( !table->keep_alive )
730 ft_mem_table_free( table, block );
732 table->alloc_count--;
734 _ft_debug_file =
"<unknown>";
735 _ft_debug_lineno = 0;
745 FT_MemTable table = (FT_MemTable)memory->user;
746 FT_MemNode node, *pnode;
750 const char* file_name = FT_FILENAME( _ft_debug_file );
751 FT_Long line_no = _ft_debug_lineno;
755 if ( new_size == cur_size )
760 if ( block ==
NULL || cur_size == 0 )
761 ft_mem_debug_panic(
"trying to reallocate NULL in (%s:%ld)",
762 file_name, line_no );
769 "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)",
770 block, cur_size, file_name, line_no );
773 pnode = ft_mem_table_get_nodep( table, (
FT_Byte*)block );
777 "trying to reallocate unknown block at %p in (%s:%ld)",
778 block, file_name, line_no );
780 if ( node->size <= 0 )
782 "trying to reallocate freed block at %p in (%s:%ld)",
783 block, file_name, line_no );
785 if ( node->size != cur_size )
786 ft_mem_debug_panic(
"invalid ft_realloc request for %p. cur_size is " 787 "%ld instead of %ld in (%s:%ld)",
788 block, cur_size, node->size, file_name, line_no );
791 if ( table->bound_count &&
792 table->alloc_count >= table->alloc_count_max )
795 delta = (
FT_Long)( new_size - cur_size );
799 table->bound_total &&
800 table->alloc_current + (
FT_ULong)delta > table->alloc_total_max )
803 new_block = (
FT_Byte *)ft_mem_table_alloc( table, new_size );
804 if ( new_block ==
NULL )
807 ft_mem_table_set( table, (
FT_Byte*)new_block, new_size, delta );
809 ft_memcpy( new_block, block, cur_size < new_size ? cur_size : new_size );
811 ft_mem_table_remove( table, (
FT_Byte*)block, delta );
813 _ft_debug_file =
"<unknown>";
814 _ft_debug_lineno = 0;
816 if ( !table->keep_alive )
817 ft_mem_table_free( table, block );
830 if ( getenv(
"FT2_DEBUG_MEMORY" ) )
832 table = ft_mem_table_new( memory );
838 memory->user =
table;
839 memory->alloc = ft_mem_debug_alloc;
840 memory->realloc = ft_mem_debug_realloc;
841 memory->free = ft_mem_debug_free;
843 p = getenv(
"FT2_ALLOC_TOTAL_MAX" );
851 table->bound_total = 1;
852 table->alloc_total_max = (
FT_ULong)total_max;
856 p = getenv(
"FT2_ALLOC_COUNT_MAX" );
862 if ( total_count > 0 )
864 table->bound_count = 1;
865 table->alloc_count_max = (
FT_ULong)total_count;
869 p = getenv(
"FT2_KEEP_ALIVE" );
875 if ( keep_alive > 0 )
876 table->keep_alive = 1;
889 FT_MemTable table = (FT_MemTable)memory->user;
894 memory->free = table->free;
895 memory->realloc = table->realloc;
896 memory->alloc = table->alloc;
898 ft_mem_table_destroy( table );
906 ft_mem_source_compare(
const void* p1,
909 FT_MemSource
s1 = *(FT_MemSource*)p1;
910 FT_MemSource
s2 = *(FT_MemSource*)p2;
913 if ( s2->max_size > s1->max_size )
915 else if ( s2->max_size < s1->max_size )
925 FT_MemTable table = (FT_MemTable)memory->user;
930 FT_MemSource* bucket = table->sources;
931 FT_MemSource*
limit = bucket + FT_MEM_SOURCE_BUCKETS;
938 for ( ; bucket <
limit; bucket++ )
940 FT_MemSource source = *bucket;
943 for ( ;
source; source = source->link )
947 sources = (FT_MemSource*)ft_mem_table_alloc(
948 table,
sizeof ( *sources ) *
count );
951 for ( bucket = table->sources; bucket < limit; bucket++ )
953 FT_MemSource source = *bucket;
956 for ( ;
source; source = source->link )
957 sources[count++] = source;
960 ft_qsort( sources, count,
sizeof ( *sources ), ft_mem_source_compare );
962 printf(
"FreeType Memory Dump: " 963 "current=%ld max=%ld total=%ld count=%ld\n",
964 table->alloc_current, table->alloc_max,
965 table->alloc_total, table->alloc_count );
966 printf(
" block block sizes sizes sizes source\n" );
967 printf(
" count high sum highsum max location\n" );
968 printf(
"-------------------------------------------------\n" );
970 fmt =
"%6ld %6ld %8ld %8ld %8ld %s:%d\n";
972 for ( nn = 0; nn <
count; nn++ )
974 FT_MemSource source = sources[nn];
978 source->cur_blocks, source->max_blocks,
979 source->cur_size, source->max_size, source->cur_max,
980 FT_FILENAME( source->file_name ),
983 printf(
"------------------------------------------------\n" );
985 ft_mem_table_free( table, sources );
#define FT_ARRAY_ZERO(dest, count)
GLsizei GLsizei GLchar * source
void *(* FT_Realloc_Func)(FT_Memory memory, long cur_size, long new_size, void *block)
FT_BEGIN_HEADER typedef unsigned char FT_Bool
void(* FT_Free_Func)(FT_Memory memory, void *block)
void *(* FT_Alloc_Func)(FT_Memory memory, long size)
typedefFT_BEGIN_HEADER struct FT_MemoryRec_ * FT_Memory
if(!abbox) return FT_THROW(Invalid_Argument)
GLuint GLuint GLsizei count
#define FT_MEM_SET(dest, byte, count)
GLenum GLsizei GLenum GLenum const GLvoid * table