[squeak-dev] sends of #class and #== considered harmful, may we please stop?

Eliot Miranda eliot.miranda at gmail.com
Sat Dec 1 17:45:18 UTC 2018


Marcus,

> On Nov 30, 2018, at 4:21 AM, Marcus Denker <marcus.denker at inria.fr> wrote:
> 
> 
>>> 
>>> +1.  Again see Marcus’ super cool reification of inlined blocks in Pharo, even if it is slooooow :-)
>> 
>> Yes, it is very slow. The goal was more these two:
>> 
>> 1) do not loose the clever student in the first lecture. They do the “lets implement 3 value logic” and are *very* upset when they realise that the system is not as nice as they thought :-)
>> 2) understand the problem better
>> 
>> and of course, it is not much code. This is the full code (and it can be turned off by a setting):
>> 
> 
> ….
> 
>> So this means we do the compilation for every execution. I wonder if this could not be speed up by caching… maybe even one could do something similar at the JIT level?
>> 
> 
> I now implemented caching of the compiled DoIt. It adds a method property #mustBeBooleanCache which is a dictionary that stores the doit per pc.
> The cached method itself stores the pc after the jump. (#mustBeBooleanJump):
> 
> 
> mustBeBooleanDeOptimizeIn: context
>    "Permits to redefine methods inlined by compiler.
>    Take the ast node corresponding to the mustBeBoolean error, compile it on the fly and executes it as a DoIt. Then resume the execution of the context.
>    the generated DoIts are cached in the calling method"
> 
>    | ret cache method |
> 
>    cache := context method propertyAt: #mustBeBooleanCache ifAbsentPut: [ IdentityDictionary new ].
>    "compile a doit method for the unoptimized expression"
>    method := cache at: (context pc - 1) ifAbsent: [self mustBeBooleanCompileExpression: context andCache: cache ].
>    "Execute the generated method with the pc still at the optimzized block so that the lookUp can read variables defined in the optimized block"
>    ret := context receiver withArgs: {context} executeMethod: method.
>       "resume the context at the instruction following the send when returning from deoptimized code."
>         context pc: (method propertyAt: #mustBeBooleanJump).
>    ^ret.
> 
> 
> with the compilation done in this method:
> 
> mustBeBooleanCompileExpression: context andCache: cache
>    "Permits to redefine methods inlined by compiler.
>    Take the ast node corresponding to the mustBeBoolean error, compile it on the fly and executes it as a DoIt. Then resume the execution of the context."
> 
>    | sendNode methodNode pc method pcAfterJump |
> 
>    "get the message send node that triggered mustBeBoolean"
>    pc := context pc - 1.
>    sendNode := context sourceNode sourceNodeForPC: pc.
>    "Rewrite non-local returns to return to the correct context from send"
>    RBParseTreeRewriter new 
>        replace: '^ ``@value' with: 'ThisContext home return: ``@value';
>        executeTree: sendNode.
>    "Build doit node to perform send unoptimized"
>    methodNode := sendNode copy asDoitForContext: context.
>    "Keep same compilation context as the sender node's"
>    methodNode compilationContext: sendNode methodNode compilationContext copy.
>    "Disable inlining so the message send will be unoptimized"
>    methodNode compilationContext compilerOptions: #(- optionInlineIf optionInlineAndOr optionInlineWhile).
>    "Generate the method"    
>    OCASTSemanticCleaner clean: methodNode.
>    method := methodNode generate.
>    "store the pc of the instruction following the send when returning from deoptimized code."
>    pcAfterJump := sendNode irInstruction nextBytecodeOffsetAfterJump.
>    method propertyAt: #mustBeBooleanJump put: pcAfterJump.
>    "cache the method we just created"
>    cache at: pc put: method.
>    ^method
>    
> 
> seems lead to a factor 200 speedup for trivial examples. The “hot” code-path now just gets the method from the cache and executes it,
> so all the overhead of compilation.  And the mapping pc-AST is not needed at runtime.

Bravo! This (the entire scheme including caching) is worth writing up as an example of language extensibility in Smalltalk.  You might be able to get it accepted at SPLASH. Personally I love to see coherent use of reflection like this.  Elegant and powerful.

>    Marcus


More information about the Squeak-dev mailing list