pike.git / src / program.c

version» Context lines:

pike.git/src/program.c:178:    /* NOTE: After this point there are only fake lfuns. */    "_search",    "_types",    "_serialize",    "_deserialize",    "_size_object",    "_random",    "`**",    "``**",    "_sqrt", +  "_annotations", +  "_m_clear", +  "_m_add",   };      struct pike_string *lfun_strings[NELEM(lfun_names)];      static struct mapping *lfun_ids;      /* mapping(string:type) */   static struct mapping *lfun_types;      static const char *const raw_lfun_types[] = {
pike.git/src/program.c:242:    tFuncV(tZero tRangeBound tZero tRangeBound, tVoid, tMix), /* "`[..]" */    /* NOTE: After this point there are only fake lfuns. */    tFuncV(tZero tOr(tZero, tVoid), tZero, tMix), /* "_search", */    tFuncV(tNone,tVoid,tArray), /* "_types", */    tFuncV(tObj tZero, tVoid, tVoid), /* "_serialize", */    tFuncV(tObj tZero, tVoid, tVoid), /* "_deserialize", */    tFuncV(tNone, tVoid, tInt), /* "_size_object", */    tFuncV(tFunction tFunction, tVoid, tMix), /* "_random", */    tFuncV(tOr3(tInt,tFloat,tObj),tVoid,tOr3(tObj,tInt,tFloat)), /* "pow", */    tFuncV(tOr3(tInt,tFloat,tObj),tVoid,tOr3(tObj,tInt,tFloat)), /* "rpow", */ -  tFunc(tVoid,tMix),/* "_sqrt* */ +  tFunc(tVoid,tMix), /* "_sqrt", */ +  tFuncV(tOr(tVoid,tObj) tOr(tVoid,tInt) +  tOr(tInt01,tVoid),tVoid,tArray), /* "_annotations", */ +  tFuncV(tNone, tVoid, tVoid), /* "_m_clear", */ +  tFuncV(tZero, tVoid, tVoid), /* "_m_add", */   };      /* These two are not true LFUNs! */   static struct pike_type *lfun_getter_type_string = NULL;   static struct pike_type *lfun_setter_type_string = NULL;      /*! @namespace lfun::    *!    *! Callback functions used to overload various builtin functions.    *!
pike.git/src/program.c:1211:    */      /*! @decl mixed lfun::_m_delete(mixed arg)    *!    *! Delete index callback.    *!    *! @seealso    *! @[predef::m_delete()]    */    - /*! @decl predef::Iterator lfun::_get_iterator() + /*! @decl predef::Iterator lfun::_get_iterator(mixed ... args)    *!    *! Iterator creation callback.    *! -  +  *! @param args +  *! Optional extra arguments as passed to @[get_iterator()]. +  *! The implicit call from @[foreach()] does not provide any arguments. +  *!    *! The returned @[predef::Iterator] instance works as a cursor that    *! references a specific item contained (in some arbitrary sense)    *! in this one.    *!    *! @note    *! It's assumed that this function is side-effect free.    *!    *! @seealso    *! @[predef::Iterator], @[predef::get_iterator], @[predef::foreach()]    */
pike.git/src/program.c:1374:    *! A @[RandomInterface()->random_string] function that returns    *! a string(8bit) of the specified length.    *!    *! @param random    *! A @[RandomInterface()->random] function.    *!    *! @seealso    *! @[predef::random()], @[RandomInterface]    */    + /*! @decl object|int|float lfun::`**(int|float|object exp) +  *! Called by @[predef::`**()]. +  *! +  *! @seealso +  *! @[predef::`**()], @[lfun::``**()] +  */ +  + /*! @decl object|int|float lfun::``**(int|float|object base) +  *! Called by @[predef::`**()]. +  *! +  *! @seealso +  *! @[predef::`**()], @[lfun::`**()] +  */ +  + /*! @decl mixed lfun::_sqrt() +  *! Called by @[sqrt()]. +  *! +  *! @seealso +  *! @[sqrt()] +  */ +  + /*! @decl array lfun::_annotations(object|void context, int|void access, @ +  *! int(0..1)|void recursive) +  *! Called by @[annotations()] +  *! +  *! @param context +  *! Inherit in the current object to return the annotations for. +  *! If @expr{UNDEFINED@} or left out, @expr{this_program::this@} +  *! should be used (ie start at the current context and ignore +  *! any overloaded symbols). +  *! +  *! @param access +  *! Access permission override. One of the following: +  *! @int +  *! @value 0 +  *! @value UNDEFINED +  *! See only public symbols. +  *! @value 1 +  *! See protected symbols as well. +  *! @endint +  *! +  *! @param recursive +  *! Include nested annotations from the inherits. +  *! +  *! @seealso +  *! @[annotations()] +  */ +  + /*! @decl void lfun::_m_clear() +  *! +  *! Called by @[m_clear()]. +  *! +  *! @seealso +  *! @[lfun::_m_delete()], @[lfun::_m_add()] +  */ +  + /*! @decl void lfun::_m_add() +  *! +  *! Called by @[m_add()]. +  *! +  *! @seealso +  *! @[lfun::_m_delete()], @[lfun::_m_clear()] +  */ +    /**** END FAKE LFUNS ****/   /**** BEGIN MAGIC LFUNS ****/      /*! @decl mixed lfun::`symbol()    *! @decl mixed lfun::`->symbol()    *!    *! Variable retrieval callback (aka "getter").    *!    *! @note    *! Note that the @expr{symbol@} in the name can be any symbol.
pike.git/src/program.c:1521:   #define RELOCATE_program(ORIG, NEW)   #endif /* !RELOCATE_program */   #define RELOCATE_identifier_cache(ORIG,NEW)   #define RELOCATE_linenumbers(ORIG,NEW)   #define RELOCATE_identifier_index(ORIG,NEW)   #define RELOCATE_variable_index(ORIG,NEW)   #define RELOCATE_identifier_references(ORIG,NEW)   #define RELOCATE_strings(ORIG,NEW)   #define RELOCATE_inherits(ORIG,NEW)   #define RELOCATE_identifiers(ORIG,NEW) + #define RELOCATE_annotations(ORIG,NEW)   #define RELOCATE_constants(ORIG,NEW)   #define RELOCATE_relocations(ORIG,NEW)      #if SIZEOF_LONG_LONG == 8   /* we have 8 byte ints, hopefully this constant works on all these systems */   #define MAXVARS(NUMTYPE) \    (NUMTYPE)(sizeof(NUMTYPE)==1?254: \    (sizeof(NUMTYPE)==2?65534: \    (sizeof(NUMTYPE)==4?4294967294U:18446744073709551614ULL)))   #else
pike.git/src/program.c:1689:         #include "program_areas.h"         #define add_to_program(ARG) do { \    debug_malloc_touch(Pike_compiler->new_program->program); \    add_to_program(ARG); \    } while(0)    - void ins_int(INT32 i, void (*func)(char tmp)) + void ins_int(INT32 i, void (*func)(unsigned char tmp))   {    int e;    unsigned char *p = (unsigned char *)&i;    for(e=0;e<(long)sizeof(i);e++) {    func(p[e]);    }   }         #if 0
pike.git/src/program.c:1749:    dummy.func = func;    dummy.opt_flags = opt_flags;   #ifdef PROFILING    dummy.self_time=0;    dummy.num_calls=0;    dummy.recur_depth=0;    dummy.total_time=0;   #endif    debug_add_to_identifiers(dummy);    +  if (Pike_compiler->current_annotations) { +  /* FIXME: What about annotations for eg variant functions? */ +  compiler_add_annotations(n, Pike_compiler->current_annotations); +  /* Only annotate a single identifier. */ +  free_node(Pike_compiler->current_annotations); +  Pike_compiler->current_annotations = NULL; +  } +     return n;   }      static int add_identifier(struct compilation *c,    struct pike_type *type,    struct pike_string *name,    unsigned int modifier_flags,    unsigned int identifier_flags,    unsigned int opt_flags,    union idptr func,
pike.git/src/program.c:1795:       n = Pike_compiler->new_program->num_identifier_references;    add_to_identifier_references(ref);       return n;   }      void add_relocated_int_to_program(INT32 i)   {    add_to_relocations(Pike_compiler->new_program->num_program); -  ins_int(i, (void (*)(char))add_to_program); +  ins_int(i, add_to_program);   }      void use_module(struct svalue *s)   {    struct compilation *c = THIS_COMPILATION;    if( (1<<TYPEOF(*s)) & (BIT_MAPPING | BIT_OBJECT | BIT_PROGRAM))    {    c->num_used_modules++;    Pike_compiler->num_used_modules++;    assign_svalue_no_free((struct svalue *)
pike.git/src/program.c:2404:    mknewintnode(state_depth));    } else if(ident == lfun_strings[LFUN__INDICES]) {    return mknode(F_MAGIC_INDICES, mknewintnode(i),    mknewintnode(state_depth));    } else if(ident == lfun_strings[LFUN__VALUES]) {    return mknode(F_MAGIC_VALUES, mknewintnode(i),    mknewintnode(state_depth));    } else if(ident == lfun_strings[LFUN__TYPES]) {    return mknode(F_MAGIC_TYPES, mknewintnode(i),    mknewintnode(state_depth)); +  } else if(ident == lfun_strings[LFUN__ANNOTATIONS]) { +  return mknode(F_MAGIC_ANNOTATIONS, mknewintnode(i), +  mknewintnode(state_depth));    }       if (inherit_num && !TEST_COMPAT(7, 8) &&    (state->new_program->num_inherits > 1)) {    /* Check if there's an inherited lfun::`->() that we can call. */    int id;    struct program *prog = state->new_program->inherits[i].prog;    if (((id = FIND_LFUN(prog, LFUN_ARROW)) == -1) &&    (prog == state->new_program)) {    /* We are allowed to see private symbols in ourselves... */
pike.git/src/program.c:3032:    SEE_PROTECTED|SEE_PRIVATE);       if((e != i) && (e != -1))    {    my_yyerror("Illegal to redefine final identifier %S", name);    }    }    }    }    +  if (p->num_annotations) { +  struct pike_string *save_file = c->lex.current_file; +  INT_TYPE save_line = c->lex.current_line; +  +  for (i = 0; i < p->num_annotations; i++) { +  struct multiset *l = p->annotations[i]; +  int d; +  +  if (!l) continue; +  +  /* Make using yyerror() et al more convenient. */ +  c->lex.current_line = p->identifiers[i].linenumber; +  c->lex.current_file = p->strings[p->identifiers[i].filename_strno]; +  +  /* Convert the identifier number (i) to a reference number (d). */ +  for (d = 0; d < p->num_identifier_references; d++) { +  struct reference *ref = p->identifier_references + d; +  ptrdiff_t pos; +  +  if (ref->inherit_offset || (ref->identifier_offset != i)) continue; +  +  for (pos = multiset_first(l); pos >= 0; pos = multiset_next(l, pos)) { +  push_multiset_index(l, pos); +  +  if (TYPEOF(Pike_sp[-1]) == PIKE_T_OBJECT) { +  struct object *o = Pike_sp[-1].u.object; +  struct program *op = o->prog; +  if (op) { +  struct inherit *inh = op->inherits + SUBTYPEOF(Pike_sp[-1]); +  int fun; +  op = inh->prog; +  fun = find_identifier("end_pass_identifier", op); +  if (fun >= 0) { +  fun += inh->identifier_level; +  push_int(COMPILER_PASS_LAST); +  ref_push_program(p); +  push_int(d); +  ref_push_object_inherit(Pike_fp->current_object, +  Pike_fp->context - +  Pike_fp->current_program->inherits); +  safe_apply_low2(o, fun, 4, NULL); +  pop_stack(); +  } +  } +  } +  +  pop_stack(); +  } +  /* Remove the msnode_ref added by multiset_first(). */ +  sub_msnode_ref(l); +  } +  } +  +  c->lex.current_file = save_file; +  c->lex.current_line = save_line; +  } +    #ifdef DEBUG_MALLOC    {   #define DBSTR(X) ((X)?(X)->str:"")    int e,v;    INT_TYPE line;    struct pike_string *tmp;    struct memory_map *m=0;;    if(c->lex.current_file &&    c->lex.current_file->str &&    c->lex.current_file->len &&
pike.git/src/program.c:3158: Inside #if 0
  #if 0    fprintf(stderr,"Compiling class %s, depth=%d\n",    name->str, c->compilation_depth);    }else{    fprintf(stderr,"Compiling file %s, depth=%d\n",    c->lex.current_file ? c->lex.current_file->str : "-",    c->compilation_depth);   #endif    }    }else{ +  int e;    tmp.u.program=p;    add_ref(p);    if((pass != COMPILER_PASS_FIRST) && name)    {    struct identifier *i;    id=isidentifier(name);    if (id < 0)    Pike_fatal("Program constant disappeared in second pass.\n");    i=ID_FROM_INT(Pike_compiler->new_program, id);    free_type(i->type);
pike.git/src/program.c:3181:    if (pass == COMPILER_PASS_FIRST) {    if(c->compilation_depth >= 1) {    add_ref(p->parent = Pike_compiler->new_program);    debug_malloc_touch (p);    }    }    p->flags &=~ PROGRAM_VIRGIN;    if(idp) *idp=id;       CDFPRINTF("th(%ld) %p low_start_new_program() %s " -  "pass=%d: lock_depth:%d, compilation_depth:%d\n", +  "pass=%d: compilation_depth:%d\n",    (long)th_self(), p, name ? name->str : "-",    Pike_compiler->compiler_pass, -  lock_depth, c->compilation_depth); +  c->compilation_depth);       init_type_stack();      #define PUSH   #include "compilation.h"       ba_init(&Pike_compiler->node_allocator, sizeof(struct node_s), 512);       Pike_compiler->parent_identifier=id;    Pike_compiler->compiler_pass = pass;
pike.git/src/program.c:3373:       i.prog=Pike_compiler->new_program;    i.identifier_level=0;    i.storage_offset=0;    i.inherit_level=0;    i.identifier_ref_offset=0;    i.parent=0;    i.parent_identifier=-1;    i.parent_offset=OBJECT_PARENT;    i.name=0; +  i.annotations = NULL;    add_to_inherits(i);    }       Pike_compiler->init_node=0;    Pike_compiler->num_parse_error=0;       push_compiler_frame(0);    copy_pike_type(Pike_compiler->compiler_frame->current_return_type,    void_type_string);   
pike.git/src/program.c:3409:    { /* Trim off the leading path of the compilation environment. */    const char *p = DEFINETOSTR(PIKE_SRC_ROOT), *f = file;    while (*p && *p == *f) p++, f++;    while (*f == '/' || *f == '\\') f++;       c->lex.current_file = make_shared_string(f);    c->lex.current_line = line;    }       CDFPRINTF("th(%ld) start_new_program(%ld, %s): " -  "lock_depth:%d, compilation_depth:%d\n", +  "compilation_depth:%d\n",    (long)th_self(), (long)line, file, -  lock_depth, c->compilation_depth); +  c->compilation_depth);       low_start_new_program(0, COMPILER_PASS_FIRST, 0, 0, 0);    store_linenumber(line,c->lex.current_file);    debug_malloc_name(Pike_compiler->new_program, file, line);       free_string(c->lex.current_file);    c->lex.current_file = dmalloc_touch(struct pike_string *, save_file);    c->lex.current_line = save_line;   }   
pike.git/src/program.c:3463:    /* fprintf(stderr, "Exiting program: %p, id:%d\n", p, p->id); */       if(id_to_program_cache[p->id & (ID_TO_PROGRAM_CACHE_SIZE-1)]==p)    id_to_program_cache[p->id & (ID_TO_PROGRAM_CACHE_SIZE-1)]=0;       if(p->strings)    for(e=0; e<p->num_strings; e++)    if(p->strings[e])    free_string(p->strings[e]);    +  if (p->annotations) { +  for (e = 0; e < p->num_annotations; e++) { +  do_free_multiset(p->annotations[e]); +  } +  } +     if(p->identifiers)    {    for(e=0; e<p->num_identifiers; e++)    {    if(p->identifiers[e].name)    free_string(p->identifiers[e].name);    if(p->identifiers[e].type)    free_type(p->identifiers[e].type);    }    }
pike.git/src/program.c:3488: Inside #if 0
   free_svalue(& p->constants[e].sval);   #if 0    if(p->constants[e].name) free_string(p->constants[e].name);   #endif /* 0 */    }    }       if(p->inherits)    for(e=0; e<p->num_inherits; e++)    { +  if (p->inherits[e].annotations) +  free_multiset(p->inherits[e].annotations);    if(p->inherits[e].name)    free_string(p->inherits[e].name);    if(e)    {    if(p->inherits[e].prog)    free_program(p->inherits[e].prog);    }    if(p->inherits[e].parent)    free_object(p->inherits[e].parent);    }
pike.git/src/program.c:3567: Inside #if defined(PIKE_DEBUG)
      for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," ");    fprintf(stderr,"inherited program: %d\n",p->inherits[e].prog->id);       if(p->inherits[e].name)    {    for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," ");    fprintf(stderr,"name : %s\n",p->inherits[e].name->str);    }    +  if (p->inherits[e].annotations) { +  union msnode *node = low_multiset_first(p->inherits[e].annotations->msd); +  fprintf(stderr, "annotations:\n"); +  while (node) { +  if (TYPEOF(node->i.ind) != T_DELETED) { +  low_push_multiset_index(node); +  safe_pike_fprintf(stderr, " %O\n", Pike_sp-1); +  pop_stack(); +  } +  node = low_multiset_next(node); +  } +  } +     for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," ");    fprintf(stderr,"inherit_level: %d\n",p->inherits[e].inherit_level);       for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," ");    fprintf(stderr,"identifier_level: %d\n",p->inherits[e].identifier_level);       for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," ");    fprintf(stderr,"parent_identifier: %d\n",p->inherits[e].parent_identifier);       for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," ");
pike.git/src/program.c:3625: Inside #if defined(PIKE_DEBUG)
   }    fprintf(stderr,"All sorted identifiers:\n");    for(q=0;q<(int)p->num_identifier_index;q++)    {    e=p->identifier_index[q];    fprintf(stderr,"%3d (%3d):",e,q);    for(d=0;d<INHERIT_FROM_INT(p,e)->inherit_level;d++) fprintf(stderr," ");    fprintf(stderr,"%s;\n", ID_FROM_INT(p,e)->name->str);    }    +  if (p->annotations) { +  fprintf(stderr, "All identifier annotations:\n"); +  for (q = 0; q < p->num_annotations; q++) { +  struct multiset *l = p->annotations[q]; +  union msnode *node; +  if (!l) continue; +  fprintf(stderr, " Identifier #%d: %s\n", +  q, p->identifiers[q].name->str); +  for (node = low_multiset_first(l->msd); +  node; +  node = low_multiset_next(node)) { +  low_push_multiset_index(node); +  safe_pike_fprintf(stderr, " %O\n", Pike_sp-1); +  pop_stack(); +  } +  } +  } +     fprintf(stderr,"$$$$$ dump_program_desc for %p done\n", p);   }   #endif      static void toss_compilation_resources(void)   {    if(Pike_compiler->fake_object)    {    if( ((struct parent_info *)Pike_compiler->fake_object->storage)->parent )    {
pike.git/src/program.c:3676:    free_string(Pike_compiler->last_identifier);    Pike_compiler->last_identifier=0;    }       if(Pike_compiler->last_file)    {    free_string(Pike_compiler->last_file);    Pike_compiler->last_file=0;    }    +  if (Pike_compiler->current_annotations) { +  free_node(Pike_compiler->current_annotations); +  Pike_compiler->current_annotations = NULL; +  } +     if (Pike_compiler->current_attributes) {    free_node(Pike_compiler->current_attributes);    Pike_compiler->current_attributes = NULL;    }       unuse_modules(Pike_compiler->num_used_modules);       free_all_nodes();       ba_destroy(&Pike_compiler->node_allocator);
pike.git/src/program.c:3801: Inside #if defined(PIKE_DEBUG)
   struct inherit *inh = p->inherits + d;       fprintf(stderr, "%*s %4d: %5d %7d %8d %12"PRINTPTRDIFFT"d %6d %8d %10d %11"PRINTSIZET"d\n",    indent, "",    d, inh->inherit_level,    inh->prog ? inh->prog->id : -1,    inh->identifier_level, inh->storage_offset,    inh->parent_identifier, inh->parent_offset,    inh->parent ? inh->parent->program_id : -1,    inh->identifier_ref_offset); +  +  if (inh->annotations) { +  union msnode *node = low_multiset_first(inh->annotations->msd); +  int i; +  for (i = 0; node; (node = low_multiset_next(node)), i++) { +  fprintf(stderr, "%*s annotation #%d: ", indent, "", i); +  low_push_multiset_index(node); +  safe_pike_fprintf(stderr, "%O\n", Pike_sp-1); +  pop_stack();    } -  +  } +  }    fprintf(stderr, "\n"    "%*sIdentifier table:\n"    "%*s ####: Flags Offset Type Name\n",    indent, "", indent, "");    for (d=0; d < p->num_identifiers; d++) {    struct identifier *id = p->identifiers + d;       fprintf(stderr,    "%*s %4d: %5x %6"PRINTPTRDIFFT"d %4d \"%s\"\n"    "%*s %s:%ld\n",    indent, "",    d, id->identifier_flags, id->func.offset,    id->run_time_type, id->name->str,    indent, "",    p->num_strings?p->strings[id->filename_strno]->str:"-",    (long)id->linenumber); -  +  if ((d < p->num_annotations) && p->annotations[d]) { +  union msnode *node = low_multiset_first(p->annotations[d]->msd); +  int i; +  for (i = 0; node; (node = low_multiset_next(node)), i++) { +  fprintf(stderr, "%*s annotation #%d: ", indent, "", i); +  low_push_multiset_index(node); +  safe_pike_fprintf(stderr, "%O\n", Pike_sp-1); +  pop_stack();    } -  +  } +  }       fprintf(stderr, "\n"    "%*sVariable table:\n"    "%*s ####: Index\n",    indent, "", indent, "");    for (d = 0; d < p->num_variable_index; d++) {    fprintf(stderr, "%*s %4d: %5d\n",    indent, "",    d, p->variable_index[d]);    }
pike.git/src/program.c:3877:       fprintf(stderr, "\n"    "%*sLinenumber table:\n",    indent, "");    {    INT32 off = 0;    INT_TYPE line = 0;    char *cnt = p->linenumbers;       while (cnt < p->linenumbers + p->num_linenumbers) { -  if (*cnt == 127) { +  while (*cnt == 127) {    int strno;    cnt++;    strno = get_small_number(&cnt); -  +  if (strno >= 0) {    fprintf(stderr, "%*s Filename: String #%d\n", indent, "", strno); -  +  } else { +  int offset = ~strno; +  int kind = *(cnt++); +  strno = (kind >= 0)?get_small_number(&cnt):0; +  switch(kind) { +  case -1: /* end */ +  fprintf(stderr, "%*s Variable #%d end\n", indent, "", offset); +  break; +  case 0: /* name */ +  fprintf(stderr, "%*s Variable #%d name: string #%d\n", +  indent, "", offset, strno); +  break; +  case 1: /* type */ +  fprintf(stderr, "%*s Variable #%d type: constant #%d\n", +  indent, "", offset, strno); +  break; +  default: +  fprintf(stderr, "%*s Variable #%d unknown (%d): value: %d\n", +  indent, "", offset, kind, strno); +  break;    } -  +  } +  if (cnt >= p->linenumbers + p->num_linenumbers) break; +  } +  if (cnt >= p->linenumbers + p->num_linenumbers) break;    off += get_small_number(&cnt);    line += get_small_number(&cnt);    fprintf(stderr, "%*s %8d:%8ld\n", indent, "", off, (long)line);    }    }       fprintf(stderr, "\n");   }      void check_program(struct program *p)
pike.git/src/program.c:4194:    struct pike_type *type,    int id_flags)   {    union idptr dispatch_fun;    dispatch_fun.c_fun = f_dispatch_variant;    return define_function(name, type, id_flags & ~(ID_VARIANT|ID_LOCAL),    IDENTIFIER_C_FUNCTION, &dispatch_fun, 0);   }      /** +  * Add a single annotation for a symbol in the current program +  * being compiled. +  * +  * @param id +  * Identifier to annotate. +  * +  * @param val +  * Annotation value. Should be an object implementing +  * the Pike.Annotation interface. +  */ + PMOD_EXPORT void add_annotation(int id, struct svalue *val) + { +  while (Pike_compiler->new_program->num_annotations <= id) { +  add_to_annotations(NULL); +  } +  +  if (val) { +  if (Pike_compiler->new_program->annotations[id]) { +  multiset_add(Pike_compiler->new_program->annotations[id], val); +  } else { +  push_svalue(val); +  f_aggregate_multiset(1); +  Pike_compiler->new_program->annotations[id] = Pike_sp[-1].u.multiset; +  Pike_sp--; +  } +  } + } +  + void compiler_add_annotations(int id, node *annotations) + { +  while(annotations) { +  node *val_node = CAR(annotations); +  annotations = CDR(annotations); +  if (val_node->token != F_CONSTANT) continue; +  add_annotation(id, &val_node->u.sval); +  } + } +  + /** +  * Add a single annotation for an inherit in the current program +  * being compiled. +  * +  * @param inh +  * Inherit to annotate. +  * +  * @param val +  * Annotation value. Should be an object implementing +  * the Pike.Annotation interface. +  * +  * NOTE: This operation is ONLY valid for inherits at +  * levels 0 and 1! +  * +  */ + PMOD_EXPORT void add_program_annotation(int inh, struct svalue *val) + { +  struct inherit *inherit = Pike_compiler->new_program->inherits + inh; +  if (inherit->inherit_level > 1) { +  Pike_fatal("Attempt to annotate inherit #%d at level %d!\n", +  inh, inherit->inherit_level); +  } +  if (val) { +  if (inherit->annotations) { +  multiset_add(inherit->annotations, val); +  } else { +  push_svalue(val); +  f_aggregate_multiset(1); +  inherit->annotations = Pike_sp[-1].u.multiset; +  Pike_sp--; +  } +  } + } +  + void compiler_add_program_annotations(int inh, node *annotations) + { +  while(annotations) { +  node *val_node = CAR(annotations); +  annotations = CDR(annotations); +  if (val_node->token != F_CONSTANT) continue; +  add_program_annotation(inh, &val_node->u.sval); +  } + } +  + /**    * End the current compilation pass.    *    * @param finish    * finish-state:    *    * 0: First pass.    * 1: Last pass.    * 2: Called from decode_value().    *    * Note: This function is misnamed, since it's run after all passes.
pike.git/src/program.c:4335:    * further down when we have entered pass 2.    *    * Also make sure that it is marked as having side effects,    * or it will be optimized away when inherited...    */    define_function(init_name, function_type_string, ID_PROTECTED,    IDENTIFIER_PIKE_FUNCTION, NULL,    OPT_SIDE_EFFECT|OPT_EXTERNAL_DEPEND);    }    } +  /* FIXME: Call end_pass() in annotations here? +  */    Pike_compiler->compiler_pass = COMPILER_PASS_LAST;    }    -  +  if (!Pike_compiler->num_parse_error) { +  prog = Pike_compiler->new_program; +  /* NB: Need referenced msnodes! */ +  if (prog->inherits->annotations) { +  struct multiset *l = prog->inherits->annotations; +  ptrdiff_t pos; +  /* NB: multiset_first() adds an msnode_ref. */ +  for (pos = multiset_first(l); pos >= 0; pos = multiset_next(l, pos)) { +  struct object *o; +  struct program *p; +  struct inherit *inh; +  int fun; +  push_multiset_index(l, pos); +  if (TYPEOF(Pike_sp[-1]) == PIKE_T_OBJECT) { +  o = Pike_sp[-1].u.object; +  p = o->prog; +  if (p) { +  inh = p->inherits + SUBTYPEOF(Pike_sp[-1]); +  p = inh->prog; +  fun = find_identifier("end_pass", p); +  if (fun >= 0) { +  fun += inh->identifier_level; +  push_int(Pike_compiler->compiler_pass); +  ref_push_program(prog); +  ref_push_object_inherit(Pike_fp->current_object, +  Pike_fp->context - +  Pike_fp->current_program->inherits); +  safe_apply_low2(o, fun, 3, NULL); +  pop_stack(); +  } +  } +  } +  pop_stack(); +  } +  /* Remove the msnode_ref added by multiset_first(). */ +  sub_msnode_ref(l); +  } +  } +     /*    * Define the __INIT function, but only if there was any code    * to initialize.    */       if(Pike_compiler->init_node)    {    /* Inhibit this_function. */    Pike_compiler->compiler_frame->current_function_number = -2;   
pike.git/src/program.c:4461:    c->resolve_cache=0;    }      #define POP   #include "compilation.h"       exit_type_stack();          CDFPRINTF("th(%ld) %p end_first_pass(%d): " -  "lock_depth:%d, compilation_depth:%d\n", +  "compilation_depth:%d\n",    (long)th_self(), prog, finish, -  lock_depth, c->compilation_depth); +  c->compilation_depth);       c->compilation_depth--;       unlock_pike_compiler();      #if 0   #ifdef PIKE_USE_MACHINE_CODE    if (prog &&    (((unsigned long long *)prog->program)[-1] != 0xdeadfeedf00dfaddLL)) {    Pike_fatal("Bad mexec magic!\n");
pike.git/src/program.c:4773:    * Program state for the program being compiled that will have    * the reference added. May be NULL to indicate Pike_compiler.    *    * @param i    * Inherit number in q->new_program.    *    * @param f    * Reference number in q->new_program->inherit[i].prog.    *    * @return -  * Returns an equivalent reference that is INLINE|HIDDEN. +  * Returns an equivalent reference that is INLINE (and HIDDEN if +  * a new reference was created).    *    * Returns -1 if the referenced identifier is -1 or a prototype.    */   PMOD_EXPORT int really_low_reference_inherited_identifier(struct program_state *q,    int i,    int f)   {    struct program *np=(q?q:Pike_compiler)->new_program;    struct reference funp;    struct program *p;
pike.git/src/program.c:4812:       num_id_refs = np->num_identifier_references;       for(d = 0; d < num_id_refs; d++)    {    struct reference *refp;    refp = np->identifier_references + d;       if ((refp->inherit_offset == funp.inherit_offset) &&    (refp->identifier_offset == funp.identifier_offset) && -  ((refp->id_flags | ID_USED) == (funp.id_flags | ID_USED))) { +  ((refp->id_flags & (ID_INLINE|ID_EXTERN|ID_VARIANT)) == +  (funp.id_flags & (ID_INLINE|ID_EXTERN|ID_VARIANT)))) {    return d;    }    }       funp.run_time_type = PIKE_T_UNKNOWN;       if(q)    low_add_to_identifier_references(q,funp);    else    add_to_identifier_references(funp);
pike.git/src/program.c:5040:   #endif    CDFPRINTF("th(%ld) %p inherit %p\n",    (long) th_self(), Pike_compiler->new_program, p);       if(!p)    {    yyerror("Illegal program pointer.");    return;    }    -  if (Pike_compiler->compiler_pass == COMPILER_PASS_EXTRA) { +  if (Pike_compiler->compiler_pass != COMPILER_PASS_FIRST) { +  /* NB: Pike_compiler->num_inherits is off by 1! +  * This is probably due to not counting the initial inherit. +  */    struct program *old_p =    Pike_compiler->new_program->    inherits[Pike_compiler->num_inherits+1].prog; -  +  inherit_offset = Pike_compiler->num_inherits + 1;    Pike_compiler->num_inherits += old_p->num_inherits;       if (old_p != p) {    yyerror("Got different program for inherit in second pass "    "(resolver problem).");    } -  +  +  if (Pike_compiler->compiler_pass == COMPILER_PASS_EXTRA) {    return;    } -  if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST) { -  struct program *old_p = -  Pike_compiler->new_program-> -  inherits[Pike_compiler->num_inherits+1].prog; -  Pike_compiler->num_inherits += old_p->num_inherits; +     -  if (old_p != p) { -  yyerror("Got different program for inherit in second pass " -  "(resolver problem)."); -  } +  assert(Pike_compiler->compiler_pass == COMPILER_PASS_LAST);       if (!(p->flags & PROGRAM_FINISHED)) {    /* Require that the inherited program really is finished in pass    * 2. Otherwise we might not have all definitions when we    * fixate our program.    *    * FIXME: Maybe this can be relaxed by registering a dependency    * and delaying compilation here?    */    yyerror ("Cannot inherit program in pass 2 "
pike.git/src/program.c:5181:   #endif    }else{    inherit.parent=parent;    inherit.parent_identifier=parent_identifier;    inherit.parent_offset=INHERIT_PARENT;    }    }else{    inherit.parent_offset=parent_offset;    inherit.parent_identifier=parent_identifier;    } +  +  if (inherit.annotations) { +  struct multiset *annotations; +  union msnode *node = low_multiset_first(inherit.annotations->msd); +  int keep_annotations = 0; +  +  inherit.annotations = annotations = copy_multiset(inherit.annotations); +  +  ref_push_object(Inherited_annotation); +  +  while(node) { +  if (TYPEOF(node->i.ind) != T_DELETED) { +  low_push_multiset_index(node); +  if (TYPEOF(Pike_sp[-1]) == PIKE_T_OBJECT) { +  /* FIXME: Subtyped objects? */ +  struct object *ann = Pike_sp[-1].u.object; +  if (ann->prog && ann->prog->inherits[0].annotations) { +  /* Check if it has the @Inherited annotation. */ +  struct multiset *l = ann->prog->inherits[0].annotations; +  if (multiset_lookup(l, Pike_sp-2)) { +  add_program_annotation(0, Pike_sp-1); +  +  multiset_delete(annotations, Pike_sp-1); +  } else { +  keep_annotations = 1; +  } +  } else { +  keep_annotations = 1; +  } +  } else { +  keep_annotations = 1; +  } +  pop_stack(); +  } +  node = low_multiset_next(node); +  } +  if (!keep_annotations) { +  free_multiset(annotations); +  inherit.annotations = NULL; +  } +  pop_stack(); +  }    }else{    if(!inherit.parent)    {    if(parent && parent->next != parent && inherit.parent_offset)    {    struct object *par=parent;    int e,pid=parent_identifier;       for(e=1;e<inherit.parent_offset;e++)    {
pike.git/src/program.c:5239:    pid = -1;    par = NULL;    }    }    }       inherit.parent=par;    inherit.parent_offset=INHERIT_PARENT;    }    } +  if (inherit.annotations) { +  add_ref(inherit.annotations);    } -  +  }    if(inherit.parent) add_ref(inherit.parent);       if(name)    {    if(e==0)    {    copy_shared_string(inherit.name,name);    }    else if(inherit.name)    {
pike.git/src/program.c:5423:    low_inherit(p, parent_obj, parent_id, 0, flags, name);   }      void compiler_do_inherit(node *n,    INT32 flags,    struct pike_string *name)   {    struct program *p;    struct identifier *i;    INT32 numid=-1, offset=0; +  int inherit_offset = Pike_compiler->new_program->num_inherits;       if(!n)    { -  yyerror("Unable to inherit"); +  yyerror("Unable to inherit.");    return;    }    -  +  if (Pike_compiler->compiler_pass != COMPILER_PASS_FIRST) { +  /* Note off by one! */ +  inherit_offset = Pike_compiler->num_inherits + 1; +  } +     if ((n->token == F_APPLY) && (CAR(n)->token == F_CONSTANT) &&    (TYPEOF(CAR(n)->u.sval) == T_FUNCTION) &&    (SUBTYPEOF(CAR(n)->u.sval) == FUNCTION_BUILTIN) &&    (CAR(n)->u.sval.u.efun->function == debug_f_aggregate)) {    /* Disambiguate multiple inherit ::-reference. */    node *arg;    while(1) {    while ((arg = CDR(n))) {    n = arg;    if (n->token != F_ARG_LIST) goto found;
pike.git/src/program.c:5465:    ;    }       fix_type_field(n);       if (!pike_types_le(n->type, inheritable_type_string) &&    (THIS_COMPILATION->lex.pragmas & ID_STRICT_TYPES)) {    yytype_report(REPORT_WARNING,    n->current_file, n->line_number, inheritable_type_string,    n->current_file, n->line_number, n->type, -  0, "Program required for inherit.\n"); +  0, "Program required for inherit.");    }       switch(n->token)    {    case F_EXTERNAL:    {    struct program_state *state = Pike_compiler;       offset = 0;    while (state && (state->new_program->id != n->u.integer.a)) {    state = state->previous;    offset++;    }    if (!state) { -  yyerror("Failed to resolv external constant.\n"); +  yyerror("Failed to resolv external constant.");    return;    }    p = state->new_program;    numid = n->u.integer.b;    if ((name == this_program_string) && (offset == 1)) {    /* Klugde: Default to renaming ::this_program    * to the name of the current class.    *    * Otherwise the this_program:-scope    * will become confusing, as it will
pike.git/src/program.c:5521:    return;    }else{    low_inherit(s->u.program,    0,    numid,    offset+42,    flags,    name);    }    }else{ -  yyerror("Inherit identifier is not a constant program"); +  yyerror("Inherit identifier is not a constant program.");    return;    }    break;       default:    resolv_class(n);    do_inherit(Pike_sp-1, flags, name);    pop_stack();    } - } +     - void compiler_do_implement(node *n) - { -  if (!n) { -  yyerror("Invalid implement directive."); -  return; +  if (Pike_compiler->current_annotations && +  (Pike_compiler->compiler_pass == COMPILER_PASS_FIRST)) { +  compiler_add_program_annotations(inherit_offset, +  Pike_compiler->current_annotations); +  free_node(Pike_compiler->current_annotations); +  Pike_compiler->current_annotations = NULL;    } -  /* FIXME: Implement. */ +    }      int call_handle_inherit(struct pike_string *s)   {    struct compilation *c = THIS_COMPILATION;       CHECK_COMPILER();       ref_push_string(s);    f_string_to_utf8(1);
pike.git/src/program.c:5867:    if(type == void_type_string)    yyerror("Variables can't be of type void.");       n = isidentifier(name);       if(Pike_compiler->new_program->flags & PROGRAM_PASS_1_DONE)    {    if(n==-1)    yyerror("Pass2: Variable disappeared!");    else { -  struct identifier *id=ID_FROM_INT(Pike_compiler->new_program,n); +  struct reference *ref = PTR_FROM_INT(Pike_compiler->new_program, n); +  struct identifier *id = ID_FROM_PTR(Pike_compiler->new_program, ref); +     free_type(id->type);    copy_pike_type(id->type, type);    return n;    }    }      #ifdef PIKE_DEBUG    if(Pike_compiler->new_program->flags & (PROGRAM_FIXED | PROGRAM_OPTIMIZED))    Pike_fatal("Attempting to add variable to fixed program\n");   #endif
pike.git/src/program.c:6121:    if(Pike_compiler->new_program->flags & PROGRAM_PASS_1_DONE)    {    if(n==-1   #if 1    || !c   #endif    )    {    yyerror("Pass2: Constant disappeared!");    }else{ -  struct identifier *id; -  id=ID_FROM_INT(Pike_compiler->new_program,n); +  struct reference *ref = PTR_FROM_INT(Pike_compiler->new_program, n); +  struct identifier *id = ID_FROM_PTR(Pike_compiler->new_program, ref); +     if (IDENTIFIER_IS_ALIAS(id->identifier_flags)) {    /* FIXME: We probably ought to do something here... */    } else if(id->func.const_info.offset>=0) {    /* Update the stored constant. */    assign_svalue (&PROG_FROM_INT(Pike_compiler->new_program,n)->    constants[id->func.const_info.offset].sval, c);    } else {    id->run_time_type = (unsigned char) TYPEOF(*c);    id->func.const_info.offset = store_constant(c, 0, 0);    }
pike.git/src/program.c:6373:    id=make_shared_binary_string(name,namelen);    ret=add_constant(id, &tmp, flags);    /* The following is not really true, but it helps encode_value()... */    Pike_compiler->new_program->flags |=    tmp.u.program->flags & PROGRAM_HAS_C_METHODS;    free_string(id);    free_svalue(&tmp);    return ret;   }    + int is_lfun_name(struct pike_string *name) + { +  if (low_mapping_string_lookup(lfun_types, name)) { +  return 1; +  } +  return 0; + } +    /**    * Define a new function.    *    * if func isn't given, it is supposed to be a prototype.    */   INT32 define_function(struct pike_string *name,    struct pike_type *type,    unsigned flags,    unsigned function_flags,    union idptr *func,
pike.git/src/program.c:6442:    } else if (c->lex.pragmas & ID_STRICT_TYPES) {    level = REPORT_WARNING;    }    if (level != REPORT_NOTICE) {    yytype_report(level, NULL, 0, lfun_type->u.type,    NULL, 0, type, 0,    "Type mismatch for callback function %S:", name);    }    }    c->lex.pragmas = orig_pragmas; +  +  /* NB: define_function() is called multiple times... */ +  if (((flags & (ID_PROTECTED|ID_PRIVATE)) != ID_PROTECTED) && func && +  !(orig_pragmas & ID_NO_DEPRECATION_WARNINGS) && +  !deprecated_typep(type)) { +  if (!(flags & (ID_PROTECTED|ID_PRIVATE))) { +  yywarning("Lfun %S is public.", name); +  } else { +  yywarning("Lfun %S is private.", name);    } -  +  } +  }    } else if (((name->len > 3) &&    (index_shared_string(name, 0) == '`') &&    (index_shared_string(name, 1) == '-') &&    (index_shared_string(name, 2) == '>')) ||    ((name->len > 1) &&    (index_shared_string(name, 0) == '`') &&    wide_isidchar(index_shared_string(name, 1)))) {    /* Getter setter. */    struct pike_string *symbol = NULL;    struct pike_type *symbol_type = NULL;
pike.git/src/program.c:6638:       funp = ID_FROM_INT(prog, i);    ref = prog->identifier_references[i];       if (funp->identifier_flags & IDENTIFIER_HAS_BODY)    /* Keep this flag. */    function_flags |= IDENTIFIER_HAS_BODY;       if(!(ref.id_flags & ID_INHERITED)) /* not inherited */    { -  +     if( !( IDENTIFIER_IS_FUNCTION(funp->identifier_flags) &&    ( (!func || func->offset == -1) || (funp->func.offset == -1))))    {    my_yyerror("Identifier %S defined twice.", name);       if (getter_setter != -1) {    struct identifier *id = ID_FROM_INT(prog, getter_setter);    (&id->func.gs_info.getter)[is_setter] = i;    }    return i;
pike.git/src/program.c:7611:    }    }    }    f_aggregate(n);    res = Pike_sp[-1].u.array;    add_ref(res);    pop_stack();    return(res);   }    + /** +  * Returns an array containing the recursive annotations +  * for all inherits in the program. +  * +  * Retuns NULL if there are no such annotations. +  */ + struct array *program_inherit_annotations(struct program *p) + { +  int prev_offset = -1; +  int i; +  int found = 0; +  struct svalue *res = Pike_sp; +  +  for (i = 0; i < p->num_inherits; i++) { +  push_undefined(); +  } +  for (i = 0; i < p->num_inherits; i++) { +  struct inherit *inh = p->inherits + i; +  if (inh->inherit_level > 0) { +  push_svalue(res + inh->inherit_level - 1); +  } else { +  push_undefined(); +  } +  if (inh->annotations) { +  ref_push_multiset(inh->annotations); +  f_add(2); +  found = 1; +  } +  assign_svalue(res + inh->inherit_level, Pike_sp - 1); +  pop_stack(); +  } +  if (found) { +  return aggregate_array(Pike_sp - res); +  } +  pop_n_elems(Pike_sp - res); +  return NULL; + } +  + struct array *program_annotations(struct program *p, int flags) + { +  int i; +  int n = 0; +  struct array *res; +  struct array *inherit_annotations = NULL; +  if (flags & 1) { +  inherit_annotations = program_inherit_annotations(p); +  } +  for (i = p->num_identifier_index; i--; ) { +  struct identifier *id; +  int e = p->identifier_index[i]; +  if (p->identifier_references[e].id_flags & +  (ID_HIDDEN|ID_VARIANT|ID_PROTECTED|ID_PRIVATE)) { +  continue; +  } +  id = ID_FROM_INT(p, e); +  if (IDENTIFIER_IS_ALIAS(id->identifier_flags)) { +  /* FIXME! +  */ +  continue; +  } else if (IDENTIFIER_IS_CONSTANT(id->identifier_flags)) { +  if (id->func.const_info.offset >= 0) { +  struct reference *ref = PTR_FROM_INT(p, e); +  struct program *p2 = PROG_FROM_PTR(p, ref); +  struct svalue *val = &p2->constants[id->func.const_info.offset].sval; +  struct multiset *inh_ann = NULL; +  if ((TYPEOF(*val) != T_PROGRAM) || +  !(val->u.program->flags & PROGRAM_USES_PARENT)) { +  if (inherit_annotations && +  (TYPEOF(ITEM(inherit_annotations)[ref->inherit_offset]) == +  PIKE_T_MULTISET)) { +  inh_ann = ITEM(inherit_annotations)[ref->inherit_offset].u.multiset; +  ref_push_multiset(inh_ann); +  } +  if ((p2->num_annotations > ref->identifier_offset) && +  p2->annotations[ref->identifier_offset]) { +  ref_push_multiset(p2->annotations[ref->identifier_offset]); +  if (inh_ann) { +  f_add(2); +  } +  } else if (!inh_ann) { +  push_int(0); +  } +  n++; +  } +  } else { +  /* FIXME: Prototype constant. */ +  push_int(0); +  n++; +  } +  } +  } +  do_free_array(inherit_annotations); +  f_aggregate(n); +  res = Pike_sp[-1].u.array; +  add_ref(res); +  pop_stack(); +  return(res); + } +    int low_program_index_no_free(struct svalue *to, struct program *p, int e,    struct object *parent, int parent_identifier)   {    struct identifier *id;    id=ID_FROM_INT(p, e);       if (IDENTIFIER_IS_ALIAS(id->identifier_flags)) {    struct external_variable_context loc;    struct object fake_object;    struct parent_info parent_info;
pike.git/src/program.c:7721:   /*    * Line number support routines, now also tells what file we are in.    */      /* program.linenumbers format:    *    * Filename entry:    * 1. char 127 (marker).    * 2. small number Filename entry number in string table.    * +  * Frame variable: +  * 1. char 127 (marker). +  * 2. small number ~(frame stack offset). +  * 3. char -1: end, 0: name, 1: type (kind) +  * 4. small number end: -, name: strings_offset, type: constants_offset +  *    * Line number entry:    * 1. small number Index in program.program (pc).    * Stored as the difference from the pc in the    * closest previous line number entry. The first    * stored entry is absolute.    * 2. small number Line number. Stored in the same way as the pc.    *    * Small number:    * If -127 < n < 127:    * 1. char The number.
pike.git/src/program.c:7928: Inside #if defined(PIKE_DEBUG)
   (INT32) PIKE_PC);    fprintf(stderr, " last_line:%ld last_file:\"%s\"\n",    (long)Pike_compiler->last_line,    Pike_compiler->last_file?Pike_compiler->last_file->str:"");    }       while(cnt < Pike_compiler->new_program->linenumbers +    Pike_compiler->new_program->num_linenumbers)    {    char *start = cnt; -  if(*cnt == 127) +  while(*cnt == 127)    {    int strno;    cnt++;    strno = get_small_number(&cnt); -  +  if (strno >= 0) {    CHECK_FILE_ENTRY (Pike_compiler->new_program, strno);    if (a_flag > 100) {    file = Pike_compiler->new_program->strings[strno];    fprintf(stderr, "Filename entry:\n"    " len: %"PRINTSIZET"d, shift: %d\n",    file->len, file->size_shift);    } -  +  } else { +  int offset = ~strno; +  int kind = *(cnt++); +  strno = (kind < 0)?-1:get_small_number(&cnt); +  if (a_flag > 100) { +  switch(kind) { +  case -1: /* end */ +  fprintf(stderr, "Variable end entry:\n" +  " offset: 0x%04x\n", offset); +  break; +  case 0: /* name */ +  { +  struct pike_string *var_name = +  Pike_compiler->new_program->strings[strno]; +  fprintf(stderr, "Variable name entry:\n" +  " offset: 0x%04x name: \"%.*s\"\n", +  offset, (int)var_name->len, var_name->str); +  break;    } -  +  case 1: /* type */ +  fprintf(stderr, "Variable type entry:\n" +  " offset: 0x%04x Type constant #%d\n", +  offset, strno); +  break; +  default: +  fprintf(stderr, "Unknown entry #%d\n" +  " offset: 0x%04x Number: 0x%08x\n", +  kind, offset, (kind > 0)?strno:0); +  break; +  } +  } +  } +  if (cnt >= Pike_compiler->new_program->linenumbers + +  Pike_compiler->new_program->num_linenumbers) break; +  } +  if (cnt >= Pike_compiler->new_program->linenumbers + +  Pike_compiler->new_program->num_linenumbers) break;    off+=get_small_number(&cnt);    line+=get_small_number(&cnt);    if (a_flag > 100) {    fprintf(stderr, " off: %d, line: %ld\n"    " raw: ",    off, (long)line);    for (;start < cnt; start++) {    fprintf(stderr, "%02x ", *((unsigned char *)start));    }    fprintf(stderr, "\n");
pike.git/src/program.c:7992:    insert_small_number(store_prog_string(current_file));    copy_shared_string(Pike_compiler->last_file, current_file);    }    insert_small_number((INT32)(PIKE_PC-Pike_compiler->last_pc));    insert_small_number(current_line-Pike_compiler->last_line);    Pike_compiler->last_line = current_line;    Pike_compiler->last_pc = (INT32)PIKE_PC;    }   }    + void store_linenumber_local_name(int local_num, int string_num) + { +  add_to_linenumbers(127); +  insert_small_number(~local_num); +  add_to_linenumbers(0); +  insert_small_number(string_num); + } +  + void store_linenumber_local_type(int local_num, int constant_num) + { +  add_to_linenumbers(127); +  insert_small_number(~local_num); +  add_to_linenumbers(1); +  insert_small_number(constant_num); + } +  + void store_linenumber_local_end(int local_num) + { +  add_to_linenumbers(127); +  insert_small_number(~local_num); +  add_to_linenumbers(-1); + } +    #define FIND_PROGRAM_LINE(prog, file, line) do { \    char *pos = prog->linenumbers; \    file = NULL; \    \    if (pos < prog->linenumbers + prog->num_linenumbers) { \    if (*pos == 127) { \    int strno; \    pos++; \    strno = get_small_number(&pos); \    CHECK_FILE_ENTRY (prog, strno); \
pike.git/src/program.c:8147:    if (!res) {    struct pike_string *dash;    REF_MAKE_CONST_STRING(dash, "-");    return dash;    }    return res;   }      PMOD_EXPORT struct pike_string *low_get_line (PIKE_OPCODE_T *pc,    struct program *prog, -  INT_TYPE *linep) +  INT_TYPE *linep, +  struct local_variable_info *vars)   {    linep[0] = 0;       if (prog->program && prog->linenumbers) {    ptrdiff_t offset = pc - prog->program;    if ((offset < (ptrdiff_t)prog->num_program) && (offset >= 0)) {    static struct pike_string *file = NULL; -  +  static struct pike_string *next_file = NULL;    static char *base, *cnt;    static ptrdiff_t off;    static INT32 pid;    static INT_TYPE line; -  +  static struct local_variable_info frame;       if(prog->linenumbers == base && prog->id == pid && offset > off &&    cnt < prog->linenumbers + prog->num_linenumbers)    goto fromold;       base = cnt = prog->linenumbers;    off=line=0;    pid=prog->id;    file = 0; -  +  frame.num_local = 0;       while(cnt < prog->linenumbers + prog->num_linenumbers)    {    if(*cnt == 127)    {    int strno;    cnt++;    strno = get_small_number(&cnt); -  +  if (strno >= 0) {    CHECK_FILE_ENTRY (prog, strno); -  file = prog->strings[strno]; +  next_file = prog->strings[strno]; +  } else { +  int local_num = ~strno; +  int kind = *((signed char *)cnt++); +  if (kind >= 0) { +  strno = get_small_number(&cnt); +  } +  if (local_num < MAX_LOCAL) { +  frame.num_local = local_num + 1; +  switch(kind) { +  case -1: /* end */ +  frame.num_local = local_num; +  break; +  case 0: /* name */ +  frame.names[local_num] = strno; +  break; +  case 1: /* type */ +  frame.types[local_num] = strno; +  break; + #ifdef PIKE_DEBUG +  default: +  Pike_fatal("Unknown linenumber entry: %d\n", kind); +  break; + #endif +  } + #ifdef PIKE_DEBUG +  } else { +  Pike_fatal("Local variable out of range: %d\n", local_num); + #endif +  } +  }    continue;    }    off+=get_small_number(&cnt);    fromold:    if(off > offset) break;    line+=get_small_number(&cnt); -  +  file = next_file;    }    if (cnt >= prog->linenumbers + prog->num_linenumbers) {    /* We reached the end of the table. Make sure    * we get in sync again next time we're called.    */    base = NULL;    }    linep[0]=line; -  +  if (vars) *vars = frame;    if (file) {    add_ref(file);    return file;    }    } else {    fprintf(stderr, "Bad offset: pc:%p program:%p (%p)\n",    pc, prog->program, (void *)prog->num_program);    }    } else {    fprintf(stderr, "No program of linenumbers program:%p linenumbers:%p\n",
pike.git/src/program.c:8228:    ptrdiff_t offset = pc - prog->program;       if ((offset < (ptrdiff_t)prog->num_program) && (offset >= 0)) {    char *cnt = prog->linenumbers;    INT32 off = 0;    INT_TYPE line = 0;    struct pike_string *file = NULL;       while(cnt < prog->linenumbers + prog->num_linenumbers)    { -  if(*cnt == 127) +  while(*cnt == 127)    {    int strno;    cnt++;    strno = get_small_number(&cnt); -  +  if (strno >= 0) {    CHECK_FILE_ENTRY (prog, strno);    file = prog->strings[strno]; -  +  } else { +  int frame_offset = ~strno; +  int kind = *(cnt++); +  strno = (kind < 0)?-1:get_small_number(&cnt);    } -  +  }    off+=get_small_number(&cnt);    if(off > offset) break;    line+=get_small_number(&cnt);    }    linep[0]=line;       if (file)    return make_plain_file(file, malloced);    }    }
pike.git/src/program.c:8288:   {    struct pike_string *res;       if (prog == 0) {    struct pike_string *unknown_program;    REF_MAKE_CONST_STRING(unknown_program, "Unknown program");    linep[0] = 0;    return unknown_program;    }    -  res = low_get_line(pc, prog, linep); +  res = low_get_line(pc, prog, linep, NULL);    if (!res) {    struct pike_string *not_found;    REF_MAKE_CONST_STRING(not_found, "Line not found");    return not_found;    }    return res;   }      PMOD_EXPORT struct pike_string *low_get_function_line (struct object *o,    int fun,
pike.git/src/program.c:8320:    if (!IDENTIFIER_IS_ALIAS(id->identifier_flags)) break;    loc.o = o;    loc.inherit = INHERIT_FROM_INT(o->prog, fun);    loc.parent_identifier = fun;    find_external_context(&loc, id->func.ext_ref.depth);    fun = id->func.ext_ref.id + loc.inherit->identifier_level;    o = loc.o;    }    if (IDENTIFIER_IS_PIKE_FUNCTION(id->identifier_flags) &&    (id->func.offset != -1)) -  return low_get_line (p->program + id->func.offset, p, linep); +  return low_get_line (p->program + id->func.offset, p, linep, NULL);    if ((ret = get_identifier_line(o->prog, fun, linep))) {    add_ref(ret);    return ret;    }    return low_get_program_line(o->prog, linep);    }    *linep = 0;    return NULL;   }   
pike.git/src/program.c:8432:    MAKE_CONST_STRING(this_program_string,"this_program");    MAKE_CONST_STRING(this_string,"this");    MAKE_CONST_STRING(UNDEFINED_string,"UNDEFINED");    MAKE_CONST_STRING(args_string, "__args__");       MAKE_CONST_STRING(parser_system_string, "parser");    MAKE_CONST_STRING(type_check_system_string, "type_check");       MAKE_CONST_STRING(compat_lfun_destroy_string, "destroy");    -  lfun_ids = allocate_mapping(NUM_LFUNS); -  lfun_types = allocate_mapping(NUM_LFUNS); +  /* NB: One extra entry needed for lfun::destroy(). */ +  lfun_ids = allocate_mapping(NUM_LFUNS + 1); +  lfun_types = allocate_mapping(NUM_LFUNS + 1);    for (i=0; i < NELEM(lfun_names); i++) {    lfun_strings[i] = make_shared_static_string(lfun_names[i], strlen(lfun_names[i]), eightbit);       SET_SVAL(id, T_INT, NUMBER_NUMBER, integer, i);    SET_SVAL(key, T_STRING, 0, string, lfun_strings[i]);    mapping_insert(lfun_ids, &key, &id);       SET_SVAL(val, T_TYPE, 0, type, make_pike_type(raw_lfun_types[i]));    mapping_insert(lfun_types, &key, &val); -  +  +  if (i == LFUN__DESTRUCT) { +  /* Special case for lfun::destroy(). */ +  SET_SVAL(key, T_STRING, 0, string, compat_lfun_destroy_string); +  /* FIXME: Adjust the type to be __deprecated__? */ +  mapping_insert(lfun_types, &key, &val);    free_type(val.u.type); -  +  +  SET_SVAL(id, T_INT, NUMBER_NUMBER, integer, i); +  mapping_insert(lfun_ids, &key, &id); +  } else { +  free_type(val.u.type);    } -  +  }       lfun_getter_type_string = make_pike_type(tFuncV(tNone, tVoid, tMix));    lfun_setter_type_string = make_pike_type(tFuncV(tZero, tVoid, tVoid));    -  init_pike_compiler(); +  low_init_pike_compiler();       enter_compiler(NULL, 0);       exit_compiler();   }      void cleanup_program(void)   {    size_t e;   
pike.git/src/program.c:8503: Inside #if defined(DO_PIKE_CLEANUP)
   placeholder_object=0;    }       if(placeholder_program)    {    free_program(placeholder_program);    placeholder_program=0;    }   #endif    -  cleanup_pike_compiler(); +  low_cleanup_pike_compiler();   }         PMOD_EXPORT void visit_program (struct program *p, int action, void *extra)   {    visit_enter(p, T_PROGRAM, extra);    switch (action & VISIT_MODE_MASK) {   #ifdef PIKE_DEBUG    default:    Pike_fatal ("Unknown visit action %d.\n", action);
pike.git/src/program.c:8617:    for(e = p->num_constants - 1; e >= 0; e--)    gc_mark_svalues(& p->constants[e].sval, 1);       for(e = p->num_inherits - 1; e >= 0; e--)    {    if(p->inherits[e].parent)    gc_mark_object_as_referenced(p->inherits[e].parent);       if(e && p->inherits[e].prog)    gc_mark_program_as_referenced(p->inherits[e].prog); +  +  if (p->inherits[e].annotations) +  gc_mark_multiset_as_referenced(p->inherits[e].annotations);    }      #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP)    for (e = p->num_identifiers - 1; e >= 0; e--)    gc_mark_type_as_referenced (p->identifiers[e].type);   #endif    -  +  for (e = p->num_annotations-1; e >= 0; e--) { +  if (p->annotations[e]) +  gc_mark_multiset_as_referenced(p->annotations[e]); +  }    } GC_LEAVE;   }      void real_gc_cycle_check_program(struct program *p, int weak)   {    GC_CYCLE_ENTER(p, T_PROGRAM, weak) {    int e;       if (!(p->flags & PROGRAM_AVOID_CHECK))    {    for(e = p->num_constants - 1; e >= 0; e--)    gc_cycle_check_svalues(& p->constants[e].sval, 1);       for(e = p->num_inherits - 1; e >= 0; e--)    {    if(p->inherits[e].parent)    gc_cycle_check_object(p->inherits[e].parent, 0);       if(e && p->inherits[e].prog)    gc_cycle_check_program(p->inherits[e].prog, 0); -  +  +  if (p->inherits[e].annotations) +  gc_cycle_check_multiset(p->inherits[e].annotations, 0);    }    -  +  for (e = p->num_annotations - 1; e >= 0; e--) { +  if (p->annotations[e]) +  gc_cycle_check_multiset(p->annotations[e], 0); +  } +     /* Strong ref follows. It must be last. */    if(p->parent)    gc_cycle_check_program(p->parent, 0);    }    } GC_CYCLE_LEAVE;   }      static void gc_check_program(struct program *p)   {    int e;
pike.git/src/program.c:8690:    " as inherited parent object of a program");    }      #ifdef PIKE_DEBUG    if (Pike_in_gc == GC_PASS_LOCATE && p->inherits[e].name)    debug_gc_check (p->inherits[e].name, " as inherit name");   #endif       if(e && p->inherits[e].prog)    debug_gc_check (p->inherits[e].prog, " as inherited program of a program"); +  +  if (p->inherits[e].annotations) +  debug_gc_check(p->inherits[e].annotations, +  " as annotations for an inherit");    }      #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP)    if (gc_keep_markers || Pike_in_gc == GC_PASS_LOCATE)    {    for(e = p->num_strings - 1; e >= 0; e--)    debug_gc_check (p->strings[e], " in the string storage of a program");    for(e = p->num_identifiers - 1; e >= 0; e--)    debug_gc_check (p->identifiers[e].name,    " as identifier name in a program");    }       for(e = p->num_identifiers - 1; e >= 0; e--)    debug_gc_check (p->identifiers[e].type,    " as identifier type in a program");   #endif    -  +  for (e = p->num_annotations - 1; e >= 0; e--) { +  if (p->annotations[e]) +  debug_gc_check(p->annotations[e], " as annotations in a program"); +  }    } GC_LEAVE;   }      unsigned gc_touch_all_programs(void)   {    unsigned n = 0;    struct program *p;    if (first_program && first_program->prev)    Pike_fatal("Error in program link list.\n");    for (p = first_program; p; p = p->next) {
pike.git/src/program.c:8802:    if(p->inherits[e].parent)    {    free_object(p->inherits[e].parent);    p->inherits[e].parent=0;    }    if(e && p->inherits[e].prog)    {    free_program(p->inherits[e].prog);    p->inherits[e].prog=0;    } +  +  if (p->inherits[e].annotations) { +  free_multiset(p->inherits[e].annotations); +  p->inherits[e].annotations = NULL;    } -  +  }    -  +  for (e = 0; e < p->num_annotations; e++) { +  do_free_multiset(p->annotations[e]); +  p->annotations[e] = NULL; +  } +     gc_free_extra_ref(p);    SET_NEXT_AND_FREE(p, free_program);   #ifdef PIKE_DEBUG    if (first) gc_internal_program = next;   #endif    }else{    next=p->next;   #ifdef PIKE_DEBUG    first = 0;   #endif
pike.git/src/program.c:8976:    }       return id_to_program((int)(ptrdiff_t)t->cdr);   }      /* NOTE: Does not add references to the return value! */   PMOD_EXPORT struct program *low_program_from_svalue(const struct svalue *s,    struct object **parent_obj,    int *parent_id)   { +  while(s) {    switch(TYPEOF(*s))    {    case T_OBJECT:    {    struct program *p = s->u.object->prog;   #if 0    int call_fun;   #endif       if (!p) return 0;
pike.git/src/program.c:9014:    if (SUBTYPEOF(*s) == FUNCTION_BUILTIN) return 0;    return low_program_from_function(*parent_obj = s->u.object,    *parent_id = SUBTYPEOF(*s));       case T_PROGRAM:    return s->u.program;       case PIKE_T_TYPE:    return program_from_type(s->u.type);    +  case PIKE_T_ARRAY: +  if (!s->u.array->size) break; +  /* Return result for the last element of the array. +  * +  * This is compatible with the corresponding behavior for inherit. +  */ +  s = ITEM(s->u.array) + s->u.array->size - 1; +  continue; +     default: -  return 0; +  break;    } -  +  +  break;    }    -  +  return NULL; + } +    /* NOTE: Does not add references to the return value! */   PMOD_EXPORT struct program *program_from_svalue(const struct svalue *s)   {    struct object *parent_obj = NULL;    int parent_id = -1;    return low_program_from_svalue(s, &parent_obj, &parent_id);   }      #define FIND_CHILD_HASHSIZE 5003   struct find_child_cache_s