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

Marcus Denker marcus.denker at inria.fr
Wed Nov 28 15:59:31 UTC 2018



> On 23 Nov 2018, at 20:01, Eliot Miranda <eliot.miranda at gmail.com> wrote:
> 
> 
> 
>> On Nov 22, 2018, at 2:51 PM, Levente Uzonyi <leves at caesar.elte.hu> wrote:
>> 
>> Hi Chris,
>> 
>> I think it should work the other way around. When you want to be able to use proxies everywhere (which can't work btw, because everywhere is just too vague), there should be a switch - a preference with an action - that recompiles all methods with the #== and #class bytescodes disabled except for those methods which have a special pragma preventing such deoptimization.

#class does never use the special send, I think #== still does as using it does not do an interrupt check, while it would if it would be a message send it would, which can have very bad side effects especially in 
the code for process scheduling…

For compiler pragmas, in Opal we added pragmas, e.g. to turn on #repeat inlining, which is off by default for backward compatibility:

exampleRepeatEffect
	<compilerOptions: #(#+ #optionInlineRepeat)>
	| i |
	i := 1.
	[ 
	i := i + 1.
	i = 10
		ifTrue: [ ^ true ] ] repeat

this can be set per class, too. For example, it was hard-coded deep the compiler that InstructionStream ivar access is compiled specially for Cog. This is now done by overriding #compiler on the class side:

compiler
	"The JIT compiler needs to trap all reads to instance variables of contexts. As this check is costly, it is only done
	in the long form of the bytecodes, which are not used often. In this hierarchy we force the compiler to alwasy generate
	long bytecodes"
	^super compiler options: #(+ optionLongIvarAccessBytecodes)

> 
> +1 on the idea; there are a few implementation choices
> 
>> I'm surprised you didn't mention other special methods like #ifTrue:, #whileTrue:, #repeat:, #to:do:, etc. I think that's because you rarely create proxies for numbers, booleans and blocks.
> 
> +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):

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

	| sendNode methodNode method ret |

	"get the message send node that triggered mustBeBoolean"
	sendNode := context sourceNode sourceNodeForPC: context pc - 1.

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

	"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: sendNode irInstruction nextBytecodeOffsetAfterJump.	
	^ret.


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?


	Marcus




More information about the Squeak-dev mailing list