Branch: Tag:

2001-01-14

2001-01-14 04:13:48 by Martin Stjernholm <mast@lysator.liu.se>

Cleaned up the statement label stuff a bit and separated the cleanup
frames from them. Also fixed bug where the marks wasn't popped
correctly for F_FOREACH and F_*_LOOP when running with -d.

Rev: src/docode.c:1.93

5:   \*/   /**/   #include "global.h" - RCSID("$Id: docode.c,v 1.92 2001/01/11 14:12:30 grubba Exp $"); + RCSID("$Id: docode.c,v 1.93 2001/01/14 04:13:48 mast Exp $");   #include "las.h"   #include "program.h"   #include "pike_types.h"
29:      static int do_docode2(node *n, INT16 flags);    + typedef void (*cleanup_func)(void *); +  + struct cleanup_frame + { +  struct cleanup_frame *prev; +  cleanup_func cleanup; +  void *cleanup_arg; + }; +    struct statement_label_name   {    struct statement_label_name *next;    struct pike_string *str; -  unsigned INT16 line_number; +  unsigned int line_number;   };      struct statement_label   {    struct statement_label *prev;    struct statement_label_name *name; -  INT16 emit_break_label; +  /* -2 in break_label is used to flag "open" statement_label entries. +  * If an open entry is on top of the stack, it's used instead of a +  * new one. That's used to associate statement labels to the +  * following statement. */    INT32 break_label, continue_label; -  void (*cleanup)(void *); -  void *cleanup_arg; +  int emit_break_label; +  struct cleanup_frame *cleanups;   }; - static struct statement_label *current_label = 0; +     -  + static struct statement_label top_statement_label_dummy = +  {0, 0, -1, -1, 0, 0}; + static struct statement_label *current_label = &top_statement_label_dummy; +  + #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); \ +  DO_IF_DEBUG( \ +  if (current_label->cleanups == (void *)(ptrdiff_t) -1) \ +  fatal("current_label points to an unused statement_label.\n"); \ +  ) \ +  if (current_label->break_label == -2) { \ +  DO_IF_DEBUG( \ +  if (current_label->prev->break_label == -2) \ +  fatal("Found two open statement_label entries in a row.\n"); \ +  ) \ +  cleanup_frame__.prev = current_label->prev->cleanups; \ +  current_label->prev->cleanups = &cleanup_frame__; \ +  } \ +  else { \ +  cleanup_frame__.prev = current_label->cleanups; \ +  current_label->cleanups = &cleanup_frame__; \ +  } +  + #define POP_AND_DONT_CLEANUP \ +  if (current_label->cleanups == &cleanup_frame__) \ +  current_label->cleanups = cleanup_frame__.prev; \ +  else { \ +  DO_IF_DEBUG( \ +  if (current_label->prev->cleanups != &cleanup_frame__) \ +  fatal("Cleanup frame lost from statement_label cleanup list.\n");\ +  ) \ +  current_label->prev->cleanups = cleanup_frame__.prev; \ +  } \ + } while (0) +  + #define POP_AND_DO_CLEANUP \ +  cleanup_frame__.cleanup(cleanup_frame__.cleanup_arg); \ +  POP_AND_DONT_CLEANUP +    #define PUSH_STATEMENT_LABEL do { \    struct statement_label new_label__; \    new_label__.prev = current_label; \ -  new_label__.cleanup = 0; \ -  if (!current_label || current_label->break_label != -2) { \ -  /* Only cover the current label if it's in use by a statement. */ \ +  if (current_label->break_label != -2) { \ +  /* Only cover the current label if it's closed. */ \    new_label__.name = 0; \    new_label__.break_label = new_label__.continue_label = -1; \ -  +  new_label__.cleanups = 0; \    current_label = &new_label__; \    } \ -  DO_IF_DEBUG( \ -  else if (current_label && current_label->cleanup) \ -  fatal("Cleanup callback taken in unused statement label.\n"); \ -  ) \ -  do +  DO_IF_DEBUG(else new_label__.cleanups = (void *)(ptrdiff_t) -1;)      #define POP_STATEMENT_LABEL \ -  while (0); \ +     current_label = new_label__.prev; \ -  if (new_label__.cleanup) \ -  new_label__.cleanup(new_label__.cleanup_arg); \ +  DO_IF_DEBUG( \ +  if (new_label__.cleanups && \ +  new_label__.cleanups != (void *)(ptrdiff_t) -1) \ +  fatal("Cleanup frames still left in statement_label.\n")); \   } while (0)      static INT32 current_switch_case;
151:      void do_pop(int x)   { + #ifdef PIKE_DEBUG +  if (x < 0) fatal("Cannot do pop of %d args.\n", x); + #endif    switch(x)    {    case 0: return;
159:    }   }    + void do_cleanup_pop(int x) + { + #ifdef PIKE_DEBUG +  if(d_flag) +  emit0(F_POP_MARK); + #endif +  do_pop(x); + } +    void do_escape_catch()   {    emit0(F_ESCAPE_CATCH);
711:    case F_FOR:    {    INT32 *prev_switch_jumptable = current_switch_jumptable; -  PUSH_STATEMENT_LABEL { +  PUSH_STATEMENT_LABEL;       current_switch_jumptable=0;    current_label->break_label=alloc_label();
731:    ins_label(current_label->break_label);       current_switch_jumptable = prev_switch_jumptable; -  } POP_STATEMENT_LABEL; +  POP_STATEMENT_LABEL;    return 0;    }   
742:    {    node *arr;    INT32 *prev_switch_jumptable = current_switch_jumptable; -  PUSH_STATEMENT_LABEL { +  PUSH_CLEANUP_FRAME(do_cleanup_pop, 4); +  PUSH_STATEMENT_LABEL;       current_switch_jumptable=0;    current_label->break_label=alloc_label();
768:    emit0(F_CONST0);       foreach_arg_pushed: -  current_label->cleanup = (void (*)(void *)) do_pop; -  current_label->cleanup_arg = (void *) 4; +    #ifdef PIKE_DEBUG    /* This is really ugly because there is always a chance that the bug    * will disappear when new instructions are added to the code, but
786:    do_jump(n->token, DO_NOT_WARN((INT32)tmp1));    ins_label(current_label->break_label);    - #ifdef PIKE_DEBUG -  if(d_flag) -  emit0(F_POP_MARK); - #endif -  +     current_switch_jumptable = prev_switch_jumptable; -  } POP_STATEMENT_LABEL; +  POP_STATEMENT_LABEL; +  POP_AND_DO_CLEANUP;    return 0;    }   
802:    case F_DEC_LOOP:    {    INT32 *prev_switch_jumptable = current_switch_jumptable; -  PUSH_STATEMENT_LABEL { +  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); -  current_label->cleanup = (void (*)(void *)) do_pop; -  current_label->cleanup_arg = (void *) 3; +    #ifdef PIKE_DEBUG    /* This is really ugly because there is always a chance that the bug    * will disappear when new instructions are added to the code, but
827:    low_insert_label( DO_NOT_WARN((INT32)tmp3));    do_jump(n->token, DO_NOT_WARN((INT32)tmp1));    ins_label(current_label->break_label); - #ifdef PIKE_DEBUG -  if(d_flag) -  emit0(F_POP_MARK); - #endif +        current_switch_jumptable = prev_switch_jumptable; -  } POP_STATEMENT_LABEL; +  POP_STATEMENT_LABEL; +  POP_AND_DO_CLEANUP;    return 0;    }       case F_DO:    {    INT32 *prev_switch_jumptable = current_switch_jumptable; -  PUSH_STATEMENT_LABEL { +  PUSH_STATEMENT_LABEL;       current_switch_jumptable=0;    current_label->break_label=alloc_label();
853:    ins_label(current_label->break_label);       current_switch_jumptable = prev_switch_jumptable; -  } POP_STATEMENT_LABEL; +  POP_STATEMENT_LABEL;    return 0;    }   
1006: Inside #if defined(PIKE_DEBUG)
  #ifdef PIKE_DEBUG    struct svalue *save_sp=Pike_sp;   #endif -  PUSH_STATEMENT_LABEL { +  PUSH_STATEMENT_LABEL;       if(do_docode(CAR(n),0)!=1)    fatal("Internal compiler error, time to panic\n");
1099:       low_insert_label( current_label->break_label);    -  } POP_STATEMENT_LABEL; +  POP_STATEMENT_LABEL;   #ifdef PIKE_DEBUG    if(Pike_interpreter.recoveries && Pike_sp-Pike_interpreter.evaluator_stack < Pike_interpreter.recoveries->stack_pointer)    fatal("Stack error after F_SWITCH (underflow)\n");
1227:    else    if (n->token == F_BREAK) {    label = current_label; -  if(!label || label->break_label < 0) +  if(label->break_label < 0)    {    yyerror("Break outside loop or switch.");    return 0;
1243:    ;    }    -  for (p = current_label; p != label; p = p->prev) -  if (p->cleanup) -  p->cleanup(p->cleanup_arg); +  for (p = current_label; 1; p = p->prev) { +  struct cleanup_frame *q; +  for (q = p->cleanups; q; q = q->prev) +  q->cleanup(q->cleanup_arg); +  if (p == label) break; +  }       if (n->token == F_BREAK) {    if (label->break_label < 0) label->emit_break_label = 1;
1258:    }       case F_NORMAL_STMT_LABEL: -  case F_CUSTOM_STMT_LABEL: -  PUSH_STATEMENT_LABEL { +  case F_CUSTOM_STMT_LABEL: {    struct statement_label *label;    struct statement_label_name name; -  +  PUSH_STATEMENT_LABEL;    name.str = CAR(n)->u.sval.u.string;    name.line_number = n->line_number;   
1274:    my_yyerror("Duplicate nested labels, previous one on line %d.",    lbl_name->line_number);    lex.current_line = save_line; -  break; +  goto label_check_done;    }    } -  +  label_check_done:       name.next = current_label->name;    current_label->name = &name;
1294:    DO_CODE_BLOCK(CDR(n));    if (!name.next && current_label->emit_break_label)    low_insert_label(current_label->break_label); -  } POP_STATEMENT_LABEL; +  POP_STATEMENT_LABEL;    return 0; -  +  }       case F_RETURN:    do_docode(CAR(n),0);
1308:    emit1(F_SSCANF, DO_NOT_WARN((INT32)(tmp1+tmp2)));    return 1;    -  case F_CATCH: -  PUSH_STATEMENT_LABEL { +  case F_CATCH: {    INT32 *prev_switch_jumptable = current_switch_jumptable; -  +  PUSH_STATEMENT_LABEL;       current_switch_jumptable=0;    current_label->break_label=alloc_label();    if (TEST_COMPAT(7,0))    current_label->continue_label=alloc_label(); -  current_label->cleanup = (void (*)(void *)) do_escape_catch; +  PUSH_CLEANUP_FRAME(do_escape_catch, 0);       tmp1=do_jump(F_CATCH,-1);    DO_CODE_BLOCK(CAR(n));
1328:    ins_label(DO_NOT_WARN((INT32)tmp1));       current_switch_jumptable = prev_switch_jumptable; -  current_label->cleanup = 0; -  } POP_STATEMENT_LABEL; +  POP_AND_DONT_CLEANUP; +  POP_STATEMENT_LABEL;    return 1; -  +  }       case F_LVALUE_LIST:    return do_docode(CAR(n),DO_LVALUE)+do_docode(CDR(n),DO_LVALUE);