summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYusuke Endoh <mame@ruby-lang.org>2019-09-07 16:45:49 +0900
committerYusuke Endoh <mame@ruby-lang.org>2019-09-07 16:45:49 +0900
commita2260bd636646cde486afeebe5a0a7ef5ec78a4e (patch)
treefa4b485846423edc9e3d3cad581a6bcf5f84ff5f
parent2f2f8107d0d21f5ebaaaf3b2d7ed6d09dfec91d5 (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.c281
1 files changed, 160 insertions, 121 deletions
diff --git a/compile.c b/compile.c
index 10dff7ca03..c2fbab079b 100644
--- a/compile.c
+++ b/compile.c
@@ -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;