[Pharo-dev] [Reflectivity] Support for primitive methods

Marcus Denker marcus.denker at inria.fr
Thu Sep 17 02:58:10 EDT 2015


Hi,

One thing I added over the last weeks: support to put links on primitives.

1) fail code. You can put links into the smalltalk code that is executed in case of primitive failure.
    For all primitive methods, we generate code immediately when setting the link, we do not wait
    till the method is called. (this is in there since a while).

2) links on the method node itself. What we do here is to wrap the original method.

It is interesting how simple this was to do:

1) when generating code for a ReflectiveMethod, check if it is a primitive:

compileAndInstallCompiledMethod
	"we install the old one as the compiler might need it”
	self installCompiledMethod.
	compiledMethod isRealPrimitive ifTrue: [ self generatePrimitiveWrapper ].
	self recompileAST.
	self installCompiledMethod.


2) compile a wrapper by building an AST by hand:

generatePrimitiveWrapper
	| wrappedMethod send wrapperMethod |
	ast compilationContext 
		semanticAnalyzerClass: RFSemanticAnalyzer;
		astTranslatorClass: RFASTTranslator.
	ast doSemanticAnalysis. "force semantic analysis"
	wrappedMethod := ast generate: compiledMethod trailer.
	
	send := RBMessageNode
		receiver: (RBLiteralNode value: wrappedMethod)
		selector:  #valueWithReceiver:arguments: 
		arguments: {RBVariableNode named: #self . RBArrayNode statements: ast variableNodes }.
	
	wrapperMethod := RBMethodNode
		selector: ast selector
		arguments: ast variableNodes 
		body: (RBReturnNode value: send) asSequenceNode.
		
	wrapperMethod methodClass: ast methodClass.
	wrapperMethod propertyAt: #wrappedPrimitive put: true.
	ast hasMetalink ifTrue: [wrapperMethod propertyAt: #links put: (ast propertyAt: #links)].
	ast := wrapperMethod.

This means we copy over the links to the new wrapper. the #wrappedPrimitive marker is there so that,
when we destroy the twin when the last link is removed, we remember to unwrap.

3) the compiler plugin that takes the links into account ignores links on MethodNode if it’s a primitive.

4) when getting rid of the Twin (because we remove the last link), we detect if it was a primitive and unwrap:

destroyTwin
	(ast hasProperty: #wrappedPrimitive) ifTrue: [  ast :=  compiledMethod parseTree].
	self recompileAST.
	self installCompiledMethod.
	compiledMethod reflectiveMethod: nil.
	SystemAnnouncer uniqueInstance unsubscribe: self

e.g.

testBeforeMethodPrimitive
	| methodNode link |
	methodNode := (ReflectivityExamples >> #examplePrimitiveMethod) ast.
	link := MetaLink new
		metaObject: self;
		selector: #tagExec.
	self assert: (ReflectivityExamples>>#examplePrimitiveMethod) isRealPrimitive.	
	methodNode link: link.
	self assert: methodNode hasMetalink.
	self assert: (ReflectivityExamples >> #examplePrimitiveMethod) class = CompiledMethod.
	self assert: tag isNil.
	self assert: ReflectivityExamples new examplePrimitiveMethod class = ByteString.
	self deny: (ReflectivityExamples>>#examplePrimitiveMethod) isRealPrimitive.	
	self assert: tag = #yes.
	self assert: (ReflectivityExamples >> #examplePrimitiveMethod) class = CompiledMethod.
	link uninstall.
	self assert: (ReflectivityExamples>>#examplePrimitiveMethod) isRealPrimitive.	
	ReflectivityExamples recompile: #examplePrimitiveMethod


Marcus








More information about the Pharo-dev mailing list