2 Copyright (C) 2001-2009, Parrot Foundation.
7 src/gc/alloc_resources.c - Allocate and deallocate buffer resources such as
12 Functions to manage non-PObj memory, including strings and buffers.
14 =head2 Parrot Memory Management Code
22 #include "parrot/parrot.h"
23 #include "gc_private.h"
26 #define RECLAMATION_FACTOR 0.20
27 #define WE_WANT_EVER_GROWING_ALLOCATIONS 0
29 /* show allocated blocks on stderr */
30 #define RESOURCE_DEBUG 0
31 #define RESOURCE_DEBUG_SIZE 1000000
33 #define POOL_SIZE 65536 * 2
35 typedef void (*compact_f
) (Interp
*, Variable_Size_Pool
*);
37 /* HEADERIZER HFILE: src/gc/gc_private.h */
39 /* HEADERIZER BEGIN: static */
40 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
42 static void alloc_new_block(PARROT_INTERP
,
44 ARGMOD(Variable_Size_Pool
*pool
),
45 ARGIN(const char *why
))
46 __attribute__nonnull__(1)
47 __attribute__nonnull__(3)
48 __attribute__nonnull__(4)
51 PARROT_CANNOT_RETURN_NULL
52 PARROT_WARN_UNUSED_RESULT
53 static const char* buffer_location(PARROT_INTERP
, ARGIN(const PObj
*b
))
54 __attribute__nonnull__(1)
55 __attribute__nonnull__(2);
57 static void check_fixed_size_obj_pool(ARGMOD(Fixed_Size_Pool
* pool
))
58 __attribute__nonnull__(1)
59 FUNC_MODIFIES(* pool
);
61 static void check_memory_system(PARROT_INTERP
)
62 __attribute__nonnull__(1);
64 static void check_var_size_obj_pool(ARGMOD(Variable_Size_Pool
*pool
))
65 __attribute__nonnull__(1)
68 static void debug_print_buf(PARROT_INTERP
, ARGIN(const Buffer
*b
))
69 __attribute__nonnull__(1)
70 __attribute__nonnull__(2);
73 PARROT_CANNOT_RETURN_NULL
74 static Variable_Size_Pool
* new_memory_pool(
76 NULLOK(compact_f compact
));
78 #define ASSERT_ARGS_alloc_new_block __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
79 PARROT_ASSERT_ARG(interp) \
80 , PARROT_ASSERT_ARG(pool) \
81 , PARROT_ASSERT_ARG(why))
82 #define ASSERT_ARGS_buffer_location __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
83 PARROT_ASSERT_ARG(interp) \
84 , PARROT_ASSERT_ARG(b))
85 #define ASSERT_ARGS_check_fixed_size_obj_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
86 PARROT_ASSERT_ARG(pool))
87 #define ASSERT_ARGS_check_memory_system __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
88 PARROT_ASSERT_ARG(interp))
89 #define ASSERT_ARGS_check_var_size_obj_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
90 PARROT_ASSERT_ARG(pool))
91 #define ASSERT_ARGS_debug_print_buf __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
92 PARROT_ASSERT_ARG(interp) \
93 , PARROT_ASSERT_ARG(b))
94 #define ASSERT_ARGS_new_memory_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
95 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
96 /* HEADERIZER END: static */
101 =item C<static void alloc_new_block(PARROT_INTERP, size_t size,
102 Variable_Size_Pool *pool, const char *why)>
104 Allocate a new memory block. We allocate either the requested size or the
105 default size, whichever is larger. Add the new block to the given memory
106 pool. The given C<char *why> text is used for debugging.
113 alloc_new_block(PARROT_INTERP
, size_t size
, ARGMOD(Variable_Size_Pool
*pool
),
114 ARGIN(const char *why
))
116 ASSERT_ARGS(alloc_new_block
)
117 Memory_Block
*new_block
;
119 const size_t alloc_size
= (size
> pool
->minimum_block_size
)
120 ? size
: pool
->minimum_block_size
;
123 fprintf(stderr
, "new_block (%s) size %u -> %u\n",
124 why
, size
, alloc_size
);
129 /* Allocate a new block. Header info's on the front */
130 new_block
= (Memory_Block
*)mem_internal_allocate_zeroed(
131 sizeof (Memory_Block
) + alloc_size
);
134 fprintf(stderr
, "out of mem allocsize = %d\n", (int)alloc_size
);
138 new_block
->free
= alloc_size
;
139 new_block
->size
= alloc_size
;
141 new_block
->next
= NULL
;
142 new_block
->start
= (char *)new_block
+ sizeof (Memory_Block
);
143 new_block
->top
= new_block
->start
;
145 /* Note that we've allocated it */
146 interp
->mem_pools
->memory_allocated
+= alloc_size
;
148 /* If this is for a public pool, add it to the list */
149 new_block
->prev
= pool
->top_block
;
151 /* If we're not first, then tack us on the list */
153 pool
->top_block
->next
= new_block
;
155 pool
->top_block
= new_block
;
156 pool
->total_allocated
+= alloc_size
;
161 =item C<void * mem_allocate(PARROT_INTERP, size_t size, Variable_Size_Pool
164 Allocates memory for headers.
166 Alignment problems history:
168 See L<http://archive.develooper.com/perl6-internals%40perl.org/msg12310.html>
171 - return aligned pointer *if needed*
172 - return strings et al at unaligned i.e. void* boundaries
173 - remember alignment in a buffer header bit
174 use this in compaction code
175 - reduce alignment to a reasonable value i.e. MALLOC_ALIGNMENT
176 aka 2*sizeof (size_t) or just 8 (TODO make a config hint)
178 Buffer memory layout:
181 | ref_count |f | # GC header
182 obj->bufstart -> +-----------------+
186 * if PObj_is_COWable is set, then we have
187 - a ref_count, {inc, dec}remented by 2 always
188 - the lo bit 'f' means 'is being forwarded" - what TAIL_flag was
190 * if PObj_align_FLAG is set, obj->bufstart is aligned like discussed above
191 * obj->buflen is the usable length excluding the optional GC part.
198 PARROT_CANNOT_RETURN_NULL
200 mem_allocate(PARROT_INTERP
, size_t size
, ARGMOD(Variable_Size_Pool
*pool
))
202 ASSERT_ARGS(mem_allocate
)
205 /* we always should have one block at least */
206 PARROT_ASSERT(pool
->top_block
);
208 /* If not enough room, try to find some */
209 if (pool
->top_block
->free
< size
) {
211 * force a GC mark run to get live flags set
212 * for incremental M&S collection is run from there
213 * but only if there may be something worth collecting!
214 * TODO pass required allocation size to the GC system,
215 * so that collection can be skipped if needed
217 if (!interp
->mem_pools
->gc_mark_block_level
218 && interp
->mem_pools
->mem_allocs_since_last_collect
) {
219 Parrot_gc_mark_and_sweep(interp
, GC_trace_stack_FLAG
);
221 if (interp
->gc_sys
->sys_type
!= INF
) {
222 /* Compact the pool if allowed and worthwhile */
224 /* don't bother reclaiming if it's only a small amount */
225 if ((pool
->possibly_reclaimable
* pool
->reclaim_factor
+
226 pool
->guaranteed_reclaimable
) > size
) {
227 (*pool
->compact
) (interp
, pool
);
232 if (pool
->top_block
->free
< size
) {
233 if (pool
->minimum_block_size
< 65536 * 16)
234 pool
->minimum_block_size
*= 2;
238 * Mark the block as big block (it has just one item)
239 * And don't set big blocks as the top_block.
241 alloc_new_block(interp
, size
, pool
, "compact failed");
243 interp
->mem_pools
->mem_allocs_since_last_collect
++;
245 if (pool
->top_block
->free
< size
) {
246 fprintf(stderr
, "out of mem\n");
252 /* TODO inline the fast path */
253 return_val
= pool
->top_block
->top
;
254 pool
->top_block
->top
+= size
;
255 pool
->top_block
->free
-= size
;
262 =item C<static const char* buffer_location(PARROT_INTERP, const PObj *b)>
264 Recturns a constant string representing the location of the given
265 PObj C<b> in one of the PMC registers. If the PMC is not located
266 in one of the PMC registers of the current context, returns the
274 PARROT_CANNOT_RETURN_NULL
275 PARROT_WARN_UNUSED_RESULT
277 buffer_location(PARROT_INTERP
, ARGIN(const PObj
*b
))
279 ASSERT_ARGS(buffer_location
)
283 Parrot_Context
* const ctx
= CONTEXT(interp
);
285 for (i
= 0; i
< ctx
->n_regs_used
[REGNO_STR
]; ++i
) {
286 PObj
* const obj
= (PObj
*) CTX_REG_STR(interp
, ctx
, i
);
288 sprintf(reg
, "S%d", i
);
298 =item C<static void debug_print_buf(PARROT_INTERP, const Buffer *b)>
300 Prints a debug statement with information about the given PObj C<b>.
306 debug_print_buf(PARROT_INTERP
, ARGIN(const Buffer
*b
))
308 ASSERT_ARGS(debug_print_buf
)
309 fprintf(stderr
, "found %p, len %d, flags 0x%08x at %s\n",
310 b
, (int)Buffer_buflen(b
), (uint
)PObj_get_FLAGS(b
),
311 buffer_location(interp
, b
));
319 =head2 Compaction Code
323 =item C<void compact_pool(PARROT_INTERP, Variable_Size_Pool *pool)>
325 Compact the string buffer pool. Does not perform a GC scan, or mark items
326 as being alive in any way.
333 compact_pool(PARROT_INTERP
, ARGMOD(Variable_Size_Pool
*pool
))
335 ASSERT_ARGS(compact_pool
)
339 Memory_Block
*new_block
; /* A pointer to our working block */
340 char *cur_spot
; /* Where we're currently copying to */
342 Fixed_Size_Arena
*cur_buffer_arena
;
343 Memory_Pools
* const mem_pools
= interp
->mem_pools
;
345 /* Bail if we're blocked */
346 if (mem_pools
->gc_sweep_block_level
)
349 ++mem_pools
->gc_sweep_block_level
;
351 /* We're collecting */
352 mem_pools
->mem_allocs_since_last_collect
= 0;
353 mem_pools
->header_allocs_since_last_collect
= 0;
354 mem_pools
->gc_collect_runs
++;
356 /* total - reclaimable == currently used. Add a minimum block to the
357 * current amount, so we can avoid having to allocate it in the future. */
359 Memory_Block
*cur_block
= pool
->top_block
;
367 * Currently all available blocks are compacted into on new
368 * block with total_size. This is more than suboptimal, if
369 * the block has just one live item from a big allocation.
371 * But currently it's unknown if the buffer memory is alive
372 * as the live bits are in Buffer headers. We have to run the
373 * compaction loop below to check liveness. OTOH if this
374 * compaction is running through all the buffer headers, there
375 * is no relation to the block.
378 * Moving the life bit into the buffer thus also solves this
381 total_size
+= cur_block
->size
- cur_block
->free
;
382 cur_block
= cur_block
->prev
;
386 * XXX for some reason the guarantee isn't correct
390 /* total_size -= pool->guaranteed_reclaimable; */
392 /* this makes for ever increasing allocations but fewer collect runs */
393 #if WE_WANT_EVER_GROWING_ALLOCATIONS
394 total_size
+= pool
->minimum_block_size
;
397 /* Snag a block big enough for everything */
398 alloc_new_block(interp
, total_size
, pool
, "inside compact");
400 new_block
= pool
->top_block
;
402 /* Start at the beginning */
403 cur_spot
= new_block
->start
;
405 /* Run through all the Buffer header pools and copy */
406 for (j
= (INTVAL
)mem_pools
->num_sized
- 1; j
>= 0; --j
) {
407 Fixed_Size_Pool
* const header_pool
= mem_pools
->sized_header_pools
[j
];
413 object_size
= header_pool
->object_size
;
415 for (cur_buffer_arena
= header_pool
->last_Arena
;
417 cur_buffer_arena
= cur_buffer_arena
->prev
) {
418 Buffer
*b
= (Buffer
*) cur_buffer_arena
->start_objects
;
420 const size_t objects_end
= cur_buffer_arena
->used
;
422 for (i
= objects_end
; i
; --i
) {
423 INTVAL
*ref_count
= NULL
;
425 /* ! (on_free_list | constant | external | sysmem) */
426 if (Buffer_buflen(b
) && PObj_is_movable_TESTALL(b
)) {
427 ptrdiff_t offset
= 0;
429 if (Buffer_buflen(b
) >= RESOURCE_DEBUG_SIZE
)
430 debug_print_buf(interp
, b
);
433 /* we can't perform the math all the time, because
434 * strstart might be in unallocated memory */
435 if (PObj_is_COWable_TEST(b
)) {
436 ref_count
= Buffer_bufrefcountptr(b
);
438 if (PObj_is_string_TEST(b
)) {
439 offset
= (ptrdiff_t)((STRING
*)b
)->strstart
-
440 (ptrdiff_t)Buffer_bufstart(b
);
444 /* buffer has already been moved; just change the header */
445 if (PObj_COW_TEST(b
) &&
446 (ref_count
&& *ref_count
& Buffer_moved_FLAG
)) {
447 /* Find out who else references our data */
448 Buffer
* const hdr
= *((Buffer
**)Buffer_bufstart(b
));
451 PARROT_ASSERT(PObj_is_COWable_TEST(b
));
453 /* Make sure they know that we own it too */
456 /* TODO incr ref_count, after fixing string too
457 * Now make sure we point to where the other guy does */
458 Buffer_bufstart(b
) = Buffer_bufstart(hdr
);
460 /* And if we're a string, update strstart */
461 /* Somewhat of a hack, but if we get per-pool
462 * collections, it should help ease the pain */
463 if (PObj_is_string_TEST(b
)) {
464 ((STRING
*)b
)->strstart
= (char *)Buffer_bufstart(b
) +
469 cur_spot
= aligned_mem(b
, cur_spot
);
471 if (PObj_is_COWable_TEST(b
)) {
472 INTVAL
* const new_ref_count
= ((INTVAL
*) cur_spot
) - 1;
476 /* Copy our memory to the new pool */
477 memcpy(cur_spot
, Buffer_bufstart(b
), Buffer_buflen(b
));
480 if (PObj_COW_TEST(b
)) {
481 PARROT_ASSERT(PObj_is_COWable_TEST(b
));
483 /* Let the old buffer know how to find us */
484 *((Buffer
**)Buffer_bufstart(b
)) = b
;
486 /* No guarantees that our data is still COW, so
487 * assume not, and let the above code fix-up */
490 /* Finally, let the tail know that we've moved, so
491 * that any other references can know to look for
492 * us and not re-copy */
494 *ref_count
|= Buffer_moved_FLAG
;
497 Buffer_bufstart(b
) = cur_spot
;
499 if (PObj_is_string_TEST(b
)) {
500 ((STRING
*)b
)->strstart
= (char *)Buffer_bufstart(b
) +
504 cur_spot
+= Buffer_buflen(b
);
507 b
= (Buffer
*)((char *)b
+ object_size
);
512 /* Okay, we're done with the copy. Set the bits in the pool struct */
513 /* First, where we allocate next */
514 new_block
->top
= cur_spot
;
516 PARROT_ASSERT(new_block
->size
>= (size_t)new_block
->top
-
517 (size_t)new_block
->start
);
519 /* How much is free. That's the total size minus the amount we used */
520 new_block
->free
= new_block
->size
- (new_block
->top
- new_block
->start
);
522 mem_pools
->memory_collected
+= (new_block
->top
- new_block
->start
);
524 /* Now we're done. We're already on the pool's free list, so let us be the
525 * only one on the free list and free the rest */
527 Memory_Block
*cur_block
= new_block
->prev
;
529 PARROT_ASSERT(new_block
== pool
->top_block
);
532 Memory_Block
* const next_block
= cur_block
->prev
;
534 /* Note that we don't have it any more */
535 mem_pools
->memory_allocated
-= cur_block
->size
;
537 /* We know the pool body and pool header are a single chunk, so
538 * this is enough to get rid of 'em both */
539 mem_internal_free(cur_block
);
540 cur_block
= next_block
;
543 /* Set our new pool as the only pool */
544 new_block
->prev
= NULL
;
545 pool
->total_allocated
= total_size
;
548 pool
->guaranteed_reclaimable
= 0;
549 pool
->possibly_reclaimable
= 0;
551 --mem_pools
->gc_sweep_block_level
;
556 =item C<size_t aligned_size(const Buffer *buffer, size_t len)>
558 Determines the size of Buffer C<buffer> which has nominal length C<len>.
559 The actual size in RAM of the Buffer might be different because of
567 PARROT_WARN_UNUSED_RESULT
569 aligned_size(ARGIN(const Buffer
*buffer
), size_t len
)
571 ASSERT_ARGS(aligned_size
)
572 if (PObj_is_COWable_TEST(buffer
))
573 len
+= sizeof (void*);
574 if (PObj_aligned_TEST(buffer
))
575 len
= (len
+ BUFFER_ALIGN_1
) & BUFFER_ALIGN_MASK
;
577 len
= (len
+ WORD_ALIGN_1
) & WORD_ALIGN_MASK
;
583 =item C<char * aligned_mem(const Buffer *buffer, char *mem)>
585 Returns a pointer to the aligned allocated storage for Buffer C<buffer>,
586 which might not be the same as the pointer to C<buffeR> because of
593 PARROT_CANNOT_RETURN_NULL
594 PARROT_WARN_UNUSED_RESULT
596 aligned_mem(ARGIN(const Buffer
*buffer
), ARGIN(char *mem
))
598 ASSERT_ARGS(aligned_mem
)
599 if (PObj_is_COWable_TEST(buffer
))
600 mem
+= sizeof (void*);
601 if (PObj_aligned_TEST(buffer
))
602 mem
= (char*)(((unsigned long)(mem
+ BUFFER_ALIGN_1
)) &
605 mem
= (char*)(((unsigned long)(mem
+ WORD_ALIGN_1
)) & WORD_ALIGN_MASK
);
612 =item C<size_t aligned_string_size(size_t len)>
614 Determines the size of a string of length C<len> in RAM, accounting for
621 PARROT_CONST_FUNCTION
622 PARROT_WARN_UNUSED_RESULT
624 aligned_string_size(size_t len
)
626 ASSERT_ARGS(aligned_string_size
)
627 len
+= sizeof (void*);
628 len
= (len
+ WORD_ALIGN_1
) & WORD_ALIGN_MASK
;
636 =head2 Parrot Re/Allocate Code
640 =item C<static Variable_Size_Pool * new_memory_pool(size_t min_block, compact_f
643 Allocate a new C<Variable_Size_Pool> structures, and set some initial values.
644 return a pointer to the new pool.
651 PARROT_CANNOT_RETURN_NULL
652 static Variable_Size_Pool
*
653 new_memory_pool(size_t min_block
, NULLOK(compact_f compact
))
655 ASSERT_ARGS(new_memory_pool
)
656 Variable_Size_Pool
* const pool
= mem_internal_allocate_typed(Variable_Size_Pool
);
658 pool
->top_block
= NULL
;
659 pool
->compact
= compact
;
660 pool
->minimum_block_size
= min_block
;
661 pool
->total_allocated
= 0;
662 pool
->guaranteed_reclaimable
= 0;
663 pool
->possibly_reclaimable
= 0;
664 pool
->reclaim_factor
= RECLAMATION_FACTOR
;
671 =item C<void initialize_var_size_pools(PARROT_INTERP)>
673 Initialize the managed memory pools. Parrot maintains two C<Variable_Size_Pool>
674 structures, the general memory pool and the constant string pool. Create
675 and initialize both pool structures, and allocate initial blocks of memory
683 initialize_var_size_pools(PARROT_INTERP
)
685 ASSERT_ARGS(initialize_var_size_pools
)
686 Memory_Pools
* const mem_pools
= interp
->mem_pools
;
688 mem_pools
->memory_pool
= new_memory_pool(POOL_SIZE
, &compact_pool
);
689 alloc_new_block(interp
, POOL_SIZE
, mem_pools
->memory_pool
, "init");
691 /* Constant strings - not compacted */
692 mem_pools
->constant_string_pool
= new_memory_pool(POOL_SIZE
, NULL
);
693 alloc_new_block(interp
, POOL_SIZE
, mem_pools
->constant_string_pool
, "init");
699 =item C<void merge_pools(Variable_Size_Pool *dest, Variable_Size_Pool *source)>
701 Merge two memory pools together. Do this by moving all memory blocks
702 from the C<*source> pool into the C<*dest> pool. The C<source> pool
703 is emptied, but is not destroyed here.
710 merge_pools(ARGMOD(Variable_Size_Pool
*dest
), ARGMOD(Variable_Size_Pool
*source
))
712 ASSERT_ARGS(merge_pools
)
713 Memory_Block
*cur_block
;
715 cur_block
= source
->top_block
;
718 Memory_Block
* const next_block
= cur_block
->prev
;
720 if (cur_block
->free
== cur_block
->size
)
721 mem_internal_free(cur_block
);
723 cur_block
->next
= NULL
;
724 cur_block
->prev
= dest
->top_block
;
726 dest
->top_block
= cur_block
;
727 dest
->total_allocated
+= cur_block
->size
;
729 cur_block
= next_block
;
732 dest
->guaranteed_reclaimable
+= source
->guaranteed_reclaimable
;
733 dest
->possibly_reclaimable
+= dest
->possibly_reclaimable
;
735 source
->top_block
= NULL
;
736 source
->total_allocated
= 0;
737 source
->possibly_reclaimable
= 0;
738 source
->guaranteed_reclaimable
= 0;
743 =item C<static void check_memory_system(PARROT_INTERP)>
745 Checks the memory system of parrot on any corruptions, including
753 check_memory_system(PARROT_INTERP
)
755 ASSERT_ARGS(check_memory_system
)
757 Memory_Pools
* const mem_pools
= interp
->mem_pools
;
759 check_var_size_obj_pool(mem_pools
->memory_pool
);
760 check_var_size_obj_pool(mem_pools
->constant_string_pool
);
761 check_fixed_size_obj_pool(mem_pools
->pmc_pool
);
762 check_fixed_size_obj_pool(mem_pools
->constant_pmc_pool
);
763 check_fixed_size_obj_pool(mem_pools
->string_header_pool
);
764 check_fixed_size_obj_pool(mem_pools
->constant_string_header_pool
);
766 for (i
= 0; i
< mem_pools
->num_sized
; i
++) {
767 Fixed_Size_Pool
* pool
= mem_pools
->sized_header_pools
[i
];
768 if (pool
!= NULL
&& pool
!= mem_pools
->string_header_pool
)
769 check_fixed_size_obj_pool(pool
);
775 =item C<static void check_fixed_size_obj_pool(Fixed_Size_Pool * pool)>
777 Checks a small object pool, if it contains buffer it checks the buffers also.
784 check_fixed_size_obj_pool(ARGMOD(Fixed_Size_Pool
* pool
))
786 ASSERT_ARGS(check_fixed_size_obj_pool
)
787 size_t total_objects
;
788 size_t last_free_list_count
;
789 Fixed_Size_Arena
* arena_walker
;
794 GC_MS_PObj_Wrapper
* pobj_walker
;
796 count
= 10000000; /*detect unendless loop just use big enough number*/
798 total_objects
= pool
->total_objects
;
799 last_free_list_count
= 1;
802 arena_walker
= pool
->last_Arena
;
803 while (arena_walker
!= NULL
) {
804 total_objects
-= arena_walker
->total_objects
;
805 object
= (PObj
*)arena_walker
->start_objects
;
806 for (i
= 0; i
< arena_walker
->total_objects
; ++i
) {
807 if (PObj_on_free_list_TEST(object
)) {
809 pobj_walker
= (GC_MS_PObj_Wrapper
*)object
;
810 if (pobj_walker
->next_ptr
== NULL
)
811 /* should happen only once at the end */
812 --last_free_list_count
;
814 /* next item on free list should also be flaged as free item */
815 pobj_walker
= (GC_MS_PObj_Wrapper
*)pobj_walker
->next_ptr
;
816 PARROT_ASSERT(PObj_on_free_list_TEST((PObj
*)pobj_walker
));
819 else if (pool
->mem_pool
!= NULL
) {
820 /*then it means we are a buffer*/
821 check_buffer_ptr((Buffer
*)object
, pool
->mem_pool
);
823 object
= (PObj
*)((char *)object
+ pool
->object_size
);
824 PARROT_ASSERT(--count
);
827 if (arena_walker
->prev
!= NULL
)
828 PARROT_ASSERT(arena_walker
->prev
->next
== arena_walker
);
829 arena_walker
= arena_walker
->prev
;
830 PARROT_ASSERT(--count
);
835 PARROT_ASSERT(free_objects
== pool
->num_free_objects
);
837 pobj_walker
= (GC_MS_PObj_Wrapper
*)pool
->free_list
;
838 while (pobj_walker
!= NULL
) {
839 PARROT_ASSERT(pool
->start_arena_memory
<= (size_t)pobj_walker
);
840 PARROT_ASSERT(pool
->end_arena_memory
> (size_t)pobj_walker
);
841 PARROT_ASSERT(PObj_on_free_list_TEST((PObj
*)pobj_walker
));
843 pobj_walker
= (GC_MS_PObj_Wrapper
*)pobj_walker
->next_ptr
;
844 PARROT_ASSERT(--count
);
847 PARROT_ASSERT(total_objects
== 0);
848 PARROT_ASSERT(last_free_list_count
== 0 || pool
->num_free_objects
== 0);
849 PARROT_ASSERT(free_objects
== 0);
854 =item C<static void check_var_size_obj_pool(Variable_Size_Pool *pool)>
856 Checks a memory pool, containing buffer data
863 check_var_size_obj_pool(ARGMOD(Variable_Size_Pool
*pool
))
865 ASSERT_ARGS(check_var_size_obj_pool
)
867 Memory_Block
* block_walker
;
868 count
= 10000000; /*detect unendless loop just use big enough number*/
870 block_walker
= (Memory_Block
*)pool
->top_block
;
871 while (block_walker
!= NULL
) {
872 PARROT_ASSERT(block_walker
->start
== (char *)block_walker
+
873 sizeof (Memory_Block
));
874 PARROT_ASSERT((size_t)(block_walker
->top
-
875 block_walker
->start
) == block_walker
->size
- block_walker
->free
);
878 if (block_walker
->prev
!= NULL
)
879 PARROT_ASSERT(block_walker
->prev
->next
== block_walker
);
880 block_walker
= block_walker
->prev
;
881 PARROT_ASSERT(--count
);
887 =item C<void check_buffer_ptr(Buffer * pobj, Variable_Size_Pool * pool)>
889 Checks wether the buffer is within the bounds of the memory pool
896 check_buffer_ptr(ARGMOD(Buffer
* pobj
), ARGMOD(Variable_Size_Pool
* pool
))
898 ASSERT_ARGS(check_buffer_ptr
)
899 Memory_Block
* cur_block
= pool
->top_block
;
902 bufstart
= (char*)Buffer_bufstart(pobj
);
904 if (bufstart
== NULL
&& Buffer_buflen(pobj
) == 0)
907 if (PObj_external_TEST(pobj
) || PObj_sysmem_TEST(pobj
)) {
908 /*buffer does not come from the memory pool*/
909 if (PObj_is_string_TEST(pobj
)) {
910 PARROT_ASSERT(((STRING
*) pobj
)->strstart
>=
911 (char *) Buffer_bufstart(pobj
));
912 PARROT_ASSERT(((STRING
*) pobj
)->strstart
+
913 ((STRING
*) pobj
)->strlen
<=
914 (char *) Buffer_bufstart(pobj
) + Buffer_buflen(pobj
));
919 if (PObj_is_COWable_TEST(pobj
))
920 bufstart
-= sizeof (void*);
923 if ((char *)bufstart
>= cur_block
->start
&&
924 (char *)Buffer_bufstart(pobj
) +
925 Buffer_buflen(pobj
) < cur_block
->start
+ cur_block
->size
) {
926 if (PObj_is_string_TEST(pobj
)) {
927 PARROT_ASSERT(((STRING
*)pobj
)->strstart
>=
928 (char *)Buffer_bufstart(pobj
));
929 PARROT_ASSERT(((STRING
*)pobj
)->strstart
+
930 ((STRING
*)pobj
)->strlen
<= (char *)Buffer_bufstart(pobj
) +
931 Buffer_buflen(pobj
));
935 cur_block
= cur_block
->prev
;
950 Initial version by Dan on 2001.10.2.
958 * c-file-style: "parrot"
960 * vim: expandtab shiftwidth=4: