Smalltalk code generation

Marcus Denker denker at iam.unibe.ch
Sat Oct 8 08:19:58 UTC 2005


Am 08.10.2005 um 05:47 schrieb Mariano Montone:

> Hi Alexandre, sorry for not answering before, I hadn't noticed the  
> message.
>
> The problem is that I have a code generation visitor traversing the  
> AST. I need to generate different parts of the method from  
> different methods of the visitor. I don't see how your approach may  
> fit, that's why I need to implement it this way.
>

Yes, then you don't want to deal with text, for sure. One way to do  
it is to visit your AST and build up a refactoring browser AST. The  
new compiler
(see project NewCompiler on SqueakSource) then can generate bytecode  
from that. (Or you can use the standard Squeak AST for that, but
this is far from fun to use...)

Another way to do it is to reuse just the back-end of the new compiler:
Generate directly bytecode from your AST. This saved you from doing  
the conversion to the Squeak AST, thus it's faster and you are not bound
to Smalltalk semantics, that is, you can encode controlflow with  
jumps directly as you like, thus generating quite nice code for your  
language.

The backend is IRBuilder: It's a kind of a "symbolic assembler" for  
Squeak Bytecode.

Here's a simple example:

     iRMethod := IRBuilder new
         numRargs: 1;
         addTemps: #(self);        "receiver and args declarations"
         pushLiteral: 1;
         returnTop;
         ir.
         aCompiledMethod := iRMethod compiledMethod.

So for your AST visitor, you make one IRBuilder, put it in an instVar  
of the visitor and then just call methods on it while
traversing the tree. IRBuilder has support for symbolic jumps, a test  
showing this:

     ir := IRBuilder new
         numRargs: 2;
         addTemps: #(self a z);        "rcvr, arg, & extra temp (not  
used here)"
         pushTemp: #self;
         pushInstVar: 2;
         pushTemp: #a;
         send: #>;
         jumpAheadTo: #else if: false;
         pushLiteral: 'yes';
         returnTop;
         jumpAheadTarget: #else;
         pushLiteral: 'no';
         returnTop;
         ir.
         cm := ir compiledMethod.
         self assert: (cm isKindOf: CompiledMethod).
         self assert: (cm valueWithReceiver: self arguments: #(1)) =  
'yes' .
         self assert: (cm valueWithReceiver: self arguments: #(3)) =  
'no' .
         ^cm

There are some examples in the IRBuilderTest method (e.g. for how to  
do blocks).

Of course there are downsides: For a complete system you need to take  
care of debugging (a it more difficult,
but it should be doable. The debugger just needs a mapping bytecode-- 
 >text that your compiler/decompiler need to
build up). And you need to keep in mind that the code generated will  
not be decompilable by the smalltalk decompiler,
If you need a decompiler, then do your own that then will decompile  
directly to your AST.

One problem: It's not yet all to easy to get it in installed,  the  
new compiler requires the
latest 3.9a with AST and methodAnnotations (from http:// 
www.iam.unibe.ch/~denker/temp/CMAnnotations.zip).
This will be fixed soon.


     Marcus



More information about the Squeak-dev mailing list