Branch: Tag:

2001-01-15

2001-01-15 00:26:51 by Martin Stjernholm <mast@lysator.liu.se>

Added stack depth tracking to handle jumping out of blocks nested inside
expressions. This is not only a fix due to the labeled breaks, e.g. the
following program have always bugged until now:

int main()
{
foreach (({1,2,3}), int j)
do
if (17 + j + gauge {break;}) return 0;
while (0);
}

Rev: src/docode.c:1.97

5:   \*/   /**/   #include "global.h" - RCSID("$Id: docode.c,v 1.96 2001/01/14 21:39:36 grubba Exp $"); + RCSID("$Id: docode.c,v 1.97 2001/01/15 00:26:51 mast Exp $");   #include "las.h"   #include "program.h"   #include "pike_types.h"
36:    struct cleanup_frame *prev;    cleanup_func cleanup;    void *cleanup_arg; +  int stack_depth;   };      struct statement_label_name
55:    * following statement. */    INT32 break_label, continue_label;    int emit_break_label; +  int stack_depth;    struct cleanup_frame *cleanups;   };      static struct statement_label top_statement_label_dummy = -  {0, 0, -1, -1, 0, 0}; +  {0, 0, -1, -1, 0, -1, 0};   static struct statement_label *current_label = &top_statement_label_dummy; -  + #ifdef PIKE_DEBUG + static int current_stack_depth = -4711; + #else + static int current_stack_depth = 0; + #endif      #define PUSH_CLEANUP_FRAME(func, arg) do { \    struct cleanup_frame cleanup_frame__; \    cleanup_frame__.cleanup = (cleanup_func) (func); \    cleanup_frame__.cleanup_arg = (void *)(ptrdiff_t) (arg); \ -  +  cleanup_frame__.stack_depth = current_stack_depth; \    DO_IF_DEBUG( \    if (current_label->cleanups == (void *)(ptrdiff_t) -1) \    fatal("current_label points to an unused statement_label.\n"); \
96:   } while (0)      #define POP_AND_DO_CLEANUP \ +  do_pop(current_stack_depth - cleanup_frame__.stack_depth); \    cleanup_frame__.cleanup(cleanup_frame__.cleanup_arg); \    POP_AND_DONT_CLEANUP   
107:    new_label__.name = 0; \    new_label__.break_label = new_label__.continue_label = -1; \    new_label__.cleanups = 0; \ +  new_label__.stack_depth = current_stack_depth; \    current_label = &new_label__; \    } \ -  DO_IF_DEBUG(else new_label__.cleanups = (void *)(ptrdiff_t) -1;) +  else { \ +  DO_IF_DEBUG( \ +  new_label__.cleanups = (void *)(ptrdiff_t) -1; \ +  new_label__.stack_depth = current_stack_depth; \ +  ) \ +  current_label->stack_depth = current_stack_depth; \ +  }      #define POP_STATEMENT_LABEL \    current_label = new_label__.prev; \
209:    case 1: emit0(F_POP_VALUE); break;    default: emit1(F_POP_N_ELEMS,x); break;    } +  current_stack_depth -= x;   }      void do_cleanup_pop(int x)
220:    do_pop(x);   }    + void do_pop_mark() + { +  emit0(F_POP_MARK); + } +  + void do_pop_to_mark() + { +  emit0(F_POP_TO_MARK); + } +    void do_escape_catch()   {    emit0(F_ESCAPE_CATCH);
230:   int do_docode(node *n, INT16 flags)   {    int i; +  int stack_depth_save = current_stack_depth;    int save_current_line=lex.current_line;    if(!n) return 0;    lex.current_line=n->line_number; -  + #ifdef PIKE_DEBUG +  if (current_stack_depth == -4711) fatal("do_docode() used outside docode().\n"); + #endif    i=do_docode2(check_node_hash(n), flags); -  +  current_stack_depth = stack_depth_save + i;       lex.current_line=save_current_line;    return i;
308:    do_jump(F_BRANCH_WHEN_NON_ZERO, label);    else    do_jump(F_BRANCH_WHEN_ZERO, label); +  current_stack_depth--;    }else{    if(iftrue)    do_jump(F_LOR, label);
357:      int do_lfun_call(int id,node *args)   { +  emit0(F_MARK); +  PUSH_CLEANUP_FRAME(do_pop_mark, 0); +  do_docode(args,0);   #if 1    if(id == Pike_compiler->compiler_frame->current_function_number)    {
365: Inside #if 1
   {    if(Pike_compiler->compiler_frame->is_inline)    { -  emit0(F_MARK); -  do_docode(args,0); +     Pike_compiler->compiler_frame->recur_label=do_jump(F_RECUR,    Pike_compiler->compiler_frame->recur_label); -  return 1; +     }else{ -  emit0(F_MARK); -  do_docode(args,0); +     emit1(F_COND_RECUR,id);    Pike_compiler->compiler_frame->recur_label=do_jump(F_POINTER,    Pike_compiler->compiler_frame->recur_label); -  return 1; +     }    }    } -  +  else   #endif -  emit0(F_MARK); -  do_docode(args,0); +     emit1(F_CALL_LFUN, id); -  +  POP_AND_DONT_CLEANUP;    return 1;   }   
499:    emit1(F_NUMBER,0);    return 1;    -  case F_PUSH_ARRAY: +  case F_PUSH_ARRAY: { +  if (current_label != &top_statement_label_dummy || current_label->cleanups) { +  /* Might not have a surrounding apply node if evaluated as a +  * constant by the optimizer. */ + #ifdef PIKE_DEBUG +  if (!current_label->cleanups || +  (current_label->cleanups->cleanup != do_pop_mark && +  current_label->cleanups->cleanup != do_pop_to_mark)) +  fatal("F_PUSH_ARRAY unexpected in this context.\n"); + #endif +  current_label->cleanups->cleanup = do_pop_to_mark; +  }    code_expression(CAR(n), 0, "`@");    emit0(F_PUSH_ARRAY); -  return -0x7ffffff; +  return 0; +  }       case '?':    {
804:    {    node *arr;    INT32 *prev_switch_jumptable = current_switch_jumptable; -  PUSH_CLEANUP_FRAME(do_cleanup_pop, 4); -  PUSH_STATEMENT_LABEL; +     -  current_switch_jumptable=0; -  current_label->break_label=alloc_label(); -  current_label->continue_label=alloc_label(); -  +     arr=CAR(n);       if(arr->token==F_RANGE)
829:    }    tmp2=do_docode(CAR(n),DO_NOT_COPY);    emit0(F_CONST0); +  current_stack_depth++;       foreach_arg_pushed:   #ifdef PIKE_DEBUG
839: Inside #if defined(PIKE_DEBUG)
   if(d_flag)    emit0(F_MARK);   #endif +  PUSH_CLEANUP_FRAME(do_cleanup_pop, 4); +  +  PUSH_STATEMENT_LABEL; +  current_switch_jumptable=0; +  current_label->break_label=alloc_label(); +  current_label->continue_label=alloc_label(); +     tmp3=do_branch(-1);    tmp1=ins_label(-1);    DO_CODE_BLOCK(CDR(n));
859:    case F_DEC_LOOP:    {    INT32 *prev_switch_jumptable = current_switch_jumptable; -  PUSH_CLEANUP_FRAME(do_cleanup_pop, 3); -  PUSH_STATEMENT_LABEL; +     -  current_switch_jumptable=0; -  current_label->break_label=alloc_label(); -  current_label->continue_label=alloc_label(); -  +     tmp2=do_docode(CAR(n),0);   #ifdef PIKE_DEBUG    /* This is really ugly because there is always a chance that the bug
875: Inside #if defined(PIKE_DEBUG)
   if(d_flag)    emit0(F_MARK);   #endif +  PUSH_CLEANUP_FRAME(do_cleanup_pop, 3); +  +  PUSH_STATEMENT_LABEL; +  current_switch_jumptable=0; +  current_label->break_label=alloc_label(); +  current_label->continue_label=alloc_label();    tmp3=do_branch(-1);    tmp1=ins_label(-1);   
974:    !CAR(n)->u.sval.u.efun->docode(n))    {    emit0(F_MARK); +  PUSH_CLEANUP_FRAME(do_pop_mark, 0);    do_docode(CDR(n),0);    tmp1=store_constant(& CAR(n)->u.sval,    !(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND),    CAR(n)->name);    emit1(F_APPLY, DO_NOT_WARN((INT32)tmp1)); -  +  POP_AND_DONT_CLEANUP;    }    if(n->type == void_type_string)    return 0;
991:    }       emit0(F_MARK); +  PUSH_CLEANUP_FRAME(do_pop_mark, 0);    do_docode(CDR(n),0);    tmp1=store_constant(& CAR(n)->u.sval,    !(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND),    CAR(n)->name);    emit1(F_APPLY, DO_NOT_WARN((INT32)tmp1)); -  +  POP_AND_DONT_CLEANUP;       return 1;    }
1019:    node *foo;       emit0(F_MARK); +  PUSH_CLEANUP_FRAME(do_pop_mark, 0);    do_docode(CAR(n),0);    do_docode(CDR(n),0);   
1041:    }    }    free_node(foo); +  POP_AND_DONT_CLEANUP;    return 1;    }   
1090:    cases=count_cases(CDR(n));       tmp1=emit1(F_SWITCH,0); +  current_stack_depth--;    emit1(F_ALIGN,sizeof(INT32));       current_switch_values_on_stack=0;
1282:    for (label = current_label; label; label = label->prev)    for (lbl_name = label->name; lbl_name; lbl_name = lbl_name->next)    if (lbl_name->str == name) -  goto label_found; +  goto label_found_1;    my_yyerror("No surrounding statement labeled '%s'.", name->str);    return 0;    -  label_found: +  label_found_1:    if (n->token == F_CONTINUE && label->continue_label < 0) {    my_yyerror("Cannot continue the non-loop statement on line %d.",    lbl_name->line_number);
1294:    }    }    -  else +  else {    if (n->token == F_BREAK) { -  label = current_label; -  if(label->break_label < 0) -  { +  for (label = current_label; label; label = label->prev) +  if (label->break_label >= 0) +  goto label_found_2;    yyerror("Break outside loop or switch.");    return 0;    } -  } +     else {    for (label = current_label; label; label = label->prev)    if (label->continue_label >= 0) -  goto continue_label_found; +  goto label_found_2;    yyerror("Continue outside loop.");    return 0; -  continue_label_found: -  ; +     } -  +  label_found_2: ; +  }       for (p = current_label; 1; p = p->prev) {    struct cleanup_frame *q; -  for (q = p->cleanups; q; q = q->prev) +  for (q = p->cleanups; q; q = q->prev) { +  do_pop(current_stack_depth - q->stack_depth);    q->cleanup(q->cleanup_arg); -  +  } +  do_pop(current_stack_depth - p->stack_depth);    if (p == label) break;    }   
1385:       case F_CATCH: {    INT32 *prev_switch_jumptable = current_switch_jumptable; -  PUSH_STATEMENT_LABEL; +  tmp1=do_jump(F_CATCH,-1); +  PUSH_CLEANUP_FRAME(do_escape_catch, 0);    -  +  PUSH_STATEMENT_LABEL;    current_switch_jumptable=0;    current_label->break_label=alloc_label();    if (TEST_COMPAT(7,0))    current_label->continue_label=alloc_label(); -  PUSH_CLEANUP_FRAME(do_escape_catch, 0); +     -  tmp1=do_jump(F_CATCH,-1); +     DO_CODE_BLOCK(CAR(n));       if (TEST_COMPAT(7,0))    ins_label(current_label->continue_label);    ins_label(current_label->break_label);    emit0(F_THROW_ZERO); -  +  current_switch_jumptable = prev_switch_jumptable; +  POP_STATEMENT_LABEL; +     ins_label(DO_NOT_WARN((INT32)tmp1)); -  +  current_stack_depth++;    -  current_switch_jumptable = prev_switch_jumptable; +     POP_AND_DONT_CLEANUP; -  POP_STATEMENT_LABEL; +     return 1;    }   
1610:      void do_code_block(node *n)   { + #ifdef PIKE_DEBUG +  if (current_stack_depth != -4711) fatal("Reentrance in do_code_block().\n"); +  current_stack_depth = 0; + #endif +     init_bytecode();    label_no=1;   
1647:    DO_CODE_BLOCK(n);    }    assemble(); +  + #ifdef PIKE_DEBUG +  current_stack_depth = -4711; + #endif   }      int docode(node *n)
1654:    int tmp;    int label_no_save = label_no;    dynamic_buffer instrbuf_save = instrbuf; +  int stack_depth_save = current_stack_depth; +  struct statement_label *label_save = current_label; +  struct cleanup_frame *top_cleanups_save = top_statement_label_dummy.cleanups;       instrbuf.s.str=0;    label_no=1; -  +  current_stack_depth = 0; +  current_label = &top_statement_label_dummy; /* Fix these two to */ +  top_statement_label_dummy.cleanups = 0; /* please F_PUSH_ARRAY. */    init_bytecode();       tmp=do_docode(n,0);
1664:       instrbuf=instrbuf_save;    label_no = label_no_save; +  current_stack_depth = stack_depth_save; +  current_label = label_save; +  top_statement_label_dummy.cleanups = top_cleanups_save;    return tmp;   }