pike.git / src / program.c

version» Context lines:

pike.git/src/program.c:1:   /*   || This file is part of Pike. For copyright information see COPYRIGHT.   || Pike is distributed under GPL, LGPL and MPL. See the file COPYING   || for more information. - || $Id$ +    */      #include "global.h"   #include "program.h"   #include "object.h"   #include "dynamic_buffer.h"   #include "pike_types.h"   #include "stralloc.h"   #include "las.h"   #include "lex.h"
pike.git/src/program.c:22:   #include "main.h"   #include "pike_memory.h"   #include "gc.h"   #include "threads.h"   #include "constants.h"   #include "operators.h"   #include "builtin_functions.h"   #include "stuff.h"   #include "mapping.h"   #include "cyclic.h" - #include "pike_security.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 <errno.h>   #include <fcntl.h>      #define sp Pike_sp    - #undef ATTRIBUTE - #define ATTRIBUTE(X) +     -  + #ifdef PIKE_THREADS + static COND_T Pike_compiler_cond; + static THREAD_T Pike_compiler_thread; + static int lock_depth = 0; +  + PMOD_EXPORT void lock_pike_compiler(void) + { +  if (lock_depth && (Pike_compiler_thread != th_self())) { +  SWAP_OUT_CURRENT_THREAD(); +  while (lock_depth && (Pike_compiler_thread != th_self())) { +  co_wait_interpreter(&Pike_compiler_cond); +  } +  SWAP_IN_CURRENT_THREAD(); +  } +  lock_depth++; +  Pike_compiler_thread = th_self(); + } +  + PMOD_EXPORT void unlock_pike_compiler(void) + { + #ifdef PIKE_DEBUG +  if (lock_depth < 1) { +  Pike_fatal("Pike compiler running unlocked!\n"); +  } + #endif +  lock_depth--; +  co_broadcast(&Pike_compiler_cond); + } + #else + PMOD_EXPORT void lock_pike_compiler(void) + { + } + PMOD_EXPORT void unlock_pike_compiler(void) + { + } + #endif +    static void low_enter_compiler(struct object *ce, int inherit);   static void exit_program_struct(struct program *);   static size_t add_xstorage(size_t size,    size_t alignment,    ptrdiff_t modulo_orig);    - #undef EXIT_BLOCK - #define EXIT_BLOCK(P) exit_program_struct( (P) ) + static struct block_allocator program_allocator = BA_INIT_PAGES(sizeof(struct program), 4);    - #undef COUNT_OTHER - #define COUNT_OTHER() do{ \ -  struct program *p; \ -  for(p=first_program;p;p=p->next) \ -  { \ -  size+=p->total_size - sizeof (struct program); \ -  } \ - }while(0) + ATTRIBUTE((malloc)) + struct program * alloc_program(void) { +  return ba_alloc(&program_allocator); + }    - BLOCK_ALLOC_FILL_PAGES(program, 4) + void really_free_program(struct program * p) { +  exit_program_struct(p); +  ba_free(&program_allocator, p); + }    -  + void count_memory_in_programs(size_t *num, size_t *_size) { +  size_t size; +  struct program *p; +  ba_count_all(&program_allocator, num, &size); +  for(p=first_program;p;p=p->next) { +  size+=p->total_size - sizeof (struct program); +  } +  *_size = size; + }    -  + void free_all_program_blocks(void) { +  ba_destroy(&program_allocator); + } +    /* #define COMPILER_DEBUG */   /* #define PROGRAM_BUILD_DEBUG */      #ifdef COMPILER_DEBUG   #define CDFPRINTF(X) fprintf X -  + #ifndef PIKE_THREADS + /* The CDFPRINTF lines wants to print lock_depth, so fake one of those */ + static const int lock_depth = 1; + #endif   #else /* !COMPILER_DEBUG */   #define CDFPRINTF(X)   #endif /* COMPILER_DEBUG */      /*    * These two values should probably be fine-tuned, but doing so    * more or less requires running a predictable 'typical' application    * and testing different hashsizes and tresholds. I tried to do it    * mathematically by measuring the extremes (no cache hits, 100%    * cache hits etc.) but it seems that the processor cache becomes    * exhausted in some of my measurements, which renders my mathematical    * model useless.    *    * Further measurements seems to indicate that this cache can slow    * things down a bit if the hit/miss rate is not fairly high.    * For normal applications, the hitrate is most likely well over 90%,    * but that should be verified. -  * - Holistiska Centralbyr√•n (Hubbe) +  * - Hubbe    */      /* Define the size of the cache that is used for method lookup. */   /* A value of zero disables this cache */ - #define FIND_FUNCTION_HASHSIZE 15013 + #define FIND_FUNCTION_HASHSIZE 16384      /* Programs with less methods will not use the cache for method lookups.. */ - #define FIND_FUNCTION_HASH_TRESHOLD 9 + #define FIND_FUNCTION_HASH_TRESHOLD 0         #define DECLARE   #include "compilation.h"    - struct pike_string *this_program_string; - static struct pike_string *this_string, *this_function_string; + struct pike_string *this_program_string, *this_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;    -  + /* 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",    "`+",    "`-",    "`&",    "`|",    "`^",    "`<<",
pike.git/src/program.c:155:    "_sprintf",    "_equal",    "_m_delete",    "_get_iterator",    "`[..]",    /* NOTE: After this point there are only fake lfuns. */    "_search",    "_types",    "_serialize",    "_deserialize", +  "_size_object", +  "_random",   };      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:187:    tFuncV(tNone,tZero,tMix), /* "`%", */    tFuncV(tNone,tVoid,tMix), /* "`~", */    tFuncV(tMix,tVoid,tInt), /* "`==", */    tFuncV(tMix,tVoid,tInt), /* "`<", */    tFuncV(tMix,tVoid,tInt), /* "`>", */    tFuncV(tNone,tVoid,tInt), /* "__hash", */    tFuncV(tString,tVoid,tMix), /* "cast", */    tFuncV(tNone,tVoid,tInt), /* "`!", */    tFuncV(tZero,tVoid,tMix), /* "`[]", */    tFuncV(tZero tSetvar(0,tZero),tVoid,tVar(0)), /* "`[]=", */ -  tFuncV(tStr,tVoid,tMix), /* "`->", */ -  tFuncV(tStr tSetvar(0,tZero),tVoid,tVar(0)), /* "`->=", */ -  tFuncV(tNone,tVoid,tInt), /* "_sizeof", */ -  tFuncV(tNone,tVoid,tArray), /* "_indices", */ -  tFuncV(tNone,tVoid,tArray), /* "_values", */ +  tFuncV(tStr tOr(tVoid,tObj) tOr(tVoid,tInt),tVoid,tMix), /* "`->", */ +  tFuncV(tStr tSetvar(0,tZero) tOr(tVoid,tObj) tOr(tVoid,tInt),tVoid,tVar(0)), /* "`->=", */ +  tFuncV(tOr(tVoid,tObj) tOr(tVoid,tInt),tVoid,tInt), /* "_sizeof", */ +  tFuncV(tOr(tVoid,tObj) tOr(tVoid,tInt),tVoid,tArray), /* "_indices", */ +  tFuncV(tOr(tVoid,tObj) tOr(tVoid,tInt),tVoid,tArray), /* "_values", */    tFuncV(tNone,tZero,tMix), /* "`()", */    tFuncV(tZero,tZero,tMix), /* "``+", */    tFuncV(tZero,tVoid,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), /* "``/", */
pike.git/src/program.c:215:    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), tVoid, 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, tMix), /* "_random", */   };      /* 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:316:      /*! @decl void lfun::create(zero ... args)    *!    *! Object creation callback.    *!    *! This function is called right after @[lfun::__INIT()].    *!    *! @[args] are the arguments passed when the program was called.    *!    *! @note -  *! In Pike 7.2 and later this function can be created implicitly -  *! by the compiler using the new syntax: +  *! 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:    *! @code    *! class Foo {    *! int foo;
pike.git/src/program.c:448:    *!    *! @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    *! adds external references to them. However, all objects with    *! @[lfun::destroy] in the cycle are already scheduled for    *! destruction and will therefore be destroyed even if external    *! references are added to them.    *! -  *! @note -  *! The garbage collector had completely random destruct order in -  *! versions prior to 7.2. -  *! +     *! @seealso    *! @[lfun::create()], @[predef::destruct()]    */      /*! @decl mixed lfun::`+(zero arg, zero ... rest)    *!    *! Left side addition/concatenation callback.    *!    *! This is used by @[predef::`+]. It's called with any arguments    *! that follow this object in the argument list of the call to
pike.git/src/program.c:752:    *!    *! @note    *! It's assumed that this function is side-effect free.    *!    *! @seealso    *! @[predef::`~()]    */      /*! @decl int(0..1) lfun::`==(mixed arg)    *! -  *! Equality test callback. +  *! Equivalence test callback.    *! -  +  *! @returns +  *! Is expected to return @expr{1@} if the current object is +  *! equivalent to @[arg] (ie may be replaced with @[arg], with +  *! no semantic differences (disregarding the effects of @[destruct()])), +  *! and @expr{0@} (zero) otherwise. +  *!    *! @note -  *! If this is implemented it might be necessary to implement -  *! @[lfun::__hash] too. Otherwise mappings might hold several +  *! If this is implemented it may be necessary to implement +  *! @[lfun::__hash] too. Otherwise mappings may hold several    *! objects as indices which are duplicates according to this -  *! function. Various other functions that use hashing also might -  *! not work correctly, e.g. @[predef::Array.uniq]. +  *! function. This may also affect various other functions +  *! that use hashing internally, e.g. @[predef::Array.uniq].    *!    *! @note    *! It's assumed that this function is side-effect free.    *! -  +  *! @note +  *! It's recommended to only implement this function for +  *! immutable objects, as otherwise stuff may get confusing +  *! when things that once were equivalent no longer are so, +  *! or the reverse. +  *!    *! @seealso    *! @[predef::`==()], @[lfun::__hash]    */      /*! @decl int(0..1) lfun::`<(mixed arg)    *!    *! Less than test callback.    *!    *! @note    *! It's assumed that this function is side-effect free.
pike.git/src/program.c:840:    *! Currently casting between object types is a noop.    *!    *! @note    *! If the returned value is not deemed to be of the requested type    *! a runtime error may be thrown.    *!    *! @note    *! It's assumed that this function is side-effect free.    */    - /*! @decl mixed lfun::`[..](zero low, int low_bound_type, @ -  *! zero high, int high_bound_type) -  *! -  *! Subrange callback. -  *! -  *! @note -  *! It's assumed that this function is side-effect free. -  *! -  *! @seealso -  *! @[predef::`[..]] -  */ -  +    /*! @decl mixed lfun::`[](zero arg1, zero|void arg2)    *!    *! Indexing callback.    *!    *! For compatibility, this is also called to do subranges unless    *! there is a @[`[..]] in the class. See @[predef::`[..]] for    *! details.    *!    *! @note    *! It's assumed that this function is side-effect free.
pike.git/src/program.c:875:    */      /*! @decl mixed lfun::`[]=(zero arg1, zero arg2)    *!    *! Index assignment callback.    *!    *! @seealso    *! @[predef::`[]=()], @[lfun::`->=()]    */    - /*! @decl mixed lfun::`->(string arg) + /*! @decl mixed lfun::`->(string index, object|void context, int|void access)    *!    *! Arrow index callback.    *! -  +  *! @param index +  *! Symbol in @[context] to access. +  *! +  *! @param context +  *! Context in the current object to start the search from. +  *! If @expr{UNDEFINED@} or left out, @expr{this_program::this@} +  *! is to be 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 +  *! +  *! @returns +  *! Returns the value at @[index] if it exists, and +  *! @expr{UNDEFINED@} otherwise. +  *!    *! @note    *! It's assumed that this function is side-effect free.    *!    *! @seealso -  *! @[predef::`->()] +  *! @[predef::`->()], @[::`->()]    */    - /*! @decl mixed lfun::`->=(string arg1, zero arg2) + /*! @decl mixed lfun::`->=(string index, zero value, @ +  *! object|void context, int|void access)    *!    *! Arrow index assignment callback.    *! -  +  *! @param index +  *! Symbol in @[context] to change the value of. +  *! +  *! @param value +  *! The new value. +  *! +  *! @param context +  *! Context in the current object to start the search from. +  *! If @expr{UNDEFINED@} or left out, @expr{this_program::this@} +  *! is to 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 +  *! +  *! This function is to index the current object with the string @[index], +  *! and set it to @[value]. +  *! +  *! @returns +  *! Returns the set @[value]. +  *!    *! @seealso -  *! @[predef::`->=()], @[lfun::`[]=()] +  *! @[predef::`->=()], @[::`->=()], @[lfun::`[]=()]    */      /*! @decl int lfun::_sizeof()    *!    *! Size query callback.    *!    *! Called by @[predef::sizeof()] to determine the number of elements    *! in an object. If this function is not present, the number    *! of public symbols in the object will be returned.    *!    *! @returns    *! Expected to return the number of valid indices in the object.    *!    *! @note    *! It's assumed that this function is side-effect free.    *!    *! @seealso    *! @[predef::sizeof()]    */    - /*! @decl array lfun::_indices() + /*! @decl array lfun::_indices(object|void context, int|void access)    *!    *! List indices callback.    *!    *! @returns    *! Expected to return an array with the valid indices in the object.    *!    *! @note    *! It's assumed that this function is side-effect free.    *!    *! @seealso    *! @[predef::indices()], @[lfun::_values()], @[lfun::_types()],    *! @[::_indices()]    */    - /*! @decl array lfun::_values() + /*! @decl array lfun::_values(object|void context, int|void access)    *!    *! List values callback.    *!    *! @returns    *! Expected to return an array with the values corresponding to    *! the indices returned by @[lfun::_indices()].    *!    *! @note    *! It's assumed that this function is side-effect free.    *!
pike.git/src/program.c:1087:    *! It's assumed that this function is side-effect free.    *!    *! @seealso    *! @[predef::sprintf()]    */      /*! @decl int lfun::_equal(mixed arg)    *!    *! Recursive equality callback.    *! +  *! @returns +  *! Is expected to return @expr{1@} if the current object is +  *! equal to @[arg], and @expr{0@} (zero) otherwise. +  *!    *! @note    *! It's assumed that this function is side-effect free.    *! -  +  *! @note +  *! Note that this function may return different values at different +  *! times for the same argument due to the mutability of the object. +  *!    *! @seealso    *! @[predef::equal()], @[lfun::`==()]    */      /*! @decl mixed lfun::_m_delete(mixed arg)    *!    *! Delete index callback.    *!    *! @seealso    *! @[predef::m_delete()]
pike.git/src/program.c:1117:    *! 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()]    */    + /*! @decl mixed lfun::`[..](zero low, int low_bound_type, @ +  *! zero high, int high_bound_type) +  *! +  *! Subrange callback. +  *! +  *! @note +  *! It's assumed that this function is side-effect free. +  *! +  *! @seealso +  *! @[predef::`[..]] +  */ +  + /**** END TRUE LFUNS ****/ + /**** BEGIN FAKE LFUNS ****/ +    /*! @decl mixed lfun::_search(mixed needle, mixed|void start)    *!    *! Search callback.    *!    *! @seealso    *! @[predef::search()]    */    - /*! @decl array lfun::_types() + /*! @decl array lfun::_types(object|void context, int|void access)    *!    *! List types callback.    *!    *! This callback is typically called via @[predef::types()].    *!    *! @returns    *! Expected to return an array with the types corresponding to    *! the indices returned by @[lfun::_indices()].    *!    *! @note
pike.git/src/program.c:1209:    *!    *! @note    *! A default implementation of @[lfun::_serialize()] and    *! @[lfun::_deserialize()] is available in @[Serializer.Serializable].    *!    *! @seealso    *! @[lfun::_serialize()], @[Serializer.deserialize()],    *! @[Serializer.Serializable()->_deserialize()]    */    + /*! @decl int lfun::_size_object() +  *! +  *! @[Debug.size_object()] callback. +  *! +  *! @returns +  *! Returns an approximation of the memory use in bytes for the object. +  *! +  *! @seealso +  *! @[Debug.size_object()], @[lfun::_sizeof()] +  */ +  + /*! @decl mixed lfun::_random() +  *! Called by @[random()]. Typical use is when the object implements +  *! a ADT, when a call to this lfun should return a random member of +  *! the ADT or range implied by the ADT. +  *! +  *! @seealso +  *! @[predef::random()] +  */ +  + /**** 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.    *!    *! @note    *! This is not a true LFUN, since it is even more low level!
pike.git/src/program.c:1313:    */      /*! @endclass    */      struct program *first_program = 0;   static int current_program_id = PROG_DYNAMIC_ID_START;      struct program *null_program=0;    + static struct program *reporter_program = NULL;   struct program *compilation_program = 0;   struct program *compilation_env_program = 0;   struct object *compilation_environment = NULL;      struct program *gc_internal_program = 0;   static struct program *gc_mark_program_pos = 0;    - static struct mapping *resolve_cache=0; -  - #ifdef PIKE_DEBUG - #define CHECK_FILE_ENTRY(PROG, POS, LEN, SHIFT) \ + #define CHECK_FILE_ENTRY(PROG, STRNO) \    do { \ -  if (SHIFT < 0 || SHIFT > 2 || \ -  POS + (LEN << SHIFT) > PROG->linenumbers + PROG->num_linenumbers) \ +  if ((STRNO < 0) || (STRNO >= PROG->num_strings)) \    Pike_fatal ("Invalid file entry in linenumber info.\n"); \    } while (0) - #else - #define CHECK_FILE_ENTRY(PROG, POS, LEN, SHIFT) do {} while (0) - #endif +     - int get_small_number(char **q); + INT_TYPE get_small_number(char **q);      PMOD_EXPORT void do_free_program (struct program *p)   {    if (p)    free_program(p);   }      /* So what if we don't have templates? / Hubbe */      #ifdef PIKE_DEBUG
pike.git/src/program.c:1398:    TYPE ARG) { \    NUMTYPE m = state->malloc_size_program->PIKE_CONCAT(num_,NAME); \    CHECK_FOO(NUMTYPE,TYPE,NAME); \    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)); \ -  tmp = mexec_realloc((void *)state->new_program->NAME, \ -  sizeof(TYPE) * m); \ +  tmp = mexec_realloc(state->new_program->NAME, sizeof(TYPE) * m); \    if(!tmp) Pike_fatal("Out of memory.\n"); \    PIKE_CONCAT(RELOCATE_,NAME)(state->new_program, tmp); \    state->malloc_size_program->PIKE_CONCAT(num_,NAME)=m; \    state->new_program->NAME=tmp; \    } \    state->new_program-> \    NAME[state->new_program->PIKE_CONCAT(num_,NAME)++]=(ARG); \   } \   void PIKE_CONCAT(low_add_many_to_,NAME) (struct program_state *state, \    TYPE *ARG, NUMTYPE cnt) { \
pike.git/src/program.c:1423:    TYPE *tmp; \    NUMTYPE n = m; \    do { \    if(n==MAXVARS(NUMTYPE)) { \    yyerror("Too many " #NAME "."); \    return; \    } \    n = MINIMUM(n*2+1,MAXVARS(NUMTYPE)); \    } while (m + cnt > n); \    m = n; \ -  tmp = mexec_realloc((void *)state->new_program->NAME, \ -  sizeof(TYPE) * m); \ +  tmp = mexec_realloc(state->new_program->NAME, sizeof(TYPE) * m); \    if(!tmp) Pike_fatal("Out of memory.\n"); \    PIKE_CONCAT(RELOCATE_,NAME)(state->new_program, tmp); \    state->malloc_size_program->PIKE_CONCAT(num_,NAME)=m; \    state->new_program->NAME=tmp; \    } \ -  MEMCPY(state->new_program->NAME + \ +  memcpy(state->new_program->NAME + \    state->new_program->PIKE_CONCAT(num_,NAME), \    ARG, sizeof(TYPE) * cnt); \    state->new_program->PIKE_CONCAT(num_,NAME) += cnt; \   } \   void PIKE_CONCAT(add_to_,NAME) (ARGTYPE ARG) { \    PIKE_CONCAT(low_add_to_,NAME) ( Pike_compiler, ARG ); \   }   #else /* !PIKE_USE_MACHINE_CODE */   #define BAR(NUMTYPE,TYPE,ARGTYPE,NAME) \    FOO(NUMTYPE,TYPE,ARGTYPE,NAME) \
pike.git/src/program.c:1456:    TYPE *tmp; \    NUMTYPE n = m; \    do { \    if(n==MAXVARS(NUMTYPE)) { \    yyerror("Too many " #NAME "."); \    return; \    } \    n = MINIMUM(n*2+1,MAXVARS(NUMTYPE)); \    } while (m + cnt > n); \    m = n; \ -  tmp = realloc((void *)state->new_program->NAME, \ -  sizeof(TYPE) * m); \ +  tmp = realloc(state->new_program->NAME, sizeof(TYPE) * m); \    if(!tmp) Pike_fatal("Out of memory.\n"); \    PIKE_CONCAT(RELOCATE_,NAME)(state->new_program, tmp); \    state->malloc_size_program->PIKE_CONCAT(num_,NAME)=m; \    state->new_program->NAME=tmp; \    } \ -  MEMCPY(state->new_program->NAME + \ +  memcpy(state->new_program->NAME + \    state->new_program->PIKE_CONCAT(num_,NAME), \    ARG, sizeof(TYPE) * cnt); \    state->new_program->PIKE_CONCAT(num_,NAME) += cnt; \   }   #endif /* PIKE_USE_MACHINE_CODE */      /* Funny guys use the uppermost value for nonexistant variables and    the like. Hence -2 and not -1. Y2K. */   #define FOO(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); \    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)); \ -  tmp = realloc((void *)state->new_program->NAME, \ -  sizeof(TYPE) * m); \ +  tmp = realloc(state->new_program->NAME, sizeof(TYPE) * m); \    if(!tmp) Pike_fatal("Out of memory.\n"); \    PIKE_CONCAT(RELOCATE_,NAME)(state->new_program, tmp); \    state->malloc_size_program->PIKE_CONCAT(num_,NAME)=m; \    state->new_program->NAME=tmp; \    } \    state->new_program-> \    NAME[state->new_program->PIKE_CONCAT(num_,NAME)++]=(ARG); \   } \   void PIKE_CONCAT(add_to_,NAME) (ARGTYPE ARG) { \    PIKE_CONCAT(low_add_to_,NAME) ( Pike_compiler, ARG ); \
pike.git/src/program.c:1516:    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)); \ -  tmp = realloc((void *)state->new_program->NAME, \ -  sizeof(TYPE) * m); \ +  tmp = realloc(state->new_program->NAME, sizeof(TYPE) * m); \    if(!tmp) Pike_fatal("Out of memory.\n"); \    PIKE_CONCAT(RELOCATE_,NAME)(state->new_program, tmp); \    state->malloc_size_program->PIKE_CONCAT(num_,NAME)=m; \    state->new_program->NAME=tmp; \    } \    state->new_program-> \    NAME[state->new_program->PIKE_CONCAT(num_,NAME)++]=(ARG); \   } \   void PIKE_CONCAT(add_to_,NAME) (ARGTYPE ARG) { \    PIKE_CONCAT(low_add_to_,NAME) ( Pike_compiler, ARG ); \
pike.git/src/program.c:1548:      void ins_int(INT32 i, void (*func)(char tmp))   {    int e;    unsigned char *p = (unsigned char *)&i;    for(e=0;e<(long)sizeof(i);e++) {    func(p[e]);    }   }    - void ins_short(int i, void (*func)(char tmp)) - { -  int e; -  unsigned char *p = (unsigned char *)&i; -  for(e=0;e<(long)sizeof(i);e++) { -  func(p[e]); -  } - } +       #if 0   /* This check is not possible to do since the identifier is added    * before checking for duplicates in add_constant. */   static void debug_add_to_identifiers (struct identifier id)   {    if (d_flag) {    int i;    for (i = 0; i < Pike_compiler->new_program->num_identifiers; i++)    if (Pike_compiler->new_program->identifiers[i].name == id.name) {
pike.git/src/program.c:1601:    c->num_used_modules++;    Pike_compiler->num_used_modules++;    assign_svalue_no_free((struct svalue *)    low_make_buf_space(sizeof(struct svalue),    &c->used_modules), s);    if(Pike_compiler->module_index_cache)    {    free_mapping(Pike_compiler->module_index_cache);    Pike_compiler->module_index_cache=0;    } +  if(c->resolve_cache) +  { +  free_mapping(c->resolve_cache); +  c->resolve_cache=0; +  }    }else{    yyerror("Module is neither mapping nor object");    }   }      void unuse_modules(INT32 howmany)   {    struct compilation *c = THIS_COMPILATION;    if(!howmany) return;   #ifdef PIKE_DEBUG
pike.git/src/program.c:1628:    free_svalues((struct svalue *)low_make_buf_space(0, &c->used_modules),    howmany,    BIT_MAPPING | BIT_OBJECT | BIT_PROGRAM);    if(Pike_compiler->module_index_cache)    {    free_mapping(Pike_compiler->module_index_cache);    Pike_compiler->module_index_cache=0;    }   }    - int low_find_shared_string_identifier(struct pike_string *name, -  struct program *prog); -  -  -  +    static struct node_s *index_modules(struct pike_string *ident,    struct mapping **module_index_cache, -  int num_used_modules, +  const int num_used_modules,    struct svalue *modules) -  +  /* num_used_modules is declared const here to convince the compiler that it is not +  * modified in between setjmp() and longjmp(). This prevents -Wglobbered warnings. +  */   {    if(*module_index_cache)    {    struct svalue *tmp=low_mapping_string_lookup(*module_index_cache,ident);    if(tmp)    {    if(!(SAFE_IS_ZERO(tmp) && SUBTYPEOF(*tmp)==1))    return mksvaluenode(tmp);    return 0;    }
pike.git/src/program.c:1776:   struct node_s *resolve_identifier(struct pike_string *ident)   {    struct compilation *c = THIS_COMPILATION;    node *ret = NULL;       /* Handle UNDEFINED */    if (ident == UNDEFINED_string) {    return mkconstantsvaluenode(&svalue_undefined);    }    -  if(resolve_cache) +  if(c->resolve_cache)    { -  struct svalue *tmp=low_mapping_string_lookup(resolve_cache,ident); +  struct svalue *tmp=low_mapping_string_lookup(c->resolve_cache,ident);    if(tmp)    {    if(!IS_UNDEFINED (tmp))    return mkconstantsvaluenode(tmp);       return 0;    }    }       CHECK_COMPILER();
pike.git/src/program.c:1825:       if (Pike_compiler->compiler_pass == 2 &&    ((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(!resolve_cache) -  resolve_cache=dmalloc_touch(struct mapping *, allocate_mapping(10)); -  mapping_string_insert(resolve_cache,ident,Pike_sp-1); +  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);    }    }    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)) { +  add_ref(ret); +  } else { +  my_yyerror("Invalid program identifier '%S'.", ident); +  } +  free_node(n); +  } else { +  my_yyerror("Unknown program identifier '%S'.", ident); +  } +  return ret; + } +    /*! @decl constant this    *!    *! Builtin read only variable that evaluates to the current object.    *!    *! @seealso    *! @[this_program], @[this_object()]    */      /*! @decl constant this_program    *!    *! Builtin constant that evaluates to the current program.    *!    *! @seealso    *! @[this], @[this_object()]    */    - /* If the identifier is recognized as one of the magic identifiers, + /** +  * If the identifier is recognized as one of the magic identifiers,    * like "this", "this_program" or "`->" when preceded by ::, then a    * suitable node is returned, NULL otherwise.    * -  * inherit_num is -1 when no specific inherit has been specified; ie -  * either when the identifier has no prefix (colon_colon_ref == 0) or -  * when the identifier has the prefix :: without any preceding identifier -  * (colon_colon_ref == 1). +  * @param inherit_num +  * Inherit number in state->new_program that the identifier has been +  * qualified with. -1 when no specific inherit has been specified; ie +  * either when the identifier has no prefix (colon_colon_ref == 0) or +  * when the identifier has the prefix :: without any preceding identifier +  * (colon_colon_ref == 1). +  * +  * New in Pike 7.9.5 and later: +  * +  * If colon_colon_ref is 1 and the selected inherit defines the +  * `->() lfun, code calling the lfun will be generated as follows: +  * +  * inh::`->(ident, inh::this, 1)    */   struct node_s *program_magic_identifier (struct program_state *state,    int state_depth, int inherit_num,    struct pike_string *ident,    int colon_colon_ref)   {   #if 0    fprintf (stderr, "magic_identifier (state, %d, %d, %s, %d)\n",    state_depth, inherit_num, ident->str, colon_colon_ref);   #endif    -  if (!inherit_num && TEST_COMPAT(7,6)) { -  /* Pike 7.6 and earlier couldn't refer to the current inherit. */ -  inherit_num = -1; -  } -  -  if ((inherit_num == -1) || (!TEST_COMPAT(7,6) && (inherit_num >= 0))) { +  /* FIXME: Is this expression always true? */ +  if ((inherit_num == -1) || (inherit_num >= 0)) {    if (ident == this_string) {    /* Handle this. */    return mkthisnode(state->new_program, inherit_num);    }       /* Handle this_program */    if (ident == this_program_string) { -  node *n = mkefuncallnode("object_program", +  node *n; +  if (!state_depth && (inherit_num == -1) && colon_colon_ref && +  !TEST_COMPAT(7,8) && +  state->previous && state->previous->new_program) { +  /* ::this_program +  * +  * This refers to the previous definition of the current class +  * in its parent, and is typically used with inherit like: +  * +  * inherit Foo; +  * +  * // Override the Bar inherited from Foo. +  * class Bar { +  * // Bar is based on the implementation from Foo. +  * inherit ::this_program; +  * +  * // ... +  * } +  */ +  struct program *parent; +  struct pike_string *name = NULL; +  int e; +  int i; +  +  /* Find the name of the current class. */ +  parent = state->previous->new_program; +  for (e = parent->num_identifier_references; e--;) { +  struct identifier *id = ID_FROM_INT(parent, e); +  struct svalue *s; +  if (!IDENTIFIER_IS_CONSTANT(id->identifier_flags) || +  (id->func.const_info.offset < 0)) { +  continue; +  } +  s = &PROG_FROM_INT(parent, e)-> +  constants[id->func.const_info.offset].sval; +  if ((TYPEOF(*s) != T_PROGRAM) || +  (s->u.program != state->new_program)) { +  continue; +  } +  /* Found! */ +  name = id->name; +  break; +  } +  if (!name) { +  yyerror("Failed to find current class in its parent."); +  return NULL; +  } +  +  /* Find ::name in the parent. */ +  i = reference_inherited_identifier(state->previous, NULL, name); +  if (i == -1) { +  my_yyerror("Failed to find previous inherited definition of %S " +  "in parent.", name); +  return NULL; +  } +  n = mkexternalnode(parent, i); +  } else { +  n = mkefuncallnode("object_program",    mkthisnode(state->new_program, inherit_num)); -  +  }    /* We know this expression is constant. */    n->node_info &= ~OPT_NOT_CONST;    n->tree_info &= ~OPT_NOT_CONST;    return n;    }       /* Handle this_function */    if (ident == this_function_string) {    int i;    if ((i = Pike_compiler->compiler_frame->current_function_number) >= 0) {
pike.git/src/program.c:1913:    } else {    return mkidentifiernode(i);    }    } else {    /* FIXME: Fall back to __INIT? */    }    }    }       if (colon_colon_ref) { +  int i = inherit_num; +     /* These are only recognized when prefixed with the :: operator. */    -  if (inherit_num < 0) inherit_num = 0; +  if (inherit_num < 0) i = 0;    if(ident == lfun_strings[LFUN_ARROW] ||    ident == lfun_strings[LFUN_INDEX]) { -  return mknode(F_MAGIC_INDEX, mknewintnode(inherit_num), +  return mknode(F_MAGIC_INDEX, mknewintnode(i),    mknewintnode(state_depth));    } else if(ident == lfun_strings[LFUN_ASSIGN_ARROW] ||    ident == lfun_strings[LFUN_ASSIGN_INDEX]) { -  return mknode(F_MAGIC_SET_INDEX, mknewintnode(inherit_num), +  return mknode(F_MAGIC_SET_INDEX, mknewintnode(i),    mknewintnode(state_depth));    } else if(ident == lfun_strings[LFUN__INDICES]) { -  return mknode(F_MAGIC_INDICES, mknewintnode(inherit_num), +  return mknode(F_MAGIC_INDICES, mknewintnode(i),    mknewintnode(state_depth));    } else if(ident == lfun_strings[LFUN__VALUES]) { -  return mknode(F_MAGIC_VALUES, mknewintnode(inherit_num), +  return mknode(F_MAGIC_VALUES, mknewintnode(i),    mknewintnode(state_depth));    } else if(ident == lfun_strings[LFUN__TYPES]) { -  return mknode(F_MAGIC_TYPES, mknewintnode(inherit_num), +  return mknode(F_MAGIC_TYPES, 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... */ +  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 (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) { +  inherit_num--; +  } +  } +  return mknode(F_APPLY, mkexternalnode(state->new_program, id), +  mknode(F_ARG_LIST, +  mkstrnode(ident), +  mknode(F_ARG_LIST, +  mkthisnode(state->new_program, inherit_num), +  mkintnode(1)))); +  } +  } +  }       return NULL;   }      /* Fixme: allow level=0 to return the current level */   struct program *parent_compilation(int level)   {    struct compilation *c = THIS_COMPILATION;    int n;    struct program_state *p=Pike_compiler->previous;
pike.git/src/program.c:2010:    case PROG_PARSER_HTML_ID:    module = "Parser._parser";    break;    case PROG_GMP_MPZ_ID:    module = "Gmp";    break;    case PROG_MODULE_MIME_ID:    module = "___MIME";    break;    default: -  if ((id >= 100) && (id <= 300)) { +  if ((id >= 100) && (id < 300)) {    module = "Image"; -  +  } else if ((id >= 300) && (id < 400)) { +  module = "Nettle";    } else if ((id >= 1000) && (id < 2000)) { -  module = "___GTK"; +  module = "___GTK1"; /* Deprecated */    } else if ((id >= 2000) && (id < 3000)) {    module = "___GTK2";    }    break;    }    if (module && get_master()) {    /* fprintf(stderr, "%s... ", module); */    push_text(module);    SAFE_APPLY_MASTER("resolv", 1);    pop_stack();
pike.git/src/program.c:2059:    *    * end_first_pass ==> PROGRAM_PASS_1_DONE    *    * fixate_program ==> PROGRAM_FIXED    *    * optimize_program ==> PROGRAM_OPTIMIZED    *    * end_first_pass(1) ==> PROGRAM_FINISHED    */    - /* Re-allocate all the memory in the program in one chunk. because: -  * 1) The individual blocks are much bigger than they need to be -  * 2) cuts down on malloc overhead (maybe) -  * 3) localizes memory access (decreases paging) + /** +  * Re-allocate all the memory in the program in one chunk. because: +  * @b 1) The individual blocks are much bigger than they need to be +  * @b 2) cuts down on malloc overhead (maybe) +  * @b 3) localizes memory access (decreases paging)    */   void optimize_program(struct program *p)   {    size_t size=0;    char *data;       /* Already done (shouldn't happen, but who knows?) */    if(p->flags & PROGRAM_OPTIMIZED) return;      #ifdef PIKE_USE_MACHINE_CODE
pike.git/src/program.c:2099:    size=0;      #ifdef PIKE_USE_MACHINE_CODE    /* As above. */   #define BAR(NUMTYPE,TYPE,ARGTYPE,NAME)   #endif /* PIKE_USE_MACHINE_CODE */      #define FOO(NUMTYPE,TYPE,ARGTYPE,NAME) \    size=DO_ALIGN(size, ALIGNOF(TYPE)); \    if (p->PIKE_CONCAT (num_, NAME)) \ -  MEMCPY(data+size,p->NAME,p->PIKE_CONCAT(num_,NAME)*sizeof(p->NAME[0])); \ +  memcpy(data+size,p->NAME,p->PIKE_CONCAT(num_,NAME)*sizeof(p->NAME[0])); \    PIKE_CONCAT(RELOCATE_,NAME)(p, (TYPE *)(data+size)); \    dmfree(p->NAME); \    p->NAME=(TYPE *)(data+size); \    size+=p->PIKE_CONCAT(num_,NAME)*sizeof(p->NAME[0]);   #include "program_areas.h"       p->total_size=size + sizeof(struct program);       p->flags |= PROGRAM_OPTIMIZED;    make_program_executable(p);
pike.git/src/program.c:2134:   #define ID fsort_program_identifier_index   #define TYPE unsigned short   #include "fsort_template.h"   #undef TYPE   #undef ID   #undef XARGS   #undef EXTRA_ARGS   #undef CMP      #ifdef PIKE_DEBUG - struct pike_string *find_program_name(struct program *p, INT32 *line) + struct pike_string *find_program_name(struct program *p, INT_TYPE *line)   { -  INT32 l; +  INT_TYPE l;    if(!line) line=&l;      #ifdef DEBUG_MALLOC    { -  char *tmp=dmalloc_find_name(p); +  const char *tmp=dmalloc_find_name(p);    if (tmp) { -  char *p = STRCHR (tmp, ':'); +  char *p = strchr (tmp, ':');    if (p) {    char *pp; -  while ((pp = STRCHR (p + 1, ':'))) p = pp; +  while ((pp = strchr (p + 1, ':'))) p = pp;    *line = atoi (p + 1);    return make_shared_binary_string (tmp, p - tmp);    }    else {    *line=0;    return make_shared_string(tmp);    }    }    }   #endif       return get_program_line(p, line);   }   #endif    - int override_identifier (struct reference *new_ref, struct pike_string *name) + int override_identifier (struct reference *new_ref, struct pike_string *name, +  int required_flags)   {    struct compilation *c = THIS_COMPILATION;    int id = -1, cur_id = 0, is_used = 0;       int new_is_variable =    IDENTIFIER_IS_VARIABLE(ID_FROM_PTR(Pike_compiler->new_program,    new_ref)->identifier_flags);       /* This loop could possibly be optimized by looping over    * each inherit and looking up 'name' in each inherit
pike.git/src/program.c:2191:    struct reference *ref =    Pike_compiler->new_program->identifier_references + cur_id;    struct identifier *i;       /* No need to do anything for ourselves. */    if (ref == new_ref) continue;       /* Do not zapp hidden identifiers */    if(ref->id_flags & ID_HIDDEN) continue;    +  if(ref->id_flags & ID_VARIANT) continue; +  +  if ((ref->id_flags & required_flags) != required_flags) continue; +     /* Do not zapp functions with the wrong name... */    if((i = ID_FROM_PTR(Pike_compiler->new_program, ref))->name != name)    continue;       /* Do not zapp inherited inline ('local') identifiers,    * or inherited externals with new externals,    * since this makes it hard to identify in encode_value().    */    if((ref->id_flags & (ID_INLINE|ID_INHERITED)) == (ID_INLINE|ID_INHERITED)    || (ref->id_flags & new_ref->id_flags & ID_EXTERN)) {
pike.git/src/program.c:2228:    continue;    }       if ((ref->id_flags & (ID_INHERITED|ID_USED)) == (ID_INHERITED|ID_USED)) {    struct inherit *inh = INHERIT_FROM_PTR(Pike_compiler->new_program, ref);    struct reference *sub_ref;       /* Find the inherit one level away. */    while (inh->inherit_level > 1) inh--;    + #if 0   #ifdef PIKE_DEBUG    if (!inh->inherit_level) { -  +  /* FIXME: This is valid for references that are about to be +  * overridden by the variant dispatcher. +  */    Pike_fatal("Inherit without intermediate levels.\n");    }   #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) &&    !pike_types_le(ID_FROM_PTR(Pike_compiler->new_program,
pike.git/src/program.c:2314:    * Consider this a fatal?    */    p->identifiers[i].run_time_type = T_FUNCTION;    }    }       /* Fixup identifier overrides. */    for (i = 0; i < p->num_identifier_references; i++) {    struct reference *ref = p->identifier_references + i;    if (ref->id_flags & ID_HIDDEN) continue; +  if (ref->id_flags & ID_VARIANT) continue;    if (ref->inherit_offset != 0) continue; -  override_identifier (ref, ID_FROM_PTR (p, ref)->name); -  -  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); +  override_identifier (ref, ID_FROM_PTR (p, ref)->name, 0);    } -  } +        /* Ok, sort for binsearch */    for(e=i=0;i<(int)p->num_identifier_references;i++)    {    struct reference *funp;    struct identifier *fun;    funp=p->identifier_references+i;    if(funp->id_flags & ID_HIDDEN) continue; -  +  if(funp->id_flags & ID_VARIANT) continue;    fun=ID_FROM_PTR(p, funp);    if(funp->id_flags & ID_INHERITED)    {    int found_better=-1;    int funa_is_prototype;       /* NOTE: Mixin is currently not supported for PRIVATE symbols. */    if(funp->id_flags & ID_PRIVATE) continue;    funa_is_prototype = fun->func.offset == -1;   /* if(fun->func.offset == -1) continue; * prototype */       /* check for multiple definitions */    for(t=i+1;t<(int)p->num_identifier_references;t++)    {    struct reference *funpb;    struct identifier *funb;       funpb=p->identifier_references+t;    if (funpb->id_flags & ID_HIDDEN) continue; -  +  if (funpb->id_flags & ID_VARIANT) continue;    funb=ID_FROM_PTR(p,funpb);    /* if(funb->func.offset == -1) continue; * prototype */       if(fun->name==funb->name)    {    if (!(funpb->id_flags & ID_PROTECTED)) {    /* Only regard this symbol as better if it    * will end up in the index further below.    */    found_better=t;
pike.git/src/program.c:2439:    id = probe;    }    p->num_identifier_index = i;    }       p->flags |= PROGRAM_FIXED;       /* Yes, it is supposed to start at 1 /Hubbe */    for(i=1;i<NUM_LFUNS;i++) {    int id = p->lfuns[i] = low_find_lfun(p, i); +  if (id >= 0) { +  // LFUNs are used. +  p->identifier_references[id].id_flags |= ID_USED;    } -  +  }    -  +  /* Complain about unused private symbols. */ +  for (i = 0; i < p->num_identifier_references; i++) { +  struct reference *ref = p->identifier_references + i; +  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    * 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);    if (!IDENTIFIER_IS_PIKE_FUNCTION (id->identifier_flags) ||    id->func.offset != -1) {
pike.git/src/program.c:2492:    my_yyerror("Illegal to redefine final identifier %S", name);    }    }    }    }      #ifdef DEBUG_MALLOC    {   #define DBSTR(X) ((X)?(X)->str:"")    int e,v; -  INT32 line; +  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 &&    !strcmp(c->lex.current_file->str,"-"))    {    m=dmalloc_alloc_mmap( DBSTR(c->lex.current_file), c->lex.current_line);    }    else if( (tmp=find_program_name(Pike_compiler->new_program, &line)) )
pike.git/src/program.c:2559:    }    }    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)); +  memset(p, 0, sizeof(struct program));    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); -  GETTIMEOFDAY(& p->timestamp); +  ACCURATE_GETTIMEOFDAY(& p->timestamp);    return p;   }    - /* + /**    * Start building a new program    */   void low_start_new_program(struct program *p,    int pass,    struct pike_string *name,    int flags,    int *idp)   {    struct compilation *c = THIS_COMPILATION;    int id=0;    struct svalue tmp;       CHECK_COMPILER();    - #ifdef WITH_FACETS -  if(Pike_compiler->compiler_pass == 1 && p) { -  p->facet_index = -1; -  p->facet_group = NULL; -  } - #endif -  -  /* We don't want to change thread, but we don't want to -  * wait for the other threads to complete either. +  /* We aren't thread safe, but we are reentrant. +  * +  * Lock out any other threads from the compiler until we are finished.    */ -  low_init_threads_disable(); +  lock_pike_compiler();       c->compilation_depth++;    -  if (!Pike_compiler->compiler_frame) { -  new_node_s_context(); -  } -  +     SET_SVAL_TYPE(tmp, T_PROGRAM);    if(!p)    {    p=low_allocate_program();    if(name)    {    tmp.u.program=p;    id=add_constant(name, &tmp, flags & ~ID_EXTERN);   #if 0    fprintf(stderr,"Compiling class %s, depth=%d\n",
pike.git/src/program.c:2646:    if (pass == 1) {    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((stderr, "th(%ld) %p low_start_new_program() %s " -  "pass=%d: threads_disabled:%d, compilation_depth:%d\n", +  "pass=%d: lock_depth:%d, compilation_depth:%d\n",    (long)th_self(), p, name ? name->str : "-",    Pike_compiler->compiler_pass, -  threads_disabled, c->compilation_depth)); +  lock_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_compiler->num_used_modules=0; /* FIXME: Duplicate? */       if(p->flags & PROGRAM_FINISHED)    {    yyerror("Pass2: Program already done");    }       Pike_compiler->malloc_size_program = ALLOC_STRUCT(program);    Pike_compiler->fake_object=alloc_object();      #ifdef PIKE_DEBUG    Pike_compiler->fake_object->storage=(char *)malloc(256 * sizeof(struct svalue));    if (Pike_compiler->fake_object->storage) {    /* Stipple to find illegal accesses */ -  MEMSET(Pike_compiler->fake_object->storage,0x55,256*sizeof(struct svalue)); +  memset(Pike_compiler->fake_object->storage,0x55,256*sizeof(struct svalue));    PIKE_MEM_WO_RANGE (Pike_compiler->fake_object->storage,    256 * sizeof (struct svalue));    }   #else    Pike_compiler->fake_object->storage=(char *)malloc(sizeof(struct parent_info));   #endif    if (!Pike_compiler->fake_object->storage) {    yyerror("Out of memory when allocating object storage.");    }    /* Can't use GC_ALLOC on fake objects, but still it's good to know
pike.git/src/program.c:2698:    Pike_compiler->fake_object->prev=Pike_compiler->fake_object;    Pike_compiler->fake_object->refs=0;    add_ref(Pike_compiler->fake_object); /* For DMALLOC... */    Pike_compiler->fake_object->prog=p;    add_ref(p);      #ifdef PIKE_DEBUG    Pike_compiler->fake_object->program_id=p->id;   #endif    - #ifdef PIKE_SECURITY -  Pike_compiler->fake_object->prot=0; - #endif -  +     debug_malloc_touch(Pike_compiler->fake_object);    debug_malloc_touch(Pike_compiler->fake_object->storage);       if (Pike_compiler->fake_object->storage) {    if(name)    {    /* Fake objects have parents regardless of PROGRAM_USES_PARENT */    if((((struct parent_info *)Pike_compiler->fake_object->storage)->parent=Pike_compiler->previous->fake_object))    add_ref(Pike_compiler->previous->fake_object);    ((struct parent_info *)Pike_compiler->fake_object->storage)->parent_identifier=id;
pike.git/src/program.c:2736: Inside #if defined(PROGRAM_BUILD_DEBUG)
   print_svalue (stderr, --Pike_sp);    putc ('\n', stderr);    }    else    fprintf (stderr, "%.*sstarting program %d (pass=%d)\n",    c->compilation_depth, "",    Pike_compiler->new_program->id, Pike_compiler->compiler_pass);   #endif       if (c->compilation_depth >= 1) { -  if(TEST_COMPAT(7,2) || (c->lex.pragmas & ID_SAVE_PARENT)) +  if(c->lex.pragmas & ID_SAVE_PARENT)    {    p->flags |= PROGRAM_USES_PARENT; -  }else if (!(c->lex.pragmas & ID_DONT_SAVE_PARENT)) { +  } else if (!(c->lex.pragmas & ID_DONT_SAVE_PARENT)) {    struct pike_string *tmp=findstring("__pragma_save_parent__");    if(tmp)    {    struct node_s *n=find_module_identifier(tmp, 0);    if(n)    {    int do_save_parent = !node_is_false(n); /* Default to true. */    free_node(n);    if (do_save_parent) p->flags |= PROGRAM_USES_PARENT;    }
pike.git/src/program.c:2765:    debug_malloc_touch(Pike_compiler->fake_object->storage);       if(Pike_compiler->new_program->program)    {   #define FOO(NUMTYPE,TYPE,ARGTYPE,NAME) \    Pike_compiler->malloc_size_program->PIKE_CONCAT(num_,NAME) = \    Pike_compiler->new_program->PIKE_CONCAT(num_,NAME);   #include "program_areas.h"       { -  INT32 line=0, off=0; +  INT_TYPE line = 0; +  INT32 off = 0;    size_t len = 0;    INT32 shift = 0; -  char *file=0; +  struct pike_string *file=0;    char *cnt=Pike_compiler->new_program->linenumbers;       while(cnt < Pike_compiler->new_program->linenumbers +    Pike_compiler->new_program->num_linenumbers)    {    if(*cnt == 127)    { -  +  int strno;    cnt++; -  len = get_small_number(&cnt); -  shift = *cnt; -  file = ++cnt; -  CHECK_FILE_ENTRY (Pike_compiler->new_program, cnt, len, shift); -  cnt += len<<shift; +  strno = get_small_number(&cnt); +  CHECK_FILE_ENTRY (Pike_compiler->new_program, strno); +  file = Pike_compiler->new_program->strings[strno];    }    off+=get_small_number(&cnt);    line+=get_small_number(&cnt);    }    Pike_compiler->last_line=line;    Pike_compiler->last_pc=off;    if(file)    { -  struct pike_string *str = begin_wide_shared_string(len, shift); +     if(Pike_compiler->last_file) free_string(Pike_compiler->last_file); -  memcpy(str->str, file, len<<shift); -  Pike_compiler->last_file = end_shared_string(str); +  copy_shared_string(Pike_compiler->last_file, file);    }    }       }else{    static struct pike_string *s;    struct inherit i;    -  +  if (Pike_compiler->new_program->strings) { +  struct pike_string **str = Pike_compiler->new_program->strings; +  int j = Pike_compiler->new_program->num_strings; +  while(j--) { +  free_string(*str); +  str++; +  } +  } +    #define START_SIZE 64   #ifdef PIKE_USE_MACHINE_CODE   #define BAR(NUMTYPE,TYPE,ARGTYPE,NAME) \    if (Pike_compiler->new_program->NAME) { \    mexec_free(Pike_compiler->new_program->NAME); \    Pike_compiler->new_program->PIKE_CONCAT(num_,NAME) = 0; \    } \    Pike_compiler->malloc_size_program->PIKE_CONCAT(num_,NAME) = \    START_SIZE; \    Pike_compiler->new_program->NAME = \
pike.git/src/program.c:2847:    Pike_compiler->num_parse_error=0;       push_compiler_frame(0);    copy_pike_type(Pike_compiler->compiler_frame->current_return_type,    void_type_string);       debug_malloc_touch(Pike_compiler->fake_object);    debug_malloc_touch(Pike_compiler->fake_object->storage);   }    - PMOD_EXPORT void debug_start_new_program(int line, const char *file) + PMOD_EXPORT void debug_start_new_program(INT_TYPE line, const char *file)   {    struct pike_string *save_file; -  int save_line; +  INT_TYPE save_line;    struct compilation *c;       CHECK_COMPILER();    c = THIS_COMPILATION;       save_file = dmalloc_touch(struct pike_string *, c->lex.current_file);    save_line = c->lex.current_line;       { /* 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((stderr, -  "th(%ld) start_new_program(%d, %s): " -  "threads_disabled:%d, compilation_depth:%d\n", -  (long)th_self(), line, file, -  threads_disabled, c->compilation_depth)); +  "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);    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:2962:    {    if(p->inherits[e].prog)    free_program(p->inherits[e].prog);    }    if(p->inherits[e].parent)    free_object(p->inherits[e].parent);    }       DOUBLEUNLINK(first_program, p);    - #ifdef WITH_FACETS -  if(p->facet_group) -  { -  free_object(p->facet_group); -  } - #endif -  +     if(p->flags & PROGRAM_OPTIMIZED)    {   #ifdef PIKE_USE_MACHINE_CODE    do {    /* NOTE: Assumes all BAR's are before any FOO. */   #define BAR(NUMTYPE,TYPE,ARGTYPE,NAME) \    if (p->NAME) mexec_free(p->NAME);   #define FOO(NUMTYPE,TYPE,ARGTYPE,NAME) \    if (p->NAME) { \    dmfree(p->NAME); \
pike.git/src/program.c:3049: Inside #if defined(PIKE_DEBUG)
   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," ");    fprintf(stderr,"parent_offset: %d\n",p->inherits[e].parent_offset);       for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," ");    fprintf(stderr,"storage_offset: %ld\n", -  DO_NOT_WARN((long)p->inherits[e].storage_offset)); +  (long)p->inherits[e].storage_offset);       for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," ");    fprintf(stderr,"parent: %p\n",p->inherits[e].parent);       if(p->inherits[e].parent &&    p->inherits[e].parent->prog &&    p->inherits[e].parent->prog->num_linenumbers>1)    {    for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," ");    fprintf(stderr,"parent: %s\n",p->inherits[e].parent->prog->linenumbers+1);
pike.git/src/program.c:3144:    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_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);   }      int sizeof_variable(int run_time_type)   {    switch(run_time_type)    {    case T_FUNCTION:    case T_MIXED: return sizeof(struct svalue);    case T_FLOAT: return sizeof(FLOAT_TYPE);    case T_INT: return sizeof(INT_TYPE);
pike.git/src/program.c:3177:    case T_FLOAT: return ALIGNOF(FLOAT_TYPE);    case T_INT: return ALIGNOF(INT_TYPE);    case PIKE_T_FREE:    case PIKE_T_GET_SET: return 1;    default: return ALIGNOF(void *);    }   }      #ifdef PIKE_DEBUG    - void dump_program_tables (const struct program *p, int indent) + PMOD_EXPORT void dump_program_tables (const struct program *p, int indent)   {    int d;       if (!p) {    fprintf(stderr, "%*sProgram: NULL\n\n", indent, "");    return;    }       fprintf(stderr,    "%*sProgram flags: 0x%04x\n\n",    indent, "", p->flags);       fprintf(stderr,    "%*sReference table:\n"    "%*s ####: Flags Inherit Identifier\n",    indent, "", indent, "");    for (d=0; d < p->num_identifier_references; d++) {    struct reference *ref = p->identifier_references + d;    struct identifier *id = ID_FROM_PTR(p, ref); -  +  struct program *inh_p = INHERIT_FROM_PTR(p, ref)->prog;       fprintf(stderr,    "%*s %4d: %5x %7d %10d %s\n" -  "%*s %s:%d\n", +  "%*s %s:%ld\n",    indent, "",    d, ref->id_flags, ref->inherit_offset,    ref->identifier_offset,    id->name->size_shift ? "(wide)" : id->name->str,    indent, "", -  p->num_strings?p->strings[id->filename_strno]->str:"-", id->linenumber); +  inh_p->num_strings?inh_p->strings[id->filename_strno]->str:"-", +  (long)id->linenumber);    if (IDENTIFIER_IS_ALIAS(id->identifier_flags)) {    fprintf (stderr, "%*s Alias for %d:%d\n",    indent, "", id->func.ext_ref.depth, id->func.ext_ref.id);    } else if (IDENTIFIER_IS_CONSTANT(id->identifier_flags)) {    fprintf (stderr, "%*s Constant #%ld\n",    indent, "", (long)id->func.const_info.offset);    } else if (IDENTIFIER_IS_VARIABLE(id->identifier_flags)) {    fprintf (stderr, "%*s Offset: 0x%08lx\n",    indent, "", (long)id->func.offset);    } else if (IDENTIFIER_IS_PIKE_FUNCTION(id->identifier_flags)) { -  INT32 line; -  struct program *inh_p = INHERIT_FROM_PTR(p,ref)->prog; +  INT_TYPE line;    struct pike_string *file =    get_line (ID_FROM_PTR(p,ref)->func.offset + inh_p->program, inh_p, &line);    if (!file->size_shift) -  fprintf (stderr, "%*s %s:%d\n", -  indent, "", file->str, line); +  fprintf (stderr, "%*s %s:%ld\n", +  indent, "", file->str, (long)line);    free_string (file);    } else {    fprintf (stderr, "%*s Cfun: %p\n",    indent, "", id->func.c_fun);    }    }       fprintf(stderr, "\n"    "%*sIdentifier index table:\n"    "%*s ####: Index\tName\n",
pike.git/src/program.c:3269: Inside #if defined(PIKE_DEBUG)
   }    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:%d\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:"-", id->linenumber); +  p->num_strings?p->strings[id->filename_strno]->str:"-", +  (long)id->linenumber);    }       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:3329:    if (p->lfuns[d] != -1) {    fprintf(stderr, "%*s %4d: %04d %s\n",    indent, "", d, p->lfuns[d], lfun_names[d]);    }    }       fprintf(stderr, "\n"    "%*sLinenumber table:\n",    indent, "");    { -  INT32 off = 0, line = 0; +  INT32 off = 0; +  INT_TYPE line = 0;    char *cnt = p->linenumbers;       while (cnt < p->linenumbers + p->num_linenumbers) {    if (*cnt == 127) { -  int len, shift; -  char *file; +  int strno;    cnt++; -  len = get_small_number(&cnt); -  shift = *cnt; -  file = ++cnt; -  CHECK_FILE_ENTRY (p, cnt, len, shift); -  cnt += len << shift; -  if (!shift) { -  fprintf(stderr, "%*s Filename: \"%s\"\n", indent, "", file); -  } else { -  fprintf(stderr, "%*s Filename: len:%d, shift:%d\n", indent, "", len, shift); +  strno = get_small_number(&cnt); +  fprintf(stderr, "%*s Filename: String #%d\n", indent, "", strno);    } -  } +     off += get_small_number(&cnt);    line += get_small_number(&cnt); -  fprintf(stderr, "%*s %8d:%8d\n", indent, "", off, line); +  fprintf(stderr, "%*s %8d:%8ld\n", indent, "", off, (long)line);    }    }       fprintf(stderr, "\n");   }      void check_program(struct program *p)   {    unsigned INT32 e;    int variable_positions[1024];
pike.git/src/program.c:3457:    p->inherits[e].storage_offset)    Pike_fatal("Overlapping inherits! (3)\n");    }    }          if(p->flags & PROGRAM_FINISHED)    for(e=0;e<p->num_identifiers;e++)    {    check_string(p->identifiers[e].name); -  check_type_string(p->identifiers[e].type); +        switch (p->identifiers[e].identifier_flags & IDENTIFIER_TYPE_MASK) {    case IDENTIFIER_VARIABLE:    case IDENTIFIER_PIKE_FUNCTION:    case IDENTIFIER_C_FUNCTION:    case IDENTIFIER_CONSTANT:    break;       default:    Pike_fatal("Invalid identifier type.\n");
pike.git/src/program.c:3629:    p) > 0)) {    Pike_fatal("Program->identifier_index[%ld] > "    "Program->identifier_index[%ld]\n",    (long)(e-1), (long)e);    }    }      }   #endif    - /* Note: This function is misnamed, since it's run after both passes. /mast */ - /* finish-states: + static void f_dispatch_variant(INT32 args); +  + int low_is_variant_dispatcher(struct identifier *id) + { +  if (!id) return 0; +  return (IDENTIFIER_IS_C_FUNCTION(id->identifier_flags) && +  !IDENTIFIER_IS_ALIAS(id->identifier_flags) && +  (id->func.c_fun == f_dispatch_variant)); + } +  + int is_variant_dispatcher(struct program *prog, int fun) + { +  struct reference *ref; +  struct identifier *id; +  if (fun < 0) return 0; +  ref = PTR_FROM_INT(prog, fun); +  id = ID_FROM_PTR(prog, ref); +  return low_is_variant_dispatcher(id); + } +  + static int add_variant_dispatcher(struct pike_string *name, +  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); + } +  + /** +  * 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.    */   struct program *end_first_pass(int finish)   {    struct compilation *c = THIS_COMPILATION;    int e; -  struct program *prog; -  struct pike_string *s; +  struct program *prog = Pike_compiler->new_program; +  struct pike_string *init_name; +  int num_refs = prog->num_identifier_references; +  union idptr dispatch_fun;    -  +  dispatch_fun.c_fun = f_dispatch_variant; +  +  /* Collect variant functions that have been defined in this program, +  * and add the corresponding dispatchers. +  */ +  for (e = 0; e < num_refs; e++) { +  struct identifier *id; +  struct pike_string *name; +  struct pike_type *type; +  int id_flags; +  int opt_flags; +  int j; +  if (prog->identifier_references[e].inherit_offset) continue; +  if (!is_variant_dispatcher(prog, e)) continue; +  /* Found a dispatcher. */ +  +  id = ID_FROM_INT(prog, e); +  name = id->name; +  type = NULL; +  id_flags = 0; +  opt_flags = 0; +  +  CDFPRINTF((stderr, "Collecting variants of \"%s\"...\n", name->str)); +  +  /* Collect the variants of the function. */ +  j = prog->num_identifier_references; +  while ((j = really_low_find_variant_identifier(name, prog, NULL, j, +  SEE_PROTECTED|SEE_PRIVATE)) >= 0) { +  struct reference *ref = prog->identifier_references + j; +  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. +  */ +  prog->identifier_references[j].id_flags |= ID_LOCAL; +  { +  struct pike_type * temp = type; +  type = or_pike_types(type, id->type, 1); +  if (temp) free_type(temp); +  } + #ifdef COMPILER_DEBUG +  fprintf(stderr, "type: "); +  simple_describe_type(id->type); +  fprintf(stderr, "\n"); + #endif +  } + #ifdef COMPILER_DEBUG +  fprintf(stderr, "Dispatcher type: "); +  simple_describe_type(type); +  fprintf(stderr, "\n"); + #endif +  /* Update the type of the dispatcher. */ +  id = ID_FROM_INT(prog, e); +  free_type(id->type); +  id->type = type; +  id->opt_flags = opt_flags; +  prog->identifier_references[e].id_flags |= id_flags & ~(ID_VARIANT|ID_LOCAL); +  next_ref: +  ; +  } +     debug_malloc_touch(Pike_compiler->fake_object);    debug_malloc_touch(Pike_compiler->fake_object->storage);    -  MAKE_CONST_STRING(s,"__INIT"); +  init_name = lfun_strings[LFUN___INIT];    -  +     /* Collect references to inherited __INIT functions */    if (!(Pike_compiler->new_program->flags & PROGRAM_AVOID_CHECK)) {    for(e=Pike_compiler->new_program->num_inherits-1;e;e--)    {    int id;    if(Pike_compiler->new_program->inherits[e].inherit_level!=1) continue; -  id=low_reference_inherited_identifier(0, e, s, SEE_PROTECTED); +  id = Pike_compiler->new_program->inherits[e].prog->lfuns[LFUN___INIT]; +  id = really_low_reference_inherited_identifier(0, e, id);    if(id!=-1)    {    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) { +  /* 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; +  } +     /*    * 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; -  e=dooptcode(s, +  +  e=dooptcode(init_name,    mknode(F_COMMA_EXPR,    Pike_compiler->init_node,    mknode(F_RETURN,mkintnode(0),0)),    function_type_string,    ID_PROTECTED);    Pike_compiler->init_node=0;    } else if (finish == 2) {    /* Called from decode_value(). */    e = low_find_lfun(Pike_compiler->new_program, LFUN___INIT); -  +  if ((e != -1) && +  (ID_FROM_INT(Pike_compiler->new_program, e)->func.offset == -1)) { +  /* Just a prototype. Make sure not to call it. */ +  e = -1; +  }    }else{ -  +  /* Note that we may zap an __INIT that existed in pass 1 here. +  * This is intentional to avoid having to keep track of whether +  * __INIT() is just a prototype or not. +  */    e=-1;    }    Pike_compiler->new_program->lfuns[LFUN___INIT]=e;       pop_compiler_frame(); /* Pop __INIT local variables */       if(Pike_compiler->num_parse_error > 0)    {    CDFPRINTF((stderr, "th(%ld) %p Compilation errors (%d).\n",    (long)th_self(), Pike_compiler->new_program,
pike.git/src/program.c:3725:       fixate_program();    if(Pike_compiler->num_parse_error)    {    free_program(prog);    prog=0;    }else{    optimize_program(Pike_compiler->new_program);    Pike_compiler->new_program->flags |= PROGRAM_FINISHED;    } +  } else { +  /* All references in prog are now known. +  * Fixup identifier overrides or external symbols, +  * so that inherit is safe. +  */ +  for (e = 0; e < prog->num_identifier_references; e++) { +  struct reference *ref = prog->identifier_references + e; +  if (ref->id_flags & ID_HIDDEN) continue; +  if (ref->inherit_offset != 0) continue; +  override_identifier (ref, ID_FROM_PTR (prog, ref)->name, +  ID_EXTERN);    } -  +  }      #ifdef PIKE_DEBUG    if (prog) {    check_program(prog);    if(l_flag)    dump_program_desc(prog);    }   #endif    }   
pike.git/src/program.c:3752:    toss_compilation_resources();      #if 0    CDFPRINTF((stderr,    "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) && resolve_cache) +  if(!Pike_compiler->compiler_frame && (Pike_compiler->compiler_pass==2 || !prog) && c->resolve_cache)    { -  free_mapping(dmalloc_touch(struct mapping *, resolve_cache)); -  resolve_cache=0; +  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();    -  free_all_nodes(); +        CDFPRINTF((stderr,    "th(%ld) %p end_first_pass(%d): " -  "threads_disabled:%d, compilation_depth:%d\n", +  "lock_depth:%d, compilation_depth:%d\n",    (long)th_self(), prog, finish, -  threads_disabled, c->compilation_depth)); +  lock_depth, c->compilation_depth));       c->compilation_depth--;    -  exit_threads_disable(NULL); +  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");    }   #endif /* PIKE_USE_MACHINE_CODE */   #endif /* 0 */    return prog;   }    - /* + /**    * Finish this program, returning the newly built program    */   PMOD_EXPORT struct program *debug_end_program(void)   { -  Pike_compiler->compiler_pass = 2; +     return end_first_pass(1);   }       - /* + /**    * Allocate space needed for this program in the object structure.    * An offset to the data is returned.    */   PMOD_EXPORT size_t low_add_storage(size_t size, size_t alignment,    ptrdiff_t modulo_orig)   {    ptrdiff_t offset;    ptrdiff_t modulo;       if(!size) return Pike_compiler->new_program->storage_needed;
pike.git/src/program.c:3844:    * STORAGE_NEEDED() is defined in program.h.    * /Hubbe 1999-09-29    *    * Oops, seems I read the test below the wrong way around.    * /grubba 1999-09-29    */    Pike_compiler->new_program->inherits[0].storage_offset=offset;    }       if(Pike_compiler->new_program->alignment_needed<alignment) -  Pike_compiler->new_program->alignment_needed = -  DO_NOT_WARN((unsigned INT8)alignment); +  Pike_compiler->new_program->alignment_needed = (unsigned INT8)alignment;      #ifdef PIKE_DEBUG    if(offset < Pike_compiler->new_program->storage_needed)    Pike_fatal("add_storage failed horribly!\n");       if( (offset /* + OFFSETOF(object,storage) */ - modulo_orig ) % alignment )    Pike_fatal("add_storage failed horribly(2) %ld %ld %ld %ld!\n", -  DO_NOT_WARN((long)offset), +  (long)offset,    (long)0 /* + OFFSETOF(object,storage) */, -  DO_NOT_WARN((long)modulo_orig), -  DO_NOT_WARN((long)alignment)); +  (long)modulo_orig, +  (long)alignment);      #endif       Pike_compiler->new_program->storage_needed = offset + size;       return (size_t) offset;   }      /*    * Internal function.
pike.git/src/program.c:3933:    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.    */   PMOD_EXPORT void set_init_callback(void (*init)(struct object *))   {    add_compat_event_handler();    ((oldhandlertype *)Pike_compiler->new_program->program)[PROG_EVENT_INIT]=init;   }    - /* + /**    * Set a callback to be called when clones of this program are    * destructed.    *    * This function is obsolete; see pike_set_prog_event_callback for    * details.    *    * Note: If the callback only does very trivial stuff, like freeing or    * clearing a few pointers in the object storage, you can do    *    * Pike_compiler->new_program->flags &= ~PROGRAM_LIVE_OBJ;
pike.git/src/program.c:3969:    * called out of order for PROG_EVENT_EXIT events; see the docs for    * PROGRAM_LIVE_OBJ in program.h for further details.    */   PMOD_EXPORT void set_exit_callback(void (*exit)(struct object *))   {    add_compat_event_handler();    ((oldhandlertype *)Pike_compiler->new_program->program)[PROG_EVENT_EXIT]=exit;    Pike_compiler->new_program->flags |= PROGRAM_LIVE_OBJ;   }    - /* + /**    * This callback is used by the gc to traverse all references to    * things in memory. It should call some gc_recurse_* function exactly    * once for each reference that the pike internals doesn't know about.    *    * If a reference is shared between objects, it should be traversed    * once for every instance sharing it.    *    * The callback might be called more than once for the same instance    * during a gc pass. The gc assumes that the references are enumerated    * in the same order in that case.
pike.git/src/program.c:4004:    *    * This function is obsolete; see pike_set_prog_event_callback for    * details.    */   PMOD_EXPORT void set_gc_recurse_callback(void (*m)(struct object *))   {    add_compat_event_handler();    ((oldhandlertype *)Pike_compiler->new_program->program)[PROG_EVENT_GC_RECURSE]=m;   }    - /* + /**    * This callback is used by the gc to count all references to things    * in memory. It should call gc_check, gc_check_(weak_)svalues or    * gc_check_(weak_)short_svalue exactly once for each reference that    * the pike internals don't know about.    *    * If a reference is shared between objects, it should be counted once    * for all shared instances. The return value from gc_check is useful    * to ensure this; it's zero when called the first time for its    * argument (it is perfectly fine to use gc_check on things that the    * pike core doesn't know about, but they must have an INT32 refcount
pike.git/src/program.c:4026:    *    * This function is obsolete; see pike_set_prog_event_callback for    * details.    */   PMOD_EXPORT void set_gc_check_callback(void (*m)(struct object *))   {    add_compat_event_handler();    ((oldhandlertype *)Pike_compiler->new_program->program)[PROG_EVENT_GC_CHECK]=m;   }    - /* + /**    * Set a callback to be called when any of the special program events    * occur. The event type is sent as an integer argument. The events    * include, but might not be limited to, the following:    *    * PROG_EVENT_INIT    * An object is being cloned from the program. See set_init_callback    * for details.    * PROG_EVENT_EXIT    * An object is being destructed. See set_exit_callback for details.    * PROG_EVENT_GC_RECURSE
pike.git/src/program.c:4075:      PMOD_EXPORT void pike_set_prog_optimize_callback(node *(*opt)(node *))   {   #ifdef PIKE_DEBUG    if(Pike_compiler->new_program->optimize)    Pike_fatal("Program already has an optimize handler!\n");   #endif    Pike_compiler->new_program->optimize = opt;   }    - int really_low_reference_inherited_identifier(struct program_state *q, -  int e, -  int i) + /** +  * Reference an inherited identifier. +  * +  * @param q +  * 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 -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;    int d, num_id_refs;    -  if(i==-1) return -1; +  if(f==-1) return -1;    -  p = np->inherits[e].prog; +  p = np->inherits[i].prog;    -  funp = p->identifier_references[i]; -  funp.inherit_offset += e; +  if ((q?q:Pike_compiler)->compiler_pass == 2) { +  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;    funp.id_flags = (funp.id_flags & ~ID_INHERITED) | ID_INLINE|ID_HIDDEN;       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_USED) == (funp.id_flags | ID_USED))) {    return d;    } -  +  }       funp.run_time_type = PIKE_T_UNKNOWN;       if(q)    low_add_to_identifier_references(q,funp);    else    add_to_identifier_references(funp);    /* NOTE: np->num_identifier_references has been increased by one by    * {low_,}add_to_identifier_references().    */   #ifdef PIKE_DEBUG    if (num_id_refs != np->num_identifier_references-1) {    fatal("Unexpected number of identifier references: %d != %d\n",    num_id_refs, np->num_identifier_references-1);    }   #endif /* PIKE_DEBUG */ -  +     return num_id_refs; /* aka np->num_identifier_references - 1 */   }    - int low_reference_inherited_identifier(struct program_state *q, + PMOD_EXPORT int low_reference_inherited_identifier(struct program_state *q,    int e,    struct pike_string *name,    int flags)   {    struct program *np=(q?q:Pike_compiler)->new_program;    struct program *p;    int i;       p=np->inherits[e].prog;    i=find_shared_string_identifier(name,p);
pike.git/src/program.c:4153:    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 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 */ -  /* FIXME: This loop could be optimized by advancing by the number -  * of inherits in the inherit. But in that case the loop -  * would have to go the other way. -  */ +     for(e = p->num_inherits-1; e>0; e--) {   #if 0    fprintf(stderr, " %04d: %04d %s\n",    e, p->inherits[e].inherit_level,    p->inherits[e].name?p->inherits[e].name->str:"NULL");   #endif /* 0 */ -  if (p->inherits[e].inherit_level > 1) continue; -  if (name == p->inherits[e].name) return e; +  if (p->inherits[e].inherit_level >= level) continue; +  if (name == p->inherits[e].name) { +  res = e; +  level = p->inherits[e].inherit_level; +  if (level == 1) break;    } -  return 0; +     } -  +  return res; + }    - /* Reference the symbol super_name::function_name */ - node *reference_inherited_identifier(struct pike_string *super_name, -  struct pike_string *function_name) + /** +  * Reference the symbol inherit::name in the lexical context +  * specified by state. +  * +  * @return Returns the reference in state->new_program if found. +  */ + PMOD_EXPORT int reference_inherited_identifier(struct program_state *state, +  struct pike_string *inherit, +  struct pike_string *name)   { -  int n,e,id; -  struct compilation *c = THIS_COMPILATION; -  struct program_state *state=Pike_compiler->previous; -  +  int e, id;    struct program *p;    -  +    #ifdef PIKE_DEBUG -  if(function_name!=debug_findstring(function_name)) -  Pike_fatal("reference_inherited_function on nonshared string.\n"); +  if (name != debug_findstring(name)) +  Pike_fatal("reference_inherited_identifier on nonshared string.\n");   #endif    -  p=Pike_compiler->new_program; +  if (!state) state = Pike_compiler;    -  /* FIXME: This loop could be optimized by advancing by the number -  * of inherits in the inherit. But in that case the loop -  * would have to go the other way. -  */ -  for(e=p->num_inherits-1;e>0;e--) -  { -  if(p->inherits[e].inherit_level!=1) continue; -  if(!p->inherits[e].name) continue; +  p = state->new_program;    -  if(super_name) -  if(super_name != p->inherits[e].name) -  continue; -  -  id=low_reference_inherited_identifier(0, -  e, -  function_name, -  SEE_PROTECTED); -  -  if(id!=-1) -  return mkidentifiernode(id); -  -  if(ISCONSTSTR(function_name,"`->") || -  ISCONSTSTR(function_name,"`[]")) -  { -  return mknode(F_MAGIC_INDEX,mknewintnode(e),mknewintnode(0)); -  } -  -  if(ISCONSTSTR(function_name,"`->=") || -  ISCONSTSTR(function_name,"`[]=")) -  { -  return mknode(F_MAGIC_SET_INDEX,mknewintnode(e),mknewintnode(0)); -  } -  -  if(ISCONSTSTR(function_name,"_indices")) -  { -  return mknode(F_MAGIC_INDICES,mknewintnode(e),mknewintnode(0)); -  } -  -  if(ISCONSTSTR(function_name,"_values")) -  { -  return mknode(F_MAGIC_VALUES,mknewintnode(e),mknewintnode(0)); -  } -  } -  -  -  for(n=0;n<c->compilation_depth;n++,state=state->previous) -  { -  struct program *p=state->new_program; -  +     /* FIXME: This loop could be optimized by advancing by the number    * of inherits in the inherit. But in that case the loop    * would have to go the other way.    */ -  for(e=p->num_inherits-1;e>0;e--) -  { -  if(p->inherits[e].inherit_level!=1) continue; -  if(!p->inherits[e].name) continue; +  for (e = p->num_inherits; e--;) { +  if (p->inherits[e].inherit_level != 1) continue; +  if (inherit && (inherit != p->inherits[e].name)) continue;    -  if(super_name) -  if(super_name != p->inherits[e].name) -  continue; +  id = low_reference_inherited_identifier(state, e, name, SEE_PROTECTED);    -  id=low_reference_inherited_identifier(state,e,function_name,SEE_PROTECTED); -  -  if(id!=-1) -  return mkexternalnode(p, id); -  -  if(ISCONSTSTR(function_name,"`->") || -  ISCONSTSTR(function_name,"`[]")) -  { -  return mknode(F_MAGIC_INDEX, -  mknewintnode(e),mknewintnode(n+1)); +  if (id != -1) return id;    }    -  if(ISCONSTSTR(function_name,"`->=") || -  ISCONSTSTR(function_name,"`[]=")) -  { -  return mknode(F_MAGIC_SET_INDEX, -  mknewintnode(e),mknewintnode(n+1)); +  return -1;   }    -  if(ISCONSTSTR(function_name,"_indices")) -  { -  return mknode(F_MAGIC_INDICES, -  mknewintnode(e),mknewintnode(n+1)); -  } -  -  if(ISCONSTSTR(function_name,"_values")) -  { -  return mknode(F_MAGIC_VALUES, -  mknewintnode(e),mknewintnode(n+1)); -  } -  } -  } -  -  return 0; - } -  +    /* FIXME: This function probably doesn't do what it is intended to do    * if the last inherit had inherits of its own. Consider removal.    */   void rename_last_inherit(struct pike_string *n)   {    if(Pike_compiler->new_program->inherits[Pike_compiler->new_program->num_inherits].name)    free_string(Pike_compiler->new_program->inherits[Pike_compiler->new_program->num_inherits].name);    copy_shared_string(Pike_compiler->new_program->inherits[Pike_compiler->new_program->num_inherits].name,    n);   }
pike.git/src/program.c:4371: Inside #if 0
   parent_offset+=i->parent_offset;   #endif       return locate_parent_state(&state,    &i,    &parent_identifier,    depth);   }   #endif    - #ifdef WITH_FACETS - void check_for_facet_inherit(struct program *p) - { -  /* If the inherit statement comes before the facet keyword in the -  * class declaration the class will be temporarily marked as a -  * product-class, but this will be taken care of when the facet -  * keyword is found. */ -  if (!p) return; -  if (Pike_compiler->new_program->facet_group && -  p->facet_group != Pike_compiler->new_program->facet_group) -  yyerror("A class can not belong to two facet-groups."); -  if (p->flags & PROGRAM_IS_FACET) { -  if (Pike_compiler->new_program->flags & PROGRAM_IS_FACET) { -  if(Pike_compiler->new_program->facet_index != p->facet_index) -  yyerror("Facet class can't inherit from class in different facet."); -  } -  /* Otherwise this is a product class */ -  else { -  if( !Pike_compiler->new_program->facet_group ) { -  Pike_compiler->new_program->flags |= PROGRAM_IS_PRODUCT; -  add_ref(p->facet_group); -  Pike_compiler->new_program->facet_group = p->facet_group; -  } -  push_int(Pike_compiler->new_program->id); -  push_int(p->facet_index); -  push_int(p->id); -  safe_apply(p->facet_group, "add_product_class", 3); -  pop_stack(); -  } -  } -  /* The inherited class is not a facet class */ -  else if (p->flags & PROGRAM_IS_PRODUCT) { -  if (Pike_compiler->new_program->flags & PROGRAM_IS_FACET) { -  yyerror("Facet class can't inherit from product class."); -  } -  else if(Pike_compiler->new_program->flags & PROGRAM_IS_PRODUCT){ -  yyerror("Product class can't inherit from other product class."); -  } -  /* A class that inherits from a product class is also a product class */ -  else { -  Pike_compiler->new_program->flags |= PROGRAM_IS_PRODUCT; -  add_ref(p->facet_group); -  Pike_compiler->new_program->facet_group = p->facet_group; -  } -  } - } - #endif -  -  - /* -  * make this program inherit another program -  */ - PMOD_EXPORT void low_inherit(struct program *p, + void lower_inherit(struct program *p,    struct object *parent,    int parent_identifier,    int parent_offset,    INT32 flags,    struct pike_string *name)   {    int e;    ptrdiff_t inherit_offset, storage_offset;    struct inherit inherit;   
pike.git/src/program.c:4510:    }       if (!(p->flags & (PROGRAM_FINISHED | PROGRAM_PASS_1_DONE))) {    yyerror ("Cannot inherit program in pass 1 "    "which is only a placeholder.");    yyerror ("(You probably have a cyclic symbol dependency that the "    "compiler cannot handle.)");    return;    }    - #ifdef WITH_FACETS -  /* Check if inherit is a facet inherit. */ -  check_for_facet_inherit(p); - #endif -  +     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)) { +  Pike_compiler->new_program->flags |= +  (p->flags & (PROGRAM_HAS_C_METHODS|PROGRAM_CLEAR_STORAGE)); +  } +     /* 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;    storage_offset=low_add_storage(STORAGE_NEEDED(p),    p->alignment_needed,
pike.git/src/program.c:4650:    if(inherit.parent) add_ref(inherit.parent);       if(name)    {    if(e==0)    {    copy_shared_string(inherit.name,name);    }    else if(inherit.name)    { -  /* FIXME: Wide string handling. */ -  struct pike_string *s; -  s=begin_shared_string(inherit.name->len + name->len + 2); -  MEMCPY(s->str,name->str,name->len); -  MEMCPY(s->str+name->len,"::",2); -  MEMCPY(s->str+name->len+2,inherit.name->str,inherit.name->len); -  inherit.name=end_shared_string(s); +  add_ref(inherit.name);    } -  else -  { -  inherit.name=0; -  } +     }else{    inherit.name=0;    }    add_to_inherits(inherit);    }       /* This value is used by encode_value() to reverse the inherit operation. */    Pike_compiler->new_program->inherits[inherit_offset].identifier_ref_offset =    Pike_compiler->new_program->num_identifier_references;   
pike.git/src/program.c:4687:       fun.inherit_offset += inherit_offset;       fun.run_time_type = PIKE_T_UNKNOWN; /* Invalidate the vtable cache. */       if (fun.id_flags & ID_FINAL)    {    Pike_compiler->flags |= COMPILATION_CHECK_FINAL;    }    +  if (flags & ID_PUBLIC) +  fun.id_flags &= ~(ID_PRIVATE|ID_PUBLIC); +     if(fun.id_flags & ID_PRIVATE) fun.id_flags|=ID_HIDDEN;    -  if (fun.id_flags & ID_PUBLIC) -  fun.id_flags |= flags & ~ID_PRIVATE; -  else -  fun.id_flags |= flags; +  fun.id_flags |= flags & ~ID_PUBLIC;       fun.id_flags |= ID_INHERITED;    add_to_identifier_references(fun);    }   }    -  + /** +  * Make the program being compiled inherit another program. +  * +  * @param p +  * Program to inherit. +  * +  * @param parent +  * Object containing p (if applicable). +  * +  * @param parent_identifier +  * Identifier reference in parent->prog that is p. +  * +  * @param parent_offset +  * Lexical scope to parent from the program being compiled +  * offsetted by 42, or OBJECT_PARENT or INHERIT_PARENT. +  * +  * @param flags +  * Modifier flags for the inherit. +  * +  * @param name +  * Optional rename of the inherit. +  */ + PMOD_EXPORT void low_inherit(struct program *p, +  struct object *parent, +  int parent_identifier, +  int parent_offset, +  INT32 flags, +  struct pike_string *name) + { +  lower_inherit(p, parent, parent_identifier, parent_offset, flags, name); +  +  /* Don't do this for OBJECT_PARENT or INHERIT_PARENT inherits. +  * They may show up here from decode_value(). +  */ +  if (parent_offset >= 42) { +  if (p->flags & (PROGRAM_NEEDS_PARENT|PROGRAM_USES_PARENT)) { +  /* We'll need the parent pointer as well... */ +  struct program_state *state = Pike_compiler; +  +  /* parent offset was increased by 42 by the caller... */ +  parent_offset -= 42; +  +  while (state && state->new_program && parent_offset--) { +  state->new_program->flags |= PROGRAM_NEEDS_PARENT|PROGRAM_USES_PARENT; +  state = state->previous; +  } +  } +  } + } +    PMOD_EXPORT void do_inherit(struct svalue *s,    INT32 flags,    struct pike_string *name)   { -  struct program *p=program_from_svalue(s); -  low_inherit(p, -  TYPEOF(*s) == T_FUNCTION ? s->u.object : 0, -  TYPEOF(*s) == T_FUNCTION ? SUBTYPEOF(*s) : -1, -  0, -  flags, -  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);   }      void compiler_do_inherit(node *n,    INT32 flags,    struct pike_string *name)   {    struct program *p;    struct identifier *i;    INT32 numid=-1, offset=0;       if(!n)    {    yyerror("Unable to inherit");    return;    }    -  +  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"); +  } +     switch(n->token)    { -  case F_IDENTIFIER: -  p=Pike_compiler->new_program; -  offset=0; -  numid=n->u.id.number; -  goto continue_inherit; -  +     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");    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 +  * refer to the inherit and not the +  * current class. +  */ +  name = ID_FROM_INT(p, numid)->name;    } -  +  }       continue_inherit:       /* FIXME: Support external constants. */    if(numid != IDREF_MAGIC_THIS &&    (IDENTIFIER_IS_CONSTANT((i=ID_FROM_INT(p, numid))->    identifier_flags)) &&    (i->func.const_info.offset != -1))    {    struct svalue *s=&PROG_FROM_INT(p, numid)->
pike.git/src/program.c:4773:    do_inherit(s,flags,name);    return;    }else{    low_inherit(s->u.program,    0,    numid,    offset+42,    flags,    name);    } -  if (n->token == F_EXTERNAL) { -  struct program *p=program_from_svalue(s); -  if (p->flags & (PROGRAM_NEEDS_PARENT|PROGRAM_NEEDS_PARENT)) { -  /* We'll need the parent pointer as well... */ -  struct program_state *state = Pike_compiler; -  -  while (state && (state->new_program->id != n->u.integer.a)) { -  state->new_program->flags |= PROGRAM_NEEDS_PARENT|PROGRAM_USES_PARENT; -  state = state->previous; -  } -  } -  } +     }else{    yyerror("Inherit identifier is not a constant program");    return;    }    break;       default:    resolv_class(n);    do_inherit(Pike_sp-1, flags, name);    pop_stack();    }   }      int call_handle_inherit(struct pike_string *s)   {    struct compilation *c = THIS_COMPILATION;       CHECK_COMPILER();       ref_push_string(s); -  if (!TEST_COMPAT(7,6)) { -  /* In Pike 7.7 and later filenames belonging to Pike are assumed -  * to be encoded according to UTF-8. -  */ +     f_string_to_utf8(1); -  } +        if (safe_apply_current2(PC_HANDLE_INHERIT_FUN_NUM, 1, NULL))    if (TYPEOF(Pike_sp[-1]) != T_INT)    return 1;    else {    my_yyerror("Couldn't find program %S", s);    }    else {    handle_compile_exception ("Error finding program");    }
pike.git/src/program.c:4842:    if(name)    {    free_string(s);    s=name;    }    do_inherit(Pike_sp-1, flags, s);    free_string(s);    pop_stack();   }    - /* -  * Return the index of the identifier found, otherwise -1. + /** +  * 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)   {    return really_low_find_shared_string_identifier(s,    Pike_compiler->new_program,    SEE_PROTECTED|SEE_PRIVATE);   }      /*    * Definition of identifiers.
pike.git/src/program.c:4866:    *    * IDENTIFIER_VARIABLE - A value stored in object->storage    * IDENTIFIER_CONSTANT - A value stored in program->constants    * IDENTIFIER_FUNCTION - Either a C function or a Pike function    * and    * IDENTIFIER_ALIAS - An alias for a different identifier.    *    */       - /* Define an alias for a (possibly extern) identifier. + /** +  * Define an alias for a (possibly extern) identifier.    *    * Note that both type and name may be NULL. If they are NULL    * they will be defaulted to the values from the aliased identifier.    */   int low_define_alias(struct pike_string *name, struct pike_type *type,    int flags, int depth, int refno)   {    int n;    int e;   
pike.git/src/program.c:4891: Inside #if defined(PIKE_DEBUG)
     #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)    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; state && (e < depth); e++) { +  for(e = 0; DO_IF_DEBUG_ELSE(state, 1) && (e < depth); e++) {    state = state->previous;    }      #ifdef PIKE_DEBUG    if (!state) {    Pike_fatal("Internal error: External symbol buried too deep.\n");    }    if (state->new_program->num_identifier_references <= refno) {    Pike_fatal("Internal error: Reference out of bounds: %d (max: %d).\n",    refno, state->new_program->num_identifier_references);
pike.git/src/program.c:4927:    dummy.filename_strno = store_prog_string(c->lex.current_file);    dummy.linenumber = c->lex.current_line;    dummy.identifier_flags = id->identifier_flags | IDENTIFIER_ALIAS;    dummy.run_time_type = id->run_time_type; /* Not actually used. */    dummy.func.ext_ref.depth = depth;    dummy.func.ext_ref.id = refno;    dummy.opt_flags = 0;   #ifdef PROFILING    dummy.self_time=0;    dummy.num_calls=0; +  dummy.recur_depth=0;    dummy.total_time=0;   #endif       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;   
pike.git/src/program.c:5057:    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_VARIABLE;    dummy.run_time_type=run_time_type;    dummy.func.offset=offset - Pike_compiler->new_program->inherits[0].storage_offset;    dummy.opt_flags = 0;   #ifdef PROFILING    dummy.self_time=0;    dummy.num_calls=0; +  dummy.recur_depth=0;    dummy.total_time=0;   #endif       if (run_time_type == PIKE_T_FREE) dummy.func.offset = -1;    -  if (flags & ID_PRIVATE) flags |= ID_INLINE; +  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);       debug_add_to_identifiers(dummy);   
pike.git/src/program.c:5110:    free_string(n);    free_type(t);    return ret;   }      /* 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 type_length, +  int UNUSED(type_length),    INT32 run_time_type,    INT32 flags)   {    int ret;    struct pike_string *n;    struct pike_type *t;       n = make_shared_binary_string(name, name_length);    t = make_pike_type(type);   
pike.git/src/program.c:5146:    free_type(t);    return ret;   }      /* argument must be a shared string */   int define_variable(struct pike_string *name,    struct pike_type *type,    INT32 flags)   {    int n, run_time_type; +  int no_this = 0;      #ifdef PIKE_DEBUG    if(name!=debug_findstring(name))    Pike_fatal("define_variable on nonshared string.\n");   #endif      #ifdef PROGRAM_BUILD_DEBUG    {    struct compilation *c = THIS_COMPILATION;    struct pike_string *d = describe_type (type);
pike.git/src/program.c:5275:    }    }       if (flags & ID_EXTERN) {    run_time_type = PIKE_T_FREE;    } else {    run_time_type=compile_type_to_runtime_type(type);       switch(run_time_type)    { - #ifdef AUTO_BIGNUM -  case T_INT: - #endif +     case T_OBJECT:    /* Make place for the object subtype. */    case T_FUNCTION: -  +  no_this = 1; +  /* FALL_THROUGH */ +  case T_INT:    case T_PROGRAM:    run_time_type = T_MIXED;    }    }       n=low_define_variable(name,type,flags,    low_add_storage(sizeof_variable(run_time_type),    alignof_variable(run_time_type),0),    run_time_type);    -  +  if( no_this )    ID_FROM_INT(Pike_compiler->new_program, n)->identifier_flags |= IDENTIFIER_NO_THIS_REF;       return n;   }      PMOD_EXPORT int simple_add_variable(const char *name,    const char *type,    INT32 flags)   {    INT32 ret;
pike.git/src/program.c:5357: Inside #if 0
  #if 0    if (!c) {    c = &svalue_int_zero;    }   #endif      #ifdef PIKE_DEBUG    if(name!=debug_findstring(name))    Pike_fatal("define_constant on nonshared string.\n");    if (c) { -  check_svalue (c); +  check_svalue ((struct svalue*)c);    if (TYPEOF(*c) > MAX_TYPE)    /* check_svalue allows some things like T_SVALUE_PTR. */    Pike_fatal ("Invalid type in svalue: %d\n", TYPEOF(*c));    }   #endif       n = isidentifier(name);       if(   #if 1
pike.git/src/program.c:5404:    c = NULL;    } else {    /* Alias for a function or a variable or constant in a surrounding    * scope.    */    int n = SUBTYPEOF(*c);    struct reference *remote_ref = PTR_FROM_INT(state->new_program, n);    if (!(remote_ref->id_flags & (ID_INLINE|ID_HIDDEN))) {    /* We need to get a suitable reference. */    n = really_low_reference_inherited_identifier(state, 0, n); +  if (n < 0) return n;    }    return define_alias(name, id->type, flags, depth, n);    }    }    }       if(   #if 1    c &&   #endif
pike.git/src/program.c:5438:    id=ID_FROM_INT(Pike_compiler->new_program,n);    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);    }    free_type(id->type); -  if ((TYPEOF(*c) == T_INT) && !(flags & ID_INLINE)) { -  if (c->u.integer) { -  copy_pike_type(id->type, int_type_string); -  } else { -  copy_pike_type(id->type, zero_type_string); -  } -  } else { -  id->type = get_type_of_svalue(c); -  } +  if( !(flags & ID_INLINE) ) +  id->type = get_lax_type_of_svalue( c ); +  else +  id->type = get_type_of_svalue( c );   #ifdef PROGRAM_BUILD_DEBUG    fprintf (stderr, "%.*sstored constant #%d at %d\n",    cc->compilation_depth, "",    n, id->func.const_info.offset);   #endif    }    return n;    }      #ifdef PIKE_DEBUG
pike.git/src/program.c:5476:   #endif       copy_shared_string(dummy.name, name);    dummy.identifier_flags = IDENTIFIER_CONSTANT;    dummy.filename_strno = store_prog_string(cc->lex.current_file);    dummy.linenumber = cc->lex.current_line;      #if 1    if (c) {   #endif -  if ((TYPEOF(*c) == T_INT) && !(flags & ID_INLINE)) { -  if (c->u.integer) { -  copy_pike_type(dummy.type, int_type_string); -  } else { -  copy_pike_type(dummy.type, zero_type_string); -  } -  } else { -  dummy.type = get_type_of_svalue(c); -  } +  if( !(flags & ID_INLINE) ) +  dummy.type = get_lax_type_of_svalue( c ); +  else +  dummy.type = get_type_of_svalue( c );    dummy.run_time_type = (unsigned char) TYPEOF(*c);    dummy.func.const_info.offset = store_constant(c, 0, 0);    dummy.opt_flags=OPT_SIDE_EFFECT | OPT_EXTERNAL_DEPEND;    if(TYPEOF(*c) == PIKE_T_PROGRAM && (c->u.program->flags & PROGRAM_CONSTANT))    dummy.opt_flags=0;   #if 1    }    else {    copy_pike_type(dummy.type, mixed_type_string);    dummy.run_time_type=T_MIXED;    dummy.func.const_info.offset = -1;    dummy.opt_flags=0;    }   #endif    -  if (flags & ID_PRIVATE) flags |= ID_INLINE; +  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;      #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(n != -1)    {    int overridden;       if(IDENTIFIERP(n)->id_flags & ID_FINAL)    my_yyerror("Illegal to redefine 'final' identifier %S", name);    -  if(!TEST_COMPAT(7,2) && -  IDENTIFIER_IS_VARIABLE(ID_FROM_INT(Pike_compiler->new_program, +  if(IDENTIFIER_IS_VARIABLE(ID_FROM_INT(Pike_compiler->new_program,    n)->identifier_flags))    {    my_yyerror("Illegal to redefine variable %S as constant.", name);    }       /* not inherited */    if(Pike_compiler->new_program->identifier_references[n].inherit_offset == 0)    {    my_yyerror("Identifier %S defined twice.", name);    return n;    }       /* override */ -  if ((overridden = override_identifier (&ref, name)) >= 0) { +  if ((overridden = override_identifier (&ref, name, 0)) >= 0) {   #ifdef PIKE_DEBUG    struct reference *oref =    Pike_compiler->new_program->identifier_references+overridden;    if((oref->inherit_offset != ref.inherit_offset) ||    (oref->identifier_offset != ref.identifier_offset) ||    ((oref->id_flags | ID_USED) != (ref.id_flags | ID_USED))) {    Pike_fatal("New constant overriding algorithm failed!\n");    }   #endif    return overridden;
pike.git/src/program.c:5577:      PMOD_EXPORT int add_integer_constant(const char *name,    INT_ARG_TYPE i,    INT32 flags)   {    struct svalue tmp;    SET_SVAL(tmp, T_INT, NUMBER_NUMBER, integer, i);    return simple_add_constant(name, &tmp, flags);   }    + PMOD_EXPORT int low_add_integer_constant(struct pike_string *name, +  INT_ARG_TYPE i, +  INT32 flags) + { +  struct svalue tmp; +  SET_SVAL(tmp, T_INT, NUMBER_NUMBER, integer, i); +  return add_constant(name, &tmp, flags); + } +    PMOD_EXPORT int quick_add_integer_constant(const char *name,    int name_length,    INT_ARG_TYPE i,    INT32 flags)   { -  struct svalue tmp; -  struct pike_string *id; +     INT32 ret; -  -  SET_SVAL(tmp, T_INT, NUMBER_NUMBER, integer, i); -  id=make_shared_binary_string(name,name_length); -  ret=add_constant(id, &tmp, flags); -  free_string(id); +  struct pike_string *n = make_shared_binary_string(name, name_length); +  ret=low_add_integer_constant(n, i, flags); +  free_string(n);    return ret;   }      PMOD_EXPORT int add_float_constant(const char *name,    FLOAT_ARG_TYPE f,    INT32 flags)   {    struct svalue tmp;    SET_SVAL(tmp, T_FLOAT, 0, float_number, (FLOAT_TYPE)f);    return simple_add_constant(name, &tmp, flags);
pike.git/src/program.c:5692:    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;   }    - /* -  * define a new function + /** +  * 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,    unsigned opt_flags)   {    struct compilation *c = THIS_COMPILATION; -  +  struct program *prog = Pike_compiler->new_program;    struct identifier *funp,fun;    struct reference ref;    struct svalue *lfun_type;    int run_time_type = T_FUNCTION;    INT32 i; -  INT16 *getter_setter = NULL; +  int getter_setter = -1; +  int is_setter = 0;       CHECK_COMPILER();      #ifdef PROGRAM_BUILD_DEBUG    {    struct pike_string *d = describe_type (type);    fprintf (stderr, "%.*sdefining function (pass=%d): %s ",    c->compilation_depth, "", Pike_compiler->compiler_pass, d->str);    free_string (d);    push_string (name);    print_svalue (stderr, --Pike_sp);    putc ('\n', stderr);    }   #endif      #ifdef PROFILING    fun.self_time=0;    fun.num_calls=0; -  +  fun.recur_depth=0;    fun.total_time=0;   #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 */ -  +  /* 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) == '`') &&    ((index_shared_string(name, 1) >= 256) ||    isidchar(index_shared_string(name, 1))))) {    /* Getter setter. */    struct pike_string *symbol = NULL;    struct pike_type *symbol_type = NULL;    struct pike_type *gs_type = NULL; -  int is_setter = 0; +     int delta = 1; /* new-style */    if (index_shared_string(name, 1) == '-') {    /* Getter setter (old-style). */    delta = 3;    }    if (index_shared_string(name, name->len-1) != '=') {    /* fprintf(stderr, "Got getter: %s\n", name->str); */    gs_type = lfun_getter_type_string;    symbol = string_slice(name, delta, name->len-delta);    symbol_type = get_argument_type(type, -1);
pike.git/src/program.c:5785:    /* fprintf(stderr, "Got setter: %s\n", name->str); */    gs_type = lfun_setter_type_string;    is_setter = 1;    symbol = string_slice(name, delta, name->len-(delta+1));    symbol_type = get_argument_type(type, 0);    }       if (symbol) {    /* We got a getter or a setter. */    struct reference *ref; +  int orig_pragmas = c->lex.pragmas; +  /* Inhibit deprecation warnings during the comparison. */ +  c->lex.pragmas |= ID_NO_DEPRECATION_WARNINGS;    if (!pike_types_le(type, gs_type)) {    int level = REPORT_NOTICE;    if (!match_types(type, gs_type)) {    level = REPORT_ERROR;    } else if (c->lex.pragmas & ID_STRICT_TYPES) {    level = REPORT_WARNING;    }    yytype_report(level, NULL, 0, gs_type,    NULL, 0, type, 0,    "Type mismatch for callback function %S:", name);    } -  +  c->lex.pragmas = orig_pragmas; +  if (flags & ID_VARIANT) { +  my_yyerror("Variants not supported for getter/setters: %S", name); +  flags &= ~ID_VARIANT; +  }    i = isidentifier(symbol);    if ((i >= 0) && -  !((ref = PTR_FROM_INT(Pike_compiler->new_program, i))-> -  id_flags & ID_INHERITED)) { +  !((ref = PTR_FROM_INT(prog, i))->id_flags & ID_INHERITED)) {    /* Not an inherited symbol. */ -  struct identifier *id = ID_FROM_INT(Pike_compiler->new_program, i); +  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) {    yywarning("Modifier mismatch for variable %S.", symbol);    }    ref->id_flags &= flags | ID_USED;    } -  getter_setter = &id->func.gs_info.getter + is_setter; +  getter_setter = i;    }    /* FIXME: Update id->type here. */    } else {    struct identifier *id;    i = low_define_variable(symbol, symbol_type, flags,    ~0, PIKE_T_GET_SET); -  id = ID_FROM_INT(Pike_compiler->new_program, i); +  id = ID_FROM_INT(prog, i);       /* Paranoia. */    id->func.gs_info.getter = -1;    id->func.gs_info.setter = -1;    -  getter_setter = &id->func.gs_info.getter + is_setter; +  getter_setter = i;    }    /* NOTE: The function needs to have the same PRIVATE/INLINE    * behaviour as the variable for overloading to behave    * as expected.    *    * FIXME: Force PRIVATE?    */    flags |= ID_PROTECTED /* | ID_PRIVATE | ID_INLINE | ID_USED */;    free_type(symbol_type);    free_string(symbol);    }    }       if(IDENTIFIER_IS_C_FUNCTION(function_flags)) -  Pike_compiler->new_program->flags |= PROGRAM_HAS_C_METHODS; +  prog->flags |= PROGRAM_HAS_C_METHODS;       if (Pike_compiler->compiler_pass == 1) {    /* 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); +  i = isidentifier(name); +  if (Pike_compiler->compiler_pass == 1) { +  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. +  */ +  prog->identifier_references[i].id_flags |= ID_INHERITED; +  add_variant_dispatcher(name, type, flags); +  /* Restore the termination function as a variant. */ +  ref.id_flags |= ID_VARIANT; +  if (is_variant_dispatcher(prog, i)) { +  /* The termination function got replaced with +  * the variant dispatcher. +  */ +  add_to_identifier_references(ref); +  } else { +  /* The termination function is still in the same place. */ +  prog->identifier_references[i].id_flags = ref.id_flags; +  } +  } else if (prog->identifier_references[i].inherit_offset) { +  /* NB: If we are overriding an inherited dispatcher, there's +  * no need to go via it, since our new dispatcher can +  * just continue on with the old ones variant functions. +  */ +  add_variant_dispatcher(name, type, flags); +  } +  } else { +  add_variant_dispatcher(name, type, flags); +  } +  i = really_low_find_variant_identifier(name, prog, type, +  prog->num_identifier_references, +  SEE_PROTECTED|SEE_PRIVATE); +  } else if (is_variant_dispatcher(prog, i) && +  !prog->identifier_references[i].inherit_offset) { +  if (!func || (func->c_fun != f_dispatch_variant) || +  !IDENTIFIER_IS_C_FUNCTION(function_flags)) { +  /* FIXME: What about the case +  * +  * non-variant prototype; +  * +  * variant; +  * +  * non-variant definition. +  */ +  my_yyerror("Overriding variant function %S() with " +  "non-variant in the same class.", +  name); +  } +  } +  } else if (i >= 0) { +  /* Pass 2 */ +  if (is_variant_dispatcher(prog, i)) { +  if (!func || (func->c_fun != f_dispatch_variant) || +  !IDENTIFIER_IS_C_FUNCTION(function_flags)) { +  /* Variant or variant termination function in second pass. */ +  flags |= ID_VARIANT; +  i = really_low_find_variant_identifier(name, prog, type, +  prog->num_identifier_references, +  SEE_PROTECTED|SEE_PRIVATE); +  } +  } +  }       if(i >= 0)    {    int overridden;       /* already defined */      #ifdef PROGRAM_BUILD_DEBUG    fprintf(stderr, "%.*sexisted as identifier #%d\n",    c->compilation_depth, "", i);   #endif    -  funp=ID_FROM_INT(Pike_compiler->new_program, i); -  ref=Pike_compiler->new_program->identifier_references[i]; +  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) { -  *getter_setter = i; +  if (getter_setter != -1) { +  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) &&    (funp->run_time_type == T_FUNCTION)) {    /* match types against earlier prototype or vice versa */    if(!match_types(type, funp->type))    { -  if (!(flags & ID_VARIANT)) { +     yytype_report(REPORT_ERROR, NULL, 0,    funp->type,    NULL, 0, type, 0,    "Prototype doesn't match for function %S.", name);    }    } -  } +        if(func)    funp->func = *func;   #if 0 /* prototypes does not override non-prototypes, ok? */    else    funp->func.offset = -1;   #endif       funp->identifier_flags=function_flags;    funp->run_time_type = run_time_type;
pike.git/src/program.c:5933:       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) && +  (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; +  while ((j = really_low_find_variant_identifier(name, prog, NULL, j, +  SEE_PROTECTED|SEE_PRIVATE)) != -1) { +  if (!prog->identifier_references[j].inherit_offset) { +  /* FIXME: This doesn't catch all cases, and should probably +  * be moved to a place where it does. +  */ +  my_yyerror("Overloading variant function %S with non-variant in same class.", +  name); +  } +  prog->identifier_references[j].id_flags |= ID_HIDDEN; +  } +  }       if(ref.id_flags & ID_INLINE)    {   #ifdef PROGRAM_BUILD_DEBUG    fprintf(stderr, "%.*sidentifier is local\n",    c->compilation_depth, "");   #endif    /* Hide the previous definition, and make a new definition. */ -  Pike_compiler->new_program->identifier_references[i].id_flags |= -  ID_PROTECTED; +  prog->identifier_references[i].id_flags |= ID_PROTECTED;    goto make_a_new_def;    }       /* Otherwise we alter the existing definition */   #ifdef PROGRAM_BUILD_DEBUG    fprintf(stderr, "%.*saltering the existing definition\n",    c->compilation_depth, "");   #endif       copy_shared_string(fun.name, name);
pike.git/src/program.c:5968:       fun.identifier_flags=function_flags;       if(func)    fun.func = *func;    else    fun.func.offset = -1;       fun.opt_flags = opt_flags;    -  ref.identifier_offset=Pike_compiler->new_program->num_identifiers; +  ref.identifier_offset = prog->num_identifiers;    debug_add_to_identifiers(fun);    }    -  if (flags & ID_PRIVATE) flags |= ID_INLINE; +  if (flags & ID_PRIVATE) flags |= ID_LOCAL|ID_PROTECTED;       ref.inherit_offset = 0;    ref.id_flags = flags; -  if ((overridden = override_identifier (&ref, name)) >= 0) { +  if (flags & ID_VARIANT) { +  ref.id_flags |= ID_USED; +  prog->identifier_references[i] = ref; +  overridden = i; +  } else { +  overridden = override_identifier(&ref, name, 0); +  } +  if (overridden >= 0) {   #ifdef PIKE_DEBUG -  struct reference *oref = -  Pike_compiler->new_program->identifier_references+overridden; +  struct reference *oref = prog->identifier_references+overridden;    if((oref->inherit_offset != ref.inherit_offset) ||    (oref->identifier_offset != ref.identifier_offset) ||    ((oref->id_flags | ID_USED) != (ref.id_flags | ID_USED))) {    fprintf(stderr,    "ref: %d:%d 0x%04x\n"    "got: %d:%d 0x%04x (%d)\n",    ref.inherit_offset, ref.identifier_offset,    ref.id_flags,    oref->inherit_offset,    oref->identifier_offset,    oref->id_flags,    overridden);    Pike_fatal("New function overloading algorithm failed!\n");    }   #endif    -  if (getter_setter) { -  INT32 old_i = *getter_setter; +  if (getter_setter != -1) { +  struct identifier *id = ID_FROM_INT(prog, getter_setter); +  INT32 old_i = (&id->func.gs_info.getter)[is_setter];    if ((old_i >= 0) && (old_i != overridden)) {    my_yyerror("Multiple definitions for %S.", name);    } -  *getter_setter = overridden; +  (&id->func.gs_info.getter)[is_setter] = overridden;    }    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) -  Pike_fatal("Internal error: Not allowed to add more identifiers during second compiler pass.\n"); +  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 */       copy_shared_string(fun.name, name);    copy_pike_type(fun.type, type);    fun.filename_strno = store_prog_string(c->lex.current_file);    fun.linenumber = c->lex.current_line;       fun.identifier_flags=function_flags;
pike.git/src/program.c:6038:    else    fun.func.offset = -1;       fun.opt_flags = opt_flags;      #ifdef PIKE_DEBUG    if (a_flag > 5) {    fprintf(stderr,    "Adding new function #%d: '%s'\n"    " identifier_flags:0x%02x opt_flags:0x%04x\n", -  Pike_compiler->new_program->num_identifiers, +  prog->num_identifiers,    fun.name->str,    fun.identifier_flags, fun.opt_flags);    }   #endif /* PIKE_DEBUG */    -  i=Pike_compiler->new_program->num_identifiers; +  i = prog->num_identifiers;       debug_add_to_identifiers(fun);    -  if (flags & ID_PRIVATE) flags |= ID_INLINE; +  if (flags & ID_PRIVATE) flags |= ID_LOCAL|ID_PROTECTED;       ref.id_flags = flags;    ref.identifier_offset = i;    ref.inherit_offset = 0;    }       ref.run_time_type = PIKE_T_UNKNOWN;       /* Add the reference. */    -  i=Pike_compiler->new_program->num_identifier_references; +  i = prog->num_identifier_references;    add_to_identifier_references(ref);      #ifdef PROGRAM_BUILD_DEBUG    fprintf(stderr, "%.*sadded new definition #%d\n",    c->compilation_depth, "", i);   #endif    -  if (getter_setter) { -  INT32 old_i = *getter_setter; +  if (getter_setter != -1) { +  struct identifier *id = ID_FROM_INT(prog, getter_setter); +  INT32 old_i = (&id->func.gs_info.getter)[is_setter];    if (old_i >= 0) {    my_yyerror("Multiple definitions for %S.", name);    } -  *getter_setter = i; +  (&id->func.gs_info.getter)[is_setter] = i;    }       return i;   }      #if 0      int add_ext_ref(struct program_state *state, struct program *target, int i)   {    struct reference ref, *r;
pike.git/src/program.c:6107: Inside #if 0
   ref.identifier_offset = i;    ref.inherit_offset = 0;    ref.run_time_type = PIKE_T_UNKNOWN;    add_to_identifier_references(ref);    state->new_program->flags |= PROGRAM_USES_PARENT | PROGRAM_NEEDS_PARENT;    return j;   }      #endif /* 0 */    - /* Identifier lookup + /** +  * Identifier lookup    *    * The search algorithm has changed several times during Pike 7.3.    *    * It now (Pike 7.3.33 and later) looks up the most recent definition    * in the most recent inherit.    *    * In Pike 7.3.23 -- 7.3.32 it looked up the most recent definition    * with the least inherit depth.    *    * In Pike 7.3.22 and prior, it looked up the last definition regardless
pike.git/src/program.c:6180:    * B-+-foo All versions of Pike    * |    * +-A---foo    *    * External lookup of identifier "foo" in E():    *    * F-+-A---foo --- Pike 7.7.33    * |    * +-E---foo Pike 7.7.34 ---    */ - int really_low_find_shared_string_identifier(struct pike_string *name, -  struct program *prog, + PMOD_EXPORT int really_low_find_shared_string_identifier(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((stderr,"th(%ld) %p Trying to find %s flags=%d\n",    (long)th_self(), prog, name->str, flags));   #endif
pike.git/src/program.c:6208:   #endif /* PIKE_DEBUG */       id = -1;    depth = 0;    last_inh = prog->num_inherits;    i = (int)prog->num_identifier_references;    while(i--)    {    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(funp->id_flags & ID_INHERITED)    {    struct inherit *inh = INHERIT_FROM_PTR(prog, funp);    if ((funp->id_flags & ID_PRIVATE) && !(flags & SEE_PRIVATE)) continue;
pike.git/src/program.c:6248:    depth = inh->inherit_level;    id = i;    }    } else {    return i;    }    }    return id;   }    + 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; +  + #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 +  + #ifdef PIKE_DEBUG +  if (!prog) { +  Pike_fatal("really_low_find_variant_identifier(\"%s\", NULL, %p, %d, %d)\n" +  "prog is NULL!\n", name->str, type, start_pos, flags); +  } + #endif /* PIKE_DEBUG */ +  +  id = -1; +  depth = 0; +  last_inh = prog->num_inherits; +  i = start_pos; + #ifdef PIKE_DEBUG +  if (i > (int)prog->num_identifier_references) { +  Pike_fatal("really_low_find_variant_identifier(\"%s\", %p, %p, %d, %d):\n" +  "Start position is past max: %d\n", +  name->str, prog, type, start_pos, flags, +  prog->num_identifier_references); +  } + #endif /* PIKE_DEBUG */ +  while(i--) +  { +  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(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; +  if (inh2->inherit_level >= min_level) { +  /* Got deeper in the inherit graph */ +  continue; +  } +  min_level = inh2->inherit_level; +  } +  if (!(inh->inherit_level < min_level)) { +  continue; +  } +  /* Found new identifier on the path from the old identifier to +  * the root. +  */ +  } +  last_inh = funp->inherit_offset; +  depth = inh->inherit_level; +  id = i; +  } +  } else { +  CDFPRINTF((stderr, "Found %d\n", i)); +  return i; +  } +  } +  CDFPRINTF((stderr, "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) + { +  struct pike_frame *fp = Pike_fp; +  struct program *prog = fp->context->prog; +  struct reference *funp = PTR_FROM_INT(fp->current_program, fp->fun); +  struct identifier *id = ID_FROM_PTR(fp->current_program, funp); +  struct pike_string *name = id->name; +  int fun_num = prog->num_identifier_references; +  int flags = 0; +  int best = -1; +  struct pike_type *t; +  int expected = 0; +  +  /* NB: The following is mostly to support a potential future +  * case where a mixed set of protections would cause +  * multiple dispatchers with the same name to be added +  * (but different protection (and types)). +  */ +  if (funp->id_flags & ID_PRIVATE) { +  flags = SEE_PRIVATE|SEE_PROTECTED; +  } else if (funp->id_flags & ID_PROTECTED) { +  flags = SEE_PROTECTED; +  } +  +  while ((fun_num = really_low_find_variant_identifier(name, prog, NULL, +  fun_num, flags)) != -1) { +  int i; +  struct pike_type *ret; +  +  id = ID_FROM_INT(prog, fun_num); +  add_ref(t = id->type); +  +  /* Check whether the type is compatible with our arguments. */ +  for (i = 0; i < args; i++) { +  struct pike_type *cont = +  check_call_svalue(t, 0, Pike_sp+i - (args + expected)); +  if (!cont && (i >= best)) { +  if ((i > best) && expected) { +  pop_n_elems(expected); +  expected = 0; +  } +  best = i; +  push_type_value(t); +  expected++; +  t = NULL; +  break; +  } else { +  free_type(t); +  } +  if (!(t = cont)) break; +  } +  if (!t) continue; +  ret = new_get_return_type(t, 0); +  +  if (!ret && (i+1 >= best)) { +  if (((i+1) > best) && expected) { +  pop_n_elems(expected); +  expected = 0; +  } +  best = i+1; +  push_type_value(t); +  expected++; +  continue; +  } +  free_type(t); +  if (!ret) continue; +  free_type(ret); +  +  if (expected) { +  pop_n_elems(expected); +  } +  +  /* Found a function to call! */ +  apply_current(fun_num, args); +  return; +  } +  if (!expected) { +  /* No variants listed? */ +  Pike_error("No variants of %S() to dispatch to!\n", name); +  } +  if (expected > 1) { +  f_or(expected); +  } +  f___get_first_arg_type(1); +  if (!UNSAFE_IS_ZERO(Pike_sp-1)) { +  if (best < args) { +  Pike_error("Bad argument %d to %S(). Expected %O.\n", +  best + 1, name, Pike_sp-1); +  } else { +  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, ptrdiff_t lfun)   { -  struct pike_string *lfun_name = lfun_strings[lfun]; +  struct pike_string *lfun_name;    unsigned int flags = 0; - #if 0 +  int i;    struct identifier *id; - #endif -  int i = -  really_low_find_shared_string_identifier(lfun_name, +  if ((size_t)lfun >= NELEM(lfun_strings)) { +  return find_lfun_fatal(p, lfun); +  } +  +  lfun_name = lfun_strings[lfun]; +  +  i = really_low_find_shared_string_identifier(lfun_name,    dmalloc_touch(struct program *,    p),    SEE_PROTECTED); - #if 0 +     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;    } - #endif /* 0 */ +     return i;   }    -  + PMOD_EXPORT int find_lfun_fatal(struct program *UNUSED(p), ptrdiff_t lfun) + { +  Pike_fatal("Invalid lfun number: %d\n", lfun); +  UNREACHABLE(return -1); + } +    int lfun_lookup_id(struct pike_string *lfun_name)   {    struct svalue *id = low_mapping_string_lookup(lfun_ids, lfun_name);    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 + /** +  * 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, -  struct program *prog) +  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);      #ifdef PIKE_DEBUG
pike.git/src/program.c:6341: Inside #if defined(FIND_FUNCTION_HASHSIZE)
  {    struct pike_string *name;    int id;    int fun;   };      static struct ff_hash cache[FIND_FUNCTION_HASHSIZE];   #endif      int find_shared_string_identifier(struct pike_string *name, -  struct program *prog) +  const struct program *prog)   {   #ifdef PIKE_DEBUG    if (!prog) {    Pike_fatal("find_shared_string_identifier(): No program!\n"    "Identifier: %s%s%s\n",    name?"\"":"", name?name->str:"NULL", name?"\"":"");    }   #endif /* PIKE_DEBUG */   #ifdef FIND_FUNCTION_HASHSIZE    if(prog -> flags & PROGRAM_FIXED   #if FIND_FUNCTION_HASH_TRESHOLD - 0    && prog->num_identifier_index >= FIND_FUNCTION_HASH_TRESHOLD   #endif    )    {    size_t hashval;    hashval = my_hash_string(name);    hashval += prog->id; -  hashval %= FIND_FUNCTION_HASHSIZE; +  hashval &= (FIND_FUNCTION_HASHSIZE-1);    if(is_same_string(cache[hashval].name,name) &&    cache[hashval].id==prog->id)    return cache[hashval].fun;       if(cache[hashval].name) free_string(cache[hashval].name);    copy_shared_string(cache[hashval].name,name);    cache[hashval].id=prog->id;    return cache[hashval].fun=low_find_shared_string_identifier(name,prog);    }   #endif /* FIND_FUNCTION_HASHSIZE */       return low_find_shared_string_identifier(name,prog);   }    - PMOD_EXPORT int find_identifier(const char *name,struct program *prog) + PMOD_EXPORT int find_identifier(const char *name,const struct program *prog)   {    struct pike_string *n;    if(!prog) {    if (strlen(name) < 1024) {    Pike_error("Lookup of identifier %s in destructed object.\n", name);    } else {    Pike_error("Lookup of long identifier in destructed object.\n");    }    }    n=findstring(name);    if(!n) return -1;    return find_shared_string_identifier(n,prog);   }      int store_prog_string(struct pike_string *str)   {    unsigned int i; -  +  if( str->refs > 1 )    for (i=0;i<Pike_compiler->new_program->num_strings;i++)    if (Pike_compiler->new_program->strings[i] == str)    return i;       reference_shared_string(str);    add_to_strings(str); -  return i; +  return Pike_compiler->new_program->num_strings-1;   }      /* NOTE: O(n¬≤)! */   int store_constant(const struct svalue *foo,    int equal, -  struct pike_string *constant_name) +  struct pike_string *UNUSED(constant_name))   {    struct program_constant tmp;    volatile unsigned int e;       JMP_BUF jmp;    if (SETJMP(jmp)) {    handle_compile_exception ("Error comparing constants.");    /* Assume that if `==() throws an error, the svalues aren't equal. */    e = Pike_compiler->new_program->num_constants;    } else { -  +  if(!equal && +  (TYPEOF(*foo) == PIKE_T_MAPPING || +  TYPEOF(*foo) == PIKE_T_MULTISET || +  TYPEOF(*foo) == PIKE_T_STRING || +  TYPEOF(*foo) == PIKE_T_ARRAY )) /* no possibility of comparator. Check refs first. */ +  { +  if(*foo->u.refs == 1 ) +  { +  e = Pike_compiler->new_program->num_constants; +  goto not_present; +  } +  } +     for(e=0;e<Pike_compiler->new_program->num_constants;e++)    {    struct program_constant *c = Pike_compiler->new_program->constants+e;       if (TYPEOF(*foo) == TYPEOF(c->sval)) {    /* Make sure only to compare within the same basic type. */    if (TYPEOF(*foo) == T_OBJECT) {    /* Special case objects -- We don't want strange LFUN effects... */    if ((foo->u.object == c->sval.u.object) &&    (SUBTYPEOF(*foo) == SUBTYPEOF(c->sval))) {    UNSETJMP(jmp);    return e;    }    } else if (TYPEOF(*foo) == T_INT) {    if (foo->u.integer == c->sval.u.integer) {    /* Make sure UNDEFINED is kept (but not in compat mode). */ -  if (foo->u.integer || (SUBTYPEOF(*foo) == SUBTYPEOF(c->sval)) || -  TEST_COMPAT(7, 6)) { +  if (foo->u.integer || (SUBTYPEOF(*foo) == SUBTYPEOF(c->sval))){    UNSETJMP(jmp);    return e;    }    }    } else if(equal ? is_equal(& c->sval,foo) : is_eq(& c->sval,foo)) {    UNSETJMP(jmp);    return e;    }    }    }    } -  + not_present:    UNSETJMP(jmp);    assign_svalue_no_free(&tmp.sval,foo);   #if 0    if((tmp.name=constant_name)) add_ref(constant_name);   #else /* !0 */    tmp.offset = -1;   #endif /* 0 */       add_to_constants(tmp);   
pike.git/src/program.c:6471:    */      struct array *program_indices(struct program *p)   {    int e;    int n = 0;    struct array *res;    for (e = p->num_identifier_references; e--; ) {    struct identifier *id;    if (p->identifier_references[e].id_flags & -  (ID_HIDDEN|ID_PROTECTED|ID_PRIVATE)) { +  (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 program *p2 = PROG_FROM_INT(p, e);
pike.git/src/program.c:6510:   }      struct array *program_values(struct program *p)   {    int e;    int n = 0;    struct array *res;    for(e = p->num_identifier_references; e--; ) {    struct identifier *id;    if (p->identifier_references[e].id_flags & -  (ID_HIDDEN|ID_PROTECTED|ID_PRIVATE)) { +  (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 program *p2 = PROG_FROM_INT(p, e);
pike.git/src/program.c:6549:   }      struct array *program_types(struct program *p)   {    int e;    int n = 0;    struct array *res;    for (e = p->num_identifier_references; e--; ) {    struct identifier *id;    if (p->identifier_references[e].id_flags & -  (ID_HIDDEN|ID_PROTECTED|ID_PRIVATE)) { +  (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 program *p2 = PROG_FROM_INT(p, e);
pike.git/src/program.c:6692:    if (low_program_index_no_free(to, p, e, parent, parent_identifier))    return 1;    }       SET_SVAL(*to, T_INT, NUMBER_UNDEFINED, integer, 0);    return 1;   }      /*    * Line number support routines, now also tells what file we are in. -  * -  * FIXME: Consider storing the filenames in strings (like what is now done -  * for identifiers). +     */      /* program.linenumbers format:    *    * Filename entry:    * 1. char 127 (marker). -  * 2. small number Filename string length. -  * 3. char Filename string size shift. -  * 4. string data (Possibly wide) filename string without null -  * termination. -  * Each character is stored in native byte order. +  * 2. small number Filename entry number in string table.    *    * 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.    * Else if -32768 <= n < 32768:    * 1. char -127 (marker).    * 2. short The 16-bit signed number stored in big endian order. -  +  * Else if n < -0x80000000 or n > 0x7fffffff: +  * 1. char -127 (marker). +  * 2. short Zero (64-bit marker). +  * 3. INT_TYPE The 64-bit signed number stored in big endian order.    * Else:    * 1. char -128 (marker).    * 2. int The 32-bit signed number stored in big endian order.    *    * Whenever the filename changes, a filename entry followed by a line    * number entry is stored. If only the line number changes, a line    * number entry is stored. The first stored entry (at pc 0) is the    * file and line where the program is defined, if they are known. The    * definition line for a top level program is set to 0.    */    - int get_small_number(char **q) + INT_TYPE get_small_number(char **q)   {    /* This is a workaround for buggy cc & Tru64 */    unsigned char *addr = (unsigned char *)*q; -  int ret = *((signed char *)addr); -  ret=*(signed char *)*q; +  INT_TYPE ret = *((signed char *)addr);    addr++;    switch(ret)    {    case -127: -  ret = (((signed char *)addr)[0]<<8) | addr[1]; +  ret = (INT16)get_unaligned_be16(addr);    addr += 2; -  +  if (!ret) { +  /* 64-bit signed number. */ +  ret = get_unaligned_be64(addr); +  addr += 8; +  }    break;       case -128: -  ret = (((signed char *)addr)[0]<<24) | (addr[1]<<16) | -  (addr[2]<<8) | addr[3]; +  ret = (INT32)get_unaligned_be32(addr);    addr += 4;    break;      #ifdef PIKE_DEBUG    case 127:    Pike_fatal("get_small_number used on filename entry\n");   #endif    }    *q = (char *)addr;    return ret;
pike.git/src/program.c:6770:   void start_line_numbering(void)   {    if(Pike_compiler->last_file)    {    free_string(Pike_compiler->last_file);    Pike_compiler->last_file=0;    }    Pike_compiler->last_pc=Pike_compiler->last_line=0;   }    - static void insert_small_number(INT32 a) + static void insert_small_number(INT_TYPE a)   {   #ifdef PIKE_DEBUG -  int start = Pike_compiler->new_program->num_linenumbers; +  size_t start = Pike_compiler->new_program->num_linenumbers;   #endif /* PIKE_DEBUG */    if(a>-127 && a<127)    {    add_to_linenumbers(a);    }else if(a>=-32768 && a<32768){    add_to_linenumbers(-127);    add_to_linenumbers(a>>8);    add_to_linenumbers(a); -  + #ifdef INT_TYPE_INT32_CONVERSION +  } else if (a < -0x80000000L || a > 0x7fffffffL) { +  /* Overload 16-bit zero as marker for 64-bit. */ +  fprintf(stderr, "Saving huge linenumber: %lld\n", (long long)a); +  add_to_linenumbers(-127); +  add_to_linenumbers(0); +  add_to_linenumbers(0); +  add_to_linenumbers(a>>56); +  add_to_linenumbers(a>>48); +  add_to_linenumbers(a>>40); +  add_to_linenumbers(a>>32); +  add_to_linenumbers(a>>24); +  add_to_linenumbers(a>>16); +  add_to_linenumbers(a>>8); +  add_to_linenumbers(a); + #endif    }else{    add_to_linenumbers(-128);    add_to_linenumbers(a>>24);    add_to_linenumbers(a>>16);    add_to_linenumbers(a>>8);    add_to_linenumbers(a);    }   #ifdef PIKE_DEBUG    {    char *tmp = Pike_compiler->new_program->linenumbers + start; -  INT32 res = get_small_number(&tmp); +  INT_TYPE res = get_small_number(&tmp);    if (a != res) {    tmp = Pike_compiler->new_program->linenumbers + start;    fprintf(stderr, "0x%p: %02x %02x %02x %02x %02x\n",    tmp, (unsigned char) tmp[0], (unsigned char) tmp[1],    (unsigned char) tmp[2], (unsigned char) tmp[3], (unsigned char) tmp[4]); -  Pike_fatal("insert_small_number failed: %d (0x%08x) != %d (0x%08x)\n", -  a, a, res, res); +  if ((start + 5) < Pike_compiler->new_program->num_linenumbers) { +  /* 64-bit. Dump the remaining 6 bytes as well. */ +  fprintf(stderr, "0x%p: %02x %02x %02x %02x %02x %02x\n", +  tmp, (unsigned char) tmp[5], (unsigned char) tmp[6], +  (unsigned char) tmp[7], (unsigned char) tmp[8], +  (unsigned char) tmp[9], (unsigned char) tmp[10]);    } -  +  Pike_fatal("insert_small_number failed: %ld (0x%08lx) != %ld (0x%08lx)\n", +  (long)a, (long)a, (long)res, (long)res);    } -  +  }   #endif /* PIKE_DEBUG */   }    - static void ext_insert_small_number (char **ptr, INT32 a) + static void ext_insert_small_number (char **ptr, INT_TYPE a)   {    if(a>-127 && a<127)    {    *(*ptr)++ = a;    }else if(a>=-32768 && a<32768){    *(*ptr)++ = -127;    *(*ptr)++ = a>>8;    *(*ptr)++ = a; -  + #ifdef INT_TYPE_INT32_CONVERSION +  } else if (a < -0x80000000L || a > 0x7fffffffL) { +  /* Overload 16-bit zero as marker for 64-bit. */ +  *(*ptr)++ = -127; +  *(*ptr)++ = 0; +  *(*ptr)++ = 0; +  *(*ptr)++ = a>>56; +  *(*ptr)++ = a>>48; +  *(*ptr)++ = a>>40; +  *(*ptr)++ = a>>32; +  *(*ptr)++ = a>>24; +  *(*ptr)++ = a>>16; +  *(*ptr)++ = a>>8; +  *(*ptr)++ = a; + #endif    }else{    *(*ptr)++ = -128;    *(*ptr)++ = a>>24;    *(*ptr)++ = a>>16;    *(*ptr)++ = a>>8;    *(*ptr)++ = a;    }   }    - void ext_store_program_line (struct program *prog, INT32 line, struct pike_string *file) + void ext_store_program_line (struct program *prog, INT_TYPE line, struct pike_string *file)   {    char *ptr;      #ifdef PIKE_DEBUG -  if (prog->linenumbers) +  if (prog->linenumbers || prog->strings)    Pike_fatal ("Program already got linenumber info.\n");    if (Pike_compiler->new_program == prog)    Pike_fatal ("Use store_linenumber instead when the program is compiled.\n");   #endif    -  ptr = prog->linenumbers = xalloc (1 + 5 + 1 + (file->len << file->size_shift) + 5 + 5); -  *ptr++ = 127; -  ext_insert_small_number (&ptr, file->len); -  *ptr++ = (char) file->size_shift; -  MEMCPY (ptr, file->str, file->len << file->size_shift); -  ptr += file->len << file->size_shift; -  *ptr++ = 0; /* PC */ -  ext_insert_small_number (&ptr, line); +  add_ref((prog->strings = xalloc(sizeof(struct pike_string *)))[0] = file); +  prog->num_strings = 1; +  +  ptr = prog->linenumbers = xalloc (1 + 1 + 1 + 11); +  *ptr++ = 127; /* 1 */ +  *ptr++ = 0; /* String #0 */ /* 1 */ +  *ptr++ = 0; /* PC */ /* 1 */ +  ext_insert_small_number (&ptr, line); /* 11 */    prog->num_linenumbers = ptr - prog->linenumbers;   }    - void store_linenumber(INT32 current_line, struct pike_string *current_file) + void store_linenumber(INT_TYPE current_line, struct pike_string *current_file)   {   /* if(!store_linenumbers) Pike_fatal("Fnord.\n"); */   #ifdef PIKE_DEBUG    if(a_flag)    { -  INT32 line=0, off=0; -  size_t len = 0; -  INT32 shift = 0; -  char *file=0; +  INT_TYPE line=0; +  INT32 off=0;    char *cnt=Pike_compiler->new_program->linenumbers; -  +  struct pike_string *file = NULL;       if (a_flag > 50) { -  fprintf(stderr, "store_linenumber(%d, \"%s\") at pc %d\n", -  current_line, current_file->str, +  fprintf(stderr, "store_linenumber(%ld, \"%s\") at pc %d\n", +  (long)current_line, current_file->str,    (INT32) PIKE_PC); -  fprintf(stderr, " last_line:%d last_file:\"%s\"\n", -  Pike_compiler->last_line, +  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)    { -  +  int strno;    cnt++; -  len = get_small_number(&cnt); -  shift = *cnt; -  file = ++cnt; -  CHECK_FILE_ENTRY (Pike_compiler->new_program, cnt, len, shift); -  cnt += len<<shift; +  strno = get_small_number(&cnt); +  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", -  len, shift); +  file->len, file->size_shift);    }    }    off+=get_small_number(&cnt);    line+=get_small_number(&cnt);    if (a_flag > 100) { -  fprintf(stderr, " off: %d, line: %d\n" +  fprintf(stderr, " off: %d, line: %ld\n"    " raw: ", -  off, line); +  off, (long)line);    for (;start < cnt; start++) {    fprintf(stderr, "%02x ", *((unsigned char *)start));    }    fprintf(stderr, "\n");    }    }       if(Pike_compiler->last_line != line ||    Pike_compiler->last_pc != off || -  (Pike_compiler->last_file && file && -  MEMCMP(Pike_compiler->last_file->str, file, len<<shift))) +  (file && (Pike_compiler->last_file != file)))    {    Pike_fatal("Line numbering out of whack\n" -  " (line : %d ?= %d)!\n" +  " (line : %ld ?= %ld)!\n"    " ( pc : %d ?= %d)!\n"    " (shift: %d ?= %d)!\n"    " (len : %"PRINTSIZET"d ?= %"PRINTSIZET"d)!\n"    " (file : %s ?= %s)!\n", -  Pike_compiler->last_line, line, +  (long)Pike_compiler->last_line, (long)line,    Pike_compiler->last_pc, off,    Pike_compiler->last_file?Pike_compiler->last_file->size_shift:0, -  shift, -  Pike_compiler->last_file?Pike_compiler->last_file->len:0, len, +  file?file->size_shift:0, +  Pike_compiler->last_file?Pike_compiler->last_file->len:0, +  file?file->len:0,    Pike_compiler->last_file?Pike_compiler->last_file->str:"N/A", -  file?file:"N/A"); +  file?file->str:"N/A");    }    }   #endif    if(Pike_compiler->last_line != current_line ||    Pike_compiler->last_file != current_file)    {    if(Pike_compiler->last_file != current_file)    { -  char *tmp; -  INT32 remain = DO_NOT_WARN((INT32)current_file->len)<< -  current_file->size_shift; -  +     if(Pike_compiler->last_file) free_string(Pike_compiler->last_file);    add_to_linenumbers(127); -  insert_small_number(DO_NOT_WARN((INT32)current_file->len)); -  add_to_linenumbers(current_file->size_shift); -  for(tmp=current_file->str; remain-- > 0; tmp++) -  add_to_linenumbers(*tmp); +  insert_small_number(store_prog_string(current_file));    copy_shared_string(Pike_compiler->last_file, current_file);    } -  insert_small_number(DO_NOT_WARN((INT32)(PIKE_PC-Pike_compiler->last_pc))); +  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 = DO_NOT_WARN((INT32)PIKE_PC); +  Pike_compiler->last_pc = (INT32)PIKE_PC;    }   }    - #define FIND_PROGRAM_LINE(prog, file, len, shift, line) do { \ + #define FIND_PROGRAM_LINE(prog, file, line) do { \    char *pos = prog->linenumbers; \ -  len = 0; \ -  shift = 0; \ +     file = NULL; \    \    if (pos < prog->linenumbers + prog->num_linenumbers) { \    if (*pos == 127) { \ -  +  int strno; \    pos++; \ -  len = get_small_number(&pos); \ -  shift = *pos; \ -  file = ++pos; \ -  CHECK_FILE_ENTRY (prog, pos, len, shift); \ -  pos += len<<shift; \ +  strno = get_small_number(&pos); \ +  CHECK_FILE_ENTRY (prog, strno); \ +  file = prog->strings[strno]; \    } \    get_small_number(&pos); /* Ignore the offset */ \    line = get_small_number(&pos); \    } \    } while (0)      PMOD_EXPORT struct pike_string *low_get_program_line (struct program *prog, -  INT32 *linep) +  INT_TYPE *linep)   {    *linep = 0;       if (prog->linenumbers) { -  size_t len; -  INT32 shift; -  char *file; +  struct pike_string *file;    -  FIND_PROGRAM_LINE (prog, file, len, shift, (*linep)); +  FIND_PROGRAM_LINE (prog, file, (*linep));       if (file) { -  struct pike_string *str = begin_wide_shared_string(len, shift); -  memcpy(str->str, file, len<<shift); -  return end_shared_string(str); +  add_ref(file); +  return file;    }    }       return NULL;   }    - static char *make_plain_file (char *file, size_t len, INT32 shift, int malloced) + static char *make_plain_file (struct pike_string *filename, int malloced)   {    static char buf[1000]; -  +  char *file = filename->str; +  size_t len = filename->len; +  INT32 shift = filename->size_shift; +     if(shift)    {    size_t bufsize;    char *buffer;    PCHARP from=MKPCHARP(file, shift);    size_t ptr=0;       if (malloced) { -  bufsize = len + 1; +  bufsize = len + 21;    buffer = malloc (bufsize); -  +  if(!buffer) return NULL;    }    else {    bufsize = NELEM(buf) - 1;    buffer = buf;    }       for (; len--; INC_PCHARP(from, 1))    {    size_t space;    int chr = EXTRACT_PCHARP(from);    space = chr > 255 ? 20 : 1;       if (ptr + space > bufsize) {    if (malloced) { -  +  char *new_buffer;    bufsize = (bufsize << 1) + space + 1; -  buffer = realloc (buffer, bufsize); +  new_buffer = realloc (buffer, bufsize); +  if(!new_buffer) +  { +  free(buffer); +  return NULL;    } -  +  buffer = new_buffer; +  }    else    break;    }       if(chr > 255)    {    sprintf(buffer+ptr,"\\u%04X",chr);    ptr+=strlen(buffer+ptr);    }else{    buffer[ptr++]=chr;
pike.git/src/program.c:7040:       else{    char *buffer;    if (malloced)    buffer = malloc (len + 1);    else {    buffer = buf;    if (len > NELEM (buf) - 1)    len = NELEM (buf) - 1;    } -  MEMCPY (buffer, file, len); +  memcpy (buffer, file, len);    buffer[len] = 0;    return buffer;    }   }    - /* Same as low_get_program_line but returns a plain char *. It's + /** +  * Same as low_get_program_line but returns a plain char *. It's    * malloced if the malloced flag is set, otherwise it's a pointer to a    * static buffer which might be clobbered by later calls.    *    * This function is useful when the shared string table has been freed    * and in sensitive parts of the gc where the shared string structures    * can't be touched. It also converts wide strings to ordinary ones    * with escaping.    */ - PMOD_EXPORT char *low_get_program_line_plain(struct program *prog, INT32 *linep, + PMOD_EXPORT char *low_get_program_line_plain(struct program *prog, +  INT_TYPE *linep,    int malloced)   {    *linep = 0;       if (prog->linenumbers) { -  char *file; -  size_t len; -  INT32 shift; -  FIND_PROGRAM_LINE (prog, file, len, shift, (*linep)); -  if (file) return make_plain_file (file, len, shift, malloced); +  struct pike_string *file; +  FIND_PROGRAM_LINE (prog, file, (*linep)); +  if (file) +  return make_plain_file(file, malloced);    }       return NULL;   }    - /* Returns the file where the program is defined. The line of the + /** +  * Returns the file where the program is defined. The line of the    * class start is written to linep, or 0 if the program is the top -  * level of the file. */ +  * level of the file. +  */   PMOD_EXPORT struct pike_string *get_program_line(struct program *prog, -  INT32 *linep) +  INT_TYPE *linep)   {    struct pike_string *res = low_get_program_line(prog, linep);    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, INT32 *linep) +  struct program *prog, +  INT_TYPE *linep)   {    linep[0] = 0;       if (prog->program && prog->linenumbers) {    ptrdiff_t offset = pc - prog->program;    if ((offset < (ptrdiff_t)prog->num_program) && (offset >= 0)) { -  static char *file = NULL; +  static struct pike_string *file = NULL;    static char *base, *cnt; -  static INT32 off,line,pid; -  static size_t len; -  static INT32 shift; +  static ptrdiff_t off; +  static INT32 pid; +  static INT_TYPE line;    -  if(prog->linenumbers != base || prog->id != pid || offset < off) -  { +  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; -  }else{ -  if (cnt < prog->linenumbers + prog->num_linenumbers) -  goto fromold; -  } +        while(cnt < prog->linenumbers + prog->num_linenumbers)    {    if(*cnt == 127)    { -  +  int strno;    cnt++; -  len = get_small_number(&cnt); -  shift = *cnt; -  file = ++cnt; -  CHECK_FILE_ENTRY (prog, cnt, len, shift); -  cnt += len<<shift; +  strno = get_small_number(&cnt); +  CHECK_FILE_ENTRY (prog, strno); +  file = prog->strings[strno]; +  continue;    }    off+=get_small_number(&cnt);    fromold:    if(off > offset) break;    line+=get_small_number(&cnt);    } -  +  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 (file) { -  struct pike_string *res = begin_wide_shared_string(len, shift); -  memcpy(res->str, file, len<<shift); -  return end_shared_string(res); +  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",    prog->program, prog->linenumbers);    }       return NULL;   }    - /* This is to low_get_line as low_get_program_line_plain is to -  * low_get_program_line. */ + /** +  * This is to low_get_line as low_get_program_line_plain is to +  * low_get_program_line. +  */   PMOD_EXPORT char *low_get_line_plain (PIKE_OPCODE_T *pc, struct program *prog, -  INT32 *linep, int malloced) +  INT_TYPE *linep, int malloced)   {    linep[0] = 0;       if (prog->program && prog->linenumbers) {    ptrdiff_t offset = pc - prog->program;       if ((offset < (ptrdiff_t)prog->num_program) && (offset >= 0)) {    char *cnt = prog->linenumbers; -  INT32 off = 0, line = 0; -  char *file = NULL; -  size_t len = 0; -  INT32 shift = 0; +  INT32 off = 0; +  INT_TYPE line = 0; +  struct pike_string *file = NULL;       while(cnt < prog->linenumbers + prog->num_linenumbers)    {    if(*cnt == 127)    { -  +  int strno;    cnt++; -  len = get_small_number(&cnt); -  shift = *cnt; -  file = ++cnt; -  CHECK_FILE_ENTRY (prog, cnt, len, shift); -  cnt += len<<shift; +  strno = get_small_number(&cnt); +  CHECK_FILE_ENTRY (prog, strno); +  file = prog->strings[strno];    }    off+=get_small_number(&cnt);    if(off > offset) break;    line+=get_small_number(&cnt);    }    linep[0]=line;    -  if (file) return make_plain_file (file, len, shift, malloced); +  if (file) +  return make_plain_file(file, malloced);    }    }       return NULL;   }      #ifdef PIKE_DEBUG   /* Variants for convenient use from a debugger. */      void gdb_program_line (struct program *prog)   { -  INT32 line; +  INT_TYPE line;    char *file = low_get_program_line_plain (prog, &line, 0); -  fprintf (stderr, "%s:%d\n", file, line); +  fprintf (stderr, "%s:%ld\n", file, (long)line);   }      void gdb_get_line (PIKE_OPCODE_T *pc, struct program *prog)   { -  INT32 line; +  INT_TYPE line;    char *file = low_get_line_plain (pc, prog, &line, 0); -  fprintf (stderr, "%s:%d\n", file, line); +  fprintf (stderr, "%s:%ld\n", file, (long)line);   }      #endif    - /* -  * return the file in which we were executing. pc should be the + /** +  * Return the file in which we were executing. pc should be the    * program counter (i.e. the address in prog->program), prog the    * current program, and line will be initialized to the line in that    * file.    */   PMOD_EXPORT struct pike_string *get_line(PIKE_OPCODE_T *pc, -  struct program *prog, INT32 *linep) +  struct program *prog, +  INT_TYPE *linep)   {    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);    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, INT32 *linep) +  int fun, +  INT_TYPE *linep)   {    if (o->prog) {    struct program *p;    struct identifier *id;    struct pike_string *ret;    while (1) {    struct external_variable_context loc;    struct reference *idref = o->prog->identifier_references + fun;    p = PROG_FROM_PTR(o->prog, idref);    id = p->identifiers + idref->identifier_offset;
pike.git/src/program.c:7265:    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;   }    - /* Return the file and line where the identifier with reference number + /** +  * Return the file and line where the identifier with reference number    * fun was defined.    *    * Note: Unlike the other get*line() functions, this one does not    * add a reference to the returned string.    */   PMOD_EXPORT struct pike_string *get_identifier_line(struct program *p, -  int fun, INT32 *linep) +  int fun, +  INT_TYPE *linep)   {    struct reference *ref = PTR_FROM_INT(p, fun);    struct identifier *id = ID_FROM_PTR(p, ref);    p = PROG_FROM_PTR(p, ref);    if (id->filename_strno >= p->num_strings) return NULL;    if (linep) *linep = id->linenumber;    return p->strings[id->filename_strno];   }    - /* Main entry point for compiler messages originating from -  * C-code. + /** +  * Main entry point for compiler messages originating from C-code.    *    * Sends the message along to PikeCompiler()->report().    *    * NOTE: The format string fmt (and vargs) is only formatted with    * string_builder_vsprintf() if the number of extra    * Pike stack arguments (args) is zero.    *    * NOTE: This function may be called from functions that sometimes    * execute outside of the compilation context, eg by    * __handle_sprintf_format(), which can be called directly    * by Pike-code, in which case it is a NO-OP.    */   PMOD_EXPORT void va_yyreport(int severity_level, -  struct pike_string *file, INT32 line, +  struct pike_string *file, INT_TYPE line,    struct pike_string *system, INT32 args,    const char *fmt, va_list vargs)   {    struct compilation *c = MAYBE_THIS_COMPILATION;    struct string_builder s;       if (!c) {    /* No compiler context. */    pop_n_elems(args);    return;
pike.git/src/program.c:7372:    push_string(finish_string_builder(&s));    }       safe_apply_current(PC_REPORT_FUN_NUM, args + 5);    pop_stack();    if (args) pop_n_elems(args);    STACK_LEVEL_DONE(0);   }      PMOD_EXPORT void low_yyreport(int severity_level, -  struct pike_string *file, INT32 line, +  struct pike_string *file, INT_TYPE line,    struct pike_string *system,    INT32 args, const char *fmt, ...)   {    va_list vargs;       va_start(vargs,fmt);    va_yyreport(severity_level, file, line, system, args, fmt, vargs);    va_end(vargs);   }   
pike.git/src/program.c:7417:    va_start(vargs,fmt);    va_yyreport(REPORT_ERROR, NULL, 0, parser_system_string, 0, fmt, vargs);    va_end(vargs);   }      PMOD_EXPORT void yyerror(const char *str)   {    my_yyerror("%s", str);   }    - /* Main entry point for errors from the type-checking subsystems. + /** +  * Main entry point for errors from the type-checking subsystems.    *    * The message (if any) will be formatted for the same source    * position as the got_t.    *    * The expect_t will be formatted for the same position as the got_t    * if there's no expected_file/expected_line.    *    * The got_t will be formatted for the current lex position if there's    * no got_file/got_line.    */   void yytype_report(int severity_level, -  struct pike_string *expected_file, INT32 expected_line, +  struct pike_string *expected_file, INT_TYPE expected_line,    struct pike_type *expected_t, -  struct pike_string *got_file, INT32 got_line, +  struct pike_string *got_file, INT_TYPE got_line,    struct pike_type *got_t,    INT32 args, const char *fmt, ...)   {    if (fmt)    {    va_list vargs;    va_start(vargs, fmt);    va_yyreport(severity_level, got_file, got_line, type_check_system_string,    args, fmt, vargs);    va_end(vargs);
pike.git/src/program.c:7525:    if (s) {    push_string(s);    yyreport(REPORT_ERROR, parser_system_string, 1, "%s");    }    }       pop_stack();    free_svalue(&thrown);   }    - extern void yyparse(void); + extern int yyparse(void);    -  + static void do_yyparse(void) + { +  struct svalue *save_sp = Pike_sp; +  yyparse(); /* Parse da program */ +  if (save_sp != Pike_sp) {   #ifdef PIKE_DEBUG - #define do_yyparse() do { \ -  struct svalue *save_sp=Pike_sp; \ -  yyparse(); /* Parse da program */ \ -  if(save_sp != Pike_sp) { \ -  Pike_fatal("yyparse() left %"PRINTPTRDIFFT"d droppings on the stack!\n", \ -  Pike_sp - save_sp); \ -  } \ - }while(0) - #else - #define do_yyparse() yyparse() +  if (!Pike_compiler->num_parse_error) { +  Pike_fatal("yyparse() left %"PRINTPTRDIFFT"d droppings on the stack!\n", +  Pike_sp - save_sp); +  }   #endif -  +  pop_n_elems(Pike_sp - save_sp); +  } + }      struct Supporter *current_supporter=0;         #ifdef PIKE_DEBUG      struct supporter_marker   {    struct supporter_marker *next;    void *data;    int level, verified;   };    - #undef EXIT_BLOCK - #define EXIT_BLOCK(P) - #undef COUNT_OTHER - #define COUNT_OTHER() -  +    #undef INIT_BLOCK   #define INIT_BLOCK(X) do { (X)->level = (X)->verified = 0; }while(0)   PTR_HASH_ALLOC(supporter_marker, 128);      static int supnum;      #define SNUM(X) (get_supporter_marker((X))->level)      static void mark_supporters(struct Supporter *s)   {
pike.git/src/program.c:7792:    verify_supporters();    ret++; /* dependency registred */    }    }    }    }    verify_supporters();    return ret;   }    - /*! @module DefaultCompilerEnvironment + /*! @class Reporter    *! -  *! The @[CompilerEnvironment] object that is used -  *! for loading C-modules and by @[predef::compile()]. -  *! -  *! @note -  *! @[predef::compile()] is essentially an alias for the -  *! @[CompilerEnvironment()->compile()] in this object. -  *! -  *! @seealso -  *! @[CompilerEnvironment], @[predef::compile()] +  *! API for reporting parse errors and similar.    */    - /*! @endmodule -  */ -  - /*! @class CompilerEnvironment -  *! -  *! The compiler environment. -  *! -  *! By inheriting this class and overloading the functions, -  *! it is possible to make a custom Pike compiler. -  *! -  *! @note -  *! Prior to Pike 7.8 this sort of customization has to be done -  *! either via custom master objects, or via @[CompilationHandler]s. -  *! -  *! @seealso -  *! @[CompilationHandler], @[MasterObject], @[master()], @[replace_master()] -  */ -  +    /*! @decl enum SeverityLevel    *! Message severity level.    *! { NOTICE, WARNING, ERROR, FATAL }    *!    *! @constant NOTICE    *! @constant WARNING    *! @constant ERROR    *! @constant FATAL    *!    *! @seealso    *! @[report()]    */      /*! @decl void report(SeverityLevel severity, @ -  *! string filename, int linenumber, @ +  *! string filename, int(1..) linenumber, @    *! string subsystem, @    *! string message, mixed ... extra_args)    *!    *! Report a diagnostic from the compiler.    *!    *! @param severity    *! The severity of the diagnostic.    *! -  *! The default implementation does the following depending on @[severity]: -  *! @int -  *! @value NOTICE -  *! Ignored. -  *! @value WARNING -  *! Calls @[MasterObject()->compile_warning()]. -  *! @value ERROR -  *! @value FATAL -  *! Calls @[MasterObject()->compile_error()]. -  *! @endint -  *! -  *! If there's no master object yet, the diagnostic is output to -  *! @[Stdio.stderr]. -  *! +     *! @param filename    *! @param linenumber    *! Location which triggered the diagnostic.    *!    *! @param subsystem    *! Compiler subsystem that generated the diagnostic.    *!    *! @param message    *! @[sprintf()]-style formatting string with the diagnostic message.    *!    *! @param extra_args    *! Extra arguments to @[sprintf()].    *! -  +  *! The default implementation does the following: +  *! +  *! @ul +  *! @item +  *! If there's a @[MasterObject()->report()], call it +  *! with the same arguments as ourselves. +  *! @item +  *! Otherwise depending on @[severity]: +  *! @int +  *! @value NOTICE +  *! Ignored. +  *! @value WARNING +  *! Calls @[MasterObject()->compile_warning()]. +  *! @value ERROR +  *! @value FATAL +  *! Calls @[MasterObject()->compile_error()]. +  *! @endint +  *! @endul +  *! +  *! If there's no master object yet, the diagnostic is output to +  *! @[Stdio.stderr]. +  *! +  *! @note +  *! In Pike 7.8 and earlier @[MasterObject()->report()] was not called. +  *!    *! @seealso    *! @[PikeCompiler()->report()]    */ - static void f_compilation_env_report(INT32 args) + /* NOTE: This function MUST NOT use any storage in the Reporter program! */ + static void f_reporter_report(INT32 args)   {    int level;    struct pike_string *filename;    INT_TYPE linenumber;    struct pike_string *subsystem;    struct pike_string *message; -  +  struct object *master_ob;    -  +  if ((master_ob = get_master()) && master_ob->prog) { +  int fun = find_identifier("report", master_ob->prog); +  if (fun >= 0) { +  apply_low(master_ob, fun, args); +  return; +  } +  } +     if (args > 5) {    f_sprintf(args - 4);    args = 5;    } -  get_all_args("report", args, "%d%W%i%W%W", +  get_all_args("report", args, "%d%W%+%W%W",    &level, &filename, &linenumber, &subsystem, &message);       /* Ignore informational level messages */    if (level >= REPORT_WARNING) { -  if (get_master()) { +  if (master_ob && master_ob->prog) {    ref_push_string(filename);    push_int(linenumber);    ref_push_string(message);    if (level >= REPORT_ERROR) {    APPLY_MASTER("compile_error", 3);    args++;    } else {    APPLY_MASTER("compile_warning", 3);    args++;    }    } else {    /* We hope that errors from compiling the master    * won't contain wide-strings... */    if (level >= REPORT_ERROR) {    fprintf(stderr, "%s:%ld: %s\n", -  filename->str, linenumber, message->str); +  filename->str, (long)linenumber, message->str);    } else {    fprintf(stderr, "%s:%ld: Warning: %s\n", -  filename->str, linenumber, message->str); +  filename->str, (long)linenumber, message->str);    }    fflush(stderr);    }    }    pop_n_elems(args);    push_int(0);   }    -  + /*! @endclass +  */ +  + /*! @module DefaultCompilerEnvironment +  *! +  *! The @[CompilerEnvironment] object that is used +  *! for loading C-modules and by @[predef::compile()]. +  *! +  *! @note +  *! @[predef::compile()] is essentially an alias for the +  *! @[CompilerEnvironment()->compile()] in this object. +  *! +  *! @seealso +  *! @[CompilerEnvironment], @[predef::compile()] +  */ +  + /*! @endmodule +  */ +  + /*! @class CompilerEnvironment +  *! +  *! The compiler environment. +  *! +  *! By inheriting this class and overloading the functions, +  *! it is possible to make a custom Pike compiler. +  *! +  *! @note +  *! Prior to Pike 7.8 this sort of customization has to be done +  *! either via custom master objects, or via @[CompilationHandler]s. +  *! +  *! @seealso +  *! @[CompilationHandler], @[MasterObject], @[master()], @[replace_master()] +  */ +  + /*! @decl inherit Reporter +  *! +  *! Implements the @[Reporter] API. +  *! +  *! @seealso +  *! @[Reporter()->report()], @[Reporter()->SeverityLevel] +  */ +    /*! @decl program compile(string source, CompilationHandler|void handler, @    *! int|void major, int|void minor,@    *! program|void target, object|void placeholder)    *!    *! Compile a string to a program.    *!    *! This function takes a piece of Pike code as a string and    *! compiles it into a clonable program.    *!    *! The optional argument @[handler] is used to specify an alternative
pike.git/src/program.c:7971:    args = 1;    if (TYPEOF(Pike_sp[-1]) != T_OBJECT) {    Pike_error("Bad return value from PikeCompiler().\n");    }    apply(Pike_sp[-1].u.object, "compile", 0);    stack_pop_n_elems_keep_top(args);   }      /*! @decl mixed resolv(string identifier, string filename, @    *! object|void handler) +  *! +  *! Look up @[identifier] in the current context. +  *! +  *! The default implementation calls the corresponding +  *! function in the master object.    */   static void f_compilation_env_resolv(INT32 args)   {    struct pike_string *ident;    struct pike_string *filename;    struct object *handler = NULL;       get_all_args("resolv", args, "%W%W.%O",    &ident, &filename, &handler);   
pike.git/src/program.c:8081:   {    if(get_master())    {    APPLY_MASTER("handle_inherit", args);    } else {    pop_n_elems(args);    push_undefined();    }   }    - /*! @decl int filter_exception(SeverityLevel level, mixed err) -  *! -  *! The default implementation calls -  *! @[MasterObject()->compile_exception()] for @[level] @[ERROR] -  *! and @[FATAL]. -  *! -  *! @note -  *! This function is not implemented in Pike 7.8. -  *! -  *! @seealso -  *! @[MasterObject()->compile_exception()]. + #if 0 + /* @decl int filter_exception(SeverityLevel level, mixed err) +  * +  * The default implementation calls +  * @[MasterObject()->compile_exception()] for @[level] @[ERROR] +  * and @[FATAL]. +  * +  * @note +  * This function is not implemented in Pike 7.8. +  * +  * @seealso +  * @[MasterObject()->compile_exception()].    */   static void f_compilation_env_filter_exception(INT32 args)   {    int level;    struct svalue *err;       get_all_args("filter_exception", args, "%d%*", &level, &err);    if (args > 2) {    pop_n_elems(args-2);    args = 2;
pike.git/src/program.c:8121: Inside #if 0
   push_string(format_exception_for_error_msg(err));    /* FIXME! */    }    }   #endif       pop_n_elems(args);    push_undefined();    return;   } + #endif      /*! @class PikeCompiler    *!    *! The Pike compiler.    *!    *! An object of this class compiles a single string    *! of Pike code.    */      static void free_compilation(struct compilation *c)
pike.git/src/program.c:8161:    c->p = NULL;    }    if(c->placeholder) {    free_object(c->placeholder);    c->placeholder = NULL;    }    if(c->lex.current_file) {    free_string(c->lex.current_file);    c->lex.current_file = NULL;    } +  if(c->lex.attributes) { +  free_node(c->lex.attributes); +  c->lex.attributes = NULL; +  } +  if (c->resolve_cache) { +  free_mapping(c->resolve_cache); +  c->resolve_cache = NULL; +  }    free_svalue(& c->default_module);    SET_SVAL(c->default_module, T_INT, NUMBER_NUMBER, integer, 0);    free_supporter(&c->supporter);    verify_supporters();   }      static void run_init(struct compilation *c)   {    debug_malloc_touch(c);       if (c->compat_handler) free_object(c->compat_handler);    c->compat_handler=0;    -  c->resolve_cache_save = resolve_cache; -  resolve_cache = 0; +  if (c->resolve_cache) { +  free_mapping(c->resolve_cache); +  c->resolve_cache = 0; +  }       c->lex.current_line=1;    free_string(c->lex.current_file);    c->lex.current_file=make_shared_string("-");    -  +  c->lex.attributes = NULL; +     if (runtime_options & RUNTIME_STRICT_TYPES)    {    c->lex.pragmas = ID_STRICT_TYPES;    } else {    c->lex.pragmas = 0;    }       c->lex.end = c->prog->str + (c->prog->len << c->prog->size_shift);       switch(c->prog->size_shift)    {    case 0: c->lex.current_lexer = yylex0; break;    case 1: c->lex.current_lexer = yylex1; break;    case 2: c->lex.current_lexer = yylex2; break; - #ifdef PIKE_DEBUG -  default: -  Pike_fatal("Program has bad shift %d!\n", c->prog->size_shift); -  break; - #endif +     }       c->lex.pos=c->prog->str;   }      static void run_init2(struct compilation *c)   {   #if 0    int i;    struct program *p;
pike.git/src/program.c:8262:    Pike_fatal("Failed to pop modules properly.\n");   #endif      #ifdef PIKE_DEBUG    if (c->compilation_depth != -1) {    fprintf(stderr, "compile(): compilation_depth is %d\n",    c->compilation_depth);    }   #endif /* PIKE_DEBUG */    -  if (resolve_cache) -  free_mapping(resolve_cache); -  resolve_cache = c->resolve_cache_save; +  if (c->resolve_cache) { +  free_mapping(c->resolve_cache); +  c->resolve_cache = NULL; +  }       verify_supporters();   }      static void zap_placeholder(struct compilation *c)   {    /* fprintf(stderr, "Destructing placeholder.\n"); */    if (c->placeholder->storage) {    yyerror("Placeholder already has storage!");   #if 0
pike.git/src/program.c:8324:    if(c->target && !(c->target->flags & PROGRAM_VIRGIN)) {    yyerror("Placeholder program is not virgin!");    return 0;    }       low_start_new_program(c->target,1,0,0,0);    c->supporter.prog = Pike_compiler->new_program;       CDFPRINTF((stderr,    "th(%ld) %p run_pass1() start: " -  "threads_disabled:%d, compilation_depth:%d\n", +  "lock_depth:%d, compilation_depth:%d\n",    (long)th_self(), Pike_compiler->new_program, -  threads_disabled, c->compilation_depth)); +  lock_depth, c->compilation_depth));       run_init2(c);       if(c->placeholder)    {    if(c->placeholder->prog != null_program)    {    yyerror("Placeholder argument is not a null_program clone!");    c->placeholder=0;    debug_malloc_touch(c->placeholder);
pike.git/src/program.c:8413:       run_init(c);    low_start_new_program(c->p,2,0,0,0);    free_program(c->p);    c->p=0;       run_init2(c);       CDFPRINTF((stderr,    "th(%ld) %p run_pass2() start: " -  "threads_disabled:%d, compilation_depth:%d\n", +  "lock_depth:%d, compilation_depth:%d\n",    (long)th_self(), Pike_compiler->new_program, -  threads_disabled, c->compilation_depth)); +  lock_depth, c->compilation_depth));       verify_supporters();       do_yyparse(); /* Parse da program */       CDFPRINTF((stderr, "th(%ld) %p run_pass2() done for %s\n",    (long)th_self(), Pike_compiler->new_program,    c->lex.current_file->str));       verify_supporters();
pike.git/src/program.c:8437:    c->p=debug_malloc_pass(end_program());       run_exit(c);   }      static void run_cleanup(struct compilation *c, int delayed)   {    debug_malloc_touch(c);    debug_malloc_touch(c->placeholder);   #if 0 /* FIXME */ -  if (threads_disabled != c->saved_threads_disabled) { -  Pike_fatal("compile(): threads_disabled:%d saved_threads_disabled:%d\n", -  threads_disabled, c->saved_threads_disabled); + #ifdef PIKE_THREADS +  if (lock_depth != c->saved_lock_depth) { +  Pike_fatal("compile(): lock_depth:%d saved_lock_depth:%d\n", +  lock_depth, c->saved_lock_depth);    } -  + #endif   #endif /* PIKE_DEBUG */    -  exit_threads_disable(NULL); +  unlock_pike_compiler();       CDFPRINTF((stderr,    "th(%ld) %p run_cleanup(): " -  "threads_disabled:%d, compilation_depth:%d\n", +  "lock_depth:%d, compilation_depth:%d\n",    (long)th_self(), c->target, -  threads_disabled, c->compilation_depth)); +  lock_depth, c->compilation_depth));    if (!c->p)    {    /* fprintf(stderr, "Destructing placeholder.\n"); */    if(c->placeholder) {    debug_malloc_touch(c->placeholder);    zap_placeholder(c);    }       if(delayed && c->target)    {
pike.git/src/program.c:8593:   }      static void compilation_event_handler(int e)   {    struct compilation *c = THIS_COMPILATION;       switch (e) {    case PROG_EVENT_INIT:    CDFPRINTF((stderr, "th(%ld) compilation: INIT(%p).\n",    (long) th_self(), c)); -  MEMSET(c, 0, sizeof(*c)); +  memset(c, 0, sizeof(*c));    c->supporter.self = Pike_fp->current_object; /* NOTE: Not ref-counted! */    c->compilation_inherit =    Pike_fp->context - Pike_fp->current_object->prog->inherits;    initialize_buf(&c->used_modules);    SET_SVAL(c->default_module, T_MAPPING, 0, mapping, get_builtin_constants());    add_ref(c->default_module.u.mapping);    c->major = -1;    c->minor = -1;    c->lex.current_line = 1;    c->lex.current_file = make_shared_string("-");
pike.git/src/program.c:8622:    }   }      /*! @decl void report(SeverityLevel severity, @    *! string filename, int linenumber, @    *! string subsystem, @    *! string message, mixed ... extra_args)    *!    *! Report a diagnostic from the compiler.    *! -  *! The default implementation calls the corresponding function -  *! in the active handlers, and otherwise falls back to -  *! @[CompilerEnvironment()->report()] in the parent object. +  *! The default implementation attempts to call the first +  *! corresponding function in the active handlers in priority order: +  *! +  *! @ol +  *! @item +  *! Call handler->report(). +  *! @item +  *! Call handler->compile_warning() or handler->compile_error() +  *! depending on @[severity]. +  *! @item +  *! Call compat->report(). +  *! @item +  *! Call compat->compile_warning() or compat->compile_error() +  *! depending on @[severity]. +  *! @item +  *! Fallback: Call @[CompilerEnvironment()->report()] +  *! in the parent object. +  *! @endol +  *! +  *! The arguments will be as follows: +  *! @dl +  *! @item report() +  *! The report() function will be called with the same arguments +  *! as this function. +  *! @item compile_warning()/compile_error() +  *! Depending on the @[severity] either compile_warning() +  *! or compile_error() will be called. +  *! +  *! They will be called with the @[filename], @[linenumber] +  *! and formatted @[message] as arguments. +  *! +  *! Note that these will not be called for the @[NOTICE] severity, +  *! and that compile_error() will be used for both @[ERROR] and +  *! @[FATAL]. +  *! @enddl +  *! +  *! @note +  *! In Pike 7.8 and earlier the report() function was not called +  *! in the handlers. +  *! +  *! @seealso +  *! @[CompilerEnvironment()->report()]    */   static void f_compilation_report(INT32 args)   {    struct compilation *c = THIS_COMPILATION;    int level;    struct pike_string *filename;    INT_TYPE linenumber;    struct pike_string *subsystem;    struct pike_string *message;    struct object *handler = NULL;    int fun = -1;       /* FIXME: get_all_args() ought to have a marker    * indicating that we accept more arguments...    */    get_all_args("report", args, "%d", &level);    -  if ((c->handler || c->compat_handler) && -  (level >= REPORT_WARNING)) { -  /* Ignore informational level messages */ +  if ((c->handler || c->compat_handler)) {    const char *fun_name = "compile_warning";       if (level >= REPORT_ERROR) fun_name = "compile_error";       if((handler = c->handler) && handler->prog) { -  if ((fun = find_identifier(fun_name, handler->prog)) != -  -1) { +  if ((fun = find_identifier("report", handler->prog)) != -1) { +  apply_low(handler, fun, args); +  return; +  } +  if ((fun = find_identifier(fun_name, handler->prog)) != -1) {    goto apply_handler;    }    }    if ((handler = c->compat_handler) && handler->prog) { -  if ((fun = find_identifier(fun_name, handler->prog)) != -  -1) { +  if ((fun = find_identifier("report", handler->prog)) != -1) { +  apply_low(handler, fun, args); +  return; +  } +  if ((fun = find_identifier(fun_name, handler->prog)) != -1) {    goto apply_handler;    }    }    }    /* Nothing apropriate in any handlers.    * Call the report() in our parent.    */    apply_external(1, CE_REPORT_FUN_NUM, args);    return;       apply_handler: -  +  /* Ignore informational level messages */ +  if (level < REPORT_WARNING) return;    if (args > 5) {    f_sprintf(args - 4);    args = 5;    } -  get_all_args("report", args, "%d%W%i%W%W", +  get_all_args("report", args, "%d%W%+%W%W",    &level, &filename, &linenumber,    &subsystem, &message);       ref_push_string(filename);    push_int(linenumber);    ref_push_string(message);    apply_low(handler, fun, 3);    stack_pop_n_elems_keep_top(args);   }   
pike.git/src/program.c:8855:    ref_push_program(c->p);    return;    }      #ifdef PIKE_DEBUG    SET_ONERROR(tmp, fatal_on_error,"Compiler exited with longjump!\n");   #endif       c->flags |= COMPILER_BUSY;    -  low_init_threads_disable(); -  c->saved_threads_disabled = threads_disabled; +  lock_pike_compiler(); + #ifdef PIKE_THREADS +  c->saved_lock_depth = lock_depth; + #endif       init_supporter(& c->supporter,    (supporter_callback *) call_delayed_pass2,    (void *)c);       delay=run_pass1(c);    dependants_ok = call_dependants(& c->supporter, !!c->p );   #ifdef PIKE_DEBUG    /* FIXME */    UNSET_ONERROR(tmp);
pike.git/src/program.c:9393:    string_builder_strcat(&buf, "UNDEFINED, ");    }    string_builder_sprintf(&buf, "%d, %d, %s, %s)",    c->major, c->minor,    c->target?"target":"UNDEFINED",    c->placeholder?"placeholder":"UNDEFINED");    pop_n_elems(args);    push_string(finish_string_builder(&buf));   }    - /* Fake being called via PikeCompiler()->compile() + /** +  * Fake being called via PikeCompiler()->compile()    *    * This function is used to set up the environment for    * compiling C efuns and modules.    *    * Note: Since this is a stack frame, it will be cleaned up    * automatically on error, so no need to use ONERROR().    *    * Note: Steals a reference from ce.    */   static void low_enter_compiler(struct object *ce, int inherit)
pike.git/src/program.c:9433: Inside #if defined(PIKE_DEBUG)
   new_frame->context->prog, compilation_program);    }   #endif /* PIKE_DEBUG */    new_frame->fun = new_frame->context->identifier_level + PC_COMPILE_FUN_NUM;    new_frame->expendible = Pike_sp;    new_frame->locals = Pike_sp;    new_frame->save_sp = Pike_sp;    new_frame->save_mark_sp = Pike_mark_sp;    new_frame->mark_sp_base = Pike_mark_sp;    new_frame->args = 0; +  new_frame->num_args = 0;    new_frame->num_locals = 0;    new_frame->pc = 0;    new_frame->return_addr = 0;    new_frame->scope = 0;    new_frame->save_sp = Pike_sp;    Pike_fp = new_frame;   }    - PMOD_EXPORT void enter_compiler(struct pike_string *filename, int linenumber) + PMOD_EXPORT void enter_compiler(struct pike_string *filename, +  INT_TYPE linenumber)   {    struct object *ce = parent_clone_object(compilation_program,    compilation_environment,    CE_PIKE_COMPILER_FUN_NUM, 0);    struct compilation *c;       low_enter_compiler(ce, 0);       c = THIS_COMPILATION;    if (filename) {    free_string(c->lex.current_file);    copy_shared_string(c->lex.current_file, filename);    }    if (linenumber) {    c->lex.current_line = linenumber;    }   }    - /* Reverse the effect of enter_compiler(). + /** +  * Reverse the effect of enter_compiler().    */   PMOD_EXPORT void exit_compiler(void)   {   #ifdef PIKE_DEBUG    if ((Pike_fp->current_program != compilation_program) ||    (Pike_fp->fun != PC_COMPILE_FUN_NUM)) {    Pike_fatal("exit_compiler(): Frame stack out of whack!\n");    }   #endif /* PIKE_DEBUG */    POP_PIKE_FRAME();
pike.git/src/program.c:9483:   /*! @class CompilerState    *!    *! Keeps the state of a single program/class during compilation.    *!    *! @note    *! Not in use yet!    */      #define THIS_PROGRAM_STATE ((struct program_state *)(Pike_fp->current_storage))    - static void program_state_event_handler(int event) + static void program_state_event_handler(int UNUSED(event))   {   #if 0    struct program_state *c = THIS_PROGRAM_STATE;    switch (event) {    case PROG_EVENT_INIT:   #define INIT   #include "compilation.h"    break;    case PROG_EVENT_EXIT:   #define EXIT
pike.git/src/program.c:9509:      /*! @endclass    */      /*! @endclass    */      /*! @endclass    */    - /* Strap the compiler by creating the compilation program by hand. */ + /** +  * Strap the compiler by creating the compilation program by hand. +  */   static void compile_compiler(void)   {    struct program *p = low_allocate_program();    struct program *p2 = compilation_program = low_allocate_program();    struct object *co;    struct inherit *inh;       p->parent_info_storage = -1;    /* p->event_handler = compilation_env_event_handler; */    p->flags |= PROGRAM_HAS_C_METHODS;
pike.git/src/program.c:9582:    p2->flags |= PROGRAM_PASS_1_DONE;    co = parent_clone_object(p2, compilation_environment,    CE_PIKE_COMPILER_FUN_NUM, 0);    p2->flags &= ~PROGRAM_PASS_1_DONE;       low_enter_compiler(co, 0);       low_start_new_program(p, 1, NULL, 0, NULL);    free_program(p); /* Remove the extra ref we just got... */    -  ADD_FUNCTION("report", f_compilation_env_report, +  /* NOTE: The order of these identifiers is hard-coded in +  * the CE_*_FUN_NUM definitions in "pike_compiler.h". +  */ +  +  /* NB: Overloaded properly by inherit of Reporter later on. */ +  ADD_FUNCTION("report", f_reporter_report,    tFuncV(tName("SeverityLevel", tInt03) tStr tIntPos    tStr tStr, tMix, tVoid),0);       ADD_FUNCTION("compile", f_compilation_env_compile,    tFunc(tOr(tStr, tVoid) tOr(tObj, tVoid)    tOr(tInt, tVoid) tOr(tInt, tVoid)    tOr(tPrg(tObj), tVoid) tOr(tObj, tVoid),    tPrg(tObj)), 0);       ADD_FUNCTION("resolv", f_compilation_env_resolv,
pike.git/src/program.c:9710:    f_compilation_env_get_compilation_handler,    tFunc(tInt tInt, tObj), 0);       ADD_FUNCTION("get_default_module",    f_compilation_env_get_default_module,    tFunc(tNone, tOr(tMap(tStr, tMix), tObj)), 0);       ADD_FUNCTION("handle_inherit", f_compilation_env_handle_inherit,    tFunc(tStr tStr tOr(tObj, tVoid), tPrg(tObj)), 0);    +  /* Reporter */ +  start_new_program();    {    struct svalue type_value;    -  +  ADD_FUNCTION("report", f_reporter_report, +  tFuncV(tName("SeverityLevel", tInt03) tStr tIntPos +  tStr tStr, tMix, tVoid),0); +     /* enum SeverityLevel { NOTICE, WARNING, ERROR, FATAL } */    SET_SVAL(type_value, PIKE_T_TYPE, 0, type,    CONSTTYPE(tName("SeverityLevel", tInt03)));    simple_add_constant("SeverityLevel", &type_value, 0);    free_svalue(&type_value);       add_integer_constant("NOTICE", REPORT_NOTICE, 0);    add_integer_constant("WARNING", REPORT_WARNING, 0);    add_integer_constant("ERROR", REPORT_ERROR, 0);    add_integer_constant("FATAL", REPORT_FATAL, 0); -  +  +  reporter_program = end_program();    } -  +  add_global_program("Reporter", reporter_program);    -  +  low_inherit(reporter_program, NULL, -1, 0, 0, 0); +     compilation_env_program = end_program();       add_global_program("CompilerEnvironment", compilation_env_program);       exit_compiler();       ref_push_object(compilation_environment);    low_add_constant("DefaultCompilerEnvironment", Pike_sp-1);    pop_stack();   }
pike.git/src/program.c:9795:    }else{    ref_push_mapping(get_builtin_constants());    }    free_svalue(& c->default_module);    move_svalue (&c->default_module, --Pike_sp);      #ifdef PIKE_DEBUG    SET_ONERROR(tmp, fatal_on_error,"Compiler exited with longjump!\n");   #endif    -  low_init_threads_disable(); -  c->saved_threads_disabled = threads_disabled; +  lock_pike_compiler(); + #ifdef PIKE_THREADS +  c->saved_lock_depth = lock_depth; + #endif       init_supporter(& c->supporter,    (supporter_callback *) call_delayed_pass2,    (void *)c);       delay=run_pass1(c);    dependants_ok = call_dependants(& c->supporter, !!c->p );   #ifdef PIKE_DEBUG    /* FIXME */    UNSET_ONERROR(tmp);
pike.git/src/program.c:9891:    flags,    IDENTIFIER_C_FUNCTION,    0,    opt_flags);    }    free_string(name_tmp);    free_type(type_tmp);    return ret;   }    - PMOD_EXPORT int quick_add_function(const char *name, -  int name_length, + PMOD_EXPORT int low_quick_add_function(struct pike_string * name_tmp,    void (*cfun)(INT32),    const char *type, -  int type_length, +  int UNUSED(type_length),    unsigned flags,    unsigned opt_flags)   {    int ret; -  struct pike_string *name_tmp; +     struct pike_type *type_tmp;    union idptr tmp;   /* fprintf(stderr,"ADD_FUNC: %s\n",name); */ -  name_tmp = make_shared_binary_string(name, name_length); +     type_tmp = make_pike_type(type);       if(cfun)    {    tmp.c_fun=cfun;    ret=define_function(name_tmp,    type_tmp,    flags,    IDENTIFIER_C_FUNCTION,    &tmp,
pike.git/src/program.c:9961: Inside #if defined(PIKE_DEBUG)
   }   #endif      }   #endif      #undef THIS   #define THIS ((struct pike_trampoline *)(CURRENT_STORAGE))   struct program *pike_trampoline_program=0;    - static void apply_trampoline(INT32 args) + static void apply_trampoline(INT32 UNUSED(args))   {    Pike_error("Internal error: Trampoline magic failed!\n");   }      static void not_trampoline(INT32 args)   {    pop_n_elems(args);    if (!THIS->frame || !THIS->frame->current_object ||    !THIS->frame->current_object->prog) {    push_int(1);
pike.git/src/program.c:9999:       ref_push_function (THIS->frame->current_object, THIS->func);    init_buf(&save_buf);    describe_svalue (sp - 1, 0, 0);    str = complex_free_buf(&save_buf);    pop_stack();    push_string (make_shared_binary_string (str.str, str.len));    free (str.str);   }    - static void init_trampoline(struct object *o) + static void init_trampoline(struct object *UNUSED(o))   {    THIS->frame=0;   }    - static void exit_trampoline(struct object *o) + static void exit_trampoline(struct object *UNUSED(o))   {    if(THIS->frame)    {    free_pike_scope(THIS->frame);    THIS->frame=0;    }   }      static void gc_check_frame(struct pike_frame *f)   {
pike.git/src/program.c:10027:    if(f->current_object)    debug_gc_check (f->current_object, " as current_object in trampoline frame");    if(f->current_program)    debug_gc_check (f->current_program, " as current_program in trampoline frame");    debug_gc_check_svalues (f->locals, f->num_locals, " in locals of trampoline frame");    if(f->scope && !debug_gc_check (f->scope, " as scope frame of trampoline frame"))    gc_check_frame(f->scope);    }   }    - static void gc_check_trampoline(struct object *o) + static void gc_check_trampoline(struct object *UNUSED(o))   {    if (THIS->frame &&    !debug_gc_check (THIS->frame, " as trampoline frame"))    gc_check_frame(THIS->frame);   }      static void gc_recurse_frame(struct pike_frame *f)   {    if(f->current_object) gc_recurse_object(f->current_object);    if(f->current_program) gc_recurse_program(f->current_program);    if(f->flags & PIKE_FRAME_MALLOCED_LOCALS)    gc_recurse_svalues(f->locals,f->num_locals);    if(f->scope) gc_recurse_frame(f->scope);   }    - static void gc_recurse_trampoline(struct object *o) + static void gc_recurse_trampoline(struct object *UNUSED(o))   {    if (THIS->frame) gc_recurse_frame(THIS->frame);   }         /* This placeholder should be used    * in the first compiler pass to take the place    * of unknown things    */   struct program *placeholder_program;
pike.git/src/program.c:10083:    MAKE_CONST_STRING (s, "__placeholder_object");    ref_push_string (s);   }      void init_program(void)   {    size_t i;    struct svalue key;    struct svalue val;    struct svalue id; -  init_program_blocks(); +        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(parser_system_string, "parser");    MAKE_CONST_STRING(type_check_system_string, "type_check");       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_string(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);    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));    -  + #ifdef PIKE_THREADS +  co_init(&Pike_compiler_cond); + #endif +     compile_compiler();       enter_compiler(NULL, 0);       start_new_program();    debug_malloc_touch(Pike_compiler->fake_object);    debug_malloc_touch(Pike_compiler->fake_object->storage);    ADD_STORAGE(struct pike_trampoline);    ADD_FUNCTION("`()",apply_trampoline,tFunction,0);    ADD_FUNCTION("`!",not_trampoline,tFunc(tVoid,tInt),0);
pike.git/src/program.c:10196: Inside #if defined(FIND_FUNCTION_HASHSIZE)
   {    if(cache[e].name)    {    free_string(cache[e].name);    cache[e].name=0;    }    }   #endif      #ifdef DO_PIKE_CLEANUP -  if(resolve_cache) -  { -  free_mapping(dmalloc_touch (struct mapping *, resolve_cache)); -  resolve_cache=0; -  } -  +     if(pike_trampoline_program)    {    free_program(pike_trampoline_program);    pike_trampoline_program=0;    }       if(null_program)    {    free_program(null_program);    null_program=0;
pike.git/src/program.c:10239:    compilation_program = 0;    }    if (compilation_environment) {    free_object(compilation_environment);    compilation_environment = 0;    }    if (compilation_env_program) {    free_program(compilation_env_program);    compilation_env_program = 0;    } +  if (reporter_program) { +  free_program(reporter_program); +  reporter_program = 0;    } -  + #ifdef PIKE_THREADS +  co_destroy(&Pike_compiler_cond); + #endif + }       - PMOD_EXPORT void visit_program (struct program *p, int action) + PMOD_EXPORT void visit_program (struct program *p, int action, void *extra)   { -  switch (action) { +  visit_enter(p, T_PROGRAM, extra); +  switch (action & VISIT_MODE_MASK) {   #ifdef PIKE_DEBUG    default:    Pike_fatal ("Unknown visit action %d.\n", action);    case VISIT_NORMAL:    case VISIT_COMPLEX_ONLY:    break;   #endif    case VISIT_COUNT_BYTES:    mc_counted_bytes += p->total_size;    break;    }       if (!(p->flags & PROGRAM_AVOID_CHECK)) {    int e;    struct program_constant *consts = p->constants;    struct inherit *inh = p->inherits;       for (e = p->num_constants - 1; e >= 0; e--) -  visit_svalue (&consts[e].sval, REF_TYPE_NORMAL); +  visit_svalue (&consts[e].sval, REF_TYPE_NORMAL, extra);       for (e = p->num_inherits - 1; e >= 0; e--) {    if (inh[e].parent) -  visit_object_ref (inh[e].parent, REF_TYPE_NORMAL); +  visit_object_ref (inh[e].parent, REF_TYPE_NORMAL, extra);       if (e && inh[e].prog) -  visit_program_ref (inh[e].prog, REF_TYPE_NORMAL); +  visit_program_ref (inh[e].prog, REF_TYPE_NORMAL, extra);    }       if (!(action & VISIT_COMPLEX_ONLY)) {    struct identifier *ids = p->identifiers;    struct pike_string **strs = p->strings;       for (e = p->num_inherits - 1; e >= 0; e--) {    if (inh[e].name) -  visit_string_ref (inh[e].name, REF_TYPE_NORMAL); +  visit_string_ref (inh[e].name, REF_TYPE_NORMAL, extra);    }       for (e = p->num_identifiers - 1; e >= 0; e--) {    struct identifier *id = ids + e; -  visit_string_ref (id->name, REF_TYPE_NORMAL); -  visit_type_ref (id->type, REF_TYPE_NORMAL); +  visit_string_ref (id->name, REF_TYPE_NORMAL, extra); +  visit_type_ref (id->type, REF_TYPE_NORMAL, extra);    }       for (e = p->num_strings - 1; e >= 0; e--) -  visit_string_ref (strs[e], REF_TYPE_NORMAL); +  visit_string_ref (strs[e], REF_TYPE_NORMAL, extra);    }       /* Strong ref follows. It must be last. */    if (p->parent) -  visit_program_ref (p->parent, REF_TYPE_STRONG); +  visit_program_ref (p->parent, REF_TYPE_STRONG, extra);    } -  +  visit_leave(p, T_PROGRAM, extra);   }      static void gc_check_program(struct program *p);      void gc_mark_program_as_referenced(struct program *p)   {    debug_malloc_touch(p);       if (p->flags & PROGRAM_AVOID_CHECK) {    /* Program is in an inconsistent state.
pike.git/src/program.c:10594:    f->last_block_level=-1;       f->current_function_number=-2; /* no function */    f->recur_label=-1;    f->is_inline=0;    f->num_args=-1;    f->opt_flags = OPT_SIDE_EFFECT|OPT_EXTERNAL_DEPEND; /* FIXME: Should be 0. */    Pike_compiler->compiler_frame=f;   }    - void low_pop_local_variables(int level) + node *low_pop_local_variables(int level, node *block)   {    struct compilation *c = THIS_COMPILATION;    while(Pike_compiler->compiler_frame->current_number_of_locals > level)    {    int e;    e=--(Pike_compiler->compiler_frame->current_number_of_locals); -  +  if (block) { +  block = mknode(F_COMMA_EXPR, block, +  mknode(F_POP_VALUE, +  mknode(F_ASSIGN, +  mkintnode(0), +  mklocalnode(e, 0)), +  NULL)); +  }    if ((Pike_compiler->compiler_pass == 2) &&    !(Pike_compiler->compiler_frame->variable[e].flags &    LOCAL_VAR_IS_USED)) {    ref_push_string(Pike_compiler->compiler_frame->variable[e].name);    low_yyreport(REPORT_WARNING,    Pike_compiler->compiler_frame->variable[e].file,    Pike_compiler->compiler_frame->variable[e].line,    parser_system_string,    1, "Unused local variable %s.");    }    free_string(Pike_compiler->compiler_frame->variable[e].name);    free_type(Pike_compiler->compiler_frame->variable[e].type);    if(Pike_compiler->compiler_frame->variable[e].def)    free_node(Pike_compiler->compiler_frame->variable[e].def);       free_string(Pike_compiler->compiler_frame->variable[e].file);    } -  +  return block;   }    - void pop_local_variables(int level) + node *pop_local_variables(int level, node *block)   {   #if 1    struct compilation *c = THIS_COMPILATION;    /* We need to save the variables Kuppo (but not their names) */    if(level < Pike_compiler->compiler_frame->min_number_of_locals)    {    /* FIXME: Consider using flags to indicate whether a local variable    * actually is used from a nested scope. */    for(;level<Pike_compiler->compiler_frame->min_number_of_locals;level++)    {
pike.git/src/program.c:10651: Inside #if 1
   Pike_compiler->compiler_frame->variable[level].flags |=    LOCAL_VAR_IS_USED;    }    free_string(Pike_compiler->compiler_frame->variable[level].name);    copy_shared_string(Pike_compiler->compiler_frame->variable[level].name,    empty_pike_string);    /* FIXME: Do we need to keep the filenames? */    }    }   #endif -  low_pop_local_variables(level); +  return low_pop_local_variables(level, block);   }         void pop_compiler_frame(void)   {    struct compiler_frame *f;       f=Pike_compiler->compiler_frame;   #ifdef PIKE_DEBUG    if(!f)    Pike_fatal("Popping out of compiler frames\n");   #endif    -  low_pop_local_variables(0); +  low_pop_local_variables(0, NULL);    if(f->current_type)    free_type(f->current_type);       if(f->current_return_type)    free_type(f->current_return_type);       Pike_compiler->compiler_frame=f->previous;    dmfree((char *)f);   }       -  + PMOD_EXPORT void *get_inherit_storage(struct object *o, int inherit) + { +  if (!o || !o->prog) return NULL; + #ifdef PIKE_DEBUG +  if ((inherit < 0) || (inherit >= o->prog->num_inherits)) +  Pike_fatal("Inherit #%d out of range [0..%d]\n", +  inherit, o->prog->num_inherits-1); + #endif +  return o->storage + o->prog->inherits[inherit].storage_offset; + } +    #define GET_STORAGE_CACHE_SIZE 1024   static struct get_storage_cache   {    INT32 oid, pid;    ptrdiff_t offset;   } get_storage_cache[GET_STORAGE_CACHE_SIZE];      PMOD_EXPORT ptrdiff_t low_get_storage(struct program *o, struct program *p)   {    INT32 oid, pid;    ptrdiff_t offset;    unsigned INT32 hval;       if(!o) return -1;    oid=o->id;    pid=p->id; -  hval=oid*9248339 + pid; -  hval%=GET_STORAGE_CACHE_SIZE; - #ifdef PIKE_DEBUG -  if(hval>GET_STORAGE_CACHE_SIZE) -  Pike_fatal("hval>GET_STORAGE_CACHE_SIZE\n"); - #endif +  hval=(unsigned)oid*9248339 + (unsigned)pid; +  hval&=GET_STORAGE_CACHE_SIZE-1;    if(get_storage_cache[hval].oid == oid &&    get_storage_cache[hval].pid == pid)    {    offset=get_storage_cache[hval].offset;    }else{    INT32 e;    offset=-1;    for(e=0;e<o->num_inherits;e++)    {    if(o->inherits[e].prog==p)
pike.git/src/program.c:10723:    }       get_storage_cache[hval].oid=oid;    get_storage_cache[hval].pid=pid;    get_storage_cache[hval].offset=offset;    }       return offset;   }    - PMOD_EXPORT char *get_storage(struct object *o, struct program *p) + PMOD_EXPORT void *get_storage(struct object *o, struct program *p)   {    ptrdiff_t offset;      #ifdef _REENTRANT    if(d_flag) CHECK_INTERPRETER_LOCK();   #endif       offset= low_get_storage(o->prog, p);    if(offset == -1) return 0;    return o->storage + offset;   }    - struct program *low_program_from_function(struct object *o, INT32 i) + PMOD_EXPORT struct program *low_program_from_function(struct object *o, INT32 i)   {    struct svalue *f;    struct program *p;    struct identifier *id;    while(1) {    struct external_variable_context loc;    p = o->prog;       if(!p) return 0;   
pike.git/src/program.c:10768:    if(id->func.const_info.offset==-1) return 0;    f = &PROG_FROM_INT(p,i)->constants[id->func.const_info.offset].sval;    if(TYPEOF(*f) != T_PROGRAM) return 0;    return f->u.program;   }      PMOD_EXPORT struct program *program_from_function(const struct svalue *f)   {    if(TYPEOF(*f) != T_FUNCTION) return 0;    if(SUBTYPEOF(*f) == FUNCTION_BUILTIN) return 0; +     return low_program_from_function(f->u.object, SUBTYPEOF(*f));   }    -  + PMOD_EXPORT struct program *program_from_type(const struct pike_type *t) + { +  if (!t) return NULL; +  +  switch(t->type) { +  case T_OBJECT: +  if (t->cdr) break; +  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 */ +  case T_SCOPE: +  case T_ASSIGN: +  case PIKE_T_ATTRIBUTE: +  case PIKE_T_NAME: +  return program_from_type(t->cdr); +  break; +  default: +  return NULL; +  } +  +  return id_to_program((int)(ptrdiff_t)t->cdr); + } +    /* NOTE: Does not add references to the return value! */ - PMOD_EXPORT struct program *program_from_svalue(const struct svalue *s) + PMOD_EXPORT struct program *low_program_from_svalue(const struct svalue *s, +  struct object **parent_obj, +  int *parent_id)   {    switch(TYPEOF(*s))    {    case T_OBJECT:    {    struct program *p = s->u.object->prog;   #if 0    int call_fun;   #endif   
pike.git/src/program.c:10795: Inside #if 0
  #if 0    p = p->inherits[SUBTYPEOF(*s)].prog;    if ((call_fun = FIND_LFUN(p, LFUN_CALL)) >= 0) {    /* Get the program from the return type. */    struct identifier *id = ID_FROM_INT(p, call_fun);    /* FIXME: do it. */    return 0;    }   #endif    push_svalue(s); -  f_object_program(1); -  p=program_from_svalue(Pike_sp-1); +  o_cast(program_type_string, T_PROGRAM); +  p = low_program_from_svalue(Pike_sp-1, parent_obj, parent_id);    pop_stack();    return p; /* We trust that there is a reference somewhere... */    }       case T_FUNCTION: -  return program_from_function(s); +  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); +     default:    return 0;    }   }    -  + /* 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   {    INT32 pid,cid,id;   };      #if 0   static struct find_child_cache_s find_child_cache[FIND_CHILD_HASHSIZE];      int find_child(struct program *parent, struct program *child)
pike.git/src/program.c:10850: Inside #if 0
   return i;    }    }    }    return -1;   }   #endif /* 0 */          - /* returns 1 if a implements b */ + /** +  * @return Returns 1 if a implements b. +  */   static int low_implements(struct program *a, struct program *b)   { -  +  DECLARE_CYCLIC();    int e; -  +  int ret = 1;    struct pike_string *s=findstring("__INIT"); -  +  +  if (BEGIN_CYCLIC(a, b)) { +  END_CYCLIC(); +  return 1; /* Tentatively ok, */ +  } +  SET_CYCLIC_RET(1); +     for(e=0;e<b->num_identifier_references;e++)    {    struct identifier *bid;    int i; -  if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN)) +  if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN|ID_VARIANT))    continue; /* Skip protected & hidden */    bid = ID_FROM_INT(b,e);    if(s == bid->name) continue; /* Skip __INIT */    i = find_shared_string_identifier(bid->name,a);    if (i == -1) {    if (b->identifier_references[e].id_flags & (ID_OPTIONAL))    continue; /* It's ok... */   #if 0    fprintf(stderr, "Missing identifier \"%s\"\n", bid->name->str);   #endif /* 0 */ -  return 0; +  ret = 0; +  break;    }       if (!pike_types_le(bid->type, ID_FROM_INT(a, i)->type)) {    if(!match_types(ID_FROM_INT(a,i)->type, bid->type)) {   #if 0    fprintf(stderr, "Identifier \"%s\" is incompatible.\n",    bid->name->str);   #endif /* 0 */ -  return 0; +  ret = 0; +  break;    } else {   #if 0    fprintf(stderr, "Identifier \"%s\" is not strictly compatible.\n",    bid->name->str);   #endif /* 0 */    }    }    } -  return 1; +  +  END_CYCLIC(); +  return ret;   }    - #define IMPLEMENTS_CACHE_SIZE 4711 + #define IMPLEMENTS_CACHE_SIZE 1024   struct implements_cache_s { INT32 aid, bid, ret; };   static struct implements_cache_s implements_cache[IMPLEMENTS_CACHE_SIZE];    - /* returns 1 if a implements b, but faster */ + static int implements_hval( INT32 aid, INT32 bid ) + { +  return ((aid<<4) ^ bid ^ (aid>>4)) & (IMPLEMENTS_CACHE_SIZE-1); + } +  + /** +  * @return Returns 1 if a implements b, but faster. +  */   PMOD_EXPORT int implements(struct program *a, struct program *b)   {    unsigned long hval;    if(!a || !b) return -1;    if(a==b) return 1;    -  hval = a->id*9248339 + b->id; -  hval %= IMPLEMENTS_CACHE_SIZE; - #ifdef PIKE_DEBUG -  if(hval >= IMPLEMENTS_CACHE_SIZE) -  Pike_fatal("Implements_cache failed!\n"); - #endif +  hval = implements_hval(a->id,b->id);    if(implements_cache[hval].aid==a->id && implements_cache[hval].bid==b->id)    {    return implements_cache[hval].ret;    }    /* Do it the tedious way */    implements_cache[hval].aid=a->id;    implements_cache[hval].bid=b->id;    implements_cache[hval].ret = 1; /* Tentatively compatible. */    implements_cache[hval].ret = low_implements(a,b);    /* NOTE: If low_implements() returns 0, the cache may have received    * some false positives. Those should be cleared.    */    return implements_cache[hval].ret;   }    - /* Returns 1 if a is compatible with b */ + /** +  * @return Returns 1 if a is compatible with b. +  */   static int low_is_compatible(struct program *a, struct program *b)   { -  +  DECLARE_CYCLIC();    int e; -  +  int ret = 1;    struct pike_string *s=findstring("__INIT");    -  +  if (BEGIN_CYCLIC(a, b)) { +  END_CYCLIC(); +  return 1; +  } +  SET_CYCLIC_RET(1); +     /* Optimize the loop somewhat */    if (a->num_identifier_references < b->num_identifier_references) {    struct program *tmp = a;    a = b;    b = tmp;    }       for(e=0;e<b->num_identifier_references;e++)    {    struct identifier *bid;    int i; -  if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN)) +  if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN|ID_VARIANT))    continue; /* Skip protected & hidden */       /* FIXME: What if they aren't protected & hidden in a? */       bid = ID_FROM_INT(b,e);    if(s == bid->name) continue; /* Skip __INIT */    i = find_shared_string_identifier(bid->name,a);    if (i == -1) {    continue; /* It's ok... */    }       /* Note: Uses weaker check for constant integers. */    if(((bid->run_time_type != PIKE_T_INT) ||    (ID_FROM_INT(a, i)->run_time_type != PIKE_T_INT)) &&    !match_types(ID_FROM_INT(a,i)->type, bid->type)) {   #if 0    fprintf(stderr, "Identifier \"%s\" is incompatible.\n",    bid->name->str);   #endif /* 0 */ -  return 0; +  ret = 0; +  break;    }    } -  return 1; +  +  END_CYCLIC(); +  return ret;   }      static struct implements_cache_s is_compatible_cache[IMPLEMENTS_CACHE_SIZE]; - /* Returns 1 if a is compatible with b + /** +  * Returns 1 if a is compatible with b. +  *    * ie it's possible to write a hypothetical c that implements both.    */   PMOD_EXPORT int is_compatible(struct program *a, struct program *b)   {    unsigned long hval;    unsigned long rhval;    int aid, bid;    if(!a || !b) return -1;    if(a==b) return 1;       /* Order the id's so we don't need double entries in the cache. */    aid = a->id;    bid = b->id;    if (aid > bid) {    int tmp = aid;    aid = bid;    bid = tmp;    }    -  hval = aid*9248339 + bid; -  hval %= IMPLEMENTS_CACHE_SIZE; - #ifdef PIKE_DEBUG -  if(hval >= IMPLEMENTS_CACHE_SIZE) -  Pike_fatal("Implements_cache failed!\n"); - #endif +  hval = implements_hval(aid,bid);    if(is_compatible_cache[hval].aid==aid &&    is_compatible_cache[hval].bid==bid)    {    return is_compatible_cache[hval].ret;    }    if(implements_cache[hval].aid==aid &&    implements_cache[hval].bid==bid &&    implements_cache[hval].ret)    {    /* a implements b */    return 1;    } -  rhval = bid*9248339 + aid; -  rhval %= IMPLEMENTS_CACHE_SIZE; - #ifdef PIKE_DEBUG -  if(rhval >= IMPLEMENTS_CACHE_SIZE) -  Pike_fatal("Implements_cache failed!\n"); - #endif +  rhval = implements_hval(bid,aid);    if(implements_cache[rhval].aid==bid &&    implements_cache[rhval].bid==aid &&    implements_cache[rhval].ret)    {    /* b implements a */    return 1;    }    /* Do it the tedious way */    is_compatible_cache[hval].aid=aid;    is_compatible_cache[hval].bid=bid;    is_compatible_cache[hval].ret = 1; /* Tentatively compatible. */    is_compatible_cache[hval].ret = low_is_compatible(a,b);    /* NOTE: If low_is compatible() returns 0, the cache may have received    * some false positives. Those should be cleared.    */    return is_compatible_cache[hval].ret;   }    - /* Explains why a is not compatible with b */ + /** +  * Explains why a is not compatible with b. +  */   void yyexplain_not_compatible(int severity_level,    struct program *a, struct program *b)   {    int e;    struct pike_string *s=findstring("__INIT");    int res = 1; -  INT32 a_line = 0; -  INT32 b_line = 0; +  INT_TYPE a_line = 0; +  INT_TYPE b_line = 0;    struct pike_string *a_file;    struct pike_string *b_file;    DECLARE_CYCLIC();       /* Optimize the loop somewhat */    if (a->num_identifier_references < b->num_identifier_references) {    struct program *tmp = a;    a = b;    b = tmp;    }
pike.git/src/program.c:11062:    }    SET_CYCLIC_RET(1);       a_file = get_program_line(a, &a_line);    b_file = get_program_line(b, &b_line);       for(e=0;e<b->num_identifier_references;e++)    {    struct identifier *bid;    int i; -  if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN)) +  if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN|ID_VARIANT))    continue; /* Skip protected & hidden */       /* FIXME: What if they aren't protected & hidden in a? */       bid = ID_FROM_INT(b,e);    if(s == bid->name) continue; /* Skip __INIT */    i = find_shared_string_identifier(bid->name,a);    if (i == -1) {    continue; /* It's ok... */    }       /* Note: Uses weaker check for constant integers. */    if(((bid->run_time_type != PIKE_T_INT) ||    (ID_FROM_INT(a, i)->run_time_type != PIKE_T_INT)) &&    !match_types(ID_FROM_INT(a,i)->type, bid->type)) { -  INT32 aid_line = a_line; -  INT32 bid_line = b_line; +  INT_TYPE aid_line = a_line; +  INT_TYPE bid_line = b_line;    struct pike_string *aid_file = get_identifier_line(a, i, &aid_line);    struct pike_string *bid_file = get_identifier_line(b, e, &bid_line);    if (!aid_file) aid_file = a_file;    if (!bid_file) bid_file = b_file;    ref_push_string(bid->name);    ref_push_program(a);    ref_push_program(b);    yytype_report(severity_level,    aid_file, aid_line, ID_FROM_INT(a, i)->type,    bid_file, bid_line, bid->type, 3,    "Identifier %s in %O is incompatible with the same in %O.");    }    }    free_string(b_file);    free_string(a_file);    END_CYCLIC();    return;   }    - /* Explains why a does not implement b */ + /** +  * Explains why a does not implement b. +  */   void yyexplain_not_implements(int severity_level,    struct program *a, struct program *b)   {    int e;    struct pike_string *s=findstring("__INIT"); -  INT32 a_line = 0; -  INT32 b_line = 0; +  INT_TYPE a_line = 0; +  INT_TYPE b_line = 0;    struct pike_string *a_file;    struct pike_string *b_file;    DECLARE_CYCLIC();       if (BEGIN_CYCLIC(a, b)) {    END_CYCLIC();    return;    }    SET_CYCLIC_RET(1);       a_file = get_program_line(a, &a_line);    b_file = get_program_line(b, &b_line);       for(e=0;e<b->num_identifier_references;e++)    {    struct identifier *bid;    int i; -  if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN)) +  if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN|ID_VARIANT))    continue; /* Skip protected & hidden */    bid = ID_FROM_INT(b,e);    if(s == bid->name) continue; /* Skip __INIT */    i = find_shared_string_identifier(bid->name,a);    if (i == -1) { -  INT32 bid_line = b_line; +  INT_TYPE bid_line = b_line;    struct pike_string *bid_file;    if (b->identifier_references[e].id_flags & (ID_OPTIONAL))    continue; /* It's ok... */    bid_file = get_identifier_line(b, e, &bid_line);    if (!bid_file) bid_file = b_file;    yytype_report(severity_level,    bid_file, bid_line, bid->type,    a_file, a_line, NULL,    0, "Missing identifier %S.", bid->name);    continue;    }       if (!pike_types_le(bid->type, ID_FROM_INT(a, i)->type)) { -  INT32 aid_line = a_line; -  INT32 bid_line = b_line; +  INT_TYPE aid_line = a_line; +  INT_TYPE bid_line = b_line;    struct pike_string *aid_file = get_identifier_line(a, i, &aid_line);    struct pike_string *bid_file = get_identifier_line(b, e, &bid_line);    if (!aid_file) aid_file = a_file;    if (!bid_file) bid_file = b_file;    if(!match_types(ID_FROM_INT(a,i)->type, bid->type)) {    yytype_report(severity_level,    bid_file, bid_line, bid->type,    aid_file, aid_line, ID_FROM_INT(a, i)->type,    0, "Type of identifier %S does not match.", bid->name);    } else {
pike.git/src/program.c:11171:    bid->name);    }    continue;    }    }    free_string(b_file);    free_string(a_file);    END_CYCLIC();   }    - PMOD_EXPORT void *parent_storage(int depth) + /* FIXME: Code duplication of yyexplain_not_compatible() above! */ + /** +  * Explains why a is not compatible with b. +  */ + void string_builder_explain_not_compatible(struct string_builder *s, +  struct program *a, +  struct program *b)   { -  struct external_variable_context loc; -  struct program *p; +  int e; +  struct pike_string *init_string = findstring("__INIT"); +  int res = 1; +  DECLARE_CYCLIC();    -  +  /* Optimize the loop somewhat */ +  if (a->num_identifier_references < b->num_identifier_references) { +  struct program *tmp = a; +  a = b; +  b = tmp; +  }    -  loc.o=Pike_fp->current_object; -  p=loc.o->prog; -  if(!p) +  if (BEGIN_CYCLIC(a, b)) { +  END_CYCLIC(); +  return; +  } +  SET_CYCLIC_RET(1); +  +  for(e=0;e<b->num_identifier_references;e++)    { -  /* magic fallback */ -  p=get_program_for_object_being_destructed(loc.o); -  if(!p) +  struct identifier *bid; +  int i; +  if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN|ID_VARIANT)) +  continue; /* Skip protected & hidden */ +  +  /* FIXME: What if they aren't protected & hidden in a? */ +  +  bid = ID_FROM_INT(b,e); +  if(init_string == bid->name) continue; /* Skip __INIT */ +  i = find_shared_string_identifier(bid->name,a); +  if (i == -1) { +  continue; /* It's ok... */ +  } +  +  /* Note: Uses weaker check for constant integers. */ +  if(((bid->run_time_type != PIKE_T_INT) || +  (ID_FROM_INT(a, i)->run_time_type != PIKE_T_INT)) && +  !match_types(ID_FROM_INT(a,i)->type, bid->type)) { +  ref_push_program(a); +  ref_push_program(b); +  ref_push_type_value(ID_FROM_INT(a, i)->type); +  ref_push_type_value(bid->type); +  string_builder_sprintf(s, +  "Identifier %S in %O is incompatible with " +  "the same in %O.\n" +  "Expected: %O\n" +  "Got : %O\n", +  bid->name, Pike_sp-4, +  Pike_sp-3, +  Pike_sp-2, +  Pike_sp-1); +  pop_n_elems(4); +  } +  } +  END_CYCLIC(); +  return; + } +  + /* FIXME: code duplication of yyexplain_not_implements() above! */ + /** +  * Explains why a does not implement b. +  */ + void string_builder_explain_not_implements(struct string_builder *s, +  struct program *a, +  struct program *b)   { -  Pike_error("Cannot access parent of destructed object.\n"); +  int e; +  struct pike_string *init_string = findstring("__INIT"); +  DECLARE_CYCLIC(); +  +  if (BEGIN_CYCLIC(a, b)) { +  END_CYCLIC(); +  return;    } -  +  SET_CYCLIC_RET(1); +  +  for(e=0;e<b->num_identifier_references;e++) +  { +  struct identifier *bid; +  int i; +  if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN|ID_VARIANT)) +  continue; /* Skip protected & hidden */ +  bid = ID_FROM_INT(b,e); +  if(init_string == bid->name) continue; /* Skip __INIT */ +  i = find_shared_string_identifier(bid->name,a); +  if (i == -1) { +  if (b->identifier_references[e].id_flags & (ID_OPTIONAL)) +  continue; /* It's ok... */ +  ref_push_type_value(bid->type); +  string_builder_sprintf(s, +  "Missing identifier %O %S.\n", +  Pike_sp-1, bid->name); +  pop_stack(); +  continue;    }    -  if((Pike_fp->fun & 0xffff) == 0xffff) -  Pike_error("Cannot access parent storage!\n"); +  if (!pike_types_le(bid->type, ID_FROM_INT(a, i)->type)) { +  ref_push_type_value(bid->type); +  ref_push_type_value(ID_FROM_INT(a, i)->type); +  if(!match_types(ID_FROM_INT(a,i)->type, bid->type)) { +  string_builder_sprintf(s, +  "Type of identifier %S does not match.\n" +  "Expected: %O.\n" +  "Got : %O.\n", +  bid->name, +  Pike_sp-2, +  Pike_sp-1); +  } else { +  string_builder_sprintf(s, +  "Type of identifier %S is not strictly compatible." +  "Expected: %O.\n" +  "Got : %O.\n", +  bid->name, +  Pike_sp-2, +  Pike_sp-1); +  } +  pop_n_elems(2); +  continue; +  } +  } +  END_CYCLIC(); + }    -  loc.parent_identifier=Pike_fp->fun; -  loc.inherit=INHERIT_FROM_INT(p, Pike_fp->fun); + PMOD_EXPORT void *parent_storage(int depth, struct program *expected) + { +  struct external_variable_context loc; +  int i;    -  +  loc.o = Pike_fp->current_object; +  loc.parent_identifier = 0; +  loc.inherit = Pike_fp->context; +     find_external_context(&loc, depth);       if (!loc.o->prog)    Pike_error ("Cannot access storage of destructed parent object.\n");    -  +  for (i = 0; i < loc.inherit->prog->num_inherits; i++) { +  if (loc.inherit[i].prog == expected) { +  /* Found. */ +  loc.inherit += i; +  break; +  } +  } +  + #ifdef PIKE_DEBUG +  if (loc.inherit->prog != expected) { +  Pike_fatal("Failed to find expected parent storage.\n"); +  } + #endif +     return loc.o->storage + loc.inherit->storage_offset;   }    -  + PMOD_EXPORT void *get_inherited_storage(int inh, +  struct program *DEBUGUSED(expected)) + { +  struct inherit *i = Pike_fp->context + inh; +  + #ifdef PIKE_DEBUG +  struct program *p = Pike_fp->current_program; +  if (i >= (p->inherits + p->num_inherits)) { +  Pike_fatal("Inherit out of range!\n"); +  } +  if (i->prog != expected) { +  Pike_fatal("Unexpected program at inherit #%d!\n", inh); +  } + #endif +  +  return Pike_fp->current_object->storage + i->storage_offset; + } +    PMOD_EXPORT void change_compiler_compatibility(int major, int minor)   {    CHECK_COMPILER();       push_int(major);    push_int(minor);       safe_apply_current2(PC_CHANGE_COMPILER_COMPATIBILITY_FUN_NUM, 2,    "change_compiler_compatibility");    pop_stack();   }      #ifdef PIKE_USE_MACHINE_CODE      #ifdef HAVE_SYS_MMAN_H   #include <sys/mman.h>   #endif    -  + #if defined(HAVE_SYNC_INSTRUCTION_MEMORY) || defined(FLUSH_INSTRUCTION_CACHE) || !defined(USE_MY_MEXEC_ALLOC)   void make_area_executable (char *start, size_t len)   {   #ifndef USE_MY_MEXEC_ALLOC    {    /* Perform page alignment. */    void *addr = (void *)(((size_t)start) & ~(page_size-1));    size_t l = ((start + len) - ((char *)addr) +    (page_size - 1)) & ~(page_size-1);       if (mprotect(addr, l, PROT_EXEC | PROT_READ | PROT_WRITE) < 0) {
pike.git/src/program.c:11245: Inside #if undefined(USE_MY_MEXEC_ALLOC)
   }    }   #endif /* !USE_MY_MEXEC_ALLOC */      #ifdef HAVE_SYNC_INSTRUCTION_MEMORY    sync_instruction_memory(start, len);   #elif defined(FLUSH_INSTRUCTION_CACHE)    FLUSH_INSTRUCTION_CACHE(start, len);   #endif /* HAVE_SYNC_INSTRUCTION_MEMORY || FLUSH_INSTRUCTION_CACHE */   } + #else + void make_area_executable (char *UNUSED(start), size_t UNUSED(len)) + { + } + #endif      void make_program_executable(struct program *p)   {    if (!p->num_program) return;    if ((p->event_handler == compat_event_handler) &&    ((p->num_program * sizeof(p->program[0]) <=    (NUM_PROG_EVENTS * sizeof(p->event_handler))))) {    /* Only event handlers. */    return;    }       make_area_executable ((char *) p->program,    p->num_program * sizeof (p->program[0]));   }   #endif