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 <bonzini gnu.org>
* 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 %dn",
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.)
[J[J[J[J[J[J[24;1HVim: Error reading input,
exiting...
Vim: Finished.
[24;1H
_______________________________________________
help-smalltalk mailing list
help-smalltalk gnu.org
http://lists.gnu.org/mailman/listinfo/help-smalltalk
|