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

Reply via email to