Skip to content

Commit

Permalink
add yp_alloc to begin creating our own allocator
Browse files Browse the repository at this point in the history
  • Loading branch information
HParker committed Sep 5, 2023
1 parent 49cca88 commit 068c475
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 19 deletions.
3 changes: 3 additions & 0 deletions include/yarp/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "yarp/util/yp_list.h"
#include "yarp/util/yp_newline_list.h"
#include "yarp/util/yp_state_stack.h"
#include "yarp/util/yp_alloc.h"

#include <stdbool.h>

Expand Down Expand Up @@ -316,6 +317,8 @@ struct yp_parser {
size_t index; // the current index into the lexer mode stack
} lex_modes;

yp_allocator_t allocator;

const uint8_t *start; // the pointer to the start of the source
const uint8_t *end; // the pointer to the end of the source
yp_token_t previous; // the previous token we were considering
Expand Down
38 changes: 38 additions & 0 deletions include/yarp/util/yp_alloc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#ifndef YARP_ALLOC_H
#define YARP_ALLOC_H

#include <stdbool.h>
#include <stdlib.h>

typedef struct yp_memory_pool {
size_t capacity;
size_t size;
char *memory;
struct yp_memory_pool *prev;
} yp_memory_pool_t;

typedef struct yp_allocator {
size_t capacity;
size_t size;
size_t pool_count;
yp_memory_pool_t *pool;

yp_memory_pool_t *large_pool;
} yp_allocator_t;

void *
yp_malloc(yp_allocator_t *allocator, size_t size);

void *
yp_calloc(yp_allocator_t *allocator, size_t num, size_t size);

void
yp_free(yp_allocator_t *allocator, void *ptr);

void
yp_allocator_init(yp_allocator_t *allocator, size_t size);

void
yp_allocator_free(yp_allocator_t *allocator);

#endif // YARP_ALLOC_H
133 changes: 133 additions & 0 deletions src/util/yp_alloc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#include <assert.h>
#include "yarp/defines.h"
#include "yarp/util/yp_alloc.h"

#define DEFAULT_POOL_SIZE 16384
#define USE_ARENA 1

yp_memory_pool_t *
yp_memory_pool_init(size_t capacity) {
yp_memory_pool_t * pool = malloc(sizeof(yp_memory_pool_t));
pool->capacity = capacity;
pool->size = 0;
pool->prev = NULL;
pool->memory = malloc(capacity);
return pool;
}

void
yp_ensure_available_memory(yp_allocator_t *allocator, size_t size) {
if (allocator->pool->size + size >= allocator->pool->capacity) {
allocator->pool_count++;

yp_memory_pool_t *prev_pool = allocator->pool;
allocator->pool = yp_memory_pool_init(DEFAULT_POOL_SIZE);
allocator->pool->prev = prev_pool;
}
}

void *
yp_malloc(yp_allocator_t *allocator, size_t size) {
size = (size + 7) & ~7UL;

if (USE_ARENA) {
if (size >= DEFAULT_POOL_SIZE) {
yp_memory_pool_t *large_pool = yp_memory_pool_init(size + 1);
if (allocator->large_pool == NULL) {
allocator->large_pool = large_pool;
} else {
yp_memory_pool_t *prev_pool = allocator->large_pool;
allocator->large_pool = large_pool;
allocator->large_pool->prev = prev_pool;
}
return large_pool->memory;
} else {
yp_ensure_available_memory(allocator, size);

void *ptr = allocator->pool->memory + allocator->pool->size;
allocator->pool->size += size;

return ptr;
}
} else {
return malloc(size);
}
}

void *
yp_calloc(yp_allocator_t *allocator, size_t num, size_t size) {
if (USE_ARENA) {
if (num * size < size) {
return NULL;
}
void *ptr = yp_malloc(allocator, num * size);
memset(ptr, 0, num * size);
return ptr;
} else {
return calloc(num, size);
}
}

void
yp_free(yp_allocator_t *allocator, void *ptr) {
if (USE_ARENA) {
// NO OP
#ifdef YARP_DEBUG_MODE_BUILD
bool found = false;
yp_memory_pool_t *pool = allocator->pool;

while (pool != NULL) {
yp_memory_pool_t *prev = pool->prev;
if (found == false && (char *)ptr >= pool->memory && (char *)ptr < pool->memory + pool->size) {
found = true;
}
pool = prev;
}

pool = allocator->large_pool;

while (pool != NULL) {
yp_memory_pool_t *prev = pool->prev;
if (found == false && (char *)ptr >= pool->memory && (char *)ptr < pool->memory + pool->size) {
found = true;
}
pool = prev;
}
assert(found);
#else
(void)allocator;
#endif // YARP_DEBUG_MODE_BUILD
} else {
free(ptr);
}
}

void
yp_allocator_init(yp_allocator_t *allocator, size_t capacity) {
(void)capacity;
allocator->pool_count = 0;
allocator->pool = yp_memory_pool_init(DEFAULT_POOL_SIZE);
allocator->large_pool = NULL;
}

void
yp_allocator_free(yp_allocator_t *allocator) {
(void)allocator;
yp_memory_pool_t *pool = allocator->pool;

while (pool != NULL) {
yp_memory_pool_t *prev = pool->prev;
free(pool->memory);
free(pool);
pool = prev;
}

pool = allocator->large_pool;

while (pool != NULL) {
yp_memory_pool_t *prev = pool->prev;
free(pool->memory);
free(pool);
pool = prev;
}
}
39 changes: 21 additions & 18 deletions src/yarp.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ lex_mode_push(yp_parser_t *parser, yp_lex_mode_t lex_mode) {
parser->lex_modes.index++;

if (parser->lex_modes.index > YP_LEX_STACK_SIZE - 1) {
parser->lex_modes.current = (yp_lex_mode_t *) malloc(sizeof(yp_lex_mode_t));
parser->lex_modes.current = (yp_lex_mode_t *) yp_malloc(&parser->allocator, sizeof(yp_lex_mode_t));
if (parser->lex_modes.current == NULL) return false;

*parser->lex_modes.current = lex_mode;
Expand Down Expand Up @@ -342,7 +342,7 @@ lex_mode_pop(yp_parser_t *parser) {
} else {
parser->lex_modes.index--;
yp_lex_mode_t *prev = parser->lex_modes.current->prev;
free(parser->lex_modes.current);
yp_free(&parser->allocator, parser->lex_modes.current);
parser->lex_modes.current = prev;
}
}
Expand Down Expand Up @@ -622,7 +622,7 @@ parse_decimal_number(yp_parser_t *parser, const uint8_t *start, const uint8_t *e
assert(diff > 0 && ((unsigned long) diff < SIZE_MAX));
size_t length = (size_t) diff;

char *digits = calloc(length + 1, sizeof(char));
char *digits = yp_calloc(&parser->allocator, length + 1, sizeof(char));
memcpy(digits, start, length);
digits[length] = '\0';

Expand All @@ -635,7 +635,7 @@ parse_decimal_number(yp_parser_t *parser, const uint8_t *start, const uint8_t *e
value = UINT32_MAX;
}

free(digits);
yp_free(&parser->allocator, digits);

if (value > UINT32_MAX) {
yp_diagnostic_list_append(&parser->error_list, start, end, "invalid decimal number");
Expand Down Expand Up @@ -681,7 +681,7 @@ yp_statements_node_body_append(yp_statements_node_t *node, yp_node_t *statement)
// implement our own arena allocation.
static inline void *
yp_alloc_node(YP_ATTRIBUTE_UNUSED yp_parser_t *parser, size_t size) {
void *memory = calloc(1, size);
void *memory = yp_calloc(&parser->allocator, 1, size);
if (memory == NULL) {
fprintf(stderr, "Failed to allocate %zu bytes\n", size);
abort();
Expand Down Expand Up @@ -1495,7 +1495,7 @@ yp_call_and_write_node_create(yp_parser_t *parser, yp_call_node_t *target, const
// Here we're going to free the target, since it is no longer necessary.
// However, we don't want to call `yp_node_destroy` because we want to keep
// around all of its children since we just reused them.
free(target);
yp_free(&parser->allocator, target);

return node;
}
Expand Down Expand Up @@ -1533,7 +1533,7 @@ yp_call_operator_write_node_create(yp_parser_t *parser, yp_call_node_t *target,
// Here we're going to free the target, since it is no longer necessary.
// However, we don't want to call `yp_node_destroy` because we want to keep
// around all of its children since we just reused them.
free(target);
yp_free(&parser->allocator, target);

return node;
}
Expand Down Expand Up @@ -1571,7 +1571,7 @@ yp_call_or_write_node_create(yp_parser_t *parser, yp_call_node_t *target, const
// Here we're going to free the target, since it is no longer necessary.
// However, we don't want to call `yp_node_destroy` because we want to keep
// around all of its children since we just reused them.
free(target);
yp_free(&parser->allocator, target);

return node;
}
Expand Down Expand Up @@ -4232,7 +4232,7 @@ yp_string_node_to_symbol_node(yp_parser_t *parser, yp_string_node_t *node, const
// We are explicitly _not_ using yp_node_destroy here because we don't want
// to trash the unescaped string. We could instead copy the string if we
// know that it is owned, but we're taking the fast path for now.
free(node);
yp_free(&parser->allocator, node);

return new_node;
}
Expand All @@ -4256,7 +4256,7 @@ yp_symbol_node_to_string_node(yp_parser_t *parser, yp_symbol_node_t *node) {
// We are explicitly _not_ using yp_node_destroy here because we don't want
// to trash the unescaped string. We could instead copy the string if we
// know that it is owned, but we're taking the fast path for now.
free(node);
yp_free(&parser->allocator, node);

return new_node;
}
Expand Down Expand Up @@ -4563,7 +4563,7 @@ yp_yield_node_create(yp_parser_t *parser, const yp_token_t *keyword, const yp_lo
// Allocate and initialize a new scope. Push it onto the scope stack.
static bool
yp_parser_scope_push(yp_parser_t *parser, bool closed) {
yp_scope_t *scope = (yp_scope_t *) malloc(sizeof(yp_scope_t));
yp_scope_t *scope = (yp_scope_t *) yp_malloc(&parser->allocator, sizeof(yp_scope_t));
if (scope == NULL) return false;

*scope = (yp_scope_t) { .closed = closed, .previous = parser->current_scope };
Expand Down Expand Up @@ -4630,7 +4630,7 @@ static void
yp_parser_scope_pop(yp_parser_t *parser) {
yp_scope_t *scope = parser->current_scope;
parser->current_scope = scope->previous;
free(scope);
yp_free(&parser->allocator, scope);
}

/******************************************************************************/
Expand Down Expand Up @@ -5036,7 +5036,7 @@ context_recoverable(yp_parser_t *parser, yp_token_t *token) {

static bool
context_push(yp_parser_t *parser, yp_context_t context) {
yp_context_node_t *context_node = (yp_context_node_t *) malloc(sizeof(yp_context_node_t));
yp_context_node_t *context_node = (yp_context_node_t *) yp_malloc(&parser->allocator, sizeof(yp_context_node_t));
if (context_node == NULL) return false;

*context_node = (yp_context_node_t) { .context = context, .prev = NULL };
Expand All @@ -5054,7 +5054,7 @@ context_push(yp_parser_t *parser, yp_context_t context) {
static void
context_pop(yp_parser_t *parser) {
yp_context_node_t *prev = parser->current_context->prev;
free(parser->current_context);
yp_free(&parser->allocator, parser->current_context);
parser->current_context = prev;
}

Expand Down Expand Up @@ -5762,7 +5762,7 @@ parser_lex_callback(yp_parser_t *parser) {
// Return a new comment node of the specified type.
static inline yp_comment_t *
parser_comment(yp_parser_t *parser, yp_comment_type_t type) {
yp_comment_t *comment = (yp_comment_t *) malloc(sizeof(yp_comment_t));
yp_comment_t *comment = (yp_comment_t *) yp_malloc(&parser->allocator, sizeof(yp_comment_t));
if (comment == NULL) return NULL;

*comment = (yp_comment_t) {
Expand Down Expand Up @@ -13796,6 +13796,8 @@ yp_parser_init(yp_parser_t *parser, const uint8_t *source, size_t size, const ch
.newline_list = YP_NEWLINE_LIST_EMPTY
};

yp_allocator_init(&parser->allocator, 0);

yp_accepts_block_stack_push(parser, true);

// Initialize the constant pool. We're going to completely guess as to the
Expand Down Expand Up @@ -13856,14 +13858,14 @@ yp_parser_register_encoding_decode_callback(yp_parser_t *parser, yp_encoding_dec

// Free all of the memory associated with the comment list.
static inline void
yp_comment_list_free(yp_list_t *list) {
yp_comment_list_free(yp_allocator_t *allocator, yp_list_t *list) {
yp_list_node_t *node, *next;

for (node = list->head; node != NULL; node = next) {
next = node->next;

yp_comment_t *comment = (yp_comment_t *) node;
free(comment);
yp_free(allocator, comment);
}
}

Expand All @@ -13873,9 +13875,10 @@ yp_parser_free(yp_parser_t *parser) {
yp_string_free(&parser->filepath_string);
yp_diagnostic_list_free(&parser->error_list);
yp_diagnostic_list_free(&parser->warning_list);
yp_comment_list_free(&parser->comment_list);
yp_comment_list_free(&parser->allocator, &parser->comment_list);
yp_constant_pool_free(&parser->constant_pool);
yp_newline_list_free(&parser->newline_list);
yp_allocator_free(&parser->allocator);

while (parser->lex_modes.index >= YP_LEX_STACK_SIZE) {
lex_mode_pop(parser);
Expand Down
2 changes: 1 addition & 1 deletion templates/src/node.c.erb
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) {
assert(false && "unreachable");
break;
}
free(node);
yp_free(&parser->allocator, node);
}

static void
Expand Down
2 changes: 2 additions & 0 deletions yarp.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Gem::Specification.new do |spec|
"include/yarp/regexp.h",
"include/yarp/unescape.h",
"include/yarp/util/yp_buffer.h",
"include/yarp/util/yp_alloc.h",
"include/yarp/util/yp_char.h",
"include/yarp/util/yp_constant_pool.h",
"include/yarp/util/yp_list.h",
Expand Down Expand Up @@ -83,6 +84,7 @@ Gem::Specification.new do |spec|
"src/token_type.c",
"src/unescape.c",
"src/util/yp_buffer.c",
"src/util/yp_alloc.c",
"src/util/yp_char.c",
"src/util/yp_constant_pool.c",
"src/util/yp_list.c",
Expand Down

0 comments on commit 068c475

Please sign in to comment.