Author: Nicolas Truessel <ntrues...@njsm.de> Branch: quad-color-gc Changeset: r87126:86dfb2ca9890 Date: 2016-09-14 08:11 +0200 http://bitbucket.org/pypy/pypy/changeset/86dfb2ca9890/
Log: QCGC update (performance) diff --git a/rpython/translator/c/src/qcgc/qcgc.c b/rpython/translator/c/src/qcgc/qcgc.c --- a/rpython/translator/c/src/qcgc/qcgc.c +++ b/rpython/translator/c/src/qcgc/qcgc.c @@ -25,6 +25,8 @@ QCGC_STATIC QCGC_INLINE void initialize_shadowstack(void); QCGC_STATIC QCGC_INLINE void destroy_shadowstack(void); +QCGC_STATIC object_t *bump_allocate(size_t size); + void qcgc_initialize(void) { initialize_shadowstack(); qcgc_state.prebuilt_objects = qcgc_shadow_stack_create(16); // XXX @@ -79,14 +81,14 @@ if (LIKELY(size <= 1<<QCGC_LARGE_ALLOC_THRESHOLD_EXP)) { // Use bump / fit allocator //if (qcgc_allocator_state.use_bump_allocator) { - if (true) { - result = qcgc_bump_allocate(size); + if (false) { + result = bump_allocate(size); } else { result = qcgc_fit_allocate(size); // Fallback to bump allocator if (result == NULL) { - result = qcgc_bump_allocate(size); + result = bump_allocate(size); } } } else { @@ -140,11 +142,13 @@ if ((object->flags & QCGC_PREBUILT_OBJECT) != 0) { // NOTE: No mark test here, as prebuilt objects are always reachable // Push prebuilt object to general purpose gray stack + qcgc_state.gray_stack_size++; qcgc_state.gp_gray_stack = qcgc_gray_stack_push( qcgc_state.gp_gray_stack, object); } else if ((object_t *) qcgc_arena_addr((cell_t *) object) == object) { if (qcgc_hbtable_is_marked(object)) { // Push huge block to general purpose gray stack + qcgc_state.gray_stack_size++; qcgc_state.gp_gray_stack = qcgc_gray_stack_push( qcgc_state.gp_gray_stack, object); } @@ -153,6 +157,7 @@ qcgc_arena_cell_index((cell_t *) object)) == BLOCK_BLACK) { // This was black before, push it to gray stack again arena_t *arena = qcgc_arena_addr((cell_t *) object); + qcgc_state.gray_stack_size++; arena->gray_stack = qcgc_gray_stack_push( arena->gray_stack, object); } @@ -199,3 +204,11 @@ free(qcgc_shadowstack.base); } + +QCGC_STATIC object_t *bump_allocate(size_t size) { + if (UNLIKELY(qcgc_allocator_state.bump_state.remaining_cells < + bytes_to_cells(size))) { + qcgc_bump_allocator_renew_block(); + } + return qcgc_bump_allocate(size); +} diff --git a/rpython/translator/c/src/qcgc/src/allocator.c b/rpython/translator/c/src/qcgc/src/allocator.c --- a/rpython/translator/c/src/qcgc/src/allocator.c +++ b/rpython/translator/c/src/qcgc/src/allocator.c @@ -3,15 +3,10 @@ #include <assert.h> #include <stdbool.h> #include <stdlib.h> -#include <string.h> #include "hugeblocktable.h" -QCGC_STATIC size_t bytes_to_cells(size_t bytes); - QCGC_STATIC QCGC_INLINE void bump_allocator_assign(cell_t *ptr, size_t cells); -QCGC_STATIC QCGC_INLINE void bump_allocator_advance(size_t cells); -QCGC_STATIC void bump_allocator_renew_block(void); QCGC_STATIC QCGC_INLINE bool is_small(size_t cells); QCGC_STATIC QCGC_INLINE size_t small_index(size_t cells); @@ -71,20 +66,21 @@ } void qcgc_fit_allocator_add(cell_t *ptr, size_t cells) { - if (cells > 0) { - if (is_small(cells)) { - size_t index = small_index(cells); - qcgc_allocator_state.fit_state.small_free_list[index] = - qcgc_linear_free_list_add( - qcgc_allocator_state.fit_state.small_free_list[index], - ptr); - } else { - size_t index = large_index(cells); - qcgc_allocator_state.fit_state.large_free_list[index] = - qcgc_exp_free_list_add( - qcgc_allocator_state.fit_state.large_free_list[index], - (struct exp_free_list_item_s) {ptr, cells}); - } +#if CHECKED + assert(cells > 0); +#endif + if (is_small(cells)) { + size_t index = small_index(cells); + qcgc_allocator_state.fit_state.small_free_list[index] = + qcgc_linear_free_list_add( + qcgc_allocator_state.fit_state.small_free_list[index], + ptr); + } else { + size_t index = large_index(cells); + qcgc_allocator_state.fit_state.large_free_list[index] = + qcgc_exp_free_list_add( + qcgc_allocator_state.fit_state.large_free_list[index], + (struct exp_free_list_item_s) {ptr, cells}); } } @@ -92,42 +88,8 @@ * Bump Allocator * ******************************************************************************/ -object_t *qcgc_bump_allocate(size_t bytes) { +void qcgc_bump_allocator_renew_block(void) { #if CHECKED - assert(bytes <= 1<<QCGC_LARGE_ALLOC_THRESHOLD_EXP); -#endif - size_t cells = bytes_to_cells(bytes); - if (UNLIKELY(cells > qcgc_allocator_state.bump_state.remaining_cells)) { - if (LIKELY(qcgc_allocator_state.bump_state.remaining_cells > 0)) { - qcgc_arena_set_blocktype( - qcgc_arena_addr(qcgc_allocator_state.bump_state.bump_ptr), - qcgc_arena_cell_index( - qcgc_allocator_state.bump_state.bump_ptr), - BLOCK_FREE); - } - bump_allocator_renew_block(); - } - cell_t *mem = qcgc_allocator_state.bump_state.bump_ptr; - bump_allocator_advance(cells); - - qcgc_arena_set_blocktype(qcgc_arena_addr(mem), qcgc_arena_cell_index(mem), - BLOCK_WHITE); - /* - if (qcgc_allocator_state.bump_state.remaining_cells > 0) { - qcgc_arena_set_blocktype(qcgc_allocator_state.bump_state.bump_ptr, - BLOCK_FREE); - } - */ - - object_t *result = (object_t *) mem; - -#if QCGC_INIT_ZERO - memset(result, 0, cells * sizeof(cell_t)); -#endif - - result->flags = QCGC_GRAY_FLAG; -#if CHECKED - assert(qcgc_arena_is_coalesced(qcgc_arena_addr((cell_t *)result))); if (qcgc_allocator_state.bump_state.remaining_cells > 0) { for (size_t i = 1; i < qcgc_allocator_state.bump_state.remaining_cells; i++) { @@ -139,30 +101,16 @@ } } #endif - return result; -} - -QCGC_STATIC void bump_allocator_renew_block(void) { -#if CHECKED + // Add remaining memory to fit allocator if (qcgc_allocator_state.bump_state.remaining_cells > 0) { - assert(qcgc_arena_get_blocktype( - qcgc_arena_addr( qcgc_allocator_state.bump_state.bump_ptr), - qcgc_arena_cell_index( - qcgc_allocator_state.bump_state.bump_ptr)) - == BLOCK_FREE); - for (size_t i = 1; i < qcgc_allocator_state.bump_state.remaining_cells; - i++) { - assert(qcgc_arena_get_blocktype(qcgc_arena_addr( - qcgc_allocator_state.bump_state.bump_ptr + i), - qcgc_arena_cell_index( - qcgc_allocator_state.bump_state.bump_ptr + i)) - == BLOCK_EXTENT); - } + qcgc_arena_set_blocktype( + qcgc_arena_addr(qcgc_allocator_state.bump_state.bump_ptr), + qcgc_arena_cell_index( + qcgc_allocator_state.bump_state.bump_ptr), + BLOCK_FREE); + qcgc_fit_allocator_add(qcgc_allocator_state.bump_state.bump_ptr, + qcgc_allocator_state.bump_state.remaining_cells); } -#endif - // Add remaining memory to fit allocator - qcgc_fit_allocator_add(qcgc_allocator_state.bump_state.bump_ptr, - qcgc_allocator_state.bump_state.remaining_cells); // Try finding some huge block from fit allocator exp_free_list_t *free_list = qcgc_allocator_state.fit_state. @@ -215,11 +163,6 @@ qcgc_allocator_state.bump_state.remaining_cells = cells; } -QCGC_STATIC void bump_allocator_advance(size_t cells) { - qcgc_allocator_state.bump_state.bump_ptr += cells; - qcgc_allocator_state.bump_state.remaining_cells -= cells; -} - object_t *qcgc_fit_allocate(size_t bytes) { #if CHECKED //free_list_consistency_check(); @@ -365,7 +308,6 @@ qcgc_allocator_state.fit_state.large_free_list[index], 0); - qcgc_arena_mark_allocated(item.ptr, cells); qcgc_arena_set_blocktype(qcgc_arena_addr(item.ptr), qcgc_arena_cell_index(item.ptr), BLOCK_WHITE); if (item.size - cells > 0) { @@ -379,10 +321,6 @@ return NULL; } -QCGC_STATIC size_t bytes_to_cells(size_t bytes) { - return (bytes + sizeof(cell_t) - 1) / sizeof(cell_t); -} - QCGC_STATIC bool is_small(size_t cells) { return cells <= QCGC_SMALL_FREE_LISTS; } diff --git a/rpython/translator/c/src/qcgc/src/allocator.h b/rpython/translator/c/src/qcgc/src/allocator.h --- a/rpython/translator/c/src/qcgc/src/allocator.h +++ b/rpython/translator/c/src/qcgc/src/allocator.h @@ -2,6 +2,8 @@ #include "../qcgc.h" +#include <string.h> + #include "arena.h" #include "bag.h" @@ -69,15 +71,6 @@ object_t *qcgc_fit_allocate(size_t bytes); /** - * Allocate new memory region using bump allocator - * - * @param bytes Desired size of the memory region in bytes - * @return Pointer to memory large enough to hold size bytes, NULL in case of - * errors, already zero initialized if QCGC_INIT_ZERO is set - */ -object_t *qcgc_bump_allocate(size_t bytes); - -/** * Allocate new memory region using huge block allocator * * @param bytes Desired size of the memory region in bytes @@ -99,3 +92,42 @@ * @param cells Size of memory region in cells */ void qcgc_fit_allocator_add(cell_t *ptr, size_t cells); + +QCGC_STATIC QCGC_INLINE size_t bytes_to_cells(size_t bytes) { + return (bytes + sizeof(cell_t) - 1) / sizeof(cell_t); +} + +/** + * Find a new block for the bump allocator + */ +void qcgc_bump_allocator_renew_block(void); + +/** + * Allocate new memory region using bump allocator. + * Bump allocator must have enough space for desired bytes + * (client is responsible, use qcgc_bump_allocator_renew_block) + * + * @param bytes Desired size of the memory region in bytes + * @return Pointer to memory large enough to hold size bytes, NULL in case of + * errors, already zero initialized if QCGC_INIT_ZERO is set + */ +QCGC_STATIC QCGC_INLINE object_t *qcgc_bump_allocate(size_t bytes) { + size_t cells = bytes_to_cells(bytes); + + cell_t *mem = qcgc_allocator_state.bump_state.bump_ptr; + + qcgc_arena_set_blocktype(qcgc_arena_addr(mem), qcgc_arena_cell_index(mem), + BLOCK_WHITE); + + qcgc_allocator_state.bump_state.bump_ptr += cells; + qcgc_allocator_state.bump_state.remaining_cells -= cells; + + object_t *result = (object_t *) mem; + +#if QCGC_INIT_ZERO + memset(result, 0, cells * sizeof(cell_t)); +#endif + + result->flags = QCGC_GRAY_FLAG; + return result; +} diff --git a/rpython/translator/c/src/qcgc/src/collector.c b/rpython/translator/c/src/qcgc/src/collector.c --- a/rpython/translator/c/src/qcgc/src/collector.c +++ b/rpython/translator/c/src/qcgc/src/collector.c @@ -20,6 +20,7 @@ while (qcgc_state.gp_gray_stack->index > 0) { object_t *top = qcgc_gray_stack_top(qcgc_state.gp_gray_stack); + qcgc_state.gray_stack_size--; qcgc_state.gp_gray_stack = qcgc_gray_stack_pop( qcgc_state.gp_gray_stack); qcgc_pop_object(top); @@ -31,6 +32,7 @@ while (arena->gray_stack->index > 0) { object_t *top = qcgc_gray_stack_top(arena->gray_stack); + qcgc_state.gray_stack_size--; arena->gray_stack = qcgc_gray_stack_pop(arena->gray_stack); qcgc_pop_object(top); } @@ -53,6 +55,7 @@ while (to_process > 0 && qcgc_state.gp_gray_stack->index > 0) { object_t *top = qcgc_gray_stack_top(qcgc_state.gp_gray_stack); + qcgc_state.gray_stack_size--; qcgc_state.gp_gray_stack = qcgc_gray_stack_pop( qcgc_state.gp_gray_stack); qcgc_pop_object(top); @@ -66,6 +69,7 @@ while (to_process > 0 && arena->gray_stack->index > 0) { object_t *top = qcgc_gray_stack_top(arena->gray_stack); + qcgc_state.gray_stack_size--; arena->gray_stack = qcgc_gray_stack_pop(arena->gray_stack); qcgc_pop_object(top); to_process--; @@ -99,6 +103,7 @@ // because of the write barrier size_t count = qcgc_state.prebuilt_objects->count; for (size_t i = 0; i < count; i++) { + qcgc_state.gray_stack_size++; qcgc_state.gp_gray_stack = qcgc_gray_stack_push( qcgc_state.gp_gray_stack, qcgc_state.prebuilt_objects->items[i]); @@ -157,6 +162,7 @@ if (qcgc_hbtable_mark(object)) { // Did mark it / was white before object->flags |= QCGC_GRAY_FLAG; + qcgc_state.gray_stack_size++; qcgc_state.gp_gray_stack = qcgc_gray_stack_push( qcgc_state.gp_gray_stack, object); } @@ -169,6 +175,7 @@ if (qcgc_arena_get_blocktype(arena, index) == BLOCK_WHITE) { object->flags |= QCGC_GRAY_FLAG; qcgc_arena_set_blocktype(arena, index, BLOCK_BLACK); + qcgc_state.gray_stack_size++; arena->gray_stack = qcgc_gray_stack_push(arena->gray_stack, object); } } diff --git a/rpython/translator/c/src/qcgc/src/core.c b/rpython/translator/c/src/qcgc/src/core.c deleted file mode 100644 --- a/rpython/translator/c/src/qcgc/src/core.c +++ /dev/null @@ -1,184 +0,0 @@ -#include "core.h" - -#include <assert.h> -#include <stdio.h> -#include <sys/mman.h> - -#include "allocator.h" -#include "collector.h" -#include "event_logger.h" -#include "gc_state.h" -#include "hugeblocktable.h" -#include "signal_handler.h" - -#define env_or_fallback(var, env_name, fallback) do { \ - char *env_val = getenv(env_name); \ - if (env_val != NULL) { \ - if (1 != sscanf(env_val, "%zu", &var)) { \ - var = fallback; \ - } \ - } else { \ - var = fallback; \ - } \ -} while(0) - -QCGC_STATIC QCGC_INLINE void _initialize_shadowstack(void); -QCGC_STATIC QCGC_INLINE void _destroy_shadowstack(void); - -/******************************************************************************/ - -void qcgc_initialize(void) { - _initialize_shadowstack(); - qcgc_state.prebuilt_objects = qcgc_shadow_stack_create(16); // XXX - qcgc_state.weakrefs = qcgc_weakref_bag_create(16); // XXX - qcgc_state.gp_gray_stack = qcgc_gray_stack_create(16); // XXX - qcgc_state.gray_stack_size = 0; - qcgc_state.phase = GC_PAUSE; - qcgc_state.bytes_since_collection = 0; - qcgc_state.bytes_since_incmark = 0; - qcgc_state.free_cells = 0; - qcgc_state.largest_free_block = 0; - qcgc_allocator_initialize(); - qcgc_hbtable_initialize(); - qcgc_event_logger_initialize(); - - env_or_fallback(qcgc_state.major_collection_threshold, "QCGC_MAJOR_COLLECTION", - QCGC_MAJOR_COLLECTION_THRESHOLD); - env_or_fallback(qcgc_state.incmark_threshold, "QCGC_INCMARK", QCGC_INCMARK_THRESHOLD); - - setup_signal_handler(); -} - -void qcgc_destroy(void) { - qcgc_event_logger_destroy(); - qcgc_hbtable_destroy(); - qcgc_allocator_destroy(); - _destroy_shadowstack(); - free(qcgc_state.prebuilt_objects); - free(qcgc_state.weakrefs); - free(qcgc_state.gp_gray_stack); -} - -object_t *qcgc_allocate(size_t size) { -#if LOG_ALLOCATION - qcgc_event_logger_log(EVENT_ALLOCATE_START, sizeof(size_t), - (uint8_t *) &size); -#endif - object_t *result; - - if (qcgc_state.bytes_since_collection > - qcgc_state.major_collection_threshold) { - qcgc_collect(); - } - if (qcgc_state.bytes_since_incmark > qcgc_state.incmark_threshold) { - qcgc_mark(true); - } - - if (size <= 1<<QCGC_LARGE_ALLOC_THRESHOLD_EXP) { - // Use bump / fit allocator - if (qcgc_allocator_state.use_bump_allocator) { - result = qcgc_bump_allocate(size); - } else { - result = qcgc_fit_allocate(size); - - // Fallback to bump allocator - if (result == NULL) { - result = qcgc_bump_allocate(size); - } - } - } else { - // Use huge block allocator - result = qcgc_large_allocate(size); - } - - // XXX: Should we use cells instead of bytes? - qcgc_state.bytes_since_collection += size; - qcgc_state.bytes_since_incmark += size; - - -#if LOG_ALLOCATION - qcgc_event_logger_log(EVENT_ALLOCATE_DONE, sizeof(object_t *), - (uint8_t *) &result); -#endif - return result; -} - -void qcgc_collect(void) { - qcgc_mark(false); - qcgc_sweep(); - qcgc_state.bytes_since_collection = 0; -} - -void qcgc_write(object_t *object) { -#if CHECKED - assert(object != NULL); -#endif - if ((object->flags & QCGC_GRAY_FLAG) != 0) { - // Already gray, skip - return; - } - object->flags |= QCGC_GRAY_FLAG; - - // Register prebuilt object if necessary - if (((object->flags & QCGC_PREBUILT_OBJECT) != 0) && - ((object->flags & QCGC_PREBUILT_REGISTERED) == 0)) { - object->flags |= QCGC_PREBUILT_REGISTERED; - qcgc_state.prebuilt_objects = qcgc_shadow_stack_push( - qcgc_state.prebuilt_objects, object); - } - - if (qcgc_state.phase == GC_PAUSE) { - return; // We are done - } - - // Triggered barrier, we must not collect now - qcgc_state.phase = GC_MARK; - - // Test reachability of object and push if neccessary - if ((object->flags & QCGC_PREBUILT_OBJECT) != 0) { - // NOTE: No mark test here, as prebuilt objects are always reachable - // Push prebuilt object to general purpose gray stack - qcgc_state.gp_gray_stack = qcgc_gray_stack_push( - qcgc_state.gp_gray_stack, object); - } else if ((object_t *) qcgc_arena_addr((cell_t *) object) == object) { - if (qcgc_hbtable_is_marked(object)) { - // Push huge block to general purpose gray stack - qcgc_state.gp_gray_stack = qcgc_gray_stack_push( - qcgc_state.gp_gray_stack, object); - } - } else { - if (qcgc_arena_get_blocktype((cell_t *) object) == BLOCK_BLACK) { - // This was black before, push it to gray stack again - arena_t *arena = qcgc_arena_addr((cell_t *) object); - arena->gray_stack = qcgc_gray_stack_push( - arena->gray_stack, object); - } - } -} - -/******************************************************************************/ - -QCGC_STATIC QCGC_INLINE void *_trap_page_addr(object_t **shadow_stack) { - object_t **shadow_stack_end = shadow_stack + QCGC_SHADOWSTACK_SIZE; - char *in_trap_page = (((char *)shadow_stack_end) + 4095); - void *rounded_trap_page = (void *)(((uintptr_t)in_trap_page) & (~4095)); - return rounded_trap_page; -} - -QCGC_STATIC QCGC_INLINE void _initialize_shadowstack(void) { - size_t stack_size = QCGC_SHADOWSTACK_SIZE * sizeof(object_t *); - // allocate stack + size for alignement + trap page - object_t **stack = (object_t **) malloc(stack_size + 8192); - assert(stack != NULL); - mprotect(_trap_page_addr(stack), 4096, PROT_NONE); - - qcgc_state.shadow_stack = stack; - qcgc_state.shadow_stack_base = stack; -} - -QCGC_STATIC void _destroy_shadowstack(void) { - mprotect(_trap_page_addr(qcgc_state.shadow_stack_base), 4096, PROT_READ | - PROT_WRITE); - - free(qcgc_state.shadow_stack_base); -} diff --git a/rpython/translator/c/src/qcgc/src/core.h b/rpython/translator/c/src/qcgc/src/core.h deleted file mode 100644 --- a/rpython/translator/c/src/qcgc/src/core.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "config.h" - -#include <stddef.h> - -#include "object.h" - - -void qcgc_initialize(void); -void qcgc_destroy(void); -object_t *qcgc_allocate(size_t size); -void qcgc_collect(void); -void qcgc_write(object_t *object); diff --git a/rpython/translator/c/src/qcgc/src/gray_stack.c b/rpython/translator/c/src/qcgc/src/gray_stack.c --- a/rpython/translator/c/src/qcgc/src/gray_stack.c +++ b/rpython/translator/c/src/qcgc/src/gray_stack.c @@ -1,13 +1,8 @@ #include "gray_stack.h" -#include <assert.h> #include <stdlib.h> -#include "gc_state.h" - QCGC_STATIC size_t gray_stack_size(size_t size); -QCGC_STATIC gray_stack_t *gray_stack_grow(gray_stack_t *stack); -QCGC_STATIC gray_stack_t *gray_stack_shrink(gray_stack_t *stack); gray_stack_t *qcgc_gray_stack_create(size_t size) { gray_stack_t *result = (gray_stack_t *) malloc(gray_stack_size(size)); @@ -16,44 +11,17 @@ return result; } -gray_stack_t *qcgc_gray_stack_push(gray_stack_t *stack, object_t *item) { - if (stack->size == stack->index) { - stack = gray_stack_grow(stack); - } - stack->items[stack->index] = item; - stack->index++; - qcgc_state.gray_stack_size++; - return stack; -} - -object_t *qcgc_gray_stack_top(gray_stack_t *stack) { -#if CHECKED - assert(stack->index != 0); -#endif - return stack->items[stack->index - 1]; -} - -gray_stack_t *qcgc_gray_stack_pop(gray_stack_t *stack) { - // TODO: Add lower bound for size (config.h) - if (stack->index < stack->size / 4) { - stack = gray_stack_shrink(stack); - } - stack->index--; - qcgc_state.gray_stack_size--; - return stack; -} - QCGC_STATIC size_t gray_stack_size(size_t size) { return (sizeof(gray_stack_t) + size * sizeof(object_t *)); } -QCGC_STATIC gray_stack_t *gray_stack_grow(gray_stack_t *stack) { +gray_stack_t *gray_stack_grow(gray_stack_t *stack) { stack = (gray_stack_t *) realloc(stack, gray_stack_size(stack->size * 2)); stack->size *= 2; return stack; } -QCGC_STATIC gray_stack_t *gray_stack_shrink(gray_stack_t *stack) { +gray_stack_t *gray_stack_shrink(gray_stack_t *stack) { stack = (gray_stack_t *) realloc(stack, gray_stack_size(stack->size / 2)); stack->size /= 2; return stack; diff --git a/rpython/translator/c/src/qcgc/src/gray_stack.h b/rpython/translator/c/src/qcgc/src/gray_stack.h --- a/rpython/translator/c/src/qcgc/src/gray_stack.h +++ b/rpython/translator/c/src/qcgc/src/gray_stack.h @@ -12,9 +12,35 @@ gray_stack_t *qcgc_gray_stack_create(size_t size); __attribute__ ((warn_unused_result)) -gray_stack_t *qcgc_gray_stack_push(gray_stack_t *stack, object_t *item); - -object_t *qcgc_gray_stack_top(gray_stack_t *stack); +gray_stack_t *gray_stack_grow(gray_stack_t *stack); __attribute__ ((warn_unused_result)) -gray_stack_t *qcgc_gray_stack_pop(gray_stack_t *stack); +gray_stack_t *gray_stack_shrink(gray_stack_t *stack); + +__attribute__ ((warn_unused_result)) +QCGC_STATIC QCGC_INLINE gray_stack_t *qcgc_gray_stack_push( + gray_stack_t *stack, object_t *item) { + if (stack->size == stack->index) { + stack = gray_stack_grow(stack); + } + stack->items[stack->index] = item; + stack->index++; + return stack; +} + +QCGC_STATIC QCGC_INLINE object_t *qcgc_gray_stack_top(gray_stack_t *stack) { +#if CHECKED + assert(stack->index != 0); +#endif + return stack->items[stack->index - 1]; +} + +__attribute__ ((warn_unused_result)) +QCGC_STATIC QCGC_INLINE gray_stack_t *qcgc_gray_stack_pop(gray_stack_t *stack) { + // TODO: Add lower bound for size (config.h) + if (stack->index < stack->size / 4) { + stack = gray_stack_shrink(stack); + } + stack->index--; + return stack; +} _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit