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.186 2003/06/11 19:59:54 mast Exp $ + || $Id: encode.c,v 1.187 2003/06/12 09:31:12 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.186 2003/06/11 19:59:54 mast Exp $"); + RCSID("$Id: encode.c,v 1.187 2003/06/12 09:31:12 mast Exp $");    - /* #define ENCODE_DEBUG */ + #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)   #ifndef PIKE_DEBUG   #error ENCODE_DEBUG requires PIKE_DEBUG
pike.git/src/encode.c:93:   #define TAG_INT 8   #define TAG_TYPE 9 /* Not supported yet */      #define TAG_DELAYED 14 /* Note: Coincides with T_ZERO. */   #define TAG_AGAIN 15   #define TAG_MASK 15   #define TAG_NEG 16   #define TAG_SMALL 32   #define SIZE_SHIFT 6   #define MAX_SMALL (1<<(8-SIZE_SHIFT)) - #define COUNTER_START -4 + #define COUNTER_START (-MAX_SMALL)      /* Entries used to encode the identifier_references table. */   #define ID_ENTRY_RAW -2   #define ID_ENTRY_EOT -1   #define ID_ENTRY_VARIABLE 0   #define ID_ENTRY_FUNCTION 1   #define ID_ENTRY_CONSTANT 2   #define ID_ENTRY_INHERIT 3      struct encode_data
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 */ -  encode_value2(&p->constants[d].sval, data, 0); +  /* 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);       /* 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:1730:   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); + static void decode_value2(struct decode_data *data, int force_decode);      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:2003:    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); +  decode_value2(data, 0);       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); +  decode_value2(data, 0);    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:2057:    }    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; \ -  tmp.u.U=VAR=ALLOCATE; \ +  {ALLOCATE;} \ +  tmp.u.U=VAR; \    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:2153:    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();   }    - static void decode_value2(struct decode_data *data) + /* 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)      #ifdef PIKE_DEBUG   #undef decode_value2 - #define decode_value2(X) do { struct svalue *_=Pike_sp; decode_value2_(X); if(Pike_sp!=_+1) Pike_fatal("decode_value2 failed!\n"); } while(0) + #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)   #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:2308:    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, allocate_array(num), +  SETUP_DECODE_MEMOBJ(T_ARRAY, array, a, a = allocate_array(num),    free_svalues(ITEM(a), a->size, a->type_field));       types = 0;    for(e=0;e<num;e++)    { -  decode_value2(data); +  decode_value2(data, 0);    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:2336:    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, allocate_mapping(num), ; ); +  SETUP_DECODE_MEMOBJ(T_MAPPING, mapping, m, m = allocate_mapping(num), ; );       for(e=0;e<num;e++)    { -  decode_value2(data); -  decode_value2(data); +  decode_value2(data, 0); +  decode_value2(data, 0);    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:2367:    /* 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, -  allocate_multiset (0, 0, NULL), ;); +  m = 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, -  allocate_multiset(low_allocate_array(num, 0)), ;); +  m = allocate_multiset(low_allocate_array(num, 0)), ;);    a=m->ind;   #endif       types = 0;    for(e=0;e<num;e++)    { -  decode_value2(data); +  decode_value2(data, 0);    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:2401:    }   #else    order_multiset(m);   #endif    ref_push_multiset(m);    goto decode_done;    }       case TAG_OBJECT:    { -  decode_value2(data); -  +     switch(num)    {    case 0: -  apply(data->codec,"objectof", 1); +  decode_value2(data, 0); +  push_int (!force_decode); +  apply(data->codec,"objectof", 2);    break;       case 1:    {    int fun; -  +  struct object *o;    /* decode_value_clone_object does not call __INIT, so    * we want to do that ourselves...    */ -  struct object *o=decode_value_clone_object(Pike_sp-1); +  decode_value2(data, 1); +  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); +  decode_value2(data, 0);    pop_n_elems(2);    push_undefined();    break;    }       debug_malloc_touch(o);    pop_stack();    push_object(o);       if(o->prog)
pike.git/src/encode.c:2457:    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); -  if(!data->codec) -  decode_error(Pike_sp - 1, NULL, -  "Cannot decode object without codec.\n"); +  decode_value2(data, 0);       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); +  decode_value2(data, 0);    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: -  apply(data->codec,"functionof", 1); +  decode_value2(data, 0); +  push_int (0); +  apply(data->codec,"functionof", 2);    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); +  decode_value2(data, 0);    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:2575:    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); -  apply(data->codec,"programof", 1); +  decode_value2(data, 0); +  push_int (!force_decode); +  apply(data->codec,"programof", 2);    -  +  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, err4; +  ONERROR err1, err2, err3;      #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, low_allocate_program(),;); +  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(); +  }, +  ;);       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:2647:    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    -  if(placeholder) -  SET_ONERROR(err4, zap_placeholder, placeholder); +  placeholder = data->placeholder; +  data->placeholder = NULL;    -  decode_value2(data); +  decode_value2(data, 0);    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:2682:    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); +  decode_value2(data, 0);    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:2842:       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); +  decode_value2(data, 0);    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:2980:    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); +  decode_value2(data, 0);    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:3018:    } 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:3134:    }      #ifdef _REENTRANT    UNSET_ONERROR(err);    exit_threads_disable(NULL);   #endif    goto decode_done;    }       case 2: -  decode_value2(data); -  decode_value2(data); +  decode_value2(data, 1); +  decode_value2(data, 0);    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); +  decode_value2(data, 0);    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. */ -  struct program *p = low_allocate_program(); -  -  push_program (p); +  case 5: /* Forward reference for new-style encoding. */ +  push_program (low_allocate_program());    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:3255:    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 ride on that one -  * just like when it's created there. */ +  * Pike_compiler->new_program and we want to 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:3290:    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); +  decode_value2(data, 0);    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); +  decode_value2(data, 0);    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:3376:    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); +  decode_value2(data, 0);    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:3456:    p->identifier_references[no] = ref;    }    }    break;       case ID_ENTRY_VARIABLE:    {    int no, n;       /* name */ -  decode_value2(data); +  decode_value2(data, 0);    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); +  decode_value2(data, 0);    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:3507:    break;    case ID_ENTRY_FUNCTION:    {    union idptr func;    unsigned INT8 func_flags;    unsigned INT16 opt_flags;    int no;    int n;       /* name */ -  decode_value2(data); +  decode_value2(data, 0);    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); +  decode_value2(data, 0);    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:3583:    }    break;    case ID_ENTRY_CONSTANT:    {    struct identifier id;    struct reference ref;    int no;    int n;       /* name */ -  decode_value2(data); +  decode_value2(data, 0);    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); +  decode_value2(data, 0);    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:3682:       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); +  decode_value2(data, 0);    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); +  decode_value2(data, 1);    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); +  decode_value2(data, 0);    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:3766:    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:3808:    }   #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); +  decode_value2(data, 0);    /* name */ -  decode_value2(data); +  decode_value2(data, 0);    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:3832:    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:3919:    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:3955:   }      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); +  decode_value2(data, 0);       while (data->ptr < data->len) { -  decode_value2 (data); +  decode_value2 (data, 0);    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 object *codec, +  struct program *target_prog, +  struct object *placeholder   #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:4025:    }    }       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:4051:    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:4132:    *! 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) + /*! @decl object objectof(string data, int delay) +  *! @decl function functionof(string data, int delay) +  *! @decl program programof(string data, int delay)    *! -  *! Decode object encoded in @[data]. +  *! Get the object, function and program, respectively, represented +  *! by @[data].    *!    *! This function is called by @[decode_value()] when it encounters -  *! encoded objects. +  *! values from @[nameof()] in the encoded data.    *!    *! @param data -  *! Encoding of some object as specified by @[nameof()]. +  *! Encoding of some object, function or program as specified by +  *! @[nameof()].    *! -  *! @param minor -  *! Minor version. +  *! @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.    *! -  *! @returns -  *! Returns the decoded object. +  *! 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.)    *! -  *! @seealso -  *! @[functionof()], @[programof()] -  */ -  - /*! @decl function functionof(string data) +  *! This delay process isn't applicable for functions since they +  *! always involve an indexing, but the parameter is passed anyway +  *! for consistency.    *! -  *! 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 function. -  *! -  *! @seealso -  *! @[objectof()], @[programof()] +  *! Returns the decoded object.    */    - /*! @decl program programof(string data) + /*! @decl void finish (program target)    *! -  *! 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()] +  *! FIXME    */    - /*! @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:4274:    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; -  APPLY_MASTER("objectof", 1); +  push_int (0); +  APPLY_MASTER("objectof", 2);    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; -  APPLY_MASTER("functionof", 1); +  push_int (0); +  APPLY_MASTER("functionof", 2);    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; -  APPLY_MASTER("programof", 1); +  push_int (0); +  APPLY_MASTER("programof", 2);    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) + /*! @decl mixed decode_value(string coded_value, void|Codec codec, @ +  *! void|program target, void|object placeholder)    *!    *! 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; +  struct object *codec, *placeholder = NULL; +  struct program *target_prog = NULL;      #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 +  if(!my_decode(s, codec, target_prog, placeholder   #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);   }