Skip to content

Commit 77eebdc

Browse files
committed
- The deactivator is now an object and not a block. This is to have a cleaner approach.
- Now obtaining the temp variables in the deactivator by index and not by name. The indeces are stored in class variables for better understanding of the code. - Added tests to tests that the deactivator not to send value and that the after is executed besided the exception.
1 parent e2e41d8 commit 77eebdc

13 files changed

+222
-68
lines changed

src/MethodProxies-Tests/MpArgumentListTestHandler.class.st

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,19 @@ Class {
33
#superclass : 'MpHandler',
44
#instVars : [
55
'beforeArgs',
6-
'afterArgs'
6+
'afterArgs',
7+
'unwound'
78
],
89
#category : 'MethodProxies-Tests',
910
#package : 'MethodProxies-Tests'
1011
}
1112

13+
{ #category : 'evaluating' }
14+
MpArgumentListTestHandler >> aboutToReturnWithReceiver: receiver arguments: arguments [
15+
16+
unwound := true
17+
]
18+
1219
{ #category : 'accessing' }
1320
MpArgumentListTestHandler >> afterArgs [
1421

@@ -33,3 +40,15 @@ MpArgumentListTestHandler >> beforeExecutionWithReceiver: anObject arguments: an
3340

3441
beforeArgs := anArrayOfObjects
3542
]
43+
44+
{ #category : 'accessing' }
45+
MpArgumentListTestHandler >> unwound [
46+
47+
^ unwound
48+
]
49+
50+
{ #category : 'accessing' }
51+
MpArgumentListTestHandler >> unwound: anObject [
52+
53+
unwound := anObject
54+
]

src/MethodProxies-Tests/MpClassA.class.st

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ MpClassA >> methodWithArgumentOne: anInteger argumentTwo: anInteger2 [
5656
^ self x
5757
]
5858

59+
{ #category : 'debugging' }
60+
MpClassA >> methodWithArgumentOne: anInteger argumentTwo: anInteger2 argThree: arg3 [
61+
62+
1 error
63+
]
64+
5965
{ #category : 'debugging' }
6066
MpClassA >> methodWithException [
6167

@@ -68,6 +74,12 @@ MpClassA >> methodWithNonLocalReturn [
6874
self methodAcceptingABlock: [ ^ self ]
6975
]
7076

77+
{ #category : 'debugging' }
78+
MpClassA >> methodWithNonResumableError [
79+
80+
1 error
81+
]
82+
7183
{ #category : 'debugging' }
7284
MpClassA >> methodWithWarning [
7385

src/MethodProxies-Tests/MpMethodProxyTest.class.st

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,20 @@ MpMethodProxyTest >> handlerClass [
3030
^ MpHandler
3131
]
3232

33+
{ #category : 'tests - safety' }
34+
MpMethodProxyTest >> testAfterMethodGetsExecutedBesidesOfExceptioon [
35+
36+
| mp handler |
37+
mp := MpMethodProxy
38+
onMethod: MpClassA >> #methodWithNonResumableError
39+
handler: (handler := MpAfterCounterHandler new).
40+
41+
self installMethodProxy: mp.
42+
43+
self should: [ MpClassA new methodWithNonResumableError ] raise: Error.
44+
self assert: handler count equals: 1
45+
]
46+
3347
{ #category : 'tests - safety' }
3448
MpMethodProxyTest >> testArgumentListIsSent [
3549

@@ -50,6 +64,35 @@ MpMethodProxyTest >> testArgumentListIsSent [
5064
self assert: handler afterArgs first equals: 111.
5165
]
5266

67+
{ #category : 'tests - safety' }
68+
MpMethodProxyTest >> testArgumentListIsSentSizeThreeWithException [
69+
70+
| mp handler semaphore p |
71+
mp := MpMethodProxy
72+
onMethod: MpClassA >> #methodWithArgumentOne:argumentTwo:argThree:
73+
handler: (handler := MpArgumentListTestHandler new).
74+
75+
self installMethodProxy: mp.
76+
77+
semaphore := Semaphore new.
78+
p := [
79+
[ MpClassA new methodWithArgumentOne: 22 argumentTwo: 33 argThree: 3 ]
80+
on: Error
81+
do: [ semaphore wait ] ] forkAt: Processor activePriority + 1.
82+
83+
p terminate.
84+
85+
mp uninstall.
86+
87+
"Test before"
88+
self assert: handler beforeArgs size equals: 3.
89+
self assert: handler beforeArgs first equals: 22.
90+
self assert: handler beforeArgs second equals: 33.
91+
self assert: handler beforeArgs third equals: 3.
92+
93+
self assert: handler unwound
94+
]
95+
5396
{ #category : 'tests - safety' }
5497
MpMethodProxyTest >> testArgumentListIsSentSizeTwo [
5598

@@ -233,8 +276,10 @@ MpMethodProxyTest >> testCanWrapValueWithException [
233276
on: Error
234277
do: #yourself. "to avoid an extra block"
235278

279+
mp uninstall.
280+
236281
"#on:do: does send value too but it's optimised by default and there is no message send"
237-
self assert: handler count equals: 2
282+
self assert: handler count equals: 3
238283
]
239284

240285
{ #category : 'tests - safety' }
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
Class {
2+
#name : 'MpDeactivator',
3+
#superclass : 'Object',
4+
#instVars : [
5+
'handler'
6+
],
7+
#classVars : [
8+
'CompleteTempVariableIndex',
9+
'WasMetaTempVariableIndex'
10+
],
11+
#category : 'MethodProxies',
12+
#package : 'MethodProxies'
13+
}
14+
15+
{ #category : 'class initialization' }
16+
MpDeactivator class >> initialize [
17+
18+
WasMetaTempVariableIndex := (MpMethodProxy class >> #prototypeTrap) tempNames indexOf: #wasMeta.
19+
CompleteTempVariableIndex := (MpMethodProxy class >> #prototypeTrap) tempNames indexOf: #complete
20+
]
21+
22+
{ #category : 'as yet unclassified' }
23+
MpDeactivator class >> withHandler: aMpHandler [
24+
25+
^ self new
26+
handler: aMpHandler;
27+
yourself
28+
]
29+
30+
{ #category : 'accessing' }
31+
MpDeactivator >> asContextWithSender: aContext [
32+
"Inner private support method for evaluation. Do not use unless you know what you're doing."
33+
34+
^(Context newForMethod: (MpDeactivator >> #value))
35+
setSender: aContext
36+
receiver: self
37+
method: (MpDeactivator >> #value)
38+
closure: nil
39+
startpc: (MpDeactivator >> #value) initialPC;
40+
privRefresh
41+
]
42+
43+
{ #category : 'accessing' }
44+
MpDeactivator >> handler: aMpHandler [
45+
46+
handler := aMpHandler
47+
]
48+
49+
{ #category : 'evaluating' }
50+
MpDeactivator >> value [
51+
52+
"Execution handler for the slow path. An exception or a non local return happened during proxy execution"
53+
| wasMeta trapContext |
54+
"Jump to the meta level (to avoid meta-recursions) to observe if the handler was in a meta level, marked by the wasMeta flag.
55+
During the meta-jump call the handler to tell there was an unwind."
56+
thisProcess shiftLevelUp.
57+
trapContext := thisContext.
58+
[ trapContext := trapContext findNextUnwindContextUpTo: nil ] doWhileFalse: [
59+
trapContext method hasPragmaNamed: #trap ].
60+
61+
wasMeta := trapContext tempAt: trapContext method numArgs + WasMetaTempVariableIndex.
62+
handler aboutToReturnWithReceiver: trapContext receiver arguments: trapContext arguments.
63+
64+
thisProcess shiftLevelDown.
65+
66+
"If the handler was in a meta-state (i.e., the exception or non-local return happened in the handler),
67+
shift it back to the base level before returning.
68+
Otherwise, we were already in the base level and we need to do nothing!"
69+
wasMeta ifTrue: [ thisProcess shiftLevelDown ].
70+
71+
"Mark execution as complete to avoid double execution of the handler."
72+
trapContext tempAt: trapContext method numArgs + CompleteTempVariableIndex put: true
73+
]

src/MethodProxies/MpMethodProxy.class.st

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,30 +1286,7 @@ MpMethodProxy >> install [
12861286
(proxifiedMethod hasPragmaNamed: #noInstrumentation) ifTrue: [
12871287
^ MpCannotInstall signalWith: self ].
12881288

1289-
slowdeactivator := [
1290-
"Execution handler for the slow path. An exception or a non local return happened during proxy execution"
1291-
| wasMeta trapContext |
1292-
"Jump to the meta level (to avoid meta-recursions) to observe if the handler was in a meta level, marked by the wasMeta flag.
1293-
During the meta-jump call the handler to tell there was an unwind."
1294-
thisProcess shiftLevelUp.
1295-
trapContext := thisContext.
1296-
[ trapContext := trapContext findNextUnwindContextUpTo: nil ]
1297-
doWhileFalse: [ trapContext method hasPragmaNamed: #trap ].
1298-
1299-
wasMeta := trapContext tempAt: trapContext method numArgs + 5.
1300-
handler
1301-
aboutToReturnWithReceiver: trapContext receiver
1302-
arguments: trapContext arguments.
1303-
1304-
thisProcess shiftLevelDown.
1305-
1306-
"If the handler was in a meta-state (i.e., the exception or non-local return happened in the handler), shift it back to the base level before returning.
1307-
Otherwise, we were already in the base level and we need to do nothing!"
1308-
wasMeta ifTrue: [ thisProcess shiftLevelDown ].
1309-
1310-
"Mark execution as complete to avoid double execution of the handler."
1311-
trapContext tempAt: 2 put: true "complete temp var".
1312-
].
1289+
slowdeactivator := MpDeactivator withHandler: handler.
13131290

13141291
newTrap := self prototypeTrapMethod copy.
13151292
trapSelector := newTrap selector.

src/MethodProxiesExamples/MpAllocationProfilerHandler.class.st

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,17 @@ p3 install.
1818
```
1919
"
2020
Class {
21-
#name : #MpAllocationProfilerHandler,
22-
#superclass : #MpHandler,
21+
#name : 'MpAllocationProfilerHandler',
22+
#superclass : 'MpHandler',
2323
#instVars : [
2424
'allocations',
2525
'transformationBlock'
2626
],
27-
#category : #MethodProxiesExamples
27+
#category : 'MethodProxiesExamples',
28+
#package : 'MethodProxiesExamples'
2829
}
2930

30-
{ #category : #initialization }
31+
{ #category : 'initialization' }
3132
MpAllocationProfilerHandler >> afterExecutionWithReceiver: receiver arguments: arguments returnValue: returnValue [
3233

3334
| allocationsPerClass transformedContext |
@@ -37,12 +38,12 @@ MpAllocationProfilerHandler >> afterExecutionWithReceiver: receiver arguments: a
3738
^ returnValue
3839
]
3940

40-
{ #category : #accessing }
41+
{ #category : 'accessing' }
4142
MpAllocationProfilerHandler >> allocations [
4243
^ allocations
4344
]
4445

45-
{ #category : #evaluating }
46+
{ #category : 'evaluating' }
4647
MpAllocationProfilerHandler >> captureCallingContext [
4748

4849
| runWithInContext |
@@ -56,20 +57,20 @@ MpAllocationProfilerHandler >> captureCallingContext [
5657
^ runWithInContext ifNotNil: [ runWithInContext sender ]
5758
]
5859

59-
{ #category : #accessing }
60+
{ #category : 'accessing' }
6061
MpAllocationProfilerHandler >> contextTransformationBlock: aBlock [
6162

6263
transformationBlock := aBlock
6364
]
6465

65-
{ #category : #initialization }
66+
{ #category : 'initialization' }
6667
MpAllocationProfilerHandler >> initialize [
6768

6869
super initialize.
6970
allocations := Dictionary new.
7071
]
7172

72-
{ #category : #'as yet unclassified' }
73+
{ #category : 'as yet unclassified' }
7374
MpAllocationProfilerHandler >> transformContext: aContext [
7475

7576
^ transformationBlock

src/MethodProxiesExamples/MpCalledHandler.class.st

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,34 @@
22
I'm an example handler that reports if the spyied method has been executed
33
"
44
Class {
5-
#name : #MpCalledHandler,
6-
#superclass : #MpHandler,
5+
#name : 'MpCalledHandler',
6+
#superclass : 'MpHandler',
77
#instVars : [
88
'called'
99
],
10-
#category : #MethodProxiesExamples
10+
#category : 'MethodProxiesExamples',
11+
#package : 'MethodProxiesExamples'
1112
}
1213

13-
{ #category : #evaluating }
14+
{ #category : 'evaluating' }
1415
MpCalledHandler >> beforeMethod [
1516

1617
called := true
1718
]
1819

19-
{ #category : #accessing }
20+
{ #category : 'accessing' }
2021
MpCalledHandler >> called [
2122

2223
^ called
2324
]
2425

25-
{ #category : #accessing }
26+
{ #category : 'accessing' }
2627
MpCalledHandler >> called: aBoolean [
2728

2829
called := aBoolean
2930
]
3031

31-
{ #category : #initialization }
32+
{ #category : 'initialization' }
3233
MpCalledHandler >> initialize [
3334

3435
super initialize.

src/MethodProxiesExamples/MpCountingHandler.class.st

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,34 @@
22
I'm an example handler that counts all the times a method has been invoked
33
"
44
Class {
5-
#name : #MpCountingHandler,
6-
#superclass : #MpHandler,
5+
#name : 'MpCountingHandler',
6+
#superclass : 'MpHandler',
77
#instVars : [
88
'count'
99
],
10-
#category : #MethodProxiesExamples
10+
#category : 'MethodProxiesExamples',
11+
#package : 'MethodProxiesExamples'
1112
}
1213

13-
{ #category : #evaluating }
14+
{ #category : 'evaluating' }
1415
MpCountingHandler >> beforeMethod [
1516

1617
self count: self count + 1
1718
]
1819

19-
{ #category : #accessing }
20+
{ #category : 'accessing' }
2021
MpCountingHandler >> count [
2122

2223
^ count
2324
]
2425

25-
{ #category : #accessing }
26+
{ #category : 'accessing' }
2627
MpCountingHandler >> count: anInteger [
2728

2829
count := anInteger
2930
]
3031

31-
{ #category : #initialization }
32+
{ #category : 'initialization' }
3233
MpCountingHandler >> initialize [
3334

3435
super initialize.

0 commit comments

Comments
 (0)