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.90 2001/01/10 20:00:23 mast Exp $"); + RCSID("$Id: docode.c,v 1.91 2001/01/10 23:31:55 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:35:    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; +  void (*cleanup)(void *); +  void *cleanup_arg;   };   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; \ -  +  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. */ \    new_label__.name = 0; \    new_label__.break_label = new_label__.continue_label = -1; \ -  new_label__.catch_depth = catch_depth; \ +     current_label = &new_label__; \    } \ -  +  DO_IF_DEBUG( \ +  else if (current_label && current_label->cleanup) \ +  fatal("Cleanup callback taken in unused statement label.\n"); \ +  ) \    do      #define POP_STATEMENT_LABEL \    while (0); \    current_label = new_label__.prev; \ -  +  if (new_label__.cleanup) \ +  new_label__.cleanup(new_label__.cleanup_arg); \   } 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)   {
pike.git/src/docode.c:93:    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 catch_escapes) + int do_branch(INT32 lbl)   {    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:120:    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:149:   void do_pop(int x)   {    switch(x)    {    case 0: return;    case 1: emit0(F_POP_VALUE); break;    default: emit1(F_POP_N_ELEMS,x); break;    }   }    + void do_escape_catch() + { +  emit0(F_ESCAPE_CATCH); + } +    #define DO_CODE_BLOCK(X) do_pop(do_docode((X),DO_NOT_COPY | DO_POP | DO_DEFER_POP))      int do_docode(node *n, INT16 flags)   {    int i;    int save_current_line=lex.current_line;    if(!n) return 0;    lex.current_line=n->line_number;    i=do_docode2(check_node_hash(n), flags);   
pike.git/src/docode.c:194:   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, 0); +  if(t == iftrue) do_branch( label);    return;    }    }       switch(n->token)    {    case F_LAND:    case F_LOR:    if(iftrue == (n->token==F_LAND))    {
pike.git/src/docode.c:461:    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, 0); +  tmp2=do_branch(-1);    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:753:    {    tmp2=do_docode(CAR(arr),DO_NOT_COPY);    do_docode(*a1,DO_NOT_COPY);    goto foreach_arg_pushed;    }    }    tmp2=do_docode(CAR(n),DO_NOT_COPY);    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    * think it is worth it.    */    if(d_flag)    emit0(F_MARK);   #endif -  tmp3=do_branch(-1, 0); +  tmp3=do_branch(-1);    tmp1=ins_label(-1);    DO_CODE_BLOCK(CDR(n));    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_label->break_label);      #ifdef PIKE_DEBUG    if(d_flag)    emit0(F_POP_MARK);   #endif       current_switch_jumptable = prev_switch_jumptable;    } 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;    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    * think it is worth it.    */    if(d_flag)    emit0(F_MARK);   #endif -  tmp3=do_branch(-1, 0); +  tmp3=do_branch(-1);    tmp1=ins_label(-1);       DO_CODE_BLOCK(CDR(n));    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_label->break_label);   #ifdef PIKE_DEBUG    if(d_flag)    emit0(F_POP_MARK);   #endif       current_switch_jumptable = prev_switch_jumptable;    } POP_STATEMENT_LABEL; -  do_pop(3); +     return 0;    }       case F_DO:    {    INT32 *prev_switch_jumptable = current_switch_jumptable;    PUSH_STATEMENT_LABEL {       current_switch_jumptable=0;    current_label->break_label=alloc_label();
pike.git/src/docode.c:1186:    {    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: -  case F_CONTINUE: +  case F_CONTINUE: { +  struct statement_label *label, *p; +     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) +  if (n->token == F_CONTINUE && 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); +  return 0;    }    }       else    if (n->token == F_BREAK) { -  if(!current_label || current_label->break_label < 0) +  label = current_label; +  if(!label || label->break_label < 0)    {    yyerror("Break outside loop or switch."); -  }else{ -  do_branch( current_label->break_label, -  catch_depth - current_label->catch_depth); +  return 0;    }    }    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); +  if (label->continue_label >= 0) +  goto continue_label_found; +  yyerror("Continue outside loop.");    return 0; -  +  continue_label_found:    } -  yyerror("Continue outside loop."); +  +  for (p = current_label; p != label; p = p->prev) +  if (p->cleanup) +  p->cleanup(p->cleanup_arg); +  +  if (n->token == F_BREAK) { +  if (label->break_label < 0) label->emit_break_label = 1; +  label->break_label = do_branch(label->break_label);    } -  +  else +  do_branch(label->continue_label); +     return 0; -  +  }       case F_NORMAL_STMT_LABEL:    case F_CUSTOM_STMT_LABEL: -  { +     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) {
pike.git/src/docode.c:1275:    * 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: -  { +     PUSH_STATEMENT_LABEL {    INT32 *prev_switch_jumptable = current_switch_jumptable;       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;    -  catch_depth++; +     tmp1=do_jump(F_CATCH,-1);    DO_CODE_BLOCK(CAR(n)); -  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_switch_jumptable = prev_switch_jumptable; -  +  current_label->cleanup = 0;    } 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)    fatal("Very internal compiler error.\n");   #endif
pike.git/src/docode.c:1509:    emit1(F_GLOBAL,n->u.id.number);    }    }    return 1;       case F_VAL_LVAL:    return do_docode(CAR(n),flags) +    do_docode(CDR(n), (INT16)(flags | DO_LVALUE));       default: -  fatal("Infernal compiler error (unknown parse-tree-token).\n"); +  fatal("Infernal compiler error (unknown parse-tree-token %d).\n", n->token);    return 0; /* make gcc happy */    }   }      void do_code_block(node *n)   {    init_bytecode();    label_no=1;       emit1(F_BYTE,Pike_compiler->compiler_frame->max_number_of_locals);