diff options
Diffstat (limited to 'node.c')
| -rw-r--r-- | node.c | 308 |
1 files changed, 127 insertions, 181 deletions
@@ -10,22 +10,12 @@ **********************************************************************/ #ifdef UNIVERSAL_PARSER - #include <stddef.h> #include "node.h" #include "rubyparser.h" -#include "internal/parse.h" -#define T_NODE 0x1b - -#else +#endif -#include "internal.h" -#include "internal/hash.h" #include "internal/variable.h" -#include "ruby/ruby.h" -#include "vm_core.h" - -#endif #define NODE_BUF_DEFAULT_SIZE (sizeof(struct RNode) * 16) @@ -39,7 +29,7 @@ init_node_buffer_elem(node_buffer_elem_t *nbe, size_t allocated, void *xmalloc(s } static void -init_node_buffer_list(node_buffer_list_t * nb, node_buffer_elem_t *head, void *xmalloc(size_t)) +init_node_buffer_list(node_buffer_list_t *nb, node_buffer_elem_t *head, void *xmalloc(size_t)) { init_node_buffer_elem(head, NODE_BUF_DEFAULT_SIZE, xmalloc); nb->head = nb->last = head; @@ -48,7 +38,6 @@ init_node_buffer_list(node_buffer_list_t * nb, node_buffer_elem_t *head, void *x #ifdef UNIVERSAL_PARSER #define ruby_xmalloc config->malloc -#define Qnil config->qnil #endif #ifdef UNIVERSAL_PARSER @@ -60,56 +49,34 @@ rb_node_buffer_new(void) #endif { const size_t bucket_size = offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_SIZE; - const size_t alloc_size = sizeof(node_buffer_t) + (bucket_size * 2); + const size_t alloc_size = sizeof(node_buffer_t) + (bucket_size); STATIC_ASSERT( integer_overflow, offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_SIZE - > sizeof(node_buffer_t) + 2 * sizeof(node_buffer_elem_t)); + > sizeof(node_buffer_t) + sizeof(node_buffer_elem_t)); node_buffer_t *nb = ruby_xmalloc(alloc_size); - init_node_buffer_list(&nb->unmarkable, (node_buffer_elem_t*)&nb[1], ruby_xmalloc); - init_node_buffer_list(&nb->markable, (node_buffer_elem_t*)((size_t)nb->unmarkable.head + bucket_size), ruby_xmalloc); + init_node_buffer_list(&nb->buffer_list, (node_buffer_elem_t*)&nb[1], ruby_xmalloc); nb->local_tables = 0; - nb->mark_hash = Qnil; - nb->tokens = Qnil; -#ifdef UNIVERSAL_PARSER - nb->config = config; -#endif + nb->tokens = 0; return nb; } #ifdef UNIVERSAL_PARSER #undef ruby_xmalloc -#define ruby_xmalloc ast->node_buffer->config->malloc +#define ruby_xmalloc ast->config->malloc #undef xfree -#define xfree ast->node_buffer->config->free -#define rb_ident_hash_new ast->node_buffer->config->ident_hash_new -#define rb_xmalloc_mul_add ast->node_buffer->config->xmalloc_mul_add -#define ruby_xrealloc(var,size) (ast->node_buffer->config->realloc_n((void *)var, 1, size)) -#define rb_gc_mark ast->node_buffer->config->gc_mark -#define rb_gc_location ast->node_buffer->config->gc_location -#define rb_gc_mark_movable ast->node_buffer->config->gc_mark_movable -#undef Qnil -#define Qnil ast->node_buffer->config->qnil -#define Qtrue ast->node_buffer->config->qtrue -#define NIL_P ast->node_buffer->config->nil_p -#define rb_hash_aset ast->node_buffer->config->hash_aset -#define rb_hash_delete ast->node_buffer->config->hash_delete -#define RB_OBJ_WRITE(old, slot, young) ast->node_buffer->config->obj_write((VALUE)(old), (VALUE *)(slot), (VALUE)(young)) +#define xfree ast->config->free +#define rb_xmalloc_mul_add ast->config->xmalloc_mul_add +#define ruby_xrealloc(var,size) (ast->config->realloc_n((void *)var, 1, size)) #endif typedef void node_itr_t(rb_ast_t *ast, void *ctx, NODE *node); static void iterate_node_values(rb_ast_t *ast, node_buffer_list_t *nb, node_itr_t * func, void *ctx); -/* Setup NODE structure. - * NODE is not an object managed by GC, but it imitates an object - * so that it can work with `RB_TYPE_P(obj, T_NODE)`. - * This dirty hack is needed because Ripper jumbles NODEs and other type - * objects. - */ void rb_node_init(NODE *n, enum node_type type) { - RNODE(n)->flags = T_NODE; + RNODE(n)->flags = 0; nd_init_type(RNODE(n), type); RNODE(n)->nd_loc.beg_pos.lineno = 0; RNODE(n)->nd_loc.beg_pos.column = 0; @@ -172,16 +139,66 @@ struct rb_ast_local_table_link { static void parser_string_free(rb_ast_t *ast, rb_parser_string_t *str) { + if (!str) return; + xfree(str->ptr); xfree(str); } static void +parser_ast_token_free(rb_ast_t *ast, rb_parser_ast_token_t *token) +{ + if (!token) return; + parser_string_free(ast, token->str); + xfree(token); +} + +static void +parser_tokens_free(rb_ast_t *ast, rb_parser_ary_t *tokens) +{ + for (long i = 0; i < tokens->len; i++) { + parser_ast_token_free(ast, tokens->data[i]); + } + xfree(tokens->data); + xfree(tokens); +} + +static void +parser_nodes_free(rb_ast_t *ast, rb_parser_ary_t *nodes) +{ + /* Do nothing for nodes because nodes are freed when rb_ast_t is freed */ + xfree(nodes->data); + xfree(nodes); +} + +static void free_ast_value(rb_ast_t *ast, void *ctx, NODE *node) { switch (nd_type(node)) { + case NODE_STR: + parser_string_free(ast, RNODE_STR(node)->string); + break; + case NODE_DSTR: + parser_string_free(ast, RNODE_DSTR(node)->string); + break; + case NODE_XSTR: + parser_string_free(ast, RNODE_XSTR(node)->string); + break; + case NODE_DXSTR: + parser_string_free(ast, RNODE_DXSTR(node)->string); + break; case NODE_SYM: parser_string_free(ast, RNODE_SYM(node)->string); break; + case NODE_REGX: + case NODE_MATCH: + parser_string_free(ast, RNODE_REGX(node)->string); + break; + case NODE_DSYM: + parser_string_free(ast, RNODE_DSYM(node)->string); + break; + case NODE_DREGX: + parser_string_free(ast, RNODE_DREGX(node)->string); + break; case NODE_FILE: parser_string_free(ast, RNODE_FILE(node)->path); break; @@ -197,6 +214,9 @@ free_ast_value(rb_ast_t *ast, void *ctx, NODE *node) case NODE_IMAGINARY: xfree(RNODE_IMAGINARY(node)->val); break; + case NODE_UNDEF: + parser_nodes_free(ast, RNODE_UNDEF(node)->nd_undefs); + break; default: break; } @@ -205,9 +225,11 @@ free_ast_value(rb_ast_t *ast, void *ctx, NODE *node) static void rb_node_buffer_free(rb_ast_t *ast, node_buffer_t *nb) { - iterate_node_values(ast, &nb->unmarkable, free_ast_value, NULL); - node_buffer_list_free(ast, &nb->unmarkable); - node_buffer_list_free(ast, &nb->markable); + if (nb->tokens) { + parser_tokens_free(ast, nb->tokens); + } + iterate_node_values(ast, &nb->buffer_list, free_ast_value, NULL); + node_buffer_list_free(ast, &nb->buffer_list); struct rb_ast_local_table_link *local_table = nb->local_tables; while (local_table) { struct rb_ast_local_table_link *next_table = local_table->next; @@ -244,46 +266,14 @@ ast_newnode_in_bucket(rb_ast_t *ast, node_buffer_list_t *nb, size_t size, size_t return ptr; } -RBIMPL_ATTR_PURE() -static bool -nodetype_markable_p(enum node_type type) -{ - switch (type) { - case NODE_MATCH: - case NODE_LIT: - case NODE_STR: - case NODE_XSTR: - case NODE_DSTR: - case NODE_DXSTR: - case NODE_DREGX: - case NODE_DSYM: - return true; - default: - return false; - } -} - NODE * rb_ast_newnode(rb_ast_t *ast, enum node_type type, size_t size, size_t alignment) { node_buffer_t *nb = ast->node_buffer; - node_buffer_list_t *bucket = - (nodetype_markable_p(type) ? &nb->markable : &nb->unmarkable); + node_buffer_list_t *bucket = &nb->buffer_list; return ast_newnode_in_bucket(ast, bucket, size, alignment); } -#if RUBY_DEBUG -void -rb_ast_node_type_change(NODE *n, enum node_type type) -{ - enum node_type old_type = nd_type(n); - if (nodetype_markable_p(old_type) != nodetype_markable_p(type)) { - rb_bug("node type changed: %s -> %s", - ruby_node_name(old_type), ruby_node_name(type)); - } -} -#endif - rb_ast_id_table_t * rb_ast_new_local_table(rb_ast_t *ast, int size) { @@ -321,14 +311,18 @@ rb_ast_t * rb_ast_new(const rb_parser_config_t *config) { node_buffer_t *nb = rb_node_buffer_new(config); - return config->ast_new((VALUE)nb); + rb_ast_t *ast = (rb_ast_t *)config->calloc(1, sizeof(rb_ast_t)); + ast->config = config; + ast->node_buffer = nb; + return ast; } #else rb_ast_t * rb_ast_new(void) { node_buffer_t *nb = rb_node_buffer_new(); - rb_ast_t *ast = (rb_ast_t *)rb_imemo_new(imemo_ast, 0, 0, 0, (VALUE)nb); + rb_ast_t *ast = ruby_xcalloc(1, sizeof(rb_ast_t)); + ast->node_buffer = nb; return ast; } #endif @@ -354,80 +348,21 @@ iterate_node_values(rb_ast_t *ast, node_buffer_list_t *nb, node_itr_t * func, vo } static void -mark_ast_value(rb_ast_t *ast, void *ctx, NODE *node) -{ -#ifdef UNIVERSAL_PARSER - bug_report_func rb_bug = ast->node_buffer->config->bug; -#endif - - switch (nd_type(node)) { - case NODE_MATCH: - case NODE_LIT: - case NODE_STR: - case NODE_XSTR: - case NODE_DSTR: - case NODE_DXSTR: - case NODE_DREGX: - case NODE_DSYM: - rb_gc_mark_movable(RNODE_LIT(node)->nd_lit); - break; - default: - rb_bug("unreachable node %s", ruby_node_name(nd_type(node))); - } -} - -static void -update_ast_value(rb_ast_t *ast, void *ctx, NODE *node) -{ -#ifdef UNIVERSAL_PARSER - bug_report_func rb_bug = ast->node_buffer->config->bug; -#endif - - switch (nd_type(node)) { - case NODE_MATCH: - case NODE_LIT: - case NODE_STR: - case NODE_XSTR: - case NODE_DSTR: - case NODE_DXSTR: - case NODE_DREGX: - case NODE_DSYM: - RNODE_LIT(node)->nd_lit = rb_gc_location(RNODE_LIT(node)->nd_lit); - break; - default: - rb_bug("unreachable"); - } -} - -void -rb_ast_update_references(rb_ast_t *ast) -{ - if (ast->node_buffer) { - node_buffer_t *nb = ast->node_buffer; - - iterate_node_values(ast, &nb->markable, update_ast_value, NULL); - } -} - -void -rb_ast_mark(rb_ast_t *ast) +script_lines_free(rb_ast_t *ast, rb_parser_ary_t *script_lines) { - if (ast->node_buffer) { - rb_gc_mark(ast->node_buffer->mark_hash); - rb_gc_mark(ast->node_buffer->tokens); - node_buffer_t *nb = ast->node_buffer; - iterate_node_values(ast, &nb->markable, mark_ast_value, NULL); - if (ast->body.script_lines) rb_gc_mark(ast->body.script_lines); + if (!script_lines) return; + for (long i = 0; i < script_lines->len; i++) { + parser_string_free(ast, (rb_parser_string_t *)script_lines->data[i]); } + xfree(script_lines->data); + xfree(script_lines); } void rb_ast_free(rb_ast_t *ast) { - if (ast->node_buffer) { - rb_node_buffer_free(ast, ast->node_buffer); - ast->node_buffer = 0; - } + rb_ast_dispose(ast); + xfree(ast); } static size_t @@ -445,56 +380,67 @@ buffer_list_size(node_buffer_list_t *nb) size_t rb_ast_memsize(const rb_ast_t *ast) { - size_t size = 0; + size_t size = sizeof(rb_ast_t); node_buffer_t *nb = ast->node_buffer; + rb_parser_ary_t *tokens = NULL; + struct rb_ast_local_table_link *link = NULL; + rb_parser_ary_t *script_lines = ast->body.script_lines; + + long i; if (nb) { size += sizeof(node_buffer_t); - size += buffer_list_size(&nb->unmarkable); - size += buffer_list_size(&nb->markable); + size += buffer_list_size(&nb->buffer_list); + link = nb->local_tables; + tokens = nb->tokens; } - return size; -} -void -rb_ast_dispose(rb_ast_t *ast) -{ - rb_ast_free(ast); -} + while (link) { + size += sizeof(struct rb_ast_local_table_link); + size += link->size * sizeof(ID); + link = link->next; + } -void -rb_ast_add_mark_object(rb_ast_t *ast, VALUE obj) -{ - if (NIL_P(ast->node_buffer->mark_hash)) { - RB_OBJ_WRITE(ast, &ast->node_buffer->mark_hash, rb_ident_hash_new()); + if (tokens) { + size += sizeof(rb_parser_ary_t); + for (i = 0; i < tokens->len; i++) { + size += sizeof(rb_parser_ast_token_t); + rb_parser_ast_token_t *token = tokens->data[i]; + size += sizeof(rb_parser_string_t); + size += token->str->len + 1; + } } - rb_hash_aset(ast->node_buffer->mark_hash, obj, Qtrue); -} -void -rb_ast_delete_mark_object(rb_ast_t *ast, VALUE obj) -{ - if (NIL_P(ast->node_buffer->mark_hash)) return; - rb_hash_delete(ast->node_buffer->mark_hash, obj); -} + if (script_lines) { + size += sizeof(rb_parser_ary_t); + for (i = 0; i < script_lines->len; i++) { + size += sizeof(rb_parser_string_t); + size += ((rb_parser_string_t *)script_lines->data[i])->len + 1; + } + } -VALUE -rb_ast_tokens(rb_ast_t *ast) -{ - return ast->node_buffer->tokens; + return size; } void -rb_ast_set_tokens(rb_ast_t *ast, VALUE tokens) +rb_ast_dispose(rb_ast_t *ast) { - RB_OBJ_WRITE(ast, &ast->node_buffer->tokens, tokens); + if (ast && ast->node_buffer) { + script_lines_free(ast, ast->body.script_lines); + ast->body.script_lines = NULL; + rb_node_buffer_free(ast, ast->node_buffer); + ast->node_buffer = 0; + } } VALUE rb_node_set_type(NODE *n, enum node_type t) { -#if RUBY_DEBUG - rb_ast_node_type_change(n, t); -#endif return nd_init_type(n, t); } + +enum node_type +rb_node_get_type(const NODE *n) +{ + return (enum node_type)nd_type(n); +} |
