pike.git / src / docode.c

version» Context lines:

pike.git/src/docode.c:1:   /*\   ||| This file a part of Pike, and is copyright by Fredrik Hubinette   ||| Pike is distributed as GPL (General Public License)   ||| See the files COPYING and DISCLAIMER for more information.   \*/   /**/   #include "global.h" - RCSID("$Id: docode.c,v 1.89 2000/12/05 21:08:17 per Exp $"); + RCSID("$Id: docode.c,v 1.90 2001/01/10 20:00:23 mast Exp $");   #include "las.h"   #include "program.h"   #include "pike_types.h"   #include "stralloc.h"   #include "interpret.h"   #include "constants.h"   #include "array.h"   #include "pike_macros.h"   #include "pike_error.h"   #include "pike_memory.h"
pike.git/src/docode.c:22:   #include "peep.h"   #include "docode.h"   #include "operators.h"   #include "object.h"   #include "opcodes.h"   #include "language.h"   #include "lex.h"      static int do_docode2(node *n, INT16 flags);    - INT32 current_break=-1; - INT32 current_continue=-1; + struct statement_label_name + { +  struct statement_label_name *next; +  struct pike_string *str; +  unsigned INT16 line_number; + };    -  + struct statement_label + { +  struct statement_label *prev; +  struct statement_label_name *name; +  INT16 emit_break_label; +  INT32 break_label, continue_label; +  unsigned catch_depth; + }; + static struct statement_label *current_label = 0; +  + static unsigned catch_depth = 0; +  + #define PUSH_STATEMENT_LABEL do { \ +  struct statement_label new_label__; \ +  new_label__.prev = current_label; \ +  if (!current_label || current_label->break_label != -2) { \ +  /* Only cover the current label if it's in use by a statement. */ \ +  new_label__.name = 0; \ +  new_label__.break_label = new_label__.continue_label = -1; \ +  new_label__.catch_depth = catch_depth; \ +  current_label = &new_label__; \ +  } \ +  do +  + #define POP_STATEMENT_LABEL \ +  while (0); \ +  current_label = new_label__.prev; \ + } while (0) +    static INT32 current_switch_case;   static INT32 current_switch_default;   static INT32 current_switch_values_on_stack;   static INT32 *current_switch_jumptable =0;   static struct pike_string *current_switch_type = NULL;      void upd_int(int offset, INT32 tmp)   {    MEMCPY(Pike_compiler->new_program->program+offset, (char *)&tmp,sizeof(tmp));   }
pike.git/src/docode.c:60:    return lbl;   }         #define LBLCACHESIZE 4711   #define CURRENT_INSTR ((long)instrbuf.s.len / (long)sizeof(p_instr))   #define MAX_UNWIND 100      static int lbl_cache[LBLCACHESIZE];    - int do_branch(INT32 lbl) + int do_branch(INT32 lbl, int catch_escapes)   {    if(lbl==-1)    {    lbl=alloc_label();    }else{    INT32 last,pos=lbl_cache[lbl % LBLCACHESIZE];    if(pos < (last=CURRENT_INSTR) && (CURRENT_INSTR - pos) < MAX_UNWIND)    {   #define BUF ((p_instr *)instrbuf.s.str)    if(BUF[pos].opcode == F_LABEL && BUF[pos].arg == lbl)
pike.git/src/docode.c:87:    BUF[pos].arg,    BUF[pos].arg2,    BUF[pos].line,    BUF[pos].file);    }    }    }    }       } +  while (catch_escapes--) +  emit0(F_ESCAPE_CATCH);    emit1(F_BRANCH, lbl);    return lbl;   }      void low_insert_label(int lbl)   {    lbl_cache[ lbl % LBLCACHESIZE ] = CURRENT_INSTR;    emit1(F_LABEL, lbl);   }   
pike.git/src/docode.c:159:   void do_cond_jump(node *n, int label, int iftrue, int flags)   {    iftrue=!!iftrue;    if((flags & DO_POP) && node_is_tossable(n))    {    int t,f;    t=!!node_is_true(n);    f=!!node_is_false(n);    if(t || f)    { -  if(t == iftrue) do_branch( label); +  if(t == iftrue) do_branch( label, 0);    return;    }    }       switch(n->token)    {    case F_LAND:    case F_LOR:    if(iftrue == (n->token==F_LAND))    {
pike.git/src/docode.c:426:    return 0;    }       tmp1=alloc_label();    do_jump_when_zero(CAR(n), DO_NOT_WARN((INT32)tmp1));       adroppings=do_docode(CADR(n), flags);    tmp3=emit1(F_POP_N_ELEMS,0);       /* Else */ -  tmp2=do_branch(-1); +  tmp2=do_branch(-1, 0);    low_insert_label( DO_NOT_WARN((INT32)tmp1));       bdroppings=do_docode(CDDR(n), flags);    if(adroppings < bdroppings)    {    do_pop(bdroppings - adroppings);    }       if(adroppings > bdroppings)    {
pike.git/src/docode.c:661:    emit0(F_DEC_AND_POP);    return 0;    }else{    emit0(n->token);    return 1;    }       case F_FOR:    {    INT32 *prev_switch_jumptable = current_switch_jumptable; -  INT32 break_save = current_break; -  INT32 continue_save = current_continue; +  PUSH_STATEMENT_LABEL {       current_switch_jumptable=0; -  current_break=alloc_label(); -  current_continue=alloc_label(); +  current_label->break_label=alloc_label(); +  current_label->continue_label=alloc_label();       if(CDR(n))    { -  do_jump_when_zero(CAR(n),current_break); +  do_jump_when_zero(CAR(n),current_label->break_label);    tmp2=ins_label(-1);    DO_CODE_BLOCK(CADR(n)); -  ins_label(current_continue); +  ins_label(current_label->continue_label);    DO_CODE_BLOCK(CDDR(n));    }else{    tmp2=ins_label(-1);    }    do_jump_when_non_zero(CAR(n), DO_NOT_WARN((INT32)tmp2)); -  ins_label(current_break); +  ins_label(current_label->break_label);       current_switch_jumptable = prev_switch_jumptable; -  current_break=break_save; -  current_continue=continue_save; +  } POP_STATEMENT_LABEL;    return 0;    }       case ' ':    return do_docode(CAR(n),0)+do_docode(CDR(n),DO_LVALUE);       case F_FOREACH:    {    node *arr;    INT32 *prev_switch_jumptable = current_switch_jumptable; -  INT32 break_save = current_break; -  INT32 continue_save = current_continue; +  PUSH_STATEMENT_LABEL {       current_switch_jumptable=0; -  current_break=alloc_label(); -  current_continue=alloc_label(); +  current_label->break_label=alloc_label(); +  current_label->continue_label=alloc_label();       arr=CAR(n);       if(arr->token==F_RANGE)    {    node **a1=my_get_arg(&_CDR(n),0);    node **a2=my_get_arg(&_CDR(n),1);    if(a1 && a2 && a2[0]->token==F_CONSTANT &&    a2[0]->u.sval.type==T_INT &&    a2[0]->u.sval.type==0x7fffffff &&
pike.git/src/docode.c:729:       foreach_arg_pushed:   #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    * think it is worth it.    */    if(d_flag)    emit0(F_MARK);   #endif -  tmp3=do_branch(-1); +  tmp3=do_branch(-1, 0);    tmp1=ins_label(-1);    DO_CODE_BLOCK(CDR(n)); -  ins_label(current_continue); +  ins_label(current_label->continue_label);    low_insert_label( DO_NOT_WARN((INT32)tmp3));    do_jump(n->token, DO_NOT_WARN((INT32)tmp1)); -  ins_label(current_break); +  ins_label(current_label->break_label);      #ifdef PIKE_DEBUG    if(d_flag)    emit0(F_POP_MARK);   #endif       current_switch_jumptable = prev_switch_jumptable; -  current_break=break_save; -  current_continue=continue_save; +  } POP_STATEMENT_LABEL;    do_pop(4);    return 0;    }       case F_INC_NEQ_LOOP:    case F_DEC_NEQ_LOOP:    case F_INC_LOOP:    case F_DEC_LOOP:    {    INT32 *prev_switch_jumptable = current_switch_jumptable; -  INT32 break_save = current_break; -  INT32 continue_save = current_continue; +  PUSH_STATEMENT_LABEL {       current_switch_jumptable=0; -  current_break=alloc_label(); -  current_continue=alloc_label(); +  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    * will disappear when new instructions are added to the code, but    * think it is worth it.    */    if(d_flag)    emit0(F_MARK);   #endif -  tmp3=do_branch(-1); +  tmp3=do_branch(-1, 0);    tmp1=ins_label(-1);       DO_CODE_BLOCK(CDR(n)); -  ins_label(current_continue); +  ins_label(current_label->continue_label);    low_insert_label( DO_NOT_WARN((INT32)tmp3));    do_jump(n->token, DO_NOT_WARN((INT32)tmp1)); -  ins_label(current_break); +  ins_label(current_label->break_label);   #ifdef PIKE_DEBUG    if(d_flag)    emit0(F_POP_MARK);   #endif       current_switch_jumptable = prev_switch_jumptable; -  current_break=break_save; -  current_continue=continue_save; +  } POP_STATEMENT_LABEL;    do_pop(3);    return 0;    }       case F_DO:    {    INT32 *prev_switch_jumptable = current_switch_jumptable; -  INT32 break_save = current_break; -  INT32 continue_save = current_continue; +  PUSH_STATEMENT_LABEL {       current_switch_jumptable=0; -  current_break=alloc_label(); -  current_continue=alloc_label(); +  current_label->break_label=alloc_label(); +  current_label->continue_label=alloc_label();       tmp2=ins_label(-1);    DO_CODE_BLOCK(CAR(n)); -  ins_label(current_continue); +  ins_label(current_label->continue_label);    do_jump_when_non_zero(CDR(n), DO_NOT_WARN((INT32)tmp2)); -  ins_label(current_break); +  ins_label(current_label->break_label);       current_switch_jumptable = prev_switch_jumptable; -  current_break=break_save; -  current_continue=continue_save; +  } POP_STATEMENT_LABEL;    return 0;    }       case F_POP_VALUE:    {    DO_CODE_BLOCK(CAR(n));    return 0;    }       case F_CAST:
pike.git/src/docode.c:958:    */       case F_SWITCH:    {    INT32 e,cases,*order;    INT32 *jumptable;    INT32 prev_switch_values_on_stack = current_switch_values_on_stack;    INT32 prev_switch_case = current_switch_case;    INT32 prev_switch_default = current_switch_default;    INT32 *prev_switch_jumptable = current_switch_jumptable; -  INT32 break_save = current_break; +     struct pike_string *prev_switch_type = current_switch_type;   #ifdef PIKE_DEBUG    struct svalue *save_sp=Pike_sp;   #endif -  +  PUSH_STATEMENT_LABEL {       if(do_docode(CAR(n),0)!=1)    fatal("Internal compiler error, time to panic\n");       if (!(CAR(n) && (current_switch_type = CAR(n)->type))) {    current_switch_type = mixed_type_string;    }    -  current_break=alloc_label(); +  current_label->break_label=alloc_label();       cases=count_cases(CDR(n));       tmp1=emit1(F_SWITCH,0);    emit1(F_ALIGN,sizeof(INT32));       current_switch_values_on_stack=0;    current_switch_case=1;    current_switch_default=-1;    current_switch_jumptable=(INT32 *)xalloc(sizeof(INT32)*(cases*2+2));
pike.git/src/docode.c:1053:    pop_stack();    free((char *)jumptable);    free((char *)current_switch_jumptable);       current_switch_jumptable = prev_switch_jumptable;    current_switch_default = prev_switch_default;    current_switch_case = prev_switch_case;    current_switch_values_on_stack = prev_switch_values_on_stack;    current_switch_type = prev_switch_type;    -  low_insert_label( current_break); +  low_insert_label( current_label->break_label);    -  current_break=break_save; +  } 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");   #endif    return 0;    }       case F_CASE:    {    if(!current_switch_jumptable)
pike.git/src/docode.c:1159:    {    yyerror("Default outside switch.");    }else if(current_switch_default!=-1){    yyerror("Duplicate switch default.");    }else{    current_switch_default = ins_label(-1);    }    return 0;       case F_BREAK: -  if(current_break == -1) +  case F_CONTINUE: +  if (CAR(n)) { +  struct pike_string *name = CAR(n)->u.sval.u.string; +  struct statement_label *label; +  struct statement_label_name *lbl_name; +  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; +  my_yyerror("No surrounding statement labeled '%s'.", name->str); +  return 0; +  +  label_found: +  if (n->token == F_BREAK) { +  if (label->break_label < 0) label->emit_break_label = 1; +  label->break_label = +  do_branch(label->break_label, catch_depth - label->catch_depth); +  } +  else { +  if (label->continue_label < 0) +  my_yyerror("Cannot continue the non-loop statement on line %d.", +  lbl_name->line_number); +  else +  do_branch(label->continue_label, catch_depth - label->catch_depth); +  } +  } +  +  else +  if (n->token == F_BREAK) { +  if(!current_label || current_label->break_label < 0)    {    yyerror("Break outside loop or switch.");    }else{ -  do_branch( current_break); +  do_branch( current_label->break_label, +  catch_depth - current_label->catch_depth);    } -  +  } +  else { +  struct statement_label *label; +  for (label = current_label; label; label = label->prev) +  if (label->continue_label >= 0) { +  do_branch( label->continue_label, +  catch_depth - label->catch_depth);    return 0; -  +  } +  yyerror("Continue outside loop."); +  } +  return 0;    -  case F_CONTINUE: -  if(current_continue == -1) +  case F_NORMAL_STMT_LABEL: +  case F_CUSTOM_STMT_LABEL:    { -  yyerror("continue outside loop or switch."); -  }else{ -  do_branch( current_continue); +  PUSH_STATEMENT_LABEL { +  struct statement_label *label; +  struct statement_label_name name; +  name.str = CAR(n)->u.sval.u.string; +  name.line_number = n->line_number; +  +  for (label = current_label; label; label = label->prev) { +  struct statement_label_name *lbl_name; +  for (lbl_name = label->name; lbl_name; lbl_name = lbl_name->next) +  if (lbl_name->str == name.str) { +  INT32 save_line = lex.current_line; +  lex.current_line = name.line_number; +  my_yyerror("Duplicate nested labels, previous one on line %d.", +  lbl_name->line_number); +  lex.current_line = save_line; +  break;    } -  +  } +  +  name.next = current_label->name; +  current_label->name = &name; +  +  if (!name.next) { +  current_label->emit_break_label = 0; +  if (n->token == F_CUSTOM_STMT_LABEL) +  /* The statement we precede has custom label handling; leave +  * the statement_label "open" so the statement will use it +  * instead of covering it. */ +  current_label->break_label = -2; +  else +  current_label->break_label = -1; +  } +  DO_CODE_BLOCK(CDR(n)); +  if (!name.next && current_label->emit_break_label) +  low_insert_label(current_label->break_label); +  } POP_STATEMENT_LABEL;    return 0; -  +  }       case F_RETURN:    do_docode(CAR(n),0);    emit0(F_RETURN);    return 0;       case F_SSCANF:    tmp1=do_docode(CAR(n),DO_NOT_COPY);    tmp2=do_docode(CDR(n),DO_NOT_COPY | DO_LVALUE);    emit1(F_SSCANF, DO_NOT_WARN((INT32)(tmp1+tmp2)));    return 1;       case F_CATCH:    { -  /* FIXME: Pike 7.0 compatibility? */ -  INT32 break_save = current_break; -  INT32 continue_save = current_continue; +  PUSH_STATEMENT_LABEL {    INT32 *prev_switch_jumptable = current_switch_jumptable;       current_switch_jumptable=0; -  current_break=alloc_label(); -  current_continue=alloc_label(); +  current_label->break_label=alloc_label(); +  if (TEST_COMPAT(7,0)) +  current_label->continue_label=alloc_label();    -  +  catch_depth++;    tmp1=do_jump(F_CATCH,-1);    DO_CODE_BLOCK(CAR(n)); -  ins_label(current_continue); -  ins_label(current_break); +  catch_depth--; +  +  if (TEST_COMPAT(7,0)) +  ins_label(current_label->continue_label); +  ins_label(current_label->break_label);    emit0(F_THROW_ZERO);    ins_label(DO_NOT_WARN((INT32)tmp1));    -  current_break=break_save; -  current_continue=continue_save; +     current_switch_jumptable = prev_switch_jumptable; -  +  } POP_STATEMENT_LABEL;    return 1;    }       case F_LVALUE_LIST:    return do_docode(CAR(n),DO_LVALUE)+do_docode(CDR(n),DO_LVALUE);       case F_ARRAY_LVALUE:    tmp1=do_docode(CAR(n),DO_LVALUE);   #ifdef PIKE_DEBUG    if(tmp1 & 1)