aboutsummaryrefslogtreecommitdiffstats
path: root/compile.c
diff options
context:
space:
mode:
Diffstat (limited to 'compile.c')
-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;