pike.git / src / encode.c

version» Context lines:

pike.git/src/encode.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. - || $Id: encode.c,v 1.188 2003/06/12 14:13:49 grubba Exp $ + || $Id: encode.c,v 1.189 2003/06/12 18:42:56 mast Exp $   */      #include "global.h"   #include "stralloc.h"   #include "pike_macros.h"   #include "object.h"   #include "constants.h"   #include "interpret.h"   #include "svalue.h"   #include "mapping.h"
pike.git/src/encode.c:20:   #include "operators.h"   #include "builtin_functions.h"   #include "module_support.h"   #include "fsort.h"   #include "threads.h"   #include "stuff.h"   #include "version.h"   #include "bignum.h"   #include "pikecode.h"    - RCSID("$Id: encode.c,v 1.188 2003/06/12 14:13:49 grubba Exp $"); + RCSID("$Id: encode.c,v 1.189 2003/06/12 18:42:56 mast Exp $");      /* #define ENCODE_DEBUG */      /* Use the old encoding method for programs. */   /* #define OLD_PIKE_ENCODE_PROGRAM */      #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 { debug_malloc_touch(data); if (data->debug>=N) {X;} } while (0)
pike.git/src/encode.c:1499:    /* Encode the constant values table. */    {    struct svalue str_sval;    str_sval.type = T_STRING;    str_sval.subtype = 0;       /* constants */    for(d=0;d<p->num_constants;d++)    {    /* value */ -  /* Must force encoding of constants. They typically are -  * inner classes which must be finished before this -  * program is, since an object might be created for it -  * immediately afterwards which instantiate the inner -  * classes. */ -  encode_value2(&p->constants[d].sval, data, 1); +  encode_value2(&p->constants[d].sval, data, 0);       /* name */    if (p->constants[d].name) {    str_sval.u.string = p->constants[d].name;    encode_value2(&str_sval, data, 0);    } else {    push_int(0);    encode_value2(Pike_sp-1, data, 0);    dmalloc_touch_svalue(Pike_sp-1);    Pike_sp--;
pike.git/src/encode.c:1735:   struct decode_data   {    unsigned char *data;    ptrdiff_t len;    ptrdiff_t ptr;    struct mapping *decoded;    struct unfinished_prog_link *unfinished_programs;    struct unfinished_obj_link *unfinished_objects;    struct svalue counter;    struct object *codec; -  struct program *target_prog; -  struct object *placeholder; -  struct array *delayed; +     int pickyness;    int pass;    struct pike_string *raw;    struct decode_data *next;   #ifdef PIKE_THREADS    struct thread_state *thread_state;   #endif   #ifdef ENCODE_DEBUG    int debug, depth;   #endif    struct Supporter supporter;   };    - static void decode_value2(struct decode_data *data, int force_decode); + static void decode_value2(struct decode_data *data);      static int my_extract_char(struct decode_data *data)   {    if(data->ptr >= data->len)    Pike_error("Format error, not enough data in string.\n");    return data->data [ data->ptr++ ];   }      #define GETC() my_extract_char(data)   
pike.git/src/encode.c:2011:    case T_FLOAT:    case T_STRING:    case T_MIXED:    case T_ZERO:    case T_VOID:    case PIKE_T_UNKNOWN:    push_type(tmp);    break;       case PIKE_T_NAME: -  decode_value2(data, 0); +  decode_value2(data);       if (Pike_sp[-1].type != PIKE_T_STRING) {    Pike_error("decode_value(): Type name is not a string (%s)\n",    get_name_of_type(Pike_sp[-1].type));    }    low_decode_type(data);    push_type_name(Pike_sp[-1].u.string);    pop_stack();    break;       case T_OBJECT:    {    int flag = GETC();    -  decode_value2(data, 0); +  decode_value2(data);    switch(Pike_sp[-1].type)    {    case T_INT:    push_object_type_backwards(flag, Pike_sp[-1].u.integer );    break;       case T_PROGRAM:    push_object_type_backwards(flag, Pike_sp[-1].u.program->id);    break;   
pike.git/src/encode.c:2065:    }    pop_stack();    }    }       UNSET_ONERROR(err2);    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; \    struct svalue tmp; \    if(data->pass > 1 && \    (tmpptr=low_mapping_lookup(data->decoded, & entry_id))) \    { \    tmp=*tmpptr; \    VAR=tmp.u.U; \ -  {SCOUR;} \ +  SCOUR; \    }else{ \    tmp.type=TYPE; \ -  {ALLOCATE;} \ -  tmp.u.U=VAR; \ +  tmp.u.U=VAR=ALLOCATE; \    mapping_insert(data->decoded, & entry_id, &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. \    */ \    sub_ref(VAR); \    } \   }while(0)      /* This really needs to disable threads.... */   #define decode_type(X,data) do { \    type_stack_mark(); \    low_decode_type(data); \    (X)=pop_unfinished_type(); \   } while(0)      static void cleanup_new_program_decode (int *orig_compilation_depth)   { - #if 0 -  ref_push_program (Pike_compiler->new_program); -  /* FIXME: Shouldn't the compilation handler be used here? */ -  SAFE_APPLY_MASTER("unregister",1); -  pop_stack(); - #endif -  +     end_first_pass(0);    compilation_depth = *orig_compilation_depth;   }      static DECLSPEC(noreturn) void decode_error (struct svalue *decoding,    struct svalue *other,    char *msg, ...)    ATTRIBUTE((noreturn,format (printf, 3, 4)));      static DECLSPEC(noreturn) void decode_error (struct svalue *decoding,
pike.git/src/encode.c:2155:    f_backtrace (0);    f_aggregate (2);       free_svalue(& throw_value);    dmalloc_touch_svalue(Pike_sp-1);    throw_value = *--Pike_sp;    throw_severity = THROW_ERROR;    pike_throw();   }    - /* force_decode == 0: A placeholder (object or program) suffices. -  * force_decode == 1: Must have the real object. */ - static void decode_value2(struct decode_data *data, int force_decode) + static void decode_value2(struct decode_data *data)      #ifdef PIKE_DEBUG   #undef decode_value2 - #define decode_value2(X, Y) do { \ -  struct svalue *_=Pike_sp; \ -  decode_value2_(X, Y); \ -  if(Pike_sp!=_+1) \ -  Pike_fatal("decode_value2 failed!\n"); \ -  } while(0) + #define decode_value2(X) do { struct svalue *_=Pike_sp; decode_value2_(X); if(Pike_sp!=_+1) Pike_fatal("decode_value2 failed!\n"); } while(0)   #endif    -  +    {    INT32 what, e, num, numh;    struct svalue entry_id, *tmp2;    struct svalue *delayed_enc_val;      #ifdef ENCODE_DEBUG    data->depth += 2;   #endif       DECODE("decode_value2");
pike.git/src/encode.c:2316:    if(num < 0)    Pike_error("Failed to decode array. (array size is negative)\n");       /* Heruetical */    if(data->ptr + num > data->len)    Pike_error("Failed to decode array. (not enough data)\n");       EDB(2,fprintf(stderr, "%*sDecoding array of size %d to <%d>\n",    data->depth, "", num, entry_id.u.integer));    -  SETUP_DECODE_MEMOBJ(T_ARRAY, array, a, a = allocate_array(num), +  SETUP_DECODE_MEMOBJ(T_ARRAY, array, a, allocate_array(num),    free_svalues(ITEM(a), a->size, a->type_field));       types = 0;    for(e=0;e<num;e++)    { -  decode_value2(data, 0); +  decode_value2(data);    stack_pop_to_no_free (ITEM(a) + e);    types |= 1 << ITEM(a)[e].type;    }    a->type_field = types;    ref_push_array(a);    goto decode_done;    }       case TAG_MAPPING:    {
pike.git/src/encode.c:2344:    if(num<0)    Pike_error("Failed to decode mapping. (mapping size is negative)\n");       /* Heruetical */    if(data->ptr + num > data->len)    Pike_error("Failed to decode mapping. (not enough data)\n");       EDB(2,fprintf(stderr, "%*sDecoding mapping of size %d to <%d>\n",    data->depth, "", num, entry_id.u.integer));    -  SETUP_DECODE_MEMOBJ(T_MAPPING, mapping, m, m = allocate_mapping(num), ; ); +  SETUP_DECODE_MEMOBJ(T_MAPPING, mapping, m, allocate_mapping(num), ; );       for(e=0;e<num;e++)    { -  decode_value2(data, 0); -  decode_value2(data, 0); +  decode_value2(data); +  decode_value2(data);    mapping_insert(m, Pike_sp-2, Pike_sp-1);    pop_n_elems(2);    }    ref_push_mapping(m);    goto decode_done;    }       case TAG_MULTISET:    {    struct multiset *m;
pike.git/src/encode.c:2375:    /* Heruetical */    if(data->ptr + num > data->len)    Pike_error("Failed to decode multiset. (not enough data)\n");       /* NOTE: This code knows stuff about the implementation of multisets...*/       EDB(2,fprintf(stderr, "%*sDecoding multiset of size %d to <%d>\n",    data->depth, "", num, entry_id.u.integer));   #ifdef PIKE_NEW_MULTISETS    SETUP_DECODE_MEMOBJ (T_MULTISET, multiset, m, -  m = allocate_multiset (0, 0, NULL), ;); +  allocate_multiset (0, 0, NULL), ;);    /* FIXME: This array could be avoided by building the multiset directly. */    a = low_allocate_array (num, 0);   #else    SETUP_DECODE_MEMOBJ(T_MULTISET, multiset, m, -  m = allocate_multiset(low_allocate_array(num, 0)), ;); +  allocate_multiset(low_allocate_array(num, 0)), ;);    a=m->ind;   #endif       types = 0;    for(e=0;e<num;e++)    { -  decode_value2(data, 0); +  decode_value2(data);    stack_pop_to_no_free (ITEM(a) + e);    types |= 1 << ITEM(a)[e].type;    }    a->type_field = types;   #ifdef PIKE_NEW_MULTISETS    {    struct multiset *l = mkmultiset (a);    free_array (a);    /* This special case is handled efficiently by merge_multisets. */    merge_multisets (m, l, PIKE_MERGE_DESTR_A | PIKE_ARRAY_OP_ADD);
pike.git/src/encode.c:2409:    }   #else    order_multiset(m);   #endif    ref_push_multiset(m);    goto decode_done;    }       case TAG_OBJECT:    { +  decode_value2(data); +     switch(num)    {    case 0: -  decode_value2(data, 0); -  push_int (!force_decode); -  apply(data->codec,"objectof", 2); +  apply(data->codec,"objectof", 1);    break;       case 1:    {    int fun; -  struct object *o; +     /* decode_value_clone_object does not call __INIT, so    * we want to do that ourselves...    */ -  decode_value2(data, 1); -  o = decode_value_clone_object(Pike_sp-1); +  struct object *o=decode_value_clone_object(Pike_sp-1);       if (!o) {    if (data->pickyness)    decode_error (NULL, Pike_sp - 1,    "Failed to decode program for object. Got: ");    EDB(1,fprintf(stderr, "%*sDecoded a failed object to <%d>: ",    data->depth, "", entry_id.u.integer);    print_svalue(stderr, Pike_sp-1);    fputc('\n', stderr);); -  decode_value2(data, 0); +  decode_value2(data);    pop_n_elems(2);    push_undefined();    break;    }       debug_malloc_touch(o);    pop_stack();    push_object(o);       if(o->prog)
pike.git/src/encode.c:2467:    data->unfinished_objects=ol;    }    }       EDB(2,fprintf(stderr, "%*sDecoded an object to <%d>: ",    data->depth, "", entry_id.u.integer);    print_svalue(stderr, Pike_sp-1);    fputc('\n', stderr););       ref_push_object(o); -  decode_value2(data, 0); +  decode_value2(data); +  if(!data->codec) +  decode_error(Pike_sp - 1, NULL, +  "Cannot decode object without codec.\n");       fun = find_identifier("decode_object", data->codec->prog);    if (fun < 0)    decode_error(Pike_sp - 1, NULL,    "Cannot decode objects without a "    "\"decode_object\" function in the codec.\n");    apply_low(data->codec,fun,2);    pop_stack();    }       break;      #ifdef AUTO_BIGNUM    /* It is possible that we should do this even without    * AUTO_BIGNUM /Hubbe    * However, that requires that some of the bignum functions    * are always available...    */    case 2:    { -  decode_value2(data, 0); +     check_stack(2);    /* 256 would be better, but then negative numbers    * doesn't work... /Hubbe    */    push_int(36);    convert_stack_top_with_base_to_bignum();    break;    }      #endif    case 3: -  decode_value2(data, 0); +     pop_stack(); -  decode_value2(data, 0); +  decode_value2(data);    break;       default:    Pike_error("Object coding not compatible.\n");    break;    }       if(Pike_sp[-1].type != T_OBJECT && data->pickyness)    decode_error(NULL, Pike_sp - 1, "Failed to decode object. Got: ");       break;    }       case TAG_FUNCTION: -  +  decode_value2(data); +     switch(num)    {    case 0: -  decode_value2(data, 0); -  push_int (0); -  apply(data->codec,"functionof", 2); +  apply(data->codec,"functionof", 1);    break;       case 1: {    struct program *p; -  decode_value2(data, 1); +     if(Pike_sp[-1].type != T_OBJECT && data->pickyness)    decode_error(NULL, Pike_sp - 1,    "Failed to decode function object. Got: ");    -  decode_value2(data, 0); +  decode_value2(data);    if(Pike_sp[-1].type != T_STRING && data->pickyness)    decode_error(NULL, Pike_sp - 1,    "Failed to decode function identifier. Got: ");       if (Pike_sp[-2].type == T_OBJECT &&    Pike_sp[-1].type == T_STRING &&    (p = Pike_sp[-2].u.object->prog)) {    int f = find_shared_string_identifier(Pike_sp[-1].u.string, p);    if (f >= 0) {    struct svalue func;
pike.git/src/encode.c:2585:    case TAG_PROGRAM:    EDB(3,    fprintf(stderr, "%*s TAG_PROGRAM(%d)\n",    data->depth, "", num));    switch(num)    {    case 0:    {    struct program *p;    -  decode_value2(data, 0); -  push_int (!force_decode); -  apply(data->codec,"programof", 2); +  decode_value2(data); +  apply(data->codec,"programof", 1);    -  if (Pike_sp[-1].type == T_PROGRAM || Pike_sp[-1].type == T_FUNCTION) +     p = program_from_svalue(Pike_sp-1); -  else -  p = 0; +        if (!p) {    if(data->pickyness)    decode_error(NULL, Pike_sp - 1,    "Failed to decode program. Got: ");    pop_stack();    push_undefined();    break;    }       add_ref(p);    pop_stack();    push_program(p); -  -  if (p->flags == PROGRAM_VIRGIN) { -  EDB (2, -  fprintf (stderr, "%*sdecode: got program embryo to finish later: ", -  data->depth, ""); -  print_svalue (stderr, Pike_sp - 1); -  fputc ('\n', stderr);); -  data->delayed = append_array (data->delayed, Pike_sp - 1); -  } -  +     break;    }       case 1: /* Old-style encoding. */    {    int d, in;    size_t size=0;    char *dat=0;    struct program *p;    struct object *placeholder=0; -  ONERROR err1, err2, err3; +  ONERROR err1, err2, err3, err4;      #ifdef _REENTRANT    ONERROR err;    low_init_threads_disable();    SET_ONERROR(err, do_enable_threads, 0);   #endif       fprintf (stderr, "Warning: Using old-style encoding\n");       EDB(2,fprintf(stderr, "%*sDecoding a program to <%d>: ",    data->depth, "", entry_id.u.integer);    print_svalue(stderr, &entry_id);    fputc('\n', stderr););    -  SETUP_DECODE_MEMOBJ(T_PROGRAM, program, p, -  { -  if (data->target_prog) { -  add_ref (p = data->target_prog); -  data->target_prog = NULL; -  } -  else -  p = low_allocate_program(); -  }, -  ;); +  SETUP_DECODE_MEMOBJ(T_PROGRAM, program, p, low_allocate_program(),;);       SET_ONERROR(err3, zap_unfinished_program, p);    - #if 0 +     if(data->pass == 1)    {    if(! data->supporter.prog)    data->supporter.prog = p;       debug_malloc_touch(p);    ref_push_program(p);    apply(data->codec, "__register_new_program", 1);       /* return a placeholder */
pike.git/src/encode.c:2681: Inside #if 0
   Pike_sp--;    }    else if (Pike_sp[-1].type != T_INT ||    Pike_sp[-1].u.integer)    Pike_error ("Expected placeholder object or zero "    "from __register_new_program.\n");    else {    pop_stack();    }    } - #endif +     -  placeholder = data->placeholder; -  data->placeholder = NULL; +  if(placeholder) +  SET_ONERROR(err4, zap_placeholder, placeholder);    -  decode_value2(data, 0); +  decode_value2(data);    f_version(0);    if(!is_eq(Pike_sp-1,Pike_sp-2))    Pike_error("Cannot decode programs encoded with other pike version.\n");    pop_n_elems(2);       data->pickyness++;       debug_malloc_touch(p);    decode_number(p->flags,data);   
pike.git/src/encode.c:2717:    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, 0); +  decode_value2(data);    switch(Pike_sp[-1].type)    {    case T_INT:    p->parent=0;    break;    case T_PROGRAM:    p->parent=Pike_sp[-1].u.program;    break;    case T_FUNCTION:    p->parent=program_from_svalue(Pike_sp-1);
pike.git/src/encode.c:2877:       if(placeholder && data->pass==1)    {    if(placeholder->prog != null_program)    {    debug_malloc_touch(placeholder);    ref_push_program (p);    decode_error(Pike_sp - 1, NULL,    "Placeholder is no longer a __null_program clone.\n");    }else{ -  Pike_fatal ("foo\n"); +     free_program(placeholder->prog);    add_ref(placeholder->prog = p);    debug_malloc_touch(placeholder);    }    }       debug_malloc_touch(p);       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);    decode_number(p->inherits[d].parent_offset,data);    decode_number(p->inherits[d].parent_identifier,data);    decode_number(p->inherits[d].storage_offset,data);    -  decode_value2(data, 0); +  decode_value2(data);    if(d==0)    {    if(Pike_sp[-1].type != T_PROGRAM ||    Pike_sp[-1].u.program != p) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,    "Program decode of self inherit failed. Got: ");    }    sub_ref(p);    }
pike.git/src/encode.c:3016:    p->identifier_index +    p->num_identifier_index - 1,    p);       debug_malloc_touch(dat);    debug_malloc_touch(p);       p->flags |= PROGRAM_PASS_1_DONE | PROGRAM_FIXED;    for(d=0;d<p->num_constants;d++)    { -  decode_value2(data, 0); +  decode_value2(data);    if(data->pass > 1)    {    assign_svalue(& p->constants[d].sval , Pike_sp -1 );    pop_stack();    }else{    dmalloc_touch_svalue(Pike_sp-1);    p->constants[d].sval=*--Pike_sp;    }    dmalloc_touch_svalue(Pike_sp);    getdata3(p->constants[d].name);
pike.git/src/encode.c:3054:    } 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
pike.git/src/encode.c:3165:    }      #ifdef _REENTRANT    UNSET_ONERROR(err);    exit_threads_disable(NULL);   #endif    goto decode_done;    }       case 2: -  decode_value2(data, 1); -  decode_value2(data, 0); +  decode_value2(data); +  decode_value2(data);    if(Pike_sp[-2].type==T_INT)    {    pop_stack();    }else{    f_arrow(2);    }    if(Pike_sp[-1].type != T_PROGRAM && data->pickyness)    decode_error(NULL, Pike_sp - 1, "Failed to decode program. Got: ");    break;       case 3: -  decode_value2(data, 0); +  decode_value2(data);    if ((Pike_sp[-1].type == T_INT) &&    (Pike_sp[-1].u.integer < PROG_DYNAMIC_ID_START) &&    (Pike_sp[-1].u.integer > 0)) {    struct program *p = id_to_program(Pike_sp[-1].u.integer);    if (!p) {    Pike_error("Failed to get program from ID %"PRINTPIKEINT"d\n",    Pike_sp[-1].u.integer);    }    pop_stack();    ref_push_program(p);    } else {    decode_error(NULL, Pike_sp - 1,    "Failed to decode program by ID. Expected integer, got: ");    }    break;    -  case 5: /* Forward reference for new-style encoding. */ -  push_program (low_allocate_program()); +  case 5: { /* Forward reference for new-style encoding. */ +  struct program *p = low_allocate_program(); +  +  push_program (p);    EDB(2,    fprintf (stderr, "%*sInited an embryo for a delay encoded program "    "to <%d>: ",    data->depth, "", entry_id.u.integer);    print_svalue (stderr, Pike_sp - 1);    fputc ('\n', stderr);); -  +  + #if 0 +  /* Is this necessary? In that case, how do we pass an +  * adequate context to __register_new_program so that it +  * knows which program is being decoded? */ +  if (data->codec) { +  ref_push_program (p); +  apply (data->codec, "__register_new_program", 1); +  +  /* Returns a placeholder. */ +  if (Pike_sp[-1].type == T_OBJECT) { +  if (Pike_sp[-1].u.object->prog != null_program) +  Pike_error ("Placeholder object is not a null_program clone.\n"); +  } +  else if (Pike_sp[-1].type != T_INT || +  Pike_sp[-1].u.integer) +  Pike_error ("Expected placeholder object or zero " +  "from __register_new_program.\n"); +  pop_stack(); +  } + #endif +     break; -  +  }       case 4: /* New-style encoding. */    {    struct program *p; -  struct object *placeholder = NULL; +     ONERROR err;    int orig_compilation_depth;    int byteorder;    int bytecode_method;    int entry_type;    INT16 id_flags;    INT16 p_flags;   #define FOO(NUMTYPE,Y,ARGTYPE,NAME) \    NUMTYPE PIKE_CONCAT(local_num_, NAME) = 0;   #include "program_areas.h"
pike.git/src/encode.c:3262:    data->depth, "");    print_svalue(stderr, delayed_enc_val);    fputc('\n', stderr););    if (delayed_enc_val->type != T_PROGRAM ||    delayed_enc_val->u.program->flags != PROGRAM_VIRGIN) {    decode_error (NULL, delayed_enc_val,    "Didn't get program embryo "    "for delay encoded program <%d>: ", entry_id.u.integer);    }    /* No new ref here; low_start_new_program will add one for -  * Pike_compiler->new_program and we want to ride on that -  * one just like when it's created there. */ +  * Pike_compiler->new_program and we want ride on that one +  * just like when it's created there. */    p = delayed_enc_val->u.program;    } -  else if (data->target_prog) { -  p = data->target_prog; -  debug_malloc_touch (p); -  data->target_prog = NULL; -  } +     else    p = NULL;       /* Start the new program. */    orig_compilation_depth = compilation_depth;    compilation_depth = -1;    low_start_new_program(p, 1, NULL, 0, NULL);    p = Pike_compiler->new_program;       p->flags = p_flags;
pike.git/src/encode.c:3302:    prog.u.program=p;    EDB(2,fprintf(stderr, "%*sDecoding a program to <%d>: ",    data->depth, "", entry_id.u.integer);    print_svalue(stderr, &prog);    fputc('\n', stderr););    mapping_insert(data->decoded, &entry_id, &prog);    }       debug_malloc_touch(p);    - #if 0 -  ref_push_program (p); -  apply (data->codec, "__register_new_program", 1); -  -  /* Returns a placeholder. */ -  if (Pike_sp[-1].type == T_OBJECT) { -  if (Pike_sp[-1].u.object->prog != null_program) -  Pike_error ("Placeholder object is not a __null_program clone.\n"); -  placeholder = Pike_sp[-1].u.object; -  dmalloc_touch_svalue (Pike_sp - 1); -  Pike_sp--; -  SET_ONERROR (placeholder_uwp, zap_placeholder, placeholder); -  } -  else { -  if (Pike_sp[-1].type != T_INT || -  Pike_sp[-1].u.integer) -  Pike_error ("Expected placeholder object or zero " -  "from __register_new_program.\n"); -  pop_stack(); -  } - #endif -  -  placeholder = data->placeholder; -  data->placeholder = NULL; -  +     /* Check the version. */ -  decode_value2(data, 0); +  decode_value2(data);    f_version(0);    if(!is_eq(Pike_sp-1,Pike_sp-2))    Pike_error("Cannot decode programs encoded with other pike version.\n");    pop_n_elems(2);       debug_malloc_touch(p);       data->pickyness++;       /* parent */ -  decode_value2(data, 0); +  decode_value2(data);    if (Pike_sp[-1].type == T_PROGRAM) {    p->parent = Pike_sp[-1].u.program;    } else if ((Pike_sp[-1].type == T_INT) &&    (!Pike_sp[-1].u.integer)) {    p->parent = NULL;    } else {    Pike_error("Bad type for parent program (%s)\n",    get_name_of_type(Pike_sp[-1].type));    }    dmalloc_touch_svalue(Pike_sp-1);
pike.git/src/encode.c:3413:    push_program (p);    print_svalue (stderr, --Pike_sp);    fputc('\n', stderr));       /* identifier_index & variable_index are created by    * fixate_program() and optimize_program().    */       /* Decode strings */    for (e=0; e<local_num_strings; e++) { -  decode_value2(data, 0); +  decode_value2(data);    if (Pike_sp[-1].type != T_STRING) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,    "Nonstrings in string table: ");    }    add_to_strings(Pike_sp[-1].u.string);    dmalloc_touch_svalue(Pike_sp-1);    Pike_sp--;    }   
pike.git/src/encode.c:3493:    p->identifier_references[no] = ref;    }    }    break;       case ID_ENTRY_VARIABLE:    {    int no, n;       /* name */ -  decode_value2(data, 0); +  decode_value2(data);    if (Pike_sp[-1].type != T_STRING) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,    "Bad variable name (not a string): ");    }       /* type */ -  decode_value2(data, 0); +  decode_value2(data);    if (Pike_sp[-1].type != T_TYPE) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,    "Bad variable type (not a type): ");    }       /* Expected identifier offset */    decode_number(no, data);       EDB(5,
pike.git/src/encode.c:3544:    break;    case ID_ENTRY_FUNCTION:    {    union idptr func;    unsigned INT8 func_flags;    unsigned INT16 opt_flags;    int no;    int n;       /* name */ -  decode_value2(data, 0); +  decode_value2(data);    if (Pike_sp[-1].type != T_STRING) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,    "Bad function name (not a string): ");    }       /* type */ -  decode_value2(data, 0); +  decode_value2(data);    if (Pike_sp[-1].type != T_TYPE) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,    "Bad function type (not a type): ");    }       /* func_flags (aka identifier_flags) */    decode_number(func_flags, data);       /* func */
pike.git/src/encode.c:3620:    }    break;    case ID_ENTRY_CONSTANT:    {    struct identifier id;    struct reference ref;    int no;    int n;       /* name */ -  decode_value2(data, 0); +  decode_value2(data);    if (Pike_sp[-1].type != T_STRING) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,    "Bad constant name (not a string): ");    }    id.name = Pike_sp[-1].u.string;       /* identifier_flags */    id.identifier_flags = IDENTIFIER_CONSTANT;       /* offset */    decode_number(id.func.offset, data);       /* FIXME:    * Verify validity of func.offset    */       /* type */ -  decode_value2(data, 0); +  decode_value2(data);    if (Pike_sp[-1].type != T_TYPE) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,    "Bad constant type (not a type): ");    }    id.type = Pike_sp[-1].u.type;       /* run_time_type */    decode_number(id.run_time_type, data);   
pike.git/src/encode.c:3719:       decode_number(no, data);    if (no !=    Pike_compiler->new_program->num_identifier_references) {    ref_push_program (p);    decode_error(Pike_sp - 1, NULL,    "Bad inherit identifier offset: %d\n", no);    }       /* name */ -  decode_value2(data, 0); +  decode_value2(data);    if (Pike_sp[-1].type == T_STRING) {    name = Pike_sp[-1].u.string;    } else if ((Pike_sp[-1].type != T_INT) ||    Pike_sp[-1].u.integer) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,    "Bad inherit name (not a string): ");    }       /* prog */ -  decode_value2(data, 1); +  decode_value2(data);    if (Pike_sp[-1].type != T_PROGRAM) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,    "Bad inherit: Expected program, got ");    }    prog = Pike_sp[-1].u.program;    if (prog == placeholder_program) {    ref_push_program (p);    decode_error (Pike_sp - 1, NULL,    "Trying to inherit placeholder program "    "(resolver or codec problem).\n");    }    if(!(prog->flags & (PROGRAM_FINISHED | PROGRAM_PASS_1_DONE))) {    ref_push_program (p);    decode_error (Pike_sp - 1, Pike_sp - 2,    "Cannot inherit a program which is not "    "fully compiled yet (resolver or codec problem):\n");    }       /* parent */ -  decode_value2(data, 0); +  decode_value2(data);    if (Pike_sp[-1].type == T_OBJECT) {    parent = Pike_sp[-1].u.object;    } else if ((Pike_sp[-1].type != T_INT) ||    Pike_sp[-1].u.integer) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,    "Bad inherit: Parent isn't an object: ");    }       /* parent_identifier */
pike.git/src/encode.c:3803:    default:    Pike_error("Unsupported id entry type: %d\n", entry_type);    }    decode_number(entry_type, data);    }      #ifdef ENCODE_DEBUG    data->depth-=2;   #endif    -  push_program(p); /* "Take" the ref from Pike_compiler->new_program. */ +     UNSET_ONERROR(err);       /* De-kludge to get end_first_pass() to free the program. */    Pike_compiler->num_parse_error--;       p->flags |= PROGRAM_PASS_1_DONE;       /* Fixate & optimize    *    * lfuns and identifier_index    */ -  +  ref_push_program (p);    if (!(p = end_first_pass(2))) { -  decode_error (Pike_sp - 1, NULL, -  "Failed to decode program.\n"); +  decode_error(Pike_sp - 1, NULL, "Failed to decode program.\n");    } -  +  pop_stack();    compilation_depth = orig_compilation_depth; -  +  push_program(p);       EDB(5, dump_program_tables(p, data->depth));   #ifdef PIKE_DEBUG    check_program (p);   #endif       /* Verify... */   #define FOO(NUMTYPE,TYPE,ARGTYPE,NAME) \    if (PIKE_CONCAT(local_num_, NAME) != p->PIKE_CONCAT(num_,NAME)) { \    ref_push_program (p); \
pike.git/src/encode.c:3844:    }   #include "program_areas.h"       /* Decode the actual constants    *    * This must be done after the program has been ended.    */    for (e=0; e<local_num_constants; e++) {    struct program_constant *constant = p->constants+e;    /* value */ -  decode_value2(data, 0); +  decode_value2(data);    /* name */ -  decode_value2(data, 0); +  decode_value2(data);    if (Pike_sp[-1].type == T_STRING) {    constant->name = Pike_sp[-1].u.string;    } else if ((Pike_sp[-1].type == T_INT) &&    !Pike_sp[-1].u.integer) {    constant->name = NULL;    } else {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,    "Name of constant is not a string: ");    }
pike.git/src/encode.c:3868:    dmalloc_touch_svalue(Pike_sp-1);    dmalloc_touch_svalue(Pike_sp-2);    Pike_sp -= 2;    }       data->pickyness--;       /* The program should be consistent now. */    p->flags &= ~PROGRAM_AVOID_CHECK;    -  /* Make a real object of the placeholder. */ -  if (placeholder) { -  if(placeholder->prog != null_program) -  { -  debug_malloc_touch(placeholder); -  ref_push_program (p); -  decode_error(Pike_sp - 1, NULL, -  "Placeholder is no longer a __null_program clone.\n"); -  } -  -  free_program(placeholder->prog); -  add_ref(placeholder->prog = p); -  debug_malloc_touch(placeholder); -  -  if(placeholder->storage) { -  ref_push_object (placeholder); -  decode_error(Pike_sp - 2, Pike_sp - 1, -  "Placeholder already has storage: "); -  } -  -  placeholder->storage=p->storage_needed ? -  (char *)xalloc(p->storage_needed) : -  (char *)0; -  call_c_initializers(placeholder); -  init_placeholder (placeholder); -  } -  +     EDB(5, fprintf(stderr, "%*sProgram flags: 0x%04x\n",    data->depth, "", p->flags));      #ifdef ENCODE_DEBUG    data->depth -= 2;   #endif    goto decode_done;    }       default:    Pike_error("Cannot decode program encoding type %d\n",num);    }    break;       default:    Pike_error("Failed to restore string. (Illegal type)\n");    }    -  if (data->target_prog || data->placeholder) -  Pike_error ("Failed to decode a program to use for the target or placeholder.\n"); -  +     mapping_insert(data->decoded, &entry_id, Pike_sp-1);      decode_done:;    EDB(2,fprintf(stderr, "%*sDecoded to <%d>: ", data->depth, "", entry_id.u.integer);    print_svalue(stderr, Pike_sp-1);    fputc('\n', stderr););   #ifdef ENCODE_DEBUG    data->depth -= 2;   #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;    }   }      
pike.git/src/encode.c:3984:    call_dependants(& data->supporter, 1);       if(delay)    {    debug_malloc_touch(data);    /* We have been delayed */    return;    }       free_mapping(data->decoded); -  free_array (data->delayed); +       #ifdef PIKE_DEBUG    if(data->unfinished_programs)    Pike_fatal("We have unfinished programs left in decode()!\n");    if(data->unfinished_objects)    Pike_fatal("We have unfinished objects left in decode()!\n");   #endif       while(data->unfinished_programs)    {
pike.git/src/encode.c:4021:   }      static void low_do_decode (struct decode_data *data)   {    int e;    struct keypair *k;    ONERROR err;    SET_ONERROR(err, free_decode_data, data);    current_decode = data;    -  decode_value2(data, 0); +  decode_value2(data);       while (data->ptr < data->len) { -  decode_value2 (data, 0); +  decode_value2 (data);    pop_stack();    }      #ifdef PIKE_DEBUG    NEW_MAPPING_LOOP (data->decoded->data) {    if (k->val.type == T_PROGRAM &&    !(k->val.u.program->flags & PROGRAM_FINISHED)) {    decode_error (NULL, &k->val,    "Got unfinished program <%"PRINTPIKEINT"d> after decode: ",    k->ind.u.integer);    }    }   #endif    -  for (e = 0; e < data->delayed->size; e++) { -  struct program *p; - #ifdef PIKE_DEBUG -  if (ITEM (data->delayed)[e].type != T_PROGRAM) -  Pike_fatal ("Invalid value in data->delayed.\n"); - #endif -  p = ITEM (data->delayed)[e].u.program; -  if (p->flags == PROGRAM_VIRGIN) { -  ref_push_program (p); -  apply (data->codec, "finish_program", 1); -  if (p->flags == PROGRAM_VIRGIN) { -  ref_push_program (p); -  decode_error (NULL, Pike_sp - 1, "finish_program() failed to finish "); -  } -  pop_stack(); -  } -  } -  +     UNSET_ONERROR(err);    free_decode_data(data);   }      /* Run pass2 */   int re_decode(struct decode_data *data, int ignored)   {    data->next = current_decode;    low_do_decode (data);    return 1;   }      static INT32 my_decode(struct pike_string *tmp, -  struct object *codec, -  struct program *target_prog, -  struct object *placeholder +  struct object *codec   #ifdef ENCODE_DEBUG    , int debug   #endif    )   {    struct decode_data *data;       /* Attempt to avoid infinite recursion on circular structures. */    for (data = current_decode; data; data=data->next) {    if (data->raw == tmp && data->codec == codec
pike.git/src/encode.c:4111:    }    }       data=ALLOC_STRUCT(decode_data);    data->counter.type=T_INT;    data->counter.u.integer=COUNTER_START;    data->data=(unsigned char *)tmp->str;    data->len=tmp->len;    data->ptr=0;    data->codec=codec; -  data->target_prog = target_prog; -  data->placeholder = placeholder; +     data->pickyness=0;    data->pass=1;    data->unfinished_programs=0;    data->unfinished_objects=0;    data->raw = tmp;    data->next = current_decode;   #ifdef PIKE_THREADS    data->thread_state = Pike_interpreter.thread_state;   #endif   #ifdef ENCODE_DEBUG
pike.git/src/encode.c:4139:    GETC() != 182 ||    GETC() != 'k' ||    GETC() != 'e' ||    GETC() != '0')    {    free( (char *) data);    return 0;    }       data->decoded=allocate_mapping(128); -  data->delayed = allocate_array (0); +        init_supporter(& data->supporter,    (supporter_callback *) re_decode,    (void *)data);       low_do_decode (data);       return 1;   }   
pike.git/src/encode.c:4221:    *! Returns @[UNDEFINED] on failure.    *!    *! @note    *! @[encode_value()] has fallbacks for some classes of objects,    *! functions and programs.    *!    *! @seealso    *! @[objectof()], @[functionof()], @[objectof()]    */    - /*! @decl object objectof(string data, int delay) -  *! @decl function functionof(string data, int delay) -  *! @decl program programof(string data, int delay) + /*! @decl object objectof(string data)    *! -  *! Get the object, function and program, respectively, represented -  *! by @[data]. +  *! Decode object encoded in @[data].    *!    *! This function is called by @[decode_value()] when it encounters -  *! values from @[nameof()] in the encoded data. +  *! encoded objects.    *!    *! @param data -  *! Encoding of some object, function or program as specified by -  *! @[nameof()]. +  *! Encoding of some object as specified by @[nameof()].    *! -  *! @param delay -  *! This parameter is used to handle circular references between the -  *! values decoded by several different @[decode_value] sessions. In -  *! the simple case when the decoding environment is complete, it's -  *! safe to ignore it. +  *! @param minor +  *! Minor version.    *! -  *! If compilation or decoding is needed to retrieve the object or -  *! program, then try to delay it and return a placeholder object -  *! (@[__null_program] clone) or empty program (@[__empty_program] -  *! return value) instead. If an empty program is returned then the -  *! codec will get a call to @[finish] later on with the returned -  *! value and it should then be filled out to the real program. -  *! (Placeholder objects get no calls since they are converted -  *! automatically when the corresponding program is finished.) +  *! @returns +  *! Returns the decoded object.    *! -  *! This delay process isn't applicable for functions since they -  *! always involve an indexing, but the parameter is passed anyway -  *! for consistency. +  *! @seealso +  *! @[functionof()], @[programof()] +  */ +  + /*! @decl function functionof(string data)    *! -  +  *! Decode function encoded in @[data]. +  *! +  *! This function is called by @[decode_value()] when it encounters +  *! encoded functions. +  *! +  *! @param data +  *! Encoding of some function as specified by @[nameof()]. +  *! +  *! @param minor +  *! Minor version. +  *!    *! @returns -  *! Returns the decoded object. +  *! Returns the decoded function. +  *! +  *! @seealso +  *! @[objectof()], @[programof()]    */    - /*! @decl void finish (program target) + /*! @decl program programof(string data)    *! -  *! FIXME +  *! Decode program encoded in @[data]. +  *! +  *! This function is called by @[decode_value()] when it encounters +  *! encoded programs. +  *! +  *! @param data +  *! Encoding of some program as specified by @[nameof()]. +  *! +  *! @param minor +  *! Minor version. +  *! +  *! @returns +  *! Returns the decoded program. +  *! +  *! @seealso +  *! @[functionof()], @[objectof()]    */    -  + /*! @decl object __register_new_program(program p) +  *! +  *! Called by @[decode_value()] to register the program that is +  *! being decoded. Might get called repeatedly with several other +  *! programs that are being decoded recursively. The only safe +  *! assumption is that when the top level thing being decoded is a +  *! program, then the first call will be with the unfinished embryo +  *! that will later become that program. +  *! +  *! @returns +  *! Returns either zero or a placeholder object. A placeholder +  *! object must be a clone of @[__null_program]. When the program is +  *! finished, the placeholder object will be converted to a clone of +  *! it. This is used for pike module objects. +  */ +    /*! @endclass    */      static void rec_restore_value(char **v, ptrdiff_t *l)   {    ptrdiff_t t, i;       i = extract_int(v,l);    t = extract_int(v,l);    switch(i)
pike.git/src/encode.c:4329:    rec_restore_value(v,l);    }    f_aggregate_mapping(DO_NOT_WARN(t*2)); /* FIXME: Unbounded stack consumption. */    return;       case TAG_OBJECT:    if(t<0) Pike_error("Format error: length of object is negative.\n");    if(*l < t) Pike_error("Format error: string to short\n");    push_string(make_shared_binary_string(*v, t));    (*l) -= t; (*v) += t; -  push_int (0); -  APPLY_MASTER("objectof", 2); +  APPLY_MASTER("objectof", 1);    return;       case TAG_FUNCTION:    if(t<0) Pike_error("Format error: length of function is negative.\n");    if(*l < t) Pike_error("Format error: string to short\n");    push_string(make_shared_binary_string(*v, t));    (*l) -= t; (*v) += t; -  push_int (0); -  APPLY_MASTER("functionof", 2); +  APPLY_MASTER("functionof", 1);    return;       case TAG_PROGRAM:    if(t<0) Pike_error("Format error: length of program is negative.\n");    if(*l < t) Pike_error("Format error: string to short\n");    push_string(make_shared_binary_string(*v, t));    (*l) -= t; (*v) += t; -  push_int (0); -  APPLY_MASTER("programof", 2); +  APPLY_MASTER("programof", 1);    return;       default:    Pike_error("Format error: Unknown type tag %ld:%ld\n",    PTRDIFF_T_TO_LONG(i), PTRDIFF_T_TO_LONG(t));    }   }    - /*! @decl mixed decode_value(string coded_value, void|Codec codec, @ -  *! void|program target, void|object placeholder) + /*! @decl mixed decode_value(string coded_value, void|Codec codec)    *!    *! Decode a value from the string @[coded_value].    *!    *! This function takes a string created with @[encode_value()] or    *! @[encode_value_canonic()] and converts it back to the value that was    *! coded.    *!    *! If @[codec] is specified, it's used as the codec for the decode.    *! If no codec is specified, the current master object will be used.    *! -  *! @[target] and @[placeholder] are used to deal with cyclic -  *! references between programs and modules that are being decoded; -  *! users normally don't need to bother with them. If @[target] is -  *! given, it's extended with the decoded program, so that @[target] -  *! will become it afterwards. @[target] must be a newly created value -  *! from @[__empty_program]. If @[placeholder] is given, it must be a -  *! new created instance of @[__null_program] and it will become an -  *! instance of the program decoded to @[target]. -  *! +     *! @seealso    *! @[encode_value()], @[encode_value_canonic()]    */   void f_decode_value(INT32 args)   {    struct pike_string *s; -  struct object *codec, *placeholder = NULL; -  struct program *target_prog = NULL; +  struct object *codec;      #ifdef ENCODE_DEBUG    int debug = 0;   #endif /* ENCODE_DEBUG */       check_all_args("decode_value", args,    BIT_STRING,    BIT_VOID | BIT_OBJECT | BIT_ZERO, -  BIT_VOID | BIT_PROGRAM | BIT_ZERO, -  BIT_VOID | BIT_OBJECT | BIT_ZERO, +    #ifdef ENCODE_DEBUG    /* This argument is only an internal debug helper.    * It's intentionally not part of the function    * prototype, to keep the argument position free for    * other uses in the future. */    BIT_VOID | BIT_INT,   #endif    0);       s = Pike_sp[-args].u.string;       switch (args) {    default:   #ifdef ENCODE_DEBUG    debug = Pike_sp[4-args].u.integer; -  case 4: - #endif -  if (Pike_sp[3-args].type == T_OBJECT) { -  placeholder = Pike_sp[3-args].u.object; -  if(placeholder->prog != null_program) -  SIMPLE_ARG_ERROR ("decode_value", 4, "Not a __null_program clone.\n"); -  debug_malloc_touch (placeholder); -  } +     /* Fall through. */ -  case 3: -  if (Pike_sp[2-args].type == T_PROGRAM) { -  target_prog = Pike_sp[2-args].u.program; -  if (target_prog->flags != PROGRAM_VIRGIN) -  SIMPLE_ARG_ERROR ("decode_value", 3, "Not an empty program.\n"); -  } -  /* Fall through. */ +     case 2: -  + #endif    if (Pike_sp[1-args].type == T_OBJECT) {    codec = Pike_sp[1-args].u.object;    break;    }    /* Fall through. */    case 1:    codec = get_master();    if (!codec) {    /* Use a dummy if there's no master around yet, to avoid checks. */    push_object (clone_object (null_program, 0));    args++;    codec = Pike_sp[-1].u.object;    }    }    -  if(!my_decode(s, codec, target_prog, placeholder +  if(!my_decode(s, codec   #ifdef ENCODE_DEBUG    , debug   #endif    ))    {    char *v=s->str;    ptrdiff_t l=s->len;    rec_restore_value(&v, &l);    }    assign_svalue(Pike_sp-args-1, Pike_sp-1);    pop_n_elems(args);   }