Another silly primitive question
agree at carltonfields.com
agree at carltonfields.com
Wed Feb 17 17:49:25 UTC 1999
Stephen writes:
>A while back (in 2.2), I wrote some primitives that allowed me to allocate
and free external blocks of memory (using standard malloc and free). I was
doing that in an attempt to create a generic mechanism for calling out to
external functions (using any of several well known calling
conventions)...which I was doing to implement a framework for abstracting OS
platform specifics. I too needed to guarantee the location of the memory
wouldn't change underneath me. I then created a nice Smalltalk class to
wrapper the blocks of external memory. It was very elegant to have this
ability to manage external memory using Smalltalk objects. The only thing
lacking was a finalization capability in 2.2 (so memory was never freed, but
I was waiting for others to add the finalization).
That would, indeed, be a useful thing.
> Getting the memory from the operating system is likely a lot safer and
easier that trying to "steal" it from Squeak heaps. My guess is fiddling
with Squeak heaps would tricky and dangerous.
Right -- I don't suggest messing with the heaps. Rather, if you are writing
some code that needs memory for, say a stringbuffer or the like, you can
accomplish this result by asking interpreterProxy to instantiate a String or a
ByteArray for you, and access it from C using the C array access facilities.
Alternatively, the ByteArray can be created by the calling routine and passed
either as a parameter or an instance variable. The downside of this is that
the block of memory, though it will survive garbage collections since it is
pointed to by the Smalltalk references, will be moved in memory from time to
time, so every C procedure must access the block of memory through the
parameter or instance variable, and not by hard addresses, and hard addresses
should not be stored in the array itself.
This works just great in conjunction with the pluggable primitives where the
smalltalk/C language interface is effectively seamless (I'm writing a short
article on the subject now, and have put a brief piece on pluggables up on the
Swiki), particularly for things like returning and manipulating strings and
the like, but it won't suit all purposes.
> I stopped work on this stuff once I heard that pluggable primitives were
being added (sounds like I had a similar experience to Chris Reuter). Has
anyone tried the pluggable primitives? How well does it work? Is good
support for marshaling objects to and from external data types?
PP's work GREAT! Contrary to the suggestion earlier, I find them
straightforward to work with and fun to code. The problem, of course, is that
they are almost undocumented as a feature -- I intend to help remedy that
problem. In answer to your question, its relatively straightforward to get
access to objects in a pluggable, to the extent permitted by the
interpreterProxy facility.
In short, you can get and manipulate an object reference; you can get and
manipulate instance variables from the object; and you can get and manipulate
the array elements at a byte, word or other level. There is support for
conversion between some basic types, and that's about it -- but its plenty for
you to build whatever else you might need.
Additionally, you can, of course, manipulate the calling stack (to handle
parameters and return a value), and obtain access to some basic Smalltalk
services -- such as to instantiate objects to which you have a pointer (some
basic objects already are provided).
Facilities are provided to make the access to arrays, for example, ABSOLUTELY
SEAMLESS (including the fact that Smalltalk arrays start at 1, and C arrays
start at 0), so that you can code almost all of what you need in Smalltalk and
have it translate correctly to C. In short, you take your object "handle",
ask the interpreterProxy to give you the pointer to the object in array form
(its a void *) to C, and a CArrayAccess (or something like that), coerce the
sucker to whatever you need, and reach the array either in C or in Smalltalk
without another thought. If you need to send that data structure back to
smalltalk, use the object "handle" and you're done!
However, all of this presupposes that you are writing the primitive while
aware you are dealing with a smalltalk interpreter. Consider the application
with which I am presently playing around -- interfacing GNU's rx (regular
expression) library to squeak:
No problem with respect to the wrapper or the interface: it was
straightforward to build an rxPlugin and an interface to the main Posix
functions, and the code I have even compiles and searches literal regular
expressions correctly and with great speed. The problem is that when the
library calls malloc (as most third party libraries are wont to do), things go
crunch in the night. We need to be able to provide such a plugin with memory
of the "traditional C heap" variety, and not access to floating blocks as
described above.
Please tell me more about your primitive. Does using malloc and free from
within Smalltalk interfere with the Smalltalk memory management -- if not, its
a straightforward solution and (I might suggest) a basic and essential one
that the interpreterProxy arguably ought to provide to the PrimitivePlugin
world to avoid perpetual reinventing of the wheel.
PP's are PERFECT for speeding up hunks of Smalltalk code; and they are great
for providing interfaces to native system resources. It would be nice to be
able to build plugIns to generally portable open source libraries such as rx.
However, to do so, we need to provide some kind of memory management facility
to those libraries.
What do you think?
More information about the Squeak-dev
mailing list
|