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: program.c,v 1.615 2007/05/13 15:45:32 mast Exp $ + || $Id: program.c,v 1.616 2007/05/26 19:14:59 mast Exp $   */      #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:2078:    p);          p->flags |= PROGRAM_FIXED;       /* Yes, it is supposed to start at 1 /Hubbe */    for(i=1;i<NUM_LFUNS;i++) {    p->lfuns[i] = low_find_lfun(p, i);    }    +  /* 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) { +  /* Got a destroy function that isn't a prototype. */ +  p->flags |= PROGRAM_LIVE_OBJ; +  goto program_live_obj_set; +  } +  } +  +  for (e = p->num_inherits - 1; e >= 0; e--) +  if (p->inherits[e].prog->flags & PROGRAM_LIVE_OBJ) { +  p->flags |= PROGRAM_LIVE_OBJ; +  break; +  } +  +  program_live_obj_set:; +  } +     if(Pike_compiler->flags & COMPILATION_CHECK_FINAL)    {    for(i=0;i<(int)p->num_identifier_references;i++)    {    if((p->identifier_references[i].id_flags & (ID_NOMASK|ID_HIDDEN)) ==    ID_NOMASK)    {    struct pike_string *name=ID_FROM_INT(p, i)->name;       e=find_shared_string_identifier(name,p);
pike.git/src/program.c:3430:    Pike_compiler->new_program->inherits[e].storage_offset+=available;       Pike_compiler->new_program->storage_needed+=available;    }       return (size_t) offset;   }      typedef void (*oldhandlertype)(struct object *);    - /* Function pointer checked by gc_object_is_live. */ - void compat_event_handler(int e) + static void compat_event_handler(int e)   {    oldhandlertype handler;    debug_malloc_touch(Pike_fp->current_object);    handler=((oldhandlertype *)Pike_fp->context.prog->program)[e];    if(handler) handler(Pike_fp->current_object);    debug_malloc_touch(Pike_fp->current_object);   }      static void add_compat_event_handler(void)   {
pike.git/src/program.c:3464:    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 almost obsolete; see pike_set_prog_event_callback -  * for details. +  * 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 almost obsolete; see pike_set_prog_event_callback -  * for details. +  * 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; +  * +  * after the set_exit_callback call. That allows the gc to operate +  * more efficiently, but the effect is that the callback might be +  * 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    * objects. 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.    *    * The callback is called after any mapped variables on the object    * have been recursed (and possibly freed).    * -  * This function is almost obsolete; see pike_set_prog_event_callback -  * for details. +  * 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 objects.    * It should call gc_check, gc_check_(weak_)svalues or    * gc_check_(weak_)short_svalue exactly once for each reference that    * the pike internals doesn'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.    * -  * This function is almost obsolete; see pike_set_prog_event_callback -  * for details. +  * 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
pike.git/src/program.c:3547:    * for details.    * PROG_EVENT_EXIT    * An object is being destructed. See set_exit_callback for details.    * PROG_EVENT_GC_RECURSE    * An object is being recursed by the gc. See    * set_gc_recurse_callback for details.    * PROG_EVENT_GC_CHECK    * An object is being checked by the gc. See set_gc_check_callback    * for details.    * -  * Using this instead of the set_*_callback functions saves some space -  * in the program (four function pointers) and is a bit more -  * efficient. +  * Note that installing an event callback will set the +  * PROGRAM_LIVE_OBJ flag since the callback might act on the +  * PROG_EVENT_EXIT event. If the callback won't do anything for that +  * event (or if it only does something very trivial for it), you +  * should do    * -  * Otoh, it forces the gc to handle all clones as "live" since the -  * callback might act on PROG_EVENT_EXIT. So if there's no need to do -  * anything for that event, using the set_*_callback functions allows -  * the gc to handle the object more efficiently if it occurs in -  * cycles. +  * Pike_compiler->new_program->flags &= ~PROGRAM_LIVE_OBJ; +  * +  * afterwards to clear it again. That allows the gc to operate more +  * efficiently, but the effect is that the callback might be 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 pike_set_prog_event_callback(void (*cb)(int))   {   #ifdef PIKE_DEBUG    if(Pike_compiler->new_program->event_handler)    Pike_fatal("Program already has an event handler!\n");   #endif    Pike_compiler->new_program->event_handler=cb; -  +  Pike_compiler->new_program->flags |= PROGRAM_LIVE_OBJ;   }      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;   }