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 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