From b2300278c007a1d2ccdbe5426280150687c19a1e Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 26 Jun 2024 10:58:23 -0400 Subject: [PATCH 01/10] An arena allocator --- include/prism/allocator.h | 40 ++++++++++++++ include/prism/parser.h | 3 ++ src/allocator.c | 107 ++++++++++++++++++++++++++++++++++++++ src/prism.c | 20 ++----- templates/src/node.c.erb | 2 +- 5 files changed, 156 insertions(+), 16 deletions(-) create mode 100644 include/prism/allocator.h create mode 100644 src/allocator.c diff --git a/include/prism/allocator.h b/include/prism/allocator.h new file mode 100644 index 0000000000..6288d0029f --- /dev/null +++ b/include/prism/allocator.h @@ -0,0 +1,40 @@ +# /** + * @file allocator.h + * + * An arena allocator. + */ +#ifndef PRISM_ALLOCATOR_H +#define PRISM_ALLOCATOR_H + +#include "prism/defines.h" +#include +#include + +typedef struct pm_allocator { + struct pm_allocator *next; + char *start; + char *current; + char *end; +} pm_allocator_t; + +/** + * Initialize an allocator with the given capacity. + */ +void pm_allocator_init(pm_allocator_t *allocator, size_t capacity); + +/** + * Allocate memory from the given allocator. + */ +void * pm_allocator_alloc(pm_allocator_t *allocator, size_t size, size_t alignment); + +/** + * Allocate memory from the given allocator and zero out the memory. + */ +void * pm_allocator_calloc(pm_allocator_t *allocator, size_t count, size_t size, size_t alignment); + +/** + * Frees the internal memory associated with the allocator. + */ +void pm_allocator_free(pm_allocator_t *allocator); + +#endif diff --git a/include/prism/parser.h b/include/prism/parser.h index 992729d655..df6b16dbc7 100644 --- a/include/prism/parser.h +++ b/include/prism/parser.h @@ -7,6 +7,7 @@ #define PRISM_PARSER_H #include "prism/defines.h" +#include "prism/allocator.h" #include "prism/ast.h" #include "prism/encoding.h" #include "prism/options.h" @@ -644,6 +645,8 @@ struct pm_parser { * but the node can be found through another parse. */ uint32_t node_id; + /** The allocator used to allocate nodes and their fields. */ + pm_allocator_t allocator; /** The current state of the lexer. */ pm_lex_state_t lex_state; diff --git a/src/allocator.c b/src/allocator.c new file mode 100644 index 0000000000..a1cb7619b6 --- /dev/null +++ b/src/allocator.c @@ -0,0 +1,107 @@ +#include "prism/allocator.h" + +#define PM_ALLOCATOR_CAPACITY_DEFAULT 4096 + +/** + * Initialize an allocator with the given capacity. + */ +void +pm_allocator_init(pm_allocator_t *allocator, size_t capacity) { + char *memory = malloc(capacity); + if (memory == NULL) { + fprintf(stderr, "[pm_allocator_init] failed to allocate memory\n"); + abort(); + } + + *allocator = (pm_allocator_t) { + .next = NULL, + .start = memory, + .current = memory, + .end = memory + capacity + }; +} + +/** + * Allocate memory from the given allocator. + */ +void * +pm_allocator_alloc(pm_allocator_t *allocator, size_t size, size_t alignment) { + assert(size > 0); + + char *result = allocator->current; + uintptr_t delta = 0; + uintptr_t current = (uintptr_t) allocator->current; + if (current % alignment != 0) { + delta = alignment - (current % alignment); + } + result += delta; + + char *next = result + size; + + if (next >= allocator->end) { + size_t next_capacity = PM_ALLOCATOR_CAPACITY_DEFAULT; + + // In case the requested size is larger than our default capacity, scale + // up just this node in the linked list to fit the allocation. + if (size > next_capacity) next_capacity = size; + + char *next_allocator_memory = malloc(sizeof(pm_allocator_t) + next_capacity); + if (next_allocator_memory == NULL) { + fprintf(stderr, "[pm_allocator_alloc] failed to allocate memory\n"); + abort(); + } + + pm_allocator_t *next_allocator = (pm_allocator_t *) next_allocator_memory; + char *start = next_allocator_memory + sizeof(pm_allocator_t); + + // Assume the alignment is correct because malloc should give us back + // the most relaxed alignment possible. + assert(((uintptr_t) start) % alignment == 0); + + *next_allocator = (pm_allocator_t) { + .next = NULL, + .start = start, + .current = NULL, // set at the end + .end = start + next_capacity + }; + + allocator->next = next_allocator; + allocator = next_allocator; + + result = allocator->start; + next = next_allocator->current + size; + } + + allocator->current = next; + return result; +} + +/** + * Allocate memory from the given allocator and zero out the memory. + */ +void * +pm_allocator_calloc(pm_allocator_t *allocator, size_t count, size_t size, size_t alignment) { + assert(size > 0); + + size_t product = count * size; + assert(product / size == count); + + void *memory = pm_allocator_alloc(allocator, product, alignment); + memset(memory, 0, product); + + return memory; +} + +/** + * Frees the internal memory associated with the allocator. + */ +void pm_allocator_free(pm_allocator_t *allocator) { + for (pm_allocator_t *current = allocator; current != NULL;) { + if (current->end != current->start) free(current->start); + + pm_allocator_t *previous = current; + current = current->next; + + if (previous != allocator) free(previous); + } +} diff --git a/src/prism.c b/src/prism.c index b01f4df6dd..7308b706e2 100644 --- a/src/prism.c +++ b/src/prism.c @@ -1904,22 +1904,8 @@ pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, static size_t pm_statements_node_body_length(pm_statements_node_t *node); -/** - * This function is here to allow us a place to extend in the future when we - * implement our own arena allocation. - */ -static inline void * -pm_node_alloc(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) { - void *memory = xcalloc(1, size); - if (memory == NULL) { - fprintf(stderr, "Failed to allocate %d bytes\n", (int) size); - abort(); - } - return memory; -} - -#define PM_NODE_ALLOC(parser, type) (type *) pm_node_alloc(parser, sizeof(type)) #define PM_NODE_IDENTIFY(parser) (++parser->node_id) +#define PM_NODE_ALLOC(parser, type) (type *) pm_allocator_calloc(&parser->allocator, 1, sizeof(type), sizeof(void *)) /** * Allocate a new MissingNode node. @@ -22110,6 +22096,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm *parser = (pm_parser_t) { .node_id = 0, + .allocator = { 0 }, .lex_state = PM_LEX_STATE_BEG, .enclosure_nesting = 0, .lambda_enclosure_nesting = -1, @@ -22161,6 +22148,9 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm .warn_mismatched_indentation = true }; + // TODO: find a better starting size + pm_allocator_init(&parser->allocator, 4096); + // Initialize the constant pool. We're going to completely guess as to the // number of constants that we'll need based on the size of the input. The // ratio we chose here is actually less arbitrary than you might think. diff --git a/templates/src/node.c.erb b/templates/src/node.c.erb index 2357e55200..c2e75549f3 100644 --- a/templates/src/node.c.erb +++ b/templates/src/node.c.erb @@ -140,7 +140,7 @@ pm_node_destroy(pm_parser_t *parser, pm_node_t *node) { assert(false && "unreachable"); break; } - xfree(node); + // xfree(node); } /** From 5b78702fad1b2c5e020216b41c16345b896c93e8 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 26 Jun 2024 13:11:54 -0400 Subject: [PATCH 02/10] Temporary --- include/prism/allocator.h | 27 +++- include/prism/node.h | 14 +-- include/prism/parser.h | 9 ++ src/allocator.c | 104 +++++++++++---- src/prism.c | 259 +++++++++++++++++++++----------------- templates/src/node.c.erb | 44 +++---- 6 files changed, 270 insertions(+), 187 deletions(-) diff --git a/include/prism/allocator.h b/include/prism/allocator.h index 6288d0029f..8f38b1e779 100644 --- a/include/prism/allocator.h +++ b/include/prism/allocator.h @@ -8,13 +8,19 @@ #include "prism/defines.h" #include +#include #include -typedef struct pm_allocator { +typedef struct pm_allocator_page { struct pm_allocator *next; char *start; char *current; char *end; +} pm_allocator_page_t; + +typedef struct pm_allocator { + pm_allocator_page_t head; + pm_allocator_page_t *tail; } pm_allocator_t; /** @@ -22,15 +28,30 @@ typedef struct pm_allocator { */ void pm_allocator_init(pm_allocator_t *allocator, size_t capacity); +/** + * Retrieve a scratch allocator with the given capacity. + */ +pm_allocator_t pm_allocator_scratch(size_t capacity); + /** * Allocate memory from the given allocator. */ -void * pm_allocator_alloc(pm_allocator_t *allocator, size_t size, size_t alignment); +void * pm_allocator_arena_alloc(pm_allocator_t *allocator, size_t size, size_t alignment); /** * Allocate memory from the given allocator and zero out the memory. */ -void * pm_allocator_calloc(pm_allocator_t *allocator, size_t count, size_t size, size_t alignment); +void * pm_allocator_arena_calloc(pm_allocator_t *allocator, size_t count, size_t size, size_t alignment); + +/** + * Retrieve a pointer to the next slot that would be allocated. + */ +void * pm_allocator_current(pm_allocator_t *allocator); + +/** + * Reset the allocator back to the given slot. + */ +void pm_allocator_reset(pm_allocator_t *allocator, void *current); /** * Frees the internal memory associated with the allocator. diff --git a/include/prism/node.h b/include/prism/node.h index e8686a327c..0f11a7f478 100644 --- a/include/prism/node.h +++ b/include/prism/node.h @@ -7,6 +7,7 @@ #define PRISM_NODE_H #include "prism/defines.h" +#include "prism/allocator.h" #include "prism/parser.h" #include "prism/util/pm_buffer.h" @@ -23,7 +24,7 @@ * @param list The list to append to. * @param node The node to append. */ -void pm_node_list_append(pm_node_list_t *list, pm_node_t *node); +void pm_node_list_append(pm_allocator_t *allocator, pm_node_list_t *list, pm_node_t *node); /** * Prepend a new node onto the beginning of the node list. @@ -31,7 +32,7 @@ void pm_node_list_append(pm_node_list_t *list, pm_node_t *node); * @param list The list to prepend to. * @param node The node to prepend. */ -void pm_node_list_prepend(pm_node_list_t *list, pm_node_t *node); +void pm_node_list_prepend(pm_allocator_t *allocator, pm_node_list_t *list, pm_node_t *node); /** * Concatenate the given node list onto the end of the other node list. @@ -39,14 +40,7 @@ void pm_node_list_prepend(pm_node_list_t *list, pm_node_t *node); * @param list The list to concatenate onto. * @param other The list to concatenate. */ -void pm_node_list_concat(pm_node_list_t *list, pm_node_list_t *other); - -/** - * Free the internal memory associated with the given node list. - * - * @param list The list to free. - */ -void pm_node_list_free(pm_node_list_t *list); +void pm_node_list_concat(pm_allocator_t *allocator, pm_node_list_t *list, pm_node_list_t *other); /** * Deallocate a node and all of its children. diff --git a/include/prism/parser.h b/include/prism/parser.h index df6b16dbc7..8e1517e73d 100644 --- a/include/prism/parser.h +++ b/include/prism/parser.h @@ -582,6 +582,12 @@ typedef struct pm_scope { /** A pointer to the previous scope in the linked list. */ struct pm_scope *previous; + /** + * This allocator is responsible for allocating the space for the list of + * the locals and the list of implicit parameters in the scope. + */ + pm_allocator_t allocator; + /** The IDs of the locals in the given scope. */ pm_locals_t locals; @@ -648,6 +654,9 @@ struct pm_parser { /** The allocator used to allocate nodes and their fields. */ pm_allocator_t allocator; + /** The allocator used to allocate lists of block exits. */ + pm_allocator_t block_exits_allocator; + /** The current state of the lexer. */ pm_lex_state_t lex_state; diff --git a/src/allocator.c b/src/allocator.c index a1cb7619b6..758ca9b0c4 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -7,30 +7,43 @@ */ void pm_allocator_init(pm_allocator_t *allocator, size_t capacity) { - char *memory = malloc(capacity); + char *memory = xmalloc(capacity); if (memory == NULL) { fprintf(stderr, "[pm_allocator_init] failed to allocate memory\n"); abort(); } *allocator = (pm_allocator_t) { - .next = NULL, - .start = memory, - .current = memory, - .end = memory + capacity + .head = { + .next = NULL, + .start = memory, + .current = memory, + .end = memory + capacity + }, + .tail = &allocator->head }; } +/** + * Retrieve a scratch allocator with the given capacity. + */ +pm_allocator_t +pm_allocator_scratch(size_t capacity) { + pm_allocator_t scratch = { 0 }; + pm_allocator_init(&scratch, capacity); + return scratch; +} + /** * Allocate memory from the given allocator. */ void * -pm_allocator_alloc(pm_allocator_t *allocator, size_t size, size_t alignment) { +pm_allocator_arena_alloc(pm_allocator_t *allocator, size_t size, size_t alignment) { assert(size > 0); - char *result = allocator->current; + char *result = allocator->tail->current; uintptr_t delta = 0; - uintptr_t current = (uintptr_t) allocator->current; + uintptr_t current = (uintptr_t) allocator->tail->current; if (current % alignment != 0) { delta = alignment - (current % alignment); } @@ -38,41 +51,41 @@ pm_allocator_alloc(pm_allocator_t *allocator, size_t size, size_t alignment) { char *next = result + size; - if (next >= allocator->end) { + if (next >= allocator->tail->end) { size_t next_capacity = PM_ALLOCATOR_CAPACITY_DEFAULT; // In case the requested size is larger than our default capacity, scale // up just this node in the linked list to fit the allocation. if (size > next_capacity) next_capacity = size; - char *next_allocator_memory = malloc(sizeof(pm_allocator_t) + next_capacity); + char *next_allocator_memory = xmalloc(sizeof(pm_allocator_page_t) + next_capacity); if (next_allocator_memory == NULL) { - fprintf(stderr, "[pm_allocator_alloc] failed to allocate memory\n"); + fprintf(stderr, "[pm_allocator_arena_alloc] failed to allocate memory\n"); abort(); } - pm_allocator_t *next_allocator = (pm_allocator_t *) next_allocator_memory; - char *start = next_allocator_memory + sizeof(pm_allocator_t); + pm_allocator_page_t *next_allocator_page = (pm_allocator_page_t *) next_allocator_memory; + char *start = next_allocator_memory + sizeof(pm_allocator_page_t); // Assume the alignment is correct because malloc should give us back // the most relaxed alignment possible. assert(((uintptr_t) start) % alignment == 0); - *next_allocator = (pm_allocator_t) { + *next_allocator_page = (pm_allocator_page_t) { .next = NULL, .start = start, .current = NULL, // set at the end .end = start + next_capacity }; - allocator->next = next_allocator; - allocator = next_allocator; + allocator->tail->next = next_allocator_page; + allocator->tail = next_allocator_page; - result = allocator->start; - next = next_allocator->current + size; + result = allocator->tail->start; + next = next_allocator_page->current + size; } - allocator->current = next; + allocator->tail->current = next; return result; } @@ -80,28 +93,65 @@ pm_allocator_alloc(pm_allocator_t *allocator, size_t size, size_t alignment) { * Allocate memory from the given allocator and zero out the memory. */ void * -pm_allocator_calloc(pm_allocator_t *allocator, size_t count, size_t size, size_t alignment) { +pm_allocator_arena_calloc(pm_allocator_t *allocator, size_t count, size_t size, size_t alignment) { assert(size > 0); size_t product = count * size; assert(product / size == count); - void *memory = pm_allocator_alloc(allocator, product, alignment); + void *memory = pm_allocator_arena_alloc(allocator, product, alignment); memset(memory, 0, product); return memory; } /** - * Frees the internal memory associated with the allocator. + * Retrieve a pointer to the next slot that would be allocated. */ -void pm_allocator_free(pm_allocator_t *allocator) { - for (pm_allocator_t *current = allocator; current != NULL;) { - if (current->end != current->start) free(current->start); +void * +pm_allocator_current(pm_allocator_t *allocator) { + return allocator->tail->current; +} + +static void +pm_allocator_page_free(pm_allocator_page_t *current) { + while (current != NULL) { + if (current->end != current->start) xfree(current->start); - pm_allocator_t *previous = current; + pm_allocator_page_t *previous = current; current = current->next; - if (previous != allocator) free(previous); + // If the memory block is immediately after the allocation of the + // allocator itself, then it came from pm_allocator_arena_alloc, so we + // should free it. Otherwise we assume it was embedded into another + // struct or allocated on the stack. + if (previous->start == ((char *) previous + sizeof(pm_allocator_t))) { + xfree(previous); + } } } + +/** + * Reset the allocator back to the given slot. + */ +void +pm_allocator_reset(pm_allocator_t *allocator, void *current) { + char *needle = current; + + for (pm_allocator_page_t *current = &allocator->head; current != NULL; current = current->next) { + if (needle >= current->start && needle <= current->end) { + current->current = needle; + pm_allocator_page_free(current->next); + return; + } + } + + assert(false && "[pm_allocator_reset] could not find reset point"); +} + +/** + * Frees the internal memory associated with the allocator. + */ +void pm_allocator_free(pm_allocator_t *allocator) { + pm_allocator_page_free(&allocator->head); +} diff --git a/src/prism.c b/src/prism.c index 7308b706e2..29d3f3933e 100644 --- a/src/prism.c +++ b/src/prism.c @@ -569,6 +569,7 @@ pm_parser_scope_push(pm_parser_t *parser, bool closed) { *scope = (pm_scope_t) { .previous = parser->current_scope, + .allocator = { 0 }, .locals = { 0 }, .parameters = PM_SCOPE_PARAMETERS_NONE, .implicit_parameters = { 0 }, @@ -576,6 +577,7 @@ pm_parser_scope_push(pm_parser_t *parser, bool closed) { .closed = closed }; + pm_allocator_init(&scope->allocator, 1024); parser->current_scope = scope; return true; } @@ -735,13 +737,6 @@ pm_parser_scope_shareable_constant_set(pm_parser_t *parser, pm_shareable_constan */ #define PM_LOCALS_HASH_THRESHOLD 9 -static void -pm_locals_free(pm_locals_t *locals) { - if (locals->capacity > 0) { - xfree(locals->locals); - } -} - /** * Use as simple and fast a hash function as we can that still properly mixes * the bits. @@ -759,12 +754,11 @@ pm_locals_hash(pm_constant_id_t name) { * above the threshold for switching to a hash, then we'll switch to a hash. */ static void -pm_locals_resize(pm_locals_t *locals) { +pm_locals_resize(pm_allocator_t *allocator, pm_locals_t *locals) { uint32_t next_capacity = locals->capacity == 0 ? 4 : (locals->capacity * 2); assert(next_capacity > locals->capacity); - pm_local_t *next_locals = xcalloc(next_capacity, sizeof(pm_local_t)); - if (next_locals == NULL) abort(); + pm_local_t *next_locals = pm_allocator_arena_calloc(allocator, next_capacity, sizeof(pm_local_t), sizeof(void *)); if (next_capacity < PM_LOCALS_HASH_THRESHOLD) { if (locals->size > 0) { @@ -789,7 +783,6 @@ pm_locals_resize(pm_locals_t *locals) { } } - pm_locals_free(locals); locals->locals = next_locals; locals->capacity = next_capacity; } @@ -810,9 +803,9 @@ pm_locals_resize(pm_locals_t *locals) { * @return True if the local was added, and false if the local already exists. */ static bool -pm_locals_write(pm_locals_t *locals, pm_constant_id_t name, const uint8_t *start, const uint8_t *end, uint32_t reads) { +pm_locals_write(pm_allocator_t *allocator, pm_locals_t *locals, pm_constant_id_t name, const uint8_t *start, const uint8_t *end, uint32_t reads) { if (locals->size >= (locals->capacity / 4 * 3)) { - pm_locals_resize(locals); + pm_locals_resize(allocator, locals); } if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) { @@ -1905,7 +1898,7 @@ static size_t pm_statements_node_body_length(pm_statements_node_t *node); #define PM_NODE_IDENTIFY(parser) (++parser->node_id) -#define PM_NODE_ALLOC(parser, type) (type *) pm_allocator_calloc(&parser->allocator, 1, sizeof(type), sizeof(void *)) +#define PM_NODE_ALLOC(parser, type) (type *) pm_allocator_arena_calloc(&parser->allocator, 1, sizeof(type), sizeof(void *)) /** * Allocate a new MissingNode node. @@ -2054,13 +2047,13 @@ pm_arguments_node_size(pm_arguments_node_t *node) { * Append an argument to an arguments node. */ static void -pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) { +pm_arguments_node_arguments_append(pm_parser_t *parser, pm_arguments_node_t *node, pm_node_t *argument) { if (pm_arguments_node_size(node) == 0) { node->base.location.start = argument->location.start; } node->base.location.end = argument->location.end; - pm_node_list_append(&node->arguments, argument); + pm_node_list_append(&parser->allocator, &node->arguments, argument); if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) { if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) { @@ -2097,12 +2090,12 @@ pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) { * Append an argument to an array node. */ static inline void -pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) { +pm_array_node_elements_append(pm_parser_t *parser, pm_array_node_t *node, pm_node_t *element) { if (!node->elements.size && !node->opening_loc.start) { node->base.location.start = element->location.start; } - pm_node_list_append(&node->elements, element); + pm_node_list_append(&parser->allocator, &node->elements, element); node->base.location.end = element->location.end; // If the element is not a static literal, then the array is not a static @@ -2161,9 +2154,9 @@ pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *node node->rest = child; found_rest = true; } else if (found_rest) { - pm_node_list_append(&node->posts, child); + pm_node_list_append(&parser->allocator, &node->posts, child); } else { - pm_node_list_append(&node->requireds, child); + pm_node_list_append(&parser->allocator, &node->requireds, child); } } @@ -2251,8 +2244,8 @@ pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *openin } static inline void -pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) { - pm_node_list_append(&node->requireds, inner); +pm_array_pattern_node_requireds_append(pm_parser_t *parser, pm_array_pattern_node_t *node, pm_node_t *inner) { + pm_node_list_append(&parser->allocator, &node->requireds, inner); } /** @@ -2564,8 +2557,8 @@ pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) * Append a new block-local variable to a BlockParametersNode node. */ static void -pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) { - pm_node_list_append(&node->locals, (pm_node_t *) local); +pm_block_parameters_node_append_local(pm_parser_t *parser, pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) { + pm_node_list_append(&parser->allocator, &node->locals, (pm_node_t *) local); if (node->base.location.start == NULL) node->base.location.start = local->base.location.start; node->base.location.end = local->base.location.end; @@ -2689,7 +2682,7 @@ pm_call_node_binary_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator); pm_arguments_node_t *arguments = pm_arguments_node_create(parser); - pm_arguments_node_arguments_append(arguments, argument); + pm_arguments_node_arguments_append(parser, arguments, argument); node->arguments = arguments; node->name = pm_parser_constant_id_token(parser, operator); @@ -2941,7 +2934,7 @@ pm_call_and_write_node_create(pm_parser_t *parser, pm_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 `pm_node_destroy` because we want to keep // around all of its children since we just reused them. - xfree(target); + // xfree(target); return node; } @@ -3003,7 +2996,7 @@ pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, cons // Here we're going to free the target, since it is no longer necessary. // However, we don't want to call `pm_node_destroy` because we want to keep // around all of its children since we just reused them. - xfree(target); + // xfree(target); return node; } @@ -3041,7 +3034,7 @@ pm_call_operator_write_node_create(pm_parser_t *parser, pm_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 `pm_node_destroy` because we want to keep // around all of its children since we just reused them. - xfree(target); + // xfree(target); return node; } @@ -3080,7 +3073,7 @@ pm_index_operator_write_node_create(pm_parser_t *parser, pm_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 `pm_node_destroy` because we want to keep // around all of its children since we just reused them. - xfree(target); + // xfree(target); return node; } @@ -3118,7 +3111,7 @@ pm_call_or_write_node_create(pm_parser_t *parser, pm_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 `pm_node_destroy` because we want to keep // around all of its children since we just reused them. - xfree(target); + // xfree(target); return node; } @@ -3157,7 +3150,7 @@ pm_index_or_write_node_create(pm_parser_t *parser, pm_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 `pm_node_destroy` because we want to keep // around all of its children since we just reused them. - xfree(target); + // xfree(target); return node; } @@ -3186,7 +3179,7 @@ pm_call_target_node_create(pm_parser_t *parser, pm_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 `pm_node_destroy` because we want to keep // around all of its children since we just reused them. - xfree(target); + // xfree(target); return node; } @@ -3220,7 +3213,7 @@ pm_index_target_node_create(pm_parser_t *parser, pm_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 `pm_node_destroy` because we want to keep // around all of its children since we just reused them. - xfree(target); + // xfree(target); return node; } @@ -3279,10 +3272,10 @@ pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node * Append a new condition to a CaseNode node. */ static void -pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) { +pm_case_node_condition_append(pm_parser_t *parser, pm_case_node_t *node, pm_node_t *condition) { assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE)); - pm_node_list_append(&node->conditions, condition); + pm_node_list_append(parser, &node->conditions, condition); node->base.location.end = condition->location.end; } @@ -3334,10 +3327,10 @@ pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, p * Append a new condition to a CaseMatchNode node. */ static void -pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) { +pm_case_match_node_condition_append(pm_parser_t *parser, pm_case_match_node_t *node, pm_node_t *condition) { assert(PM_NODE_TYPE_P(condition, PM_IN_NODE)); - pm_node_list_append(&node->conditions, condition); + pm_node_list_append(&parser->allocator, &node->conditions, condition); node->base.location.end = condition->location.end; } @@ -4070,7 +4063,7 @@ pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) { // much more efficient, as we could instead resize the node list to only point // to 1...-1. for (size_t index = 1; index < nodes->size - 1; index++) { - pm_node_list_append(&node->requireds, nodes->nodes[index]); + pm_node_list_append(&parser->allocator, &node->requireds, nodes->nodes[index]); } return node; @@ -4443,7 +4436,7 @@ pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *eleme pm_node_t *element; PM_NODE_LIST_FOREACH(elements, index, element) { - pm_node_list_append(&node->elements, element); + pm_node_list_append(&parser->allocator, &node->elements, element); } return node; @@ -4660,8 +4653,8 @@ pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) { * Append a new element to a hash node. */ static inline void -pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) { - pm_node_list_append(&hash->elements, element); +pm_hash_node_elements_append(pm_parser_t *parser, pm_hash_node_t *hash, pm_node_t *element) { + pm_node_list_append(&parser->allocator, &hash->elements, element); bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE); if (static_literal) { @@ -5134,7 +5127,7 @@ pm_instance_variable_write_node_create(pm_parser_t *parser, pm_instance_variable * literals. */ static void -pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) { +pm_interpolated_node_append(pm_parser_t *parser, pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) { switch (PM_NODE_TYPE(part)) { case PM_STRING_NODE: pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN); @@ -5169,7 +5162,7 @@ pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *p break; } - pm_node_list_append(parts, part); + pm_node_list_append(&parser->allocator, parts, part); } /** @@ -5198,7 +5191,7 @@ pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_tok } static inline void -pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) { +pm_interpolated_regular_expression_node_append(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, pm_node_t *part) { if (node->base.location.start > part->location.start) { node->base.location.start = part->location.start; } @@ -5206,7 +5199,7 @@ pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expressio node->base.location.end = part->location.end; } - pm_interpolated_node_append((pm_node_t *) node, &node->parts, part); + pm_interpolated_node_append(parser, (pm_node_t *) node, &node->parts, part); } static inline void @@ -5240,7 +5233,7 @@ pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_inte * which could potentially use a chilled string otherwise. */ static inline void -pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) { +pm_interpolated_string_node_append(pm_parser_t *parser, pm_interpolated_string_node_t *node, pm_node_t *part) { #define CLEAR_FLAGS(node) \ node->base.flags = (pm_node_flags_t) (node->base.flags & ~(PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE)) @@ -5309,7 +5302,7 @@ pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_ break; } - pm_node_list_append(&node->parts, part); + pm_node_list_append(&parser->allocator, &node->parts, part); #undef CLEAR_FLAGS #undef MUTABLE_FLAGS @@ -5367,12 +5360,12 @@ pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, con } static void -pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) { +pm_interpolated_symbol_node_append(pm_parser_t *parser, pm_interpolated_symbol_node_t *node, pm_node_t *part) { if (node->parts.size == 0 && node->opening_loc.start == NULL) { node->base.location.start = part->location.start; } - pm_interpolated_node_append((pm_node_t *) node, &node->parts, part); + pm_interpolated_node_append(parser, (pm_node_t *) node, &node->parts, part); node->base.location.end = MAX(node->base.location.end, part->location.end); } @@ -5439,8 +5432,8 @@ pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *openi } static inline void -pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) { - pm_interpolated_node_append((pm_node_t *) node, &node->parts, part); +pm_interpolated_xstring_node_append(pm_parser_t *parser, pm_interpolated_x_string_node_t *node, pm_node_t *part) { + pm_interpolated_node_append(parser, (pm_node_t *) node, &node->parts, part); node->base.location.end = part->location.end; } @@ -6036,7 +6029,7 @@ pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, // Explicitly do not call pm_node_destroy here because we want to keep // around all of the information within the MultiWriteNode node. - xfree(target); + // xfree(target); return node; } @@ -7461,7 +7454,7 @@ pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const // We are explicitly _not_ using pm_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. - xfree(node); + // xfree(node); return new_node; } @@ -7499,7 +7492,7 @@ pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) { // We are explicitly _not_ using pm_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. - xfree(node); + // xfree(node); return new_node; } @@ -7967,7 +7960,7 @@ pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) { */ static inline void pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) { - pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads); + pm_locals_write(&parser->current_scope->allocator, &parser->current_scope->locals, constant_id, start, end, reads); } /** @@ -8042,8 +8035,7 @@ static void pm_parser_scope_pop(pm_parser_t *parser) { pm_scope_t *scope = parser->current_scope; parser->current_scope = scope->previous; - pm_locals_free(&scope->locals); - pm_node_list_free(&scope->implicit_parameters); + pm_allocator_free(&scope->allocator); xfree(scope); } @@ -13651,7 +13643,7 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod pm_arguments_node_t *arguments = pm_arguments_node_create(parser); call->arguments = arguments; - pm_arguments_node_arguments_append(arguments, value); + pm_arguments_node_arguments_append(parser, arguments, value); call->base.location.end = arguments->base.location.end; parse_write_name(parser, &call->name); @@ -13669,7 +13661,7 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod call->arguments = pm_arguments_node_create(parser); } - pm_arguments_node_arguments_append(call->arguments, value); + pm_arguments_node_arguments_append(parser, call->arguments, value); target->location.end = value->location.end; // Replace the name with "[]=". @@ -14035,7 +14027,7 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod } if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) { - pm_hash_node_elements_append((pm_hash_node_t *) node, element); + pm_hash_node_elements_append(parser, (pm_hash_node_t *) node, element); } else { pm_keyword_hash_node_elements_append((pm_keyword_hash_node_t *) node, element); } @@ -14067,7 +14059,7 @@ parse_arguments_append(pm_parser_t *parser, pm_arguments_t *arguments, pm_node_t arguments->arguments = pm_arguments_node_create(parser); } - pm_arguments_node_arguments_append(arguments->arguments, argument); + pm_arguments_node_arguments_append(parser, arguments->arguments, argument); } /** @@ -15215,7 +15207,7 @@ parse_block_parameters( pm_block_local_variable_node_t *local = pm_block_local_variable_node_create(parser, &parser->previous); if (repeated) pm_node_flag_set_repeated_parameter((pm_node_t *) local); - pm_block_parameters_node_append_local(block_parameters, local); + pm_block_parameters_node_append_local(parser, block_parameters, local); } while (accept1(parser, PM_TOKEN_COMMA)); } } @@ -15464,7 +15456,7 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept if (arguments->arguments == NULL) { arguments->arguments = pm_arguments_node_create(parser); } - pm_arguments_node_arguments_append(arguments->arguments, arguments->block); + pm_arguments_node_arguments_append(parser, arguments->arguments, arguments->block); } arguments->block = (pm_node_t *) block; } @@ -15598,15 +15590,22 @@ parse_block_exit(pm_parser_t *parser, pm_node_t *node) { case PM_CONTEXT_SCLASS_RESCUE: // These are the bad cases. We're not allowed to have a block // exit in these contexts. - // - // If we get here, then we're about to mark this block exit - // as invalid. However, it could later _become_ valid if we - // find a trailing while/until on the expression. In this - // case instead of adding the error here, we'll add the - // block exit to the list of exits for the expression, and - // the node parsing will handle validating it instead. - assert(parser->current_block_exits != NULL); - pm_node_list_append(parser->current_block_exits, node); + + if (through_expression) { + // If we get here, then we're about to mark this block exit + // as invalid. However, it could later _become_ valid if we + // find a trailing while/until on the expression. In this + // case instead of adding the error here, we'll add the + // block exit to the list of exits for the expression, and + // the node parsing will handle validating it instead. + assert(parser->current_block_exits != NULL); + pm_node_list_append(&parser->block_exits_allocator, parser->current_block_exits, node); + } else { + // Otherwise, if we haven't gone through an expression + // context, then this is just invalid and we'll add the + // error here. + PM_PARSER_ERR_NODE_FORMAT(parser, node, PM_ERR_INVALID_BLOCK_EXIT, type); + } return; case PM_CONTEXT_BEGIN_ELSE: case PM_CONTEXT_BEGIN_ENSURE: @@ -15697,7 +15696,7 @@ pop_block_exits(pm_parser_t *parser, pm_node_list_t *previous_block_exits) { // However, they could still become valid in a higher level context if // there is another list above this one. In this case we'll push all of // the block exits up to the previous list. - pm_node_list_concat(previous_block_exits, parser->current_block_exits); + pm_node_list_concat(&parser->block_exits_allocator, previous_block_exits, parser->current_block_exits); parser->current_block_exits = previous_block_exits; } else { // If we did not match a trailing while/until and this was the last @@ -15731,6 +15730,7 @@ parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_contex static inline pm_node_t * parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newline_index, bool if_after_else, uint16_t depth) { + void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); pm_node_list_t current_block_exits = { 0 }; pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); @@ -15856,7 +15856,7 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl } pop_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); + pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); return parent; } @@ -16370,12 +16370,12 @@ parse_variable(pm_parser_t *parser) { } pm_node_t *node = (pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0, false); - pm_node_list_append(¤t_scope->implicit_parameters, node); + pm_node_list_append(¤t_scope->allocator, ¤t_scope->implicit_parameters, node); return node; } else if ((parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) && pm_token_is_it(parser->previous.start, parser->previous.end)) { pm_node_t *node = (pm_node_t *) pm_it_local_variable_read_node_create(parser, &parser->previous); - pm_node_list_append(¤t_scope->implicit_parameters, node); + pm_node_list_append(¤t_scope->allocator, ¤t_scope->implicit_parameters, node); return node; } @@ -16588,22 +16588,22 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1 // In that case we need to switch to an interpolated string to // be able to contain all of the parts. if (match1(parser, PM_TOKEN_STRING_CONTENT)) { + pm_allocator_t parts_allocator = pm_allocator_scratch(sizeof(pm_node_t *) * 4); pm_node_list_t parts = { 0 }; pm_token_t delimiters = not_provided(parser); pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped); - pm_node_list_append(&parts, part); + pm_node_list_append(&parts_allocator, &parts, part); do { part = (pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->current, &delimiters); - pm_node_list_append(&parts, part); + pm_node_list_append(&parts_allocator, &parts, part); parser_lex(parser); } while (match1(parser, PM_TOKEN_STRING_CONTENT)); expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF); node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); - - pm_node_list_free(&parts); + pm_allocator_free(&parts_allocator); } else if (accept1(parser, PM_TOKEN_LABEL_END)) { node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped, true)); if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL); @@ -16649,17 +16649,18 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1 } else { // If we get here, then we have interpolation so we'll need // to create a string or symbol node with interpolation. + pm_allocator_t parts_allocator = pm_allocator_scratch(sizeof(pm_node_t *) * 8); pm_node_list_t parts = { 0 }; pm_token_t string_opening = not_provided(parser); pm_token_t string_closing = not_provided(parser); pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->previous, &string_closing, &unescaped); pm_node_flag_set(part, parse_unescaped_encoding(parser)); - pm_node_list_append(&parts, part); + pm_node_list_append(&parts_allocator, &parts, part); while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) { if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) { - pm_node_list_append(&parts, part); + pm_node_list_append(&parts_allocator, &parts, part); } } @@ -16674,18 +16675,19 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1 node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); } - pm_node_list_free(&parts); + pm_allocator_free(&parts_allocator); } } else { // If we get here, then the first part of the string is not plain // string content, in which case we need to parse the string as an // interpolated string. + pm_allocator_t parts_allocator = pm_allocator_scratch(sizeof(pm_node_t *) * 8); pm_node_list_t parts = { 0 }; pm_node_t *part; while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) { if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) { - pm_node_list_append(&parts, part); + pm_node_list_append(&parts_allocator, &parts, part); } } @@ -16700,7 +16702,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1 node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); } - pm_node_list_free(&parts); + pm_allocator_free(&parts_allocator); } if (current == NULL) { @@ -16880,7 +16882,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures // attaching its constant. In this case we'll create an array pattern and // attach our constant to it. pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing); - pm_array_pattern_node_requireds_append(pattern_node, inner); + pm_array_pattern_node_requireds_append(parser, pattern_node, inner); return (pm_node_t *) pattern_node; } @@ -17220,7 +17222,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm } pm_array_pattern_node_t *node = pm_array_pattern_node_empty_create(parser, &opening, &closing); - pm_array_pattern_node_requireds_append(node, inner); + pm_array_pattern_node_requireds_append(parser, node, inner); return (pm_node_t *) node; } case PM_TOKEN_BRACE_LEFT: { @@ -18052,7 +18054,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } } - pm_array_node_elements_append(array, element); + pm_array_node_elements_append(parser, array, element); if (PM_NODE_TYPE_P(element, PM_MISSING_NODE)) break; } @@ -18073,6 +18075,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: { pm_token_t opening = parser->current; + void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); pm_node_list_t current_block_exits = { 0 }; pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); @@ -18085,7 +18088,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN); pop_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); + pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); return (pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->previous); } @@ -18117,7 +18120,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_accepts_block_stack_pop(parser); pop_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); + pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) { // If we have a single statement and are ending on a right @@ -18254,7 +18257,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } pop_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); + pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); pm_void_statements_check(parser, statements, true); return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous); @@ -18568,12 +18571,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // If we get here, then we have multiple parts in the heredoc, // so we'll need to create an interpolated string node to hold // them all. + pm_allocator_t parts_allocator = pm_allocator_scratch(sizeof(pm_node_t *) * 8); pm_node_list_t parts = { 0 }; - pm_node_list_append(&parts, part); + pm_node_list_append(&parts_allocator, &parts, part); while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) { if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) { - pm_node_list_append(&parts, part); + pm_node_list_append(&parts_allocator, &parts, part); } } @@ -18581,7 +18585,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // interpolated node. if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) { pm_interpolated_x_string_node_t *cast = pm_interpolated_xstring_node_create(parser, &opening, &opening); - cast->parts = parts; + cast->parts.nodes = pm_allocator_arena_alloc(&parser->allocator, sizeof(pm_node_t *) * parts.size, sizeof(pm_node_t *)); + cast->parts.size = parts.size; + cast->parts.capacity = parts.capacity; + memcpy(cast->parts.nodes, parts.size, sizeof(pm_node_t *) * parts.size); + pm_allocator_free(&parts_allocator); expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length); pm_interpolated_xstring_node_closing_set(cast, &parser->previous); @@ -18590,7 +18598,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b node = (pm_node_t *) cast; } else { pm_interpolated_string_node_t *cast = pm_interpolated_string_node_create(parser, &opening, &parts, &opening); - pm_node_list_free(&parts); + pm_allocator_free(&parts_allocator); expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length); pm_interpolated_string_node_closing_set(cast, &parser->previous); @@ -18701,6 +18709,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_token_t case_keyword = parser->previous; pm_node_t *predicate = NULL; + void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); pm_node_list_t current_block_exits = { 0 }; pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); @@ -18721,7 +18730,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pop_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); + pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS); return (pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->previous); @@ -18791,7 +18800,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } } - pm_case_node_condition_append(case_node, (pm_node_t *) when_node); + pm_case_node_condition_append(parser, case_node, (pm_node_t *) when_node); } // If we didn't parse any conditions (in or when) then we need @@ -18872,7 +18881,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // Now that we have the full pattern and statements, we can // create the node and attach it to the case node. pm_node_t *condition = (pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword); - pm_case_match_node_condition_append(case_node, condition); + pm_case_match_node_condition_append(parser, case_node, condition); } // If we didn't parse any conditions (in or when) then we need @@ -18912,7 +18921,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } pop_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); + pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); return node; } @@ -18923,6 +18932,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_token_t begin_keyword = parser->previous; accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); + void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); pm_node_list_t current_block_exits = { 0 }; pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); pm_statements_node_t *begin_statements = NULL; @@ -18942,7 +18952,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_begin_node_end_keyword_set(begin_node, &parser->previous); pop_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); + pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); return (pm_node_t *) begin_node; } @@ -19098,6 +19108,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b return (pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &operator, expression, statements, &parser->previous); } + void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); + pm_node_list_t current_block_exits = { 0 }; + pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); + pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1)); pm_token_t name = parser->previous; if (name.type != PM_TOKEN_CONSTANT) { @@ -19159,7 +19173,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } pop_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); + pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); return (pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->previous); } @@ -19659,6 +19673,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b return parse_conditional(parser, PM_CONTEXT_UNLESS, opening_newline_index, false, (uint16_t) (depth + 1)); } case PM_TOKEN_KEYWORD_MODULE: { + void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); pm_node_list_t current_block_exits = { 0 }; pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); @@ -19673,7 +19688,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // the name of the module, then we'll handle that here. if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) { pop_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); + pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); pm_token_t missing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end }; return (pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing); @@ -19722,7 +19737,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } pop_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); + pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); return (pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous); } @@ -19831,7 +19846,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (match1(parser, PM_TOKEN_STRING_CONTENT)) { pm_token_t opening = not_provided(parser); pm_token_t closing = not_provided(parser); - pm_array_node_elements_append(array, (pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->current, &closing)); + pm_array_node_elements_append(parser, array, (pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->current, &closing)); } expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT); @@ -19866,7 +19881,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } else { // If we hit a separator after we've hit content, then we need to // append that content to the list and reset the current node. - pm_array_node_elements_append(array, current); + pm_array_node_elements_append(parser, array, current); current = NULL; } @@ -19995,7 +20010,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // If we have a current node, then we need to append it to the list. if (current) { - pm_array_node_elements_append(array, current); + pm_array_node_elements_append(parser, array, current); } pm_token_t closing = parser->current; @@ -20026,7 +20041,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_token_t closing = not_provided(parser); pm_node_t *string = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->current, &closing); - pm_array_node_elements_append(array, string); + pm_array_node_elements_append(parser, array, string); } expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT); @@ -20066,7 +20081,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // If we hit a separator after we've hit content, // then we need to append that content to the list // and reset the current node. - pm_array_node_elements_append(array, current); + pm_array_node_elements_append(parser, array, current); current = NULL; } @@ -20176,7 +20191,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // If we have a current node, then we need to append it to the list. if (current) { - pm_array_node_elements_append(array, current); + pm_array_node_elements_append(parser, array, current); } pm_token_t closing = parser->current; @@ -20257,7 +20272,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING); } - pm_interpolated_regular_expression_node_append(interpolated, part); + pm_interpolated_regular_expression_node_append(parser, interpolated, part); } else { // If the first part of the body of the regular expression is not a // string content, then we have interpolation and we need to create an @@ -20271,6 +20286,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) { if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) { pm_interpolated_regular_expression_node_append(interpolated, part); + pm_interpolated_regular_expression_node_append(parser, interpolated, part); } } @@ -20336,7 +20352,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &parser->previous, &closing, &unescaped); pm_node_flag_set(part, parse_unescaped_encoding(parser)); - pm_interpolated_xstring_node_append(node, part); + pm_interpolated_xstring_node_append(parser, node, part); } else { // If the first part of the body of the string is not a string // content, then we have interpolation and we need to create an @@ -20347,7 +20363,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_t *part; while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) { if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) { - pm_interpolated_xstring_node_append(node, part); + pm_interpolated_xstring_node_append(parser, node, part); } } @@ -20684,13 +20700,13 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding pm_token_t opening = not_provided(parser); pm_array_node_t *array = pm_array_node_create(parser, &opening); - pm_array_node_elements_append(array, value); + pm_array_node_elements_append(parser, array, value); value = (pm_node_t *) array; while (accept1(parser, PM_TOKEN_COMMA)) { pm_node_t *element = parse_starred_expression(parser, binding_power, false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1)); - pm_array_node_elements_append(array, element); + pm_array_node_elements_append(parser, array, element); if (PM_NODE_TYPE_P(element, PM_MISSING_NODE)) break; parse_assignment_value_local(parser, element); @@ -21491,6 +21507,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t } case PM_TOKEN_QUESTION_MARK: { context_push(parser, PM_CONTEXT_TERNARY); + + void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); pm_node_list_t current_block_exits = { 0 }; pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); @@ -21511,7 +21529,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t context_pop(parser); pop_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); + pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression); } @@ -21524,7 +21542,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t context_pop(parser); pop_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); + pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression); } @@ -21647,7 +21665,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t if (arguments.arguments == NULL) { arguments.arguments = pm_arguments_node_create(parser); } - pm_arguments_node_arguments_append(arguments.arguments, arguments.block); + pm_arguments_node_arguments_append(parser, arguments.arguments, arguments.block); } arguments.block = (pm_node_t *) block; @@ -21906,6 +21924,7 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) { if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) { pm_arguments_node_t *arguments = pm_arguments_node_create(parser); pm_arguments_node_arguments_append( + parser, arguments, (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$_", 2)) ); @@ -21921,6 +21940,7 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) { if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) { pm_arguments_node_t *arguments = pm_arguments_node_create(parser); pm_arguments_node_arguments_append( + parser, arguments, (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$;", 2)) ); @@ -21939,6 +21959,7 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) { pm_arguments_node_t *arguments = pm_arguments_node_create(parser); pm_arguments_node_arguments_append( + parser, arguments, (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$/", 2)) ); @@ -21952,7 +21973,7 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) { (pm_node_t *) pm_true_node_synthesized_create(parser) )); - pm_arguments_node_arguments_append(arguments, (pm_node_t *) keywords); + pm_arguments_node_arguments_append(parser, arguments, (pm_node_t *) keywords); pm_node_flag_set((pm_node_t *) arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS); } @@ -22097,6 +22118,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm *parser = (pm_parser_t) { .node_id = 0, .allocator = { 0 }, + .block_exits_allocator = { 0 }, .lex_state = PM_LEX_STATE_BEG, .enclosure_nesting = 0, .lambda_enclosure_nesting = -1, @@ -22150,6 +22172,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm // TODO: find a better starting size pm_allocator_init(&parser->allocator, 4096); + pm_allocator_init(&parser->block_exits_allocator, 4096); // Initialize the constant pool. We're going to completely guess as to the // number of constants that we'll need based on the size of the input. The diff --git a/templates/src/node.c.erb b/templates/src/node.c.erb index c2e75549f3..276187c22c 100644 --- a/templates/src/node.c.erb +++ b/templates/src/node.c.erb @@ -7,8 +7,8 @@ * the list to be twice as large as it was before. If the reallocation fails, * this function returns false, otherwise it returns true. */ -static bool -pm_node_list_grow(pm_node_list_t *list, size_t size) { +static void +pm_node_list_grow(pm_allocator_t *allocator, pm_node_list_t *list, size_t size) { size_t requested_size = list->size + size; // If the requested size caused overflow, return false. @@ -32,58 +32,45 @@ pm_node_list_grow(pm_node_list_t *list, size_t size) { next_capacity = double_capacity; } - pm_node_t **nodes = (pm_node_t **) xrealloc(list->nodes, sizeof(pm_node_t *) * next_capacity); - if (nodes == NULL) return false; + pm_node_t **nodes = pm_allocator_arena_alloc(allocator, sizeof(pm_node_t *) * next_capacity, sizeof(pm_node_t *)); + memcpy(nodes, list->nodes, list->size * sizeof(pm_node_t *)); list->nodes = nodes; list->capacity = next_capacity; - return true; } /** * Append a new node onto the end of the node list. */ void -pm_node_list_append(pm_node_list_t *list, pm_node_t *node) { - if (pm_node_list_grow(list, 1)) { - list->nodes[list->size++] = node; - } +pm_node_list_append(pm_allocator_t *allocator, pm_node_list_t *list, pm_node_t *node) { + pm_node_list_grow(allocator, list, 1); + list->nodes[list->size++] = node; } /** * Prepend a new node onto the beginning of the node list. */ void -pm_node_list_prepend(pm_node_list_t *list, pm_node_t *node) { - if (pm_node_list_grow(list, 1)) { - memmove(list->nodes + 1, list->nodes, list->size * sizeof(pm_node_t *)); - list->nodes[0] = node; - list->size++; - } +pm_node_list_prepend(pm_allocator_t *allocator, pm_node_list_t *list, pm_node_t *node) { + pm_node_list_grow(allocator, list, 1); + memmove(list->nodes + 1, list->nodes, list->size * sizeof(pm_node_t *)); + list->nodes[0] = node; + list->size++; } /** * Concatenate the given node list onto the end of the other node list. */ void -pm_node_list_concat(pm_node_list_t *list, pm_node_list_t *other) { - if (other->size > 0 && pm_node_list_grow(list, other->size)) { +pm_node_list_concat(pm_allocator_t *allocator, pm_node_list_t *list, pm_node_list_t *other) { + if (other->size > 0) { + pm_node_list_grow(allocator, list, other->size); memcpy(list->nodes + list->size, other->nodes, other->size * sizeof(pm_node_t *)); list->size += other->size; } } -/** - * Free the internal memory associated with the given node list. - */ -void -pm_node_list_free(pm_node_list_t *list) { - if (list->capacity > 0) { - xfree(list->nodes); - *list = (pm_node_list_t) { 0 }; - } -} - PRISM_EXPORTED_FUNCTION void pm_node_destroy(pm_parser_t *parser, pm_node_t *node); @@ -94,7 +81,6 @@ static void pm_node_list_destroy(pm_parser_t *parser, pm_node_list_t *list) { pm_node_t *node; PM_NODE_LIST_FOREACH(list, index, node) pm_node_destroy(parser, node); - pm_node_list_free(list); } /** From 3f74a5a4c65647bf509acfa556bf4826ee2bfaad Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 26 Jun 2024 13:25:12 -0400 Subject: [PATCH 03/10] Temporary --- include/prism/allocator.h | 2 +- src/prism.c | 186 ++++++++++++++++++-------------------- templates/src/node.c.erb | 21 +++-- 3 files changed, 104 insertions(+), 105 deletions(-) diff --git a/include/prism/allocator.h b/include/prism/allocator.h index 8f38b1e779..3af930331c 100644 --- a/include/prism/allocator.h +++ b/include/prism/allocator.h @@ -12,7 +12,7 @@ #include typedef struct pm_allocator_page { - struct pm_allocator *next; + struct pm_allocator_page *next; char *start; char *current; char *end; diff --git a/src/prism.c b/src/prism.c index 29d3f3933e..aef45022c5 100644 --- a/src/prism.c +++ b/src/prism.c @@ -3275,7 +3275,7 @@ static void pm_case_node_condition_append(pm_parser_t *parser, pm_case_node_t *node, pm_node_t *condition) { assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE)); - pm_node_list_append(parser, &node->conditions, condition); + pm_node_list_append(&parser->allocator, &node->conditions, condition); node->base.location.end = condition->location.end; } @@ -5343,7 +5343,7 @@ pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *openin if (parts != NULL) { pm_node_t *part; PM_NODE_LIST_FOREACH(parts, index, part) { - pm_interpolated_string_node_append(node, part); + pm_interpolated_string_node_append(parser, node, part); } } @@ -5400,7 +5400,7 @@ pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *openin if (parts != NULL) { pm_node_t *part; PM_NODE_LIST_FOREACH(parts, index, part) { - pm_interpolated_symbol_node_append(node, part); + pm_interpolated_symbol_node_append(parser, node, part); } } @@ -5506,14 +5506,14 @@ pm_keyword_hash_node_create(pm_parser_t *parser) { * Append an element to a KeywordHashNode node. */ static void -pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) { +pm_keyword_hash_node_elements_append(pm_parser_t *parser, pm_keyword_hash_node_t *hash, pm_node_t *element) { // If the element being added is not an AssocNode or does not have a symbol // key, then we want to turn the SYMBOL_KEYS flag off. if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) { pm_node_flag_unset((pm_node_t *)hash, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS); } - pm_node_list_append(&hash->elements, element); + pm_node_list_append(&parser->allocator, &hash->elements, element); if (hash->base.location.start == NULL) { hash->base.location.start = element->location.start; } @@ -5959,19 +5959,19 @@ pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t node->rest = target; } else { pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS); - pm_node_list_append(&node->rights, target); + pm_node_list_append(&parser->allocator, &node->rights, target); } } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) { if (node->rest == NULL) { node->rest = target; } else { PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST); - pm_node_list_append(&node->rights, target); + pm_node_list_append(&parser->allocator, &node->rights, target); } } else if (node->rest == NULL) { - pm_node_list_append(&node->lefts, target); + pm_node_list_append(&parser->allocator, &node->lefts, target); } else { - pm_node_list_append(&node->rights, target); + pm_node_list_append(&parser->allocator, &node->rights, target); } if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) { @@ -6284,27 +6284,27 @@ pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) * Append a required parameter to a ParametersNode node. */ static void -pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) { +pm_parameters_node_requireds_append(pm_parser_t *parser, pm_parameters_node_t *params, pm_node_t *param) { pm_parameters_node_location_set(params, param); - pm_node_list_append(¶ms->requireds, param); + pm_node_list_append(&parser->allocator, ¶ms->requireds, param); } /** * Append an optional parameter to a ParametersNode node. */ static void -pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) { +pm_parameters_node_optionals_append(pm_parser_t *parser, pm_parameters_node_t *params, pm_optional_parameter_node_t *param) { pm_parameters_node_location_set(params, (pm_node_t *) param); - pm_node_list_append(¶ms->optionals, (pm_node_t *) param); + pm_node_list_append(&parser->allocator, ¶ms->optionals, (pm_node_t *) param); } /** * Append a post optional arguments parameter to a ParametersNode node. */ static void -pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) { +pm_parameters_node_posts_append(pm_parser_t *parser, pm_parameters_node_t *params, pm_node_t *param) { pm_parameters_node_location_set(params, param); - pm_node_list_append(¶ms->posts, param); + pm_node_list_append(&parser->allocator, ¶ms->posts, param); } /** @@ -6320,9 +6320,9 @@ pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) { * Append a keyword parameter to a ParametersNode node. */ static void -pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) { +pm_parameters_node_keywords_append(pm_parser_t *parser, pm_parameters_node_t *params, pm_node_t *param) { pm_parameters_node_location_set(params, param); - pm_node_list_append(¶ms->keywords, param); + pm_node_list_append(&parser->allocator, ¶ms->keywords, param); } /** @@ -6691,8 +6691,8 @@ pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subseque * Append an exception node to a rescue node, and update the location. */ static void -pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) { - pm_node_list_append(&node->exceptions, exception); +pm_rescue_node_exceptions_append(pm_parser_t *parser, pm_rescue_node_t *node, pm_node_t *exception) { + pm_node_list_append(&parser->allocator, &node->exceptions, exception); node->base.location.end = exception->location.end; } @@ -6988,7 +6988,7 @@ pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, } } - pm_node_list_append(&node->body, statement); + pm_node_list_append(&parser->allocator, &node->body, statement); if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE); } @@ -6996,9 +6996,9 @@ pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, * Prepend a new node to the given StatementsNode node's body. */ static void -pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) { +pm_statements_node_body_prepend(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement) { pm_statements_node_body_update(node, statement); - pm_node_list_prepend(&node->body, statement); + pm_node_list_prepend(&parser->allocator, &node->body, statement); pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE); } @@ -7557,9 +7557,9 @@ pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) { * Append a name to an undef node. */ static void -pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) { +pm_undef_node_append(pm_parser_t *parser, pm_undef_node_t *node, pm_node_t *name) { node->base.location.end = name->location.end; - pm_node_list_append(&node->names, name); + pm_node_list_append(&parser->allocator, &node->names, name); } /** @@ -7745,9 +7745,9 @@ pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) { * Append a new condition to a when node. */ static void -pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) { +pm_when_node_conditions_append(pm_parser_t *parser, pm_when_node_t *node, pm_node_t *condition) { node->base.location.end = condition->location.end; - pm_node_list_append(&node->conditions, condition); + pm_node_list_append(&parser->allocator, &node->conditions, condition); } /** @@ -14029,7 +14029,7 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) { pm_hash_node_elements_append(parser, (pm_hash_node_t *) node, element); } else { - pm_keyword_hash_node_elements_append((pm_keyword_hash_node_t *) node, element); + pm_keyword_hash_node_elements_append(parser, (pm_keyword_hash_node_t *) node, element); } // If there's no comma after the element, then we're done. @@ -14230,7 +14230,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1)); argument = (pm_node_t *) pm_assoc_node_create(parser, argument, &operator, value); - pm_keyword_hash_node_elements_append(bare_hash, argument); + pm_keyword_hash_node_elements_append(parser, bare_hash, argument); argument = (pm_node_t *) bare_hash; // Then parse more if we have a comma @@ -14457,9 +14457,9 @@ parse_parameters( pm_node_t *param = (pm_node_t *) parse_required_destructured_parameter(parser); if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) { - pm_parameters_node_requireds_append(params, param); + pm_parameters_node_requireds_append(parser, params, param); } else { - pm_parameters_node_posts_append(params, param); + pm_parameters_node_posts_append(parser, params, param); } break; } @@ -14489,7 +14489,7 @@ parse_parameters( pm_parameters_node_block_set(params, param); } else { pm_parser_err_node(parser, (pm_node_t *) param, PM_ERR_PARAMETER_BLOCK_MULTI); - pm_parameters_node_posts_append(params, (pm_node_t *) param); + pm_parameters_node_posts_append(parser, params, (pm_node_t *) param); } break; @@ -14509,7 +14509,7 @@ parse_parameters( // If we already have a keyword rest parameter, then we replace it with the // forwarding parameter and move the keyword rest parameter to the posts list. pm_node_t *keyword_rest = params->keyword_rest; - pm_parameters_node_posts_append(params, keyword_rest); + pm_parameters_node_posts_append(parser, params, keyword_rest); if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD); params->keyword_rest = NULL; } @@ -14570,7 +14570,7 @@ parse_parameters( if (repeated) { pm_node_flag_set_repeated_parameter((pm_node_t *) param); } - pm_parameters_node_optionals_append(params, param); + pm_parameters_node_optionals_append(parser, params, param); // If the value of the parameter increased the number of // reads of that parameter, then we need to warn that we @@ -14593,13 +14593,13 @@ parse_parameters( if (repeated) { pm_node_flag_set_repeated_parameter((pm_node_t *)param); } - pm_parameters_node_requireds_append(params, (pm_node_t *) param); + pm_parameters_node_requireds_append(parser, params, (pm_node_t *) param); } else { pm_required_parameter_node_t *param = pm_required_parameter_node_create(parser, &name); if (repeated) { pm_node_flag_set_repeated_parameter((pm_node_t *)param); } - pm_parameters_node_posts_append(params, (pm_node_t *) param); + pm_parameters_node_posts_append(parser, params, (pm_node_t *) param); } break; @@ -14635,7 +14635,7 @@ parse_parameters( pm_node_flag_set_repeated_parameter(param); } - pm_parameters_node_keywords_append(params, param); + pm_parameters_node_keywords_append(parser, params, param); break; } case PM_TOKEN_SEMICOLON: @@ -14652,7 +14652,7 @@ parse_parameters( pm_node_flag_set_repeated_parameter(param); } - pm_parameters_node_keywords_append(params, param); + pm_parameters_node_keywords_append(parser, params, param); break; } default: { @@ -14681,7 +14681,7 @@ parse_parameters( } context_pop(parser); - pm_parameters_node_keywords_append(params, param); + pm_parameters_node_keywords_append(parser, params, param); // If parsing the value of the parameter resulted in error recovery, // then we can put a missing node in its place and stop parsing the @@ -14723,7 +14723,7 @@ parse_parameters( pm_parameters_node_rest_set(params, param); } else { pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI); - pm_parameters_node_posts_append(params, param); + pm_parameters_node_posts_append(parser, params, param); } break; @@ -14766,7 +14766,7 @@ parse_parameters( pm_parameters_node_keyword_rest_set(params, param); } else { pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI); - pm_parameters_node_posts_append(params, param); + pm_parameters_node_posts_append(parser, params, param); } break; @@ -14782,7 +14782,7 @@ parse_parameters( pm_parameters_node_rest_set(params, param); } else { pm_parser_err_node(parser, (pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI); - pm_parameters_node_posts_append(params, (pm_node_t *) param); + pm_parameters_node_posts_append(parser, params, (pm_node_t *) param); } } else { pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA); @@ -14978,7 +14978,7 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_ do { pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1)); - pm_rescue_node_exceptions_append(rescue, expression); + pm_rescue_node_exceptions_append(parser, rescue, expression); // If we hit a newline, then this is the end of the rescue expression. We // can continue on to parse the statements. @@ -15591,21 +15591,14 @@ parse_block_exit(pm_parser_t *parser, pm_node_t *node) { // These are the bad cases. We're not allowed to have a block // exit in these contexts. - if (through_expression) { - // If we get here, then we're about to mark this block exit - // as invalid. However, it could later _become_ valid if we - // find a trailing while/until on the expression. In this - // case instead of adding the error here, we'll add the - // block exit to the list of exits for the expression, and - // the node parsing will handle validating it instead. - assert(parser->current_block_exits != NULL); - pm_node_list_append(&parser->block_exits_allocator, parser->current_block_exits, node); - } else { - // Otherwise, if we haven't gone through an expression - // context, then this is just invalid and we'll add the - // error here. - PM_PARSER_ERR_NODE_FORMAT(parser, node, PM_ERR_INVALID_BLOCK_EXIT, type); - } + // If we get here, then we're about to mark this block exit + // as invalid. However, it could later _become_ valid if we + // find a trailing while/until on the expression. In this + // case instead of adding the error here, we'll add the + // block exit to the list of exits for the expression, and + // the node parsing will handle validating it instead. + assert(parser->current_block_exits != NULL); + pm_node_list_append(&parser->block_exits_allocator, parser->current_block_exits, node); return; case PM_CONTEXT_BEGIN_ELSE: case PM_CONTEXT_BEGIN_ENSURE: @@ -16178,11 +16171,11 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s } pm_interpolated_symbol_node_t *symbol = pm_interpolated_symbol_node_create(parser, &opening, NULL, &opening); - if (part) pm_interpolated_symbol_node_append(symbol, part); + if (part) pm_interpolated_symbol_node_append(parser, symbol, part); while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) { if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) { - pm_interpolated_symbol_node_append(symbol, part); + pm_interpolated_symbol_node_append(parser, symbol, part); } } @@ -16219,10 +16212,10 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s pm_token_t bounds = not_provided(parser); pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped); - pm_interpolated_symbol_node_append(symbol, part); + pm_interpolated_symbol_node_append(parser, symbol, part); part = (pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &parser->current, &bounds, &parser->current_string); - pm_interpolated_symbol_node_append(symbol, part); + pm_interpolated_symbol_node_append(parser, symbol, part); if (next_state != PM_LEX_STATE_NONE) { lex_state_set(parser, next_state); @@ -16731,11 +16724,11 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1 pm_token_t bounds = not_provided(parser); pm_interpolated_string_node_t *container = pm_interpolated_string_node_create(parser, &bounds, NULL, &bounds); - pm_interpolated_string_node_append(container, current); + pm_interpolated_string_node_append(parser, container, current); current = (pm_node_t *) container; } - pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, node); + pm_interpolated_string_node_append(parser, (pm_interpolated_string_node_t *) current, node); } } @@ -17061,7 +17054,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node pm_token_t operator = not_provided(parser); pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, first_node, &operator, value); - pm_node_list_append(&assocs, assoc); + pm_node_list_append(&parser->allocator, &assocs, assoc); break; } } @@ -17077,7 +17070,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node pm_node_t *value = (pm_node_t *) pm_missing_node_create(parser, first_node->location.start, first_node->location.end); pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, first_node, &operator, value); - pm_node_list_append(&assocs, assoc); + pm_node_list_append(&parser->allocator, &assocs, assoc); break; } } @@ -17101,7 +17094,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node rest = assoc; } else { pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST); - pm_node_list_append(&assocs, assoc); + pm_node_list_append(&parser->allocator, &assocs, assoc); } } else { pm_node_t *key; @@ -17135,7 +17128,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST); } - pm_node_list_append(&assocs, assoc); + pm_node_list_append(&parser->allocator, &assocs, assoc); } } @@ -17578,14 +17571,14 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag // or a find pattern. We need to parse all of the patterns, put them // into a big list, and then determine which type of node we have. pm_node_list_t nodes = { 0 }; - pm_node_list_append(&nodes, node); + pm_node_list_append(&parser->allocator, &nodes, node); // Gather up all of the patterns into the list. while (accept1(parser, PM_TOKEN_COMMA)) { // Break early here in case we have a trailing comma. if (match6(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) { node = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous); - pm_node_list_append(&nodes, node); + pm_node_list_append(&parser->allocator, &nodes, node); trailing_rest = true; break; } @@ -17605,7 +17598,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1)); } - pm_node_list_append(&nodes, node); + pm_node_list_append(&parser->allocator, &nodes, node); } // If the first pattern and the last pattern are rest patterns, then we @@ -18042,7 +18035,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1)); pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, element, &operator, value); - pm_keyword_hash_node_elements_append(hash, assoc); + pm_keyword_hash_node_elements_append(parser, hash, assoc); element = (pm_node_t *) hash; if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) { @@ -18588,7 +18581,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b cast->parts.nodes = pm_allocator_arena_alloc(&parser->allocator, sizeof(pm_node_t *) * parts.size, sizeof(pm_node_t *)); cast->parts.size = parts.size; cast->parts.capacity = parts.capacity; - memcpy(cast->parts.nodes, parts.size, sizeof(pm_node_t *) * parts.size); + memcpy(cast->parts.nodes, parts.nodes, sizeof(pm_node_t *) * parts.size); pm_allocator_free(&parts_allocator); expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length); @@ -18761,12 +18754,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1)); pm_splat_node_t *splat_node = pm_splat_node_create(parser, &operator, expression); - pm_when_node_conditions_append(when_node, (pm_node_t *) splat_node); + pm_when_node_conditions_append(parser, when_node, (pm_node_t *) splat_node); if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE)) break; } else { pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1)); - pm_when_node_conditions_append(when_node, condition); + pm_when_node_conditions_append(parser, when_node, condition); // If we found a missing node, then this is a syntax // error and we should stop looping. @@ -19108,9 +19101,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b return (pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &operator, expression, statements, &parser->previous); } - void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); - pm_node_list_t current_block_exits = { 0 }; - pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); + // FIXME: (chris_c) Is this needed? + // void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); + // pm_node_list_t current_block_exits = { 0 }; + // pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1)); pm_token_t name = parser->previous; @@ -19619,7 +19613,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) { pm_node_destroy(parser, name); } else { - pm_undef_node_append(undef, name); + pm_undef_node_append(parser, undef, name); while (match1(parser, PM_TOKEN_COMMA)) { lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM); @@ -19631,7 +19625,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b break; } - pm_undef_node_append(undef, name); + pm_undef_node_append(parser, undef, name); } } @@ -19905,7 +19899,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_t *string = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->current, &closing); parser_lex(parser); - pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, string); + pm_interpolated_symbol_node_append(parser, (pm_interpolated_symbol_node_t *) current, string); } else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) { // If we hit string content and the current node is a symbol node, // then we need to convert the current node into an interpolated @@ -19919,8 +19913,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing); - pm_interpolated_symbol_node_append(interpolated, first_string); - pm_interpolated_symbol_node_append(interpolated, second_string); + pm_interpolated_symbol_node_append(parser, interpolated, first_string); + pm_interpolated_symbol_node_append(parser, interpolated, second_string); xfree(current); current = (pm_node_t *) interpolated; @@ -19948,7 +19942,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing); current = (pm_node_t *) pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current); - pm_interpolated_symbol_node_append(interpolated, current); + pm_interpolated_symbol_node_append(parser, interpolated, current); interpolated->base.location.start = current->location.start; start_location_set = true; current = (pm_node_t *) interpolated; @@ -19958,7 +19952,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1)); - pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, part); + pm_interpolated_symbol_node_append(parser, (pm_interpolated_symbol_node_t *) current, part); if (!start_location_set) { current->location.start = part->location.start; } @@ -19983,7 +19977,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing); current = (pm_node_t *) pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current); - pm_interpolated_symbol_node_append(interpolated, current); + pm_interpolated_symbol_node_append(parser, interpolated, current); interpolated->base.location.start = current->location.start; start_location_set = true; current = (pm_node_t *) interpolated; @@ -19995,7 +19989,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1)); - pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, part); + pm_interpolated_symbol_node_append(parser, (pm_interpolated_symbol_node_t *) current, part); if (!start_location_set) { current->location.start = part->location.start; } @@ -20106,15 +20100,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // If we hit string content and the current node is // an interpolated string, then we need to append // the string content to the list of child nodes. - pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, string); + pm_interpolated_string_node_append(parser, (pm_interpolated_string_node_t *) current, string); } else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) { // If we hit string content and the current node is // a string node, then we need to convert the // current node into an interpolated string and add // the string content to the list of child nodes. pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing); - pm_interpolated_string_node_append(interpolated, current); - pm_interpolated_string_node_append(interpolated, string); + pm_interpolated_string_node_append(parser, interpolated, current); + pm_interpolated_string_node_append(parser, interpolated, string); current = (pm_node_t *) interpolated; } else { assert(false && "unreachable"); @@ -20139,7 +20133,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_token_t opening = not_provided(parser); pm_token_t closing = not_provided(parser); pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing); - pm_interpolated_string_node_append(interpolated, current); + pm_interpolated_string_node_append(parser, interpolated, current); current = (pm_node_t *) interpolated; } else { // If we hit an embedded variable and the current @@ -20148,7 +20142,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1)); - pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part); + pm_interpolated_string_node_append(parser, (pm_interpolated_string_node_t *) current, part); break; } case PM_TOKEN_EMBEXPR_BEGIN: { @@ -20168,7 +20162,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_token_t opening = not_provided(parser); pm_token_t closing = not_provided(parser); pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing); - pm_interpolated_string_node_append(interpolated, current); + pm_interpolated_string_node_append(parser, interpolated, current); current = (pm_node_t *) interpolated; } else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) { // If we hit an embedded expression and the current @@ -20179,7 +20173,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1)); - pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part); + pm_interpolated_string_node_append(parser, (pm_interpolated_string_node_t *) current, part); break; } default: @@ -20852,7 +20846,7 @@ parse_regular_expression_named_capture(const pm_string_t *capture, void *data) { // Next, create the local variable target and add it to the list of // targets for the match. pm_node_t *target = (pm_node_t *) pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth); - pm_node_list_append(&callback_data->match->targets, target); + pm_node_list_append(&parser->allocator, &callback_data->match->targets, target); } } @@ -21954,7 +21948,7 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) { (pm_node_t *) call ); - pm_statements_node_body_prepend(statements, (pm_node_t *) write); + pm_statements_node_body_prepend(parser, statements, (pm_node_t *) write); } pm_arguments_node_t *arguments = pm_arguments_node_create(parser); @@ -21966,7 +21960,7 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) { if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) { pm_keyword_hash_node_t *keywords = pm_keyword_hash_node_create(parser); - pm_keyword_hash_node_elements_append(keywords, (pm_node_t *) pm_assoc_node_create( + pm_keyword_hash_node_elements_append(parser, keywords, (pm_node_t *) pm_assoc_node_create( parser, (pm_node_t *) pm_symbol_node_synthesized_create(parser, "chomp"), &(pm_token_t) { .type = PM_TOKEN_NOT_PROVIDED, .start = parser->start, .end = parser->start }, diff --git a/templates/src/node.c.erb b/templates/src/node.c.erb index 276187c22c..50c63ed426 100644 --- a/templates/src/node.c.erb +++ b/templates/src/node.c.erb @@ -11,24 +11,29 @@ static void pm_node_list_grow(pm_allocator_t *allocator, pm_node_list_t *list, size_t size) { size_t requested_size = list->size + size; - // If the requested size caused overflow, return false. - if (requested_size < list->size) return false; + // If the requested size caused overflow, fail. + assert(requested_size - size == list->size); - // If the requested size is within the existing capacity, return true. - if (requested_size < list->capacity) return true; + // If the requested size is within the existing capacity, return. + if (requested_size < list->capacity) return; // Otherwise, reallocate the list to be twice as large as it was before. - size_t next_capacity = list->capacity == 0 ? 4 : list->capacity * 2; + size_t next_capacity; + if (list->capacity == 0) { + next_capacity = 4; + } else { + next_capacity = list->capacity * 2; - // If multiplying by 2 caused overflow, return false. - if (next_capacity < list->capacity) return false; + // If multiplying by 2 caused overflow, fail. + assert(next_capacity / 2 == list->capacity); + } // If we didn't get enough by doubling, keep doubling until we do. while (requested_size > next_capacity) { size_t double_capacity = next_capacity * 2; // Ensure we didn't overflow by multiplying by 2. - if (double_capacity < next_capacity) return false; + assert(double_capacity / 2 == next_capacity); next_capacity = double_capacity; } From 19cdc8631754040f8e9eefbd1e65ef335e69c166 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 26 Jun 2024 13:58:42 -0400 Subject: [PATCH 04/10] Temporary --- include/prism/allocator.h | 5 --- src/allocator.c | 34 +++++++----------- src/prism.c | 75 ++++++--------------------------------- 3 files changed, 24 insertions(+), 90 deletions(-) diff --git a/include/prism/allocator.h b/include/prism/allocator.h index 3af930331c..6b1f2cef37 100644 --- a/include/prism/allocator.h +++ b/include/prism/allocator.h @@ -28,11 +28,6 @@ typedef struct pm_allocator { */ void pm_allocator_init(pm_allocator_t *allocator, size_t capacity); -/** - * Retrieve a scratch allocator with the given capacity. - */ -pm_allocator_t pm_allocator_scratch(size_t capacity); - /** * Allocate memory from the given allocator. */ diff --git a/src/allocator.c b/src/allocator.c index 758ca9b0c4..54cf56c1f6 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -24,16 +24,6 @@ pm_allocator_init(pm_allocator_t *allocator, size_t capacity) { }; } -/** - * Retrieve a scratch allocator with the given capacity. - */ -pm_allocator_t -pm_allocator_scratch(size_t capacity) { - pm_allocator_t scratch = { 0 }; - pm_allocator_init(&scratch, capacity); - return scratch; -} - /** * Allocate memory from the given allocator. */ @@ -58,14 +48,14 @@ pm_allocator_arena_alloc(pm_allocator_t *allocator, size_t size, size_t alignmen // up just this node in the linked list to fit the allocation. if (size > next_capacity) next_capacity = size; - char *next_allocator_memory = xmalloc(sizeof(pm_allocator_page_t) + next_capacity); - if (next_allocator_memory == NULL) { + char *memory = xmalloc(sizeof(pm_allocator_page_t) + next_capacity); + if (memory == NULL) { fprintf(stderr, "[pm_allocator_arena_alloc] failed to allocate memory\n"); abort(); } - pm_allocator_page_t *next_allocator_page = (pm_allocator_page_t *) next_allocator_memory; - char *start = next_allocator_memory + sizeof(pm_allocator_page_t); + pm_allocator_page_t *next_allocator_page = (pm_allocator_page_t *) memory; + char *start = memory + sizeof(pm_allocator_page_t); // Assume the alignment is correct because malloc should give us back // the most relaxed alignment possible. @@ -82,7 +72,7 @@ pm_allocator_arena_alloc(pm_allocator_t *allocator, size_t size, size_t alignmen allocator->tail = next_allocator_page; result = allocator->tail->start; - next = next_allocator_page->current + size; + next = result + size; } allocator->tail->current = next; @@ -114,10 +104,8 @@ pm_allocator_current(pm_allocator_t *allocator) { } static void -pm_allocator_page_free(pm_allocator_page_t *current) { +pm_allocator_page_free(pm_allocator_page_t *current, bool top_level) { while (current != NULL) { - if (current->end != current->start) xfree(current->start); - pm_allocator_page_t *previous = current; current = current->next; @@ -125,9 +113,13 @@ pm_allocator_page_free(pm_allocator_page_t *current) { // allocator itself, then it came from pm_allocator_arena_alloc, so we // should free it. Otherwise we assume it was embedded into another // struct or allocated on the stack. - if (previous->start == ((char *) previous + sizeof(pm_allocator_t))) { + if (top_level) { + xfree(previous->start); + } else { xfree(previous); } + + top_level = false; } } @@ -141,7 +133,7 @@ pm_allocator_reset(pm_allocator_t *allocator, void *current) { for (pm_allocator_page_t *current = &allocator->head; current != NULL; current = current->next) { if (needle >= current->start && needle <= current->end) { current->current = needle; - pm_allocator_page_free(current->next); + pm_allocator_page_free(current->next, false); return; } } @@ -153,5 +145,5 @@ pm_allocator_reset(pm_allocator_t *allocator, void *current) { * Frees the internal memory associated with the allocator. */ void pm_allocator_free(pm_allocator_t *allocator) { - pm_allocator_page_free(&allocator->head); + pm_allocator_page_free(&allocator->head, true); } diff --git a/src/prism.c b/src/prism.c index aef45022c5..71c352a649 100644 --- a/src/prism.c +++ b/src/prism.c @@ -2930,12 +2930,6 @@ pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const }; pm_call_write_read_name_init(parser, &node->read_name, &node->write_name); - - // Here we're going to free the target, since it is no longer necessary. - // However, we don't want to call `pm_node_destroy` because we want to keep - // around all of its children since we just reused them. - // xfree(target); - return node; } @@ -2993,11 +2987,6 @@ pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, cons .value = value }; - // Here we're going to free the target, since it is no longer necessary. - // However, we don't want to call `pm_node_destroy` because we want to keep - // around all of its children since we just reused them. - // xfree(target); - return node; } @@ -3031,11 +3020,6 @@ pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, pm_call_write_read_name_init(parser, &node->read_name, &node->write_name); - // Here we're going to free the target, since it is no longer necessary. - // However, we don't want to call `pm_node_destroy` because we want to keep - // around all of its children since we just reused them. - // xfree(target); - return node; } @@ -3070,11 +3054,6 @@ pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, .value = value }; - // Here we're going to free the target, since it is no longer necessary. - // However, we don't want to call `pm_node_destroy` because we want to keep - // around all of its children since we just reused them. - // xfree(target); - return node; } @@ -3108,11 +3087,6 @@ pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_call_write_read_name_init(parser, &node->read_name, &node->write_name); - // Here we're going to free the target, since it is no longer necessary. - // However, we don't want to call `pm_node_destroy` because we want to keep - // around all of its children since we just reused them. - // xfree(target); - return node; } @@ -3147,11 +3121,6 @@ pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const .value = value }; - // Here we're going to free the target, since it is no longer necessary. - // However, we don't want to call `pm_node_destroy` because we want to keep - // around all of its children since we just reused them. - // xfree(target); - return node; } @@ -3176,11 +3145,6 @@ pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) { .message_loc = target->message_loc }; - // Here we're going to free the target, since it is no longer necessary. - // However, we don't want to call `pm_node_destroy` because we want to keep - // around all of its children since we just reused them. - // xfree(target); - return node; } @@ -3210,11 +3174,6 @@ pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) { .block = (pm_block_argument_node_t *) target->block, }; - // Here we're going to free the target, since it is no longer necessary. - // However, we don't want to call `pm_node_destroy` because we want to keep - // around all of its children since we just reused them. - // xfree(target); - return node; } @@ -6027,10 +5986,6 @@ pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, .value = value }; - // Explicitly do not call pm_node_destroy here because we want to keep - // around all of the information within the MultiWriteNode node. - // xfree(target); - return node; } @@ -7451,11 +7406,6 @@ pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end }; pm_node_flag_set((pm_node_t *) new_node, parse_symbol_encoding(parser, &content, &node->unescaped, true)); - // We are explicitly _not_ using pm_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. - // xfree(node); - return new_node; } @@ -7489,11 +7439,6 @@ pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) { .unescaped = node->unescaped }; - // We are explicitly _not_ using pm_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. - // xfree(node); - return new_node; } @@ -16581,7 +16526,8 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1 // In that case we need to switch to an interpolated string to // be able to contain all of the parts. if (match1(parser, PM_TOKEN_STRING_CONTENT)) { - pm_allocator_t parts_allocator = pm_allocator_scratch(sizeof(pm_node_t *) * 4); + pm_allocator_t parts_allocator; + pm_allocator_init(&parts_allocator, sizeof(pm_node_t *) * 4); pm_node_list_t parts = { 0 }; pm_token_t delimiters = not_provided(parser); @@ -16642,7 +16588,8 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1 } else { // If we get here, then we have interpolation so we'll need // to create a string or symbol node with interpolation. - pm_allocator_t parts_allocator = pm_allocator_scratch(sizeof(pm_node_t *) * 8); + pm_allocator_t parts_allocator; + pm_allocator_init(&parts_allocator, sizeof(pm_node_t *) * 8); pm_node_list_t parts = { 0 }; pm_token_t string_opening = not_provided(parser); pm_token_t string_closing = not_provided(parser); @@ -16674,7 +16621,8 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1 // If we get here, then the first part of the string is not plain // string content, in which case we need to parse the string as an // interpolated string. - pm_allocator_t parts_allocator = pm_allocator_scratch(sizeof(pm_node_t *) * 8); + pm_allocator_t parts_allocator; + pm_allocator_init(&parts_allocator, sizeof(pm_node_t *) * 8); pm_node_list_t parts = { 0 }; pm_node_t *part; @@ -17133,8 +17081,6 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node } pm_hash_pattern_node_t *node = pm_hash_pattern_node_node_list_create(parser, &assocs, rest); - xfree(assocs.nodes); - pm_static_literals_free(&keys); return node; } @@ -17618,8 +17564,6 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS); } } - - xfree(nodes.nodes); } else if (leading_rest) { // Otherwise, if we parsed a single splat pattern, then we know we have // an array pattern, so we can go ahead and create that node. @@ -18564,7 +18508,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // If we get here, then we have multiple parts in the heredoc, // so we'll need to create an interpolated string node to hold // them all. - pm_allocator_t parts_allocator = pm_allocator_scratch(sizeof(pm_node_t *) * 8); + pm_allocator_t parts_allocator; + pm_allocator_init(&parts_allocator, sizeof(pm_node_t *) * 8); pm_node_list_t parts = { 0 }; pm_node_list_append(&parts_allocator, &parts, part); @@ -19916,7 +19861,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_interpolated_symbol_node_append(parser, interpolated, first_string); pm_interpolated_symbol_node_append(parser, interpolated, second_string); - xfree(current); current = (pm_node_t *) interpolated; } else { assert(false && "unreachable"); @@ -22425,6 +22369,9 @@ pm_parser_free(pm_parser_t *parser) { while (parser->lex_modes.index >= PM_LEX_STACK_SIZE) { lex_mode_pop(parser); } + + pm_allocator_free(&parser->block_exits_allocator); + pm_allocator_free(&parser->allocator); } /** From c6d5247c63b13e41390c6489376d19c1724063a7 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 26 Jun 2024 14:10:00 -0400 Subject: [PATCH 05/10] Temporary --- include/prism/allocator.h | 10 ---------- include/prism/parser.h | 1 + src/allocator.c | 37 ++++--------------------------------- src/prism.c | 33 ++------------------------------- 4 files changed, 7 insertions(+), 74 deletions(-) diff --git a/include/prism/allocator.h b/include/prism/allocator.h index 6b1f2cef37..7bb7e23775 100644 --- a/include/prism/allocator.h +++ b/include/prism/allocator.h @@ -38,16 +38,6 @@ void * pm_allocator_arena_alloc(pm_allocator_t *allocator, size_t size, size_t a */ void * pm_allocator_arena_calloc(pm_allocator_t *allocator, size_t count, size_t size, size_t alignment); -/** - * Retrieve a pointer to the next slot that would be allocated. - */ -void * pm_allocator_current(pm_allocator_t *allocator); - -/** - * Reset the allocator back to the given slot. - */ -void pm_allocator_reset(pm_allocator_t *allocator, void *current); - /** * Frees the internal memory associated with the allocator. */ diff --git a/include/prism/parser.h b/include/prism/parser.h index 8e1517e73d..381f09c904 100644 --- a/include/prism/parser.h +++ b/include/prism/parser.h @@ -651,6 +651,7 @@ struct pm_parser { * but the node can be found through another parse. */ uint32_t node_id; + /** The allocator used to allocate nodes and their fields. */ pm_allocator_t allocator; diff --git a/src/allocator.c b/src/allocator.c index 54cf56c1f6..97f3d3107b 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -96,16 +96,12 @@ pm_allocator_arena_calloc(pm_allocator_t *allocator, size_t count, size_t size, } /** - * Retrieve a pointer to the next slot that would be allocated. + * Frees the internal memory associated with the allocator. */ -void * -pm_allocator_current(pm_allocator_t *allocator) { - return allocator->tail->current; -} +void pm_allocator_free(pm_allocator_t *allocator) { + bool top_level = true; -static void -pm_allocator_page_free(pm_allocator_page_t *current, bool top_level) { - while (current != NULL) { + for (pm_allocator_page_t *current = &allocator->head; current != NULL;) { pm_allocator_page_t *previous = current; current = current->next; @@ -122,28 +118,3 @@ pm_allocator_page_free(pm_allocator_page_t *current, bool top_level) { top_level = false; } } - -/** - * Reset the allocator back to the given slot. - */ -void -pm_allocator_reset(pm_allocator_t *allocator, void *current) { - char *needle = current; - - for (pm_allocator_page_t *current = &allocator->head; current != NULL; current = current->next) { - if (needle >= current->start && needle <= current->end) { - current->current = needle; - pm_allocator_page_free(current->next, false); - return; - } - } - - assert(false && "[pm_allocator_reset] could not find reset point"); -} - -/** - * Frees the internal memory associated with the allocator. - */ -void pm_allocator_free(pm_allocator_t *allocator) { - pm_allocator_page_free(&allocator->head, true); -} diff --git a/src/prism.c b/src/prism.c index 71c352a649..47ad33732b 100644 --- a/src/prism.c +++ b/src/prism.c @@ -15668,7 +15668,6 @@ parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_contex static inline pm_node_t * parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newline_index, bool if_after_else, uint16_t depth) { - void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); pm_node_list_t current_block_exits = { 0 }; pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); @@ -15794,8 +15793,6 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl } pop_block_exits(parser, previous_block_exits); - pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); - return parent; } @@ -18012,7 +18009,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: { pm_token_t opening = parser->current; - void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); pm_node_list_t current_block_exits = { 0 }; pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); @@ -18025,8 +18021,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN); pop_block_exits(parser, previous_block_exits); - pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); - return (pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->previous); } @@ -18057,7 +18051,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_accepts_block_stack_pop(parser); pop_block_exits(parser, previous_block_exits); - pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) { // If we have a single statement and are ending on a right @@ -18647,7 +18640,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_token_t case_keyword = parser->previous; pm_node_t *predicate = NULL; - void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); pm_node_list_t current_block_exits = { 0 }; pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); @@ -18668,8 +18660,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pop_block_exits(parser, previous_block_exits); - pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); - pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS); return (pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->previous); } @@ -18859,8 +18849,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } pop_block_exits(parser, previous_block_exits); - pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); - return node; } case PM_TOKEN_KEYWORD_BEGIN: { @@ -18870,7 +18858,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_token_t begin_keyword = parser->previous; accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); - void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); pm_node_list_t current_block_exits = { 0 }; pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); pm_statements_node_t *begin_statements = NULL; @@ -18890,8 +18877,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_begin_node_end_keyword_set(begin_node, &parser->previous); pop_block_exits(parser, previous_block_exits); - pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); - return (pm_node_t *) begin_node; } case PM_TOKEN_KEYWORD_BEGIN_UPCASE: { @@ -19046,10 +19031,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b return (pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &operator, expression, statements, &parser->previous); } - // FIXME: (chris_c) Is this needed? - // void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); - // pm_node_list_t current_block_exits = { 0 }; - // pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); + pm_node_list_t current_block_exits = { 0 }; + pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1)); pm_token_t name = parser->previous; @@ -19112,8 +19095,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } pop_block_exits(parser, previous_block_exits); - pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); - return (pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->previous); } case PM_TOKEN_KEYWORD_DEF: { @@ -19612,7 +19593,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b return parse_conditional(parser, PM_CONTEXT_UNLESS, opening_newline_index, false, (uint16_t) (depth + 1)); } case PM_TOKEN_KEYWORD_MODULE: { - void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); pm_node_list_t current_block_exits = { 0 }; pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); @@ -19627,8 +19607,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // the name of the module, then we'll handle that here. if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) { pop_block_exits(parser, previous_block_exits); - pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); - pm_token_t missing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end }; return (pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing); } @@ -19676,8 +19654,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } pop_block_exits(parser, previous_block_exits); - pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); - return (pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous); } case PM_TOKEN_KEYWORD_NIL: @@ -21446,7 +21422,6 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_TOKEN_QUESTION_MARK: { context_push(parser, PM_CONTEXT_TERNARY); - void *block_exits_current = pm_allocator_current(&parser->block_exits_allocator); pm_node_list_t current_block_exits = { 0 }; pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); @@ -21467,8 +21442,6 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t context_pop(parser); pop_block_exits(parser, previous_block_exits); - pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); - return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression); } @@ -21480,8 +21453,6 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t context_pop(parser); pop_block_exits(parser, previous_block_exits); - pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); - return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression); } case PM_TOKEN_COLON_COLON: { From 9d155d0f797d3108ef347f30f2574c631518633d Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 26 Jun 2024 14:21:48 -0400 Subject: [PATCH 06/10] Temporary --- include/prism/util/pm_constant_pool.h | 4 +++- src/prism.c | 11 +++++++++-- src/util/pm_constant_pool.c | 6 ++---- templates/src/node.c.erb | 4 +--- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/include/prism/util/pm_constant_pool.h b/include/prism/util/pm_constant_pool.h index 6df23f8f50..4f3d5519ac 100644 --- a/include/prism/util/pm_constant_pool.h +++ b/include/prism/util/pm_constant_pool.h @@ -11,6 +11,7 @@ #define PRISM_CONSTANT_POOL_H #include "prism/defines.h" +#include "prism/allocator.h" #include #include @@ -54,10 +55,11 @@ void pm_constant_id_list_init(pm_constant_id_list_t *list); /** * Initialize a list of constant ids with a given capacity. * + * @param allocator The allocator to use to allocate space for the list. * @param list The list to initialize. * @param capacity The initial capacity of the list. */ -void pm_constant_id_list_init_capacity(pm_constant_id_list_t *list, size_t capacity); +void pm_constant_id_list_init_capacity(pm_allocator_t *allocator, pm_constant_id_list_t *list, size_t capacity); /** * Append a constant id to a list of constant ids. Returns false if any diff --git a/src/prism.c b/src/prism.c index 47ad33732b..da739c81db 100644 --- a/src/prism.c +++ b/src/prism.c @@ -936,8 +936,15 @@ pm_locals_reads(pm_locals_t *locals, pm_constant_id_t name) { * written but not read in certain contexts. */ static void -pm_locals_order(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, pm_locals_t *locals, pm_constant_id_list_t *list, bool toplevel) { - pm_constant_id_list_init_capacity(list, locals->size); +pm_locals_order(pm_parser_t *parser, pm_locals_t *locals, pm_constant_id_list_t *list, bool toplevel) { + // If there were no locals in the scope, then zero out the memory for the + // constant id list and immediately return. + if (locals->size == 0) { + *list = (pm_constant_id_list_t) { 0 }; + return; + } + + pm_constant_id_list_init_capacity(&parser->allocator, list, locals->size); // If we're still below the threshold for switching to a hash, then we only // need to loop over the locals until we hit the size because the locals are diff --git a/src/util/pm_constant_pool.c b/src/util/pm_constant_pool.c index 624002cec9..6b897fe1b6 100644 --- a/src/util/pm_constant_pool.c +++ b/src/util/pm_constant_pool.c @@ -14,10 +14,8 @@ pm_constant_id_list_init(pm_constant_id_list_t *list) { * Initialize a list of constant ids with a given capacity. */ void -pm_constant_id_list_init_capacity(pm_constant_id_list_t *list, size_t capacity) { - list->ids = xcalloc(capacity, sizeof(pm_constant_id_t)); - if (list->ids == NULL) abort(); - +pm_constant_id_list_init_capacity(pm_allocator_t *allocator, pm_constant_id_list_t *list, size_t capacity) { + list->ids = pm_allocator_arena_calloc(allocator, capacity, sizeof(pm_constant_id_t), sizeof(pm_constant_id_t)); list->size = 0; list->capacity = capacity; } diff --git a/templates/src/node.c.erb b/templates/src/node.c.erb index 50c63ed426..d8c50e4e74 100644 --- a/templates/src/node.c.erb +++ b/templates/src/node.c.erb @@ -105,6 +105,7 @@ pm_node_destroy(pm_parser_t *parser, pm_node_t *node) { <%- node.fields.each do |field| -%> <%- case field -%> <%- when Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField -%> + <%#<%- when Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::FlagsField, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField, Prism::Template::ConstantListField -%>%> <%- when Prism::Template::NodeField -%> pm_node_destroy(parser, (pm_node_t *)cast-><%= field.name %>); <%- when Prism::Template::OptionalNodeField -%> @@ -115,8 +116,6 @@ pm_node_destroy(pm_parser_t *parser, pm_node_t *node) { pm_string_free(&cast-><%= field.name %>); <%- when Prism::Template::NodeListField -%> pm_node_list_destroy(parser, &cast-><%= field.name %>); - <%- when Prism::Template::ConstantListField -%> - pm_constant_id_list_free(&cast-><%= field.name %>); <%- when Prism::Template::IntegerField -%> pm_integer_free(&cast-><%= field.name %>); <%- else -%> @@ -131,7 +130,6 @@ pm_node_destroy(pm_parser_t *parser, pm_node_t *node) { assert(false && "unreachable"); break; } - // xfree(node); } /** From 3382cf1ca48f1a4f44c07c45745358449b2c337f Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 26 Jun 2024 14:42:10 -0400 Subject: [PATCH 07/10] Temporary --- include/prism/util/pm_integer.h | 4 +++- src/prism.c | 8 +++---- src/util/pm_integer.c | 39 ++++++++++++++++++++++----------- templates/src/node.c.erb | 3 --- 4 files changed, 33 insertions(+), 21 deletions(-) diff --git a/include/prism/util/pm_integer.h b/include/prism/util/pm_integer.h index a9e2966703..134fb6fd32 100644 --- a/include/prism/util/pm_integer.h +++ b/include/prism/util/pm_integer.h @@ -7,6 +7,7 @@ #define PRISM_NUMBER_H #include "prism/defines.h" +#include "prism/allocator.h" #include "prism/util/pm_buffer.h" #include @@ -77,12 +78,13 @@ typedef enum { * has already been validated, as internal validation checks are not performed * here. * + * @param allocator The allocator to use to allocate memory for the integer. * @param integer The integer to parse into. * @param base The base of the integer. * @param start The start of the string. * @param end The end of the string. */ -void pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end); +void pm_integer_parse(pm_allocator_t *allocator, pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end); /** * Compare two integers. This function returns -1 if the left integer is less diff --git a/src/prism.c b/src/prism.c index da739c81db..9ee1b1ae59 100644 --- a/src/prism.c +++ b/src/prism.c @@ -4196,11 +4196,11 @@ pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) { memcpy(digits, start, (unsigned long) (point - start)); memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1)); - pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1); + pm_integer_parse(&parser->allocator, &node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1); digits[0] = '1'; if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1)); - pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point)); + pm_integer_parse(&parser->allocator, &node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point)); free(digits); pm_integers_reduce(&node->numerator, &node->denominator); @@ -4839,7 +4839,7 @@ pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token default: assert(false && "unreachable"); break; } - pm_integer_parse(&node->value, integer_base, token->start, token->end); + pm_integer_parse(&parser->allocator, &node->value, integer_base, token->start, token->end); return node; } @@ -4898,7 +4898,7 @@ pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const default: assert(false && "unreachable"); break; } - pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1); + pm_integer_parse(&parser->allocator, &node->numerator, integer_base, token->start, token->end - 1); return node; } diff --git a/src/util/pm_integer.c b/src/util/pm_integer.c index 4170ecc58d..842ba7944e 100644 --- a/src/util/pm_integer.c +++ b/src/util/pm_integer.c @@ -331,7 +331,7 @@ pm_integer_normalize(pm_integer_t *integer) { * In practice, it converts 10**9 to 1<<32 or 1<<32 to 10**9. */ static void -pm_integer_convert_base(pm_integer_t *destination, const pm_integer_t *source, uint64_t base_from, uint64_t base_to) { +pm_integer_convert_base(pm_allocator_t *allocator, pm_integer_t *destination, const pm_integer_t *source, uint64_t base_from, uint64_t base_to) { size_t source_length; const uint32_t *source_values; INTEGER_EXTRACT(source, source_length, source_values) @@ -383,6 +383,16 @@ pm_integer_convert_base(pm_integer_t *destination, const pm_integer_t *source, u destination->negative = source->negative; pm_integer_normalize(destination); + // If we need to, copy the allocated memory out of the heap and into the + // allocator. + if (destination->length != 0) { + size_t size = destination->length * sizeof(uint32_t); + uint32_t *values = pm_allocator_arena_alloc(allocator, size, sizeof(uint32_t)); + memcpy(values, destination->values, size); + xfree(destination->values); + destination->values = values; + } + xfree(bigints); pm_integer_free(&base); } @@ -393,12 +403,12 @@ pm_integer_convert_base(pm_integer_t *destination, const pm_integer_t *source, u * Convert digits to integer with the given power-of-two base. */ static void -pm_integer_parse_powof2(pm_integer_t *integer, uint32_t base, const uint8_t *digits, size_t digits_length) { +pm_integer_parse_powof2(pm_allocator_t *allocator, pm_integer_t *integer, uint32_t base, const uint8_t *digits, size_t digits_length) { size_t bit = 1; while (base > (uint32_t) (1 << bit)) bit++; size_t length = (digits_length * bit + 31) / 32; - uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t)); + uint32_t *values = pm_allocator_arena_calloc(allocator, length, sizeof(uint32_t), sizeof(uint32_t)); for (size_t digit_index = 0; digit_index < digits_length; digit_index++) { size_t bit_position = bit * (digits_length - digit_index - 1); @@ -420,7 +430,7 @@ pm_integer_parse_powof2(pm_integer_t *integer, uint32_t base, const uint8_t *dig * Convert decimal digits to pm_integer_t. */ static void -pm_integer_parse_decimal(pm_integer_t *integer, const uint8_t *digits, size_t digits_length) { +pm_integer_parse_decimal(pm_allocator_t *allocator, pm_integer_t *integer, const uint8_t *digits, size_t digits_length) { const size_t batch = 9; size_t length = (digits_length + batch - 1) / batch; @@ -438,7 +448,7 @@ pm_integer_parse_decimal(pm_integer_t *integer, const uint8_t *digits, size_t di } // Convert base from 10**9 to 1<<32. - pm_integer_convert_base(integer, &((pm_integer_t) { .length = length, .values = values, .value = 0, .negative = false }), 1000000000, ((uint64_t) 1 << 32)); + pm_integer_convert_base(allocator, integer, &((pm_integer_t) { .length = length, .values = values, .value = 0, .negative = false }), 1000000000, ((uint64_t) 1 << 32)); xfree(values); } @@ -446,7 +456,7 @@ pm_integer_parse_decimal(pm_integer_t *integer, const uint8_t *digits, size_t di * Parse a large integer from a string that does not fit into uint32_t. */ static void -pm_integer_parse_big(pm_integer_t *integer, uint32_t multiplier, const uint8_t *start, const uint8_t *end) { +pm_integer_parse_big(pm_allocator_t *allocator, pm_integer_t *integer, uint32_t multiplier, const uint8_t *start, const uint8_t *end) { // Allocate an array to store digits. uint8_t *digits = xmalloc(sizeof(uint8_t) * (size_t) (end - start)); size_t digits_length = 0; @@ -458,9 +468,9 @@ pm_integer_parse_big(pm_integer_t *integer, uint32_t multiplier, const uint8_t * // Construct pm_integer_t from the digits. if (multiplier == 10) { - pm_integer_parse_decimal(integer, digits, digits_length); + pm_integer_parse_decimal(allocator, integer, digits, digits_length); } else { - pm_integer_parse_powof2(integer, multiplier, digits, digits_length); + pm_integer_parse_powof2(allocator, integer, multiplier, digits, digits_length); } xfree(digits); @@ -472,7 +482,7 @@ pm_integer_parse_big(pm_integer_t *integer, uint32_t multiplier, const uint8_t * * here. */ void -pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end) { +pm_integer_parse(pm_allocator_t *allocator, pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end) { // Ignore unary +. Unary - is parsed differently and will not end up here. // Instead, it will modify the parsed integer later. if (*start == '+') start++; @@ -528,7 +538,7 @@ pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *s if (value > UINT32_MAX) { // If the integer is too large to fit into a single uint32_t, then // we'll parse it as a big integer. - pm_integer_parse_big(integer, multiplier, start, end); + pm_integer_parse_big(allocator, integer, multiplier, start, end); return; } } @@ -625,12 +635,15 @@ pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer) { } // Otherwise, first we'll convert the base from 1<<32 to 10**9. + pm_allocator_t allocator; + pm_allocator_init(&allocator, 1024); + pm_integer_t converted = { 0 }; - pm_integer_convert_base(&converted, integer, (uint64_t) 1 << 32, 1000000000); + pm_integer_convert_base(&allocator, &converted, integer, (uint64_t) 1 << 32, 1000000000); if (converted.values == NULL) { pm_buffer_append_format(buffer, "%" PRIu32, converted.value); - pm_integer_free(&converted); + pm_allocator_free(&allocator); return; } @@ -655,7 +668,7 @@ pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer) { // Finally, append the string to the buffer and free the digits. pm_buffer_append_string(buffer, digits + start_offset, digits_length - start_offset); xfree(digits); - pm_integer_free(&converted); + pm_allocator_free(&allocator); } /** diff --git a/templates/src/node.c.erb b/templates/src/node.c.erb index d8c50e4e74..dddb7c7273 100644 --- a/templates/src/node.c.erb +++ b/templates/src/node.c.erb @@ -105,7 +105,6 @@ pm_node_destroy(pm_parser_t *parser, pm_node_t *node) { <%- node.fields.each do |field| -%> <%- case field -%> <%- when Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField -%> - <%#<%- when Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::FlagsField, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField, Prism::Template::ConstantListField -%>%> <%- when Prism::Template::NodeField -%> pm_node_destroy(parser, (pm_node_t *)cast-><%= field.name %>); <%- when Prism::Template::OptionalNodeField -%> @@ -116,8 +115,6 @@ pm_node_destroy(pm_parser_t *parser, pm_node_t *node) { pm_string_free(&cast-><%= field.name %>); <%- when Prism::Template::NodeListField -%> pm_node_list_destroy(parser, &cast-><%= field.name %>); - <%- when Prism::Template::IntegerField -%> - pm_integer_free(&cast-><%= field.name %>); <%- else -%> <%- raise -%> <%- end -%> From ac6abc2422d59aae1f1dc4fdd4c8ae7cb346e478 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Wed, 26 Jun 2024 15:37:35 -0400 Subject: [PATCH 08/10] work on string fields --- include/prism/defines.h | 1 + include/prism/util/pm_string.h | 3 +- src/allocator.c | 4 +-- src/prism.c | 50 ++++++++++++++++++------------ src/util/pm_string.c | 4 +-- templates/ext/prism/api_node.c.erb | 2 +- templates/src/node.c.erb | 9 ++++-- 7 files changed, 45 insertions(+), 28 deletions(-) diff --git a/include/prism/defines.h b/include/prism/defines.h index e78c7dd75c..782216ee3e 100644 --- a/include/prism/defines.h +++ b/include/prism/defines.h @@ -164,6 +164,7 @@ * #endif * ``` */ + #ifdef PRISM_XALLOCATOR #include "prism_xallocator.h" #else diff --git a/include/prism/util/pm_string.h b/include/prism/util/pm_string.h index f99f1abdf3..29f623e4f6 100644 --- a/include/prism/util/pm_string.h +++ b/include/prism/util/pm_string.h @@ -7,6 +7,7 @@ #define PRISM_STRING_H #include "prism/defines.h" +#include "prism/allocator.h" #include #include @@ -150,7 +151,7 @@ PRISM_EXPORTED_FUNCTION pm_string_init_result_t pm_string_file_init(pm_string_t * * @param string The string to ensure is owned. */ -void pm_string_ensure_owned(pm_string_t *string); +void pm_string_ensure_owned(pm_allocator_t *allocator, pm_string_t *string); /** * Compare the underlying lengths and bytes of two strings. Returns 0 if the diff --git a/src/allocator.c b/src/allocator.c index 97f3d3107b..90d168a938 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -110,9 +110,9 @@ void pm_allocator_free(pm_allocator_t *allocator) { // should free it. Otherwise we assume it was embedded into another // struct or allocated on the stack. if (top_level) { - xfree(previous->start); + free(previous->start); } else { - xfree(previous); + free(previous); } top_level = false; diff --git a/src/prism.c b/src/prism.c index 9ee1b1ae59..81bc006ca4 100644 --- a/src/prism.c +++ b/src/prism.c @@ -7008,14 +7008,35 @@ pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_t return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY); } +/** + * Move contents of parser->current_string into the parser's arena allocator + * for a pm_string_t that will be on a node. + */ +static pm_string_t +pm_flush_current_string(pm_parser_t *parser) +{ + pm_string_t current_string = parser->current_string; + if (current_string.type == PM_STRING_OWNED) { + size_t len = pm_string_length(&parser->current_string); + if (len > 0) { + uint8_t *new_source = pm_allocator_arena_alloc(&parser->allocator, len, 1); + memcpy(new_source, pm_string_source(&parser->current_string), len); + pm_string_owned_init(¤t_string, new_source, len); + } + } + pm_string_free(&parser->current_string); + parser->current_string = PM_STRING_EMPTY; + return current_string; +} + /** * Allocate a new StringNode node and create it using the current string on the * parser. */ static pm_string_node_t * pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) { - pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string); - parser->current_string = PM_STRING_EMPTY; + pm_string_t current_string = pm_flush_current_string(parser); + pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, ¤t_string); return node; } @@ -7301,8 +7322,8 @@ pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_t */ static pm_symbol_node_t * pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) { - pm_symbol_node_t *node = pm_symbol_node_create_unescaped(parser, opening, value, closing, &parser->current_string, parse_symbol_encoding(parser, value, &parser->current_string, false)); - parser->current_string = PM_STRING_EMPTY; + pm_string_t current_string = pm_flush_current_string(parser); + pm_symbol_node_t *node = pm_symbol_node_create_unescaped(parser, opening, value, closing, ¤t_string, parse_symbol_encoding(parser, value, ¤t_string, false)); return node; } @@ -16373,10 +16394,10 @@ parse_method_definition_name(pm_parser_t *parser) { } static void -parse_heredoc_dedent_string(pm_string_t *string, size_t common_whitespace) { +parse_heredoc_dedent_string(pm_parser_t *parser, pm_string_t *string, size_t common_whitespace) { // Get a reference to the string struct that is being held by the string // node. This is the value we're going to actually manipulate. - pm_string_ensure_owned(string); + pm_string_ensure_owned(&parser->allocator, string); // Now get the bounds of the existing string. We'll use this as a // destination to move bytes into. We'll also use it for bounds checking @@ -16437,7 +16458,7 @@ parse_heredoc_dedent(pm_parser_t *parser, pm_node_list_t *nodes, size_t common_w pm_string_node_t *string_node = ((pm_string_node_t *) node); if (dedent_next) { - parse_heredoc_dedent_string(&string_node->unescaped, common_whitespace); + parse_heredoc_dedent_string(parser, &string_node->unescaped, common_whitespace); } if (string_node->unescaped.length == 0) { @@ -18194,7 +18215,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } pop_block_exits(parser, previous_block_exits); - pm_allocator_reset(&parser->block_exits_allocator, block_exits_current); pm_void_statements_check(parser, statements, true); return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous); @@ -18499,7 +18519,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (size_t) -1) && (common_whitespace != 0)) { - parse_heredoc_dedent_string(&cast->unescaped, common_whitespace); + parse_heredoc_dedent_string(parser, &cast->unescaped, common_whitespace); } node = (pm_node_t *) cast; @@ -18908,7 +18928,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } flush_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); return (pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous); } @@ -19033,14 +19052,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_do_loop_stack_pop(parser); flush_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); return (pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &operator, expression, statements, &parser->previous); } - pm_node_list_t current_block_exits = { 0 }; - pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); - pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1)); pm_token_t name = parser->previous; if (name.type != PM_TOKEN_CONSTANT) { @@ -19387,7 +19402,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.start, parse_operator_symbol_name(&name)); flush_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); return (pm_node_t *) pm_def_node_create( parser, @@ -20155,7 +20169,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // expression at least has something in it. We'll need to check if the // following token is the end (in which case we can return a plain // regular expression) or if it's not then it has interpolation. - pm_string_t unescaped = parser->current_string; + pm_string_t unescaped = pm_flush_current_string(parser); pm_token_t content = parser->current; bool ascii_only = parser->current_regular_expression_ascii_only; parser_lex(parser); @@ -20206,7 +20220,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_t *part; while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) { if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) { - pm_interpolated_regular_expression_node_append(interpolated, part); pm_interpolated_regular_expression_node_append(parser, interpolated, part); } } @@ -20252,7 +20265,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // at least has something in it. We'll need to check if the // following token is the end (in which case we can return a // plain string) or if it's not then it has interpolation. - pm_string_t unescaped = parser->current_string; + pm_string_t unescaped = pm_flush_current_string(parser);; pm_token_t content = parser->current; parser_lex(parser); @@ -21951,7 +21964,6 @@ parse_program(pm_parser_t *parser) { statements = wrap_statements(parser, statements); } else { flush_block_exits(parser, previous_block_exits); - pm_node_list_free(¤t_block_exits); } return (pm_node_t *) pm_program_node_create(parser, &locals, statements); diff --git a/src/util/pm_string.c b/src/util/pm_string.c index 7e56dec9f7..e424bd3321 100644 --- a/src/util/pm_string.c +++ b/src/util/pm_string.c @@ -312,13 +312,13 @@ pm_string_file_init(pm_string_t *string, const char *filepath) { * copy over the previous source. */ void -pm_string_ensure_owned(pm_string_t *string) { +pm_string_ensure_owned(pm_allocator_t *allocator, pm_string_t *string) { if (string->type == PM_STRING_OWNED) return; size_t length = pm_string_length(string); const uint8_t *source = pm_string_source(string); - uint8_t *memory = xmalloc(length); + uint8_t *memory = pm_allocator_arena_alloc(allocator, length, 1); if (!memory) return; pm_string_owned_init(string, memory, length); diff --git a/templates/ext/prism/api_node.c.erb b/templates/ext/prism/api_node.c.erb index 03615b0ae2..4bb9f980be 100644 --- a/templates/ext/prism/api_node.c.erb +++ b/templates/ext/prism/api_node.c.erb @@ -100,7 +100,7 @@ pm_node_stack_pop(pm_node_stack_node_t **stack) { const pm_node_t *visit = current->visit; *stack = current->prev; - xfree(current); + // xfree(current); return visit; } diff --git a/templates/src/node.c.erb b/templates/src/node.c.erb index dddb7c7273..24fa0bad79 100644 --- a/templates/src/node.c.erb +++ b/templates/src/node.c.erb @@ -100,11 +100,12 @@ pm_node_destroy(pm_parser_t *parser, pm_node_t *node) { #line <%= __LINE__ + 1 %> "prism/templates/src/<%= File.basename(__FILE__) %>" case <%= node.type %>: { <%- if node.fields.any? { |field| ![Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField].include?(field.class) } -%> + <% puts node.human %> pm_<%= node.human %>_t *cast = (pm_<%= node.human %>_t *) node; <%- end -%> <%- node.fields.each do |field| -%> <%- case field -%> - <%- when Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField -%> + <%- when Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField, Prism::Template::ConstantListField -%> <%- when Prism::Template::NodeField -%> pm_node_destroy(parser, (pm_node_t *)cast-><%= field.name %>); <%- when Prism::Template::OptionalNodeField -%> @@ -112,11 +113,13 @@ pm_node_destroy(pm_parser_t *parser, pm_node_t *node) { pm_node_destroy(parser, (pm_node_t *)cast-><%= field.name %>); } <%- when Prism::Template::StringField -%> - pm_string_free(&cast-><%= field.name %>); + (void)cast; <%- when Prism::Template::NodeListField -%> pm_node_list_destroy(parser, &cast-><%= field.name %>); + <%- when Prism::Template::IntegerField -%> + pm_integer_free(&cast-><%= field.name %>); <%- else -%> - <%- raise -%> + <%- raise node.inspect -%> <%- end -%> <%- end -%> break; From 2b9d06e925302a950cf48d7099708280daf50562 Mon Sep 17 00:00:00 2001 From: Chris Covington Date: Wed, 20 Nov 2024 21:57:44 -0800 Subject: [PATCH 09/10] dont free integer nodes that are arena alloced --- templates/src/node.c.erb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/templates/src/node.c.erb b/templates/src/node.c.erb index 24fa0bad79..201139f676 100644 --- a/templates/src/node.c.erb +++ b/templates/src/node.c.erb @@ -99,13 +99,12 @@ pm_node_destroy(pm_parser_t *parser, pm_node_t *node) { <%- nodes.each do |node| -%> #line <%= __LINE__ + 1 %> "prism/templates/src/<%= File.basename(__FILE__) %>" case <%= node.type %>: { - <%- if node.fields.any? { |field| ![Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField].include?(field.class) } -%> - <% puts node.human %> + <%- if node.fields.any? { |field| ![Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField, Prism::Template::IntegerField].include?(field.class) } -%> pm_<%= node.human %>_t *cast = (pm_<%= node.human %>_t *) node; <%- end -%> <%- node.fields.each do |field| -%> <%- case field -%> - <%- when Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField, Prism::Template::ConstantListField -%> + <%- when Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField, Prism::Template::ConstantListField, Prism::Template::IntegerField -%> <%- when Prism::Template::NodeField -%> pm_node_destroy(parser, (pm_node_t *)cast-><%= field.name %>); <%- when Prism::Template::OptionalNodeField -%> @@ -116,8 +115,6 @@ pm_node_destroy(pm_parser_t *parser, pm_node_t *node) { (void)cast; <%- when Prism::Template::NodeListField -%> pm_node_list_destroy(parser, &cast-><%= field.name %>); - <%- when Prism::Template::IntegerField -%> - pm_integer_free(&cast-><%= field.name %>); <%- else -%> <%- raise node.inspect -%> <%- end -%> From 57b85f897d9e4c7ce60d725f0ff071fbbb59eae8 Mon Sep 17 00:00:00 2001 From: Chris Covington Date: Wed, 20 Nov 2024 22:09:40 -0800 Subject: [PATCH 10/10] Lift up ignored nodes to make it a little more clear what the exceptional case is --- templates/src/node.c.erb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/templates/src/node.c.erb b/templates/src/node.c.erb index 201139f676..5485c1457a 100644 --- a/templates/src/node.c.erb +++ b/templates/src/node.c.erb @@ -93,18 +93,22 @@ pm_node_list_destroy(pm_parser_t *parser, pm_node_list_t *list) { * using the parser argument, but it's there to allow for the future possibility * of pre-allocating larger memory pools. */ +<%- ignored_node_fields_for_destroy = [ + Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, + Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField, Prism::Template::ConstantListField, + Prism::Template::IntegerField] -%> PRISM_EXPORTED_FUNCTION void pm_node_destroy(pm_parser_t *parser, pm_node_t *node) { switch (PM_NODE_TYPE(node)) { <%- nodes.each do |node| -%> #line <%= __LINE__ + 1 %> "prism/templates/src/<%= File.basename(__FILE__) %>" case <%= node.type %>: { - <%- if node.fields.any? { |field| ![Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField, Prism::Template::IntegerField].include?(field.class) } -%> + <%- if node.fields.any? { |field| !ignored_node_fields_for_destroy.include?(field.class) } -%> pm_<%= node.human %>_t *cast = (pm_<%= node.human %>_t *) node; <%- end -%> <%- node.fields.each do |field| -%> <%- case field -%> - <%- when Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField, Prism::Template::ConstantListField, Prism::Template::IntegerField -%> + <%- when *ignored_node_fields_for_destroy -%> <%- when Prism::Template::NodeField -%> pm_node_destroy(parser, (pm_node_t *)cast-><%= field.name %>); <%- when Prism::Template::OptionalNodeField -%>