Branch: Tag:

2001-11-08

2001-11-08 23:34:31 by Fredrik Hübinette (Hubbe) <hubbe@hubbe.net>

Changes from Hubbe
fixed problems with custom handlers and implemented 2-pass decode_value for programs
speedups, optimizations, memory leak fixes and some bug fixes
removed a warning

Rev: src/encode.c:1.131

25:   #include "version.h"   #include "bignum.h"    - RCSID("$Id: encode.c,v 1.130 2001/10/05 01:30:12 hubbe Exp $"); + RCSID("$Id: encode.c,v 1.131 2001/11/08 23:34:28 nilsson Exp $");      /* #define ENCODE_DEBUG */      #ifdef ENCODE_DEBUG   /* Pass a nonzero integer as the third arg to encode_value,    * encode_value_canonic and decode_value to activate this debug. */ - #define EDB(N,X) do if (data->debug>=N) {X;} while (0) + #define EDB(N,X) do { debug_malloc_touch(data); if (data->debug>=N) {X;} } while (0)   #else - #define EDB(N,X) do {} while (0) + #define EDB(N,X) do { debug_malloc_touch(data); } while (0)   #endif      /* The sp macro conflicts with Solaris 2.5.1's <sys/conf.h>. */
473:   {    int e;    debug_malloc_touch(p); +  if(p->flags & PROGRAM_FIXED) return; /* allow natural zapping */    if(p->parent)    {    free_program(p->parent);
1278:    struct svalue counter;    struct object *codec;    int pickyness; +  int pass;    struct pike_string *raw;    struct decode_data *next;   #ifdef PIKE_THREADS
1286: Inside #if defined(ENCODE_DEBUG)
  #ifdef ENCODE_DEBUG    int debug, depth;   #endif +  struct Supporter supporter;   };      static void decode_value2(struct decode_data *data);
1403:   #define getdata(X) do { \    long length; \    decode_entry(TAG_STRING, length,data); \ +  if(data->pass == 1) \    get_string_data(X, length, data); \ -  +  else \ +  data->ptr+=length; \    }while(0)      #define getdata3(X) do { \
1650:    UNSET_ONERROR(err1);   }    +  + static void zap_placeholder(struct object *placeholder) + { +  /* fprintf(stderr, "Destructing placeholder.\n"); */ +  if (placeholder->storage) { +  debug_malloc_touch(placeholder); +  destruct(placeholder); +  } else { +  free_program(placeholder->prog); +  placeholder->prog = NULL; +  debug_malloc_touch(placeholder); +  } +  free_object(placeholder); + } +  + static int init_placeholder(struct object *placeholder); +  +  + #define SETUP_DECODE_MEMOBJ(TYPE, U, VAR, ALLOCATE,SCOUR) do { \ +  struct svalue *tmpptr; \ +  if(data->pass > 1 && \ +  (tmpptr=low_mapping_lookup(data->decoded, & data->counter))) \ +  { \ +  tmp=*tmpptr; \ +  VAR=tmp.u.U; \ +  SCOUR; \ +  }else{ \ +  tmp.type=TYPE; \ +  tmp.u.U=VAR=ALLOCATE; \ +  mapping_insert(data->decoded, & data->counter, &tmp); \ +  /* Since a reference to the object is stored in the mapping, we can \ +  * safely decrease this reference here. Thus it will be automatically \ +  * freed if something goes wrong. \ +  */ \ +  VAR->refs--; \ +  } \ +  data->counter.u.integer++; \ + }while(0) +    #ifdef USE_PIKE_TYPE   /* This really needs to disable threads.... */   #define decode_type(X,data) do { \
1815:    if(data->ptr + num > data->len)    Pike_error("Failed to decode array. (not enough data)\n");    -  tmp.type=T_ARRAY; -  tmp.u.array=a=allocate_array(num); +     EDB(2,fprintf(stderr, "%*sDecoding array of size %d to <%d>\n",    data->depth, "", num, data->counter.u.integer)); -  mapping_insert(data->decoded, & data->counter, &tmp); -  data->counter.u.integer++; +     -  /* Since a reference to the array is stored in the mapping, we can -  * safely decrease this reference here. Thus it will be automatically -  * freed if something goes wrong. -  */ -  a->refs--; +  SETUP_DECODE_MEMOBJ(T_ARRAY, array, a, allocate_array(num), +  free_svalues(ITEM(a), a->size, a->type_field));       for(e=0;e<num;e++)    {
1852:    if(data->ptr + num > data->len)    Pike_error("Failed to decode mapping. (not enough data)\n");    -  m=allocate_mapping(num); -  tmp.type=T_MAPPING; -  tmp.u.mapping=m; +     EDB(2,fprintf(stderr, "%*sDecoding mapping of size %d to <%d>\n",    data->depth, "", num, data->counter.u.integer)); -  mapping_insert(data->decoded, & data->counter, &tmp); -  data->counter.u.integer++; -  m->refs--; +     -  +  SETUP_DECODE_MEMOBJ(T_MAPPING, mapping, m, allocate_mapping(num), ; ); +     for(e=0;e<num;e++)    {    decode_value2(data);
1887:    Pike_error("Failed to decode multiset. (not enough data)\n");       /* NOTE: This code knows stuff about the implementation of multisets...*/ -  a = low_allocate_array(num, 0); -  m = allocate_multiset(a); -  tmp.type = T_MULTISET; -  tmp.u.multiset = m; +     EDB(2,fprintf(stderr, "%*sDecoding multiset of size %d to <%d>\n",    data->depth, "", num, data->counter.u.integer)); -  mapping_insert(data->decoded, & data->counter, &tmp); -  data->counter.u.integer++; -  debug_malloc_touch(m); +  SETUP_DECODE_MEMOBJ(T_MULTISET, multiset, m, +  allocate_multiset(low_allocate_array(num, 0)), ;); +  a=m->ind;       for(e=0;e<num;e++)    {    decode_value2(data); -  a->item[e] = sp[-1]; -  sp--; +  assign_svalue(a->item+e , sp-1); +  pop_stack();    dmalloc_touch_svalue(sp);    }    array_fix_type_field(a);    order_multiset(m); -  push_multiset(m); +  ref_push_multiset(m);   #ifdef ENCODE_DEBUG    data->depth -= 2;   #endif
2099:    }    case 1:    { -  int d; +  int d, in;    size_t size=0; -  char *dat; +  char *dat=0;    struct program *p; -  ONERROR err1, err2, err3; +  struct object *placeholder=0; +  ONERROR err1, err2, err3, err4;      #ifdef _REENTRANT    ONERROR err;
2111:    SET_ONERROR(err, do_enable_threads, 0);   #endif    -  p=low_allocate_program(); +  EDB(2,fprintf(stderr, "%*sDecoding a program to <%d>: ", +  data->depth, "", data->counter.u.integer); +  print_svalue(stderr, &tmp); +  fputc('\n', stderr);); +  +  SETUP_DECODE_MEMOBJ(T_PROGRAM, program, p, low_allocate_program(),;); +     SET_ONERROR(err3, zap_unfinished_program, p);    -  +  if(data->pass == 1) +  { +  if(! data->supporter.prog) +  data->supporter.prog = p; +     debug_malloc_touch(p);    if(data->codec)    {    ref_push_program(p);    apply(data->codec, "__register_new_program", 1); -  +  +  /* return a placeholder */ +  if(Pike_sp[-1].type == T_OBJECT) +  { +  placeholder=Pike_sp[-1].u.object; +  if(placeholder->prog != null_program) +  Pike_error("Placeholder object is not a null_program clone!\n"); +  Pike_sp--; +  }else{    pop_stack();    } -  tmp.type=T_PROGRAM; -  tmp.u.program=p; -  EDB(2,fprintf(stderr, "%*sDecoding a program to <%d>: ", -  data->depth, "", data->counter.u.integer); -  print_svalue(stderr, &tmp); -  fputc('\n', stderr);); -  mapping_insert(data->decoded, & data->counter, &tmp); -  data->counter.u.integer++; -  p->refs--; +  } +  }    -  +  if(placeholder) +  SET_ONERROR(err4, zap_placeholder, placeholder); +     decode_value2(data);    f_version(0);    if(!is_eq(Pike_sp-1,Pike_sp-2))
2139:       debug_malloc_touch(p);    decode_number(p->flags,data); +  +  if(data->pass == 1) +  {    p->flags &= ~(PROGRAM_FINISHED | PROGRAM_OPTIMIZED |    PROGRAM_FIXED | PROGRAM_PASS_1_DONE);    p->flags |= PROGRAM_AVOID_CHECK; -  +  }    decode_number(p->storage_needed,data);    decode_number(p->xstorage,data);    decode_number(p->parent_info_storage,data);
2149:    decode_number(p->timestamp.tv_sec,data);    decode_number(p->timestamp.tv_usec,data);    +  if(data->pass && p->parent) +  { +  free_program(p->parent); +  p->parent=0; +  } +     debug_malloc_touch(p);    decode_value2(data);    switch(Pike_sp[-1].type)
2177:    decode_number( p->num_##Z, data);   #include "program_areas.h"    +  +  if(data->pass == 1) +  {   #define FOO(NUMTYPE,TYPE,NAME) \    size=DO_ALIGN(size, ALIGNOF(TYPE)); \    size+=p->PIKE_CONCAT(num_,NAME)*sizeof(p->NAME[0]);
2201:    p->total_size=size + sizeof(struct program);       p->flags |= PROGRAM_OPTIMIZED; +  }       {    INT32 bytecode_method = 0;
2293:    p->inherits[0].parent_offset=1;   */    +  if(placeholder && data->pass==1) +  { +  if(placeholder->prog != null_program) +  { +  debug_malloc_touch(placeholder); +  Pike_error("Placeholder argument is not a null_program clone!"); +  }else{ +  free_program(placeholder->prog); +  add_ref(placeholder->prog = p); +  debug_malloc_touch(placeholder); +  } +  } +     debug_malloc_touch(p); -  for(d=0;d<p->num_inherits;d++) +  +  in=p->num_inherits; +  for(d=0;d<in;d++)    {    decode_number(p->inherits[d].inherit_level,data);    decode_number(p->inherits[d].identifier_level,data);
2311:    p->refs--;    }    +  if(data->pass > 1) +  { +  if(p->inherits[d].prog) +  { +  free_program(p->inherits[d].prog); +  p->inherits[d].prog=0; +  } +  +  if(p->inherits[d].parent) +  { +  free_object(p->inherits[d].parent); +  p->inherits[d].parent=0; +  } +  } +     switch(Pike_sp[-1].type)    {    case T_FUNCTION:
2339:    Pike_error("Failed to decode inheritance.\n");    }    +  p->num_inherits=d+1; +     getdata3(p->inherits[d].name);       EDB(3, fprintf(stderr,"INHERIT%x < %d: %d id=%d\n",
2395:       debug_malloc_touch(dat);    debug_malloc_touch(p); -  p->flags |= PROGRAM_PASS_1_DONE | PROGRAM_FIXED; -  if(data->codec) -  { -  ref_push_program(p); -  apply(data->codec, "__register_new_object", 1); -  pop_stack(); -  } +     -  +  p->flags |= PROGRAM_PASS_1_DONE | PROGRAM_FIXED;    for(d=0;d<p->num_constants;d++)    {    decode_value2(data); -  +  if(data->pass > 1) +  { +  assign_svalue(& p->constants[d].sval , Pike_sp -1 ); +  pop_stack(); +  }else{    p->constants[d].sval=*--Pike_sp; -  +  }    dmalloc_touch_svalue(Pike_sp);    getdata3(p->constants[d].name);    } -  data->pickyness--; +     -  + #ifdef PIKE_DEBUG +  { +  int q; +  for(q=0;q<p->num_inherits;q++) +  if(!p->inherits[q].prog) +  fatal("FOOBAR!@!!!\n"); +  } + #endif    -  +  if(placeholder && data->pass == 1) +  { +  if(!p || (placeholder->storage)) +  { +  Pike_error("Placeholder already has storage!\n"); +  } else { +  placeholder->storage=p->storage_needed ? +  (char *)xalloc(p->storage_needed) : +  (char *)0; +  call_c_initializers(placeholder); +  } +  } +  +  data->pickyness--; +  +  if(placeholder) +  { +  free_object(placeholder); +  UNSET_ONERROR(err4); +  }    UNSET_ONERROR(err3);       ref_push_program(p);    -  +  if(!(p->flags & PROGRAM_FINISHED) && +  !data->supporter.depends_on) +  {    /* Logic for the PROGRAM_FINISHED flag:    * The purpose of this code is to make sure that the PROGRAM_FINISHED    * flat is not set on the program until all inherited programs also
2431:    p->flags &=~ PROGRAM_AVOID_CHECK;    p->flags |= PROGRAM_FINISHED;    +  if (placeholder) +  { +  if(!init_placeholder(placeholder)) +  placeholder=0; +  } +     /* Go through the linked list of unfinished programs    * to see what programs are now finished.    */
2493:    free((char *)l);    }    } -  -  +     }else{    struct unfinished_prog_link *l;    l=ALLOC_STRUCT(unfinished_prog_link);
2502:    l->next=data->unfinished_programs;    data->unfinished_programs=l;    } +  }      #ifdef _REENTRANT    UNSET_ONERROR(err);
2565:   #endif   }    + /* Placed after to prevent inlining */ + static int init_placeholder(struct object *placeholder) + { +  JMP_BUF rec; +  /* Initialize the placeholder. */ +  if(SETJMP(rec)) +  { +  dmalloc_touch_svalue(&throw_value); +  call_handle_error(); +  zap_placeholder(placeholder); +  UNSETJMP(rec); +  return 1; +  }else{ +  call_pike_initializers(placeholder,0); +  UNSETJMP(rec); +  return 0; +  } + }    -  +  +    static struct decode_data *current_decode = NULL;      static void free_decode_data(struct decode_data *data)   { -  free_mapping(data->decoded); -  while(data->unfinished_programs) -  { -  struct unfinished_prog_link *tmp=data->unfinished_programs; -  data->unfinished_programs=tmp->next; -  free((char *)tmp); -  } +  int delay;    -  while(data->unfinished_objects) -  { -  struct unfinished_obj_link *tmp=data->unfinished_objects; -  data->unfinished_objects=tmp->next; -  free((char *)tmp); -  } +  debug_malloc_touch(data); +     if (current_decode == data) {    current_decode = data->next;    } else {
2600:    }   #endif /* PIKE_DEBUG */    } +  +  +  delay=unlink_current_supporter(&data->supporter); +  call_dependants(& data->supporter); +  +  if(delay) +  { +  debug_malloc_touch(data); +  /* We have been delayed */ +  return; +  } +  +  free_mapping(data->decoded); +  + #ifdef PIKE_DEBUG +  if(data->unfinished_programs) +  fatal("We have unfinished programs left in decode()!\n"); +  if(data->unfinished_objects) +  fatal("We have unfinished objects left in decode()!\n"); + #endif +  +  while(data->unfinished_programs) +  { +  struct unfinished_prog_link *tmp=data->unfinished_programs; +  data->unfinished_programs=tmp->next; +  free((char *)tmp); +  } +  +  while(data->unfinished_objects) +  { +  struct unfinished_obj_link *tmp=data->unfinished_objects; +  data->unfinished_objects=tmp->next; +  free((char *)tmp); +  }   #ifdef PIKE_THREADS    free_object(data->thread_id);   #endif -  +  +  free( (char *) data);   }    -  + /* Run pass2 */ + void re_decode(struct decode_data *data) + { +  ONERROR err; +  SET_ONERROR(err, free_decode_data, data); +  data->next = current_decode; +  current_decode = data; +  +  decode_value2(data); +  +  CALL_AND_UNSET_ONERROR(err); +  +  free_decode_data(data); + } +    static INT32 my_decode(struct pike_string *tmp,    struct object *codec   #ifdef ENCODE_DEBUG
2613:    )   {    ONERROR err; -  struct decode_data d, *data; +  struct decode_data *data;       /* Attempt to avoid infinite recursion on circular structures. */    for (data = current_decode; data; data=data->next) {
2639:    }    }    -  data=&d; +  data=ALLOC_STRUCT(decode_data);    data->counter.type=T_INT;    data->counter.u.integer=COUNTER_START;    data->data=(unsigned char *)tmp->str;
2647:    data->ptr=0;    data->codec=codec;    data->pickyness=0; +  data->pass=1;    data->unfinished_programs=0;    data->unfinished_objects=0;    data->raw = tmp;
2659:    data->depth = -2;   #endif    -  if (tmp->size_shift) return 0; -  if(data->len < 5) return 0; -  if(GETC() != 182 || +  if (tmp->size_shift || +  data->len < 5 || +  GETC() != 182 ||    GETC() != 'k' ||    GETC() != 'e' ||    GETC() != '0') -  +  { +  free( (char *) data);    return 0; -  +  }      #ifdef PIKE_THREADS    add_ref(Pike_interpreter.thread_id);
2676:    current_decode = data;       SET_ONERROR(err, free_decode_data, data); +  +  init_supporter(& data->supporter, +  ( void (*)(void*) )re_decode, +  (void *)data); +     decode_value2(data);    - #ifdef PIKE_DEBUG -  if(data->unfinished_programs) -  fatal("We have unfinished programs left in decode()!\n"); -  if(data->unfinished_objects) -  fatal("We have unfinished objects left in decode()!\n"); - #endif +     CALL_AND_UNSET_ONERROR(err);    return 1;   }