2009/12/21 Lukas Renggli <renggli@gmail.com>:
You might want to have a look at SmaCC and how it generates the scanner code: a huge state machine implemented in a single method that consumes the source code of a programming language. To compile the method SmaCC repeatedly applies the "extract method" refactoring to reduce the code into nicely sized (but still efficient) methods.
Lukas
Of course, that would have been a nice option too (more general). Above code is from 1994, not sure what was the status of SmaCC at that time... In case of symbolic expressions, more agressive transformation could occur, like common subexpression elimination... (run on symbolic expression tree rather than AST, because knowing there would be no side effect). Nicolas
2009/12/21 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
2009/12/20 Igor Stasenko <siguctua@gmail.com>:
2009/12/20 Marcus Denker <marcus.denker@inria.fr>:
On Dec 20, 2009, at 8:44 PM, Bart Gauquie wrote:
Dear all,
I'm developing code which generates a method content, compiles it and adds it to an existing class. I compile the message using #compile: message: for instance:
In general, everything is limited to a fairly low quantity: number of temps, number of ivars, number of literals.
Especially that the literal frame is limted to some small number (255 or something) can be easily be a problem. (we ran into that already when using bytesurgeon on large existing methods when reifying all sends, for example).
To get around this, place all literals into one (usually array): #( a b c d e ..... )
For instance, the above: Â self addMMEFrom: 1054@512 to: 1037@504. Â self addMMEFrom: 651@559 to: 643@579.
can be easily replaced by something like:
#( (1054 512 1037 504) Â Â ..... put as many as you want here.... no limit!!!
  (651 559 643 579) ) do: [:each | self addMMEFrom: (each first @ each second) to: (each third @ each fourth) ]
    Marcus _______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
-- Best regards, Igor Stasenko AKA sig.
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Hehe, when generating code for evaluating monster symbolic expressions, I bumped into many of these limitations. Using a literal Array was not enough because even the indices would consume a literal slot. So i had to decompose indices into operations... Â Oh, and even some message sends had to be transformed in #perform: sends (not shown here)... Here is a fragment of code for allocating a literal slot (in Objectworks, an ancestor of VW).
Nicolas
CodeStream subclass: #ExtendedCodeStream     instanceVariableNames: 'reduceLiterals'     classVariableNames: 'MaxLiteralIndex '     poolDictionaries: 'OpcodePool '     category: 'System-Compiler'
ExtendedCodeStream>>pushReducedConstant: lit     "Handle MaxLiteralsNumber"
    | classIndex newClassArray litIndex |     self push.     lit == nil         ifTrue:             [code nextPut: OpLoadNil.             ^self].     lit == true         ifTrue:             [code nextPut: OpLoadTrue.             ^self].     lit == false         ifTrue:             [code nextPut: OpLoadFalse.             ^self].     lit isInteger         ifTrue:             [(lit >= 0 and: [lit <= 2])                 ifTrue:                     [code nextPut: OpLoadZero + lit.                     ^self].             (lit >= 0 and: [lit <= 255])                 ifTrue:                     [code nextPut: OpLoadByte with: lit.                     ^self].             (lit >= -32768 and: [lit < 32768])                 ifTrue:                     [code                         nextPut: OpLoadTwoBytes                         with: ((lit bitShift: -8)                                 bitAnd: 255)                         with: (lit bitAnd: 255).                     ^self]].     ((lit isMemberOf: Character)         and: [lit asInteger between: 0 and: 255])         ifTrue:             [code nextPut: OpLoadCharacter with: lit asInteger.             ^self].     classIndex := literals at: lit class                 ifAbsent:                     ["Add the literal class array to the collection"                     literalCollection addLast: Array new.                     literals at: lit class put: literalCollection size - 1].     classIndex > MaxLiteralIndex         ifTrue:             [Errorscript cr; show: 'compilation failure: too many literal classes...'.             self class literalLimitSignal raiseWith: topNode body].     classIndex <= MaxLoadLiteral         ifTrue: [code nextPut: OpLoadLiteral + classIndex]         ifFalse: [code nextPut: OpXLoadLiteral with: classIndex].     newClassArray := literalCollection at: classIndex + 1.     litIndex := newClassArray indexOf: lit ifAbsent: [0].     litIndex = 0         ifTrue:             [newClassArray := newClassArray copyWith: lit.             literalCollection at: classIndex + 1 put: newClassArray.             litIndex := newClassArray size].     self pushBigIndex: litIndex.     self sendNoCheck: #at: numArgs: 1
ExtendedCodeStream>>pushBigIndex: index     "i do not want the index to figure in literalCollection     so it must remain < 32768"
    | q r |     index < 32768 ifTrue: [^self pushConstant: index].     q := index // 32768.     r := index - (q * 32768).     self pushConstant: 32767; pushConstant: 1; sendNoCheck: #+ numArgs: 1.     q = 1 ifFalse: [self pushBigIndex: q; sendNoCheck: #* numArgs: 1].     r = 0 ifFalse: [self pushConstant: r; sendNoCheck: #+ numArgs: 1].
ExtendedCodeStream>>pushStatic: binding     "Static variables do normally consume a literal slot.     Arrange to economize this precious ressource"
    reduceLiterals         ifTrue:             [self pushReducedConstant: binding.             self sendNoCheck: #value numArgs: 0]         ifFalse: [super pushStatic: binding]
ExtendedCodeStream>>pushConstant: lit     "Handle MaxLiteralsIndex"
    reduceLiterals ifTrue: [^self pushReducedConstant: lit].     super pushConstant: lit.
ExtendedCodeStream>>testLiteralsSize     "Restart compilation if literal limit is exceeded"
    literalCollection size > MaxLiteralIndex ifTrue: [reduceLiterals             ifTrue: [self class literalLimitSignal raiseWith: topNode body]             ifFalse: [self doReduceLiterals; restartCompilation]]
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
-- Lukas Renggli http://www.lukas-renggli.ch
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project