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 <[email protected]>: > 2009/12/20 Igor Stasenko <[email protected]>: >> 2009/12/20 Marcus Denker <[email protected]>: >>> >>> 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: 1...@512 to: 1...@504. >> self addMMEFrom: 6...@559 to: 6...@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 >>> [email protected] >>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project >>> >> >> >> >> -- >> Best regards, >> Igor Stasenko AKA sig. >> >> _______________________________________________ >> Pharo-project mailing list >> [email protected] >> 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 > [email protected] > http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project > -- Lukas Renggli http://www.lukas-renggli.ch _______________________________________________ Pharo-project mailing list [email protected] http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
