pike.git / src / peep.c

version» Context lines:

pike.git/src/peep.c:1: + /* + || This file is part of Pike. For copyright information see COPYRIGHT. + || Pike is distributed under GPL, LGPL and MPL. See the file COPYING + || for more information. + */ +    #include "global.h" - #include "language.h" +    #include "stralloc.h"   #include "dynamic_buffer.h"   #include "program.h"   #include "las.h"   #include "docode.h" - #include "main.h" + #include "pike_embed.h"   #include "pike_error.h"   #include "lex.h"   #include "pike_memory.h"   #include "peep.h"   #include "dmalloc.h"   #include "stuff.h"   #include "bignum.h"   #include "opcodes.h" -  + #include "builtin_functions.h" + #include "constants.h" + #include "interpret.h" + #include "pikecode.h"    - RCSID("$Id: peep.c,v 1.45 2000/12/05 21:08:20 per Exp $"); -  - static void asm_opt(void); -  - dynamic_buffer instrbuf; -  + #ifdef PIKE_DEBUG   static int hasarg(int opcode)   {    return instrs[opcode-F_OFFSET].flags & I_HASARG;   }      static int hasarg2(int opcode)   {    return instrs[opcode-F_OFFSET].flags & I_HASARG2;   }    - #ifdef PIKE_DEBUG +    static void dump_instr(p_instr *p)   {    if(!p) return;    fprintf(stderr,"%s",get_token_name(p->opcode));    if(hasarg(p->opcode))    {    fprintf(stderr,"(%d",p->arg);    if(hasarg2(p->opcode))    fprintf(stderr,",%d",p->arg2);    fprintf(stderr,")");    }   }   #endif       -  + static int asm_opt(void);    -  + /* Output buffer. The optimization eye is at the end of the buffer. */ + dynamic_buffer instrbuf; + long num_instrs = 0; +  +    void init_bytecode(void)   { -  low_reinit_buf(&instrbuf); +  initialize_buf(&instrbuf); +  num_instrs = 0;   }      void exit_bytecode(void)   {    ptrdiff_t e, length;    p_instr *c;       c=(p_instr *)instrbuf.s.str;    length=instrbuf.s.len / sizeof(p_instr);    -  for(e=0;e<length;e++) free_string(c->file); +  for(e=0;e<length;e++) { +  free_string(dmalloc_touch_named(struct pike_string *, c[e].file, +  "exit_bytecode")); + #ifdef PIKE_DEBUG +  c[e].file = (void *)(ptrdiff_t)~0; + #endif +  }       toss_buffer(&instrbuf);   }    -  + /* insert_opcode{,0,1,2}() append an opcode to the instrbuf. */ +  + ptrdiff_t insert_opcode(p_instr *opcode) + { +  /* Note: Steals references from opcode. */ +  p_instr *p = (p_instr *)low_make_buf_space(sizeof(p_instr), &instrbuf); +  if (!p) Pike_fatal("Out of memory in peep.\n"); +  *p = *opcode; +  num_instrs++; +  return p - (p_instr *)instrbuf.s.str; + } +    ptrdiff_t insert_opcode2(unsigned int f,    INT32 b,    INT32 c, -  INT32 current_line, +  INT_TYPE current_line,    struct pike_string *current_file)   {    p_instr *p;      #ifdef PIKE_DEBUG    if(!hasarg2(f) && c) -  fatal("hasarg2(%d) is wrong!\n",f); +  Pike_fatal("hasarg2(%d) is wrong!\n",f);   #endif       p=(p_instr *)low_make_buf_space(sizeof(p_instr), &instrbuf);         #ifdef PIKE_DEBUG    if(!instrbuf.s.len) -  fatal("Low make buf space failed!!!!!!\n"); +  Pike_fatal("Low make buf space failed!!!!!!\n");   #endif       p->opcode=f;    p->line=current_line; -  copy_shared_string(p->file, current_file); +  copy_shared_string(p->file, dmalloc_touch_named(struct pike_string *, +  current_file, +  "insert_opcode"));    p->arg=b;    p->arg2=c;       return p - (p_instr *)instrbuf.s.str;   }      ptrdiff_t insert_opcode1(unsigned int f,    INT32 b, -  INT32 current_line, +  INT_TYPE current_line,    struct pike_string *current_file)   {   #ifdef PIKE_DEBUG    if(!hasarg(f) && b) -  fatal("hasarg(%d) is wrong!\n",f); +  Pike_fatal("hasarg(%d) is wrong!\n",f);   #endif       return insert_opcode2(f,b,0,current_line,current_file);   }    - ptrdiff_t insert_opcode0(int f,int current_line, struct pike_string *current_file) + ptrdiff_t insert_opcode0(int f, INT_TYPE current_line, +  struct pike_string *current_file)   {   #ifdef PIKE_DEBUG    if(hasarg(f)) -  fatal("hasarg(%d) is wrong!\n",f); +  Pike_fatal("hasarg(%d) is wrong!\n",f);   #endif    return insert_opcode1(f,0,current_line, current_file);   }         void update_arg(int instr,INT32 arg)   {    p_instr *p;   #ifdef PIKE_DEBUG    if(instr > (long)instrbuf.s.len / (long)sizeof(p_instr) || instr < 0) -  fatal("update_arg outside known space.\n"); +  Pike_fatal("update_arg outside known space.\n");   #endif    p=(p_instr *)instrbuf.s.str;    p[instr].arg=arg;   }    -  + #ifndef FLUSH_CODE_GENERATOR_STATE + #define FLUSH_CODE_GENERATOR_STATE() + #endif      /**** Bytecode Generator *****/    - void ins_f_byte(unsigned int b) + INT32 assemble(int store_linenumbers)   { -  +  INT32 entry_point; +  INT32 max_label=-1,tmp; +  INT32 *labels, *jumps, *uses, *aliases; +  ptrdiff_t e, length; +  p_instr *c; + #ifdef PIKE_PORTABLE_BYTECODE +  struct pike_string *tripples = NULL; + #endif /* PIKE_PORTABLE_BYTECODE */   #ifdef PIKE_DEBUG -  if(store_linenumbers && b<F_MAX_OPCODE) -  ADD_COMPILED(b); - #endif /* PIKE_DEBUG */ -  -  b-=F_OFFSET; - #ifdef PIKE_DEBUG -  if(b>255) -  Pike_error("Instruction too big %d\n",b); +  INT32 max_pointer=-1; +  int synch_depth = 0; +  size_t fun_start = Pike_compiler->new_program->num_program;   #endif -  add_to_program((unsigned char)b); - } +  int relabel; +  int reoptimize = relabel = !(debug_options & NO_PEEP_OPTIMIZING);    - static void ins_f_byte_with_arg(unsigned int a,unsigned INT32 b) +  c=(p_instr *)instrbuf.s.str; +  length=instrbuf.s.len / sizeof(p_instr); +  + #ifdef PIKE_DEBUG +  if((a_flag > 1 && store_linenumbers) || a_flag > 2)    { -  switch(b >> 8) -  { -  case 0 : break; -  case 1 : ins_f_byte(F_PREFIX_256); break; -  case 2 : ins_f_byte(F_PREFIX_512); break; -  case 3 : ins_f_byte(F_PREFIX_768); break; -  case 4 : ins_f_byte(F_PREFIX_1024); break; -  default: -  if( b < 256*256) -  { -  ins_f_byte(F_PREFIX_CHARX256); -  add_to_program((unsigned char)(b>>8)); -  }else if(b < 256*256*256) { -  ins_f_byte(F_PREFIX_WORDX256); -  add_to_program((unsigned char)(b>>16)); -  add_to_program((unsigned char)(b>>8)); -  }else{ -  ins_f_byte(F_PREFIX_24BITX256); -  add_to_program((unsigned char)(b>>24)); -  add_to_program((unsigned char)(b>>16)); -  add_to_program((unsigned char)(b>>8)); +  for (e = 0; e < length; e++) { +  if (c[e].opcode == F_POP_SYNCH_MARK) synch_depth--; +  fprintf(stderr, "~~~%4ld %4lx %*s", (long)c[e].line, +  DO_NOT_WARN((unsigned long)e), synch_depth, ""); +  dump_instr(c+e); +  fprintf(stderr,"\n"); +  if (c[e].opcode == F_SYNCH_MARK) synch_depth++;    } -  +  if (synch_depth) { +  Pike_fatal("Unbalanced sync_mark/pop_sync_mark: %d\n", synch_depth);    } -  ins_f_byte(a); -  add_to_program((unsigned char)b); +     } -  + #endif    - static void ins_f_byte_with_2_args(unsigned int a, -  unsigned INT32 c, -  unsigned INT32 b) - { + #ifdef PIKE_PORTABLE_BYTECODE +  /* No need to do this for constant evaluations. */ +  if (store_linenumbers) { +  p_wchar2 *current_tripple; +  struct pike_string *previous_file = NULL; +  INT_TYPE previous_line = 0; +  ptrdiff_t num_linedirectives = 0;    -  switch(b >> 8) -  { -  case 0 : break; -  case 1 : ins_f_byte(F_PREFIX2_256); break; -  case 2 : ins_f_byte(F_PREFIX2_512); break; -  case 3 : ins_f_byte(F_PREFIX2_768); break; -  case 4 : ins_f_byte(F_PREFIX2_1024); break; -  default: -  if( b < 256*256) -  { -  ins_f_byte(F_PREFIX2_CHARX256); -  add_to_program((unsigned char)(b>>8)); -  }else if(b < 256*256*256) { -  ins_f_byte(F_PREFIX2_WORDX256); -  add_to_program((unsigned char)(b>>16)); -  add_to_program((unsigned char)(b>>8)); -  }else{ -  ins_f_byte(F_PREFIX2_24BITX256); -  add_to_program((unsigned char)(b>>24)); -  add_to_program((unsigned char)(b>>16)); -  add_to_program((unsigned char)(b>>8)); +  /* Count the number of F_FILENAME/F_LINE pseudo-ops we need to add. */ +  for (e=0; e < length; e++) { +  if (c[e].file != previous_file) { +  previous_file = dmalloc_touch_named(struct pike_string *, +  c[e].file, "prev_file"); +  num_linedirectives++;    } -  +  if (c[e].line != previous_line) { +  previous_line = c[e].line; +  num_linedirectives++;    } -  ins_f_byte_with_arg(a,c); -  add_to_program((unsigned char)b); +     }    - void assemble(void) - { -  INT32 d,max_label,tmp; -  INT32 *labels, *jumps, *uses; -  ptrdiff_t e, length; -  p_instr *c; -  int reoptimize=1; +  /* fprintf(stderr, "length:%d directives:%d\n", +  * length, num_linedirectives); +  */    -  c=(p_instr *)instrbuf.s.str; -  length=instrbuf.s.len / sizeof(p_instr); +  if (!(tripples = begin_wide_shared_string(3*(length+num_linedirectives), +  2))) { +  Pike_fatal("Failed to allocate wide string of length %d 3*(%d + %d).\n", +  3*(length+num_linedirectives), length, num_linedirectives); +  } +  previous_file = NULL; +  previous_line = 0; +  current_tripple = STR2(tripples); +  for (e = 0; e < length; e++) { +  if (c[e].file != previous_file) { +  current_tripple[0] = F_FILENAME; +  current_tripple[1] = +  store_prog_string(dmalloc_touch_named(struct pike_string *, +  c[e].file, +  "store_prog_string")); +  current_tripple[2] = 0; +  current_tripple += 3; +  previous_file = dmalloc_touch_named(struct pike_string *, +  c[e].file, "prev_file"); +  } +  if (c[e].line != previous_line) { +  current_tripple[0] = F_LINE; +  current_tripple[1] = c[e].line; +  current_tripple[2] = c[e].line>>32; +  current_tripple += 3; +  previous_line = c[e].line; +  } +  current_tripple[0] = c[e].opcode; +  current_tripple[1] = c[e].arg; +  current_tripple[2] = c[e].arg2; +  current_tripple += 3; +  } + #ifdef PIKE_DEBUG +  if (current_tripple != STR2(tripples) + 3*(length + num_linedirectives)) { +  Pike_fatal("Tripple length mismatch %d != %d 3*(%d + %d)\n", +  current_tripple - STR2(tripples), +  3*(length + num_linedirectives), +  length, num_linedirectives); +  } + #endif /* PIKE_DEBUG */ +  tripples = end_shared_string(tripples); +  }    -  max_label=-1; -  for(e=0;e<length;e++,c++) -  if(c->opcode == F_LABEL) + #endif /* PIKE_PORTABLE_BYTECODE */ +  +  for(e=0;e<length;e++,c++) { +  if(c->opcode == F_LABEL) {    if(c->arg > max_label)    max_label = c->arg; -  +  } + #ifdef PIKE_DEBUG +  else if (instrs[c->opcode - F_OFFSET].flags & I_POINTER) { +  if (c->arg > max_pointer) +  max_pointer = c->arg; +  } + #endif /* PIKE_DEBUG */ +  }    -  + #ifdef PIKE_DEBUG +  if (max_pointer > max_label) { +  fprintf(stderr, +  "Reference to undefined label %d > %d\n" +  "Bad instructions are marked with '***':\n", +  max_pointer, max_label); +  c=(p_instr *)instrbuf.s.str; +  for(e=0;e<length;e++,c++) { +  if (c->opcode == F_POP_SYNCH_MARK) synch_depth--; +  fprintf(stderr, " * %4ld %4lx ", +  (long)c->line, DO_NOT_WARN((unsigned long)e)); +  dump_instr(c); +  if ((instrs[c->opcode - F_OFFSET].flags & I_POINTER) && +  (c->arg > max_label)) { +  fprintf(stderr, " ***\n"); +  } else { +  fprintf(stderr, "\n"); +  } +  if (c->opcode == F_SYNCH_MARK) synch_depth++; +  }    -  labels=(INT32 *)xalloc(sizeof(INT32) * (max_label+2)); -  jumps=(INT32 *)xalloc(sizeof(INT32) * (max_label+2)); -  uses=(INT32 *)xalloc(sizeof(INT32) * (max_label+2)); +  Pike_fatal("Reference to undefined label %d > %d\n", +  max_pointer, max_label); +  } + #endif /* PIKE_DEBUG */    -  while(reoptimize) + #ifndef INS_ENTRY +  /* Replace F_ENTRY with F_NOP if we have no entry prologue. */ +  for (c = (p_instr *) instrbuf.s.str, e = 0; e < length; e++, c++) +  if (c->opcode == F_ENTRY) c->opcode = F_NOP; + #endif +  +  labels=(INT32 *)xalloc(sizeof(INT32) * 4 * (max_label+2)); +  jumps = labels + max_label + 2; +  uses = jumps + max_label + 2; +  aliases = uses + max_label + 2; +  while(relabel)    { -  reoptimize=0; +  /* First do the relabel pass. */    for(e=0;e<=max_label;e++)    { -  labels[e]=jumps[e]=-1; +  labels[e]=jumps[e]= aliases[e] = -1;    uses[e]=0;    }       c=(p_instr *)instrbuf.s.str; -  +  length=instrbuf.s.len / sizeof(p_instr);    for(e=0;e<length;e++) -  if(c[e].opcode == F_LABEL && c[e].arg>=0) -  labels[c[e].arg]=DO_NOT_WARN((INT32)e); +  if(c[e].opcode == F_LABEL && c[e].arg>=0) { +  INT32 l = c[e].arg; +  labels[l]=DO_NOT_WARN((INT32)e); +  while (e+1 < length && +  c[e+1].opcode == F_LABEL && c[e+1].arg >= 0) { +  /* aliases is used to compact several labels at the same +  * position to one label. That's necessary for some peep +  * optimizations to work well. */ +  e++; +  labels[c[e].arg] = DO_NOT_WARN((INT32)e); +  aliases[c[e].arg] = l; +  } +  }       for(e=0;e<length;e++)    {    if(instrs[c[e].opcode-F_OFFSET].flags & I_POINTER)    { -  +  if (aliases[c[e].arg] >= 0) c[e].arg = aliases[c[e].arg]; +     while(1)    { -  int tmp,tmp2; +  int tmp;    tmp=labels[c[e].arg];       while(tmp<length &&    (c[tmp].opcode == F_LABEL ||    c[tmp].opcode == F_NOP)) tmp++;       if(tmp>=length) break;       if(c[tmp].opcode==F_BRANCH)    {
pike.git/src/peep.c:277:    continue;       case TWOO(F_LAND,F_BRANCH_WHEN_ZERO):    c[e].opcode=F_BRANCH_WHEN_ZERO;    case TWOO(F_LAND,F_LAND):    c[e].arg=c[tmp].arg;    continue;       case TWOO(F_LOR, F_RETURN):    c[e].opcode=F_RETURN_IF_TRUE; -  break; +  goto pointer_opcode_done;       case TWOO(F_BRANCH, F_RETURN):    case TWOO(F_BRANCH, F_RETURN_0):    case TWOO(F_BRANCH, F_RETURN_1):    case TWOO(F_BRANCH, F_RETURN_LOCAL): -  if(c[e].file) free_string(c[e].file); +  if(c[e].file) { +  free_string(dmalloc_touch_named(struct pike_string *, +  c[e].file, "branch_opt 1")); +  }    c[e]=c[tmp]; -  if(c[e].file) add_ref(c[e].file); -  break; +  if(c[e].file) { +  add_ref(dmalloc_touch_named(struct pike_string *, +  c[e].file, "branch_opt 2"));    } -  +  goto pointer_opcode_done; +  }    break;    } -  + #ifdef PIKE_DEBUG +  if (c[e].arg < 0 || c[e].arg > max_label) +  Pike_fatal ("Invalid index into uses: %d\n", c[e].arg); + #endif    uses[c[e].arg]++;    } -  +  pointer_opcode_done:;    }       for(e=0;e<=max_label;e++)    {    if(!uses[e] && labels[e]>=0)    {    c[labels[e]].opcode=F_NOP; -  reoptimize++; +  reoptimize = 1;    }    } -  if(!reoptimize) break; +     -  asm_opt(); -  reoptimize=0; +  if(!reoptimize) { + #ifdef PIKE_DEBUG +  if (a_flag > 3) fprintf (stderr, "Optimizer done after relabel.\n"); + #endif +  break;    }    -  +  /* Then do the optimize pass. */ +  +  relabel = asm_opt(); +  +  reoptimize = 0; +  +  if (!relabel) { + #ifdef PIKE_DEBUG +  if (a_flag > 3) fprintf (stderr, "Optimizer done after asm_opt.\n"); + #endif +  break; +  } +  + #if 1 + #ifdef PIKE_DEBUG +  if (a_flag > 3) +  fprintf(stderr, "Rerunning optimizer.\n"); + #endif + #else /* !1 */ +  relabel = 0; + #endif /* 1 */ +  } +  +  /* Time to create the actual bytecode. */    c=(p_instr *)instrbuf.s.str;    length=instrbuf.s.len / sizeof(p_instr);       for(e=0;e<=max_label;e++) labels[e]=jumps[e]=-1;    -  c=(p_instr *)instrbuf.s.str; +  + #ifdef START_NEW_FUNCTION +  START_NEW_FUNCTION(store_linenumbers); + #endif +  + #ifdef PIKE_PORTABLE_BYTECODE + #ifdef ALIGN_PIKE_FUNCTION_BEGINNINGS +  while( ( (((INT32) PIKE_PC)+4) & (ALIGN_PIKE_JUMPS-1))) +  ins_byte(0); + #endif +  +  if (store_linenumbers) { +  ins_data(store_prog_string(tripples)); +  free_string(tripples); +  } else { +  ins_data(0); +  } + #else + #ifdef ALIGN_PIKE_FUNCTION_BEGINNINGS +  while( ( ((INT32) PIKE_PC) & (ALIGN_PIKE_JUMPS-1))) +  ins_byte(0); + #endif + #endif /* PIKE_PORTABLE_BYTECODE */ +  +  entry_point = PIKE_PC; +  + #ifdef PIKE_DEBUG +  synch_depth = 0; + #endif +  FLUSH_CODE_GENERATOR_STATE();    for(e=0;e<length;e++)    {   #ifdef PIKE_DEBUG -  +  if (c != (((p_instr *)instrbuf.s.str)+e)) { +  Pike_fatal("Instruction loop deviates. " +  "0x%04"PRINTPTRDIFFT"x != 0x%04"PRINTPTRDIFFT"x\n", +  e, c - ((p_instr *)instrbuf.s.str)); +  }    if((a_flag > 2 && store_linenumbers) || a_flag > 3)    { -  fprintf(stderr, "===%3d %4lx ", c->line, -  DO_NOT_WARN((unsigned long)PC)); +  if (c->opcode == F_POP_SYNCH_MARK) synch_depth--; +  fprintf(stderr, "===%4ld %4lx %*s", (long)c->line, +  DO_NOT_WARN((unsigned long)PIKE_PC), synch_depth, "");    dump_instr(c);    fprintf(stderr,"\n"); -  +  if (c->opcode == F_SYNCH_MARK) synch_depth++;    }   #endif    -  if(store_linenumbers) -  store_linenumber(c->line, c->file); +  if(store_linenumbers) { +  store_linenumber(c->line, dmalloc_touch_named(struct pike_string *, +  c->file, +  "store_line")); + #ifdef PIKE_DEBUG +  if (c->opcode < F_MAX_OPCODE) +  ADD_COMPILED(c->opcode); + #endif /* PIKE_DEBUG */ +  }       switch(c->opcode)    {    case F_NOP:    case F_NOTREACHED:    case F_START_FUNCTION:    break;    case F_ALIGN: -  while(PC % c->arg) add_to_program(0); +  ins_align(c->arg);    break;       case F_BYTE: -  add_to_program((unsigned char)(c->arg)); +  ins_byte((unsigned char)(c->arg));    break;       case F_DATA: -  ins_int(c->arg, (void(*)(char))add_to_program); +  ins_data(c->arg);    break;    -  +  case F_ENTRY: + #ifdef INS_ENTRY +  INS_ENTRY(); + #else +  Pike_fatal ("F_ENTRY is supposed to be gone here.\n"); + #endif +  break; +     case F_LABEL: -  if(c->arg == -1) break; +  if(c->arg == -1) {   #ifdef PIKE_DEBUG -  +  if (!(debug_options & NO_PEEP_OPTIMIZING)) +  Pike_fatal ("Failed to optimize away an unused label.\n"); + #endif +  break; +  } + #ifdef PIKE_DEBUG    if(c->arg > max_label || c->arg < 0) -  fatal("max_label calculation failed!\n"); +  Pike_fatal("max_label calculation failed!\n");       if(labels[c->arg] != -1) -  fatal("Duplicate label!\n"); +  Pike_fatal("Duplicate label!\n");   #endif -  labels[c->arg] = DO_NOT_WARN((INT32)PC); +  FLUSH_CODE_GENERATOR_STATE(); +  labels[c->arg] = DO_NOT_WARN((INT32)PIKE_PC); +  if ((e+1 < length) && +  (c[1].opcode != F_LABEL) && +  (c[1].opcode != F_BYTE) && +  (c[1].opcode != F_ENTRY) && +  (c[1].opcode != F_DATA)) { +  /* Don't add redundant code before labels or raw data. */ +  UPDATE_PC(); +  } +     break;    -  +  case F_VOLATILE_RETURN: +  ins_f_byte(F_RETURN); +  break; +  +  case F_POINTER: + #ifdef PIKE_DEBUG +  if(c->arg > max_label || c->arg < 0) +  Pike_fatal("Jump to unknown label?\n"); + #endif +  tmp = DO_NOT_WARN((INT32)PIKE_PC); +  ins_pointer(jumps[c->arg]); +  jumps[c->arg]=tmp; +  break; +     default: -  switch(instrs[c->opcode - F_OFFSET].flags) +  switch(instrs[c->opcode - F_OFFSET].flags & I_IS_MASK)    { -  case I_ISJUMP: +  case I_ISPTRJUMP: + #ifdef INS_F_JUMP +  tmp=INS_F_JUMP(c->opcode, (labels[c->arg] != -1)); +  if(tmp != -1) +  { +  UPDATE_F_JUMP(tmp, jumps[c->arg]); +  jumps[c->arg]=~tmp; +  break; +  } + #endif +     ins_f_byte(c->opcode);    -  case I_ISPOINTER: +    #ifdef PIKE_DEBUG -  if(c->arg > max_label || c->arg < 0) fatal("Jump to unknown label?\n"); +  if(c->arg > max_label || c->arg < 0) +  Pike_fatal("Jump to unknown label?\n");   #endif -  tmp = DO_NOT_WARN((INT32)PC); -  ins_int(jumps[c->arg], (void(*)(char))add_to_program); +  tmp = DO_NOT_WARN((INT32)PIKE_PC); +  ins_pointer(jumps[c->arg]);    jumps[c->arg]=tmp;    break;    -  +  case I_ISPTRJUMPARGS: + #ifdef INS_F_JUMP_WITH_TWO_ARGS +  tmp = INS_F_JUMP_WITH_TWO_ARGS(c->opcode, c->arg, c->arg2, +  (labels[c[1].arg] != -1)); +  if(tmp != -1) +  { +  /* Step ahead to the pointer instruction, and inline it. */ + #ifdef PIKE_DEBUG +  if (c[1].opcode != F_POINTER) { +  Pike_fatal("Expected opcode %s to be followed by a pointer\n", +  instrs[c->opcode - F_OFFSET].name); +  } + #endif /* PIKE_DEBUG */ +  c++; +  e++; +  UPDATE_F_JUMP(tmp, jumps[c->arg]); +  jumps[c->arg]=~tmp; +  break; +  } + #endif /* INS_F_JUMP_WITH_TWO_ARGS */ +  +  /* FALL_THROUGH +  * +  * Note that the pointer in this case will be handled by the +  * next turn through the loop. +  */ +     case I_TWO_ARGS: -  ins_f_byte_with_2_args(c->opcode, c->arg,c->arg2); +  case I_ISJUMPARGS: +  ins_f_byte_with_2_args(c->opcode, c->arg, c->arg2);    break;    -  +  case I_ISPTRJUMPARG: + #ifdef INS_F_JUMP_WITH_ARG +  tmp = INS_F_JUMP_WITH_ARG(c->opcode, c->arg, (labels[c[1].arg] != -1)); +  if(tmp != -1) +  { +  /* Step ahead to the pointer instruction, and inline it. */ + #ifdef PIKE_DEBUG +  if (c[1].opcode != F_POINTER) { +  Pike_fatal("Expected opcode %s to be followed by a pointer\n", +  instrs[c->opcode - F_OFFSET].name); +  } + #endif /* PIKE_DEBUG */ +  c++; +  e++; +  UPDATE_F_JUMP(tmp, jumps[c->arg]); +  jumps[c->arg]=~tmp; +  break; +  } + #endif /* INS_F_JUMP_WITH_ARG */ +  +  /* FALL_THROUGH +  * +  * Note that the pointer in this case will be handled by the +  * next turn through the loop. +  */ +     case I_HASARG: -  +  case I_ISJUMPARG:    ins_f_byte_with_arg(c->opcode, c->arg);    break;       case 0: -  +  case I_ISJUMP:    ins_f_byte(c->opcode);    break;      #ifdef PIKE_DEBUG    default: -  fatal("Unknown instruction type.\n"); +  Pike_fatal("Unknown instruction type.\n");   #endif    }    }    -  + #ifdef PIKE_DEBUG +  if (instrs[c->opcode - F_OFFSET].flags & I_HASPOINTER) { +  if ((e+1 >= length) || (c[1].opcode != F_POINTER)) { +  Pike_fatal("Expected instruction %s to be followed by a pointer.\n" +  "Got %s (%d != %d)\n.", +  instrs[c->opcode - F_OFFSET].name, +  (e+1 < length)?instrs[c[1].opcode - F_OFFSET].name:"EOI", +  (e+1 < length)?c[1].opcode:0, F_POINTER); +  } +  } + #endif /* PIKE_DEBUG */ +  + #ifdef ALIGN_PIKE_JUMPS +  if(e+1 < length) +  { +  /* FIXME: Note that this code won't work for opcodes of type +  * I_ISPTRJUMPARG or I_ISPTRJUMPARGS, since c may already +  * have been advanced to the corresponding F_POINTER. +  * With the current opcode set this is a non-issue, but... +  * /grubba 2002-11-02 +  */ +  switch(c->opcode) +  { +  case F_RETURN: +  case F_VOLATILE_RETURN: +  case F_BRANCH: +  case F_RETURN_0: +  case F_RETURN_1: +  case F_RETURN_LOCAL: +  + #define CALLS(X) \ +  case PIKE_CONCAT3(F_,X,_AND_RETURN): \ +  case PIKE_CONCAT3(F_MARK_,X,_AND_RETURN): +  +  CALLS(APPLY) +  CALLS(CALL_FUNCTION) +  CALLS(CALL_LFUN) +  CALLS(CALL_BUILTIN) +  while( ((INT32) PIKE_PC & (ALIGN_PIKE_JUMPS-1) ) ) +  ins_byte(0); +  } +  } + #endif +     c++;    }       for(e=0;e<=max_label;e++)    { -  int tmp2=labels[e]; +  INT32 tmp2=labels[e];       while(jumps[e]!=-1)    {   #ifdef PIKE_DEBUG    if(labels[e]==-1) -  fatal("Hyperspace error: unknown jump point %ld at %d (pc=%x).\n", -  PTRDIFF_T_TO_LONG(e), labels[e], jumps[e]); +  Pike_fatal("Hyperspace error: unknown jump point %ld(%ld) at %d (pc=%x).\n", +  PTRDIFF_T_TO_LONG(e), PTRDIFF_T_TO_LONG(max_label), +  labels[e], jumps[e]);   #endif -  tmp=read_int(jumps[e]); -  upd_int(jumps[e], tmp2 - jumps[e]); + #ifdef INS_F_JUMP +  if(jumps[e] < 0) +  { +  tmp = READ_F_JUMP(~jumps[e]); +  UPDATE_F_JUMP(~jumps[e], tmp2);    jumps[e]=tmp; -  +  continue;    } -  + #endif +  +  tmp = read_pointer(jumps[e]); +  upd_pointer(jumps[e], tmp2 - jumps[e]); +  jumps[e]=tmp;    } -  +  }       free((char *)labels); -  free((char *)jumps); -  free((char *)uses); +     -  + #ifdef END_FUNCTION +  END_FUNCTION(store_linenumbers); + #endif    -  + #ifdef PIKE_DEBUG +  if (a_flag > 6) { +  size_t len = (Pike_compiler->new_program->num_program - fun_start)* +  sizeof(PIKE_OPCODE_T); +  fprintf(stderr, "Code at offset %"PRINTSIZET"d through %"PRINTSIZET"d:\n", +  fun_start, Pike_compiler->new_program->num_program-1); + #ifdef DISASSEMBLE_CODE +  DISASSEMBLE_CODE(Pike_compiler->new_program->program + fun_start, len); + #else /* !DISASSEMBLE_CODE */ +  { +  /* FIXME: Hexdump here. */ +  } + #endif /* DISASSEMBLE_CODE */ +  } + #endif /* PIKE_DEBUG */ +     exit_bytecode(); -  +  +  return entry_point;   }      /**** Peephole optimizer ****/    -  + static void do_optimization(int topop, int topush, ...); + static INLINE int opcode(int offset); + static INLINE int argument(int offset); + static INLINE int argument2(int offset); +  + #include "peep_engine.c" +  + #ifndef PEEP_STACK_SIZE + #define PEEP_STACK_SIZE 256 + #endif +  + /* Stack holding pending instructions. +  * Note that instructions must be pushed in reverse order. +  */ + static long stack_depth = 0; + static p_instr instrstack[PEEP_STACK_SIZE]; +    int remove_clear_locals=0x7fffffff; - static int fifo_len; +    static ptrdiff_t eye, len;   static p_instr *instructions;    - static INLINE ptrdiff_t insopt2(int f, INT32 a, INT32 b, -  int cl, struct pike_string *cf) + /* insopt{0,1,2} push an instruction on instrstack. */ +  + static INLINE p_instr *insopt2(int f, INT32 a, INT32 b, +  INT_TYPE cl, struct pike_string *cf)   {    p_instr *p;      #ifdef PIKE_DEBUG    if(!hasarg2(f) && b) -  fatal("hasarg(%d) is wrong!\n",f); +  Pike_fatal("hasarg2(%d /*%s */) is wrong!\n",f,get_f_name(f));   #endif    -  p=(p_instr *)low_make_buf_space(sizeof(p_instr), &instrbuf); +  p = instrstack + stack_depth++;    -  if(fifo_len) -  { -  MEMMOVE(p-fifo_len+1,p-fifo_len,fifo_len*sizeof(p_instr)); -  p-=fifo_len; -  } -  +    #ifdef PIKE_DEBUG -  if(!instrbuf.s.len) -  fatal("Low make buf space failed!!!!!!\n"); +  if(stack_depth > PEEP_STACK_SIZE) +  Pike_fatal("Instructions stacked too high!!!!!!\n");   #endif       p->opcode=f;    p->line=cl; -  copy_shared_string(p->file, cf); +  copy_shared_string(p->file, dmalloc_touch_named(struct pike_string *, +  cf, "insopt2"));    p->arg=a;    p->arg2=b;    -  return p - (p_instr *)instrbuf.s.str; +  return p;   }    - static INLINE ptrdiff_t insopt1(int f, INT32 a, int cl, struct pike_string *cf) + static INLINE p_instr *insopt1(int f, INT32 a, INT_TYPE cl, +  struct pike_string *cf)   {   #ifdef PIKE_DEBUG    if(!hasarg(f) && a) -  fatal("hasarg(%d) is wrong!\n",f); +  Pike_fatal("hasarg(%d /* %s */) is wrong!\n",f,get_f_name(f));   #endif       return insopt2(f,a,0,cl, cf);   }    - static INLINE ptrdiff_t insopt0(int f, int cl, struct pike_string *cf) + static INLINE p_instr *insopt0(int f, INT_TYPE cl, struct pike_string *cf)   {   #ifdef PIKE_DEBUG    if(hasarg(f)) -  fatal("hasarg(%d) is wrong!\n",f); +  Pike_fatal("hasarg(%d /* %s */) is wrong!\n",f,get_f_name(f));   #endif    return insopt2(f,0,0,cl, cf);   }    -  + #ifdef PIKE_DEBUG   static void debug(void)   { -  if(fifo_len > (long)instrbuf.s.len / (long)sizeof(p_instr)) -  fifo_len=(long)instrbuf.s.len / (long)sizeof(p_instr); - #ifdef PIKE_DEBUG -  if(eye < 0) -  fatal("Popped beyond start of code.\n"); -  +  if (num_instrs != (long)instrbuf.s.len / (long)sizeof(p_instr)) { +  Pike_fatal("PEEP: instrbuf lost count (%d != %d)\n", +  num_instrs, (long)instrbuf.s.len / (long)sizeof(p_instr)); +  }    if(instrbuf.s.len)    {    p_instr *p;    p=(p_instr *)low_make_buf_space(0, &instrbuf);    if(!p[-1].file) -  fatal("No file name on last instruction!\n"); +  Pike_fatal("No file name on last instruction!\n");    } - #endif +    } -  + #else + #define debug() + #endif       -  + /* Offset from the end of instrbuf backwards. */   static INLINE p_instr *instr(int offset)   { -  p_instr *p; -  -  debug(); -  -  if(offset < fifo_len) -  { -  p=(p_instr *)low_make_buf_space(0, &instrbuf); -  p-=fifo_len; -  p+=offset; -  if(((char *)p)<instrbuf.s.str) return 0; -  return p; -  }else{ -  offset-=fifo_len; -  offset+=eye; -  if(offset >= len) return 0; -  return instructions+offset; +  if (offset >= num_instrs) return NULL; +  return ((p_instr *)low_make_buf_space(0, &instrbuf)) - (offset + 1);   } - } +       static INLINE int opcode(int offset)   {    p_instr *a;    a=instr(offset);    if(a) return a->opcode;    return -1;   }      static INLINE int argument(int offset)
pike.git/src/peep.c:543:   }      static INLINE int argument2(int offset)   {    p_instr *a;    a=instr(offset);    if(a) return a->arg2;    return -1;   }    - static void advance(void) + static int advance(void)   { -  if(fifo_len) +  p_instr *p; +  if(stack_depth)    { -  fifo_len--; +  p = instrstack + --stack_depth;    }else{ -  p_instr *p; -  if((p=instr(0))) -  insert_opcode2(p->opcode, p->arg, p->arg2, p->line, p->file); +  if (eye >= len) return 0; +  p = instructions + eye;    eye++;    } -  +  insert_opcode(p); +  debug_malloc_touch_named(p->file, "advance");    debug(); -  +  return 1;   }      static void pop_n_opcodes(int n)   { -  int e,d; -  if(fifo_len) -  { +  int e;    p_instr *p;    -  d=n; -  if(d>fifo_len) d=fifo_len; +    #ifdef PIKE_DEBUG -  if((long)d > (long)instrbuf.s.len / (long)sizeof(p_instr)) -  fatal("Popping out of instructions.\n"); +  if (n > num_instrs) +  Pike_fatal("Popping out of instructions.\n");   #endif    -  /* FIXME: It looks like the fifo could be optimized. -  * /grubba 2000-11-21 (in Versailles) -  */ -  -  p=(p_instr *)low_make_buf_space(0, &instrbuf); -  p-=fifo_len; -  for(e=0;e<d;e++) free_string(p[e].file); -  fifo_len-=d; -  if(fifo_len) MEMMOVE(p,p+d,fifo_len*sizeof(p_instr)); -  n-=d; -  low_make_buf_space(-((INT32)sizeof(p_instr))*d, &instrbuf); +  p = ((p_instr *)low_make_buf_space(0, &instrbuf)) - n; +  for (e = 0; e < n; e++) { +  free_string(dmalloc_touch_named(struct pike_string *, p[e].file, +  "pop_n_opcodes"));    } -  eye+=n; +  num_instrs -= n; +  low_make_buf_space(-((INT32)sizeof(p_instr))*n, &instrbuf);   }    - #define DO_OPTIMIZATION_PREQUEL(topop) do { \ -  struct pike_string *cf; \ -  INT32 cl=instr(0)->line; \ -  \ -  DO_IF_DEBUG( \ -  if(a_flag>5) \ -  { \ -  int e; \ -  fprintf(stderr,"PEEP at %d:",cl); \ -  for(e=0;e<topop;e++) \ -  { \ -  fprintf(stderr," "); \ -  dump_instr(instr(e)); \ -  } \ -  fprintf(stderr," => "); \ -  } \ -  ) \ -  \ -  copy_shared_string(cf,instr(0)->file); \ -  pop_n_opcodes(topop) +     - #define DO_OPTIMIZATION_POSTQUEL(q) \ -  fifo_len+=q; \ -  free_string(cf); \ -  debug(); \ -  \ -  DO_IF_DEBUG( \ -  if(a_flag>5) \ -  { \ -  int e; \ -  for(e=0;e<q;e++) \ -  { \ -  fprintf(stderr," "); \ -  dump_instr(instr(e)); \ -  } \ -  fprintf(stderr,"\n"); \ -  } \ -  ) \ -  \ -  fifo_len += q + 3; \ -  } while(0) -  -  - static void do_optimization(int topop, ...) + /* NOTE: Called with opcodes in reverse order! */ + static void do_optimization(int topop, int topush, ...)   {    va_list arglist; -  int q=-1; +  int q=0; +  int oplen; +  struct pike_string *cf; +  INT_TYPE cl=instr(0)->line;    -  DO_OPTIMIZATION_PREQUEL(topop); + #ifdef PIKE_DEBUG +  if(a_flag>5) +  { +  int e; +  fprintf(stderr, "PEEP at %ld:", cl); +  for(e = topop; e--;) +  { +  fprintf(stderr," "); +  dump_instr(instr(e)); +  } +  fprintf(stderr," => "); +  } + #endif    -  va_start(arglist, topop); +  if (stack_depth + topush > PEEP_STACK_SIZE) { +  /* No place left on stack. Ignore the optimization. */ + #ifdef PIKE_DEBUG +  if (a_flag) { +  fprintf(stderr, "PEEP stack full.\n"); +  } + #endif +  return; +  }    -  while(1) +  copy_shared_string(cf,dmalloc_touch_named(struct pike_string *, +  instr(0)->file, +  "do_optimization")); +  pop_n_opcodes(topop); +  +  va_start(arglist, topush); +  +  while((oplen = va_arg(arglist, int)))    {    q++; -  switch(va_arg(arglist, int)) +  switch(oplen)    { -  case 0: + #ifdef PIKE_DEBUG +  default: +  Pike_fatal("Unsupported argument number: %d\n", oplen);    break; -  + #endif /* PIKE_DEBUG */ +     case 1:    {    int i=va_arg(arglist, int);    insopt0(i,cl,cf); -  continue; +     } -  +  break; +     case 2:    {    int i=va_arg(arglist, int);    int j=va_arg(arglist, int);    insopt1(i,j,cl,cf); -  continue; +     } -  +  break; +     case 3:    {    int i=va_arg(arglist, int);    int j=va_arg(arglist, int);    int k=va_arg(arglist, int);    insopt2(i,j,k,cl,cf); -  continue; +     } -  } +     break;    } -  +  }       va_end(arglist);    -  DO_OPTIMIZATION_POSTQUEL(q); +  /*fifo_len+=q;*/ +  free_string(dmalloc_touch_named(struct pike_string *, cf, +  "do_optimization")); +  debug(); +  + #ifdef PIKE_DEBUG +  if(a_flag>5) +  { +  p_instr *p = instrstack + stack_depth; +  int e; +  for(e=0;e<q;e++) +  { +  fprintf(stderr," "); +  dump_instr(p-(e+1));    } -  +  fprintf(stderr,"\n"); +  } +  if (q != topush) { +  Pike_fatal("PEEP: Lost track of instructions to push (%d != %d)\n", +  q, topush); +  } + #endif    -  +  /* Note: The 5 below is the longest +  * match prefix in the ruleset +  */ +  /*fifo_len += q + 5;*/ + }    - static void asm_opt(void) + static int asm_opt(void)   { -  +  int relabel = 0; +    #ifdef PIKE_DEBUG    if(a_flag > 3)    {    p_instr *c;    ptrdiff_t e, length; -  +  int synch_depth = 0;       c=(p_instr *)instrbuf.s.str;    length=instrbuf.s.len / sizeof(p_instr);    -  fprintf(stderr,"Optimization begins: \n"); +  fprintf(stderr,"Before peep optimization:\n");    for(e=0;e<length;e++,c++)    { -  fprintf(stderr,"---%3d: ",c->line); +  if (c->opcode == F_POP_SYNCH_MARK) synch_depth--; +  fprintf(stderr,"<<<%4ld: %*s",(long)c->line,synch_depth,"");    dump_instr(c);    fprintf(stderr,"\n"); -  +  if (c->opcode == F_SYNCH_MARK) synch_depth++;    }    }   #endif    - #ifndef IN_TPIKE - #include "peep_engine.c" - #endif /* IN_TPIKE */ +  len=instrbuf.s.len/sizeof(p_instr); +  instructions=(p_instr *)instrbuf.s.str; +  instrbuf.s.str=0; +  init_bytecode();    -  +  for(eye = 0; advance();) +  {   #ifdef PIKE_DEBUG -  +  if(a_flag>6) { +  int e; +  fprintf(stderr, "#%ld,%ld:", +  DO_NOT_WARN((long)eye), +  stack_depth); +  for(e = 4;e--;) { +  fprintf(stderr," "); +  dump_instr(instr(e)); +  } +  /* FIXME: Show instrstack too? */ +  fprintf(stderr,"\n"); +  } + #endif +  +  relabel |= low_asm_opt(); +  } +  +  free((char *)instructions); +  + #ifdef PIKE_DEBUG    if(a_flag > 4)    {    p_instr *c;    ptrdiff_t e, length; -  +  int synch_depth = 0;       c=(p_instr *)instrbuf.s.str;    length=instrbuf.s.len / sizeof(p_instr);    -  fprintf(stderr,"Optimization begins: \n"); +  fprintf(stderr,"After peep optimization:\n");    for(e=0;e<length;e++,c++)    { -  fprintf(stderr,">>>%3d: ",c->line); +  if (c->opcode == F_POP_SYNCH_MARK) synch_depth--; +  fprintf(stderr,">>>%4ld: %*s",(long)c->line,synch_depth,"");    dump_instr(c);    fprintf(stderr,"\n"); -  +  if (c->opcode == F_SYNCH_MARK) synch_depth++;    }    }   #endif - } +     -  +  return relabel; + }