diff options
author | Yusuke Endoh <mame@ruby-lang.org> | 2019-09-07 16:45:49 +0900 |
---|---|---|
committer | Yusuke Endoh <mame@ruby-lang.org> | 2019-09-07 16:45:49 +0900 |
commit | a2260bd636646cde486afeebe5a0a7ef5ec78a4e (patch) | |
tree | fa4b485846423edc9e3d3cad581a6bcf5f84ff5f | |
parent | 2f2f8107d0d21f5ebaaaf3b2d7ed6d09dfec91d5 (diff) |
compile.c: Separate compile_list to two functions for Array and Hash
compile_list was for the compilation of Array literal and Hash literal.
I guess it was originally reasonable to handle them in one function, but
now, compilation of Array is very different from Hash. So the function
was complicated by many branches for Array and Hash.
This change separates the function to two ones for Array and Hash.
-rw-r--r-- | compile.c | 281 |
1 files changed, 160 insertions, 121 deletions
@@ -3849,10 +3849,9 @@ compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, } static int -compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node_root, +compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, struct rb_call_info_kw_arg **keywords_ptr, unsigned int *flag) { - const NODE *node = node_root; int len = 0; for (; node; len++, node = node->nd_next) { @@ -3872,11 +3871,6 @@ compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node_roo return len; } -enum compile_list_type_t { - COMPILE_ARRAY_TYPE_ARRAY, - COMPILE_ARRAY_TYPE_HASH, -}; - static inline int static_literal_node_p(const NODE *node, const rb_iseq_t *iseq) { @@ -3922,21 +3916,111 @@ static_literal_value(const NODE *node, rb_iseq_t *iseq) } static int -compile_list(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node_root, - enum compile_list_type_t type, int popped) +compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped) { - const NODE *node = node_root; int line = (int)nd_line(node); int len = 0; if (nd_type(node) == NODE_ZLIST) { if (!popped) { - switch (type) { - case COMPILE_ARRAY_TYPE_ARRAY: ADD_INSN1(ret, line, newarray, INT2FIX(0)); break; - case COMPILE_ARRAY_TYPE_HASH: ADD_INSN1(ret, line, newhash, INT2FIX(0)); break; + ADD_INSN1(ret, line, newarray, INT2FIX(0)); + } + } + else { + int opt_p = 1; + int first = 1, i; + + while (node) { + const NODE *start_node = node, *end_node, *prev_node; + const int max = 0x100; + DECL_ANCHOR(anchor); + INIT_ANCHOR(anchor); + + for (i=0; i<max && node; i++, len++, prev_node = node, node = node->nd_next) { + if (CPDEBUG > 0) { + EXPECT_NODE("compile_array", node, NODE_LIST, -1); + } + + if (opt_p && !static_literal_node_p(node, iseq)) { + opt_p = 0; + } + + NO_CHECK(COMPILE_(anchor, "array element", node->nd_head, popped)); + } + + if (opt_p) { + if (!popped) { + VALUE ary = rb_ary_tmp_new(i); + + end_node = node; + node = start_node; + + while (node != end_node) { + rb_ary_push(ary, static_literal_value(node, iseq)); + node = node->nd_next; + } + while (node && static_literal_node_p(node, iseq)) { + rb_ary_push(ary, static_literal_value(node, iseq)); + node = node->nd_next; + len++; + } + + OBJ_FREEZE(ary); + + iseq_add_mark_object_compile_time(iseq, ary); + + if (first) { + first = 0; + ADD_INSN1(ret, line, duparray, ary); + } + else { + ADD_INSN1(ret, line, putobject, ary); + ADD_INSN(ret, line, concatarray); + } + } + } + else { + if (!popped) { + /* Find last node in array, and if it is a keyword argument, then set + flag to check and remove empty keyword arguments hash from array */ + if (!node && nd_type(prev_node->nd_head) == NODE_HASH && prev_node->nd_head->nd_brace == 0) { + ADD_INSN1(anchor, line, newarraykwsplat, INT2FIX(i)); + } + else { + ADD_INSN1(anchor, line, newarray, INT2FIX(i)); + } + + + if (first) { + first = 0; + } + else { + ADD_INSN(anchor, line, concatarray); + } + + APPEND_LIST(ret, anchor); + } + else { + /* popped */ + APPEND_LIST(ret, anchor); + } } } } + return len; +} + +static int +compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped) +{ + int line = (int)nd_line(node); + int len = 0; + + if (nd_type(node) == NODE_ZLIST) { + if (!popped) { + ADD_INSN1(ret, line, newhash, INT2FIX(0)); + } + } else { int opt_p = 1; int first = 1, i; @@ -3944,18 +4028,18 @@ compile_list(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node_roo int num_kw = 0; while (node) { - const NODE *start_node = node, *end_node, *prev_node; + const NODE *start_node = node, *end_node; const NODE *kw = 0; const int max = 0x100; DECL_ANCHOR(anchor); INIT_ANCHOR(anchor); - for (i=0; i<max && node; i++, len++, prev_node = node, node = node->nd_next) { + for (i=0; i<max && node; i++, len++, node = node->nd_next) { if (CPDEBUG > 0) { - EXPECT_NODE("compile_list", node, NODE_LIST, -1); + EXPECT_NODE("compile_hash", node, NODE_LIST, -1); } - if (type == COMPILE_ARRAY_TYPE_HASH && !node->nd_head) { + if (!node->nd_head) { kw = node->nd_next; num_kw++; node = 0; @@ -3987,24 +4071,15 @@ compile_list(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node_roo rb_ary_push(ary, static_literal_value(node, iseq)); node = node->nd_next; } - if (type == COMPILE_ARRAY_TYPE_ARRAY) { - while (node && static_literal_node_p(node, iseq)) { - rb_ary_push(ary, static_literal_value(node, iseq)); - node = node->nd_next; - len++; - } - } - else { /* COMPILE_ARRAY_TYPE_HASH */ - while (node && node->nd_next && - static_literal_node_p(node, iseq) && - static_literal_node_p(node->nd_next, iseq)) { - VALUE elem[2]; - elem[0] = static_literal_value(node, iseq); - elem[1] = static_literal_value(node->nd_next, iseq); - rb_ary_cat(ary, elem, 2); - node = node->nd_next->nd_next; - len++; - } + while (node && node->nd_next && + static_literal_node_p(node, iseq) && + static_literal_node_p(node->nd_next, iseq)) { + VALUE elem[2]; + elem[0] = static_literal_value(node, iseq); + elem[1] = static_literal_value(node->nd_next, iseq); + rb_ary_cat(ary, elem, 2); + node = node->nd_next->nd_next; + len++; } OBJ_FREEZE(ary); @@ -4013,103 +4088,67 @@ compile_list(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node_roo if (first) { first = 0; - if (type == COMPILE_ARRAY_TYPE_ARRAY) { - ADD_INSN1(ret, line, duparray, ary); - } - else { /* COMPILE_ARRAY_TYPE_HASH */ - VALUE hash; + VALUE hash; - hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2); - rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR_TRANSIENT(ary), hash); - iseq_add_mark_object_compile_time(iseq, rb_obj_hide(hash)); - ADD_INSN1(ret, line, duphash, hash); - } + hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2); + rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR_TRANSIENT(ary), hash); + iseq_add_mark_object_compile_time(iseq, rb_obj_hide(hash)); + ADD_INSN1(ret, line, duphash, hash); } else { - if (type == COMPILE_ARRAY_TYPE_ARRAY) { - ADD_INSN1(ret, line, putobject, ary); - ADD_INSN(ret, line, concatarray); - } - else { - COMPILE_ERROR(ERROR_ARGS "core#hash_merge_ary"); - return -1; - } + COMPILE_ERROR(ERROR_ARGS "core#hash_merge_ary"); + return -1; } } } else { - if (!popped || kw) { - switch (type) { - case COMPILE_ARRAY_TYPE_ARRAY: { - /* Find last node in array, and if it is a keyword argument, then set - flag to check and remove empty keyword arguments hash from array */ - if (!node && nd_type(prev_node->nd_head) == NODE_HASH && prev_node->nd_head->nd_brace == 0) { - ADD_INSN1(anchor, line, newarraykwsplat, INT2FIX(i)); + if (!popped || kw) { + if (i > 0) { + num_kw++; + if (first) { + if (!popped) { + ADD_INSN1(anchor, line, newhash, INT2FIX(i)); + } + APPEND_LIST(ret, anchor); } else { - ADD_INSN1(anchor, line, newarray, INT2FIX(i)); - } - - - if (first) { - first = 0; - } - else { - ADD_INSN(anchor, line, concatarray); - } - - APPEND_LIST(ret, anchor); - break; - } - case COMPILE_ARRAY_TYPE_HASH: - if (i > 0) { - num_kw++; - if (first) { - if (!popped) { - ADD_INSN1(anchor, line, newhash, INT2FIX(i)); - } - APPEND_LIST(ret, anchor); - } - else { - if (!popped) { - ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); - ADD_INSN(ret, line, swap); - } - APPEND_LIST(ret, anchor); - if (!popped) { - ADD_SEND(ret, line, id_core_hash_merge_ptr, INT2FIX(i + 1)); - } - } - } - if (kw) { - int empty_kw = nd_type(kw) == NODE_LIT; - int first_kw = num_kw == 1; - int only_kw = single_kw && first_kw; - - if (!popped && !empty_kw) { + if (!popped) { ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); - if (i > 0 || !first) ADD_INSN(ret, line, swap); - else ADD_INSN1(ret, line, newhash, INT2FIX(0)); - } - - if (empty_kw && first_kw && !only_kw) { - ADD_INSN1(ret, line, newhash, INT2FIX(0)); + ADD_INSN(ret, line, swap); } - else if (!empty_kw || only_kw) { - NO_CHECK(COMPILE(ret, "keyword splat", kw)); + APPEND_LIST(ret, anchor); + if (!popped) { + ADD_SEND(ret, line, id_core_hash_merge_ptr, INT2FIX(i + 1)); } + } + } + if (kw) { + int empty_kw = nd_type(kw) == NODE_LIT; + int first_kw = num_kw == 1; + int only_kw = single_kw && first_kw; + + if (!popped && !empty_kw) { + ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); + if (i > 0 || !first) ADD_INSN(ret, line, swap); + else ADD_INSN1(ret, line, newhash, INT2FIX(0)); + } - if (popped) { - ADD_INSN(ret, line, pop); - } - else if (!empty_kw) { - ADD_SEND(ret, line, id_core_hash_merge_kwd, INT2FIX(2)); - } - } - first = 0; - break; - } - } + if (empty_kw && first_kw && !only_kw) { + ADD_INSN1(ret, line, newhash, INT2FIX(0)); + } + else if (!empty_kw || only_kw) { + NO_CHECK(COMPILE(ret, "keyword splat", kw)); + } + + if (popped) { + ADD_INSN(ret, line, pop); + } + else if (!empty_kw) { + ADD_SEND(ret, line, id_core_hash_merge_kwd, INT2FIX(2)); + } + } + first = 0; + } else { /* popped */ APPEND_LIST(ret, anchor); @@ -7439,7 +7478,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in break; } case NODE_LIST:{ - CHECK(compile_list(iseq, ret, node, COMPILE_ARRAY_TYPE_ARRAY, popped) >= 0); + CHECK(compile_array(iseq, ret, node, popped) >= 0); break; } case NODE_ZLIST:{ @@ -7467,7 +7506,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in INIT_ANCHOR(list); switch (type) { case NODE_LIST: - CHECK(compile_list(iseq, list, node->nd_head, COMPILE_ARRAY_TYPE_HASH, popped) >= 0); + CHECK(compile_hash(iseq, list, node->nd_head, popped) >= 0); ADD_SEQ(ret, list); break; |