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.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"   #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: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; +  int stack_depth;   };      struct statement_label_name   {    struct statement_label_name *next;    struct pike_string *str;    unsigned int line_number;   };      struct statement_label   {    struct statement_label *prev;    struct statement_label_name *name;    /* -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;    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"); \    ) \    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; \
pike.git/src/docode.c:89:    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 \ +  do_pop(current_stack_depth - cleanup_frame__.stack_depth); \    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; \    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; \ -  +  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; \    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;
pike.git/src/docode.c:202: Inside #if defined(PIKE_DEBUG)
  {   #ifdef PIKE_DEBUG    if (x < 0) fatal("Cannot do pop of %d args.\n", x);   #endif    switch(x)    {    case 0: return;    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)   {   #ifdef PIKE_DEBUG    if(d_flag)    emit0(F_POP_MARK);   #endif    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);   }      #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 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;   }      static int is_efun(node *n, c_fun fun)   {    return n && n->token == F_CONSTANT &&    n->u.sval.subtype == FUNCTION_BUILTIN &&    n->u.sval.u.efun->function == fun;
pike.git/src/docode.c:301:    }       code_expression(n, (INT16)(flags | DO_NOT_COPY), "condition");       if(flags & DO_POP)    {    if(iftrue)    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);    else    do_jump(F_LAND, label);    }   }      #define do_jump_when_zero(N,L) do_cond_jump(N,L,0,DO_POP|DO_NOT_COPY)   #define do_jump_when_non_zero(N,L) do_cond_jump(N,L,1,DO_POP|DO_NOT_COPY)
pike.git/src/docode.c:350:      static inline struct compiler_frame *find_local_frame(INT32 depth)   {    struct compiler_frame *f=Pike_compiler->compiler_frame;    while(--depth>=0) f=f->previous;    return f;   }      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)    {    int n=count_args(args);    if(n == Pike_compiler->compiler_frame->num_args)    {    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;   }      static int do_docode2(node *n, INT16 flags)   {    ptrdiff_t tmp1,tmp2,tmp3;       if(!n) return 0;       if(flags & DO_LVALUE)
pike.git/src/docode.c:492:    }    }    }    break;       case F_UNDEFINED:    yyerror("Undefined identifier");    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 '?':    {    INT32 *prev_switch_jumptable = current_switch_jumptable;    int adroppings , bdroppings;    current_switch_jumptable=0;          if(!CDDR(n))    {
pike.git/src/docode.c:797:    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; -  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)    {    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 &&    a1[0]->type == int_type_string)    {    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); -  +  current_stack_depth++;       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 -  +  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));    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);       current_switch_jumptable = prev_switch_jumptable;    POP_STATEMENT_LABEL;    POP_AND_DO_CLEANUP;    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_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    * will disappear when new instructions are added to the code, but    * think it is worth it.    */    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);       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);       current_switch_jumptable = prev_switch_jumptable;
pike.git/src/docode.c:967:    if(CAR(n)->token == F_CONSTANT)    {    if(CAR(n)->u.sval.type == T_FUNCTION)    {    if(CAR(n)->u.sval.subtype == FUNCTION_BUILTIN) /* driver fun? */    {    if(!CAR(n)->u.sval.u.efun->docode ||    !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;       return 1;    }else{    if(CAR(n)->u.sval.u.object == Pike_compiler->fake_object)    return do_lfun_call(CAR(n)->u.sval.subtype,CDR(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;       return 1;    }    else if(CAR(n)->token == F_IDENTIFIER &&    IDENTIFIER_IS_FUNCTION(ID_FROM_INT(Pike_compiler->new_program,    CAR(n)->u.id.number)->identifier_flags))    {    return do_lfun_call(CAR(n)->u.id.number,CDR(n));    }    else if(CAR(n)->token == F_EXTERNAL &&
pike.git/src/docode.c:1012:    {    return do_lfun_call(CAR(n)->u.integer.b,CDR(n));    }    else    {    struct pike_string *tmp;    struct efun *fun;    node *foo;       emit0(F_MARK); +  PUSH_CLEANUP_FRAME(do_pop_mark, 0);    do_docode(CAR(n),0);    do_docode(CDR(n),0);       tmp=findstring("call_function");    if(!tmp) yyerror("No call_function efun.");    foo=find_module_identifier(tmp,0);    if(!foo || !foo->token==F_CONSTANT)    {    yyerror("No call_function efun.");    }else{
pike.git/src/docode.c:1034:    foo->u.sval.u.efun->function == f_call_function)    {    emit0(F_CALL_FUNCTION);    }else{    /* We might want to put "predef::"+foo->name here /Hubbe */    tmp1=store_constant(& foo->u.sval, 1, foo->name);    emit1(F_APPLY, DO_NOT_WARN((INT32)tmp1));    }    }    free_node(foo); +  POP_AND_DONT_CLEANUP;    return 1;    }       case F_ARG_LIST:    case F_COMMA_EXPR:    tmp1 = do_docode(CAR(n), (INT16)(flags & ~WANT_LVALUE));    tmp1+=do_docode(CDR(n),flags);    return DO_NOT_WARN((INT32)tmp1);      
pike.git/src/docode.c:1083:       if (!(CAR(n) && (current_switch_type = CAR(n)->type))) {    current_switch_type = mixed_type_string;    }       current_label->break_label=alloc_label();       cases=count_cases(CDR(n));       tmp1=emit1(F_SWITCH,0); +  current_stack_depth--;    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));    jumptable=(INT32 *)xalloc(sizeof(INT32)*(cases*2+2));       for(e=1; e<cases*2+2; e++)    {
pike.git/src/docode.c:1275:    case F_BREAK:    case F_CONTINUE: {    struct statement_label *label, *p;       if (CAR(n)) {    struct pike_string *name = CAR(n)->u.sval.u.string;    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; +  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);    return 0;    }    }    -  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;    }       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);   
pike.git/src/docode.c:1378:    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: {    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;    }       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)
pike.git/src/docode.c:1603:    do_docode(CDR(n), (INT16)(flags | DO_LVALUE));       default:    fatal("Infernal compiler error (unknown parse-tree-token %d).\n", n->token);    return 0; /* make gcc happy */    }   }      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;       emit1(F_BYTE,Pike_compiler->compiler_frame->max_number_of_locals);    emit1(F_BYTE,Pike_compiler->compiler_frame->num_args);    emit0(F_START_FUNCTION);    low_insert_label(0);    if(Pike_compiler->new_program->identifier_references[Pike_compiler->compiler_frame->    current_function_number].id_flags &    ID_INLINE)
pike.git/src/docode.c:1640:       /* This is a no-op, but prevents optimizer to delete the bytes below */    low_insert_label(-1);    emit1(F_BYTE,Pike_compiler->compiler_frame->max_number_of_locals);    emit1(F_BYTE,Pike_compiler->compiler_frame->num_args);    emit0(F_START_FUNCTION);    low_insert_label(Pike_compiler->compiler_frame->recur_label);    DO_CODE_BLOCK(n);    }    assemble(); +  + #ifdef PIKE_DEBUG +  current_stack_depth = -4711; + #endif   }      int docode(node *n)   {    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);    assemble();       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;   }