Automatic Generation of Glue for Named Primitives

Andrew C. Greenberg werdna at gate.net
Mon Sep 6 06:37:44 UTC 1999


>Andrew,
>
>This is neat stuff! I feel, however, that it is still kind of complicated to
>write code based on it since one still has to figure out what the
>specification must look like.

Agreed, I invite all to find ways to apply more usable sugar on top 
of this infrastructure.  My code was clearly a "path of least 
resistance" solution.

Indeed, I would much prefer the marshalling to be virtually 
automatic, and have actually suggested a number of similar approaches 
in the past.  My effort here was to create a reasonably 
straightforward knowledge base of the various glue approaches to 
date, and make them available in an automatic (i.e., less error 
prone) fashion.  I hope it will be of use to those getting started.

My druthers would be a facility for direct calls to C-language plugin 
code and supporting translation code, all without requiring the 
plugin to contain special purpose information.  Imagine if all we had 
to do to connect to an extant API was to code in Smalltalk!

>Have you considered using an approach similar
>to that of the translated primitives (e.g., like in String
>class>>translate:from:to:table:)?!

Of course, that would be quite sweet.  But presently, the assumptions 
implicit in the named example may be unnecessarily limiting.  For 
example, the string object contains more information than merely the 
pointer array -- i.e., a length.  And access to more complex objects 
from inside the C still appears desirable.  Until we REALLY know what 
the needs of the customers are, the named primitive structure is 
powerful, yet difficult to harness without a detailed understanding 
of the VM.

My goal in the code was to help begin to bridge that gap.

>I would love to actually start writing
>primitives by simply providing a small per-primitive specification such as
>
>MyPlugin>>mySmallIntegerAdd: arg1 arg2: arg2
>
>	self primitiveSpecification:
>		#(
>			SmallInteger			"Return type"
>			'mySmallIntegerAdd'		"The name of the
>primitive"
>			(SmallInteger SmallInteger) "Argument types"
>		).
>
>	^arg1 + arg2
>
>And then have the glue generated on the fly around the actual code (using
>the mechanisms you've introduced). This would be extremely helpful for the
>(most common) case of writing a few simple primitives while it would still
>allow one to use a more complex glue specification (which might be necessary
>for global variables) or even hand-code everything (by not using a glue-spec
>at all).

I like it, though I don't find the present approach:

glueSpecification

	^super glueSpecification
		primitive: 'mySmallIntegerAdd' on: nil returns: SmallInteger;
		parameter: arg1 as: SmallInteger;
		parameter: arg2 as: SmallInteger;
		code: #(result _ arg1 + arg2)

to appear much worse.  I considered using more concise array lists of 
type constants and symbol constants, choosing the present approach 
only because it was somewhat more flexible when I was debugging the 
thing into existence.  For example:

	^super glueSpecification
		primitive: 'mySmallIntegerAdd' returns SmallInteger;
		parms:	#( 'arg1' SmallInteger 'arg2' SmallInteger)
		code: 	#(result _ arg1 + arg2)

I went back and forth on the question, Many other alternatives seemed 
useful as well.  Other solutions, typically involving the writing of 
a parser were also considered as superior.  For now, I decided to 
simply concentrate on the guts of the "code generation," leaving the 
parsing to the system.

So, if its really just a question of syntactic sugar and a 
participating user interface and code generator to avoid the prim 
generation step, I'm all for it.

But I confess that Maloney has brought me around to appreciate the 
generality of the present approach.  Things start to get messy when 
you want to start manipulating the receiver or variable objects 
(whether pointers, bytes or words).  As Andreas noted, how would we 
handle globals?  [And don't forget the temporary variable limit, 
which is consumed very quickly for even a mildly complex prim!]  (For 
example, consider the approach in the PluginGenerator for, say, 
Arrays:  when we have a reference to foo, we generate THREE, not one 
variable:

	fooObj, the object pointer (there may be instance variables too!);
	fooSize, an integer representing the size;
	foo,  the buffer of foo objects.

Another approach, both simpler and harder in some respects, is to 
keep the interface trivial and require all the glue and marshalling 
to be done at the Smalltalk level, rather than in C.   But that can 
be very expensive as well.  Since we are using primitives sometimes 
as tools for speed in many cases (particularly those Andreas has 
used), high level gluing may be counterproductive.  (Consider the 
FlippyArray example in my code -- the FlippyArray when run through 
the interpreter was four times the price of a directly coded version 
in Smalltalk.  In turn, the compiled C-language plugin was twenty 
times faster than the directly coded version.))





More information about the Squeak-dev mailing list