[svn:parrot] r49069 - in trunk: . config/gen/makefiles src src/gc
bacek at svn.parrot.org
bacek at svn.parrot.org
Thu Sep 16 20:47:06 UTC 2010
Author: bacek
Date: Thu Sep 16 20:47:05 2010
New Revision: 49069
URL: https://trac.parrot.org/parrot/changeset/49069
Log:
Merge branch 'string_gc'
Added:
trunk/src/gc/string_gc.c
- copied, changed from r49067, trunk/src/gc/alloc_resources.c
Modified:
trunk/MANIFEST
trunk/config/gen/makefiles/root.in
trunk/src/debug.c
trunk/src/gc/alloc_resources.c
trunk/src/gc/gc_ms.c
trunk/src/gc/gc_private.h
trunk/src/gc/mark_sweep.c
Modified: trunk/MANIFEST
==============================================================================
--- trunk/MANIFEST Thu Sep 16 20:38:57 2010 (r49068)
+++ trunk/MANIFEST Thu Sep 16 20:47:05 2010 (r49069)
@@ -1,7 +1,7 @@
# ex: set ro:
# $Id$
#
-# generated by tools/dev/mk_manifest_and_skip.pl Tue Sep 14 05:49:01 2010 UT
+# generated by tools/dev/mk_manifest_and_skip.pl Thu Sep 16 15:48:25 2010 UT
#
# See below for documentation on the format of this file.
#
@@ -1288,6 +1288,7 @@
src/gc/malloc.c []
src/gc/malloc_trace.c []
src/gc/mark_sweep.c []
+src/gc/string_gc.c []
src/gc/system.c []
src/global_setup.c []
src/hash.c []
Modified: trunk/config/gen/makefiles/root.in
==============================================================================
--- trunk/config/gen/makefiles/root.in Thu Sep 16 20:38:57 2010 (r49068)
+++ trunk/config/gen/makefiles/root.in Thu Sep 16 20:47:05 2010 (r49069)
@@ -464,6 +464,7 @@
src/gc/gc_inf$(O) \
src/gc/mark_sweep$(O) \
src/gc/system$(O) \
+ src/gc/string_gc$(O) \
src/global_setup$(O) \
src/hash$(O) \
src/hll$(O) \
@@ -1300,6 +1301,9 @@
src/gc/alloc_resources$(O) : $(PARROT_H_HEADERS) \
src/gc/gc_private.h src/gc/alloc_resources.c
+src/gc/string_gc$(O) : $(PARROT_H_HEADERS) \
+ src/gc/gc_private.h src/gc/string_gc.c
+
src/hll$(O) : $(PARROT_H_HEADERS) src/hll.str $(INC_DIR)/dynext.h src/hll.c
src/platform$(O) : $(PARROT_H_HEADERS) src/platform.c
Modified: trunk/src/debug.c
==============================================================================
--- trunk/src/debug.c Thu Sep 16 20:38:57 2010 (r49068)
+++ trunk/src/debug.c Thu Sep 16 20:47:05 2010 (r49069)
@@ -82,7 +82,8 @@
static void debugger_cmdline(PARROT_INTERP)
__attribute__nonnull__(1);
-static void display_breakpoint(ARGIN(PDB_t *pdb),
+static void display_breakpoint(
+ ARGIN(PDB_t *pdb),
ARGIN(const PDB_breakpoint_t *breakpoint))
__attribute__nonnull__(1)
__attribute__nonnull__(2);
Modified: trunk/src/gc/alloc_resources.c
==============================================================================
--- trunk/src/gc/alloc_resources.c Thu Sep 16 20:38:57 2010 (r49068)
+++ trunk/src/gc/alloc_resources.c Thu Sep 16 20:47:05 2010 (r49069)
@@ -30,10 +30,6 @@
#define RESOURCE_DEBUG 0
#define RESOURCE_DEBUG_SIZE 1000000
-#define POOL_SIZE (65536 * 2)
-
-typedef void (*compact_f) (Interp *, Memory_Pools * const, Variable_Size_Pool *);
-
typedef struct string_callback_data {
Memory_Block *new_block; /* A pointer to our working block */
char *cur_spot; /* Where we're currently copying to */
@@ -44,17 +40,6 @@
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
-static void alloc_new_block(
- ARGMOD(Memory_Pools *mem_pools),
- size_t size,
- ARGMOD(Variable_Size_Pool *pool),
- ARGIN(const char *why))
- __attribute__nonnull__(1)
- __attribute__nonnull__(3)
- __attribute__nonnull__(4)
- FUNC_MODIFIES(*mem_pools)
- FUNC_MODIFIES(*pool);
-
PARROT_CANNOT_RETURN_NULL
PARROT_WARN_UNUSED_RESULT
static const char * buffer_location(PARROT_INTERP, ARGIN(const Buffer *b))
@@ -81,54 +66,10 @@
__attribute__nonnull__(2)
FUNC_MODIFIES(*dest_interp);
-static void free_memory_pool(ARGFREE(Variable_Size_Pool *pool));
-static void free_old_mem_blocks(
- ARGMOD(Memory_Pools *mem_pools),
- ARGMOD(Variable_Size_Pool *pool),
- ARGMOD(Memory_Block *new_block),
- UINTVAL total_size)
- __attribute__nonnull__(1)
- __attribute__nonnull__(2)
- __attribute__nonnull__(3)
- FUNC_MODIFIES(*mem_pools)
- FUNC_MODIFIES(*pool)
- FUNC_MODIFIES(*new_block);
-
static void free_pool(ARGFREE(Fixed_Size_Pool *pool));
static int is_block_almost_full(ARGIN(const Memory_Block *block))
__attribute__nonnull__(1);
-static void move_buffer_callback(PARROT_INTERP,
- ARGIN(Buffer *b),
- ARGIN(void *data))
- __attribute__nonnull__(1)
- __attribute__nonnull__(2)
- __attribute__nonnull__(3);
-
-PARROT_WARN_UNUSED_RESULT
-PARROT_CANNOT_RETURN_NULL
-static char * move_one_buffer(PARROT_INTERP,
- ARGIN(Memory_Block *pool),
- ARGMOD(Buffer *old_buf),
- ARGMOD(char *new_pool_ptr))
- __attribute__nonnull__(1)
- __attribute__nonnull__(2)
- __attribute__nonnull__(3)
- __attribute__nonnull__(4)
- FUNC_MODIFIES(*old_buf)
- FUNC_MODIFIES(*new_pool_ptr);
-
-PARROT_WARN_UNUSED_RESULT
-PARROT_MALLOC
-PARROT_CANNOT_RETURN_NULL
-static Variable_Size_Pool * new_memory_pool(
- size_t min_block,
- NULLOK(compact_f compact));
-
-PARROT_CANNOT_RETURN_NULL
-static UINTVAL pad_pool_size(ARGIN(const Variable_Size_Pool *pool))
- __attribute__nonnull__(1);
-
static void Parrot_gc_merge_buffer_pools(PARROT_INTERP,
ARGMOD(Memory_Pools *mem_pools),
ARGMOD(Fixed_Size_Pool *dest),
@@ -160,10 +101,6 @@
FUNC_MODIFIES(*mem_pools)
FUNC_MODIFIES(*pool);
-#define ASSERT_ARGS_alloc_new_block __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(mem_pools) \
- , PARROT_ASSERT_ARG(pool) \
- , PARROT_ASSERT_ARG(why))
#define ASSERT_ARGS_buffer_location __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(b))
@@ -179,26 +116,9 @@
#define ASSERT_ARGS_fix_pmc_syncs __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(dest_interp) \
, PARROT_ASSERT_ARG(pool))
-#define ASSERT_ARGS_free_memory_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
-#define ASSERT_ARGS_free_old_mem_blocks __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(mem_pools) \
- , PARROT_ASSERT_ARG(pool) \
- , PARROT_ASSERT_ARG(new_block))
#define ASSERT_ARGS_free_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
#define ASSERT_ARGS_is_block_almost_full __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(block))
-#define ASSERT_ARGS_move_buffer_callback __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(b) \
- , PARROT_ASSERT_ARG(data))
-#define ASSERT_ARGS_move_one_buffer __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(pool) \
- , PARROT_ASSERT_ARG(old_buf) \
- , PARROT_ASSERT_ARG(new_pool_ptr))
-#define ASSERT_ARGS_new_memory_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
-#define ASSERT_ARGS_pad_pool_size __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(pool))
#define ASSERT_ARGS_Parrot_gc_merge_buffer_pools __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(mem_pools) \
@@ -217,165 +137,6 @@
/*
-=item C<static void alloc_new_block( Memory_Pools *mem_pools, size_t size,
-Variable_Size_Pool *pool, const char *why)>
-
-Allocate a new memory block. We allocate either the requested size or the
-default size, whichever is larger. Add the new block to the given memory
-pool. The given C<char *why> text is used for debugging.
-
-=cut
-
-*/
-
-static void
-alloc_new_block(
- ARGMOD(Memory_Pools *mem_pools),
- size_t size,
- ARGMOD(Variable_Size_Pool *pool),
- ARGIN(const char *why))
-{
- ASSERT_ARGS(alloc_new_block)
- Memory_Block *new_block;
-
- const size_t alloc_size = (size > pool->minimum_block_size)
- ? size : pool->minimum_block_size;
-
-#if RESOURCE_DEBUG
- fprintf(stderr, "new_block (%s) size %u -> %u\n",
- why, size, alloc_size);
-#else
- UNUSED(why)
-#endif
-
- /* Allocate a new block. Header info's on the front */
- new_block = (Memory_Block *)mem_internal_allocate_zeroed(
- sizeof (Memory_Block) + alloc_size);
-
- if (!new_block) {
- fprintf(stderr, "out of mem allocsize = %d\n", (int)alloc_size);
- exit(EXIT_FAILURE);
- }
-
- new_block->free = alloc_size;
- new_block->size = alloc_size;
-
- new_block->next = NULL;
- new_block->start = (char *)new_block + sizeof (Memory_Block);
- new_block->top = new_block->start;
-
- /* Note that we've allocated it */
- mem_pools->memory_allocated += alloc_size;
-
- /* If this is for a public pool, add it to the list */
- new_block->prev = pool->top_block;
-
- /* If we're not first, then tack us on the list */
- if (pool->top_block)
- pool->top_block->next = new_block;
-
- pool->top_block = new_block;
- pool->total_allocated += alloc_size;
-}
-
-/*
-
-=item C<void * mem_allocate(PARROT_INTERP, Memory_Pools *mem_pools, size_t size,
-Variable_Size_Pool *pool)>
-
-Allocates memory for headers.
-
-Alignment problems history:
-
-See L<http://archive.develooper.com/perl6-internals%40perl.org/msg12310.html>
-for details.
-
-- return aligned pointer *if needed*
-- return strings et al at unaligned i.e. void* boundaries
-- remember alignment in a buffer header bit
- use this in compaction code
-- reduce alignment to a reasonable value i.e. MALLOC_ALIGNMENT
- aka 2*sizeof (size_t) or just 8 (TODO make a config hint)
-
-See pobj.h for a discussion of the Buffer descriptor and the buffer itself,
-including its header.
-
-=cut
-
-*/
-
-PARROT_MALLOC
-PARROT_CANNOT_RETURN_NULL
-void *
-mem_allocate(PARROT_INTERP,
- ARGMOD(Memory_Pools *mem_pools),
- size_t size,
- ARGMOD(Variable_Size_Pool *pool))
-{
- ASSERT_ARGS(mem_allocate)
- void *return_val;
-
- /* we always should have one block at least */
- PARROT_ASSERT(pool->top_block);
-
- /* If not enough room, try to find some */
- if (pool->top_block->free < size) {
- /*
- * force a GC mark run to get live flags set
- * for incremental M&S collection is run from there
- * but only if there may be something worth collecting!
- * TODO pass required allocation size to the GC system,
- * so that collection can be skipped if needed
- */
- size_t new_mem = mem_pools->memory_used -
- mem_pools->mem_used_last_collect;
- if (!mem_pools->gc_mark_block_level
- && new_mem > (mem_pools->mem_used_last_collect >> 2)
- && new_mem > GC_SIZE_THRESHOLD) {
- Parrot_gc_mark_and_sweep(interp, GC_trace_stack_FLAG);
-
- if (interp->gc_sys->sys_type != INF) {
- /* Compact the pool if allowed and worthwhile */
- if (pool->compact) {
- /* don't bother reclaiming if it's only a small amount */
- if ((pool->possibly_reclaimable * pool->reclaim_factor +
- pool->guaranteed_reclaimable) > size) {
- (*pool->compact) (interp, mem_pools, pool);
- }
- }
- }
- }
- if (pool->top_block->free < size) {
- if (pool->minimum_block_size < 65536 * 16)
- pool->minimum_block_size *= 2;
- /*
- * TODO - Big blocks
- *
- * Mark the block as big block (it has just one item)
- * And don't set big blocks as the top_block.
- */
- alloc_new_block(mem_pools, size, pool, "compact failed");
-
- ++mem_pools->mem_allocs_since_last_collect;
-
- if (pool->top_block->free < size) {
- fprintf(stderr, "out of mem\n");
- exit(EXIT_FAILURE);
- }
- }
- }
-
- /* TODO inline the fast path */
- return_val = pool->top_block->top;
- pool->top_block->top += size;
- pool->top_block->free -= size;
- mem_pools->memory_used += size;
-
- return return_val;
-}
-
-/*
-
=item C<static const char * buffer_location(PARROT_INTERP, const Buffer *b)>
Recturns a constant string representing the location of the given
@@ -432,386 +193,8 @@
=back
-=head2 Compaction Code
-
-=over 4
-
-=item C<void compact_pool(PARROT_INTERP, Memory_Pools *mem_pools,
-Variable_Size_Pool *pool)>
-
-Compact the string buffer pool. Does not perform a GC scan, or mark items
-as being alive in any way.
-
-=cut
-
-*/
-
-void
-compact_pool(PARROT_INTERP,
- ARGMOD(Memory_Pools *mem_pools),
- ARGMOD(Variable_Size_Pool *pool))
-{
- ASSERT_ARGS(compact_pool)
- INTVAL j;
- UINTVAL total_size;
-
- Fixed_Size_Arena *cur_buffer_arena;
-
- /* Contains new_block and cur_spot */
- string_callback_data cb_data;
-
-
- /* Bail if we're blocked */
- if (mem_pools->gc_sweep_block_level)
- return;
-
- ++mem_pools->gc_sweep_block_level;
-
- /* We're collecting */
- mem_pools->mem_allocs_since_last_collect = 0;
- mem_pools->header_allocs_since_last_collect = 0;
- ++mem_pools->gc_collect_runs;
-
- /* Snag a block big enough for everything */
- total_size = pad_pool_size(pool);
-
- if (total_size == 0) {
- free_old_mem_blocks(mem_pools, pool, pool->top_block, total_size);
- --mem_pools->gc_sweep_block_level;
- return;
- }
-
- alloc_new_block(mem_pools, total_size, pool, "inside compact");
-
- cb_data.new_block = pool->top_block;
-
- /* Start at the beginning */
- cb_data.cur_spot = cb_data.new_block->start;
-
- /* Run through all the Buffer header pools and copy */
- interp->gc_sys->iterate_live_strings(interp, move_buffer_callback, &cb_data);
-
- /* Okay, we're done with the copy. Set the bits in the pool struct */
- /* First, where we allocate next */
- cb_data.new_block->top = cb_data.cur_spot;
-
- PARROT_ASSERT(cb_data.new_block->size
- >=
- (size_t)cb_data.new_block->top - (size_t)cb_data.new_block->start);
-
- /* How much is free. That's the total size minus the amount we used */
- cb_data.new_block->free = cb_data.new_block->size
- - (cb_data.cur_spot - cb_data.new_block->start);
- mem_pools->memory_collected += (cb_data.cur_spot - cb_data.new_block->start);
- mem_pools->memory_used += (cb_data.cur_spot - cb_data.new_block->start);
-
- free_old_mem_blocks(mem_pools, pool, cb_data.new_block, total_size);
-
- --mem_pools->gc_sweep_block_level;
-}
-
-/*
-=item C<static void move_buffer_callback(PARROT_INTERP, Buffer *b, void *data)>
-
-Callback for live STRING/Buffer for compating.
-
-=cut
-*/
-static void
-move_buffer_callback(PARROT_INTERP, ARGIN(Buffer *b), ARGIN(void *data))
-{
- ASSERT_ARGS(move_buffer_callback)
- string_callback_data *cb = (string_callback_data*)data;
-
- if (Buffer_buflen(b) && PObj_is_movable_TESTALL(b)) {
- Memory_Block *old_block = Buffer_pool(b);
-
- if (!is_block_almost_full(old_block))
- cb->cur_spot = move_one_buffer(interp, cb->new_block, b, cb->cur_spot);
- }
-
-}
-
-/*
-
-=item C<static UINTVAL pad_pool_size(const Variable_Size_Pool *pool)>
-
-Calculate the size of the new pool. The currently used size equals the total
-size minus the reclaimable size. Add a minimum block to the current amount, so
-we can avoid having to allocate it in the future.
-
-Returns 0 if all blocks below the top block are almost full. In this case
-compacting is not needed.
-
-TODO - Big blocks
-
-Currently all available blocks are compacted into one new
-block with total_size. This is suboptimal, if the block has
-just one live item from a big allocation.
-
-But currently it's unknown if the buffer memory is alive
-as the live bits are in Buffer headers. We have to run the
-compaction loop to check liveness. OTOH if this compaction
-is running through all the buffer headers, there is no
-relation to the block.
-
-Moving the live bit into the buffer thus also solves this
-problem easily.
-
-=cut
-
-*/
-
-PARROT_CANNOT_RETURN_NULL
-static UINTVAL
-pad_pool_size(ARGIN(const Variable_Size_Pool *pool))
-{
- ASSERT_ARGS(pad_pool_size)
- Memory_Block *cur_block = pool->top_block->prev;
-
- UINTVAL total_size = 0;
-#if RESOURCE_DEBUG
- size_t total_blocks = 1;
-#endif
-
- while (cur_block) {
- if (!is_block_almost_full(cur_block))
- total_size += cur_block->size - cur_block->freed - cur_block->free;
- cur_block = cur_block->prev;
-#if RESOURCE_DEBUG
- ++total_blocks;
-#endif
- }
-
- if (total_size == 0)
- return 0;
-
- cur_block = pool->top_block;
- if (!is_block_almost_full(cur_block))
- total_size += cur_block->size - cur_block->freed - cur_block->free;
-
- /* this makes for ever increasing allocations but fewer collect runs */
-#if WE_WANT_EVER_GROWING_ALLOCATIONS
- total_size += pool->minimum_block_size;
-#endif
-
-#if RESOURCE_DEBUG
- fprintf(stderr, "Total blocks: %d\n", total_blocks);
-#endif
-
- return total_size;
-}
-
-/*
-
-=item C<static char * move_one_buffer(PARROT_INTERP, Memory_Block *pool, Buffer
-*old_buf, char *new_pool_ptr)>
-
-The compact_pool operation collects disjointed blocks of memory allocated on a
-given pool's free list into one large block of memory. Once the new larger
-memory block has been allocated, this function moves one buffer from the old
-memory block to the new memory block and marks that it has been moved.
-
-=cut
-
*/
-PARROT_WARN_UNUSED_RESULT
-PARROT_CANNOT_RETURN_NULL
-static char *
-move_one_buffer(PARROT_INTERP, ARGIN(Memory_Block *pool),
- ARGMOD(Buffer *old_buf), ARGMOD(char *new_pool_ptr))
-{
- ASSERT_ARGS(move_one_buffer)
-
- INTVAL *flags = NULL;
- ptrdiff_t offset = 0;
- Memory_Block *old_block = NULL;
-#if RESOURCE_DEBUG
- if (Buffer_buflen(old_buf) >= RESOURCE_DEBUG_SIZE)
- debug_print_buf(interp, old_buf);
-#else
- UNUSED(interp);
-#endif
-
- /* we can't perform the math all the time, because
- * strstart might be in unallocated memory */
- if (PObj_is_COWable_TEST(old_buf)) {
- flags = Buffer_bufflagsptr(old_buf);
- old_block = Buffer_pool(old_buf);
-
- if (PObj_is_string_TEST(old_buf)) {
- offset = (ptrdiff_t)((STRING *)old_buf)->strstart -
- (ptrdiff_t)Buffer_bufstart(old_buf);
- }
- }
-
- /* buffer has already been moved; just change the header */
- if (flags && (*flags & Buffer_shared_FLAG)
- && (*flags & Buffer_moved_FLAG)) {
- /* Find out who else references our data */
- Buffer * const hdr = *((Buffer **)Buffer_bufstart(old_buf));
-
- PARROT_ASSERT(PObj_is_COWable_TEST(old_buf));
-
- /* Make sure they know that we own it too */
- /* Set Buffer_shared_FLAG in new buffer */
- *Buffer_bufflagsptr(hdr) |= Buffer_shared_FLAG;
-
- /* Now make sure we point to where the other guy does */
- Buffer_bufstart(old_buf) = Buffer_bufstart(hdr);
-
- /* And if we're a string, update strstart */
- /* Somewhat of a hack, but if we get per-pool
- * collections, it should help ease the pain */
- if (PObj_is_string_TEST(old_buf))
- ((STRING *)old_buf)->strstart =
- (char *)Buffer_bufstart(old_buf) + offset;
- }
- else {
- new_pool_ptr = aligned_mem(old_buf, new_pool_ptr);
-
- /* Copy our memory to the new pool */
- memcpy(new_pool_ptr, Buffer_bufstart(old_buf),
- Buffer_buflen(old_buf));
-
- /* If we're shared */
- if (flags && (*flags & Buffer_shared_FLAG)) {
- PARROT_ASSERT(PObj_is_COWable_TEST(old_buf));
-
- /* Let the old buffer know how to find us */
- *((Buffer **)Buffer_bufstart(old_buf)) = old_buf;
-
- /* Finally, let the tail know that we've moved, so
- * that any other references can know to look for
- * us and not re-copy */
- *flags |= Buffer_moved_FLAG;
- }
-
- Buffer_bufstart(old_buf) = new_pool_ptr;
-
- /* Remember new pool inside */
- *Buffer_poolptr(old_buf) = pool;
-
- if (PObj_is_string_TEST(old_buf))
- ((STRING *)old_buf)->strstart =
- (char *)Buffer_bufstart(old_buf) + offset;
-
- new_pool_ptr += Buffer_buflen(old_buf);
- }
-
- return new_pool_ptr;
-}
-
-/*
-
-=item C<static void free_old_mem_blocks( Memory_Pools *mem_pools,
-Variable_Size_Pool *pool, Memory_Block *new_block, UINTVAL total_size)>
-
-The compact_pool operation collects disjointed blocks of memory allocated on a
-given pool's free list into one large block of memory, setting it as the new
-top block for the pool. Once that is done, and all items have been moved into
-the new block of memory, this function iterates through the old blocks and
-frees each one. It also performs the necessary housekeeping to record the
-freed memory blocks. At the end of this function, the pool will have only one
-block of memory on its free list.
-
-=cut
-
-*/
-
-static void
-free_old_mem_blocks(
- ARGMOD(Memory_Pools *mem_pools),
- ARGMOD(Variable_Size_Pool *pool),
- ARGMOD(Memory_Block *new_block),
- UINTVAL total_size)
-{
- ASSERT_ARGS(free_old_mem_blocks)
- Memory_Block *prev_block = new_block;
- Memory_Block *cur_block = new_block->prev;
-
- PARROT_ASSERT(new_block == pool->top_block);
-
- while (cur_block) {
- Memory_Block * const next_block = cur_block->prev;
-
- if (is_block_almost_full(cur_block)) {
- /* Skip block */
- prev_block = cur_block;
- cur_block = next_block;
- }
- else {
- /* Note that we don't have it any more */
- mem_pools->memory_allocated -= cur_block->size;
- mem_pools->memory_used -= cur_block->size - cur_block->free;
-
- /* We know the pool body and pool header are a single chunk, so
- * this is enough to get rid of 'em both */
- mem_internal_free(cur_block);
- cur_block = next_block;
-
- /* Unlink it from list */
- prev_block->prev = next_block;
- }
- }
-
- /* Terminate list */
- prev_block->prev = NULL;
-
-
- /* ANR: I suspect this should be set to new_block->size, instead of passing
- * in the raw value of total_size, because alloc_new_block pads the size of
- * the new block under certain conditions. Leaving it unmodified for now,
- * so this refactor has no functionality changes, only code cleanups.*/
- pool->total_allocated = total_size;
- pool->guaranteed_reclaimable = 0;
- pool->possibly_reclaimable = 0;
-}
-
-/*
-
-=item C<static int is_block_almost_full(const Memory_Block *block)>
-
-Tests if the block is almost full and should be skipped during compacting.
-
-Returns true if less that 20% of block is available
-
-=cut
-
-*/
-
-static int
-is_block_almost_full(ARGIN(const Memory_Block *block))
-{
- ASSERT_ARGS(is_block_almost_full)
- return 5 * (block->free + block->freed) < block->size;
-}
-
-/*
-
-=item C<char * aligned_mem(const Buffer *buffer, char *mem)>
-
-Returns a pointer to the aligned allocated storage for Buffer C<buffer>,
-which might not be the same as the pointer to C<buffer> because of
-memory alignment.
-
-=cut
-
-*/
-
-PARROT_CANNOT_RETURN_NULL
-PARROT_WARN_UNUSED_RESULT
-char *
-aligned_mem(SHIM(const Buffer *buffer), ARGIN(char *mem))
-{
- ASSERT_ARGS(aligned_mem)
- mem += sizeof (void *);
- mem = (char *)(((unsigned long)(mem + WORD_ALIGN_1)) & WORD_ALIGN_MASK);
-
- return mem;
-}
-
/*
=back
@@ -820,63 +203,8 @@
=over 4
-=item C<static Variable_Size_Pool * new_memory_pool(size_t min_block, compact_f
-compact)>
-
-Allocate a new C<Variable_Size_Pool> structures, and set some initial values.
-return a pointer to the new pool.
-
-=cut
-
-*/
-
-PARROT_WARN_UNUSED_RESULT
-PARROT_MALLOC
-PARROT_CANNOT_RETURN_NULL
-static Variable_Size_Pool *
-new_memory_pool(size_t min_block, NULLOK(compact_f compact))
-{
- ASSERT_ARGS(new_memory_pool)
- Variable_Size_Pool * const pool = mem_internal_allocate_typed(Variable_Size_Pool);
-
- pool->top_block = NULL;
- pool->compact = compact;
- pool->minimum_block_size = min_block;
- pool->total_allocated = 0;
- pool->guaranteed_reclaimable = 0;
- pool->possibly_reclaimable = 0;
- pool->reclaim_factor = RECLAMATION_FACTOR;
-
- return pool;
-}
-
-/*
-
-=item C<void initialize_var_size_pools(PARROT_INTERP, Memory_Pools *mem_pools)>
-
-Initialize the managed memory pools. Parrot maintains two C<Variable_Size_Pool>
-structures, the general memory pool and the constant string pool. Create
-and initialize both pool structures, and allocate initial blocks of memory
-for both.
-
-=cut
-
*/
-void
-initialize_var_size_pools(SHIM_INTERP, ARGMOD(Memory_Pools *mem_pools))
-{
- ASSERT_ARGS(initialize_var_size_pools)
-
- mem_pools->memory_pool = new_memory_pool(POOL_SIZE, &compact_pool);
- alloc_new_block(mem_pools, POOL_SIZE, mem_pools->memory_pool, "init");
-
- /* Constant strings - not compacted */
- mem_pools->constant_string_pool = new_memory_pool(POOL_SIZE, NULL);
- alloc_new_block(mem_pools, POOL_SIZE, mem_pools->constant_string_pool, "init");
-}
-
-
/*
=item C<void merge_pools(Variable_Size_Pool *dest, Variable_Size_Pool *source)>
@@ -938,8 +266,9 @@
ASSERT_ARGS(check_memory_system)
size_t i;
- check_var_size_obj_pool(mem_pools->memory_pool);
- check_var_size_obj_pool(mem_pools->constant_string_pool);
+ check_var_size_obj_pool(mem_pools->string_gc.memory_pool);
+ check_var_size_obj_pool(mem_pools->string_gc.constant_string_pool);
+
check_fixed_size_obj_pool(mem_pools->pmc_pool);
check_fixed_size_obj_pool(mem_pools->constant_pmc_pool);
check_fixed_size_obj_pool(mem_pools->string_header_pool);
@@ -1000,10 +329,6 @@
PARROT_ASSERT(PObj_on_free_list_TEST((PObj*)pobj_walker));
}
}
- else if (pool->mem_pool != NULL) {
- /*then it means we are a buffer*/
- check_buffer_ptr((Buffer*)object, pool->mem_pool);
- }
object = (PObj*)((char *)object + pool->object_size);
PARROT_ASSERT(--count);
}
@@ -1262,54 +587,6 @@
}
-/*
-
-=item C<static void free_memory_pool(Variable_Size_Pool *pool)>
-
-Frees a memory pool; helper function for C<Parrot_gc_destroy_memory_pools>.
-
-=cut
-
-*/
-
-static void
-free_memory_pool(ARGFREE(Variable_Size_Pool *pool))
-{
- ASSERT_ARGS(free_memory_pool)
-
- Memory_Block *cur_block = pool->top_block;
-
- while (cur_block) {
- Memory_Block * const next_block = cur_block->prev;
- mem_internal_free(cur_block);
- cur_block = next_block;
- }
-
- mem_internal_free(pool);
-}
-
-
-/*
-
-=item C<void Parrot_gc_destroy_memory_pools(PARROT_INTERP, Memory_Pools
-*mem_pools)>
-
-Destroys the memory pool and the constant string pool. Loop through both
-pools and destroy all memory blocks contained in them. Once all the
-blocks are freed, free the pools themselves.
-
-=cut
-
-*/
-
-void
-Parrot_gc_destroy_memory_pools(SHIM_INTERP, ARGMOD(Memory_Pools *mem_pools))
-{
- ASSERT_ARGS(Parrot_gc_destroy_memory_pools)
-
- free_memory_pool(mem_pools->constant_string_pool);
- free_memory_pool(mem_pools->memory_pool);
-}
/*
Modified: trunk/src/gc/gc_ms.c
==============================================================================
--- trunk/src/gc/gc_ms.c Thu Sep 16 20:38:57 2010 (r49068)
+++ trunk/src/gc/gc_ms.c Thu Sep 16 20:47:05 2010 (r49069)
@@ -61,13 +61,6 @@
__attribute__nonnull__(3)
FUNC_MODIFIES(*pool);
-static void gc_ms_allocate_buffer_storage(PARROT_INTERP,
- ARGOUT(Buffer *buffer),
- size_t size)
- __attribute__nonnull__(1)
- __attribute__nonnull__(2)
- FUNC_MODIFIES(*buffer);
-
PARROT_CANNOT_RETURN_NULL
PARROT_WARN_UNUSED_RESULT
static Buffer * gc_ms_allocate_bufferlike_header(PARROT_INTERP, size_t size)
@@ -186,13 +179,6 @@
__attribute__nonnull__(2)
FUNC_MODIFIES(*pool);
-static void gc_ms_reallocate_buffer_storage(PARROT_INTERP,
- ARGMOD(Buffer *buffer),
- size_t newsize)
- __attribute__nonnull__(1)
- __attribute__nonnull__(2)
- FUNC_MODIFIES(*buffer);
-
PARROT_MALLOC
PARROT_CANNOT_RETURN_NULL
static void * gc_ms_reallocate_memory_chunk(SHIM_INTERP,
@@ -206,13 +192,6 @@
size_t newsize,
size_t oldsize);
-static void gc_ms_reallocate_string_storage(PARROT_INTERP,
- ARGMOD(STRING *str),
- size_t newsize)
- __attribute__nonnull__(1)
- __attribute__nonnull__(2)
- FUNC_MODIFIES(*str);
-
static int gc_ms_sweep_cb(PARROT_INTERP,
ARGIN(Memory_Pools *mem_pools),
ARGMOD(Fixed_Size_Pool *pool),
@@ -280,9 +259,6 @@
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(mem_pools) \
, PARROT_ASSERT_ARG(pool))
-#define ASSERT_ARGS_gc_ms_allocate_buffer_storage __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(buffer))
#define ASSERT_ARGS_gc_ms_allocate_bufferlike_header \
__attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
@@ -345,17 +321,9 @@
, PARROT_ASSERT_ARG(pool))
#define ASSERT_ARGS_gc_ms_pool_init __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(pool))
-#define ASSERT_ARGS_gc_ms_reallocate_buffer_storage \
- __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(buffer))
#define ASSERT_ARGS_gc_ms_reallocate_memory_chunk __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
#define ASSERT_ARGS_gc_ms_reallocate_memory_chunk_zeroed \
__attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
-#define ASSERT_ARGS_gc_ms_reallocate_string_storage \
- __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(str))
#define ASSERT_ARGS_gc_ms_sweep_cb __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(mem_pools) \
@@ -435,10 +403,10 @@
interp->gc_sys->allocate_pmc_attributes = gc_ms_allocate_pmc_attributes;
interp->gc_sys->free_pmc_attributes = gc_ms_free_pmc_attributes;
- interp->gc_sys->allocate_string_storage = gc_ms_allocate_string_storage;
+ interp->gc_sys->allocate_string_storage = gc_ms_allocate_string_storage;
interp->gc_sys->reallocate_string_storage = gc_ms_reallocate_string_storage;
- interp->gc_sys->allocate_buffer_storage = gc_ms_allocate_buffer_storage;
+ interp->gc_sys->allocate_buffer_storage = gc_ms_allocate_buffer_storage;
interp->gc_sys->reallocate_buffer_storage = gc_ms_reallocate_buffer_storage;
interp->gc_sys->allocate_fixed_size_storage = gc_ms_allocate_fixed_size_storage;
@@ -465,7 +433,7 @@
interp->gc_sys->iterate_live_strings = gc_ms_iterate_live_strings;
- initialize_var_size_pools(interp, interp->mem_pools);
+ Parrot_gc_str_initialize(interp, &interp->mem_pools->string_gc);
initialize_fixed_size_pools(interp, interp->mem_pools);
Parrot_gc_initialize_fixed_size_pools(interp, interp->mem_pools,
GC_NUM_INITIAL_FIXED_SIZE_POOLS);
@@ -489,7 +457,7 @@
Parrot_gc_destroy_header_pools(interp, interp->mem_pools);
/* memory pools in resources */
- Parrot_gc_destroy_memory_pools(interp, interp->mem_pools);
+ Parrot_gc_str_finalize(interp, &interp->mem_pools->string_gc);
/* mem subsystem is dead now */
mem_internal_free(interp->mem_pools);
@@ -606,7 +574,54 @@
gc_ms_compact_memory_pool(PARROT_INTERP)
{
ASSERT_ARGS(gc_ms_compact_memory_pool)
- compact_pool(interp, interp->mem_pools, interp->mem_pools->memory_pool);
+ Parrot_gc_str_compact_pool(interp, &interp->mem_pools->string_gc);
+}
+
+/*
+
+=item C<void gc_ms_allocate_string_storage(PARROT_INTERP, STRING *str, size_t
+size)>
+
+=item C<void gc_ms_reallocate_string_storage(PARROT_INTERP, STRING *str, size_t
+size)>
+
+=item C<void gc_ms_allocate_buffer_storage(PARROT_INTERP, Buffer *str, size_t
+size)>
+
+=item C<void gc_ms_reallocate_buffer_storage(PARROT_INTERP, Buffer *str, size_t
+size)>
+
+Functions for allocating strings/buffers storage.
+
+=cut
+*/
+
+void
+gc_ms_allocate_string_storage(PARROT_INTERP, ARGIN(STRING *str), size_t size)
+{
+ ASSERT_ARGS(gc_ms_allocate_string_storage)
+ Parrot_gc_str_allocate_string_storage(interp, &interp->mem_pools->string_gc, str, size);
+}
+
+void
+gc_ms_reallocate_string_storage(PARROT_INTERP, ARGIN(STRING *str), size_t size)
+{
+ ASSERT_ARGS(gc_ms_reallocate_string_storage)
+ Parrot_gc_str_reallocate_string_storage(interp, &interp->mem_pools->string_gc, str, size);
+}
+
+void
+gc_ms_allocate_buffer_storage(PARROT_INTERP, ARGIN(Buffer *str), size_t size)
+{
+ ASSERT_ARGS(gc_ms_allocate_buffer_storage)
+ Parrot_gc_str_allocate_buffer_storage(interp, &interp->mem_pools->string_gc, str, size);
+}
+
+void
+gc_ms_reallocate_buffer_storage(PARROT_INTERP, ARGIN(Buffer *str), size_t size)
+{
+ ASSERT_ARGS(gc_ms_reallocate_buffer_storage)
+ Parrot_gc_str_reallocate_buffer_storage(interp, &interp->mem_pools->string_gc, str, size);
}
/*
@@ -1086,233 +1101,6 @@
/*
-=item C<static void gc_ms_allocate_buffer_storage(PARROT_INTERP, Buffer *buffer,
-size_t size)>
-
-Allocates a chunk of memory of at least size C<size> for the given Buffer.
-buffer is guaranteed to be properly aligned for things like C<FLOATVALS>,
-so the size may be rounded up or down to guarantee that this alignment holds.
-
-=cut
-
-*/
-
-static void
-gc_ms_allocate_buffer_storage(PARROT_INTERP,
- ARGOUT(Buffer *buffer), size_t size)
-{
- ASSERT_ARGS(gc_ms_allocate_buffer_storage)
- const size_t new_size = ALIGNED_STRING_SIZE(size);
-
- Buffer_bufstart(buffer) = (void *)aligned_mem(buffer,
- (char *)mem_allocate(interp,
- interp->mem_pools, new_size, interp->mem_pools->memory_pool));
-
- /* Save pool used to allocate into buffer header */
- *Buffer_poolptr(buffer) = interp->mem_pools->memory_pool->top_block;
-
- Buffer_buflen(buffer) = new_size - sizeof (void *);
-}
-
-/*
-
-=item C<static void gc_ms_reallocate_buffer_storage(PARROT_INTERP, Buffer
-*buffer, size_t newsize)>
-
-Reallocate the Buffer's buffer memory to the given size. The
-allocated buffer will not shrink. If the buffer was allocated with
-L<Parrot_allocate_aligned> the new buffer will also be aligned. As with
-all reallocation, the new buffer might have moved and the additional
-memory is not cleared.
-
-=cut
-
-*/
-
-static void
-gc_ms_reallocate_buffer_storage(PARROT_INTERP, ARGMOD(Buffer *buffer),
- size_t newsize)
-{
- ASSERT_ARGS(gc_ms_reallocate_buffer_storage)
- size_t copysize;
- char *mem;
- Variable_Size_Pool * const pool = interp->mem_pools->memory_pool;
- size_t new_size, needed, old_size;
-
- /* we don't shrink buffers */
- if (newsize <= Buffer_buflen(buffer))
- return;
-
- /*
- * same as below but barely used and tested - only 3 list related
- * tests do use true reallocation
- *
- * list.c, which does _reallocate, has 2 reallocations
- * normally, which play ping pong with buffers.
- * The normal case is therefore always to allocate a new block
- */
- new_size = ALIGNED_STRING_SIZE(newsize);
- old_size = ALIGNED_STRING_SIZE(Buffer_buflen(buffer));
- needed = new_size - old_size;
-
- if ((pool->top_block->free >= needed)
- && (pool->top_block->top == (char *)Buffer_bufstart(buffer) + old_size)) {
- pool->top_block->free -= needed;
- pool->top_block->top += needed;
- interp->mem_pools->memory_used += needed;
- Buffer_buflen(buffer) = newsize;
- return;
- }
-
- copysize = Buffer_buflen(buffer);
-
- mem = (char *)mem_allocate(interp, interp->mem_pools, new_size, pool);
- mem = aligned_mem(buffer, mem);
-
- /* We shouldn't ever have a 0 from size, but we do. If we can track down
- * those bugs, this can be removed which would make things cheaper */
- if (copysize)
- memcpy(mem, Buffer_bufstart(buffer), copysize);
-
- Buffer_bufstart(buffer) = mem;
-
- new_size -= sizeof (void *);
-
- Buffer_buflen(buffer) = new_size;
-
- /* Save pool used to allocate into buffer header */
- *Buffer_poolptr(buffer) = interp->mem_pools->memory_pool->top_block;
-}
-
-/*
-
-=item C<void gc_ms_allocate_string_storage(PARROT_INTERP, STRING *str, size_t
-size)>
-
-Allocate the STRING's buffer memory to the given size. The allocated
-buffer maybe slightly bigger than the given C<size>. This function
-sets also C<< str->strstart >> to the new buffer location, C<< str->bufused >>
-is B<not> changed.
-
-=cut
-
-*/
-
-void
-gc_ms_allocate_string_storage(PARROT_INTERP, ARGOUT(STRING *str),
- size_t size)
-{
- ASSERT_ARGS(gc_ms_allocate_string_storage)
- size_t new_size;
- Variable_Size_Pool *pool;
- char *mem;
-
- Buffer_buflen(str) = 0;
- Buffer_bufstart(str) = NULL;
-
- if (size == 0)
- return;
-
- pool = PObj_constant_TEST(str)
- ? interp->mem_pools->constant_string_pool
- : interp->mem_pools->memory_pool;
-
- new_size = ALIGNED_STRING_SIZE(size);
- mem = (char *)mem_allocate(interp, interp->mem_pools, new_size, pool);
- mem += sizeof (void *);
-
- Buffer_bufstart(str) = str->strstart = mem;
- Buffer_buflen(str) = new_size - sizeof (void *);
-
- /* Save pool used to allocate into buffer header */
- *Buffer_poolptr(str) = pool->top_block;
-}
-
-/*
-
-=item C<static void gc_ms_reallocate_string_storage(PARROT_INTERP, STRING *str,
-size_t newsize)>
-
-Reallocate the STRING's buffer memory to the given size. The allocated
-buffer will not shrink. This function sets also C<str-E<gt>strstart> to the
-new buffer location, C<str-E<gt>bufused> is B<not> changed.
-
-=cut
-
-*/
-
-static void
-gc_ms_reallocate_string_storage(PARROT_INTERP, ARGMOD(STRING *str),
- size_t newsize)
-{
- ASSERT_ARGS(gc_ms_reallocate_string_storage)
- size_t copysize;
- char *mem, *oldmem;
- size_t new_size, needed, old_size;
-
- Variable_Size_Pool * const pool =
- PObj_constant_TEST(str)
- ? interp->mem_pools->constant_string_pool
- : interp->mem_pools->memory_pool;
-
- /* if the requested size is smaller then buflen, we are done */
- if (newsize <= Buffer_buflen(str))
- return;
-
- /*
- * first check, if we can reallocate:
- * - if the passed strings buffer is the last string in the pool and
- * - if there is enough size, we can just move the pool's top pointer
- */
- new_size = ALIGNED_STRING_SIZE(newsize);
- old_size = ALIGNED_STRING_SIZE(Buffer_buflen(str));
- needed = new_size - old_size;
-
- if (pool->top_block->free >= needed
- && pool->top_block->top == (char *)Buffer_bufstart(str) + old_size) {
- pool->top_block->free -= needed;
- pool->top_block->top += needed;
- interp->mem_pools->memory_used += needed;
- Buffer_buflen(str) = new_size - sizeof (void *);
- return;
- }
-
- PARROT_ASSERT(str->bufused <= newsize);
-
- /* only copy used memory, not total string buffer */
- copysize = str->bufused;
-
- mem = (char *)mem_allocate(interp, interp->mem_pools, new_size, pool);
- mem += sizeof (void *);
-
- /* Update Memory_Block usage */
- /* We must not reallocate non-movable buffers! */
- PARROT_ASSERT(PObj_is_movable_TESTALL(str));
-
- /* We must not reallocate shared buffers! */
- PARROT_ASSERT(!(*Buffer_bufflagsptr(str) & Buffer_shared_FLAG));
-
- /* Decrease usage */
- PARROT_ASSERT(Buffer_pool(str));
- Buffer_pool(str)->freed += old_size;
-
- /* copy mem from strstart, *not* bufstart */
- oldmem = str->strstart;
- Buffer_bufstart(str) = (void *)mem;
- str->strstart = mem;
- Buffer_buflen(str) = new_size - sizeof (void *);
-
- /* We shouldn't ever have a 0 from size, but we do. If we can track down
- * those bugs, this can be removed which would make things cheaper */
- if (copysize)
- memcpy(mem, oldmem, copysize);
-
- /* Save pool used to allocate into buffer header */
- *Buffer_poolptr(str) = pool->top_block;
-}
-
-/*
-
=item C<void * gc_ms_allocate_fixed_size_storage(PARROT_INTERP, size_t size)>
Allocates a fixed-size chunk of memory for use. This memory is not manually
Modified: trunk/src/gc/gc_private.h
==============================================================================
--- trunk/src/gc/gc_private.h Thu Sep 16 20:38:57 2010 (r49068)
+++ trunk/src/gc/gc_private.h Thu Sep 16 20:47:05 2010 (r49069)
@@ -165,6 +165,8 @@
*/
} GC_Subsystem;
+
+
/* This header structure describes a block of memory that is part of a
variable-size pool. The allocatable memory follows the header. */
@@ -245,9 +247,6 @@
hang off the Memory_Pools root structure. */
typedef struct Fixed_Size_Pool {
-
- struct Variable_Size_Pool *mem_pool; /* Pointer to associated variable-size
- pool, or NULL. */
size_t object_size; /* Size in bytes of an individual pool
object. This size may include
a GC system-specific GC header. */
@@ -290,15 +289,22 @@
} Fixed_Size_Pool;
+/* String GC subsystem data */
+typedef struct String_GC {
+ Variable_Size_Pool *memory_pool; /* General memory pool. */
+ Variable_Size_Pool *constant_string_pool; /* Constant string pool (not
+ compacted */
+} String_GC;
+
/* This structure acts as the root for all the various memory pools:
variable-sized, fixed-size, and PMC attributes. It also contains
various GC-related items. It hangs off the Interp structure. */
typedef struct Memory_Pools {
/* Pointers to pools */
- Variable_Size_Pool *memory_pool; /* General memory pool. */
- Variable_Size_Pool *constant_string_pool; /* Constant string pool (not
- compacted). */
+ String_GC string_gc; /* TEMPORARY */
+ /* String GC susbsytem pointer */
+
Fixed_Size_Pool *string_header_pool; /* String header pool. */
Fixed_Size_Pool *pmc_pool; /* PMC object pool. */
Fixed_Size_Pool *constant_pmc_pool; /* And one for constant PMCs. */
@@ -355,10 +361,9 @@
UINTVAL gc_sweep_block_level; /* How many outstanding GC block
requests are there? */
- /* private data for the GC subsystem */
- void *gc_private; /* GC subsystem data */
} Memory_Pools;
+
/* HEADERIZER BEGIN: src/gc/system.c */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
@@ -503,11 +508,6 @@
/* HEADERIZER BEGIN: src/gc/alloc_resources.c */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
-PARROT_CANNOT_RETURN_NULL
-PARROT_WARN_UNUSED_RESULT
-char * aligned_mem(SHIM(const Buffer *buffer), ARGIN(char *mem))
- __attribute__nonnull__(2);
-
void check_buffer_ptr(
ARGMOD(Buffer * pobj),
ARGMOD(Variable_Size_Pool * pool))
@@ -516,31 +516,6 @@
FUNC_MODIFIES(* pobj)
FUNC_MODIFIES(* pool);
-void compact_pool(PARROT_INTERP,
- ARGMOD(Memory_Pools *mem_pools),
- ARGMOD(Variable_Size_Pool *pool))
- __attribute__nonnull__(1)
- __attribute__nonnull__(2)
- __attribute__nonnull__(3)
- FUNC_MODIFIES(*mem_pools)
- FUNC_MODIFIES(*pool);
-
-void initialize_var_size_pools(SHIM_INTERP, ARGMOD(Memory_Pools *mem_pools))
- __attribute__nonnull__(2)
- FUNC_MODIFIES(*mem_pools);
-
-PARROT_MALLOC
-PARROT_CANNOT_RETURN_NULL
-void * mem_allocate(PARROT_INTERP,
- ARGMOD(Memory_Pools *mem_pools),
- size_t size,
- ARGMOD(Variable_Size_Pool *pool))
- __attribute__nonnull__(1)
- __attribute__nonnull__(2)
- __attribute__nonnull__(4)
- FUNC_MODIFIES(*mem_pools)
- FUNC_MODIFIES(*pool);
-
void merge_pools(
ARGMOD(Variable_Size_Pool *dest),
ARGMOD(Variable_Size_Pool *source))
@@ -555,11 +530,6 @@
__attribute__nonnull__(2)
FUNC_MODIFIES(*mem_pools);
-void Parrot_gc_destroy_memory_pools(SHIM_INTERP,
- ARGMOD(Memory_Pools *mem_pools))
- __attribute__nonnull__(2)
- FUNC_MODIFIES(*mem_pools);
-
void Parrot_gc_merge_memory_pools(
ARGMOD(Interp *dest_interp),
ARGMOD(Memory_Pools *dest_arena),
@@ -570,21 +540,9 @@
FUNC_MODIFIES(*dest_interp)
FUNC_MODIFIES(*dest_arena);
-#define ASSERT_ARGS_aligned_mem __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(mem))
#define ASSERT_ARGS_check_buffer_ptr __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(pobj) \
, PARROT_ASSERT_ARG(pool))
-#define ASSERT_ARGS_compact_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(mem_pools) \
- , PARROT_ASSERT_ARG(pool))
-#define ASSERT_ARGS_initialize_var_size_pools __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(mem_pools))
-#define ASSERT_ARGS_mem_allocate __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(mem_pools) \
- , PARROT_ASSERT_ARG(pool))
#define ASSERT_ARGS_merge_pools __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(dest) \
, PARROT_ASSERT_ARG(source))
@@ -592,9 +550,6 @@
__attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(mem_pools))
-#define ASSERT_ARGS_Parrot_gc_destroy_memory_pools \
- __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(mem_pools))
#define ASSERT_ARGS_Parrot_gc_merge_memory_pools __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(dest_interp) \
, PARROT_ASSERT_ARG(dest_arena) \
@@ -606,16 +561,21 @@
/* HEADERIZER BEGIN: src/gc/gc_ms.c */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
+void gc_ms_allocate_buffer_storage(PARROT_INTERP,
+ ARGIN(Buffer *str),
+ size_t size)
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2);
+
PARROT_CANNOT_RETURN_NULL
void * gc_ms_allocate_fixed_size_storage(PARROT_INTERP, size_t size)
__attribute__nonnull__(1);
void gc_ms_allocate_string_storage(PARROT_INTERP,
- ARGOUT(STRING *str),
+ ARGIN(STRING *str),
size_t size)
__attribute__nonnull__(1)
- __attribute__nonnull__(2)
- FUNC_MODIFIES(*str);
+ __attribute__nonnull__(2);
void gc_ms_compact_memory_pool(PARROT_INTERP)
__attribute__nonnull__(1);
@@ -637,9 +597,24 @@
__attribute__nonnull__(2)
FUNC_MODIFIES(*pmc);
+void gc_ms_reallocate_buffer_storage(PARROT_INTERP,
+ ARGIN(Buffer *str),
+ size_t size)
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2);
+
+void gc_ms_reallocate_string_storage(PARROT_INTERP,
+ ARGIN(STRING *str),
+ size_t size)
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2);
+
void Parrot_gc_ms_init(PARROT_INTERP)
__attribute__nonnull__(1);
+#define ASSERT_ARGS_gc_ms_allocate_buffer_storage __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(str))
#define ASSERT_ARGS_gc_ms_allocate_fixed_size_storage \
__attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
@@ -658,6 +633,14 @@
__attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(pmc))
+#define ASSERT_ARGS_gc_ms_reallocate_buffer_storage \
+ __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(str))
+#define ASSERT_ARGS_gc_ms_reallocate_string_storage \
+ __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(str))
#define ASSERT_ARGS_Parrot_gc_ms_init __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
@@ -674,6 +657,116 @@
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: src/gc/gc_inf.c */
+
+/* HEADERIZER BEGIN: src/gc/string_gc.c */
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
+
+void Parrot_gc_str_alloc_new_block(
+ ARGMOD(Memory_Pools *mem_pools),
+ size_t size,
+ ARGMOD(Variable_Size_Pool *pool),
+ ARGIN(const char *why))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(3)
+ __attribute__nonnull__(4)
+ FUNC_MODIFIES(*mem_pools)
+ FUNC_MODIFIES(*pool);
+
+void Parrot_gc_str_allocate_buffer_storage(PARROT_INTERP,
+ ARGIN(String_GC *gc),
+ ARGOUT(Buffer *buffer),
+ size_t size)
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ __attribute__nonnull__(3)
+ FUNC_MODIFIES(*buffer);
+
+void Parrot_gc_str_allocate_string_storage(PARROT_INTERP,
+ ARGIN(String_GC *gc),
+ ARGOUT(STRING *str),
+ size_t size)
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ __attribute__nonnull__(3)
+ FUNC_MODIFIES(*str);
+
+void Parrot_gc_str_compact_pool(PARROT_INTERP, ARGIN(String_GC *gc))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2);
+
+void Parrot_gc_str_finalize(SHIM_INTERP, ARGMOD(String_GC *gc))
+ __attribute__nonnull__(2)
+ FUNC_MODIFIES(*gc);
+
+void Parrot_gc_str_free_buffer_storage(SHIM_INTERP,
+ ARGIN(String_GC *gc),
+ ARGMOD(Buffer *b))
+ __attribute__nonnull__(2)
+ __attribute__nonnull__(3)
+ FUNC_MODIFIES(*b);
+
+void Parrot_gc_str_initialize(PARROT_INTERP, ARGMOD(String_GC *gc))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ FUNC_MODIFIES(*gc);
+
+void Parrot_gc_str_reallocate_buffer_storage(PARROT_INTERP,
+ ARGIN(String_GC *gc),
+ ARGMOD(Buffer *buffer),
+ size_t newsize)
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ __attribute__nonnull__(3)
+ FUNC_MODIFIES(*buffer);
+
+void Parrot_gc_str_reallocate_string_storage(PARROT_INTERP,
+ ARGIN(String_GC *gc),
+ ARGMOD(STRING *str),
+ size_t newsize)
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ __attribute__nonnull__(3)
+ FUNC_MODIFIES(*str);
+
+#define ASSERT_ARGS_Parrot_gc_str_alloc_new_block __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(mem_pools) \
+ , PARROT_ASSERT_ARG(pool) \
+ , PARROT_ASSERT_ARG(why))
+#define ASSERT_ARGS_Parrot_gc_str_allocate_buffer_storage \
+ __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(gc) \
+ , PARROT_ASSERT_ARG(buffer))
+#define ASSERT_ARGS_Parrot_gc_str_allocate_string_storage \
+ __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(gc) \
+ , PARROT_ASSERT_ARG(str))
+#define ASSERT_ARGS_Parrot_gc_str_compact_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(gc))
+#define ASSERT_ARGS_Parrot_gc_str_finalize __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(gc))
+#define ASSERT_ARGS_Parrot_gc_str_free_buffer_storage \
+ __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(gc) \
+ , PARROT_ASSERT_ARG(b))
+#define ASSERT_ARGS_Parrot_gc_str_initialize __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(gc))
+#define ASSERT_ARGS_Parrot_gc_str_reallocate_buffer_storage \
+ __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(gc) \
+ , PARROT_ASSERT_ARG(buffer))
+#define ASSERT_ARGS_Parrot_gc_str_reallocate_string_storage \
+ __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(gc) \
+ , PARROT_ASSERT_ARG(str))
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
+/* HEADERIZER END: src/gc/string_gc.c */
+
#endif /* PARROT_GC_PRIVATE_H_GUARD */
/*
Modified: trunk/src/gc/mark_sweep.c
==============================================================================
--- trunk/src/gc/mark_sweep.c Thu Sep 16 20:38:57 2010 (r49068)
+++ trunk/src/gc/mark_sweep.c Thu Sep 16 20:47:05 2010 (r49069)
@@ -31,13 +31,13 @@
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
-static void free_buffer(SHIM_INTERP,
- SHIM(Memory_Pools *mem_pools),
- ARGMOD(Fixed_Size_Pool *pool),
+static void free_buffer(PARROT_INTERP,
+ ARGIN(Memory_Pools *mem_pools),
+ SHIM(Fixed_Size_Pool *pool),
ARGMOD(Buffer *b))
- __attribute__nonnull__(3)
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
__attribute__nonnull__(4)
- FUNC_MODIFIES(*pool)
FUNC_MODIFIES(*b);
static void free_pmc_in_pool(PARROT_INTERP,
@@ -78,7 +78,8 @@
FUNC_MODIFIES(*mem_pools);
#define ASSERT_ARGS_free_buffer __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(pool) \
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(mem_pools) \
, PARROT_ASSERT_ARG(b))
#define ASSERT_ARGS_free_pmc_in_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
@@ -509,7 +510,6 @@
Fixed_Size_Pool * const pmc_pool =
new_fixed_size_obj_pool(sizeof (PMC), num_headers);
- pmc_pool->mem_pool = NULL;
pmc_pool->gc_object = free_pmc_in_pool;
(interp->gc_sys->init_pool)(interp, pmc_pool);
@@ -574,7 +574,6 @@
pool->gc_object = (gc_object_fn_type)free_buffer;
- pool->mem_pool = mem_pools->memory_pool;
(interp->gc_sys->init_pool)(interp, pool);
return pool;
}
@@ -603,7 +602,6 @@
pool->last_Arena = NULL;
pool->free_list = NULL;
- pool->mem_pool = NULL;
pool->newfree = NULL;
pool->newlast = NULL;
pool->object_size = object_size;
@@ -634,7 +632,6 @@
if (constant) {
pool = new_bufferlike_pool(interp, mem_pools, sizeof (STRING));
pool->gc_object = NULL;
- pool->mem_pool = mem_pools->constant_string_pool;
}
else
pool = get_bufferlike_pool(interp, mem_pools, sizeof (STRING));
@@ -657,39 +654,18 @@
*/
static void
-free_buffer(SHIM_INTERP,
- SHIM(Memory_Pools *mem_pools),
- ARGMOD(Fixed_Size_Pool *pool),
+free_buffer(PARROT_INTERP,
+ ARGIN(Memory_Pools *mem_pools),
+ SHIM(Fixed_Size_Pool *pool),
ARGMOD(Buffer *b))
{
ASSERT_ARGS(free_buffer)
- Variable_Size_Pool * const mem_pool = (Variable_Size_Pool *)pool->mem_pool;
/* If there is no allocated buffer - bail out */
if (!Buffer_buflen(b))
return;
- /* XXX Jarkko reported that on irix pool->mem_pool was NULL, which really
- * shouldn't happen */
- if (mem_pool) {
- /* Update Memory_Block usage */
- if (PObj_is_movable_TESTALL(b)) {
- INTVAL *buffer_flags = Buffer_bufflagsptr(b);
-
- /* Mask low 2 bits used for flags */
- Memory_Block * block = Buffer_pool(b);
-
- PARROT_ASSERT(block);
-
- /* We can have shared buffers. Don't count them (yet) */
- if (!(*buffer_flags & Buffer_shared_FLAG)) {
- block->freed += ALIGNED_STRING_SIZE(Buffer_buflen(b));
- }
-
- }
- }
-
- Buffer_buflen(b) = 0;
+ Parrot_gc_str_free_buffer_storage(interp, &mem_pools->string_gc, b);
}
Copied and modified: trunk/src/gc/string_gc.c (from r49067, trunk/src/gc/alloc_resources.c)
==============================================================================
--- trunk/src/gc/alloc_resources.c Thu Sep 16 20:35:44 2010 (r49067, copy source)
+++ trunk/src/gc/string_gc.c Thu Sep 16 20:47:05 2010 (r49069)
@@ -1,15 +1,14 @@
/*
-Copyright (C) 2001-2010, Parrot Foundation.
+Copyright (C) 2010, Parrot Foundation.
$Id$
=head1 NAME
-src/gc/alloc_resources.c - Allocate and deallocate buffer resources such as
-STRINGS.
+src/gc/string_gc.c - String GC subsystem.
=head1 DESCRIPTION
-Functions to manage non-PObj memory, including strings and buffers.
+GC subsystem to manage STRINGs.
=head2 Parrot Memory Management Code
@@ -22,17 +21,16 @@
#include "parrot/parrot.h"
#include "gc_private.h"
+typedef void (*compact_f) (Interp *, Memory_Pools * const, Variable_Size_Pool *);
-#define RECLAMATION_FACTOR 0.20
-#define WE_WANT_EVER_GROWING_ALLOCATIONS 0
+#define POOL_SIZE (65536 * 2)
/* show allocated blocks on stderr */
#define RESOURCE_DEBUG 0
#define RESOURCE_DEBUG_SIZE 1000000
-#define POOL_SIZE (65536 * 2)
-
-typedef void (*compact_f) (Interp *, Memory_Pools * const, Variable_Size_Pool *);
+#define RECLAMATION_FACTOR 0.20
+#define WE_WANT_EVER_GROWING_ALLOCATIONS 0
typedef struct string_callback_data {
Memory_Block *new_block; /* A pointer to our working block */
@@ -44,6 +42,11 @@
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
+PARROT_CANNOT_RETURN_NULL
+PARROT_WARN_UNUSED_RESULT
+static char * aligned_mem(SHIM(const Buffer *buffer), ARGIN(char *mem))
+ __attribute__nonnull__(2);
+
static void alloc_new_block(
ARGMOD(Memory_Pools *mem_pools),
size_t size,
@@ -61,26 +64,19 @@
__attribute__nonnull__(1)
__attribute__nonnull__(2);
-static void check_fixed_size_obj_pool(ARGIN(const Fixed_Size_Pool *pool))
- __attribute__nonnull__(1);
-
-static void check_memory_system(ARGIN(const Memory_Pools *mem_pools))
- __attribute__nonnull__(1);
-
-static void check_var_size_obj_pool(ARGIN(const Variable_Size_Pool *pool))
- __attribute__nonnull__(1);
+static void compact_pool(PARROT_INTERP,
+ ARGMOD(Memory_Pools *mem_pools),
+ ARGMOD(Variable_Size_Pool *pool))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ __attribute__nonnull__(3)
+ FUNC_MODIFIES(*mem_pools)
+ FUNC_MODIFIES(*pool);
static void debug_print_buf(PARROT_INTERP, ARGIN(const Buffer *b))
__attribute__nonnull__(1)
__attribute__nonnull__(2);
-static void fix_pmc_syncs(
- ARGMOD(Interp *dest_interp),
- ARGIN(const Fixed_Size_Pool *pool))
- __attribute__nonnull__(1)
- __attribute__nonnull__(2)
- FUNC_MODIFIES(*dest_interp);
-
static void free_memory_pool(ARGFREE(Variable_Size_Pool *pool));
static void free_old_mem_blocks(
ARGMOD(Memory_Pools *mem_pools),
@@ -94,10 +90,21 @@
FUNC_MODIFIES(*pool)
FUNC_MODIFIES(*new_block);
-static void free_pool(ARGFREE(Fixed_Size_Pool *pool));
static int is_block_almost_full(ARGIN(const Memory_Block *block))
__attribute__nonnull__(1);
+PARROT_MALLOC
+PARROT_CANNOT_RETURN_NULL
+static void * mem_allocate(PARROT_INTERP,
+ ARGMOD(Memory_Pools *mem_pools),
+ size_t size,
+ ARGMOD(Variable_Size_Pool *pool))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ __attribute__nonnull__(4)
+ FUNC_MODIFIES(*mem_pools)
+ FUNC_MODIFIES(*pool);
+
static void move_buffer_callback(PARROT_INTERP,
ARGIN(Buffer *b),
ARGIN(void *data))
@@ -129,37 +136,8 @@
static UINTVAL pad_pool_size(ARGIN(const Variable_Size_Pool *pool))
__attribute__nonnull__(1);
-static void Parrot_gc_merge_buffer_pools(PARROT_INTERP,
- ARGMOD(Memory_Pools *mem_pools),
- ARGMOD(Fixed_Size_Pool *dest),
- ARGMOD(Fixed_Size_Pool *source))
- __attribute__nonnull__(1)
- __attribute__nonnull__(2)
- __attribute__nonnull__(3)
- __attribute__nonnull__(4)
- FUNC_MODIFIES(*mem_pools)
- FUNC_MODIFIES(*dest)
- FUNC_MODIFIES(*source);
-
-static int sweep_cb_buf(PARROT_INTERP,
- ARGIN(Memory_Pools *mem_pools),
- ARGFREE(Fixed_Size_Pool *pool),
- SHIM(int flag),
- SHIM(void *arg))
- __attribute__nonnull__(1)
- __attribute__nonnull__(2);
-
-static int sweep_cb_pmc(PARROT_INTERP,
- ARGMOD(Memory_Pools *mem_pools),
- ARGMOD(Fixed_Size_Pool *pool),
- SHIM(int flag),
- SHIM(void *arg))
- __attribute__nonnull__(1)
- __attribute__nonnull__(2)
- __attribute__nonnull__(3)
- FUNC_MODIFIES(*mem_pools)
- FUNC_MODIFIES(*pool);
-
+#define ASSERT_ARGS_aligned_mem __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(mem))
#define ASSERT_ARGS_alloc_new_block __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(mem_pools) \
, PARROT_ASSERT_ARG(pool) \
@@ -167,26 +145,24 @@
#define ASSERT_ARGS_buffer_location __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(b))
-#define ASSERT_ARGS_check_fixed_size_obj_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(pool))
-#define ASSERT_ARGS_check_memory_system __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(mem_pools))
-#define ASSERT_ARGS_check_var_size_obj_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(pool))
+#define ASSERT_ARGS_compact_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(mem_pools) \
+ , PARROT_ASSERT_ARG(pool))
#define ASSERT_ARGS_debug_print_buf __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(b))
-#define ASSERT_ARGS_fix_pmc_syncs __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(dest_interp) \
- , PARROT_ASSERT_ARG(pool))
#define ASSERT_ARGS_free_memory_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
#define ASSERT_ARGS_free_old_mem_blocks __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(mem_pools) \
, PARROT_ASSERT_ARG(pool) \
, PARROT_ASSERT_ARG(new_block))
-#define ASSERT_ARGS_free_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
#define ASSERT_ARGS_is_block_almost_full __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(block))
+#define ASSERT_ARGS_mem_allocate __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(mem_pools) \
+ , PARROT_ASSERT_ARG(pool))
#define ASSERT_ARGS_move_buffer_callback __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(b) \
@@ -199,1272 +175,1026 @@
#define ASSERT_ARGS_new_memory_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
#define ASSERT_ARGS_pad_pool_size __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(pool))
-#define ASSERT_ARGS_Parrot_gc_merge_buffer_pools __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(mem_pools) \
- , PARROT_ASSERT_ARG(dest) \
- , PARROT_ASSERT_ARG(source))
-#define ASSERT_ARGS_sweep_cb_buf __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(mem_pools))
-#define ASSERT_ARGS_sweep_cb_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(mem_pools) \
- , PARROT_ASSERT_ARG(pool))
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
-
/*
-=item C<static void alloc_new_block( Memory_Pools *mem_pools, size_t size,
-Variable_Size_Pool *pool, const char *why)>
+=item C<void Parrot_gc_str_initialize(PARROT_INTERP, String_GC *gc)>
-Allocate a new memory block. We allocate either the requested size or the
-default size, whichever is larger. Add the new block to the given memory
-pool. The given C<char *why> text is used for debugging.
+Initialize the managed memory pools. Parrot maintains two C<Variable_Size_Pool>
+structures, the general memory pool and the constant string pool. Create
+and initialize both pool structures, and allocate initial blocks of memory
+for both.
=cut
*/
-static void
-alloc_new_block(
- ARGMOD(Memory_Pools *mem_pools),
- size_t size,
- ARGMOD(Variable_Size_Pool *pool),
- ARGIN(const char *why))
+void
+Parrot_gc_str_initialize(PARROT_INTERP, ARGMOD(String_GC *gc))
{
- ASSERT_ARGS(alloc_new_block)
- Memory_Block *new_block;
+ ASSERT_ARGS(Parrot_gc_str_initialize)
- const size_t alloc_size = (size > pool->minimum_block_size)
- ? size : pool->minimum_block_size;
-
-#if RESOURCE_DEBUG
- fprintf(stderr, "new_block (%s) size %u -> %u\n",
- why, size, alloc_size);
-#else
- UNUSED(why)
-#endif
+ gc->memory_pool = new_memory_pool(POOL_SIZE, &compact_pool);
+ alloc_new_block(interp->mem_pools, POOL_SIZE, gc->memory_pool, "init");
- /* Allocate a new block. Header info's on the front */
- new_block = (Memory_Block *)mem_internal_allocate_zeroed(
- sizeof (Memory_Block) + alloc_size);
+ /* Constant strings - not compacted */
+ gc->constant_string_pool = new_memory_pool(POOL_SIZE, NULL);
+ alloc_new_block(interp->mem_pools, POOL_SIZE, gc->constant_string_pool, "init");
+}
- if (!new_block) {
- fprintf(stderr, "out of mem allocsize = %d\n", (int)alloc_size);
- exit(EXIT_FAILURE);
- }
+/*
- new_block->free = alloc_size;
- new_block->size = alloc_size;
+=item C<void Parrot_gc_str_finalize(PARROT_INTERP, String_GC *gc)>
- new_block->next = NULL;
- new_block->start = (char *)new_block + sizeof (Memory_Block);
- new_block->top = new_block->start;
+Destroys the memory pool and the constant string pool. Loop through both
+pools and destroy all memory blocks contained in them. Once all the
+blocks are freed, free the pools themselves.
- /* Note that we've allocated it */
- mem_pools->memory_allocated += alloc_size;
+=cut
- /* If this is for a public pool, add it to the list */
- new_block->prev = pool->top_block;
+*/
- /* If we're not first, then tack us on the list */
- if (pool->top_block)
- pool->top_block->next = new_block;
+void
+Parrot_gc_str_finalize(SHIM_INTERP, ARGMOD(String_GC *gc))
+{
+ ASSERT_ARGS(Parrot_gc_str_finalize)
- pool->top_block = new_block;
- pool->total_allocated += alloc_size;
+ free_memory_pool(gc->constant_string_pool);
+ free_memory_pool(gc->memory_pool);
}
/*
-=item C<void * mem_allocate(PARROT_INTERP, Memory_Pools *mem_pools, size_t size,
-Variable_Size_Pool *pool)>
-
-Allocates memory for headers.
-
-Alignment problems history:
-
-See L<http://archive.develooper.com/perl6-internals%40perl.org/msg12310.html>
-for details.
+=item C<void Parrot_gc_str_alloc_new_block( Memory_Pools *mem_pools, size_t
+size, Variable_Size_Pool *pool, const char *why)>
-- return aligned pointer *if needed*
-- return strings et al at unaligned i.e. void* boundaries
-- remember alignment in a buffer header bit
- use this in compaction code
-- reduce alignment to a reasonable value i.e. MALLOC_ALIGNMENT
- aka 2*sizeof (size_t) or just 8 (TODO make a config hint)
-
-See pobj.h for a discussion of the Buffer descriptor and the buffer itself,
-including its header.
+Allocate a new string block
=cut
*/
-PARROT_MALLOC
-PARROT_CANNOT_RETURN_NULL
-void *
-mem_allocate(PARROT_INTERP,
+void
+Parrot_gc_str_alloc_new_block(
ARGMOD(Memory_Pools *mem_pools),
size_t size,
- ARGMOD(Variable_Size_Pool *pool))
+ ARGMOD(Variable_Size_Pool *pool),
+ ARGIN(const char *why))
{
- ASSERT_ARGS(mem_allocate)
- void *return_val;
+ ASSERT_ARGS(Parrot_gc_str_alloc_new_block)
- /* we always should have one block at least */
- PARROT_ASSERT(pool->top_block);
+ alloc_new_block(mem_pools, size, pool, why);
+}
- /* If not enough room, try to find some */
- if (pool->top_block->free < size) {
- /*
- * force a GC mark run to get live flags set
- * for incremental M&S collection is run from there
- * but only if there may be something worth collecting!
- * TODO pass required allocation size to the GC system,
- * so that collection can be skipped if needed
- */
- size_t new_mem = mem_pools->memory_used -
- mem_pools->mem_used_last_collect;
- if (!mem_pools->gc_mark_block_level
- && new_mem > (mem_pools->mem_used_last_collect >> 2)
- && new_mem > GC_SIZE_THRESHOLD) {
- Parrot_gc_mark_and_sweep(interp, GC_trace_stack_FLAG);
+/*
- if (interp->gc_sys->sys_type != INF) {
- /* Compact the pool if allowed and worthwhile */
- if (pool->compact) {
- /* don't bother reclaiming if it's only a small amount */
- if ((pool->possibly_reclaimable * pool->reclaim_factor +
- pool->guaranteed_reclaimable) > size) {
- (*pool->compact) (interp, mem_pools, pool);
- }
- }
- }
- }
- if (pool->top_block->free < size) {
- if (pool->minimum_block_size < 65536 * 16)
- pool->minimum_block_size *= 2;
- /*
- * TODO - Big blocks
- *
- * Mark the block as big block (it has just one item)
- * And don't set big blocks as the top_block.
- */
- alloc_new_block(mem_pools, size, pool, "compact failed");
+=item C<void Parrot_gc_str_allocate_buffer_storage(PARROT_INTERP, String_GC *gc,
+Buffer *buffer, size_t size)>
- ++mem_pools->mem_allocs_since_last_collect;
+Allocates a chunk of memory of at least size C<size> for the given Buffer.
+buffer is guaranteed to be properly aligned for things like C<FLOATVALS>,
+so the size may be rounded up or down to guarantee that this alignment holds.
- if (pool->top_block->free < size) {
- fprintf(stderr, "out of mem\n");
- exit(EXIT_FAILURE);
- }
- }
- }
+=cut
- /* TODO inline the fast path */
- return_val = pool->top_block->top;
- pool->top_block->top += size;
- pool->top_block->free -= size;
- mem_pools->memory_used += size;
+*/
- return return_val;
+void
+Parrot_gc_str_allocate_buffer_storage(PARROT_INTERP,
+ ARGIN(String_GC *gc),
+ ARGOUT(Buffer *buffer),
+ size_t size)
+{
+ ASSERT_ARGS(Parrot_gc_str_allocate_buffer_storage)
+ const size_t new_size = ALIGNED_STRING_SIZE(size);
+
+ Buffer_bufstart(buffer) = (void *)aligned_mem(buffer,
+ (char *)mem_allocate(interp,
+ interp->mem_pools, new_size, gc->memory_pool));
+
+ /* Save pool used to allocate into buffer header */
+ *Buffer_poolptr(buffer) = gc->memory_pool->top_block;
+
+ Buffer_buflen(buffer) = new_size - sizeof (void *);
}
/*
-=item C<static const char * buffer_location(PARROT_INTERP, const Buffer *b)>
+=item C<void Parrot_gc_str_reallocate_buffer_storage(PARROT_INTERP, String_GC
+*gc, Buffer *buffer, size_t newsize)>
-Recturns a constant string representing the location of the given
-Buffer C<b> in one of the PMC registers. If the PMC is not located
-in one of the PMC registers of the current context, returns the
-string C<"???">.
+Reallocate the Buffer's buffer memory to the given size. The
+allocated buffer will not shrink. If the buffer was allocated with
+L<Parrot_allocate_aligned> the new buffer will also be aligned. As with
+all reallocation, the new buffer might have moved and the additional
+memory is not cleared.
=cut
*/
-#if RESOURCE_DEBUG
-PARROT_CANNOT_RETURN_NULL
-PARROT_WARN_UNUSED_RESULT
-static const char *
-buffer_location(PARROT_INTERP, ARGIN(const Buffer *b))
-{
- ASSERT_ARGS(buffer_location)
- Parrot_Context * const ctx = CONTEXT(interp);
- static char reg[10];
- UINTVAL i;
+void
+Parrot_gc_str_reallocate_buffer_storage(PARROT_INTERP,
+ ARGIN(String_GC *gc),
+ ARGMOD(Buffer *buffer),
+ size_t newsize)
+{
+ ASSERT_ARGS(Parrot_gc_str_reallocate_buffer_storage)
+ size_t copysize;
+ char *mem;
+ Variable_Size_Pool * const pool = gc->memory_pool;
+ size_t new_size, needed, old_size;
- for (i = 0; i < ctx->n_regs_used[REGNO_STR]; ++i) {
- PObj * const obj = (PObj *)Parrot_pcc_get_STRING_reg(interp, ctx, i);
- if ((PObj *)obj == b) {
- sprintf(reg, "S%d", (int)i);
- return reg;
- }
+ /* we don't shrink buffers */
+ if (newsize <= Buffer_buflen(buffer))
+ return;
+
+ /*
+ * same as below but barely used and tested - only 3 list related
+ * tests do use true reallocation
+ *
+ * list.c, which does _reallocate, has 2 reallocations
+ * normally, which play ping pong with buffers.
+ * The normal case is therefore always to allocate a new block
+ */
+ new_size = ALIGNED_STRING_SIZE(newsize);
+ old_size = ALIGNED_STRING_SIZE(Buffer_buflen(buffer));
+ needed = new_size - old_size;
+
+ if ((pool->top_block->free >= needed)
+ && (pool->top_block->top == (char *)Buffer_bufstart(buffer) + old_size)) {
+ pool->top_block->free -= needed;
+ pool->top_block->top += needed;
+ interp->mem_pools->memory_used += needed;
+ Buffer_buflen(buffer) = newsize;
+ return;
}
- return "???";
-}
+ copysize = Buffer_buflen(buffer);
-/*
+ mem = (char *)mem_allocate(interp, interp->mem_pools, new_size, pool);
+ mem = aligned_mem(buffer, mem);
-=item C<static void debug_print_buf(PARROT_INTERP, const Buffer *b)>
+ /* We shouldn't ever have a 0 from size, but we do. If we can track down
+ * those bugs, this can be removed which would make things cheaper */
+ if (copysize)
+ memcpy(mem, Buffer_bufstart(buffer), copysize);
-Prints a debug statement with information about the given PObj C<b>.
-=cut
+ Buffer_bufstart(buffer) = mem;
-*/
+ new_size -= sizeof (void *);
-static void
-debug_print_buf(PARROT_INTERP, ARGIN(const Buffer *b))
-{
- ASSERT_ARGS(debug_print_buf)
- fprintf(stderr, "found %p, len %d, flags 0x%08x at %s\n",
- b, (int)Buffer_buflen(b), (uint)PObj_get_FLAGS(b),
- buffer_location(interp, b));
+ Buffer_buflen(buffer) = new_size;
+
+ /* Save pool used to allocate into buffer header */
+ *Buffer_poolptr(buffer) = gc->memory_pool->top_block;
}
-#endif
/*
-=back
+=item C<void Parrot_gc_str_allocate_string_storage(PARROT_INTERP, String_GC *gc,
+STRING *str, size_t size)>
-=head2 Compaction Code
-
-=over 4
-
-=item C<void compact_pool(PARROT_INTERP, Memory_Pools *mem_pools,
-Variable_Size_Pool *pool)>
-
-Compact the string buffer pool. Does not perform a GC scan, or mark items
-as being alive in any way.
+Allocate the STRING's buffer memory to the given size. The allocated
+buffer maybe slightly bigger than the given C<size>. This function
+sets also C<< str->strstart >> to the new buffer location, C<< str->bufused >>
+is B<not> changed.
=cut
*/
void
-compact_pool(PARROT_INTERP,
- ARGMOD(Memory_Pools *mem_pools),
- ARGMOD(Variable_Size_Pool *pool))
-{
- ASSERT_ARGS(compact_pool)
- INTVAL j;
- UINTVAL total_size;
-
- Fixed_Size_Arena *cur_buffer_arena;
-
- /* Contains new_block and cur_spot */
- string_callback_data cb_data;
-
-
- /* Bail if we're blocked */
- if (mem_pools->gc_sweep_block_level)
- return;
-
- ++mem_pools->gc_sweep_block_level;
-
- /* We're collecting */
- mem_pools->mem_allocs_since_last_collect = 0;
- mem_pools->header_allocs_since_last_collect = 0;
- ++mem_pools->gc_collect_runs;
+Parrot_gc_str_allocate_string_storage(PARROT_INTERP,
+ ARGIN(String_GC *gc),
+ ARGOUT(STRING *str),
+ size_t size)
+{
+ ASSERT_ARGS(Parrot_gc_str_allocate_string_storage)
+ size_t new_size;
+ Variable_Size_Pool *pool;
+ char *mem;
- /* Snag a block big enough for everything */
- total_size = pad_pool_size(pool);
+ Buffer_buflen(str) = 0;
+ Buffer_bufstart(str) = NULL;
- if (total_size == 0) {
- free_old_mem_blocks(mem_pools, pool, pool->top_block, total_size);
- --mem_pools->gc_sweep_block_level;
+ if (size == 0)
return;
- }
- alloc_new_block(mem_pools, total_size, pool, "inside compact");
+ pool = PObj_constant_TEST(str)
+ ? gc->constant_string_pool
+ : gc->memory_pool;
- cb_data.new_block = pool->top_block;
+ new_size = ALIGNED_STRING_SIZE(size);
+ mem = (char *)mem_allocate(interp, interp->mem_pools, new_size, pool);
+ mem += sizeof (void *);
- /* Start at the beginning */
- cb_data.cur_spot = cb_data.new_block->start;
+ Buffer_bufstart(str) = str->strstart = mem;
+ Buffer_buflen(str) = new_size - sizeof (void *);
- /* Run through all the Buffer header pools and copy */
- interp->gc_sys->iterate_live_strings(interp, move_buffer_callback, &cb_data);
-
- /* Okay, we're done with the copy. Set the bits in the pool struct */
- /* First, where we allocate next */
- cb_data.new_block->top = cb_data.cur_spot;
-
- PARROT_ASSERT(cb_data.new_block->size
- >=
- (size_t)cb_data.new_block->top - (size_t)cb_data.new_block->start);
-
- /* How much is free. That's the total size minus the amount we used */
- cb_data.new_block->free = cb_data.new_block->size
- - (cb_data.cur_spot - cb_data.new_block->start);
- mem_pools->memory_collected += (cb_data.cur_spot - cb_data.new_block->start);
- mem_pools->memory_used += (cb_data.cur_spot - cb_data.new_block->start);
-
- free_old_mem_blocks(mem_pools, pool, cb_data.new_block, total_size);
-
- --mem_pools->gc_sweep_block_level;
+ /* Save pool used to allocate into buffer header */
+ *Buffer_poolptr(str) = pool->top_block;
}
/*
-=item C<static void move_buffer_callback(PARROT_INTERP, Buffer *b, void *data)>
-Callback for live STRING/Buffer for compating.
+=item C<void Parrot_gc_str_reallocate_string_storage(PARROT_INTERP, String_GC
+*gc, STRING *str, size_t newsize)>
-=cut
-*/
-static void
-move_buffer_callback(PARROT_INTERP, ARGIN(Buffer *b), ARGIN(void *data))
-{
- ASSERT_ARGS(move_buffer_callback)
- string_callback_data *cb = (string_callback_data*)data;
-
- if (Buffer_buflen(b) && PObj_is_movable_TESTALL(b)) {
- Memory_Block *old_block = Buffer_pool(b);
-
- if (!is_block_almost_full(old_block))
- cb->cur_spot = move_one_buffer(interp, cb->new_block, b, cb->cur_spot);
- }
-
-}
-
-/*
-
-=item C<static UINTVAL pad_pool_size(const Variable_Size_Pool *pool)>
+Reallocate the STRING's buffer memory to the given size. The allocated
+buffer will not shrink. This function sets also C<str-E<gt>strstart> to the
+new buffer location, C<str-E<gt>bufused> is B<not> changed.
-Calculate the size of the new pool. The currently used size equals the total
-size minus the reclaimable size. Add a minimum block to the current amount, so
-we can avoid having to allocate it in the future.
-
-Returns 0 if all blocks below the top block are almost full. In this case
-compacting is not needed.
-
-TODO - Big blocks
+=cut
-Currently all available blocks are compacted into one new
-block with total_size. This is suboptimal, if the block has
-just one live item from a big allocation.
+*/
-But currently it's unknown if the buffer memory is alive
-as the live bits are in Buffer headers. We have to run the
-compaction loop to check liveness. OTOH if this compaction
-is running through all the buffer headers, there is no
-relation to the block.
+void
+Parrot_gc_str_reallocate_string_storage(PARROT_INTERP,
+ ARGIN(String_GC *gc),
+ ARGMOD(STRING *str),
+ size_t newsize)
+{
+ ASSERT_ARGS(Parrot_gc_str_reallocate_string_storage)
+ size_t copysize;
+ char *mem, *oldmem;
+ size_t new_size, needed, old_size;
+
+ Variable_Size_Pool * const pool =
+ PObj_constant_TEST(str)
+ ? gc->constant_string_pool
+ : gc->memory_pool;
-Moving the live bit into the buffer thus also solves this
-problem easily.
+ /* if the requested size is smaller then buflen, we are done */
+ if (newsize <= Buffer_buflen(str))
+ return;
-=cut
+ /*
+ * first check, if we can reallocate:
+ * - if the passed strings buffer is the last string in the pool and
+ * - if there is enough size, we can just move the pool's top pointer
+ */
+ new_size = ALIGNED_STRING_SIZE(newsize);
+ old_size = ALIGNED_STRING_SIZE(Buffer_buflen(str));
+ needed = new_size - old_size;
+
+ if (pool->top_block->free >= needed
+ && pool->top_block->top == (char *)Buffer_bufstart(str) + old_size) {
+ pool->top_block->free -= needed;
+ pool->top_block->top += needed;
+ interp->mem_pools->memory_used += needed;
+ Buffer_buflen(str) = new_size - sizeof (void *);
+ return;
+ }
-*/
+ PARROT_ASSERT(str->bufused <= newsize);
-PARROT_CANNOT_RETURN_NULL
-static UINTVAL
-pad_pool_size(ARGIN(const Variable_Size_Pool *pool))
-{
- ASSERT_ARGS(pad_pool_size)
- Memory_Block *cur_block = pool->top_block->prev;
+ /* only copy used memory, not total string buffer */
+ copysize = str->bufused;
- UINTVAL total_size = 0;
-#if RESOURCE_DEBUG
- size_t total_blocks = 1;
-#endif
+ mem = (char *)mem_allocate(interp, interp->mem_pools, new_size, pool);
+ mem += sizeof (void *);
- while (cur_block) {
- if (!is_block_almost_full(cur_block))
- total_size += cur_block->size - cur_block->freed - cur_block->free;
- cur_block = cur_block->prev;
-#if RESOURCE_DEBUG
- ++total_blocks;
-#endif
- }
+ /* Update Memory_Block usage */
+ /* We must not reallocate non-movable buffers! */
+ PARROT_ASSERT(PObj_is_movable_TESTALL(str));
- if (total_size == 0)
- return 0;
+ /* We must not reallocate shared buffers! */
+ PARROT_ASSERT(!(*Buffer_bufflagsptr(str) & Buffer_shared_FLAG));
- cur_block = pool->top_block;
- if (!is_block_almost_full(cur_block))
- total_size += cur_block->size - cur_block->freed - cur_block->free;
+ /* Decrease usage */
+ PARROT_ASSERT(Buffer_pool(str));
+ Buffer_pool(str)->freed += old_size;
- /* this makes for ever increasing allocations but fewer collect runs */
-#if WE_WANT_EVER_GROWING_ALLOCATIONS
- total_size += pool->minimum_block_size;
-#endif
+ /* copy mem from strstart, *not* bufstart */
+ oldmem = str->strstart;
+ Buffer_bufstart(str) = (void *)mem;
+ str->strstart = mem;
+ Buffer_buflen(str) = new_size - sizeof (void *);
-#if RESOURCE_DEBUG
- fprintf(stderr, "Total blocks: %d\n", total_blocks);
-#endif
+ /* We shouldn't ever have a 0 from size, but we do. If we can track down
+ * those bugs, this can be removed which would make things cheaper */
+ if (copysize)
+ memcpy(mem, oldmem, copysize);
- return total_size;
+ /* Save pool used to allocate into buffer header */
+ *Buffer_poolptr(str) = pool->top_block;
}
/*
+=item C<void Parrot_gc_str_compact_pool(PARROT_INTERP, String_GC *gc)>
-=item C<static char * move_one_buffer(PARROT_INTERP, Memory_Block *pool, Buffer
-*old_buf, char *new_pool_ptr)>
-
-The compact_pool operation collects disjointed blocks of memory allocated on a
-given pool's free list into one large block of memory. Once the new larger
-memory block has been allocated, this function moves one buffer from the old
-memory block to the new memory block and marks that it has been moved.
+Compact string pool.
=cut
-
*/
-
-PARROT_WARN_UNUSED_RESULT
-PARROT_CANNOT_RETURN_NULL
-static char *
-move_one_buffer(PARROT_INTERP, ARGIN(Memory_Block *pool),
- ARGMOD(Buffer *old_buf), ARGMOD(char *new_pool_ptr))
+void
+Parrot_gc_str_compact_pool(PARROT_INTERP, ARGIN(String_GC *gc))
{
- ASSERT_ARGS(move_one_buffer)
-
- INTVAL *flags = NULL;
- ptrdiff_t offset = 0;
- Memory_Block *old_block = NULL;
-#if RESOURCE_DEBUG
- if (Buffer_buflen(old_buf) >= RESOURCE_DEBUG_SIZE)
- debug_print_buf(interp, old_buf);
-#else
- UNUSED(interp);
-#endif
-
- /* we can't perform the math all the time, because
- * strstart might be in unallocated memory */
- if (PObj_is_COWable_TEST(old_buf)) {
- flags = Buffer_bufflagsptr(old_buf);
- old_block = Buffer_pool(old_buf);
-
- if (PObj_is_string_TEST(old_buf)) {
- offset = (ptrdiff_t)((STRING *)old_buf)->strstart -
- (ptrdiff_t)Buffer_bufstart(old_buf);
- }
- }
-
- /* buffer has already been moved; just change the header */
- if (flags && (*flags & Buffer_shared_FLAG)
- && (*flags & Buffer_moved_FLAG)) {
- /* Find out who else references our data */
- Buffer * const hdr = *((Buffer **)Buffer_bufstart(old_buf));
-
- PARROT_ASSERT(PObj_is_COWable_TEST(old_buf));
-
- /* Make sure they know that we own it too */
- /* Set Buffer_shared_FLAG in new buffer */
- *Buffer_bufflagsptr(hdr) |= Buffer_shared_FLAG;
-
- /* Now make sure we point to where the other guy does */
- Buffer_bufstart(old_buf) = Buffer_bufstart(hdr);
-
- /* And if we're a string, update strstart */
- /* Somewhat of a hack, but if we get per-pool
- * collections, it should help ease the pain */
- if (PObj_is_string_TEST(old_buf))
- ((STRING *)old_buf)->strstart =
- (char *)Buffer_bufstart(old_buf) + offset;
- }
- else {
- new_pool_ptr = aligned_mem(old_buf, new_pool_ptr);
-
- /* Copy our memory to the new pool */
- memcpy(new_pool_ptr, Buffer_bufstart(old_buf),
- Buffer_buflen(old_buf));
-
- /* If we're shared */
- if (flags && (*flags & Buffer_shared_FLAG)) {
- PARROT_ASSERT(PObj_is_COWable_TEST(old_buf));
-
- /* Let the old buffer know how to find us */
- *((Buffer **)Buffer_bufstart(old_buf)) = old_buf;
-
- /* Finally, let the tail know that we've moved, so
- * that any other references can know to look for
- * us and not re-copy */
- *flags |= Buffer_moved_FLAG;
- }
-
- Buffer_bufstart(old_buf) = new_pool_ptr;
-
- /* Remember new pool inside */
- *Buffer_poolptr(old_buf) = pool;
-
- if (PObj_is_string_TEST(old_buf))
- ((STRING *)old_buf)->strstart =
- (char *)Buffer_bufstart(old_buf) + offset;
-
- new_pool_ptr += Buffer_buflen(old_buf);
- }
-
- return new_pool_ptr;
+ ASSERT_ARGS(Parrot_gc_str_compact_pool)
+ compact_pool(interp, interp->mem_pools, gc->memory_pool);
}
/*
-=item C<static void free_old_mem_blocks( Memory_Pools *mem_pools,
-Variable_Size_Pool *pool, Memory_Block *new_block, UINTVAL total_size)>
+=item C<void Parrot_gc_str_free_buffer_storage(PARROT_INTERP, String_GC *gc,
+Buffer *b)>
-The compact_pool operation collects disjointed blocks of memory allocated on a
-given pool's free list into one large block of memory, setting it as the new
-top block for the pool. Once that is done, and all items have been moved into
-the new block of memory, this function iterates through the old blocks and
-frees each one. It also performs the necessary housekeeping to record the
-freed memory blocks. At the end of this function, the pool will have only one
-block of memory on its free list.
+Frees a buffer, returning it to the memory pool for Parrot to possibly
+reuse later.
=cut
*/
-static void
-free_old_mem_blocks(
- ARGMOD(Memory_Pools *mem_pools),
- ARGMOD(Variable_Size_Pool *pool),
- ARGMOD(Memory_Block *new_block),
- UINTVAL total_size)
+void
+Parrot_gc_str_free_buffer_storage(SHIM_INTERP,
+ ARGIN(String_GC *gc),
+ ARGMOD(Buffer *b))
{
- ASSERT_ARGS(free_old_mem_blocks)
- Memory_Block *prev_block = new_block;
- Memory_Block *cur_block = new_block->prev;
-
- PARROT_ASSERT(new_block == pool->top_block);
+ ASSERT_ARGS(Parrot_gc_str_free_buffer_storage)
+ Variable_Size_Pool * const mem_pool = gc->memory_pool;
- while (cur_block) {
- Memory_Block * const next_block = cur_block->prev;
-
- if (is_block_almost_full(cur_block)) {
- /* Skip block */
- prev_block = cur_block;
- cur_block = next_block;
- }
- else {
- /* Note that we don't have it any more */
- mem_pools->memory_allocated -= cur_block->size;
- mem_pools->memory_used -= cur_block->size - cur_block->free;
+ /* If there is no allocated buffer - bail out */
+ if (!Buffer_buflen(b))
+ return;
- /* We know the pool body and pool header are a single chunk, so
- * this is enough to get rid of 'em both */
- mem_internal_free(cur_block);
- cur_block = next_block;
+ if (mem_pool) {
+ /* Update Memory_Block usage */
+ if (PObj_is_movable_TESTALL(b)) {
+ INTVAL *buffer_flags = Buffer_bufflagsptr(b);
+
+ /* Mask low 2 bits used for flags */
+ Memory_Block * block = Buffer_pool(b);
+
+ PARROT_ASSERT(block);
+
+ /* We can have shared buffers. Don't count them (yet) */
+ if (!(*buffer_flags & Buffer_shared_FLAG)) {
+ block->freed += ALIGNED_STRING_SIZE(Buffer_buflen(b));
+ }
- /* Unlink it from list */
- prev_block->prev = next_block;
}
}
- /* Terminate list */
- prev_block->prev = NULL;
-
-
- /* ANR: I suspect this should be set to new_block->size, instead of passing
- * in the raw value of total_size, because alloc_new_block pads the size of
- * the new block under certain conditions. Leaving it unmodified for now,
- * so this refactor has no functionality changes, only code cleanups.*/
- pool->total_allocated = total_size;
- pool->guaranteed_reclaimable = 0;
- pool->possibly_reclaimable = 0;
+ Buffer_buflen(b) = 0;
}
/*
+=item C<static Variable_Size_Pool * new_memory_pool(size_t min_block, compact_f
+compact)>
-=item C<static int is_block_almost_full(const Memory_Block *block)>
-
-Tests if the block is almost full and should be skipped during compacting.
-
-Returns true if less that 20% of block is available
-
-=cut
-
-*/
-
-static int
-is_block_almost_full(ARGIN(const Memory_Block *block))
-{
- ASSERT_ARGS(is_block_almost_full)
- return 5 * (block->free + block->freed) < block->size;
-}
-
-/*
-
-=item C<char * aligned_mem(const Buffer *buffer, char *mem)>
-
-Returns a pointer to the aligned allocated storage for Buffer C<buffer>,
-which might not be the same as the pointer to C<buffer> because of
-memory alignment.
+Allocate a new C<Variable_Size_Pool> structures, and set some initial values.
+return a pointer to the new pool.
=cut
*/
-PARROT_CANNOT_RETURN_NULL
PARROT_WARN_UNUSED_RESULT
-char *
-aligned_mem(SHIM(const Buffer *buffer), ARGIN(char *mem))
+PARROT_MALLOC
+PARROT_CANNOT_RETURN_NULL
+static Variable_Size_Pool *
+new_memory_pool(size_t min_block, NULLOK(compact_f compact))
{
- ASSERT_ARGS(aligned_mem)
- mem += sizeof (void *);
- mem = (char *)(((unsigned long)(mem + WORD_ALIGN_1)) & WORD_ALIGN_MASK);
+ ASSERT_ARGS(new_memory_pool)
+ Variable_Size_Pool * const pool = mem_internal_allocate_typed(Variable_Size_Pool);
- return mem;
+ pool->top_block = NULL;
+ pool->compact = compact;
+ pool->minimum_block_size = min_block;
+ pool->total_allocated = 0;
+ pool->guaranteed_reclaimable = 0;
+ pool->possibly_reclaimable = 0;
+ pool->reclaim_factor = RECLAMATION_FACTOR;
+
+ return pool;
}
/*
-=back
-
-=head2 Parrot Re/Allocate Code
-
-=over 4
-
-=item C<static Variable_Size_Pool * new_memory_pool(size_t min_block, compact_f
-compact)>
+=item C<static void alloc_new_block( Memory_Pools *mem_pools, size_t size,
+Variable_Size_Pool *pool, const char *why)>
-Allocate a new C<Variable_Size_Pool> structures, and set some initial values.
-return a pointer to the new pool.
+Allocate a new memory block. We allocate either the requested size or the
+default size, whichever is larger. Add the new block to the given memory
+pool. The given C<char *why> text is used for debugging.
=cut
*/
-PARROT_WARN_UNUSED_RESULT
-PARROT_MALLOC
-PARROT_CANNOT_RETURN_NULL
-static Variable_Size_Pool *
-new_memory_pool(size_t min_block, NULLOK(compact_f compact))
+static void
+alloc_new_block(
+ ARGMOD(Memory_Pools *mem_pools),
+ size_t size,
+ ARGMOD(Variable_Size_Pool *pool),
+ ARGIN(const char *why))
{
- ASSERT_ARGS(new_memory_pool)
- Variable_Size_Pool * const pool = mem_internal_allocate_typed(Variable_Size_Pool);
+ ASSERT_ARGS(alloc_new_block)
+ Memory_Block *new_block;
- pool->top_block = NULL;
- pool->compact = compact;
- pool->minimum_block_size = min_block;
- pool->total_allocated = 0;
- pool->guaranteed_reclaimable = 0;
- pool->possibly_reclaimable = 0;
- pool->reclaim_factor = RECLAMATION_FACTOR;
+ const size_t alloc_size = (size > pool->minimum_block_size)
+ ? size : pool->minimum_block_size;
- return pool;
-}
+#if RESOURCE_DEBUG
+ fprintf(stderr, "new_block (%s) size %u -> %u\n",
+ why, size, alloc_size);
+#else
+ UNUSED(why)
+#endif
-/*
+ /* Allocate a new block. Header info's on the front */
+ new_block = (Memory_Block *)mem_internal_allocate_zeroed(
+ sizeof (Memory_Block) + alloc_size);
-=item C<void initialize_var_size_pools(PARROT_INTERP, Memory_Pools *mem_pools)>
+ if (!new_block) {
+ fprintf(stderr, "out of mem allocsize = %d\n", (int)alloc_size);
+ exit(EXIT_FAILURE);
+ }
-Initialize the managed memory pools. Parrot maintains two C<Variable_Size_Pool>
-structures, the general memory pool and the constant string pool. Create
-and initialize both pool structures, and allocate initial blocks of memory
-for both.
+ new_block->free = alloc_size;
+ new_block->size = alloc_size;
-=cut
+ new_block->next = NULL;
+ new_block->start = (char *)new_block + sizeof (Memory_Block);
+ new_block->top = new_block->start;
-*/
+ /* Note that we've allocated it */
+ mem_pools->memory_allocated += alloc_size;
-void
-initialize_var_size_pools(SHIM_INTERP, ARGMOD(Memory_Pools *mem_pools))
-{
- ASSERT_ARGS(initialize_var_size_pools)
+ /* If this is for a public pool, add it to the list */
+ new_block->prev = pool->top_block;
- mem_pools->memory_pool = new_memory_pool(POOL_SIZE, &compact_pool);
- alloc_new_block(mem_pools, POOL_SIZE, mem_pools->memory_pool, "init");
+ /* If we're not first, then tack us on the list */
+ if (pool->top_block)
+ pool->top_block->next = new_block;
- /* Constant strings - not compacted */
- mem_pools->constant_string_pool = new_memory_pool(POOL_SIZE, NULL);
- alloc_new_block(mem_pools, POOL_SIZE, mem_pools->constant_string_pool, "init");
+ pool->top_block = new_block;
+ pool->total_allocated += alloc_size;
}
-
/*
-=item C<void merge_pools(Variable_Size_Pool *dest, Variable_Size_Pool *source)>
+=item C<static void * mem_allocate(PARROT_INTERP, Memory_Pools *mem_pools,
+size_t size, Variable_Size_Pool *pool)>
+
+Allocates memory for headers.
+
+Alignment problems history:
+
+See L<http://archive.develooper.com/perl6-internals%40perl.org/msg12310.html>
+for details.
+
+- return aligned pointer *if needed*
+- return strings et al at unaligned i.e. void* boundaries
+- remember alignment in a buffer header bit
+ use this in compaction code
+- reduce alignment to a reasonable value i.e. MALLOC_ALIGNMENT
+ aka 2*sizeof (size_t) or just 8 (TODO make a config hint)
-Merge two memory pools together. Do this by moving all memory blocks
-from the C<*source> pool into the C<*dest> pool. The C<source> pool
-is emptied, but is not destroyed here.
+See pobj.h for a discussion of the Buffer descriptor and the buffer itself,
+including its header.
=cut
*/
-void
-merge_pools(ARGMOD(Variable_Size_Pool *dest), ARGMOD(Variable_Size_Pool *source))
+PARROT_MALLOC
+PARROT_CANNOT_RETURN_NULL
+static void *
+mem_allocate(PARROT_INTERP,
+ ARGMOD(Memory_Pools *mem_pools),
+ size_t size,
+ ARGMOD(Variable_Size_Pool *pool))
{
- ASSERT_ARGS(merge_pools)
- Memory_Block *cur_block;
+ ASSERT_ARGS(mem_allocate)
+ void *return_val;
- cur_block = source->top_block;
+ /* we always should have one block at least */
+ PARROT_ASSERT(pool->top_block);
- while (cur_block) {
- Memory_Block * const next_block = cur_block->prev;
+ /* If not enough room, try to find some */
+ if (pool->top_block->free < size) {
+ /*
+ * force a GC mark run to get live flags set
+ * for incremental M&S collection is run from there
+ * but only if there may be something worth collecting!
+ * TODO pass required allocation size to the GC system,
+ * so that collection can be skipped if needed
+ */
+ size_t new_mem = mem_pools->memory_used -
+ mem_pools->mem_used_last_collect;
+ if (!mem_pools->gc_mark_block_level
+ && new_mem > (mem_pools->mem_used_last_collect >> 2)
+ && new_mem > GC_SIZE_THRESHOLD) {
+ Parrot_gc_mark_and_sweep(interp, GC_trace_stack_FLAG);
- if (cur_block->free == cur_block->size)
- mem_internal_free(cur_block);
- else {
- cur_block->next = NULL;
- cur_block->prev = dest->top_block;
+ if (interp->gc_sys->sys_type != INF) {
+ /* Compact the pool if allowed and worthwhile */
+ if (pool->compact) {
+ /* don't bother reclaiming if it's only a small amount */
+ if ((pool->possibly_reclaimable * pool->reclaim_factor +
+ pool->guaranteed_reclaimable) > size) {
+ (*pool->compact) (interp, mem_pools, pool);
+ }
+ }
+ }
+ }
+ if (pool->top_block->free < size) {
+ if (pool->minimum_block_size < 65536 * 16)
+ pool->minimum_block_size *= 2;
+ /*
+ * TODO - Big blocks
+ *
+ * Mark the block as big block (it has just one item)
+ * And don't set big blocks as the top_block.
+ */
+ Parrot_gc_str_alloc_new_block(mem_pools, size, pool, "compact failed");
+
+ ++mem_pools->mem_allocs_since_last_collect;
- dest->top_block = cur_block;
- dest->total_allocated += cur_block->size;
+ if (pool->top_block->free < size) {
+ fprintf(stderr, "out of mem\n");
+ exit(EXIT_FAILURE);
+ }
}
- cur_block = next_block;
}
- dest->guaranteed_reclaimable += source->guaranteed_reclaimable;
- dest->possibly_reclaimable += source->possibly_reclaimable;
+ /* TODO inline the fast path */
+ return_val = pool->top_block->top;
+ pool->top_block->top += size;
+ pool->top_block->free -= size;
+ mem_pools->memory_used += size;
- source->top_block = NULL;
- source->total_allocated = 0;
- source->possibly_reclaimable = 0;
- source->guaranteed_reclaimable = 0;
+ return return_val;
}
/*
-=item C<static void check_memory_system(const Memory_Pools *mem_pools)>
+=item C<static char * aligned_mem(const Buffer *buffer, char *mem)>
-Checks the memory system of parrot on any corruptions, including
-the string system.
+Returns a pointer to the aligned allocated storage for Buffer C<buffer>,
+which might not be the same as the pointer to C<buffer> because of
+memory alignment.
=cut
*/
-static void
-check_memory_system(ARGIN(const Memory_Pools *mem_pools))
+PARROT_CANNOT_RETURN_NULL
+PARROT_WARN_UNUSED_RESULT
+static char *
+aligned_mem(SHIM(const Buffer *buffer), ARGIN(char *mem))
{
- ASSERT_ARGS(check_memory_system)
- size_t i;
+ ASSERT_ARGS(aligned_mem)
+ mem += sizeof (void *);
+ mem = (char *)(((unsigned long)(mem + WORD_ALIGN_1)) & WORD_ALIGN_MASK);
- check_var_size_obj_pool(mem_pools->memory_pool);
- check_var_size_obj_pool(mem_pools->constant_string_pool);
- check_fixed_size_obj_pool(mem_pools->pmc_pool);
- check_fixed_size_obj_pool(mem_pools->constant_pmc_pool);
- check_fixed_size_obj_pool(mem_pools->string_header_pool);
- check_fixed_size_obj_pool(mem_pools->constant_string_header_pool);
-
- for (i = 0; i < mem_pools->num_sized; ++i) {
- const Fixed_Size_Pool * const pool = mem_pools->sized_header_pools[i];
- if (pool != NULL && pool != mem_pools->string_header_pool)
- check_fixed_size_obj_pool(pool);
- }
+ return mem;
}
/*
-=item C<static void check_fixed_size_obj_pool(const Fixed_Size_Pool *pool)>
+=item C<static const char * buffer_location(PARROT_INTERP, const Buffer *b)>
-Checks a small object pool, if it contains buffer it checks the buffers also.
+Recturns a constant string representing the location of the given
+Buffer C<b> in one of the PMC registers. If the PMC is not located
+in one of the PMC registers of the current context, returns the
+string C<"???">.
=cut
*/
-static void
-check_fixed_size_obj_pool(ARGIN(const Fixed_Size_Pool *pool))
+#if RESOURCE_DEBUG
+PARROT_CANNOT_RETURN_NULL
+PARROT_WARN_UNUSED_RESULT
+static const char *
+buffer_location(PARROT_INTERP, ARGIN(const Buffer *b))
{
- ASSERT_ARGS(check_fixed_size_obj_pool)
- size_t total_objects;
- size_t last_free_list_count;
- Fixed_Size_Arena * arena_walker;
- size_t free_objects;
- size_t count;
- GC_MS_PObj_Wrapper * pobj_walker;
-
- count = 10000000; /*detect unendless loop just use big enough number*/
-
- total_objects = pool->total_objects;
- last_free_list_count = 1;
- free_objects = 0;
-
- arena_walker = pool->last_Arena;
- while (arena_walker != NULL) {
- size_t i;
- PObj * object;
-
- total_objects -= arena_walker->total_objects;
- object = (PObj*)arena_walker->start_objects;
-
- for (i = 0; i < arena_walker->total_objects; ++i) {
- if (PObj_on_free_list_TEST(object)) {
- ++free_objects;
- pobj_walker = (GC_MS_PObj_Wrapper*)object;
- if (pobj_walker->next_ptr == NULL)
- /* should happen only once at the end */
- --last_free_list_count;
- else {
- /* next item on free list should also be flaged as free item */
- pobj_walker = (GC_MS_PObj_Wrapper*)pobj_walker->next_ptr;
- PARROT_ASSERT(PObj_on_free_list_TEST((PObj*)pobj_walker));
- }
- }
- else if (pool->mem_pool != NULL) {
- /*then it means we are a buffer*/
- check_buffer_ptr((Buffer*)object, pool->mem_pool);
- }
- object = (PObj*)((char *)object + pool->object_size);
- PARROT_ASSERT(--count);
- }
- /*check the list*/
- if (arena_walker->prev != NULL)
- PARROT_ASSERT(arena_walker->prev->next == arena_walker);
- arena_walker = arena_walker->prev;
- PARROT_ASSERT(--count);
- }
-
- count = 10000000;
-
- PARROT_ASSERT(free_objects == pool->num_free_objects);
+ ASSERT_ARGS(buffer_location)
+ Parrot_Context * const ctx = CONTEXT(interp);
+ static char reg[10];
+ UINTVAL i;
- pobj_walker = (GC_MS_PObj_Wrapper*)pool->free_list;
- while (pobj_walker != NULL) {
- PARROT_ASSERT(pool->start_arena_memory <= (size_t)pobj_walker);
- PARROT_ASSERT(pool->end_arena_memory > (size_t)pobj_walker);
- PARROT_ASSERT(PObj_on_free_list_TEST((PObj*)pobj_walker));
- --free_objects;
- pobj_walker = (GC_MS_PObj_Wrapper*)pobj_walker->next_ptr;
- PARROT_ASSERT(--count);
+ for (i = 0; i < ctx->n_regs_used[REGNO_STR]; ++i) {
+ PObj * const obj = (PObj *)Parrot_pcc_get_STRING_reg(interp, ctx, i);
+ if ((PObj *)obj == b) {
+ sprintf(reg, "S%d", (int)i);
+ return reg;
+ }
}
- PARROT_ASSERT(total_objects == 0);
- PARROT_ASSERT(last_free_list_count == 0 || pool->num_free_objects == 0);
- PARROT_ASSERT(free_objects == 0);
+ return "???";
}
/*
-=item C<static void check_var_size_obj_pool(const Variable_Size_Pool *pool)>
-
-Checks a memory pool, containing buffer data
+=item C<static void debug_print_buf(PARROT_INTERP, const Buffer *b)>
+Prints a debug statement with information about the given PObj C<b>.
=cut
*/
static void
-check_var_size_obj_pool(ARGIN(const Variable_Size_Pool *pool))
+debug_print_buf(PARROT_INTERP, ARGIN(const Buffer *b))
{
- ASSERT_ARGS(check_var_size_obj_pool)
- size_t count;
- Memory_Block * block_walker;
- count = 10000000; /*detect unendless loop just use big enough number*/
-
- block_walker = (Memory_Block *)pool->top_block;
- while (block_walker != NULL) {
- PARROT_ASSERT(block_walker->start == (char *)block_walker +
- sizeof (Memory_Block));
- PARROT_ASSERT((size_t)(block_walker->top -
- block_walker->start) == block_walker->size - block_walker->free);
-
- /*check the list*/
- if (block_walker->prev != NULL)
- PARROT_ASSERT(block_walker->prev->next == block_walker);
- block_walker = block_walker->prev;
- PARROT_ASSERT(--count);
- }
+ ASSERT_ARGS(debug_print_buf)
+ fprintf(stderr, "found %p, len %d, flags 0x%08x at %s\n",
+ b, (int)Buffer_buflen(b), (uint)PObj_get_FLAGS(b),
+ buffer_location(interp, b));
}
+#endif
/*
-=item C<void check_buffer_ptr(Buffer * pobj, Variable_Size_Pool * pool)>
+=back
+
+=head2 Compaction Code
+
+=over 4
+
+=item C<static void compact_pool(PARROT_INTERP, Memory_Pools *mem_pools,
+Variable_Size_Pool *pool)>
-Checks wether the buffer is within the bounds of the memory pool
+Compact the string buffer pool. Does not perform a GC scan, or mark items
+as being alive in any way.
=cut
*/
-void
-check_buffer_ptr(ARGMOD(Buffer * pobj), ARGMOD(Variable_Size_Pool * pool))
+static void
+compact_pool(PARROT_INTERP,
+ ARGMOD(Memory_Pools *mem_pools),
+ ARGMOD(Variable_Size_Pool *pool))
{
- ASSERT_ARGS(check_buffer_ptr)
- Memory_Block * cur_block = pool->top_block;
- char * bufstart;
+ ASSERT_ARGS(compact_pool)
+ INTVAL j;
+ UINTVAL total_size;
+
+ Fixed_Size_Arena *cur_buffer_arena;
- bufstart = (char*)Buffer_bufstart(pobj);
+ /* Contains new_block and cur_spot */
+ string_callback_data cb_data;
- if (bufstart == NULL && Buffer_buflen(pobj) == 0)
- return;
- if (PObj_external_TEST(pobj) || PObj_sysmem_TEST(pobj)) {
- /*buffer does not come from the memory pool*/
- if (PObj_is_string_TEST(pobj)) {
- PARROT_ASSERT(((STRING *) pobj)->strstart >=
- (char *) Buffer_bufstart(pobj));
- PARROT_ASSERT(((STRING *) pobj)->strstart +
- ((STRING *) pobj)->strlen <=
- (char *) Buffer_bufstart(pobj) + Buffer_buflen(pobj));
- }
+ /* Bail if we're blocked */
+ if (mem_pools->gc_sweep_block_level)
return;
- }
- if (PObj_is_COWable_TEST(pobj))
- bufstart -= sizeof (void*);
+ ++mem_pools->gc_sweep_block_level;
- while (cur_block) {
- if ((char *)bufstart >= cur_block->start &&
- (char *)Buffer_bufstart(pobj) +
- Buffer_buflen(pobj) < cur_block->start + cur_block->size) {
- if (PObj_is_string_TEST(pobj)) {
- PARROT_ASSERT(((STRING *)pobj)->strstart >=
- (char *)Buffer_bufstart(pobj));
- PARROT_ASSERT(((STRING *)pobj)->strstart +
- ((STRING *)pobj)->strlen <= (char *)Buffer_bufstart(pobj) +
- Buffer_buflen(pobj));
- }
- return;
- }
- cur_block = cur_block->prev;
- }
- PARROT_ASSERT(0);
-}
+ /* We're collecting */
+ mem_pools->mem_allocs_since_last_collect = 0;
+ mem_pools->header_allocs_since_last_collect = 0;
+ ++mem_pools->gc_collect_runs;
+ /* Snag a block big enough for everything */
+ total_size = pad_pool_size(pool);
-/*
+ if (total_size == 0) {
+ free_old_mem_blocks(mem_pools, pool, pool->top_block, total_size);
+ --mem_pools->gc_sweep_block_level;
+ return;
+ }
-=item C<void Parrot_gc_destroy_header_pools(PARROT_INTERP, Memory_Pools
-*mem_pools)>
+ Parrot_gc_str_alloc_new_block(mem_pools, total_size, pool, "inside compact");
-Performs a garbage collection sweep on all pools, then frees them. Calls
-C<header_pools_iterate_callback> to loop over all the pools, passing
-C<sweep_cb_pmc> and C<sweep_cb_buf> callback routines. Frees the array of sized
-header pointers in the C<Memory_Pools> structure too.
+ cb_data.new_block = pool->top_block;
-=cut
+ /* Start at the beginning */
+ cb_data.cur_spot = cb_data.new_block->start;
-*/
+ /* Run through all the Buffer header pools and copy */
+ interp->gc_sys->iterate_live_strings(interp, move_buffer_callback, &cb_data);
-void
-Parrot_gc_destroy_header_pools(PARROT_INTERP, ARGMOD(Memory_Pools *mem_pools))
-{
- ASSERT_ARGS(Parrot_gc_destroy_header_pools)
+ /* Okay, we're done with the copy. Set the bits in the pool struct */
+ /* First, where we allocate next */
+ cb_data.new_block->top = cb_data.cur_spot;
- /* const/non const COW strings life in different pools
- * so in first pass
- * COW refcount is done, in 2. refcounting
- * in 3rd freeing
- */
- const INTVAL start = 2;
+ PARROT_ASSERT(cb_data.new_block->size
+ >=
+ (size_t)cb_data.new_block->top - (size_t)cb_data.new_block->start);
- header_pools_iterate_callback(interp, mem_pools, POOL_PMC, NULL, sweep_cb_pmc);
- header_pools_iterate_callback(interp, mem_pools, POOL_PMC | POOL_CONST, NULL,
- sweep_cb_pmc);
+ /* How much is free. That's the total size minus the amount we used */
+ cb_data.new_block->free = cb_data.new_block->size
+ - (cb_data.cur_spot - cb_data.new_block->start);
+ mem_pools->memory_collected += (cb_data.cur_spot - cb_data.new_block->start);
+ mem_pools->memory_used += (cb_data.cur_spot - cb_data.new_block->start);
- header_pools_iterate_callback(interp, mem_pools, POOL_BUFFER | POOL_CONST,
- (void *)start, sweep_cb_buf);
+ free_old_mem_blocks(mem_pools, pool, cb_data.new_block, total_size);
- mem_internal_free(mem_pools->sized_header_pools);
+ --mem_pools->gc_sweep_block_level;
+}
- if (mem_pools->attrib_pools) {
- unsigned int i;
- for (i = 0; i < mem_pools->num_attribs; ++i) {
- PMC_Attribute_Pool *pool = mem_pools->attrib_pools[i];
- PMC_Attribute_Arena *arena;
+/*
+=item C<static void move_buffer_callback(PARROT_INTERP, Buffer *b, void *data)>
- if (!pool)
- continue;
+Callback for live STRING/Buffer for compating.
- arena = pool->top_arena;
+=cut
+*/
+static void
+move_buffer_callback(PARROT_INTERP, ARGIN(Buffer *b), ARGIN(void *data))
+{
+ ASSERT_ARGS(move_buffer_callback)
+ string_callback_data *cb = (string_callback_data*)data;
- while (arena) {
- PMC_Attribute_Arena *next = arena->next;
- mem_internal_free(arena);
- arena = next;
- }
- mem_internal_free(pool);
- }
+ if (Buffer_buflen(b) && PObj_is_movable_TESTALL(b)) {
+ Memory_Block *old_block = Buffer_pool(b);
- mem_internal_free(mem_pools->attrib_pools);
+ if (!is_block_almost_full(old_block))
+ cb->cur_spot = move_one_buffer(interp, cb->new_block, b, cb->cur_spot);
}
- mem_pools->attrib_pools = NULL;
- mem_pools->sized_header_pools = NULL;
}
/*
-=item C<static int sweep_cb_pmc(PARROT_INTERP, Memory_Pools *mem_pools,
-Fixed_Size_Pool *pool, int flag, void *arg)>
-
-Performs a garbage collection sweep of the given pmc pool, then frees it. Calls
-C<Parrot_gc_sweep_pool> to perform the sweep, and C<free_pool> to free the pool and
-all its arenas. Always returns C<0>.
+=item C<static UINTVAL pad_pool_size(const Variable_Size_Pool *pool)>
-=cut
+Calculate the size of the new pool. The currently used size equals the total
+size minus the reclaimable size. Add a minimum block to the current amount, so
+we can avoid having to allocate it in the future.
-*/
+Returns 0 if all blocks below the top block are almost full. In this case
+compacting is not needed.
-static int
-sweep_cb_pmc(PARROT_INTERP,
- ARGMOD(Memory_Pools *mem_pools),
- ARGMOD(Fixed_Size_Pool *pool),
- SHIM(int flag), SHIM(void *arg))
-{
- ASSERT_ARGS(sweep_cb_pmc)
- Parrot_gc_sweep_pool(interp, mem_pools, pool);
- free_pool(pool);
- return 0;
-}
+TODO - Big blocks
-/*
+Currently all available blocks are compacted into one new
+block with total_size. This is suboptimal, if the block has
+just one live item from a big allocation.
-=item C<static int sweep_cb_buf(PARROT_INTERP, Memory_Pools *mem_pools,
-Fixed_Size_Pool *pool, int flag, void *arg)>
+But currently it's unknown if the buffer memory is alive
+as the live bits are in Buffer headers. We have to run the
+compaction loop to check liveness. OTOH if this compaction
+is running through all the buffer headers, there is no
+relation to the block.
-Performs a final garbage collection sweep, then frees the pool. Calls
-C<Parrot_gc_sweep_pool> to perform the sweep, and C<free_pool> to free the pool and
-all its arenas.
+Moving the live bit into the buffer thus also solves this
+problem easily.
=cut
*/
-static int
-sweep_cb_buf(PARROT_INTERP,
- ARGIN(Memory_Pools *mem_pools),
- ARGFREE(Fixed_Size_Pool *pool),
- SHIM(int flag), SHIM(void *arg))
+PARROT_CANNOT_RETURN_NULL
+static UINTVAL
+pad_pool_size(ARGIN(const Variable_Size_Pool *pool))
{
- ASSERT_ARGS(sweep_cb_buf)
-
- Parrot_gc_sweep_pool(interp, mem_pools, pool);
- free_pool(pool);
-
- return 0;
-}
+ ASSERT_ARGS(pad_pool_size)
+ Memory_Block *cur_block = pool->top_block->prev;
-/*
+ UINTVAL total_size = 0;
+#if RESOURCE_DEBUG
+ size_t total_blocks = 1;
+#endif
-=item C<static void free_pool(Fixed_Size_Pool *pool)>
+ while (cur_block) {
+ if (!is_block_almost_full(cur_block))
+ total_size += cur_block->size - cur_block->freed - cur_block->free;
+ cur_block = cur_block->prev;
+#if RESOURCE_DEBUG
+ ++total_blocks;
+#endif
+ }
-Frees a pool and all of its arenas. Loops through the list of arenas backwards
-and returns each to the memory manager. Then, frees the pool structure itself.
+ if (total_size == 0)
+ return 0;
-=cut
+ cur_block = pool->top_block;
+ if (!is_block_almost_full(cur_block))
+ total_size += cur_block->size - cur_block->freed - cur_block->free;
-*/
+ /* this makes for ever increasing allocations but fewer collect runs */
+#if WE_WANT_EVER_GROWING_ALLOCATIONS
+ total_size += pool->minimum_block_size;
+#endif
-static void
-free_pool(ARGFREE(Fixed_Size_Pool *pool))
-{
- ASSERT_ARGS(free_pool)
- Fixed_Size_Arena *cur_arena;
+#if RESOURCE_DEBUG
+ fprintf(stderr, "Total blocks: %d\n", total_blocks);
+#endif
- for (cur_arena = pool->last_Arena; cur_arena;) {
- Fixed_Size_Arena * const next = cur_arena->prev;
- mem_internal_free(cur_arena->start_objects);
- mem_internal_free(cur_arena);
- cur_arena = next;
- }
- mem_internal_free(pool);
+ return total_size;
}
-
/*
-=item C<static void free_memory_pool(Variable_Size_Pool *pool)>
+=item C<static char * move_one_buffer(PARROT_INTERP, Memory_Block *pool, Buffer
+*old_buf, char *new_pool_ptr)>
-Frees a memory pool; helper function for C<Parrot_gc_destroy_memory_pools>.
+The compact_pool operation collects disjointed blocks of memory allocated on a
+given pool's free list into one large block of memory. Once the new larger
+memory block has been allocated, this function moves one buffer from the old
+memory block to the new memory block and marks that it has been moved.
=cut
*/
-static void
-free_memory_pool(ARGFREE(Variable_Size_Pool *pool))
+PARROT_WARN_UNUSED_RESULT
+PARROT_CANNOT_RETURN_NULL
+static char *
+move_one_buffer(PARROT_INTERP, ARGIN(Memory_Block *pool),
+ ARGMOD(Buffer *old_buf), ARGMOD(char *new_pool_ptr))
{
- ASSERT_ARGS(free_memory_pool)
-
- Memory_Block *cur_block = pool->top_block;
-
- while (cur_block) {
- Memory_Block * const next_block = cur_block->prev;
- mem_internal_free(cur_block);
- cur_block = next_block;
- }
+ ASSERT_ARGS(move_one_buffer)
- mem_internal_free(pool);
-}
+ INTVAL *flags = NULL;
+ ptrdiff_t offset = 0;
+ Memory_Block *old_block = NULL;
+#if RESOURCE_DEBUG
+ if (Buffer_buflen(old_buf) >= RESOURCE_DEBUG_SIZE)
+ debug_print_buf(interp, old_buf);
+#else
+ UNUSED(interp);
+#endif
+ /* we can't perform the math all the time, because
+ * strstart might be in unallocated memory */
+ if (PObj_is_COWable_TEST(old_buf)) {
+ flags = Buffer_bufflagsptr(old_buf);
+ old_block = Buffer_pool(old_buf);
-/*
+ if (PObj_is_string_TEST(old_buf)) {
+ offset = (ptrdiff_t)((STRING *)old_buf)->strstart -
+ (ptrdiff_t)Buffer_bufstart(old_buf);
+ }
+ }
-=item C<void Parrot_gc_destroy_memory_pools(PARROT_INTERP, Memory_Pools
-*mem_pools)>
+ /* buffer has already been moved; just change the header */
+ if (flags && (*flags & Buffer_shared_FLAG)
+ && (*flags & Buffer_moved_FLAG)) {
+ /* Find out who else references our data */
+ Buffer * const hdr = *((Buffer **)Buffer_bufstart(old_buf));
-Destroys the memory pool and the constant string pool. Loop through both
-pools and destroy all memory blocks contained in them. Once all the
-blocks are freed, free the pools themselves.
+ PARROT_ASSERT(PObj_is_COWable_TEST(old_buf));
-=cut
+ /* Make sure they know that we own it too */
+ /* Set Buffer_shared_FLAG in new buffer */
+ *Buffer_bufflagsptr(hdr) |= Buffer_shared_FLAG;
-*/
+ /* Now make sure we point to where the other guy does */
+ Buffer_bufstart(old_buf) = Buffer_bufstart(hdr);
-void
-Parrot_gc_destroy_memory_pools(SHIM_INTERP, ARGMOD(Memory_Pools *mem_pools))
-{
- ASSERT_ARGS(Parrot_gc_destroy_memory_pools)
+ /* And if we're a string, update strstart */
+ /* Somewhat of a hack, but if we get per-pool
+ * collections, it should help ease the pain */
+ if (PObj_is_string_TEST(old_buf))
+ ((STRING *)old_buf)->strstart =
+ (char *)Buffer_bufstart(old_buf) + offset;
+ }
+ else {
+ new_pool_ptr = aligned_mem(old_buf, new_pool_ptr);
- free_memory_pool(mem_pools->constant_string_pool);
- free_memory_pool(mem_pools->memory_pool);
-}
+ /* Copy our memory to the new pool */
+ memcpy(new_pool_ptr, Buffer_bufstart(old_buf),
+ Buffer_buflen(old_buf));
-/*
+ /* If we're shared */
+ if (flags && (*flags & Buffer_shared_FLAG)) {
+ PARROT_ASSERT(PObj_is_COWable_TEST(old_buf));
-=item C<void Parrot_gc_merge_memory_pools(Interp *dest_interp, Memory_Pools
-*dest_arena, const Memory_Pools *source_arena)>
+ /* Let the old buffer know how to find us */
+ *((Buffer **)Buffer_bufstart(old_buf)) = old_buf;
-Merges the header pools of C<source_interp> into those of C<dest_interp>.
-(Used to deal with shared objects left after interpreter destruction.)
+ /* Finally, let the tail know that we've moved, so
+ * that any other references can know to look for
+ * us and not re-copy */
+ *flags |= Buffer_moved_FLAG;
+ }
-=cut
+ Buffer_bufstart(old_buf) = new_pool_ptr;
-*/
+ /* Remember new pool inside */
+ *Buffer_poolptr(old_buf) = pool;
-void
-Parrot_gc_merge_memory_pools(ARGMOD(Interp *dest_interp),
- ARGMOD(Memory_Pools *dest_arena),
- ARGIN(const Memory_Pools *source_arena))
-{
- ASSERT_ARGS(Parrot_gc_merge_memory_pools)
-
- UINTVAL i;
-
- /* heavily borrowed from forall_header_pools */
- fix_pmc_syncs(dest_interp, source_arena->constant_pmc_pool);
- Parrot_gc_merge_buffer_pools(dest_interp, dest_arena,
- dest_arena->constant_pmc_pool, source_arena->constant_pmc_pool);
-
- fix_pmc_syncs(dest_interp, source_arena->pmc_pool);
- Parrot_gc_merge_buffer_pools(dest_interp, dest_arena,
- dest_arena->pmc_pool, source_arena->pmc_pool);
-
- Parrot_gc_merge_buffer_pools(dest_interp, dest_arena,
- dest_arena->constant_string_header_pool,
- source_arena->constant_string_header_pool);
-
- for (i = 0; i < source_arena->num_sized; ++i) {
- if (!source_arena->sized_header_pools[i])
- continue;
-
- if (i >= dest_arena->num_sized
- || !dest_arena->sized_header_pools[i]) {
- Fixed_Size_Pool *ignored = get_bufferlike_pool(dest_interp,
- dest_arena, i * sizeof (void *));
- UNUSED(ignored);
- PARROT_ASSERT(dest_arena->sized_header_pools[i]);
- }
+ if (PObj_is_string_TEST(old_buf))
+ ((STRING *)old_buf)->strstart =
+ (char *)Buffer_bufstart(old_buf) + offset;
- Parrot_gc_merge_buffer_pools(dest_interp, dest_arena,
- dest_arena->sized_header_pools[i],
- source_arena->sized_header_pools[i]);
+ new_pool_ptr += Buffer_buflen(old_buf);
}
+
+ return new_pool_ptr;
}
/*
-=item C<static void Parrot_gc_merge_buffer_pools(PARROT_INTERP, Memory_Pools
-*mem_pools, Fixed_Size_Pool *dest, Fixed_Size_Pool *source)>
+=item C<static void free_old_mem_blocks( Memory_Pools *mem_pools,
+Variable_Size_Pool *pool, Memory_Block *new_block, UINTVAL total_size)>
-Merge pool C<source> into pool C<dest>. Combines the free lists directly,
-moves all arenas to the new pool, and remove the old pool. To merge, the
-two pools must have the same object size, and the same name (if they have
-names).
+The compact_pool operation collects disjointed blocks of memory allocated on a
+given pool's free list into one large block of memory, setting it as the new
+top block for the pool. Once that is done, and all items have been moved into
+the new block of memory, this function iterates through the old blocks and
+frees each one. It also performs the necessary housekeeping to record the
+freed memory blocks. At the end of this function, the pool will have only one
+block of memory on its free list.
=cut
*/
static void
-Parrot_gc_merge_buffer_pools(PARROT_INTERP,
+free_old_mem_blocks(
ARGMOD(Memory_Pools *mem_pools),
- ARGMOD(Fixed_Size_Pool *dest), ARGMOD(Fixed_Size_Pool *source))
+ ARGMOD(Variable_Size_Pool *pool),
+ ARGMOD(Memory_Block *new_block),
+ UINTVAL total_size)
{
- ASSERT_ARGS(Parrot_gc_merge_buffer_pools)
- Fixed_Size_Arena *cur_arena;
+ ASSERT_ARGS(free_old_mem_blocks)
+ Memory_Block *prev_block = new_block;
+ Memory_Block *cur_block = new_block->prev;
- PARROT_ASSERT(dest->object_size == source->object_size);
- PARROT_ASSERT((dest->name == NULL && source->name == NULL)
- || STREQ(dest->name, source->name));
+ PARROT_ASSERT(new_block == pool->top_block);
- dest->total_objects += source->total_objects;
+ while (cur_block) {
+ Memory_Block * const next_block = cur_block->prev;
- /* append new free_list to old */
- /* XXX this won't work with, e.g., gc_gms */
- if (dest->free_list == NULL)
- dest->free_list = source->free_list;
- else {
- GC_MS_PObj_Wrapper *free_list_end = dest->free_list;
- while (free_list_end->next_ptr)
- free_list_end = free_list_end->next_ptr;
+ if (is_block_almost_full(cur_block)) {
+ /* Skip block */
+ prev_block = cur_block;
+ cur_block = next_block;
+ }
+ else {
+ /* Note that we don't have it any more */
+ mem_pools->memory_allocated -= cur_block->size;
+ mem_pools->memory_used -= cur_block->size - cur_block->free;
- free_list_end->next_ptr = source->free_list;
+ /* We know the pool body and pool header are a single chunk, so
+ * this is enough to get rid of 'em both */
+ mem_internal_free(cur_block);
+ cur_block = next_block;
+
+ /* Unlink it from list */
+ prev_block->prev = next_block;
+ }
}
- /* now append source arenas */
- cur_arena = source->last_Arena;
+ /* Terminate list */
+ prev_block->prev = NULL;
+
+
+ /* ANR: I suspect this should be set to new_block->size, instead of passing
+ * in the raw value of total_size, because alloc_new_block pads the size of
+ * the new block under certain conditions. Leaving it unmodified for now,
+ * so this refactor has no functionality changes, only code cleanups.*/
+ pool->total_allocated = total_size;
+ pool->guaranteed_reclaimable = 0;
+ pool->possibly_reclaimable = 0;
+}
+
+/*
- while (cur_arena) {
- Fixed_Size_Arena * const next_arena = cur_arena->prev;
- const size_t total_objects = cur_arena->total_objects;
+=item C<static int is_block_almost_full(const Memory_Block *block)>
- cur_arena->next = cur_arena->prev = NULL;
+Tests if the block is almost full and should be skipped during compacting.
- Parrot_append_arena_in_pool(interp, mem_pools, dest, cur_arena,
- cur_arena->total_objects);
+Returns true if less that 20% of block is available
- /* XXX needed? */
- cur_arena->total_objects = total_objects;
+=cut
- cur_arena = next_arena;
- }
+*/
- /* remove things from source */
- source->last_Arena = NULL;
- source->free_list = NULL;
- source->total_objects = 0;
- source->num_free_objects = 0;
+static int
+is_block_almost_full(ARGIN(const Memory_Block *block))
+{
+ ASSERT_ARGS(is_block_almost_full)
+ return 5 * (block->free + block->freed) < block->size;
}
/*
-=item C<static void fix_pmc_syncs(Interp *dest_interp, const Fixed_Size_Pool
-*pool)>
+=item C<static void free_memory_pool(Variable_Size_Pool *pool)>
-Walks through the given arena, looking for all live and shared PMCs,
-transferring their sync values to the destination interpreter.
+Frees a memory pool; helper function for C<Parrot_gc_destroy_memory_pools>.
=cut
*/
static void
-fix_pmc_syncs(ARGMOD(Interp *dest_interp), ARGIN(const Fixed_Size_Pool *pool))
+free_memory_pool(ARGFREE(Variable_Size_Pool *pool))
{
- ASSERT_ARGS(fix_pmc_syncs)
- Fixed_Size_Arena *cur_arena;
- const UINTVAL object_size = pool->object_size;
-
- for (cur_arena = pool->last_Arena; cur_arena; cur_arena = cur_arena->prev) {
- PMC *p = (PMC *)((char*)cur_arena->start_objects);
- size_t i;
-
- for (i = 0; i < cur_arena->used; ++i) {
- if (!PObj_on_free_list_TEST(p) && PObj_is_PMC_TEST(p)) {
- Parrot_ex_throw_from_c_args(dest_interp, NULL,
- EXCEPTION_INTERP_ERROR,
- "Unshared PMC still alive after interpreter"
- "destruction. address=%p, base_type=%d\n",
- p, p->vtable->base_type);
- }
+ ASSERT_ARGS(free_memory_pool)
- p = (PMC *)((char *)p + object_size);
- }
+ Memory_Block *cur_block = pool->top_block;
+
+ while (cur_block) {
+ Memory_Block * const next_block = cur_block->prev;
+ mem_internal_free(cur_block);
+ cur_block = next_block;
}
-}
+ mem_internal_free(pool);
+}
/*
@@ -1473,6 +1203,7 @@
=head1 SEE ALSO
F<src/gc/memory.c>.
+F<src/gc/alloc_resources.c>.
=cut
More information about the parrot-commits
mailing list