That performance regression looks more like a language implementation bug that a problem of the language itself. If we assume that #do: and some other selectors (e.g. #select, #reject) should always receive a block instead of a symbol, then the compiler could perfectly replace the symbol literal for an already instantiated block literal transparently from the user perspective. If the compiler does that we can save the bytecode for instantiating the block closure, which can save a potential roundtrip to the garbage collector. I guess (I am just speculating) that this performance overhead must be in the implementation of the #perform: primitive, which I guess has to:
1) go through the JIT stack into the C stack transition (saving/restoring interpreter/JIT state, additional pressure, and primitive activation overhead.
2) the lack of inline caches for #perform: (again, I am just guessing in this case).
Note that the OpalCompiler is currently inlining some methods such as #ifTrue:ifFalse: ,�� #ifNil:ifNotNil: #and: #or: and there are not actual message sends, so adding an additional list of selector where literal symbol arguments are synthesized as blocks is not different to the cheating that the current compiler is doing. If an user wants to disable this inlining, there is currently a pragma for telling the compiler.
Do you want me to propose an experimental patch for testing this infrastructure?
Best regards,
Ronie