pike.git / src / program.c

version» Context lines:

pike.git/src/program.c:19:   #include "interpret.h"   #include "main.h"   #include "pike_memory.h"   #include "gc.h"   #include "threads.h"   #include "constants.h"   #include "operators.h"   #include "builtin_functions.h"   #include "mapping.h"   #include "cyclic.h" - #include "pike_types.h" +    #include "opcodes.h"   #include "version.h"   #include "block_allocator.h"   #include "block_alloc.h"   #include "pikecode.h"   #include "pike_compiler.h"   #include "module_support.h"   #include "bitvector.h"   #include "sprintf.h"      #include <errno.h>   #include <fcntl.h>    - #define sp Pike_sp -  -  +    static void exit_program_struct(struct program *);   static size_t add_xstorage(size_t size,    size_t alignment,    ptrdiff_t modulo_orig);      /* mapping(int:string) */   static struct mapping *reverse_symbol_table = NULL;      static struct block_allocator program_allocator = BA_INIT_PAGES(sizeof(struct program), 4);   
pike.git/src/program.c:118:   #include "compilation.h"      struct pike_string *this_program_string, *this_string, *args_string;   static struct pike_string *this_function_string;   static struct pike_string *UNDEFINED_string;      /* Common compiler subsystems */   struct pike_string *parser_system_string;   struct pike_string *type_check_system_string;    + struct pike_string *compat_lfun_destroy_string; +    /* NOTE: There is a corresponding list to this one in    Tools.AutoDoc.PikeObjects       If new lfuns are added it might be beneficial to also add them to    that list.   */   const char *const lfun_names[] = {    "__INIT",    "create", -  "destroy", +  "_destruct",    "`+",    "`-",    "`&",    "`|",    "`^",    "`<<",    "`>>",    "`*",    "`/",    "`%",
pike.git/src/program.c:192:   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[] = {    tFuncV(tNone,tVoid,tVoid), /* "__INIT", */    tFuncV(tNone,tZero,tVoid), /* "create", */ -  tFuncV(tOr(tVoid,tInt),tVoid,tVoid), /* "destroy", */ +  tFuncV(tOr(tVoid,tInt),tVoid,tVoid), /* "_destruct", */    tFuncV(tZero,tZero,tMix), /* "`+", */    tFunc(tOr(tVoid,tZero),tMix), /* "`-", */    tFuncV(tNone,tZero,tMix), /* "`&", */    tFuncV(tNone,tZero,tMix), /* "`|", */    tFuncV(tNone,tZero,tMix), /* "`^", */    tFuncV(tZero,tVoid,tMix), /* "`<<", */    tFuncV(tZero,tVoid,tMix), /* "`>>", */    tFuncV(tNone,tZero,tMix), /* "`*", */    tFuncV(tNone,tZero,tMix), /* "`/", */    tFuncV(tNone,tZero,tMix), /* "`%", */
pike.git/src/program.c:240:    tFuncV(tInt tOr(tMap(tStr,tInt),tVoid),tVoid,tStr), /* "_sprintf", */    tFuncV(tMix,tVoid,tInt), /* "_equal", */    tFuncV(tZero,tVoid,tMix), /* "_m_delete", */    tFuncV(tNone,tVoid,tObj), /* "_get_iterator", */    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(tZero, tVoid, tInt), /* "_size_object", */ +  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* */   };      /* 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.    *!    *! The functions can be grouped into a few sets:    *!    *! @ul    *! @item    *! Object initialization and destruction.    *! -  *! @[__INIT()], @[create()], @[destroy()] +  *! @[__INIT()], @[create()], @[_destruct()]    *!    *! @item    *! Unary operator overloading.    *!    *! @[`~()], @[`!()],    *! @[_values()], @[cast()],    *! @[_sizeof()], @[_indices()],    *! @[__hash()]    *!    *! @item
pike.git/src/program.c:354:    *!    *! @note    *! This function can be created implicitly    *! by the compiler using the syntax:    *! @code    *! class Foo(int foo) {    *! int bar;    *! }    *! @endcode    *! In the above case an implicit @[lfun::create()] is created, and -  *! it's equvivalent to: +  *! it's equivalent to:    *! @code    *! class Foo {    *! int foo;    *! int bar;    *! protected void create(int foo)    *! {    *! this::foo = foo;    *! }    *! }    *! @endcode    *!    *! @seealso -  *! @[lfun::__INIT()], @[lfun::destroy()] +  *! @[lfun::__INIT()], @[lfun::_destruct()]    */    - /*! @decl void lfun::destroy (void|int reason) + /*! @decl void lfun::_destruct (void|int reason)    *!    *! Object destruction callback.    *!    *! This function is called right before the object is destructed.    *! That can happen either through a call to @[predef::destruct()],    *! when there are no more references to the object, or when the    *! garbage collector discovers that it's part of a cyclic data    *! structure that has become garbage.    *!    *! @param reason
pike.git/src/program.c:399:    *! Destructed by the garbage collector.    *! @value Object.DESTRUCT_CLEANUP    *! Destructed as part of the cleanup when the pike process    *! exits. Occurs only if Pike has been compiled with the    *! configure option @tt{--with-cleanup-on-exit@}. See note    *! below.    *! @endint    *!    *! @note    *! Objects are normally not destructed when a process exits, so -  *! @expr{destroy@} functions aren't called then. Use @[atexit] to get +  *! @expr{_destruct@} functions aren't called then. Use @[atexit] to get    *! called when the process exits.    *!    *! @note    *! Regarding destruction order during garbage collection:    *!    *! If an object is destructed by the garbage collector, it's part of    *! a reference cycle with other things but with no external -  *! references. If there are other objects with @expr{destroy@} +  *! references. If there are other objects with @expr{_destruct@}    *! functions in the same cycle, it becomes a problem which to call    *! first.    *!    *! E.g. if this object has a variable with another object which    *! (directly or indirectly) points back to this one, you might find    *! that the other object already has been destructed and the variable    *! thus contains zero.    *!    *! The garbage collector tries to minimize such problems by defining    *! an order as far as possible:    *!    *! @ul    *! @item -  *! If an object A contains an @[lfun::destroy] and an object B does +  *! If an object A contains an @[lfun::_destruct] and an object B does    *! not, then A is destructed before B.    *! @item    *! If A references B single way, then A is destructed before B.    *! @item    *! If A and B are in a cycle, and there is a reference somewhere    *! from B to A that is weaker than any reference from A to B, then    *! A is destructed before B.    *! @item    *! If a cycle is resolved according to the rule above by ignoring a    *! weaker reference, and there is another ambiguous cycle that
pike.git/src/program.c:452:    *! destructs a parent object before all children have been    *! destructed.)    *! @endul    *!    *! An example with well defined destruct order due to strong    *! references:    *!    *! @code    *! class Super {    *! class Sub { -  *! protected void destroy() { +  *! protected void _destruct() {    *! if (!Super::this)    *! error ("My parent has been destructed!\n");    *! }    *! }    *! Sub sub = Sub(); -  *! protected void destroy() { +  *! protected void _destruct() {    *! if (!sub)    *! werror ("sub already destructed.\n");    *! }    *! }    *! @endcode    *!    *! The garbage collector ensures that these objects are destructed in    *! an order so that @expr{werror@} in @expr{Super@} is called and not    *! @expr{error@} in @expr{Sub@}.    *!    *! @note -  *! When the garbage collector calls @[lfun::destroy], all accessible -  *! non-objects and objects without @expr{destroy@} functions are -  *! still intact. They are not freed if the @expr{destroy@} function +  *! When the garbage collector calls @[lfun::_destruct], all accessible +  *! non-objects and objects without @expr{_destruct@} functions are +  *! still intact. They are not freed if the @expr{_destruct@} function    *! adds external references to them. However, all objects with -  *! @[lfun::destroy] in the cycle are already scheduled for +  *! @[lfun::_destruct] in the cycle are already scheduled for    *! destruction and will therefore be destroyed even if external    *! references are added to them.    *!    *! @seealso    *! @[lfun::create()], @[predef::destruct()]    */      /*! @decl mixed lfun::`+(zero arg, zero ... rest)    *!    *! Left side addition/concatenation callback.
pike.git/src/program.c:833:    *!    *! @seealso    *! @[predef::`>()]    */      /*! @decl int lfun::__hash()    *!    *! Hashing callback.    *!    *! The main caller of this function is @[predef::hash_value()] -  *! or the low-level equvivalent, which get called by various +  *! or the low-level equivalent, which get called by various    *! mapping operations when the object is used as index in a mapping.    *!    *! @returns    *! It should return an integer that corresponds to the object    *! in such a way that all values which @[lfun::`==] considers    *! equal to the object get the same hash value.    *!    *! @note    *! The function @[predef::hash] does not return hash values that    *! are compatible with this one.
pike.git/src/program.c:1658:    PIKE_CONCAT(low_add_to_,NAME) ( Pike_compiler, ARG ); \   }      /* Funny guys use the uppermost value for nonexistant variables and    the like. Hence -2 and not -1. Y2K. */   #define PASS1ONLY(NUMTYPE,TYPE,ARGTYPE,NAME) \   void PIKE_CONCAT(low_add_to_,NAME) (struct program_state *state, \    TYPE ARG) { \    NUMTYPE m = state->malloc_size_program->PIKE_CONCAT(num_,NAME); \    CHECK_FOO(NUMTYPE,TYPE,NAME); \ -  DO_IF_DEBUG(if (state->compiler_pass != 1) { \ +  DO_IF_DEBUG(if (state->compiler_pass != COMPILER_PASS_FIRST) { \    Pike_fatal("Adding " TOSTR(NAME) " in pass %d.\n", \    state->compiler_pass); \    }); \    if(m == state->new_program->PIKE_CONCAT(num_,NAME)) { \    TYPE *tmp; \    if(m==MAXVARS(NUMTYPE)) { \    yyerror("Too many " #NAME "."); \    return; \    } \    m = MINIMUM(m*2+1,MAXVARS(NUMTYPE)); \
pike.git/src/program.c:1724: Inside #if 0
   Pike_compiler->new_program->identifiers[i].linenumber,    i);    }    }    add_to_identifiers (id);   }   #else   #define debug_add_to_identifiers(ARG) add_to_identifiers(ARG)   #endif    - static void add_identifier(struct compilation *c, + static int low_add_identifier(struct compilation *c,    struct pike_type *type,    struct pike_string *name,    unsigned int identifier_flags,    unsigned int opt_flags,    union idptr func,    int run_time_type)   {    struct identifier dummy; -  +  int n = Pike_compiler->new_program->num_identifiers; +     copy_shared_string(dummy.name, name);    copy_pike_type(dummy.type, type);    dummy.filename_strno = store_prog_string(c->lex.current_file);    dummy.linenumber = c->lex.current_line;    dummy.identifier_flags = identifier_flags;    dummy.run_time_type = run_time_type;    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); -  +  +  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, +  int run_time_type) + { +  struct reference ref; +  struct identifier dummy; +  int n; +  +  if (modifier_flags & ID_PRIVATE) modifier_flags |= ID_LOCAL|ID_PROTECTED; +  +  if (((identifier_flags & (IDENTIFIER_VARIABLE|IDENTIFIER_ALIAS)) == +  IDENTIFIER_VARIABLE) && +  (modifier_flags & ID_WEAK)) { +  identifier_flags |= IDENTIFIER_WEAK; +  } +  +  ref.id_flags = modifier_flags; +  ref.identifier_offset = +  low_add_identifier(c, type, name, +  identifier_flags, opt_flags, +  func, run_time_type); +  ref.inherit_offset = 0; +  ref.run_time_type = PIKE_T_UNKNOWN; +  +  if ((identifier_flags & (IDENTIFIER_VARIABLE|IDENTIFIER_ALIAS)) == +  IDENTIFIER_VARIABLE) { +  add_to_variable_index(ref.identifier_offset); +  } +  +  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);   }      void use_module(struct svalue *s)   {    struct compilation *c = THIS_COMPILATION;    if( (1<<TYPEOF(*s)) & (BIT_MAPPING | BIT_OBJECT | BIT_PROGRAM))
pike.git/src/program.c:1846:    {    push_svalue(m+e);    ref_push_string(ident);    f_index(2);       if(!IS_UNDEFINED(Pike_sp-1))    {    struct node_s *ret;    UNSETJMP(tmp);    -  if (Pike_compiler->compiler_pass == 2 && +  if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST &&    ((TYPEOF(Pike_sp[-1]) == T_OBJECT &&    Pike_sp[-1].u.object == placeholder_object) ||    (TYPEOF(Pike_sp[-1]) == T_PROGRAM &&    Pike_sp[-1].u.program == placeholder_program))) {    my_yyerror("Got placeholder %s (resolver problem) "    "when indexing a module with %S.",    get_name_of_type (TYPEOF(Pike_sp[-1])), ident);    ret = 0;    }    else {    if(!*module_index_cache)    *module_index_cache = allocate_mapping(10);    mapping_string_insert(*module_index_cache, ident, Pike_sp-1);    ret = mksvaluenode(Pike_sp-1); - #if 0 && defined (COMPILER_DEBUG) -  safe_pike_fprintf (stderr, "Index %S: %O\n", ident, Pike_sp - 1); - #endif +     }    pop_stack();    return ret;    }    pop_stack();    }    }    UNSETJMP(tmp);    }    - #if 0 && defined (COMPILER_DEBUG) -  safe_pike_fprintf (stderr, "Index %S: undefined\n", ident); - #endif +        return 0;   }      struct node_s *resolve_identifier(struct pike_string *ident);      struct node_s *find_module_identifier(struct pike_string *ident,    int see_inherit)   {    struct compilation *c = THIS_COMPILATION;
pike.git/src/program.c:1905:    {    int i;    if(see_inherit)    {    i=really_low_find_shared_string_identifier(ident,    p->new_program,    SEE_PROTECTED|SEE_PRIVATE);    if(i!=-1)    {    if ((p->flags & COMPILATION_FORCE_RESOLVE) && -  (p->compiler_pass == 2) && +  (p->compiler_pass == COMPILER_PASS_LAST) &&    ((p->num_inherits + 1) < p->new_program->num_inherits) &&    (PTR_FROM_INT(p->new_program, i)->inherit_offset >    p->num_inherits)) {    /* Don't look up symbols inherited later, since we need to get    * the same symbol in both passes in the force_resolve mode.    */    continue;    }    return p == Pike_compiler ?    mkidentifiernode(i) :
pike.git/src/program.c:1952:    add_ref(ret->name = ident);    free_node(tmp);    return ret;   }      /*! @decl constant UNDEFINED    *!    *! The undefined value; ie a zero for which @[zero_type()] returns 1.    */    - struct node_s *resolve_identifier(struct pike_string *ident) + int low_resolve_identifier(struct pike_string *ident)   {    struct compilation *c = THIS_COMPILATION;    node *ret = NULL;       /* Handle UNDEFINED */    if (ident == UNDEFINED_string) { -  return mkconstantsvaluenode(&svalue_undefined); +  push_undefined(); +  return 1;    }       if(c->resolve_cache)    {    struct svalue *tmp=low_mapping_string_lookup(c->resolve_cache,ident);    if(tmp)    { -  if(!IS_UNDEFINED (tmp)) -  return mkconstantsvaluenode(tmp); -  +  if(IS_UNDEFINED (tmp)) {    return 0;    } -  +  +  push_svalue(tmp); +  return 1;    } -  +  }       CHECK_COMPILER();       ref_push_string(ident); -  ref_push_string(c->lex.current_file); -  if (c->handler) { -  ref_push_object(c->handler); -  } else { -  push_int(0); -  } -  if (!safe_apply_current2(PC_RESOLV_FUN_NUM, 3, NULL)) +  if (!safe_apply_current2(PC_RESOLV_FUN_NUM, 1, NULL))    handle_compile_exception ("Error resolving '%S'.", ident);    -  if (Pike_compiler->compiler_pass != 2) { +  if (Pike_compiler->compiler_pass != COMPILER_PASS_LAST) {    /* If we get a program that hasn't gone through pass 1 yet then we    * have to register a dependency now in our pass 1 so that our    * pass 2 gets delayed. Otherwise the other program might still be    * just as unfinished when we come back here in pass 2. */    struct program *p = NULL;    if (TYPEOF(Pike_sp[-1]) == T_PROGRAM)    p = Pike_sp[-1].u.program;    else if (TYPEOF(Pike_sp[-1]) == T_OBJECT ||    (TYPEOF(Pike_sp[-1]) == T_FUNCTION &&    SUBTYPEOF(Pike_sp[-1]) != FUNCTION_BUILTIN))    p = Pike_sp[-1].u.object->prog;    if (p && !(p->flags & PROGRAM_PASS_1_DONE))    report_compiler_dependency (p);    }    -  if (Pike_compiler->compiler_pass == 2 && +  if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST &&    ((TYPEOF(Pike_sp[-1]) == T_OBJECT &&    Pike_sp[-1].u.object == placeholder_object) ||    (TYPEOF(Pike_sp[-1]) == T_PROGRAM &&    Pike_sp[-1].u.program == placeholder_program))) {    my_yyerror("Got placeholder %s (resolver problem) "    "when resolving '%S'.",    get_name_of_type (TYPEOF(Pike_sp[-1])), ident);    } else {    if(!c->resolve_cache)    c->resolve_cache=dmalloc_touch(struct mapping *, allocate_mapping(10));    mapping_string_insert(c->resolve_cache,ident,Pike_sp-1);       if(!IS_UNDEFINED (Pike_sp-1))    { -  ret=mkconstantsvaluenode(Pike_sp-1); +  return 1;    }    }    pop_stack();    -  +  return 0; + } +  + struct node_s *resolve_identifier(struct pike_string *ident) + { +  node *ret = NULL; +  +  if (low_resolve_identifier(ident)) { +  ret = mkconstantsvaluenode(Pike_sp-1); +  pop_stack(); +  }    return ret;   }      /**    * This function is intended to simplify resolving of    * program symbols during compile-time for C-modules.    *    * A typical use-case is for a C-module inheriting    * code written in Pike.    */   PMOD_EXPORT struct program *resolve_program(struct pike_string *ident)   {    struct program *ret = NULL; -  struct node_s *n = resolve_identifier(ident); -  if (n) { -  if ((n->token == F_CONSTANT) && (TYPEOF(n->u.sval) == T_PROGRAM) && -  (ret = n->u.sval.u.program)) { +  if (low_resolve_identifier(ident)) { +  if ((ret = program_from_svalue(Pike_sp-1))) {    add_ref(ret); -  } else { -  my_yyerror("Invalid program identifier '%S'.", ident); +     } -  free_node(n); -  } else { -  my_yyerror("Unknown program identifier '%S'.", ident); +  pop_stack();    } -  +  if (!ret) { +  my_yyerror("Invalid program identifier '%S'.", ident); +  }    return ret;   }      /**    * Find the identifier named ident in inherit #inh in the lexical scope    * given by inherit_state and inherit_depth.    *    * @param inherit_state    * The program state for the program where the inherit is found.    *
pike.git/src/program.c:2379:    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... */    id = really_low_find_shared_string_identifier(lfun_strings[LFUN_ARROW],    prog,    SEE_PROTECTED|SEE_PRIVATE);    } else if ((id != -1) && (prog != state->new_program)) {    id = really_low_reference_inherited_identifier(state, i, id);    } -  if ((id != -1) && (state->compiler_pass == 2)) { +  if ((id != -1) && (state->compiler_pass == COMPILER_PASS_LAST)) {    if (inherit_num < 0) {    /* Find the closest inherit containing the lfun::`->()    * that is about to be called.    *    * In the single inherit case, this will always    * result in inherit_num == 1.    */    struct inherit *inherits = state->new_program->inherits;    inherit_num = PTR_FROM_INT(state->new_program, id)->inherit_offset;    while (inherits[inherit_num].inherit_level > 1) {
pike.git/src/program.c:2729:   #endif   #endif       sub_ref = PTR_FROM_INT(inh->prog, cur_id - inh->identifier_level);       /* Check if the symbol was used before it was inherited. */    if ((c->lex.pragmas & ID_STRICT_TYPES) &&    (sub_ref->id_flags & ID_USED)) {    struct identifier *sub_id = ID_FROM_PTR(inh->prog, sub_ref);    if (IDENTIFIER_IS_FUNCTION(sub_id->identifier_flags)) { -  if ((Pike_compiler->compiler_pass == 2) && +  if ((Pike_compiler->compiler_pass == COMPILER_PASS_LAST) &&    !pike_types_le(ID_FROM_PTR(Pike_compiler->new_program,    new_ref)->type, sub_id->type)) {    yytype_report(REPORT_WARNING,    NULL, 0, sub_id->type,    NULL, 0, ID_FROM_PTR(Pike_compiler->new_program,    new_ref)->type,    0, "Type mismatch when overloading function %S.",    name);    }    } else {
pike.git/src/program.c:2944:    if (ref->id_flags & ID_HIDDEN) continue;    if (ref->id_flags & ID_VARIANT) continue;    if (ref->inherit_offset != 0) continue;       if ((ref->id_flags & (ID_HIDDEN|ID_PRIVATE|ID_USED)) == ID_PRIVATE) {    yywarning("%S is private but not used anywhere.",    ID_FROM_PTR(p, ref)->name);    }    }    -  /* Set the PROGRAM_LIVE_OBJ flag by looking for destroy() and +  /* Set the PROGRAM_LIVE_OBJ flag by looking for _destruct() and    * inherited PROGRAM_LIVE_OBJ flags. This is done at fixation time    * to allow the user to set and clear that flag while the program is    * being built. */    if (!(p->flags & PROGRAM_LIVE_OBJ)) { -  int e, destroy = p->lfuns[LFUN_DESTROY]; -  if (destroy > -1) { -  struct identifier *id = ID_FROM_INT (p, destroy); +  int e, destruct = p->lfuns[LFUN__DESTRUCT]; +  if (destruct > -1) { +  struct identifier *id = ID_FROM_INT (p, destruct);    if (!IDENTIFIER_IS_PIKE_FUNCTION (id->identifier_flags) ||    id->func.offset != -1) { -  /* Got a destroy function that isn't a prototype. */ +  /* Got a _destruct function that isn't a prototype. */    p->flags |= PROGRAM_LIVE_OBJ;    goto program_live_obj_set;    }    }       for (e = p->num_inherits - 1; e >= 0; e--)    if (p->inherits[e].prog->flags & PROGRAM_LIVE_OBJ) {    p->flags |= PROGRAM_LIVE_OBJ;    break;    }
pike.git/src/program.c:3063:    }    dmalloc_set_mmap_template(Pike_compiler->new_program, m);    }   #endif   }      struct program *low_allocate_program(void)   {    struct program *p=alloc_program();    memset(p, 0, sizeof(struct program)); +  gc_init_marker(p);    p->flags|=PROGRAM_VIRGIN;    p->alignment_needed=1;       GC_ALLOC(p);    p->id=++current_program_id;    INIT_PIKE_MEMOBJ(p, T_PROGRAM);       DOUBLELINK(first_program, p);    ACCURATE_GETTIMEOFDAY(& p->timestamp);    return p;
pike.git/src/program.c:3118: Inside #if 0
   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{    tmp.u.program=p;    add_ref(p); -  if((pass == 2) && name) +  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);    i->type=get_type_of_svalue(&tmp);    }    } -  if (pass == 1) { +  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",
pike.git/src/program.c:3371:       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",    (long)th_self(), (long)line, file,    lock_depth, c->compilation_depth);    -  low_start_new_program(0,1,0,0,0); +  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;   }         static void exit_program_struct(struct program *p)
pike.git/src/program.c:4211:    id = ID_FROM_INT(prog, j);    id_flags |= ref->id_flags;    opt_flags |= id->opt_flags;    /* NB: The dispatcher needs the variant references to    * not get overloaded for the ::-operator to work.    */    ref->id_flags |= ID_LOCAL;    if (type)    {    struct pike_type * temp = type; -  if ((Pike_compiler->compiler_pass == 2) && !ref->inherit_offset && +  if ((Pike_compiler->compiler_pass == COMPILER_PASS_LAST) && +  !ref->inherit_offset &&    !check_variant_overload(id->type, type)) {    /* This symbol is shadowed by later variants. */    yytype_report(REPORT_WARNING,    NULL, 0, NULL,    Pike_compiler->new_program->strings[id->filename_strno],    id->linenumber, id->type,    0, "Function %S() masked by later variant.",    name);    ref_push_type_value(type);    low_yyreport(REPORT_WARNING,
pike.git/src/program.c:4277:    {    Pike_compiler->init_node=mknode(F_COMMA_EXPR,    mkcastnode(void_type_string,    mkapplynode(mkidentifiernode(id),0)),    Pike_compiler->init_node);    }    }    }       if (finish == 1) { -  if (Pike_compiler->compiler_pass == 1) { +  if (Pike_compiler->compiler_pass == COMPILER_PASS_FIRST) {    /* Called from end_program(). */    if (Pike_compiler->init_node) {    /* Make sure that the __INIT symbol exists, so that    * we won't get a fatal when we add the actual code    * 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);    }    } -  Pike_compiler->compiler_pass = 2; +  Pike_compiler->compiler_pass = COMPILER_PASS_LAST;    }       /*    * Define the __INIT function, but only if there was any code    * to initialize.    */       if(Pike_compiler->init_node)    {    /* Inhibit this_function. */
pike.git/src/program.c:4403:       toss_compilation_resources();      #if 0    CDFPRINTF("th(%ld) end_first_pass(): "    "%p compilation_depth:%d, Pike_compiler->compiler_pass:%d\n",    (long)th_self(), prog,    c->compilation_depth, Pike_compiler->compiler_pass);   #endif    -  if(!Pike_compiler->compiler_frame && (Pike_compiler->compiler_pass==2 || !prog) && c->resolve_cache) +  if(!Pike_compiler->compiler_frame && +  (Pike_compiler->compiler_pass == COMPILER_PASS_LAST || !prog) && +  c->resolve_cache)    {    free_mapping(dmalloc_touch(struct mapping *, c->resolve_cache));    c->resolve_cache=0;    }    - #ifdef SHARED_NODES -  /* free(node_hash.table); */ - #endif /* SHARED_NODES */ -  +    #define POP   #include "compilation.h"       exit_type_stack();          CDFPRINTF("th(%ld) %p end_first_pass(%d): "    "lock_depth:%d, compilation_depth:%d\n",    (long)th_self(), prog, finish,    lock_depth, c->compilation_depth);
pike.git/src/program.c:4569:   static void add_compat_event_handler(void)   {    if(Pike_compiler->new_program->event_handler != compat_event_handler)    {    unsigned int e,d;    unsigned char *tmp=(unsigned char *)&Pike_compiler->new_program->event_handler;       for(d=0;d<NUM_PROG_EVENTS;d++) {    /* FIXME: This looks like it might be broken. */    /* Broken how? -Hubbe */ - #ifdef HAVE_COMPUTED_GOTO -  add_to_program(Pike_compiler->new_program->event_handler); - #else /* !HAVE_COMPUTED_GOTO */ +     for(e=0;e<sizeof(Pike_compiler->new_program->event_handler);e++)    add_to_program(tmp[e]); - #endif /* HAVE_COMPUTED_GOTO */ +     }    Pike_compiler->new_program->event_handler=compat_event_handler;    }   }      /**    * Set a callback to be called when this program is cloned.    *    * This function is obsolete; see pike_set_prog_event_callback for    * details.
pike.git/src/program.c:4753:   {    struct program *np=(q?q:Pike_compiler)->new_program;    struct reference funp;    struct program *p;    int d, num_id_refs;       if(f==-1) return -1;       p = np->inherits[i].prog;    -  if ((q?q:Pike_compiler)->compiler_pass == 2) { +  if ((q?q:Pike_compiler)->compiler_pass == COMPILER_PASS_LAST) {    struct identifier *id = ID_FROM_INT(p, f);    if (((id->identifier_flags & IDENTIFIER_TYPE_MASK) ==    IDENTIFIER_PIKE_FUNCTION) && (id->func.offset == -1)) {    /* Prototype. */    return -1;    }    }       funp = p->identifier_references[f];    funp.inherit_offset += i;
pike.git/src/program.c:4826:    if(p->identifier_references[i].id_flags & ID_HIDDEN)    return -1;       if(p->identifier_references[i].id_flags & ID_PRIVATE)    if(!(flags & SEE_PRIVATE))    return -1;       return really_low_reference_inherited_identifier(q, e, i);   }    - int find_inherit(struct program *p, struct pike_string *name) + int find_inherit(const struct program *p, const struct pike_string *name)   {    int e;    int level = p->num_inherits; /* Larger than any inherit_level. */    int res = 0;      #if 0    fprintf(stderr, "find_inherit(0x%08lx, \"%s\")...\n",    (unsigned long)p, name->str);   #endif /* 0 */   
pike.git/src/program.c:5003:   #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 == 2) { +  if (Pike_compiler->compiler_pass == COMPILER_PASS_EXTRA) {    struct program *old_p = -  Pike_compiler->new_program->inherits[Pike_compiler->num_inherits+1].prog; +  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).");    } -  +  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)."); +  } +     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 "    "which is not fully compiled yet.");
pike.git/src/program.c:5064:    yyerror ("(You probably have a cyclic symbol dependency that the "    "compiler cannot handle.)");    return;    }       if (p == placeholder_program) {    yyerror("Trying to inherit placeholder program (resolver problem).");    return;    }    -  /* Propagate the HAS_C_METHODS and CLEAR_STORAGE flags. */ -  if (p->flags & (PROGRAM_HAS_C_METHODS|PROGRAM_CLEAR_STORAGE)) { +  /* Propagate the HAS_C_METHODS, CLEAR_STORAGE and DESTRUCT_IMMEDIATE flags. */ +  if (p->flags & (PROGRAM_HAS_C_METHODS|PROGRAM_CLEAR_STORAGE|PROGRAM_DESTRUCT_IMMEDIATE)) {    Pike_compiler->new_program->flags |= -  (p->flags & (PROGRAM_HAS_C_METHODS|PROGRAM_CLEAR_STORAGE)); +  (p->flags & (PROGRAM_HAS_C_METHODS|PROGRAM_CLEAR_STORAGE|PROGRAM_DESTRUCT_IMMEDIATE));    }       /* parent offset was increased by 42 for above test.. */    if(parent_offset)    parent_offset-=42;       inherit_offset = Pike_compiler->new_program->num_inherits;       /* alignment magic */    storage_offset=p->inherits[0].storage_offset % p->alignment_needed;
pike.git/src/program.c:5289:    parent_offset -= 42;       while (state && state->new_program && parent_offset--) {    state->new_program->flags |= PROGRAM_NEEDS_PARENT|PROGRAM_USES_PARENT;    state = state->previous;    }    }    }   }    + /** +  * Inherit a class from a lexically scoped identifier. +  * +  * @param scope_depth +  * Scope at which the identifier is expected to be found. +  * +  * @param symbol +  * Name of symbol to inherit from the specified scope. +  * +  * @param flags +  * Modifier flags for the inherit. +  * +  * @param failure_severity_level +  * Severity level to yyreport() failures to perform the inherit. +  * Typically REPORT_ERROR, but eg REPORT_NOTICE and REPORT_WARNING +  * are useful if the sybol is expected to sometimes be missing. +  * +  * @returns +  * Returns NULL on failure and the inherited program on success. +  */ + PMOD_EXPORT struct program *lexical_inherit(int scope_depth, +  struct pike_string *symbol, +  INT32 flags, +  int failure_severity_level) + { +  struct program_state *state = Pike_compiler; +  int e; +  int class_fun_num; +  struct program *prog; +  +  for (e = 0; e < scope_depth; e++) { +  state = state->previous; +  if (!state) { +  my_yyerror("Invalid lexical inherit of symbol %S at depth %d (max_depth: %d).", +  symbol, scope_depth, e+1); +  return NULL; +  } +  } +  +  class_fun_num = +  really_low_find_shared_string_identifier(symbol, state->new_program, +  SEE_PROTECTED|SEE_PRIVATE); +  if (class_fun_num < 0) { +  yyreport(failure_severity_level, parser_system_string, 0, +  "Symbol to inherit (%S) not found in parent scope #%d.", +  symbol, scope_depth); +  return NULL; +  } +  +  prog = low_program_from_function(state->fake_object, class_fun_num); +  if (!prog) { +  yyreport(failure_severity_level, parser_system_string, 0, +  "Symbol %S in parent scope #%d is not a program.", +  symbol, scope_depth); +  return NULL; +  } +  +  if (scope_depth) { +  /* Add a reference to the identifier. */ +  class_fun_num = +  really_low_reference_inherited_identifier(state, 0, class_fun_num); +  } +  low_inherit(prog, 0, class_fun_num, 42 + scope_depth, flags, symbol); +  +  return prog; + } +    PMOD_EXPORT void do_inherit(struct svalue *s,    INT32 flags,    struct pike_string *name)   {    struct object *parent_obj = NULL;    int parent_id = -1;    struct program *p = low_program_from_svalue(s, &parent_obj, &parent_id);    low_inherit(p, parent_obj, parent_id, 0, flags, name);   }   
pike.git/src/program.c:5416:    }    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; +  } +  /* 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);       if (safe_apply_current2(PC_HANDLE_INHERIT_FUN_NUM, 1, NULL))
pike.git/src/program.c:5460:    do_inherit(Pike_sp-1, flags, s);    free_string(s);    pop_stack();   }      /**    * Find an identifier relative to the program being compiled.    *    * @return Return the index of the identifier found, otherwise -1.    */ - int isidentifier(struct pike_string *s) + int isidentifier(const struct pike_string *s)   {    return really_low_find_shared_string_identifier(s,    Pike_compiler->new_program,    SEE_PROTECTED|SEE_PRIVATE);   }      /*    * Definition of identifiers.    *    * Pike has three plus one classes of identifiers:
pike.git/src/program.c:5496:    */   int low_define_alias(struct pike_string *name, struct pike_type *type,    int flags, int depth, int refno)   {    int n;    int e;       struct compilation *c = THIS_COMPILATION;    struct program_state *state = Pike_compiler;    struct identifier *id; -  struct reference ref; +     union idptr func;      #ifdef PIKE_DEBUG    if(Pike_compiler->new_program->flags & (PROGRAM_FIXED | PROGRAM_OPTIMIZED))    Pike_fatal("Attempting to add variable to fixed program\n");    -  if(Pike_compiler->compiler_pass==2) +  if(Pike_compiler->compiler_pass == COMPILER_PASS_LAST)    Pike_fatal("Internal error: Not allowed to add more identifiers during second compiler pass.\n"    "Added identifier: \"%s\"\n", name->str);   #endif       for(e = 0; DO_IF_DEBUG_ELSE(state, 1) && (e < depth); e++) {    state = state->previous;    }      #ifdef PIKE_DEBUG    if (!state) {
pike.git/src/program.c:5529:    }   #endif       id = ID_FROM_INT(state->new_program, refno);       func.ext_ref.depth = depth;    func.ext_ref.id = refno;       if (flags & ID_PRIVATE) flags |= ID_INLINE;    -  ref.id_flags=flags; -  ref.identifier_offset=Pike_compiler->new_program->num_identifiers; -  ref.inherit_offset=0; -  ref.run_time_type = PIKE_T_UNKNOWN; -  -  add_identifier(c, type ? type : id->type, name ? name : id->name, -  id->identifier_flags | IDENTIFIER_ALIAS, 0, +  return add_identifier(c, type ? type : id->type, name ? name : id->name, +  flags, id->identifier_flags | IDENTIFIER_ALIAS, 0,    func, id->run_time_type); -  -  n = Pike_compiler->new_program->num_identifier_references; -  add_to_identifier_references(ref); -  -  return n; +    }      PMOD_EXPORT int define_alias(struct pike_string *name, struct pike_type *type,    int flags, int depth, int refno)   {    /* FIXME: Support NULL name and type. */    int n = isidentifier(name);       if(Pike_compiler->new_program->flags & PROGRAM_PASS_1_DONE)    {
pike.git/src/program.c:5630:    return low_define_alias(name, type, flags, depth, refno);   }      /* argument must be a shared string */   int low_define_variable(struct pike_string *name,    struct pike_type *type,    INT32 flags,    size_t offset,    INT32 run_time_type)   { -  int n; -  +     struct compilation *c = THIS_COMPILATION; -  struct identifier dummy; -  struct reference ref; +  unsigned int identifier_flags = IDENTIFIER_VARIABLE;    union idptr func;      #ifdef PIKE_DEBUG    if(Pike_compiler->new_program->flags & (PROGRAM_FIXED | PROGRAM_OPTIMIZED))    Pike_fatal("Attempting to add variable to fixed program\n");    -  if(Pike_compiler->compiler_pass==2) +  if(Pike_compiler->compiler_pass == COMPILER_PASS_LAST)    Pike_fatal("Internal error: Not allowed to add more identifiers during second compiler pass.\n"    "Added identifier: \"%s\"\n", name->str);   #endif       func.offset = offset - Pike_compiler->new_program->inherits[0].storage_offset;    if (run_time_type == PIKE_T_FREE) func.offset = -1;    -  +  if (run_time_type & PIKE_T_NO_REF_FLAG) { +  run_time_type &= ~PIKE_T_NO_REF_FLAG; +  identifier_flags |= IDENTIFIER_NO_THIS_REF; +  } +     if (flags & ID_PRIVATE) flags |= ID_LOCAL|ID_PROTECTED;    -  ref.id_flags=flags; -  ref.identifier_offset=Pike_compiler->new_program->num_identifiers; -  ref.inherit_offset=0; -  ref.run_time_type = PIKE_T_UNKNOWN; -  -  add_to_variable_index(ref.identifier_offset); -  -  if (flags & ID_WEAK) { +  return    add_identifier(c, type, name, -  IDENTIFIER_VARIABLE|IDENTIFIER_WEAK, 0, +  flags, identifier_flags, 0,    func,    run_time_type); -  } else { -  add_identifier(c, type, name, -  IDENTIFIER_VARIABLE, 0, -  func, -  run_time_type); +    }    -  n=Pike_compiler->new_program->num_identifier_references; -  add_to_identifier_references(ref); -  -  return n; - } -  +    /* type is a serialized tokenized type. */   PMOD_EXPORT int quick_map_variable(const char *name,    int name_length,    size_t offset,    const char *type,    int UNUSED(type_length),    INT32 run_time_type,    INT32 flags)   {    int ret;
pike.git/src/program.c:5801:    return n;    }    }       if (!(IDENTIFIERP(n)->id_flags & ID_EXTERN)) {    if (IDENTIFIERP(n)->id_flags & ID_FINAL)    my_yyerror("Illegal to redefine 'final' "    "variable/functions %S", name);       if(!(IDENTIFIERP(n)->id_flags & ID_INLINE) || -  Pike_compiler->compiler_pass!=1) +  Pike_compiler->compiler_pass != COMPILER_PASS_FIRST)    {    int n2;       if(ID_FROM_INT(Pike_compiler->new_program, n)->type != type &&    !pike_types_le(type,    ID_FROM_INT(Pike_compiler->new_program, n)->type)) {    int level = REPORT_WARNING;    if (!match_types(ID_FROM_INT(Pike_compiler->new_program, n)->type,    type)) {    level = REPORT_ERROR;
pike.git/src/program.c:5857:    ID_HIDDEN;    return n2;    } else if ((IDENTIFIERP(n)->id_flags & (ID_INLINE|ID_INHERITED)) ==    (ID_INLINE|ID_INHERITED)) {    /* Hide the overloaded inherited symbol. */    IDENTIFIERP(n)->id_flags |= ID_HIDDEN;    }    } else if ((IDENTIFIERP(n)->id_flags & (ID_EXTERN|ID_INHERITED)) ==    (ID_EXTERN|ID_INHERITED)) {    /* Hide the overloaded inherited symbol. */ -  IDENTIFIERP(n)->id_flags |= ID_STATIC|ID_PRIVATE|ID_USED; +  IDENTIFIERP(n)->id_flags |= ID_PROTECTED|ID_PRIVATE|ID_USED;    }    }       if (flags & ID_EXTERN) {    run_time_type = PIKE_T_FREE;    } else {    run_time_type=compile_type_to_runtime_type(type);       /* FIXME: Shouldn't these special cases be    * in compile_type_to_runtime_type()?    */    switch(run_time_type)    {    case T_OBJECT:    /* Make place for the object subtype. */    case T_MIXED:    case T_FUNCTION:    no_this = 1; -  /* FALL_THROUGH */ +  /* FALLTHRU */    case T_PROGRAM:    run_time_type = T_MIXED;    break;    case T_INT:    {    INT_TYPE int_range[] = { MAX_INT32, MIN_INT32 };    run_time_type = T_MIXED;    if (get_int_type_range(type, int_range) &&    (int_range[0] > MIN_INT32) && (int_range[1] < MAX_INT32) ) {    run_time_type = T_INT;
pike.git/src/program.c:6052:    n, id->func.const_info.offset);   #endif    }    return n;    }      #ifdef PIKE_DEBUG    if(Pike_compiler->new_program->flags & (PROGRAM_FIXED | PROGRAM_OPTIMIZED))    Pike_fatal("Attempting to add constant to fixed program\n");    -  if(Pike_compiler->compiler_pass==2) { +  if(Pike_compiler->compiler_pass == COMPILER_PASS_LAST) {    dump_program_tables(Pike_compiler->new_program, 2);    Pike_fatal("Internal error: Not allowed to add more identifiers during second compiler pass.\n"    " Attempted to add the identifier \"%s\"\n",    name->str);    }   #endif      #if 1    if (c) {   #endif
pike.git/src/program.c:6083: Inside #if 1
   else {    copy_pike_type(type, mixed_type_string);    func.const_info.offset = -1;    opt_flags = 0;    }   #endif       if (flags & ID_PRIVATE) flags |= ID_LOCAL|ID_PROTECTED;       ref.id_flags=flags; -  ref.identifier_offset=Pike_compiler->new_program->num_identifiers; +  ref.identifier_offset = +  low_add_identifier(cc, type, name, +  IDENTIFIER_CONSTANT, opt_flags, +  func, c ? TYPEOF(*c) : T_MIXED);    ref.inherit_offset=0;    ref.run_time_type = PIKE_T_UNKNOWN;    -  add_identifier(cc, type, name, -  IDENTIFIER_CONSTANT, opt_flags, -  func, c ? TYPEOF(*c) : T_MIXED); +     free_pike_type(type);       if(n != -1)    {    int overridden;       if(IDENTIFIERP(n)->id_flags & ID_FINAL)    my_yyerror("Illegal to redefine 'final' identifier %S", name);       if(IDENTIFIER_IS_VARIABLE(ID_FROM_INT(Pike_compiler->new_program,
pike.git/src/program.c:6326:   #endif       /* If this is an lfun, match against the predefined type. */    if ((lfun_type = low_mapping_string_lookup(lfun_types, name))) {    int orig_pragmas = c->lex.pragmas;   #ifdef PIKE_DEBUG    if (TYPEOF(*lfun_type) != T_TYPE) {    Pike_fatal("Bad entry in lfun_types for key \"%s\"\n", name->str);    }   #endif /* PIKE_DEBUG */ +  if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST) {    /* Inhibit deprecation warnings during the comparison. */    c->lex.pragmas |= ID_NO_DEPRECATION_WARNINGS;    if (!pike_types_le(type, lfun_type->u.type)) {    int level = REPORT_NOTICE;    if (!match_types(type, lfun_type->u.type)) {    level = REPORT_ERROR;    } 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; -  +  }    } 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:6404:    if ((i >= 0) &&    !((ref = PTR_FROM_INT(prog, i))->id_flags & ID_INHERITED)) {    /* Not an inherited symbol. */    struct identifier *id = ID_FROM_INT(prog, i);    if (!IDENTIFIER_IS_VARIABLE(id->identifier_flags)) {    my_yyerror("Illegal to redefine function %S with variable.", symbol);    } else if (id->run_time_type != PIKE_T_GET_SET) {    my_yyerror("Illegal to redefine a current variable with a getter/setter: %S.", symbol);    } else {    if ((ref->id_flags | ID_USED) != (flags | ID_USED)) { -  if (Pike_compiler->compiler_pass == 1) { +  if (Pike_compiler->compiler_pass == COMPILER_PASS_FIRST) {    yywarning("Modifier mismatch for variable %S.", symbol);    }    ref->id_flags &= flags | ID_USED;    }    getter_setter = i;    }    /* FIXME: Update id->type here. */    } else {    struct identifier *id;    i = low_define_variable(symbol, symbol_type, flags,
pike.git/src/program.c:6439:    */    flags |= ID_PROTECTED /* | ID_PRIVATE | ID_INLINE | ID_USED */;    free_type(symbol_type);    free_string(symbol);    }    }       if(IDENTIFIER_IS_C_FUNCTION(function_flags))    prog->flags |= PROGRAM_HAS_C_METHODS;    -  if (Pike_compiler->compiler_pass == 1) { +  if (Pike_compiler->compiler_pass == COMPILER_PASS_FIRST) {    /* Mark the type as tentative by setting the runtime-type    * to T_MIXED.    *    * NOTE: This should be reset to T_FUNCTION in pass 2.    */    run_time_type = T_MIXED;    }       i = isidentifier(name); -  if (Pike_compiler->compiler_pass == 1) { +  if (Pike_compiler->compiler_pass == COMPILER_PASS_FIRST) {    if (flags & ID_VARIANT) {    if (i >= 0) {    if (!is_variant_dispatcher(prog, i)) {    /* This function will be the termination function for    * our variant dispatcher.    */    struct reference ref = prog->identifier_references[i];    /* Make sure to not get complaints about multiple    * definitions when adding the variant dispatcher.    */
pike.git/src/program.c:6554:    struct identifier *id = ID_FROM_INT(prog, getter_setter);    (&id->func.gs_info.getter)[is_setter] = i;    }    return i;    }       /* Note: The type from pass 1 may be incompatible with the one from    * pass 2. Only do this in pass 2, and only if the previous    * type isn't from pass 1.    */ -  if ((Pike_compiler->compiler_pass == 2) && +  if ((Pike_compiler->compiler_pass == COMPILER_PASS_LAST) &&    (funp->run_time_type == T_FUNCTION)) {    /* match types against earlier prototype or vice versa */    if(!match_types(type, funp->type))    {    yytype_report(REPORT_ERROR, NULL, 0,    funp->type,    NULL, 0, type, 0,    "Prototype doesn't match for function %S.", name);    }    }
pike.git/src/program.c:6595:       if((ref.id_flags & ID_FINAL)   #if 0    && !(funp->func.offset == -1)   #endif    )    {    my_yyerror("Illegal to redefine 'final' function %S.", name);    }    -  if (!(flags & ID_VARIANT) && (Pike_compiler->compiler_pass == 1) && +  if (!(flags & ID_VARIANT) && +  (Pike_compiler->compiler_pass == COMPILER_PASS_FIRST) &&    (funp->func.c_fun == f_dispatch_variant) &&    (!func || (func->c_fun != f_dispatch_variant) ||    !IDENTIFIER_IS_C_FUNCTION(function_flags)) &&    IDENTIFIER_IS_C_FUNCTION(funp->identifier_flags)) {    /* Overriding a variant function dispatcher with    * a non-variant function in pass 1.    *    * Hide the corresponding variant functions.    */    int j = prog->num_identifier_references;
pike.git/src/program.c:6641: Inside #if defined(PROGRAM_BUILD_DEBUG)
  #ifdef PROGRAM_BUILD_DEBUG    fprintf(stderr, "%*saltering the existing definition\n",    c->compilation_depth, "");   #endif       if(func)    idptr = *func;    else    idptr.offset = -1;    -  ref.identifier_offset = prog->num_identifiers; -  -  add_identifier(c, type, name, +  ref.identifier_offset = +  low_add_identifier(c, type, name,    function_flags, opt_flags,    idptr, run_time_type);    }       if (flags & ID_PRIVATE) flags |= ID_LOCAL|ID_PROTECTED;       ref.inherit_offset = 0;    ref.id_flags = flags;    if (flags & ID_VARIANT) {    ref.id_flags |= ID_USED;
pike.git/src/program.c:6695:    }    return overridden;    }    /* NOTE: At this point we already have the identifier in the    * new program, and just need to add the reference.    */    } else {    make_a_new_def:      #ifdef PIKE_DEBUG -  if(Pike_compiler->compiler_pass==2) +  if(Pike_compiler->compiler_pass == COMPILER_PASS_LAST)    Pike_fatal("Internal error: Not allowed to add more identifiers during second compiler pass.\n"    "Added identifier: \"%s\"\n", name->str);   #endif       /* Define a new function */       if(func)    idptr = *func;    else    idptr.offset = -1;
pike.git/src/program.c:6718: Inside #if defined(PIKE_DEBUG)
   if (a_flag > 5) {    fprintf(stderr,    "Adding new function #%d: '%s'\n"    " identifier_flags:0x%02x opt_flags:0x%04x\n",    prog->num_identifiers,    name->str,    function_flags, opt_flags);    }   #endif /* PIKE_DEBUG */    -  i = prog->num_identifiers; -  -  add_identifier(c, type, name, +  i = low_add_identifier(c, type, name,    function_flags, opt_flags,    idptr, run_time_type);       if (flags & ID_PRIVATE) flags |= ID_LOCAL|ID_PROTECTED;       ref.id_flags = flags;    ref.identifier_offset = i;    ref.inherit_offset = 0;    }   
pike.git/src/program.c:6858:    * B-+-foo All versions of Pike    * |    * +-A---foo    *    * External lookup of identifier "foo" in F():    *    * F-+-A---foo --- Pike 7.7.33    * |    * +-E---foo Pike 7.7.34 ---    */ - PMOD_EXPORT int really_low_find_shared_string_identifier(struct pike_string *name, + PMOD_EXPORT int really_low_find_shared_string_identifier(const struct pike_string *name,    const struct program *prog,    int flags)   {    struct reference *funp;    struct identifier *fun;    int id, i, depth, last_inh;      #if 0    CDFPRINTF("th(%ld) %p Trying to find %s flags=%d\n",    (long)th_self(), prog, name->str, flags);
pike.git/src/program.c:6936:      int really_low_find_variant_identifier(struct pike_string *name,    struct program *prog,    struct pike_type *type,    int start_pos,    int flags)   {    struct reference *funp;    struct identifier *fun;    int id, i, depth, last_inh; +  int tentative = -1;      #if 1   #ifdef COMPILER_DEBUG    fprintf(stderr,"th(%ld) %p Trying to find variant \"%s\" start=%d flags=%d\n"    " type: ",    (long)th_self(), prog, name->str, start_pos, flags);    simple_describe_type(type);    fprintf(stderr, "\n");   #endif   #endif
pike.git/src/program.c:6977:    {    funp = prog->identifier_references + i;    if(funp->id_flags & ID_HIDDEN) continue;    if(!(funp->id_flags & ID_VARIANT)) continue;    if(funp->id_flags & ID_PROTECTED)    if(!(flags & SEE_PROTECTED))    continue;    fun = ID_FROM_PTR(prog, funp);    /* if(fun->func.offset == -1) continue; * Prototype */    if(!is_same_string(fun->name,name)) continue; -  if(type && (fun->type != type)) continue; +  if(type && (fun->type != type)) { +  if ((Pike_compiler->compiler_pass != COMPILER_PASS_FIRST) && +  !(funp->id_flags & ID_INHERITED) && +  match_types(fun->type, type)) { +  tentative = i; +  } +  continue; +  }    if(funp->id_flags & ID_INHERITED)    {    struct inherit *inh = INHERIT_FROM_PTR(prog, funp);    if ((funp->id_flags & ID_PRIVATE) && !(flags & SEE_PRIVATE)) continue;    if (!depth || (depth > inh->inherit_level)) {    if (id != -1) {    int j;    int min_level = depth;    for (j=last_inh-1; j > funp->inherit_offset; j--) {    struct inherit *inh2 = prog->inherits + j;
pike.git/src/program.c:7010:    }    last_inh = funp->inherit_offset;    depth = inh->inherit_level;    id = i;    }    } else {    CDFPRINTF("Found %d\n", i);    return i;    }    } +  if ((id < 0) && (tentative >= 0)) { +  if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST) { +  // Usually due to forward-referring types. The tentative match +  // is often correct, but may in some cases be wrong eg due to +  // having fall back implementations that use the mixed type. +  yytype_report(REPORT_WARNING, +  NULL, 0, ID_FROM_INT(prog, tentative)->type, +  NULL, 0, type, +  0, "Variant type mismatch in second pass for %S.", +  name); +  } +  id = tentative; +  }    CDFPRINTF("Found %d\n", id);    return id;   }      /**    * This is the dispatcher function for variant functions.    *    * cf end_first_pass().    */   static void f_dispatch_variant(INT32 args)
pike.git/src/program.c:7118:    Pike_error("Too few arguments to %S(). Expected %O.\n",    name, Pike_sp-1);    }    } else {    Pike_error("Too many arguments to %S().\n", name);    }   }      PMOD_EXPORT int low_find_lfun(struct program *p, enum LFUN lfun)   { -  struct pike_string *lfun_name; +  const struct pike_string *lfun_name;    unsigned int flags = 0;    int i;    struct identifier *id;   #ifdef PIKE_DEBUG    if ((size_t)lfun >= NELEM(lfun_strings)) {    return find_lfun_fatal(p, lfun);    }   #endif    lfun_name = lfun_strings[lfun];       i = really_low_find_shared_string_identifier(lfun_name,    dmalloc_touch(struct program *,    p),    SEE_PROTECTED); -  if (i < 0 || !(p->flags & PROGRAM_FIXED)) return i; +  +  if ((i < 0) && (lfun == LFUN__DESTRUCT)) { +  /* Try the Pike 8.0 compatibility name. */ +  i = really_low_find_shared_string_identifier(compat_lfun_destroy_string, +  dmalloc_touch(struct program *, +  p), +  SEE_PROTECTED); +  if ((i >= 0) && !(p->flags & PROGRAM_FINISHED) && !TEST_COMPAT(8,0)) { +  struct compilation *c = MAYBE_THIS_COMPILATION; +  if (c && !(c->lex.pragmas & ID_NO_DEPRECATION_WARNINGS)) { +  yywarning("Compat: Substituting destroy() for _destruct()."); +  } +  } +  } +  +  if (i < 0 || !(p->flags & PROGRAM_FIXED)) { +  return i; +  }    id = ID_FROM_INT(p, i);    if (IDENTIFIER_IS_PIKE_FUNCTION(id->identifier_flags) &&    (id->func.offset == -1)) {    /* Function prototype. */    return -1;    }    return i;   }   #ifdef PIKE_DEBUG   PMOD_EXPORT int find_lfun_fatal(struct program *UNUSED(p), enum LFUN lfun)
pike.git/src/program.c:7163:    if (!id) return -1;    if (TYPEOF(*id) == T_INT) return id->u.integer;    my_yyerror("Bad entry in lfun lookup table for %S.", lfun_name);    return -1;   }      /**    * Lookup the number of a function in a program given the name in    * a shared_string    */ - int low_find_shared_string_identifier(struct pike_string *name, + int low_find_shared_string_identifier(const struct pike_string *name,    const struct program *prog)   {    int max,min,tst;    struct identifier *fun;       if(prog->flags & PROGRAM_FIXED)    {    unsigned short *funindex = prog->identifier_index;    size_t val_n = PTR_TO_INT (name);   
pike.git/src/program.c:7356:       return e;   }      /*    * program examination functions available from Pike.    */      struct array *program_indices(struct program *p)   { -  int e; +  int i;    int n = 0;    struct array *res; -  for (e = p->num_identifier_references; e--; ) { +  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)) {
pike.git/src/program.c:7395:    }    f_aggregate(n);    res = Pike_sp[-1].u.array;    add_ref(res);    pop_stack();    return(res);   }      struct array *program_values(struct program *p)   { -  int e; +  int i;    int n = 0;    struct array *res; -  for(e = p->num_identifier_references; e--; ) { +  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)) {
pike.git/src/program.c:7434:    }    f_aggregate(n);    res = Pike_sp[-1].u.array;    add_ref(res);    pop_stack();    return(res);   }      struct array *program_types(struct program *p)   { -  int e; +  int i;    int n = 0;    struct array *res; -  for (e = p->num_identifier_references; e--; ) { +  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)) {
pike.git/src/program.c:7512:    id = ID_FROM_INT(loc.o->prog, refid);    } while (IDENTIFIER_IS_ALIAS(id->identifier_flags));       if (fake_object.refs != 1) {    Pike_fatal("Lost track of fake object! refs: %d\n",    fake_object.refs);    }       if (loc.o != &fake_object) {    low_object_index_no_free(to, loc.o, refid); - #if 0 && defined (COMPILER_DEBUG) -  safe_pike_fprintf (stderr, "low_program_index_no_free1 %O->%S: %O\n", -  what, s, to); - #endif +     return 1;    }    }       if (IDENTIFIER_IS_CONSTANT(id->identifier_flags)) {    if (id->func.const_info.offset >= 0) {    struct program *p2 = PROG_FROM_INT(p, e);    struct svalue *val = &p2->constants[id->func.const_info.offset].sval;    assign_svalue_no_free(to, val);    } else {    /* Prototype constant. */    SET_SVAL(*to, T_INT, NUMBER_NUMBER, integer, 0);    } - #if 0 && defined (COMPILER_DEBUG) -  safe_pike_fprintf (stderr, "low_program_index_no_free2 %O->%S: %O\n", -  what, s, to); - #endif +     return 1;    }    return 0;   }      int program_index_no_free(struct svalue *to, struct svalue *what,    struct svalue *ind)   {    int e;    struct object *parent = NULL;
pike.git/src/program.c:8298:       MAKE_CONST_STRING(this_function_string,"this_function");    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);    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]));
pike.git/src/program.c:8823:    return NULL;    case T_TUPLE:    case T_OR:    case T_AND:    case PIKE_T_RING:    {    struct program *res;    res = program_from_type(t->car);    if (res) return res;    } -  /* FALL_THROUGH */ +  /* FALLTHRU */    case T_SCOPE:    case T_ASSIGN:    case PIKE_T_ATTRIBUTE:    case PIKE_T_NAME:    return program_from_type(t->cdr);    break;    default:    return NULL;    }   
pike.git/src/program.c:9520:    const char **params,    const char *comment)   {    while ((start < end) || opcode || (params && params[0]) ||    (comment && comment[0])) {    ptrdiff_t field_width = sizeof(PIKE_OPCODE_T) * 2;    ptrdiff_t i;    int skip_params = 0;    int skip_comment = 0;    -  if (start < end) { +  if (end) {    /* Address */    string_builder_sprintf(s, "0x%016lx ", start);    -  +  if (start < end) {    /* Memory dump */    for (i = 0; i < 8; i += field_width) {    if (start < end) {    string_builder_sprintf(s, "%0*x ", field_width, start[0]);    start++; -  +  if (start == end) { +  end = NULL; +  }    } else {    string_builder_sprintf(s, "%*s ", field_width, "");    }    }    } else { -  +  end = NULL; +  string_builder_sprintf(s, "%*s ", 8 + 8/field_width, ""); +  } +  } else {    string_builder_sprintf(s, "%*s ", 18 + 8 + 8/field_width, "");    }       /* Opcode */    if (opcode) {    if (strlen(opcode) < 8) {    string_builder_sprintf(s, " %-8s ", opcode);    } else if (strlen(opcode) < 32) {    string_builder_sprintf(s, " %-28s ", opcode);    skip_params = 1;
pike.git/src/program.c:9595:    } else {    string_builder_sprintf(s, " # %s\n", comment);    comment = NULL;    }    } else {    string_builder_sprintf(s, "\n");    }    }   }    + PMOD_EXPORT void string_builder_append_pike_opcode(struct string_builder *s, +  const PIKE_OPCODE_T *addr, +  enum Pike_opcodes op, +  int arg1, +  int arg2) + { +  char buf[3][32]; +  const char *params[3] = { NULL, NULL, NULL }; +  const struct instr *instr = &instrs[op - F_OFFSET]; +  sprintf(buf[0], "%d", arg1); +  sprintf(buf[1], "%d", arg2); +  if (instr->flags & I_HASARG) { +  params[0] = buf[0]; +  } +  if (instr->flags & I_HASARG2) { +  params[1] = buf[1]; +  } +  sprintf(buf[2], "# %s", instr->name); +  string_builder_append_disassembly(s, addr, addr, buf[2], params, NULL); + } +    PMOD_EXPORT void add_reverse_symbol(struct pike_string *sym, void *addr)   {    struct svalue key;    struct svalue val;    SET_SVAL(key, PIKE_T_INT, NUMBER_NUMBER, integer, (ptrdiff_t)addr);    SET_SVAL(val, PIKE_T_STRING, 0, string, sym);    low_mapping_insert(reverse_symbol_table, &key, &val, 1);   }      PMOD_EXPORT void simple_add_reverse_symbol(const char *sym, void *addr)
pike.git/src/program.c:9620:      PMOD_EXPORT void init_reverse_symbol_table()   {    int op;       if (reverse_symbol_table) return;    reverse_symbol_table = allocate_mapping(256);       /* Initialize with the most popular symbols. */   #define ADD_SYMBOL(SYM) simple_add_reverse_symbol(#SYM "()", (void *)(SYM)) - #ifdef PIKE_DEBUG + #if defined(PIKE_DEBUG) && defined(PIKE_USE_MACHINE_CODE)    ADD_SYMBOL(simple_debug_instr_prologue_0);    ADD_SYMBOL(simple_debug_instr_prologue_1);    ADD_SYMBOL(simple_debug_instr_prologue_2);   #endif    ADD_SYMBOL(low_return);    ADD_SYMBOL(low_return_pop);    ADD_SYMBOL(really_free_svalue);    ADD_SYMBOL(lvalue_to_svalue_no_free);    ADD_SYMBOL(f_add);    ADD_SYMBOL(really_free_string);
pike.git/src/program.c:9643:    ADD_SYMBOL(svalue_is_true);    ADD_SYMBOL(assign_lvalue);    ADD_SYMBOL(really_free_array);    ADD_SYMBOL(object_low_set_index);    ADD_SYMBOL(low_object_index_no_free);    ADD_SYMBOL(assign_to_short_svalue);    ADD_SYMBOL(really_free_short_svalue_ptr);    ADD_SYMBOL(mega_apply);       simple_add_reverse_symbol("Pike_interpreter_pointer", -  &Pike_interpreter_pointer); +  (void *)&Pike_interpreter_pointer);      #ifdef PIKE_USE_MACHINE_CODE    /* Add the opcodes as well. */    for (op = 1; op < (F_MAX_INSTR - F_OFFSET); op++) {    if (!instrs[op].address) continue;    simple_add_reverse_symbol(instrs[op].name, instrs[op].address);    }   #endif /* PIKE_USE_MACHINE_CODE */   }