|
|
4.4 Manipulating Smalltalk data from C
GNU Smalltalk internally maps every object except Integers to a data
structure named an OOP (which is not an acronym for anything, as
far as I know). An OOP is a pointer to an internal data structure;
this data structure basically adds a level of indirection in the
representation of objects, since it contains
-
a pointer to the actual object data
-
a bunch of flags, most of which interest the garbage collection process
This additional level of indirection makes garbage collection very
efficient, since the collector is free to move an object in memory
without updating every reference to that object in the heap, thereby
keeping the heap fully compact and allowing very fast allocation of
new objects. However, it makes C code that wants to deal with objects
even more messy than it would be without; if you want some examples,
look at the hairy code in GNU Smalltalk that deals with processes.
To shield you as much as possible from the complications of doing
object-oriented programming in a non-object-oriented environment like
C, GNU Smalltalk provides friendly functions to map between common Smalltalk
objects and C types. This way you can simply declare OOP variables and
then use these functions to treat their contents like C data.
These functions are passed to a module via the VMProxy struct
a pointer to which is passed to the module, as shown in
Linking your libraries to the virtual machine.
They can be divided in two groups, those that map
from Smalltalk objects to C data types and those
that map from C data types to Smalltalk objects.
Here are those in the former group (Smalltalk to C); you can see that
they all begin with OOPTo :
- Function: long OOPToInt (OOP)
- This function assumes that the passed OOP is an Integer and returns the
C
signed long for that integer.
- Function: long OOPToId (OOP)
- This function returns an unique identifier for the given OOP, valid
until the OOP is garbage-collected.
- Function: double OOPToFloat (OOP)
- This function assumes that the passed OOP is an Float and returns the
C
double for that integer.
- Function: int OOPToBool (OOP)
- This function returns a C integer which is true (i.e.
!= 0 ) if
the given OOP is the true object, false (i.e. == 0 ) otherwise.
- Function: char OOPToChar (OOP)
- This function assumes that the passed OOP is a Character and returns the
C
char for that integer.
- Function: char *OOPToString (OOP)
- This function assumes that the passed OOP is a String or ByteArray and
returns a C null-terminated
char * with the same contents. It is
the caller's responsibility to free the pointer and to handle possible
`NUL' characters inside the Smalltalk object.
- Function: char *OOPToByteArray (OOP)
- This function assumes that the passed OOP is a String or ByteArray and
returns a C
char * with the same contents, without null-terminating
it. It is the caller's responsibility to free the pointer.
- Function: voidPtr OOPToCObject (OOP)
- This functions assumes that the passed OOP is a kind of CObject and
returns a C
voidPtr to the C data pointed to by the object. The
caller should not free the pointer, nor assume anything about its
size and contents, unless it exactly knows what it's doing. A
voidPtr is a void * if supported, or otherwise a char * .
- Function: long OOPToC (OOP)
- This functions assumes that the passed OOP is a String, a ByteArray, a
CObject, or a built-in object (nil, true, false, character, integer).
If the OOP is nil, it answers 0; else the mapping for each object is
exactly the same as for the above functions. Note that, even though the
function is declared as returning a
long , you might need to cast
it to either a char * or voidPtr .
While special care is needed to use the functions above (you will probably
want to know at least the type of the Smalltalk object you're converting),
the functions below, which convert C data to Smalltalk objects, are easier
to use and also put objects in the incubator so that they are not swept by a
garbage collection (see section 4.9 Incubator support). These functions all end with
ToOOP , except cObjectToTypedOOP :
- Function: OOP intToOOP (long)
- This object returns a Smalltalk Integer which contains the same value as
the passed C
long . Note that Smalltalk Integers are always signed and
have a bit less of precision with respect to C longs. On 32 bit machines,
their precision is 30 bits (if unsigned) or 31 bits (if signed); on 64 bit
machines, their precision is 62 bits (if unsigned) or 63 bits (if signed).
- Function: OOP idToOOP (OOP)
- This function returns an OOP from a unique identifier returned by
OOPToId . The OOP will be the same that was passed to
OOPToId only if the original OOP has not been garbage-collected
since the call to OOPToId .
- Function: OOP floatToOOP (double)
- This object returns a Smalltalk Float which contains the same value as
the passed
double . Unlike Integers, Floats have exactly the same
precision as C doubles.
- Function: OOP boolToOOP (int)
- This object returns a Smalltalk Boolean which contains the same boolean value
as the passed C
int . That is, the returned OOP is the sole instance of
either False or True , depending on where the parameter is
zero or not.
- Function: OOP charToOOP (char)
- This object returns a Smalltalk Character which represents the same char
as the passed C
char .
- Function: OOP classNameToOOP (char *)
- This method returns the Smalltalk class (i.e. an instance of a subclass of
Class) whose name is the given parameter. This method is slow; you can
safely cache its result.
- Function: OOP stringToOOP (char *)
- This method returns a String which maps to the given null-terminated
C string, or the builtin object
nil if the parameter points to
address 0 (zero).
- Function: OOP byteArrayToOOP (char *, int)
- This method returns a ByteArray which maps to the bytes that the first
parameters points to; the second parameter gives the size of the ByteArray.
The builtin object
nil is returned if the first parameter points to
address 0 (zero).
- Function: OOP symbolToOOP (char *)
- This method returns a String which maps to the given null-terminated
C string, or the builtin object
nil if the parameter points to
address 0 (zero).
- Function: OOP cObjectToOOP (voidPtr)
- This method returns a CObject which maps to the given C pointer, or the
builtin object
nil if the parameter points to address 0 (zero).
The returned value has no precise CType assigned. To assign one, use
cObjectToTypedOOP .
- Function: OOP cObjectToTypedOOP (voidPtr, OOP)
- This method returns a CObject which maps to the given C pointer, or the
builtin object
nil if the parameter points to address 0 (zero).
The returned value has the second parameter as its type; to get possible
types you can use typeNameToOOP .
- Function: OOP typeNameToOOP (char *)
- All this method actually does is evaluating its parameter as Smalltalk
code; so you can, for example, use it in any of these ways:
| cIntType = typeNameToOOP("CIntType");
myOwnCStructType = typeNameToOOP("MyOwnCStruct type");
|
This method is primarily used by msgSendf (see section 4.5 Calls from C to Smalltalk), but
it can be useful if you use lower level call-in methods. This method is
slow too; you can safely cache its result.
As said above, the C to Smalltalk layer automatically puts the objects it
creates in the incubator which prevents objects from being collected as
garbage. A plugin, however, has limited control on the incubator, and
the incubator itself is not at all useful when objects should be kept
registered for a relatively long time, and whose lives in the registry
typically overlap.
To avoid garbage collection of such object, you can use these functions,
which access a separate registry:
- Function: void registerOOP (OOP)
- Puts the given OOP in the registry. If you register an object multiple times,
you will need to unregister it the same number of times. You may want to
register objects returned by Smalltalk call-ins.
- Function: void unregisterOOP (OOP)
- Remove an occurrence of the given OOP from the registry.
|