summaryrefslogtreecommitdiff
path: root/compile.c
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-04-12 01:33:34 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-04-12 01:33:34 +0000
commitee7f8d4805fb4a661b8e8328be49f32cbc3e606d (patch)
tree82f7f28bb49cb5c3c571a649a9b32b61eb7ce988 /compile.c
parent655738577ffd90df3796c73afd8be84cd89091f6 (diff)
* compile.c (compile_array, compile_array_):
Divide big array (or hash) literals into several blocks and concatetene them. There was a problem that a big array (hash) literal causes SystemStackError exception (stack overflow) because VM push all contents of the literal onto VM stack to make an array (or hash). To solve this issue, we make several arrays (hashes) and concatenate them to make a big array (hash) object. ?? * compile.c (iseq_compile_each, setup_args): use modified compile_array. * vm.c (m_core_hash_from_ary, m_core_hash_merge_ary, m_core_hash_merge_ptr): added for above change. * id.c (Init_id), parse.y: add core method ids. * bootstraptest/test_literal.rb: add simple tests. * bootstraptest/test_eval.rb: remove rescue clause to catch SystemStackError exception. * test/ruby/test_literal.rb: add tests to check no stack overflow. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35306 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'compile.c')
-rw-r--r--compile.c173
1 files changed, 121 insertions, 52 deletions
diff --git a/compile.c b/compile.c
index b885e0724d..508d599d08 100644
--- a/compile.c
+++ b/compile.c
@@ -2274,65 +2274,139 @@ compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * cond,
return COMPILE_OK;
}
+enum compile_array_type_t {
+ COMPILE_ARRAY_TYPE_ARRAY,
+ COMPILE_ARRAY_TYPE_HASH,
+ COMPILE_ARRAY_TYPE_ARGS,
+};
+
static int
compile_array_(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root,
- VALUE opt_p, int poped)
+ enum compile_array_type_t type, int poped)
{
NODE *node = node_root;
- int len = (int)node->nd_alen, line = (int)nd_line(node), i=0;
- DECL_ANCHOR(anchor);
-
- INIT_ANCHOR(anchor);
- if (nd_type(node) != NODE_ZARRAY) {
- while (node) {
- if (nd_type(node) != NODE_ARRAY) {
- rb_bug("compile_array: This node is not NODE_ARRAY, but %s",
- ruby_node_name(nd_type(node)));
- }
+ int line = (int)nd_line(node);
+ int len = 0;
- i++;
- if (opt_p && nd_type(node->nd_head) != NODE_LIT) {
- opt_p = Qfalse;
+ if (nd_type(node) == NODE_ZARRAY) {
+ if (!poped) {
+ 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;
+ case COMPILE_ARRAY_TYPE_ARGS: /* do nothing */ break;
}
- COMPILE_(anchor, "array element", node->nd_head, poped);
- node = node->nd_next;
}
}
+ else {
+ int opt_p = 1;
+ int first = 1, i;
- if (len != i) {
- if (0) {
- rb_bug("node error: compile_array (%d: %d-%d)",
- (int)nd_line(node_root), len, i);
- }
- len = i;
- }
+ while (node) {
+ NODE *start_node = node, *end_node;
+ const int max = 0x100;
+ DECL_ANCHOR(anchor);
+ INIT_ANCHOR(anchor);
+
+ for (i=0; i<max && node; i++, len++) {
+ if (CPDEBUG > 0 && nd_type(node) != NODE_ARRAY) {
+ rb_bug("compile_array: This node is not NODE_ARRAY, but %s", ruby_node_name(nd_type(node)));
+ }
- if (opt_p == Qtrue) {
- if (!poped) {
- VALUE ary = rb_ary_tmp_new(len);
- node = node_root;
- while (node) {
- rb_ary_push(ary, node->nd_head->nd_lit);
+ if (opt_p && nd_type(node->nd_head) != NODE_LIT) {
+ opt_p = 0;
+ }
+
+ COMPILE_(anchor, "array element", node->nd_head, poped);
node = node->nd_next;
}
- OBJ_FREEZE(ary);
- iseq_add_mark_object_compile_time(iseq, ary);
- ADD_INSN1(ret, nd_line(node_root), duparray, ary);
- }
- }
- else {
- if (!poped) {
- ADD_INSN1(anchor, line, newarray, INT2FIX(len));
+
+ if (opt_p && type != COMPILE_ARRAY_TYPE_ARGS) {
+ if (!poped) {
+ VALUE ary = rb_ary_tmp_new(i);
+
+ end_node = node;
+ node = start_node;
+
+ while (node != end_node) {
+ rb_ary_push(ary, node->nd_head->nd_lit);
+ node = node->nd_next;
+ }
+ while (node && nd_type(node->nd_head) == NODE_LIT) {
+ rb_ary_push(ary, node->nd_head->nd_lit);
+ node = node->nd_next;
+ len++;
+ }
+
+ OBJ_FREEZE(ary);
+
+ iseq_add_mark_object_compile_time(iseq, ary);
+
+ if (first) {
+ first = 0;
+ if (type == COMPILE_ARRAY_TYPE_ARRAY) {
+ ADD_INSN1(ret, line, duparray, ary);
+ }
+ else { /* COMPILE_ARRAY_TYPE_HASH */
+ ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ ADD_INSN1(ret, line, putobject, ary);
+ ADD_SEND(ret, line, ID2SYM(id_core_hash_from_ary), INT2FIX(1));
+ }
+ }
+ else {
+ if (type == COMPILE_ARRAY_TYPE_ARRAY) {
+ ADD_INSN1(ret, line, putobject, ary);
+ ADD_INSN(ret, line, concatarray);
+ }
+ else {
+ ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ ADD_INSN1(ret, line, putobject, ary);
+ ADD_SEND(ret, line, ID2SYM(id_core_hash_merge_ary), INT2FIX(1));
+ }
+ }
+ }
+ }
+ else {
+ if (!poped) {
+ switch (type) {
+ case COMPILE_ARRAY_TYPE_ARRAY:
+ 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 (first) {
+ first = 0;
+ ADD_INSN1(anchor, line, newhash, INT2FIX(i));
+ APPEND_LIST(ret, anchor);
+ }
+ else {
+ ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ ADD_INSN(ret, line, swap);
+ APPEND_LIST(ret, anchor);
+ ADD_SEND(ret, line, ID2SYM(id_core_hash_merge_ptr), INT2FIX(i + 1));
+ }
+ break;
+ case COMPILE_ARRAY_TYPE_ARGS:
+ APPEND_LIST(ret, anchor);
+ break;
+ }
+ }
+ }
}
- APPEND_LIST(ret, anchor);
}
return len;
}
static VALUE
-compile_array(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root, VALUE opt_p)
+compile_array(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root, enum compile_array_type_t type)
{
- return compile_array_(iseq, ret, node_root, opt_p, 0);
+ return compile_array_(iseq, ret, node_root, type, 0);
}
static VALUE
@@ -2963,8 +3037,7 @@ setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args, NODE *argn, VALUE *flag)
*flag |= VM_CALL_ARGS_SPLAT_BIT;
if (next_is_array) {
- argc = INT2FIX(compile_array(iseq, args, argn->nd_head, Qfalse) + 1);
- POP_ELEMENT(args);
+ argc = INT2FIX(compile_array(iseq, args, argn->nd_head, COMPILE_ARRAY_TYPE_ARGS) + 1);
}
else {
argn = argn->nd_head;
@@ -2973,8 +3046,7 @@ setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args, NODE *argn, VALUE *flag)
break;
}
case NODE_ARRAY: {
- argc = INT2FIX(compile_array(iseq, args, argn, Qfalse));
- POP_ELEMENT(args);
+ argc = INT2FIX(compile_array(iseq, args, argn, COMPILE_ARRAY_TYPE_ARGS));
break;
}
default: {
@@ -4265,7 +4337,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
break;
}
case NODE_ARRAY:{
- compile_array_(iseq, ret, node, Qtrue, poped);
+ compile_array_(iseq, ret, node, COMPILE_ARRAY_TYPE_ARRAY, poped);
break;
}
case NODE_ZARRAY:{
@@ -4293,22 +4365,19 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
INIT_ANCHOR(list);
switch (type) {
- case NODE_ARRAY:{
- compile_array(iseq, list, node->nd_head, Qfalse);
- size = OPERAND_AT(POP_ELEMENT(list), 0);
+ case NODE_ARRAY:
+ size = INT2FIX(compile_array(iseq, list, node->nd_head, COMPILE_ARRAY_TYPE_HASH));
ADD_SEQ(ret, list);
break;
- }
+
case NODE_ZARRAY:
- size = INT2FIX(0);
+ ADD_INSN1(ret, nd_line(node), newhash, INT2FIX(0));
break;
default:
rb_bug("can't make hash with this node: %s", ruby_node_name(type));
}
- ADD_INSN1(ret, nd_line(node), newhash, size);
-
if (poped) {
ADD_INSN(ret, nd_line(node), pop);
}