faster startup 2/n

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

faster startup 2/n

Paolo Bonzini
A slightly trickier one.  If we don't save directly from the object
area, but allocate temporary memory for that, we can save different data
than what is in the object memory.  So, we can kill CallinProcesses when
saving, and we can force looking up CFunctionDescriptor addresses the
first time they are called.  Finally, we can map the interpreter's
primitives to what is in the image, rather than patch the
CompiledMethods so that they match the primitive numbers that were
selected at compile time.

All this replaces a loop that walked through all the objects at load
time, and saves another 10% (on top of the VFS patch that I have not yet
posted).

Next coming: replacing the _gst_mem_alloc with something less expensive
and/or storing absolute object addresses in the image, in order to
enable copy-on-write semantics if the OOP area can be loaded at the same
place.

Paolo

2006-12-14  Paolo Bonzini  <[hidden email]>

        * kernel/CFuncs.st: Accept that the address is nil.

        * libgst/cint.c: Move gst_cfunc_descriptor to cint.h.  Accept a nil
        cFunction inside a descriptor (now happens upon image load),
        remove _gst_restore_cfunc_descriptor.
        * libgst/cint.h: Adjust for cint.c changes.
        * libgst/comp.c: Remove _gst_restore_primitive_number.
        * libgst/comp.h: Remove _gst_restore_primitive_number.
        * libgst/dict.c: Initialize primitive table from default in
        _gst_init_dictionary, and from the image in prepare_primitives_table
        (which replaces prepare_primitive_numbers_map).  Don't reset
        the VMPrimitives dictionary upon image load, and don't walk the
        OOP table.
        * libgst/genpr-parse.y: Initialize _gst_default_primitive_table
        instead of _gst_primitive_table.
        * libgst/interp.c: Use _gst_default_primitive_table in
        _gst_get_primitive_attributes, add _gst_set_primitive_attributes.
        Make the primitive tables public.
        * libgst/interp.h: Adjust for the above.
        * libgst/save.c: Allocate temporary storage for the object that
        are about to be saved.  Massage the CallinProcess, Process,
        Semaphore and CFunctionDescriptor instances in that temporary
        storage rather than at load time.

--- orig/kernel/CFuncs.st
+++ mod/kernel/CFuncs.st
@@ -94,12 +94,11 @@ isValid
     "Answer whether the function represented by the receiver is actually
     a registered one"
     | newAddress |
-    cFunction address = 0 ifFalse: [ ^true ].
+    (cFunction notNil and: [ cFunction address ~= 0 ]) ifTrue: [ ^true ].
 
     newAddress := CFunctionDescriptor addressOf: self name.
+    self address: newAddress.
     ^newAddress address ~= 0
- ifTrue: [ self address: newAddress ];
- yourself
 ! !
 
 


--- orig/libgst/cint.c
+++ mod/libgst/cint.c
@@ -97,22 +97,6 @@ typedef enum
 }
 cdata_type;
 
-typedef struct gst_cfunc_descriptor
-{
-  OBJ_HEADER;
-  OOP cFunction; /* gst_cobject whose C value is func
-   addr */
-  OOP cFunctionName; /* Name of C function in mapping table */
-  OOP returnType; /* Smalltalk return type */
-  OOP numFixedArgs; /* number of real arguments passed from
-   smalltalk (excluding "self" parameters
-     which are synthetically added when
-   calling the C function).  */
-  OOP argTypes[1]; /* variable length, really numFixedArgs
-   long */
-}
- *gst_cfunc_descriptor;
-
 typedef struct symbol_type_map
 {
   OOP *symbol;
@@ -644,6 +628,9 @@ _gst_invoke_croutine (OOP cFuncOOP,
   incPtr = INC_SAVE_POINTER ();
 
   desc = (gst_cfunc_descriptor) OOP_TO_OBJ (cFuncOOP);
+  if (IS_NIL (desc->cFunction))
+    return (NULL);
+
   c_func_cur = (cfunc_info *) COBJECT_VALUE (desc->cFunction);
   if (!c_func_cur)
     return (NULL);
@@ -1245,17 +1232,3 @@ _gst_set_errno(int errnum)
   _gst_errno = errnum;
 #endif
 }
-
-void
-_gst_restore_cfunc_descriptor (OOP cFuncDescOOP)
-{
-  gst_cfunc_descriptor desc;
-  cfunc_info *cfi;
-  char *funcName;
-
-  desc = (gst_cfunc_descriptor) OOP_TO_OBJ (cFuncDescOOP);
-  funcName = (char *) _gst_to_cstring (desc->cFunctionName);
-  cfi = lookup_function (funcName);
-  xfree (funcName);
-  SET_COBJECT_VALUE (desc->cFunction, cfi);
-}


--- orig/libgst/cint.h
+++ mod/libgst/cint.h
@@ -63,6 +63,22 @@ extern int _gst_errno
 /* Element type for the name-to-C-function mapping table.  */
 typedef void (*p_void_func) ();
 
+typedef struct gst_cfunc_descriptor
+{
+  OBJ_HEADER;
+  OOP cFunction;                /* gst_cobject whose C value is func
+                                   addr */
+  OOP cFunctionName;            /* Name of C function in mapping table */
+  OOP returnType;               /* Smalltalk return type */
+  OOP numFixedArgs;             /* number of real arguments passed from
+                                   smalltalk (excluding "self" parameters
+                                   which are synthetically added when
+                                   calling the C function).  */
+  OOP argTypes[1];              /* variable length, really numFixedArgs
+                                   long */
+}
+ *gst_cfunc_descriptor;
+
 /* Invokes a C routine.  Arguments passed from Smalltalk are stored starting
    from ARGS, and the object to which the message that called-out was
    sent is RECEIVER.  CFUNCOOP is the C function descriptor used
@@ -87,16 +103,6 @@ extern void _gst_define_cfunc (const cha
 extern void _gst_init_cfuncs (void)
   ATTRIBUTE_HIDDEN;
 
-/* This routine is called during image loading to restore a C function
-   descriptor pointer.  This is because between the time that the image
-   was made and now, the executable image may have changed, so any
-   reference to the C function address may be invalid.  We therefore just
-   perform the function lookup again and use that value.  CFUNCDESCOOP
-   is the C function descriptor object to be adjusted, which contains
-   the name of the function to be looked up.  */
-extern void _gst_restore_cfunc_descriptor (OOP cFuncDescOOP)
-  ATTRIBUTE_HIDDEN;
-
 /* Makes a C based descriptor for a callout method.  Returns a
    gst_cfunc_descriptor object which holds onto the descriptor.  This
    descriptor is subsequently used when the called out function


--- orig/libgst/comp.c
+++ mod/libgst/comp.c
@@ -2901,11 +2901,3 @@ file_segment_new (void)
   INC_RESTORE_POINTER (incPtr);
   return (fileSegmentOOP);
 }
-
-void _gst_restore_primitive_number (OOP methodOOP, int *map)
-{
-  gst_compiled_method method;
-
-  method = (gst_compiled_method) OOP_TO_OBJ (methodOOP);
-  method->header.primitiveIndex = map[method->header.primitiveIndex];
-}


--- orig/libgst/comp.h
+++ mod/libgst/comp.h
@@ -104,9 +104,9 @@ typedef struct method_header
 {
 #ifdef WORDS_BIGENDIAN
 #if SIZEOF_OOP == 8
-  unsigned dummy:32; /* unused */
+  unsigned :32; /* unused */
 #endif
-  unsigned:1; /* sign - must be 0 */
+  unsigned :1; /* sign - must be 0 */
   unsigned headerFlag:MTH_FLAG_BITS; /* prim _gst_self, etc.  */
   unsigned primitiveIndex:MTH_PRIM_BITS; /* index of primitve,
    or 0 */
@@ -122,9 +122,9 @@ typedef struct method_header
   unsigned primitiveIndex:MTH_PRIM_BITS; /* index of primitve,
    or 0 */
   unsigned headerFlag:MTH_FLAG_BITS; /* prim _gst_self, etc.  */
-  unsigned:1; /* sign - must be 0 */
+  unsigned :1; /* sign - must be 0 */
 #if SIZEOF_OOP == 8
-  unsigned dummy:32; /* unused */
+  unsigned :32; /* unused */
 #endif
 #endif /* WORDS_BIGENDIAN */
 }
@@ -174,29 +174,29 @@ typedef struct block_header
 {
 #ifdef WORDS_BIGENDIAN
 #if SIZEOF_OOP == 8
-  unsigned dummy:32; /* unused */
+  unsigned :32; /* unused */
 #endif
-  unsigned:1; /* sign - must be 0 */
+  unsigned :1; /* sign - must be 0 */
   unsigned numArgs:BLK_ARGS_BITS; /* number of arguments we have */
   unsigned numTemps:BLK_TEMPS_BITS; /* number of _gst_temporaries
    we have */
   unsigned depth:BLK_DEPTH_BITS; /* number of stack slots needed
  */
-  unsigned unused:BLK_UNUSED_BITS;
+  unsigned :BLK_UNUSED_BITS;
   unsigned clean:BLK_CLEAN_BITS; /* behavior of block */
   unsigned intMark:1; /* flag this as an Int */
 #else
   unsigned intMark:1; /* flag this as an Int */
   unsigned clean:BLK_CLEAN_BITS; /* behavior of block */
-  unsigned unused:BLK_UNUSED_BITS;
+  unsigned :BLK_UNUSED_BITS;
   unsigned depth:BLK_DEPTH_BITS; /* number of stack slots needed
  */
   unsigned numTemps:BLK_TEMPS_BITS; /* number of _gst_temporaries
    we have */
   unsigned numArgs:BLK_ARGS_BITS; /* number of arguments we have */
-  unsigned:1; /* sign - must be 0 */
+  unsigned :1; /* sign - must be 0 */
 #if SIZEOF_OOP == 8
-  unsigned dummy:32; /* unused */
+  unsigned :32; /* unused */
 #endif
 #endif
 }
@@ -375,17 +375,6 @@ extern int _gst_add_forced_object (OOP o
 extern OOP _gst_make_attribute (tree_node attribute_keywords)
   ATTRIBUTE_HIDDEN;
 
-/* This routine is called during image loading to restore the
-   primitive number in a CompiledMethod.  This is because we achieve
-   better binary compatibility if we keep the primitives name
-   invariant, rather than the primitive index, across image loads.
-   This allows us to keep the primitive list in prims.inl in a logical
-   order rather than having to add at the end of the list.  MAP
-   associates primitive numbers in the saved image (obtained by the
-   saved VMPrimitives dictionary) to primitive numbers in this VM.  */
-extern void _gst_restore_primitive_number (OOP methodOOP, int *map)
-  ATTRIBUTE_HIDDEN;
-
 /* Process the attributes in ARRAYOOP, return the primitive number
    (so far, this is the only attribute we honor), or -1 for a bad
    primitive number.  */


--- orig/libgst/dict.c
+++ mod/libgst/dict.c
@@ -223,7 +223,7 @@ static void init_smalltalk_dictionary (v
 
 /* This fills MAP so that it associates primitive numbers in the saved
    image to primitive numbers in this VM.  */
-static void prepare_primitive_numbers_map (int *map);
+static void prepare_primitive_numbers_table (void);
 
 /* Add a global named GLOBALNAME and give it the value GLOBALVALUE.
    Return GLOBALVALUE.  */
@@ -768,6 +768,9 @@ init_proto_oops()
 void
 _gst_init_dictionary (void)
 {
+  memcpy (_gst_primitive_table, _gst_default_primitive_table,
+          sizeof (_gst_primitive_table));
+
   /* The order of this must match the indices defined in oop.h!! */
   _gst_smalltalk_dictionary = alloc_oop (NULL, _gst_mem.active_flag);
   _gst_processor_oop = alloc_oop (NULL, _gst_mem.active_flag);
@@ -1228,8 +1231,6 @@ mst_Boolean
 _gst_init_dictionary_on_image_load (size_t numOOPs)
 {
   const class_definition *ci;
-  OOP oop;
-  int primitive_numbers_map[NUM_PRIMITIVES];
 
   _gst_smalltalk_dictionary = OOP_AT (SMALLTALK_OOP_INDEX);
   _gst_processor_oop = OOP_AT (PROCESSOR_OOP_INDEX);
@@ -1261,38 +1262,20 @@ _gst_init_dictionary_on_image_load (size
   _gst_init_builtin_objects_classes ();
   _gst_init_symbols ();
 
-  /* Important: this is called *before* init_primitives_dictionary
-     fills the VMPrimitives dictionary and *after* _gst_init_symbols
+  /* Important: this is called *after* _gst_init_symbols
      fills in _gst_vm_primitives_symbol! */
-  prepare_primitive_numbers_map (primitive_numbers_map);
-
-  init_primitives_dictionary ();
+  prepare_primitive_numbers_table ();
   init_runtime_objects ();
-
-  for (oop = _gst_mem.ot_base; oop < &_gst_mem.ot[numOOPs]; oop++)
-    {
-      if (!IS_OOP_VALID_GC (oop))
- continue;
-
-      if UNCOMMON (OOP_CLASS (oop) == _gst_c_func_descriptor_class)
- _gst_restore_cfunc_descriptor (oop); /* in cint.c */
-      else if UNCOMMON (OOP_CLASS (oop) == _gst_compiled_method_class)
- _gst_restore_primitive_number (oop, primitive_numbers_map);
-      else if UNCOMMON (OOP_CLASS (oop) == _gst_callin_process_class)
- _gst_terminate_process (oop);
-    }
-
   return (true);
 }
 
 void
-prepare_primitive_numbers_map (int *map)
+prepare_primitive_numbers_table ()
 {
   int i;
   OOP primitivesDictionaryOOP;
   gst_dictionary primitivesDictionary;
 
-  memzero (map, NUM_PRIMITIVES * sizeof (int));
   primitivesDictionaryOOP = dictionary_at (_gst_smalltalk_dictionary,
    _gst_vm_primitives_symbol);
 
@@ -1300,6 +1283,9 @@ prepare_primitive_numbers_map (int *map)
     (gst_dictionary) OOP_TO_OBJ (primitivesDictionaryOOP);
 
   for (i = 0; i < NUM_PRIMITIVES; i++)
+    _gst_set_primitive_attributes (i, NULL);
+
+  for (i = 0; i < NUM_PRIMITIVES; i++)
     {
       prim_table_entry *pte = _gst_get_primitive_attributes (i);
       OOP symbolOOP, valueOOP;
@@ -1311,15 +1297,14 @@ prepare_primitive_numbers_map (int *map)
       symbolOOP = _gst_intern_string (pte->name);
       valueOOP = dictionary_at (primitivesDictionaryOOP, symbolOOP);
 
-      if IS_NIL (valueOOP)
+      if (IS_NIL (valueOOP))
         {
           _gst_errorf ("bad primitive name");
           continue;
         }
 
       old_index = TO_INT (valueOOP);
-      map[old_index] = i;
-      /* printf ("Old primitive %d is now %d\n", old_index, i); */
+      _gst_set_primitive_attributes (old_index, pte);
     }
 }
 


--- orig/libgst/genpr-parse.c
+++ mod/libgst/genpr-parse.c
@@ -1824,10 +1824,10 @@ gen_prim_id (const char *name, int id, c
   prim_no++;
 
   filprintf (def_fil,
-     "  _gst_primitive_table[%d].name = \"%s\";\n"
-     "  _gst_primitive_table[%d].attributes = %s;\n"
-     "  _gst_primitive_table[%d].id = %d;\n"
-     "  _gst_primitive_table[%d].func = %s;\n",
+     "  _gst_default_primitive_table[%d].name = \"%s\";\n"
+     "  _gst_default_primitive_table[%d].attributes = %s;\n"
+     "  _gst_default_primitive_table[%d].id = %d;\n"
+     "  _gst_default_primitive_table[%d].func = %s;\n",
      prim_no, name,
      prim_no, attrs,
      prim_no, id,
@@ -1890,12 +1890,12 @@ output()
   "  int i;\n"
   "%s"
   "\n"
-  "  for (i = %d; i < 1023; i++)\n"
+  "  for (i = %d; i < NUM_PRIMITIVES; i++)\n"
   "    {\n"
-  "      _gst_primitive_table[i].name = NULL;\n"
-  "      _gst_primitive_table[i].attributes = PRIM_FAIL;\n"
-  "      _gst_primitive_table[i].id = i;\n"
-  "      _gst_primitive_table[i].func = VMpr_HOLE;\n"
+  "      _gst_default_primitive_table[i].name = NULL;\n"
+  "      _gst_default_primitive_table[i].attributes = PRIM_FAIL;\n"
+  "      _gst_default_primitive_table[i].id = i;\n"
+  "      _gst_default_primitive_table[i].func = VMpr_HOLE;\n"
   "    }\n"
   "}\n"
   "\n", proto, stmt, def, prim_no + 1);


--- orig/libgst/genpr-parse.y
+++ mod/libgst/genpr-parse.y
@@ -315,10 +315,10 @@ gen_prim_id (const char *name, int id, c
   prim_no++;
 
   filprintf (def_fil,
-     "  _gst_primitive_table[%d].name = \"%s\";\n"
-     "  _gst_primitive_table[%d].attributes = %s;\n"
-     "  _gst_primitive_table[%d].id = %d;\n"
-     "  _gst_primitive_table[%d].func = %s;\n",
+     "  _gst_default_primitive_table[%d].name = \"%s\";\n"
+     "  _gst_default_primitive_table[%d].attributes = %s;\n"
+     "  _gst_default_primitive_table[%d].id = %d;\n"
+     "  _gst_default_primitive_table[%d].func = %s;\n",
      prim_no, name,
      prim_no, attrs,
      prim_no, id,
@@ -381,12 +381,12 @@ output()
   "  int i;\n"
   "%s"
   "\n"
-  "  for (i = %d; i < 1023; i++)\n"
+  "  for (i = %d; i < NUM_PRIMITIVES; i++)\n"
   "    {\n"
-  "      _gst_primitive_table[i].name = NULL;\n"
-  "      _gst_primitive_table[i].attributes = PRIM_FAIL;\n"
-  "      _gst_primitive_table[i].id = i;\n"
-  "      _gst_primitive_table[i].func = VMpr_HOLE;\n"
+  "      _gst_default_primitive_table[i].name = NULL;\n"
+  "      _gst_default_primitive_table[i].attributes = PRIM_FAIL;\n"
+  "      _gst_default_primitive_table[i].id = i;\n"
+  "      _gst_default_primitive_table[i].func = VMpr_HOLE;\n"
   "    }\n"
   "}\n"
   "\n", proto, stmt, def, prim_no + 1);


--- orig/libgst/interp.c
+++ mod/libgst/interp.c
@@ -152,7 +152,8 @@ mst_Boolean _gst_make_core_file = false;
 mst_Boolean _gst_non_interactive = true;
 
 /* The table of functions that implement the primitives.  */
-static prim_table_entry _gst_primitive_table[NUM_PRIMITIVES];
+prim_table_entry _gst_primitive_table[NUM_PRIMITIVES];
+prim_table_entry _gst_default_primitive_table[NUM_PRIMITIVES];
 
 /* Some performance counters from the interpreter: these
    count the number of special returns.  */
@@ -2620,7 +2621,16 @@ execute_primitive_operation (int primiti
 prim_table_entry *
 _gst_get_primitive_attributes (int primitive)
 {
-  return &_gst_primitive_table[primitive];
+  return &_gst_default_primitive_table[primitive];
+}
+
+void
+_gst_set_primitive_attributes (int primitive, prim_table_entry *pte)
+{
+  if (pte)
+    _gst_primitive_table[primitive] = *pte;
+  else
+    _gst_primitive_table[primitive] = _gst_default_primitive_table[0];
 }
 
 void


--- orig/libgst/interp.h
+++ mod/libgst/interp.h
@@ -542,12 +542,23 @@ prim_table_entry;
 #define PRIM_RETURN_SMALL_INTEGER 0x0100 /* 31 or 63 bits */
 #define PRIM_RETURN_SMALL_SMALLINTEGER 0x0300 /* 30 or 62 bits */
 
+/* The table of functions that implement the primitives.  */
+extern prim_table_entry _gst_primitive_table[NUM_PRIMITIVES];
+extern prim_table_entry _gst_default_primitive_table[NUM_PRIMITIVES];
+
 /* This can be used to obtain information on a particular primitive
    operations in the GNU Smalltalk system.  */
 extern prim_table_entry * _gst_get_primitive_attributes (int primitive)
   ATTRIBUTE_PURE
   ATTRIBUTE_HIDDEN;
 
+/* Dually, this maps the primitive number that will be used for running
+   the image, to the entry which was returned by _gst_get_primitive_attributes.
+   If PTE is NULL, the primitive will be invalid.  */
+extern void _gst_set_primitive_attributes (int primitive,
+   prim_table_entry *pte)
+  ATTRIBUTE_HIDDEN;
+
 /* Initialize the table of primitives.  */
 extern void _gst_init_primitives ()
   ATTRIBUTE_HIDDEN;


--- orig/libgst/save.c
+++ mod/libgst/save.c
@@ -161,15 +161,16 @@ static void buffer_fill (int imageFd);
 static void save_object (int imageFd,
  OOP oop);
 
-/* This function converts NUMFIXED absolute addresses at OBJ->data,
-   which are instance variables of the object, into relative ones.  */
-static inline void fixup_object (gst_object obj,
-  int numPointers);
+/* This function copies NUMBYTES from SRC to DEST, converting the first
+   NUMPOINTERS absolute addresses into relative ones (these are the
+   instance variables of the object).  */
+static inline void fixup_object (gst_object dest, gst_object src,
+ int numPointers, int numBytes);
 
-/* This function converts NUMFIXED relative addresses at OBJ->data,
+/* This function converts NUMPOINTERS relative addresses at OBJECT,
    which are instance variables of the object, into absolute ones.  */
 static inline void restore_object (gst_object object,
-    int numPointers);
+   int numPointers);
 
 /* This function inverts the endianness of SIZE long-words, starting at
    BUF.  */
@@ -366,7 +367,7 @@ void
 save_object (int imageFd,
      OOP oop)
 {
-  gst_object object;
+  gst_object object, saveObject;
   int numPointers, numBytes;
 
 #ifdef SNAPSHOT_TRACE
@@ -380,10 +381,20 @@ save_object (int imageFd,
   if (IS_OOP_FREE (oop))
     abort ();
 
-  fixup_object (object, numPointers);
   numBytes = sizeof (OOP) * TO_INT (object->objSize);
-  buffer_write (imageFd, object, numBytes);
-  restore_object (object, numPointers);
+  if (numBytes < 262144)
+    {
+      saveObject = alloca (numBytes);
+      fixup_object (saveObject, object, numPointers, numBytes);
+      buffer_write (imageFd, saveObject, numBytes);
+    }
+  else
+    {
+      saveObject = malloc (numBytes);
+      fixup_object (saveObject, object, numPointers, numBytes);
+      buffer_write (imageFd, saveObject, numBytes);
+      free (saveObject);
+    }
 }
 
 void
@@ -624,20 +635,79 @@ load_normal_oops (int imageFd)
    loading and saving */
 
 void
-fixup_object (gst_object obj,
-      int numPointers)
+fixup_object (gst_object dest, gst_object src,
+      int numPointers, int numBytes)
 {
-  OOP instOOP, class_oop, *i;
+  OOP class_oop;
+  int i;
 
-  class_oop = obj->objClass;
-  obj->objClass = OOP_RELATIVE (class_oop);
+  class_oop = src->objClass;
+  dest->objSize = src->objSize;
+  dest->objClass = OOP_RELATIVE (class_oop);
 
-  for (i = obj->data; numPointers; i++, numPointers--)
+  for (i = 0; i < numPointers; i++)
+    if (IS_INT (src->data[i]))
+      dest->data[i] = src->data[i];
+    else
+      dest->data[i] = OOP_RELATIVE (src->data[i]);
+
+  memcpy (&dest->data[i], &src->data[i], numBytes - sizeof (OOP) * numPointers);
+
+  /* Do the heavy work on the objects now rather than at load time, in order
+     to make the loading faster.  In general, we should do this as little as
+     possible, because it's pretty hard: the three cases below for Process,
+     Semaphore and CallinProcess for example are just there to terminate all
+     CallinProcess objects.  */
+  if (class_oop == _gst_callin_process_class)
     {
-      instOOP = *i;
-      if (IS_OOP (instOOP))
- *i = OOP_RELATIVE (instOOP);
+      gst_process process = (gst_process) dest;
+      process->suspendedContext = OOP_RELATIVE (_gst_nil_oop);
+      process->nextLink = OOP_RELATIVE (_gst_nil_oop);
+      process->myList = OOP_RELATIVE (_gst_nil_oop);
     }
+
+  else if (class_oop == _gst_process_class)
+    {
+      /* Find the new next link.  */
+      gst_process destProcess = (gst_process) dest;
+      gst_process next = (gst_process) src;
+      while (OOP_CLASS (next->nextLink) == _gst_callin_process_class)
+ next = (gst_process) OOP_TO_OBJ (next->nextLink);
+
+      destProcess->nextLink = OOP_RELATIVE (next->nextLink);
+    }
+
+  else if (class_oop == _gst_semaphore_class)
+    {
+      /* Find the new first and last link.  */
+      gst_semaphore destSem = (gst_semaphore) dest;
+      gst_semaphore srcSem = (gst_semaphore) src;
+      OOP firstOOP = _gst_nil_oop, lastOOP = _gst_nil_oop;
+      OOP linkOOP = srcSem->firstLink;
+      while (!IS_NIL (linkOOP))
+ {
+  gst_process process = (gst_process) OOP_TO_OBJ (linkOOP);
+  if (process->objClass != _gst_callin_process_class)
+    {
+      if (IS_NIL (firstOOP))
+ firstOOP = linkOOP;
+      lastOOP = linkOOP;
+    }
+  linkOOP = process->nextLink;
+ }
+
+      destSem->firstLink = OOP_RELATIVE (firstOOP);
+      destSem->lastLink = OOP_RELATIVE (lastOOP);
+    }
+
+  /* The other case is to reset CFunctionDescriptor objects, so that we'll
+     relink the external functions when we reload the image.  */
+  else if (class_oop == _gst_c_func_descriptor_class)
+    {
+      gst_cfunc_descriptor desc = (gst_cfunc_descriptor) dest;
+      desc->cFunction = OOP_RELATIVE (_gst_nil_oop);
+    }
+
 }
 
 void



* no log found, creating one automatically
* (Use "tla make-log" to create a log file.)
Vim: Error reading input, exiting...
Vim: Finished.


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: faster startup 2/n

Mike Anderson-3
Paolo Bonzini wrote:
> A slightly trickier one.  If we don't save directly from the object
> area, but allocate temporary memory for that, we can save different data
> than what is in the object memory.  So, we can kill CallinProcesses when
> saving, and we can force looking up CFunctionDescriptor addresses the
> first time they are called.  Finally, we can map the interpreter's
> primitives to what is in the image, rather than patch the
> CompiledMethods so that they match the primitive numbers that were
> selected at compile time.

It seems to me that this has other benefits than just speed; making it
easier to re-load images that link with C libraries.

Is it necessarily correct to kill a call-in process, though? Say the
process in question was a GUI event that triggered a long-running
calculation. There wouldn't be anywhere to return a result to, but it
would be the side-effects (displaying the results in the GUI) that were
important.

I'm interested because I'm still interested in the idea of persistent
Smalltalk images, although I've changed direction slightly from the gsti
idea. It would be useful to have a clear idea of what the contract is
for an image restart.

Mike


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: faster startup 2/n

Paolo Bonzini

> It seems to me that this has other benefits than just speed; making it
> easier to re-load images that link with C libraries.

Note that this has not changed the behavior; it simply moved things from
load-time to save-time.  See the init_dictionary_on_image_load diffs.

> Is it necessarily correct to kill a call-in process, though? Say the
> process in question was a GUI event that triggered a long-running
> calculation. There wouldn't be anywhere to return a result to, but it
> would be the side-effects (displaying the results in the GUI) that were
> important.

I would do this in a separate process.  The fact that call-ins are a
separate process is an implementation detail (see a recent post by Eliot
Miranda in comp.lang.smalltalk about how call-ins are handled in
VisualWorks -- note that this part of the GNU Smalltalk design was done
without knowing how VW does it).

Paolo


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk