Refactor hacky ID tables to struct rb_ast_id_table_t

The implementation of a local variable tables was represented as `ID*`,
but it was very hacky: the first element is not an ID but the size of
the table, and, the last element is (sometimes) a link to the next local
table only when the id tables are a linked list.

This change converts the hacky implementation to a normal struct.
This commit is contained in:
Yusuke Endoh 2021-11-18 03:40:49 +09:00
Родитель 86ad878e6a
Коммит feda058531
7 изменённых файлов: 79 добавлений и 54 удалений

6
ast.c
Просмотреть файл

@ -600,11 +600,11 @@ node_children(rb_ast_t *ast, const NODE *node)
}
case NODE_SCOPE:
{
ID *tbl = node->nd_tbl;
int i, size = tbl ? (int)*tbl++ : 0;
rb_ast_id_table_t *tbl = node->nd_tbl;
int i, size = tbl ? tbl->size : 0;
VALUE locals = rb_ary_new_capa(size);
for (i = 0; i < size; i++) {
rb_ary_push(locals, var_name(tbl[i]));
rb_ary_push(locals, var_name(tbl->ids[i]));
}
return rb_ary_new_from_args(3, locals, NEW_CHILD(ast, node->nd_args), NEW_CHILD(ast, node->nd_body));
}

Просмотреть файл

@ -7937,6 +7937,7 @@ localeinit.$(OBJEXT): {$(VPATH)}st.h
localeinit.$(OBJEXT): {$(VPATH)}subst.h
main.$(OBJEXT): $(hdrdir)/ruby.h
main.$(OBJEXT): $(hdrdir)/ruby/ruby.h
main.$(OBJEXT): $(top_srcdir)/internal/compilers.h
main.$(OBJEXT): {$(VPATH)}assert.h
main.$(OBJEXT): {$(VPATH)}backward.h
main.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@ -8463,6 +8464,7 @@ math.$(OBJEXT): {$(VPATH)}missing.h
math.$(OBJEXT): {$(VPATH)}st.h
math.$(OBJEXT): {$(VPATH)}subst.h
memory_view.$(OBJEXT): $(hdrdir)/ruby/ruby.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/compilers.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/hash.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/variable.h
memory_view.$(OBJEXT): {$(VPATH)}assert.h

Просмотреть файл

@ -482,7 +482,7 @@ static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
static int iseq_set_local_table(rb_iseq_t *iseq, const ID *tbl);
static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl);
static int iseq_set_exception_local_table(rb_iseq_t *iseq);
static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
@ -1946,21 +1946,13 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
}
static int
iseq_set_local_table(rb_iseq_t *iseq, const ID *tbl)
iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl)
{
unsigned int size;
if (tbl) {
size = (unsigned int)*tbl;
tbl++;
}
else {
size = 0;
}
unsigned int size = tbl ? tbl->size : 0;
if (size > 0) {
ID *ids = (ID *)ALLOC_N(ID, size);
MEMCPY(ids, tbl, ID, size);
MEMCPY(ids, tbl->ids, ID, size);
iseq->body->local_table = ids;
}
iseq->body->local_table_size = size;
@ -7908,17 +7900,20 @@ compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const N
// local table without non-mandatory parameters
const int skip_local_size = iseq->body->param.size - iseq->body->param.lead_num;
const int table_size = iseq->body->local_table_size - skip_local_size;
ID *tbl = ALLOCA_N(ID, table_size + 1);
tbl[0] = table_size;
VALUE idtmp = 0;
rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
tbl->size = table_size;
int i;
// lead parameters
for (i=0; i<iseq->body->param.lead_num; i++) {
tbl[i+1] = iseq->body->local_table[i];
tbl->ids[i] = iseq->body->local_table[i];
}
// local variables
for (; i<table_size; i++) {
tbl[i+1] = iseq->body->local_table[i + skip_local_size];
tbl->ids[i] = iseq->body->local_table[i + skip_local_size];
}
NODE scope_node;
@ -7939,6 +7934,7 @@ compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const N
ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option);
GET_VM()->builtin_inline_index = prev_inline_index;
ALLOCV_END(idtmp);
return COMPILE_OK;
}

47
node.c
Просмотреть файл

@ -1043,12 +1043,12 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
ANN("new scope");
ANN("format: [nd_tbl]: local table, [nd_args]: arguments, [nd_body]: body");
F_CUSTOM1(nd_tbl, "local table") {
ID *tbl = node->nd_tbl;
rb_ast_id_table_t *tbl = node->nd_tbl;
int i;
int size = tbl ? (int)*tbl++ : 0;
int size = tbl ? tbl->size : 0;
if (size == 0) A("(empty)");
for (i = 0; i < size; i++) {
A_ID(tbl[i]); if (i < size - 1) A(",");
A_ID(tbl->ids[i]); if (i < size - 1) A(",");
}
}
F_NODE(nd_args, "arguments");
@ -1162,7 +1162,7 @@ typedef struct {
struct node_buffer_struct {
node_buffer_list_t unmarkable;
node_buffer_list_t markable;
ID *local_tables;
struct rb_ast_local_table_link *local_tables;
VALUE mark_hash;
};
@ -1205,15 +1205,22 @@ node_buffer_list_free(node_buffer_list_t * nb)
}
}
struct rb_ast_local_table_link {
struct rb_ast_local_table_link *next;
// struct rb_ast_id_table {
int size;
ID ids[FLEX_ARY_LEN];
// }
};
static void
rb_node_buffer_free(node_buffer_t *nb)
{
node_buffer_list_free(&nb->unmarkable);
node_buffer_list_free(&nb->markable);
ID * local_table = nb->local_tables;
struct rb_ast_local_table_link *local_table = nb->local_tables;
while (local_table) {
unsigned int size = (unsigned int)*local_table;
ID * next_table = (ID *)local_table[size + 1];
struct rb_ast_local_table_link *next_table = local_table->next;
xfree(local_table);
local_table = next_table;
}
@ -1277,12 +1284,28 @@ rb_ast_node_type_change(NODE *n, enum node_type type)
}
}
void
rb_ast_add_local_table(rb_ast_t *ast, ID *buf)
rb_ast_id_table_t *
rb_ast_new_local_table(rb_ast_t *ast, int size)
{
unsigned int size = (unsigned int)*buf;
buf[size + 1] = (ID)ast->node_buffer->local_tables;
ast->node_buffer->local_tables = buf;
size_t alloc_size = sizeof(struct rb_ast_local_table_link) + size * sizeof(ID);
struct rb_ast_local_table_link *link = ruby_xmalloc(alloc_size);
link->next = ast->node_buffer->local_tables;
ast->node_buffer->local_tables = link;
link->size = size;
return (rb_ast_id_table_t *) &link->size;
}
rb_ast_id_table_t *
rb_ast_resize_latest_local_table(rb_ast_t *ast, int size)
{
struct rb_ast_local_table_link *link = ast->node_buffer->local_tables;
size_t alloc_size = sizeof(struct rb_ast_local_table_link) + size * sizeof(ID);
link = ruby_xrealloc(link, alloc_size);
ast->node_buffer->local_tables = link;
link->size = size;
return (rb_ast_id_table_t *) &link->size;
}
void

12
node.h
Просмотреть файл

@ -11,6 +11,8 @@
**********************************************************************/
#include "internal/compilers.h"
#if defined(__cplusplus)
extern "C" {
#if 0
@ -146,13 +148,18 @@ code_loc_gen(const rb_code_location_t *loc1, const rb_code_location_t *loc2)
return loc;
}
typedef struct rb_ast_id_table {
int size;
ID ids[FLEX_ARY_LEN];
} rb_ast_id_table_t;
typedef struct RNode {
VALUE flags;
union {
struct RNode *node;
ID id;
VALUE value;
ID *tbl;
rb_ast_id_table_t *tbl;
} u1;
union {
struct RNode *node;
@ -411,13 +418,14 @@ typedef struct rb_ast_struct {
rb_ast_t *rb_ast_new(void);
void rb_ast_mark(rb_ast_t*);
void rb_ast_update_references(rb_ast_t*);
void rb_ast_add_local_table(rb_ast_t*, ID *buf);
void rb_ast_dispose(rb_ast_t*);
void rb_ast_free(rb_ast_t*);
size_t rb_ast_memsize(const rb_ast_t*);
void rb_ast_add_mark_object(rb_ast_t*, VALUE);
NODE *rb_ast_newnode(rb_ast_t*, enum node_type type);
void rb_ast_delete_node(rb_ast_t*, NODE *n);
rb_ast_id_table_t *rb_ast_new_local_table(rb_ast_t*, int);
rb_ast_id_table_t *rb_ast_resize_latest_local_table(rb_ast_t*, int);
VALUE rb_parser_new(void);
VALUE rb_parser_end_seen_p(VALUE);

29
parse.y
Просмотреть файл

@ -574,7 +574,7 @@ static NODE *symbol_append(struct parser_params *p, NODE *symbols, NODE *symbol)
static NODE *match_op(struct parser_params*,NODE*,NODE*,const YYLTYPE*,const YYLTYPE*);
static ID *local_tbl(struct parser_params*);
static rb_ast_id_table_t *local_tbl(struct parser_params*);
static VALUE reg_compile(struct parser_params*, VALUE, int);
static void reg_fragment_setenc(struct parser_params*, VALUE, int);
@ -3172,9 +3172,8 @@ primary : literal
ID id = internal_id(p);
NODE *m = NEW_ARGS_AUX(0, 0, &NULL_LOC);
NODE *args, *scope, *internal_var = NEW_DVAR(id, &@2);
ID *tbl = ALLOC_N(ID, 3);
tbl[0] = 1 /* length of local var table */; tbl[1] = id /* internal id */;
rb_ast_add_local_table(p->ast, tbl);
rb_ast_id_table_t *tbl = rb_ast_new_local_table(p->ast, 1);
tbl->ids[0] = id; /* internal id */
switch (nd_type($2)) {
case NODE_LASGN:
@ -12585,38 +12584,36 @@ local_pop(struct parser_params *p)
}
#ifndef RIPPER
static ID*
static rb_ast_id_table_t *
local_tbl(struct parser_params *p)
{
int cnt_args = vtable_size(p->lvtbl->args);
int cnt_vars = vtable_size(p->lvtbl->vars);
int cnt = cnt_args + cnt_vars;
int i, j;
ID *buf;
rb_ast_id_table_t *tbl;
if (cnt <= 0) return 0;
buf = ALLOC_N(ID, cnt + 2);
MEMCPY(buf+1, p->lvtbl->args->tbl, ID, cnt_args);
tbl = rb_ast_new_local_table(p->ast, cnt);
MEMCPY(tbl->ids, p->lvtbl->args->tbl, ID, cnt_args);
/* remove IDs duplicated to warn shadowing */
for (i = 0, j = cnt_args+1; i < cnt_vars; ++i) {
for (i = 0, j = cnt_args; i < cnt_vars; ++i) {
ID id = p->lvtbl->vars->tbl[i];
if (!vtable_included(p->lvtbl->args, id)) {
buf[j++] = id;
tbl->ids[j++] = id;
}
}
if (--j < cnt) {
REALLOC_N(buf, ID, (cnt = j) + 2);
if (j < cnt) {
tbl = rb_ast_resize_latest_local_table(p->ast, j);
}
buf[0] = cnt;
rb_ast_add_local_table(p->ast, buf);
return buf;
return tbl;
}
static NODE*
node_newnode_with_locals(struct parser_params *p, enum node_type type, VALUE a1, VALUE a2, const rb_code_location_t *loc)
{
ID *a0;
rb_ast_id_table_t *a0;
NODE *n;
a0 = local_tbl(p);

9
vm.c
Просмотреть файл

@ -1256,18 +1256,17 @@ rb_binding_add_dynavars(VALUE bindval, rb_binding_t *bind, int dyncount, const I
const rb_iseq_t *base_iseq, *iseq;
rb_ast_body_t ast;
NODE tmp_node;
ID minibuf[4], *dyns = minibuf;
VALUE idtmp = 0;
if (dyncount < 0) return 0;
base_block = &bind->block;
base_iseq = vm_block_iseq(base_block);
if (dyncount >= numberof(minibuf)) dyns = ALLOCV_N(ID, idtmp, dyncount + 1);
VALUE idtmp = 0;
rb_ast_id_table_t *dyns = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + dyncount * sizeof(ID));
dyns->size = dyncount;
MEMCPY(dyns->ids, dynvars, ID, dyncount);
dyns[0] = dyncount;
MEMCPY(dyns + 1, dynvars, ID, dyncount);
rb_node_init(&tmp_node, NODE_SCOPE, (VALUE)dyns, 0, 0);
ast.root = &tmp_node;
ast.compile_option = 0;