/modules/freetype2/src/base/ftdbgmem.c

http://github.com/zpao/v8monkey · C · 997 lines · 675 code · 251 blank · 71 comment · 97 complexity · 8076195740fa65131ab5dfab6776d1ac MD5 · raw file

  1. /***************************************************************************/
  2. /* */
  3. /* ftdbgmem.c */
  4. /* */
  5. /* Memory debugger (body). */
  6. /* */
  7. /* Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2009 by */
  8. /* David Turner, Robert Wilhelm, and Werner Lemberg. */
  9. /* */
  10. /* This file is part of the FreeType project, and may only be used, */
  11. /* modified, and distributed under the terms of the FreeType project */
  12. /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
  13. /* this file you indicate that you have read the license and */
  14. /* understand and accept it fully. */
  15. /* */
  16. /***************************************************************************/
  17. #include <ft2build.h>
  18. #include FT_CONFIG_CONFIG_H
  19. #include FT_INTERNAL_DEBUG_H
  20. #include FT_INTERNAL_MEMORY_H
  21. #include FT_SYSTEM_H
  22. #include FT_ERRORS_H
  23. #include FT_TYPES_H
  24. #ifdef FT_DEBUG_MEMORY
  25. #define KEEPALIVE /* `Keep alive' means that freed blocks aren't released
  26. * to the heap. This is useful to detect double-frees
  27. * or weird heap corruption, but it uses large amounts of
  28. * memory, however.
  29. */
  30. #include FT_CONFIG_STANDARD_LIBRARY_H
  31. FT_BASE_DEF( const char* ) _ft_debug_file = 0;
  32. FT_BASE_DEF( long ) _ft_debug_lineno = 0;
  33. extern void
  34. FT_DumpMemory( FT_Memory memory );
  35. typedef struct FT_MemSourceRec_* FT_MemSource;
  36. typedef struct FT_MemNodeRec_* FT_MemNode;
  37. typedef struct FT_MemTableRec_* FT_MemTable;
  38. #define FT_MEM_VAL( addr ) ((FT_ULong)(FT_Pointer)( addr ))
  39. /*
  40. * This structure holds statistics for a single allocation/release
  41. * site. This is useful to know where memory operations happen the
  42. * most.
  43. */
  44. typedef struct FT_MemSourceRec_
  45. {
  46. const char* file_name;
  47. long line_no;
  48. FT_Long cur_blocks; /* current number of allocated blocks */
  49. FT_Long max_blocks; /* max. number of allocated blocks */
  50. FT_Long all_blocks; /* total number of blocks allocated */
  51. FT_Long cur_size; /* current cumulative allocated size */
  52. FT_Long max_size; /* maximum cumulative allocated size */
  53. FT_Long all_size; /* total cumulative allocated size */
  54. FT_Long cur_max; /* current maximum allocated size */
  55. FT_UInt32 hash;
  56. FT_MemSource link;
  57. } FT_MemSourceRec;
  58. /*
  59. * We don't need a resizable array for the memory sources, because
  60. * their number is pretty limited within FreeType.
  61. */
  62. #define FT_MEM_SOURCE_BUCKETS 128
  63. /*
  64. * This structure holds information related to a single allocated
  65. * memory block. If KEEPALIVE is defined, blocks that are freed by
  66. * FreeType are never released to the system. Instead, their `size'
  67. * field is set to -size. This is mainly useful to detect double frees,
  68. * at the price of large memory footprint during execution.
  69. */
  70. typedef struct FT_MemNodeRec_
  71. {
  72. FT_Byte* address;
  73. FT_Long size; /* < 0 if the block was freed */
  74. FT_MemSource source;
  75. #ifdef KEEPALIVE
  76. const char* free_file_name;
  77. FT_Long free_line_no;
  78. #endif
  79. FT_MemNode link;
  80. } FT_MemNodeRec;
  81. /*
  82. * The global structure, containing compound statistics and all hash
  83. * tables.
  84. */
  85. typedef struct FT_MemTableRec_
  86. {
  87. FT_ULong size;
  88. FT_ULong nodes;
  89. FT_MemNode* buckets;
  90. FT_ULong alloc_total;
  91. FT_ULong alloc_current;
  92. FT_ULong alloc_max;
  93. FT_ULong alloc_count;
  94. FT_Bool bound_total;
  95. FT_ULong alloc_total_max;
  96. FT_Bool bound_count;
  97. FT_ULong alloc_count_max;
  98. FT_MemSource sources[FT_MEM_SOURCE_BUCKETS];
  99. FT_Bool keep_alive;
  100. FT_Memory memory;
  101. FT_Pointer memory_user;
  102. FT_Alloc_Func alloc;
  103. FT_Free_Func free;
  104. FT_Realloc_Func realloc;
  105. } FT_MemTableRec;
  106. #define FT_MEM_SIZE_MIN 7
  107. #define FT_MEM_SIZE_MAX 13845163
  108. #define FT_FILENAME( x ) ((x) ? (x) : "unknown file")
  109. /*
  110. * Prime numbers are ugly to handle. It would be better to implement
  111. * L-Hashing, which is 10% faster and doesn't require divisions.
  112. */
  113. static const FT_UInt ft_mem_primes[] =
  114. {
  115. 7,
  116. 11,
  117. 19,
  118. 37,
  119. 73,
  120. 109,
  121. 163,
  122. 251,
  123. 367,
  124. 557,
  125. 823,
  126. 1237,
  127. 1861,
  128. 2777,
  129. 4177,
  130. 6247,
  131. 9371,
  132. 14057,
  133. 21089,
  134. 31627,
  135. 47431,
  136. 71143,
  137. 106721,
  138. 160073,
  139. 240101,
  140. 360163,
  141. 540217,
  142. 810343,
  143. 1215497,
  144. 1823231,
  145. 2734867,
  146. 4102283,
  147. 6153409,
  148. 9230113,
  149. 13845163,
  150. };
  151. static FT_ULong
  152. ft_mem_closest_prime( FT_ULong num )
  153. {
  154. FT_UInt i;
  155. for ( i = 0;
  156. i < sizeof ( ft_mem_primes ) / sizeof ( ft_mem_primes[0] ); i++ )
  157. if ( ft_mem_primes[i] > num )
  158. return ft_mem_primes[i];
  159. return FT_MEM_SIZE_MAX;
  160. }
  161. extern void
  162. ft_mem_debug_panic( const char* fmt,
  163. ... )
  164. {
  165. va_list ap;
  166. printf( "FreeType.Debug: " );
  167. va_start( ap, fmt );
  168. vprintf( fmt, ap );
  169. va_end( ap );
  170. printf( "\n" );
  171. exit( EXIT_FAILURE );
  172. }
  173. static FT_Pointer
  174. ft_mem_table_alloc( FT_MemTable table,
  175. FT_Long size )
  176. {
  177. FT_Memory memory = table->memory;
  178. FT_Pointer block;
  179. memory->user = table->memory_user;
  180. block = table->alloc( memory, size );
  181. memory->user = table;
  182. return block;
  183. }
  184. static void
  185. ft_mem_table_free( FT_MemTable table,
  186. FT_Pointer block )
  187. {
  188. FT_Memory memory = table->memory;
  189. memory->user = table->memory_user;
  190. table->free( memory, block );
  191. memory->user = table;
  192. }
  193. static void
  194. ft_mem_table_resize( FT_MemTable table )
  195. {
  196. FT_ULong new_size;
  197. new_size = ft_mem_closest_prime( table->nodes );
  198. if ( new_size != table->size )
  199. {
  200. FT_MemNode* new_buckets;
  201. FT_ULong i;
  202. new_buckets = (FT_MemNode *)
  203. ft_mem_table_alloc( table,
  204. new_size * sizeof ( FT_MemNode ) );
  205. if ( new_buckets == NULL )
  206. return;
  207. FT_ARRAY_ZERO( new_buckets, new_size );
  208. for ( i = 0; i < table->size; i++ )
  209. {
  210. FT_MemNode node, next, *pnode;
  211. FT_ULong hash;
  212. node = table->buckets[i];
  213. while ( node )
  214. {
  215. next = node->link;
  216. hash = FT_MEM_VAL( node->address ) % new_size;
  217. pnode = new_buckets + hash;
  218. node->link = pnode[0];
  219. pnode[0] = node;
  220. node = next;
  221. }
  222. }
  223. if ( table->buckets )
  224. ft_mem_table_free( table, table->buckets );
  225. table->buckets = new_buckets;
  226. table->size = new_size;
  227. }
  228. }
  229. static FT_MemTable
  230. ft_mem_table_new( FT_Memory memory )
  231. {
  232. FT_MemTable table;
  233. table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) );
  234. if ( table == NULL )
  235. goto Exit;
  236. FT_ZERO( table );
  237. table->size = FT_MEM_SIZE_MIN;
  238. table->nodes = 0;
  239. table->memory = memory;
  240. table->memory_user = memory->user;
  241. table->alloc = memory->alloc;
  242. table->realloc = memory->realloc;
  243. table->free = memory->free;
  244. table->buckets = (FT_MemNode *)
  245. memory->alloc( memory,
  246. table->size * sizeof ( FT_MemNode ) );
  247. if ( table->buckets )
  248. FT_ARRAY_ZERO( table->buckets, table->size );
  249. else
  250. {
  251. memory->free( memory, table );
  252. table = NULL;
  253. }
  254. Exit:
  255. return table;
  256. }
  257. static void
  258. ft_mem_table_destroy( FT_MemTable table )
  259. {
  260. FT_ULong i;
  261. FT_DumpMemory( table->memory );
  262. if ( table )
  263. {
  264. FT_Long leak_count = 0;
  265. FT_ULong leaks = 0;
  266. /* remove all blocks from the table, revealing leaked ones */
  267. for ( i = 0; i < table->size; i++ )
  268. {
  269. FT_MemNode *pnode = table->buckets + i, next, node = *pnode;
  270. while ( node )
  271. {
  272. next = node->link;
  273. node->link = 0;
  274. if ( node->size > 0 )
  275. {
  276. printf(
  277. "leaked memory block at address %p, size %8ld in (%s:%ld)\n",
  278. node->address, node->size,
  279. FT_FILENAME( node->source->file_name ),
  280. node->source->line_no );
  281. leak_count++;
  282. leaks += node->size;
  283. ft_mem_table_free( table, node->address );
  284. }
  285. node->address = NULL;
  286. node->size = 0;
  287. ft_mem_table_free( table, node );
  288. node = next;
  289. }
  290. table->buckets[i] = 0;
  291. }
  292. ft_mem_table_free( table, table->buckets );
  293. table->buckets = NULL;
  294. table->size = 0;
  295. table->nodes = 0;
  296. /* remove all sources */
  297. for ( i = 0; i < FT_MEM_SOURCE_BUCKETS; i++ )
  298. {
  299. FT_MemSource source, next;
  300. for ( source = table->sources[i]; source != NULL; source = next )
  301. {
  302. next = source->link;
  303. ft_mem_table_free( table, source );
  304. }
  305. table->sources[i] = NULL;
  306. }
  307. printf(
  308. "FreeType: total memory allocations = %ld\n", table->alloc_total );
  309. printf(
  310. "FreeType: maximum memory footprint = %ld\n", table->alloc_max );
  311. ft_mem_table_free( table, table );
  312. if ( leak_count > 0 )
  313. ft_mem_debug_panic(
  314. "FreeType: %ld bytes of memory leaked in %ld blocks\n",
  315. leaks, leak_count );
  316. printf( "FreeType: no memory leaks detected\n" );
  317. }
  318. }
  319. static FT_MemNode*
  320. ft_mem_table_get_nodep( FT_MemTable table,
  321. FT_Byte* address )
  322. {
  323. FT_ULong hash;
  324. FT_MemNode *pnode, node;
  325. hash = FT_MEM_VAL( address );
  326. pnode = table->buckets + ( hash % table->size );
  327. for (;;)
  328. {
  329. node = pnode[0];
  330. if ( !node )
  331. break;
  332. if ( node->address == address )
  333. break;
  334. pnode = &node->link;
  335. }
  336. return pnode;
  337. }
  338. static FT_MemSource
  339. ft_mem_table_get_source( FT_MemTable table )
  340. {
  341. FT_UInt32 hash;
  342. FT_MemSource node, *pnode;
  343. /* cast to FT_PtrDist first since void* can be larger */
  344. /* than FT_UInt32 and GCC 4.1.1 emits a warning */
  345. hash = (FT_UInt32)(FT_PtrDist)(void*)_ft_debug_file +
  346. (FT_UInt32)( 5 * _ft_debug_lineno );
  347. pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS];
  348. for ( ;; )
  349. {
  350. node = *pnode;
  351. if ( node == NULL )
  352. break;
  353. if ( node->file_name == _ft_debug_file &&
  354. node->line_no == _ft_debug_lineno )
  355. goto Exit;
  356. pnode = &node->link;
  357. }
  358. node = (FT_MemSource)ft_mem_table_alloc( table, sizeof ( *node ) );
  359. if ( node == NULL )
  360. ft_mem_debug_panic(
  361. "not enough memory to perform memory debugging\n" );
  362. node->file_name = _ft_debug_file;
  363. node->line_no = _ft_debug_lineno;
  364. node->cur_blocks = 0;
  365. node->max_blocks = 0;
  366. node->all_blocks = 0;
  367. node->cur_size = 0;
  368. node->max_size = 0;
  369. node->all_size = 0;
  370. node->cur_max = 0;
  371. node->link = NULL;
  372. node->hash = hash;
  373. *pnode = node;
  374. Exit:
  375. return node;
  376. }
  377. static void
  378. ft_mem_table_set( FT_MemTable table,
  379. FT_Byte* address,
  380. FT_ULong size,
  381. FT_Long delta )
  382. {
  383. FT_MemNode *pnode, node;
  384. if ( table )
  385. {
  386. FT_MemSource source;
  387. pnode = ft_mem_table_get_nodep( table, address );
  388. node = *pnode;
  389. if ( node )
  390. {
  391. if ( node->size < 0 )
  392. {
  393. /* This block was already freed. Our memory is now completely */
  394. /* corrupted! */
  395. /* This can only happen in keep-alive mode. */
  396. ft_mem_debug_panic(
  397. "memory heap corrupted (allocating freed block)" );
  398. }
  399. else
  400. {
  401. /* This block was already allocated. This means that our memory */
  402. /* is also corrupted! */
  403. ft_mem_debug_panic(
  404. "memory heap corrupted (re-allocating allocated block at"
  405. " %p, of size %ld)\n"
  406. "org=%s:%d new=%s:%d\n",
  407. node->address, node->size,
  408. FT_FILENAME( node->source->file_name ), node->source->line_no,
  409. FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
  410. }
  411. }
  412. /* we need to create a new node in this table */
  413. node = (FT_MemNode)ft_mem_table_alloc( table, sizeof ( *node ) );
  414. if ( node == NULL )
  415. ft_mem_debug_panic( "not enough memory to run memory tests" );
  416. node->address = address;
  417. node->size = size;
  418. node->source = source = ft_mem_table_get_source( table );
  419. if ( delta == 0 )
  420. {
  421. /* this is an allocation */
  422. source->all_blocks++;
  423. source->cur_blocks++;
  424. if ( source->cur_blocks > source->max_blocks )
  425. source->max_blocks = source->cur_blocks;
  426. }
  427. if ( size > (FT_ULong)source->cur_max )
  428. source->cur_max = size;
  429. if ( delta != 0 )
  430. {
  431. /* we are growing or shrinking a reallocated block */
  432. source->cur_size += delta;
  433. table->alloc_current += delta;
  434. }
  435. else
  436. {
  437. /* we are allocating a new block */
  438. source->cur_size += size;
  439. table->alloc_current += size;
  440. }
  441. source->all_size += size;
  442. if ( source->cur_size > source->max_size )
  443. source->max_size = source->cur_size;
  444. node->free_file_name = NULL;
  445. node->free_line_no = 0;
  446. node->link = pnode[0];
  447. pnode[0] = node;
  448. table->nodes++;
  449. table->alloc_total += size;
  450. if ( table->alloc_current > table->alloc_max )
  451. table->alloc_max = table->alloc_current;
  452. if ( table->nodes * 3 < table->size ||
  453. table->size * 3 < table->nodes )
  454. ft_mem_table_resize( table );
  455. }
  456. }
  457. static void
  458. ft_mem_table_remove( FT_MemTable table,
  459. FT_Byte* address,
  460. FT_Long delta )
  461. {
  462. if ( table )
  463. {
  464. FT_MemNode *pnode, node;
  465. pnode = ft_mem_table_get_nodep( table, address );
  466. node = *pnode;
  467. if ( node )
  468. {
  469. FT_MemSource source;
  470. if ( node->size < 0 )
  471. ft_mem_debug_panic(
  472. "freeing memory block at %p more than once at (%s:%ld)\n"
  473. "block allocated at (%s:%ld) and released at (%s:%ld)",
  474. address,
  475. FT_FILENAME( _ft_debug_file ), _ft_debug_lineno,
  476. FT_FILENAME( node->source->file_name ), node->source->line_no,
  477. FT_FILENAME( node->free_file_name ), node->free_line_no );
  478. /* scramble the node's content for additional safety */
  479. FT_MEM_SET( address, 0xF3, node->size );
  480. if ( delta == 0 )
  481. {
  482. source = node->source;
  483. source->cur_blocks--;
  484. source->cur_size -= node->size;
  485. table->alloc_current -= node->size;
  486. }
  487. if ( table->keep_alive )
  488. {
  489. /* we simply invert the node's size to indicate that the node */
  490. /* was freed. */
  491. node->size = -node->size;
  492. node->free_file_name = _ft_debug_file;
  493. node->free_line_no = _ft_debug_lineno;
  494. }
  495. else
  496. {
  497. table->nodes--;
  498. *pnode = node->link;
  499. node->size = 0;
  500. node->source = NULL;
  501. ft_mem_table_free( table, node );
  502. if ( table->nodes * 3 < table->size ||
  503. table->size * 3 < table->nodes )
  504. ft_mem_table_resize( table );
  505. }
  506. }
  507. else
  508. ft_mem_debug_panic(
  509. "trying to free unknown block at %p in (%s:%ld)\n",
  510. address,
  511. FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
  512. }
  513. }
  514. extern FT_Pointer
  515. ft_mem_debug_alloc( FT_Memory memory,
  516. FT_Long size )
  517. {
  518. FT_MemTable table = (FT_MemTable)memory->user;
  519. FT_Byte* block;
  520. if ( size <= 0 )
  521. ft_mem_debug_panic( "negative block size allocation (%ld)", size );
  522. /* return NULL if the maximum number of allocations was reached */
  523. if ( table->bound_count &&
  524. table->alloc_count >= table->alloc_count_max )
  525. return NULL;
  526. /* return NULL if this allocation would overflow the maximum heap size */
  527. if ( table->bound_total &&
  528. table->alloc_total_max - table->alloc_current > (FT_ULong)size )
  529. return NULL;
  530. block = (FT_Byte *)ft_mem_table_alloc( table, size );
  531. if ( block )
  532. {
  533. ft_mem_table_set( table, block, (FT_ULong)size, 0 );
  534. table->alloc_count++;
  535. }
  536. _ft_debug_file = "<unknown>";
  537. _ft_debug_lineno = 0;
  538. return (FT_Pointer)block;
  539. }
  540. extern void
  541. ft_mem_debug_free( FT_Memory memory,
  542. FT_Pointer block )
  543. {
  544. FT_MemTable table = (FT_MemTable)memory->user;
  545. if ( block == NULL )
  546. ft_mem_debug_panic( "trying to free NULL in (%s:%ld)",
  547. FT_FILENAME( _ft_debug_file ),
  548. _ft_debug_lineno );
  549. ft_mem_table_remove( table, (FT_Byte*)block, 0 );
  550. if ( !table->keep_alive )
  551. ft_mem_table_free( table, block );
  552. table->alloc_count--;
  553. _ft_debug_file = "<unknown>";
  554. _ft_debug_lineno = 0;
  555. }
  556. extern FT_Pointer
  557. ft_mem_debug_realloc( FT_Memory memory,
  558. FT_Long cur_size,
  559. FT_Long new_size,
  560. FT_Pointer block )
  561. {
  562. FT_MemTable table = (FT_MemTable)memory->user;
  563. FT_MemNode node, *pnode;
  564. FT_Pointer new_block;
  565. FT_Long delta;
  566. const char* file_name = FT_FILENAME( _ft_debug_file );
  567. FT_Long line_no = _ft_debug_lineno;
  568. /* unlikely, but possible */
  569. if ( new_size == cur_size )
  570. return block;
  571. /* the following is valid according to ANSI C */
  572. #if 0
  573. if ( block == NULL || cur_size == 0 )
  574. ft_mem_debug_panic( "trying to reallocate NULL in (%s:%ld)",
  575. file_name, line_no );
  576. #endif
  577. /* while the following is allowed in ANSI C also, we abort since */
  578. /* such case should be handled by FreeType. */
  579. if ( new_size <= 0 )
  580. ft_mem_debug_panic(
  581. "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)",
  582. block, cur_size, file_name, line_no );
  583. /* check `cur_size' value */
  584. pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block );
  585. node = *pnode;
  586. if ( !node )
  587. ft_mem_debug_panic(
  588. "trying to reallocate unknown block at %p in (%s:%ld)",
  589. block, file_name, line_no );
  590. if ( node->size <= 0 )
  591. ft_mem_debug_panic(
  592. "trying to reallocate freed block at %p in (%s:%ld)",
  593. block, file_name, line_no );
  594. if ( node->size != cur_size )
  595. ft_mem_debug_panic( "invalid ft_realloc request for %p. cur_size is "
  596. "%ld instead of %ld in (%s:%ld)",
  597. block, cur_size, node->size, file_name, line_no );
  598. /* return NULL if the maximum number of allocations was reached */
  599. if ( table->bound_count &&
  600. table->alloc_count >= table->alloc_count_max )
  601. return NULL;
  602. delta = (FT_Long)( new_size - cur_size );
  603. /* return NULL if this allocation would overflow the maximum heap size */
  604. if ( delta > 0 &&
  605. table->bound_total &&
  606. table->alloc_current + (FT_ULong)delta > table->alloc_total_max )
  607. return NULL;
  608. new_block = (FT_Byte *)ft_mem_table_alloc( table, new_size );
  609. if ( new_block == NULL )
  610. return NULL;
  611. ft_mem_table_set( table, (FT_Byte*)new_block, new_size, delta );
  612. ft_memcpy( new_block, block, cur_size < new_size ? cur_size : new_size );
  613. ft_mem_table_remove( table, (FT_Byte*)block, delta );
  614. _ft_debug_file = "<unknown>";
  615. _ft_debug_lineno = 0;
  616. if ( !table->keep_alive )
  617. ft_mem_table_free( table, block );
  618. return new_block;
  619. }
  620. extern FT_Int
  621. ft_mem_debug_init( FT_Memory memory )
  622. {
  623. FT_MemTable table;
  624. FT_Int result = 0;
  625. if ( getenv( "FT2_DEBUG_MEMORY" ) )
  626. {
  627. table = ft_mem_table_new( memory );
  628. if ( table )
  629. {
  630. const char* p;
  631. memory->user = table;
  632. memory->alloc = ft_mem_debug_alloc;
  633. memory->realloc = ft_mem_debug_realloc;
  634. memory->free = ft_mem_debug_free;
  635. p = getenv( "FT2_ALLOC_TOTAL_MAX" );
  636. if ( p != NULL )
  637. {
  638. FT_Long total_max = ft_atol( p );
  639. if ( total_max > 0 )
  640. {
  641. table->bound_total = 1;
  642. table->alloc_total_max = (FT_ULong)total_max;
  643. }
  644. }
  645. p = getenv( "FT2_ALLOC_COUNT_MAX" );
  646. if ( p != NULL )
  647. {
  648. FT_Long total_count = ft_atol( p );
  649. if ( total_count > 0 )
  650. {
  651. table->bound_count = 1;
  652. table->alloc_count_max = (FT_ULong)total_count;
  653. }
  654. }
  655. p = getenv( "FT2_KEEP_ALIVE" );
  656. if ( p != NULL )
  657. {
  658. FT_Long keep_alive = ft_atol( p );
  659. if ( keep_alive > 0 )
  660. table->keep_alive = 1;
  661. }
  662. result = 1;
  663. }
  664. }
  665. return result;
  666. }
  667. extern void
  668. ft_mem_debug_done( FT_Memory memory )
  669. {
  670. FT_MemTable table = (FT_MemTable)memory->user;
  671. if ( table )
  672. {
  673. memory->free = table->free;
  674. memory->realloc = table->realloc;
  675. memory->alloc = table->alloc;
  676. ft_mem_table_destroy( table );
  677. memory->user = NULL;
  678. }
  679. }
  680. static int
  681. ft_mem_source_compare( const void* p1,
  682. const void* p2 )
  683. {
  684. FT_MemSource s1 = *(FT_MemSource*)p1;
  685. FT_MemSource s2 = *(FT_MemSource*)p2;
  686. if ( s2->max_size > s1->max_size )
  687. return 1;
  688. else if ( s2->max_size < s1->max_size )
  689. return -1;
  690. else
  691. return 0;
  692. }
  693. extern void
  694. FT_DumpMemory( FT_Memory memory )
  695. {
  696. FT_MemTable table = (FT_MemTable)memory->user;
  697. if ( table )
  698. {
  699. FT_MemSource* bucket = table->sources;
  700. FT_MemSource* limit = bucket + FT_MEM_SOURCE_BUCKETS;
  701. FT_MemSource* sources;
  702. FT_UInt nn, count;
  703. const char* fmt;
  704. count = 0;
  705. for ( ; bucket < limit; bucket++ )
  706. {
  707. FT_MemSource source = *bucket;
  708. for ( ; source; source = source->link )
  709. count++;
  710. }
  711. sources = (FT_MemSource*)ft_mem_table_alloc(
  712. table, sizeof ( *sources ) * count );
  713. count = 0;
  714. for ( bucket = table->sources; bucket < limit; bucket++ )
  715. {
  716. FT_MemSource source = *bucket;
  717. for ( ; source; source = source->link )
  718. sources[count++] = source;
  719. }
  720. ft_qsort( sources, count, sizeof ( *sources ), ft_mem_source_compare );
  721. printf( "FreeType Memory Dump: "
  722. "current=%ld max=%ld total=%ld count=%ld\n",
  723. table->alloc_current, table->alloc_max,
  724. table->alloc_total, table->alloc_count );
  725. printf( " block block sizes sizes sizes source\n" );
  726. printf( " count high sum highsum max location\n" );
  727. printf( "-------------------------------------------------\n" );
  728. fmt = "%6ld %6ld %8ld %8ld %8ld %s:%d\n";
  729. for ( nn = 0; nn < count; nn++ )
  730. {
  731. FT_MemSource source = sources[nn];
  732. printf( fmt,
  733. source->cur_blocks, source->max_blocks,
  734. source->cur_size, source->max_size, source->cur_max,
  735. FT_FILENAME( source->file_name ),
  736. source->line_no );
  737. }
  738. printf( "------------------------------------------------\n" );
  739. ft_mem_table_free( table, sources );
  740. }
  741. }
  742. #else /* !FT_DEBUG_MEMORY */
  743. /* ANSI C doesn't like empty source files */
  744. typedef int _debug_mem_dummy;
  745. #endif /* !FT_DEBUG_MEMORY */
  746. /* END */