aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-06-25 08:55:23 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-06-25 08:55:23 +0000
commit3fe7efd7400cd9c351f7076c7c13f73d2cf0616a (patch)
treec3bf1940fbe6601068a8318761122778691c43ed
parent14ae7e3df3e7e0007d49039159748c123d091bda (diff)
downloadruby-3fe7efd7400cd9c351f7076c7c13f73d2cf0616a.tar.gz
compile.c: fix_sp_depth
* compile.c (fix_sp_depth): separate fix-up of sp depth from code generation. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59171 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--compile.c150
1 files changed, 111 insertions, 39 deletions
diff --git a/compile.c b/compile.c
index 6932365f8a..0398a77ccc 100644
--- a/compile.c
+++ b/compile.c
@@ -1571,6 +1571,112 @@ get_ivar_ic_value(rb_iseq_t *iseq,ID id)
BADINSN_DUMP(anchor, list, NULL), \
COMPILE_ERROR)
+static int
+fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
+{
+ int stack_max = 0, sp = 0, line = 0;
+ LINK_ELEMENT *list;
+
+ for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
+ if (list->type == ISEQ_ELEMENT_LABEL) {
+ LABEL *lobj = (LABEL *)list;
+ lobj->set = TRUE;
+ }
+ }
+
+ for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
+ switch (list->type) {
+ case ISEQ_ELEMENT_INSN:
+ {
+ int j, len, insn;
+ const char *types;
+ VALUE *operands;
+ INSN *iobj = (INSN *)list;
+
+ /* update sp */
+ sp = calc_sp_depth(sp, iobj);
+ if (sp < 0) {
+ BADINSN_DUMP(anchor, list, NULL);
+ COMPILE_ERROR(iseq, iobj->line_no,
+ "argument stack underflow (%d)", sp);
+ return -1;
+ }
+ if (sp > stack_max) {
+ stack_max = sp;
+ }
+
+ line = iobj->line_no;
+ /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
+ operands = iobj->operands;
+ insn = iobj->insn_id;
+ types = insn_op_types(insn);
+ len = insn_len(insn);
+
+ /* operand check */
+ if (iobj->operand_size != len - 1) {
+ /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
+ BADINSN_DUMP(anchor, list, NULL);
+ COMPILE_ERROR(iseq, iobj->line_no,
+ "operand size miss! (%d for %d)",
+ iobj->operand_size, len - 1);
+ return -1;
+ }
+
+ for (j = 0; types[j]; j++) {
+ if (types[j] == TS_OFFSET) {
+ /* label(destination position) */
+ LABEL *lobj = (LABEL *)operands[j];
+ if (!lobj->set) {
+ BADINSN_DUMP(anchor, list, NULL);
+ COMPILE_ERROR(iseq, iobj->line_no,
+ "unknown label: "LABEL_FORMAT, lobj->label_no);
+ return -1;
+ }
+ if (lobj->sp == -1) {
+ lobj->sp = sp;
+ }
+ }
+ }
+ break;
+ }
+ case ISEQ_ELEMENT_LABEL:
+ {
+ LABEL *lobj = (LABEL *)list;
+ if (lobj->sp == -1) {
+ lobj->sp = sp;
+ }
+ else {
+ sp = lobj->sp;
+ }
+ break;
+ }
+ case ISEQ_ELEMENT_NONE:
+ {
+ /* ignore */
+ break;
+ }
+ case ISEQ_ELEMENT_ADJUST:
+ {
+ ADJUST *adjust = (ADJUST *)list;
+ int orig_sp = sp;
+
+ sp = adjust->label ? adjust->label->sp : 0;
+ if (adjust->line_no != -1 && orig_sp - sp < 0) {
+ compile_bug(iseq, adjust->line_no,
+ "iseq_set_sequence: adjust bug %d < %d",
+ orig_sp, sp);
+ }
+ break;
+ }
+ default:
+ BADINSN_DUMP(anchor, list, NULL);
+ COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
+ return -1;
+ }
+ }
+ return stack_max;
+}
+
/**
ruby insn object list -> raw instruction sequence
*/
@@ -1582,7 +1688,10 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
LINK_ELEMENT *list;
VALUE *generated_iseq;
- int insn_num, code_index, line_info_index, sp, stack_max = 0, line = 0;
+ int insn_num, code_index, line_info_index, sp = 0;
+ int stack_max = fix_sp_depth(iseq, anchor);
+
+ if (stack_max < 0) return COMPILE_NG;
/* fix label position */
list = FIRST_ELEMENT(anchor);
@@ -1592,7 +1701,6 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
case ISEQ_ELEMENT_INSN:
{
INSN *iobj = (INSN *)list;
- line = iobj->line_no;
code_index += insn_data_length(iobj);
insn_num++;
break;
@@ -1601,7 +1709,6 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
{
LABEL *lobj = (LABEL *)list;
lobj->position = code_index;
- lobj->set = TRUE;
break;
}
case ISEQ_ELEMENT_NONE:
@@ -1618,10 +1725,6 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
}
break;
}
- default:
- BADINSN_DUMP(anchor, list, NULL);
- COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
- return COMPILE_NG;
}
list = list->next;
}
@@ -1650,15 +1753,6 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
/* update sp */
sp = calc_sp_depth(sp, iobj);
- if (sp < 0) {
- BADINSN_ERROR(iseq, iobj->line_no,
- "argument stack underflow (%d)", sp);
- return COMPILE_NG;
- }
- if (sp > stack_max) {
- stack_max = sp;
- }
-
/* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
operands = iobj->operands;
insn = iobj->insn_id;
@@ -1666,15 +1760,6 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
types = insn_op_types(insn);
len = insn_len(insn);
- /* operand check */
- if (iobj->operand_size != len - 1) {
- /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
- BADINSN_ERROR(iseq, iobj->line_no,
- "operand size miss! (%d for %d)",
- iobj->operand_size, len - 1);
- return COMPILE_NG;
- }
-
for (j = 0; types[j]; j++) {
char type = types[j];
/* printf("--> [%c - (%d-%d)]\n", type, k, j); */
@@ -1683,14 +1768,6 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
{
/* label(destination position) */
LABEL *lobj = (LABEL *)operands[j];
- if (!lobj->set) {
- BADINSN_ERROR(iseq, iobj->line_no,
- "unknown label: "LABEL_FORMAT, lobj->label_no);
- return COMPILE_NG;
- }
- if (lobj->sp == -1) {
- lobj->sp = sp;
- }
generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
break;
}
@@ -1793,12 +1870,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
case ISEQ_ELEMENT_LABEL:
{
LABEL *lobj = (LABEL *)list;
- if (lobj->sp == -1) {
- lobj->sp = sp;
- }
- else {
- sp = lobj->sp;
- }
+ sp = lobj->sp;
break;
}
case ISEQ_ELEMENT_ADJUST: