From c8d5b5012b5b088da62d9bac84fa11f43c2e12b8 Mon Sep 17 00:00:00 2001 From: Marcus Denker Date: Mon, 26 Nov 2018 16:34:33 +0100 Subject: [PATCH] Make #value for work method #after https://pharo.fogbugz.com/f/cases/22695/Make-value-for-work-method-after --- .../ReflectivityControlTest.class.st | 18 +++++++++++++++++ .../ReflectivityExamples.class.st | 6 ++++++ .../ReflectivityReificationTest.class.st | 12 +++++------ src/Reflectivity/RFASTTranslator.class.st | 9 +++------ .../RFASTTranslatorForEffect.class.st | 3 +-- src/Reflectivity/RFSemanticAnalyzer.class.st | 1 + src/Reflectivity/RFValueReification.class.st | 3 +-- src/Reflectivity/ReflectiveMethod.class.st | 20 +++++++++++++++---- 8 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/Reflectivity-Tests/ReflectivityControlTest.class.st b/src/Reflectivity-Tests/ReflectivityControlTest.class.st index a745dea8c99..611ef27dc6f 100644 --- a/src/Reflectivity-Tests/ReflectivityControlTest.class.st +++ b/src/Reflectivity-Tests/ReflectivityControlTest.class.st @@ -196,6 +196,24 @@ ReflectivityControlTest >> testAfterMethod [ self assert: (ReflectivityExamples >> #exampleMethod) class equals: CompiledMethod ] +{ #category : #'tests - after' } +ReflectivityControlTest >> testAfterMethod2 [ + | methodNode instance | + methodNode := (ReflectivityExamples >> #exampleMethod2) ast. + link := MetaLink new + metaObject: self; + selector: #tagExec; + control: #after. + methodNode link: link. + self assert: methodNode hasMetalink. + self assert: (ReflectivityExamples >> #exampleMethod2) class equals: ReflectiveMethod. + self assert: tag isNil. + instance := ReflectivityExamples new. + self assert: instance exampleMethod2 equals: instance. + self assert: tag equals: #yes. + self assert: (ReflectivityExamples >> #exampleMethod2) class equals: CompiledMethod +] + { #category : #'tests - level' } ReflectivityControlTest >> testAfterMethodLevel [ | methodNode | diff --git a/src/Reflectivity-Tests/ReflectivityExamples.class.st b/src/Reflectivity-Tests/ReflectivityExamples.class.st index 25d89e44a21..b66f1b5aea5 100644 --- a/src/Reflectivity-Tests/ReflectivityExamples.class.st +++ b/src/Reflectivity-Tests/ReflectivityExamples.class.st @@ -107,6 +107,12 @@ ReflectivityExamples >> exampleMethod [ ^ 2 + 3 ] +{ #category : #examples } +ReflectivityExamples >> exampleMethod2 [ + + 2 + 3 +] + { #category : #examples } ReflectivityExamples >> exampleMethodMultipleSites [ Transcript show: Object new. diff --git a/src/Reflectivity-Tests/ReflectivityReificationTest.class.st b/src/Reflectivity-Tests/ReflectivityReificationTest.class.st index a60020813a8..2d2e97aa9a9 100644 --- a/src/Reflectivity-Tests/ReflectivityReificationTest.class.st +++ b/src/Reflectivity-Tests/ReflectivityReificationTest.class.st @@ -872,24 +872,22 @@ ReflectivityReificationTest >> testReifyMethodThisContextAfter [ { #category : #'tests - method' } ReflectivityReificationTest >> testReifyMethodValue [ - | sendNode instance | - "not working yet. Need to somehow access return value of whole method" - self skip. - sendNode := (ReflectivityExamples >> #exampleMethod) ast. + | methodNode instance | + methodNode := (ReflectivityExamples >> #exampleMethod) ast. link := MetaLink new metaObject: self; selector: #tagExec:; control: #after; arguments: #(value). - sendNode link: link. - self assert: sendNode hasMetalink. + methodNode link: link. + self assert: methodNode hasMetalink. self assert: (ReflectivityExamples >> #exampleMethod) class equals: ReflectiveMethod. self assert: tag isNil. instance := ReflectivityExamples new. self assert: instance exampleMethod equals: 5. - self assert: tag equals: #exampleMethod + self assert: tag equals: 5 ] { #category : #'tests - assignment' } diff --git a/src/Reflectivity/RFASTTranslator.class.st b/src/Reflectivity/RFASTTranslator.class.st index b47f41695ac..0d576c940f0 100644 --- a/src/Reflectivity/RFASTTranslator.class.st +++ b/src/Reflectivity/RFASTTranslator.class.st @@ -24,7 +24,6 @@ RFASTTranslator >> emitMessageNode: aMessageNode [ ifFalse: [ valueTranslator visitNode: aMessageNode receiver ]. aMessageNode arguments do: [ :each | valueTranslator visitNode: each ]. self emitPreamble: aMessageNode. - self emitPrepareLinkAfter: aMessageNode. self emitMetaLinkBefore: aMessageNode. aMessageNode hasMetalinkInstead ifTrue: [ self emitMetaLinkInstead: aMessageNode ] @@ -32,7 +31,7 @@ RFASTTranslator >> emitMessageNode: aMessageNode [ aMessageNode isSuperSend ifTrue: [ methodBuilder send: aMessageNode selector toSuperOf: self compilationContext getClass ] ifFalse: [ methodBuilder send: aMessageNode selector ] ]. - self emitMetaLinkAfter: aMessageNode. + self emitMetaLinkAfterNoEnsure: aMessageNode. ] { #category : #reflectivity } @@ -239,8 +238,6 @@ RFASTTranslator >> visitMethodNode: aMethodNode [ aMethodNode pragmas do: [:each | self visitPragmaNode: each]. methodBuilder numArgs: aMethodNode arguments size. - self emitPrepareLinkAfter: aMethodNode. - (aMethodNode hasMetalinkInstead and: [ aMethodNode isPrimitive not ]) ifTrue: [ self emitMetaLinkInstead: aMethodNode. methodBuilder returnTop. ^self. ]. @@ -251,9 +248,9 @@ RFASTTranslator >> visitMethodNode: aMethodNode [ withVars: (aMethodNode scope tempVector collect: [:each| each name]) asArray. ]. effectTranslator visitNode: aMethodNode body. + aMethodNode isPrimitive ifFalse: [self emitMetaLinkAfterNoEnsure: aMethodNode]. + (aMethodNode hasProperty: #wrappedPrimitive) ifTrue: [methodBuilder pushTemp: #RFValueReificationVar; returnTop]. aMethodNode body lastIsReturn ifFalse: [methodBuilder pushReceiver; returnTop]. - self emitMetaLinkAfter: aMethodNode. - aMethodNode hasMetalinkAfter ifTrue: [methodBuilder returnTop]. ] diff --git a/src/Reflectivity/RFASTTranslatorForEffect.class.st b/src/Reflectivity/RFASTTranslatorForEffect.class.st index bacd712f730..65fb4d6de7a 100644 --- a/src/Reflectivity/RFASTTranslatorForEffect.class.st +++ b/src/Reflectivity/RFASTTranslatorForEffect.class.st @@ -129,7 +129,6 @@ RFASTTranslatorForEffect >> visitVariableNode: aVariableNode [ self emitPreamble: aVariableNode. self emitMetaLinkBefore: aVariableNode. - self emitPrepareLinkAfter: aVariableNode. aVariableNode hasMetalinkInstead ifTrue: [ self emitMetaLinkInstead: aVariableNode ]. @@ -139,6 +138,6 @@ RFASTTranslatorForEffect >> visitVariableNode: aVariableNode [ (binding isLiteralVariable or: [ binding isUndeclared ]) ifTrue: [ methodBuilder addLiteral: binding assoc ]. - self emitMetaLinkAfter: aVariableNode. + self emitMetaLinkAfterNoEnsure: aVariableNode. ] diff --git a/src/Reflectivity/RFSemanticAnalyzer.class.st b/src/Reflectivity/RFSemanticAnalyzer.class.st index a0d8335e88e..a45e42f9a6d 100644 --- a/src/Reflectivity/RFSemanticAnalyzer.class.st +++ b/src/Reflectivity/RFSemanticAnalyzer.class.st @@ -72,6 +72,7 @@ RFSemanticAnalyzer >> visitMethodNode: aMethodNode [ aMethodNode scope: scope. scope node: aMethodNode. aMethodNode arguments do: [:node | self declareArgumentNode: node ]. aMethodNode pragmas do: [:each | self visitNode: each]. + self declareVariableNode: (RBVariableNode named: #RFValueReificationVar). self analyseForLinksForNodes: aMethodNode. self visitNode: aMethodNode body. diff --git a/src/Reflectivity/RFValueReification.class.st b/src/Reflectivity/RFValueReification.class.st index 8cde55fbb5e..c4feaca5cf4 100644 --- a/src/Reflectivity/RFValueReification.class.st +++ b/src/Reflectivity/RFValueReification.class.st @@ -71,7 +71,7 @@ RFValueReification >> genForRBMessageNode [ { #category : #generate } RFValueReification >> genForRBMethodNode [ - ^RBVariableNode named: #RFReifyValueVar + ^RBTemporaryNode named: #RFValueReificationVar ] { #category : #generate } @@ -88,7 +88,6 @@ RFValueReification >> genForRBVariableNode [ { #category : #generate } RFValueReification >> postamble: aNode [ (aNode isKindOf: RBProgramNode) ifFalse: [ ^#() ]. - aNode isMethod ifTrue: [^RFStoreIntoTempNode named: 'RFReifyValueVar'. ]. aNode isMessage ifTrue: [^RFStoreIntoTempNode named: 'RFReifyValueVar'. ]. ^super postamble: aNode. diff --git a/src/Reflectivity/ReflectiveMethod.class.st b/src/Reflectivity/ReflectiveMethod.class.st index 23f877ee924..079d51cdfbb 100644 --- a/src/Reflectivity/ReflectiveMethod.class.st +++ b/src/Reflectivity/ReflectiveMethod.class.st @@ -34,9 +34,9 @@ ReflectiveMethod >> ast [ { #category : #evaluation } ReflectiveMethod >> compileAndInstallCompiledMethod [ - (compiledMethod isRealPrimitive and: [ast hasMetalink]) ifTrue: [ self generatePrimitiveWrapper ]. + self wrapperNeeded ifTrue: [ self generatePrimitiveWrapper ]. self recompileAST. - self installCompiledMethod. + self installCompiledMethod. ] { #category : #accessing } @@ -90,7 +90,7 @@ ReflectiveMethod >> flushCache [ { #category : #evaluation } ReflectiveMethod >> generatePrimitiveWrapper [ - | wrappedMethod send wrapperMethod | + | wrappedMethod send wrapperMethod assignmentNode | OCASTSemanticCleaner clean: ast. ast compilationContext semanticAnalyzerClass: RFSemanticAnalyzer; @@ -103,10 +103,14 @@ ReflectiveMethod >> generatePrimitiveWrapper [ selector: #rFwithArgs:executeMethod: arguments: {RBArrayNode statements: ast arguments . (RFLiteralVariableNode value: wrappedMethod)}. + assignmentNode := RBAssignmentNode + variable: (RBVariableNode named: #RFValueReificationVar) + value: send. + wrapperMethod := RBMethodNode selector: ast selector arguments: ast arguments - body: (RBReturnNode value: send) asSequenceNode. + body: assignmentNode asSequenceNode. wrapperMethod methodClass: ast methodClass. wrapperMethod propertyAt: #wrappedPrimitive put: true. @@ -330,3 +334,11 @@ ReflectiveMethod >> spotterPreviewCodeIn: aComposite [ ReflectiveMethod >> spotterSelectFor: aStep [ self compiledMethod spotterSelectFor: aStep ] + +{ #category : #evaluation } +ReflectiveMethod >> wrapperNeeded [ + ast hasMetalink ifFalse: [ ^false ]. + compiledMethod isRealPrimitive ifTrue: [ ^true ]. + ast hasMetalinkAfter ifTrue: [ ^true ]. + ^false. +]