From babcf049278fa540f8da1daf9febdc21bd6eadc1 Mon Sep 17 00:00:00 2001 From: Guille Polito Date: Wed, 17 Dec 2025 09:42:05 +0100 Subject: [PATCH 1/6] Specialize After trap for handlers only overriding after --- .../MpMethodProxyTest.class.st | 26 +- src/MethodProxies/MpHandler.class.st | 7 + src/MethodProxies/MpMethodProxy.class.st | 1989 +++++++++++++---- .../MpEmptyBeforeHandler.class.st | 16 + .../MpEmptyHandlerAfter.class.st | 18 + 5 files changed, 1647 insertions(+), 409 deletions(-) create mode 100644 src/MethodProxiesExamples/MpEmptyBeforeHandler.class.st create mode 100644 src/MethodProxiesExamples/MpEmptyHandlerAfter.class.st diff --git a/src/MethodProxies-Tests/MpMethodProxyTest.class.st b/src/MethodProxies-Tests/MpMethodProxyTest.class.st index b5d68a4..ebcfe2a 100644 --- a/src/MethodProxies-Tests/MpMethodProxyTest.class.st +++ b/src/MethodProxies-Tests/MpMethodProxyTest.class.st @@ -166,7 +166,7 @@ MpMethodProxyTest >> testCanRunConcurrently [ MpMethodProxyTest >> testCanWrapAboutToReturnThroughWithNonLocalReturn [ | mp handler | - mp := MpMethodProxy onMethod: Context >> #aboutToReturn:through: handler: (handler := MpCountingHandler new). + mp := MpMethodProxy onMethod: Context >> #aboutToReturn:through: handler: (handler := MpEmptyBeforeHandler new). self installMethodProxy: mp. @@ -179,7 +179,7 @@ MpMethodProxyTest >> testCanWrapAboutToReturnThroughWithNonLocalReturn [ MpMethodProxyTest >> testCanWrapBasicNew [ | mp handler | - mp := MpMethodProxy onMethod: Behavior >> #basicNew handler: (handler := MpCountingHandler new). + mp := MpMethodProxy onMethod: Behavior >> #basicNew handler: (handler := MpEmptyBeforeHandler new). self installMethodProxy: mp. @@ -193,7 +193,7 @@ MpMethodProxyTest >> testCanWrapBasicNew [ MpMethodProxyTest >> testCanWrapEnsure [ | mp handler | - mp := MpMethodProxy onMethod: BlockClosure >> #ensure: handler: (handler := MpCountingHandler new). + mp := MpMethodProxy onMethod: BlockClosure >> #ensure: handler: (handler := MpEmptyBeforeHandler new). self installMethodProxy: mp. @@ -206,7 +206,7 @@ MpMethodProxyTest >> testCanWrapEnsure [ MpMethodProxyTest >> testCanWrapEnsureNonLocalReturn [ | mp handler | - mp := MpMethodProxy onMethod: BlockClosure >> #ensure: handler: (handler := MpCountingHandler new). + mp := MpMethodProxy onMethod: BlockClosure >> #ensure: handler: (handler := MpEmptyBeforeHandler new). self installMethodProxy: mp. @@ -219,7 +219,7 @@ MpMethodProxyTest >> testCanWrapEnsureNonLocalReturn [ MpMethodProxyTest >> testCanWrapEnsureWithException [ | mp handler | - mp := MpMethodProxy onMethod: BlockClosure >> #ensure: handler: (handler := MpCountingHandler new). + mp := MpMethodProxy onMethod: BlockClosure >> #ensure: handler: (handler := MpEmptyBeforeHandler new). self installMethodProxy: mp. @@ -233,7 +233,7 @@ MpMethodProxyTest >> testCanWrapValue [ | mp handler | - mp := MpMethodProxy onMethod: (FullBlockClosure lookupSelector: #value) handler: (handler := MpCountingHandler new). + mp := MpMethodProxy onMethod: (FullBlockClosure lookupSelector: #value) handler: (handler := MpEmptyBeforeHandler new). self installMethodProxy: mp. @@ -249,7 +249,7 @@ MpMethodProxyTest >> testCanWrapValueWithException [ | mp handler | mp := MpMethodProxy onMethod: (FullBlockClosure lookupSelector: #value) - handler: (handler := MpCountingHandler new). + handler: (handler := MpEmptyBeforeHandler new). self installMethodProxy: mp. [ [ [ 1 error ] value ] value ] @@ -266,7 +266,7 @@ MpMethodProxyTest >> testCanWrapValueWithException [ MpMethodProxyTest >> testCannotWrapCriticalProxyMethods6 [ | mp handler | - mp := MpMethodProxy onMethod: InstrumentationDeactivator >> #value handler: (handler := MpCountingHandler new). + mp := MpMethodProxy onMethod: InstrumentationDeactivator >> #value handler: (handler := MpEmptyBeforeHandler new). self assertCannotInstall: mp ] @@ -288,7 +288,7 @@ MpMethodProxyTest >> testCreatingAnInstanceDoesNotInstallIt [ MpMethodProxyTest >> testDisableInstrumentationSimple [ | mp handler | - mp := MpMethodProxy onMethod: (MpClassA >> #methodOne) handler: (handler := MpCountingHandler new). + mp := MpMethodProxy onMethod: (MpClassA >> #methodOne) handler: (handler := MpEmptyBeforeHandler new). self installMethodProxy: mp. mp disableInstrumentation. @@ -305,7 +305,7 @@ MpMethodProxyTest >> testDisableInstrumentationValue [ | mp handler | - mp := MpMethodProxy onMethod: (FullBlockClosure lookupSelector: #value) handler: (handler := MpCountingHandler new). + mp := MpMethodProxy onMethod: (FullBlockClosure lookupSelector: #value) handler: (handler := MpEmptyBeforeHandler new). self installMethodProxy: mp. mp disableInstrumentation. @@ -322,7 +322,7 @@ MpMethodProxyTest >> testDisableInstrumentationValueWithException [ | mp handler | mp := MpMethodProxy onMethod: (FullBlockClosure lookupSelector: #value) - handler: (handler := MpCountingHandler new). + handler: (handler := MpEmptyBeforeHandler new). self installMethodProxy: mp. mp disableInstrumentation. @@ -340,7 +340,7 @@ MpMethodProxyTest >> testDisableInstrumentationValueWithException [ MpMethodProxyTest >> testExceptionsAfterInstrumentationDoNotBreakInstrumentation [ | mp handler | - mp := MpMethodProxy onMethod: Object >> #error: handler: (handler := MpCountingHandler new). + mp := MpMethodProxy onMethod: Object >> #error: handler: (handler := MpEmptyBeforeHandler new). self installMethodProxy: mp. @@ -357,7 +357,7 @@ MpMethodProxyTest >> testExceptionsAfterInstrumentationDoNotBreakInstrumentation MpMethodProxyTest >> testExceptionsAfterInstrumentationFlow [ "Managing exceptions in the wrapper" | p | - p := MpMethodProxy onMethod: Object >> #error: handler: MpCountingHandler new. + p := MpMethodProxy onMethod: Object >> #error: handler: MpEmptyBeforeHandler new. self installMethodProxy: p. diff --git a/src/MethodProxies/MpHandler.class.st b/src/MethodProxies/MpHandler.class.st index b6f2d64..f9d728c 100644 --- a/src/MethodProxies/MpHandler.class.st +++ b/src/MethodProxies/MpHandler.class.st @@ -53,3 +53,10 @@ MpHandler >> beforeMethod [ ] + +{ #category : 'configuring' } +MpHandler >> overridesBeforeMethod [ + + ^(self class lookupSelector: #beforeExecutionWithReceiver:arguments:) + methodClass ~= MpHandler +] diff --git a/src/MethodProxies/MpMethodProxy.class.st b/src/MethodProxies/MpMethodProxy.class.st index 4d26dab..2cb8813 100644 --- a/src/MethodProxies/MpMethodProxy.class.st +++ b/src/MethodProxies/MpMethodProxy.class.st @@ -76,38 +76,45 @@ MpMethodProxy class >> buildPrototypesUpToArguments: maxNumberOfArguments [ "self buildPrototypesUpToArguments: 15" - | forwarders argumentListNodes | + | forwarders argumentListNodes prototypeTraps | 0 to: maxNumberOfArguments do: [ :numberOfArguments | - | originalAst trapSelector trapArguments | - originalAst := (self class >> #prototypeTrap) parseTree. - - trapSelector := #trapMethod. - 1 to: numberOfArguments do: [ :i | trapSelector := trapSelector , #with: ]. - trapArguments := (1 to: numberOfArguments) collect: [ :i | - RBVariableNode named: 'arg' , i asString ]. - - originalAst selector: trapSelector. - originalAst arguments: trapArguments. - argumentListNodes := originalAst allChildren select: [ :e | e value = #argumentList ]. - argumentListNodes do: [ :e | e replaceWith: (RBArrayNode statements: trapArguments) ]. - - forwarders := originalAst sendNodes select: [ :e | e selector = #originalMessage ]. - forwarders do: [ :e | - e replaceWith: (RBMessageNode - receiver: RBVariableNode selfNode - selector: trapSelector - arguments: trapArguments) ]. - self class compile: originalAst formattedCode ] + "There are different traps, optimized by handler" + prototypeTraps := self class methods select: [ :e | e hasPragmaNamed: #prototypeTrap ]. + prototypeTraps do: [ :prototype | + | originalAst trapSelector trapArguments | + + originalAst := prototype parseTree. + originalAst addPragma: (RBPragmaNode selector: #autogenerated arguments: #()). + originalAst removePragmaNamed: #prototypeTrap. + + trapSelector := ('t', (prototype selector allButFirst: #prototypeT size)) asSymbol. + 1 to: numberOfArguments do: [ :i | trapSelector := trapSelector , #with: ]. + trapArguments := (1 to: numberOfArguments) collect: [ :i | + RBVariableNode named: 'arg' , i asString ]. + + originalAst selector: trapSelector. + originalAst arguments: trapArguments. + + argumentListNodes := originalAst allChildren select: [ :e | e value = #argumentList ]. + argumentListNodes do: [ :e | e replaceWith: (RBArrayNode statements: trapArguments) ]. + + forwarders := originalAst sendNodes select: [ :e | e selector = #originalMessage ]. + forwarders do: [ :e | + e replaceWith: (RBMessageNode + receiver: RBVariableNode selfNode + selector: trapSelector + arguments: trapArguments) ]. + self class compile: originalAst formattedCode ] ] ] -{ #category : 'as yet unclassified' } +{ #category : 'enabling' } MpMethodProxy class >> disableInstrumentation [ ENABLED := false ] -{ #category : 'as yet unclassified' } +{ #category : 'enabling' } MpMethodProxy class >> enableInstrumentation [ ENABLED := true @@ -129,13 +136,59 @@ MpMethodProxy class >> onMethod: aMethod handler: aHandler [ ] { #category : 'evaluating' } -MpMethodProxy class >> prototypeTrap [ +MpMethodProxy class >> prototypeTrapAfter [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self originalMessage. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: #argumentList + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'evaluating' } +MpMethodProxy class >> prototypeTrapBeforeAfter [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. Then this method is free to use as many extra temporaries and arguments as is wants" + | deactivator complete result process wasMeta | @@ -154,12 +207,959 @@ MpMethodProxy class >> prototypeTrap [ process shiftLevelDown. wasMeta := false. - "Back in the base-level forward the original message. - This is a message to self that will be monomorphically linked by the VM. - The core idea is that - - the original method is installed in the same method dictionary using a unique symbol - - this call is patched to use that symbol for the send" - result := self originalMessage. + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self originalMessage. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: #argumentList + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'instance creation' } +MpMethodProxy class >> proxyMethod: method handler: aHandler [ + + ^ MpMethodProxy new + proxyMethod: method; + handler: aHandler; + yourself +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfter [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self trapAfter. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: { } + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfterwith: arg1 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self trapAfterwith: arg1. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: { arg1 } + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfterwith: arg1 with: arg2 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self trapAfterwith: arg1 with: arg2. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: { + arg1. + arg2 } + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self trapAfterwith: arg1 with: arg2 with: arg3. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: { + arg1. + arg2. + arg3 } + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: { + arg1. + arg2. + arg3. + arg4 } + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: { + arg1. + arg2. + arg3. + arg4. + arg5 } + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6 } + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7 } + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8 } + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8. + arg9 } + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8. + arg9. + arg10 } + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8. + arg9. + arg10. + arg11 } + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8. + arg9. + arg10. + arg11. + arg12 } + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8. + arg9. + arg10. + arg11. + arg12. + arg13 } + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 + with: arg14. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. + + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8. + arg9. + arg10. + arg11. + arg12. + arg13. + arg14 } + returnValue: result. + process shiftLevelDown. + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 with: arg15 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 + with: arg14 + with: arg15. + + ENABLED ifFalse: [ ^ result ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ result ]. "Move to the meta level and call the after hooks. Two after hooks are required. @@ -169,7 +1169,22 @@ MpMethodProxy class >> prototypeTrap [ wasMeta := true. result := #handler afterExecutionWithReceiver: self - arguments: #argumentList + arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8. + arg9. + arg10. + arg11. + arg12. + arg13. + arg14. + arg15 } returnValue: result. process shiftLevelDown. wasMeta := false. @@ -180,16 +1195,7 @@ MpMethodProxy class >> prototypeTrap [ ] { #category : 'as yet unclassified' } -MpMethodProxy class >> proxyMethod: method handler: aHandler [ - - ^ MpMethodProxy new - proxyMethod: method; - handler: aHandler; - yourself -] - -{ #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethod [ +MpMethodProxy class >> trapBeforeAfter [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -198,36 +1204,50 @@ MpMethodProxy class >> trapMethod [ + | deactivator complete result process wasMeta | - ENABLED ifFalse: [ ^ self trapMethod ]. + ENABLED ifFalse: [ ^ self trapBeforeAfter ]. process := Processor activeProcess. - process isMeta ifTrue: [ ^ self trapMethod ]. "Set the deactivator literal for the slow path. + process isMeta ifTrue: [ ^ self trapBeforeAfter ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" - result := self trapMethod. "Move to the meta level and call the after hooks. + result := self trapBeforeAfter. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." process shiftLevelUp. wasMeta := true. - result := #handler afterExecutionWithReceiver: self arguments: { } returnValue: result. + result := #handler + afterExecutionWithReceiver: self + arguments: { } + returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethodwith: arg1 [ +MpMethodProxy class >> trapBeforeAfterwith: arg1 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -236,36 +1256,50 @@ MpMethodProxy class >> trapMethodwith: arg1 [ + | deactivator complete result process wasMeta | - ENABLED ifFalse: [ ^ self trapMethodwith: arg1 ]. + ENABLED ifFalse: [ ^ self trapBeforeAfterwith: arg1 ]. process := Processor activeProcess. - process isMeta ifTrue: [ ^ self trapMethodwith: arg1 ]. "Set the deactivator literal for the slow path. + process isMeta ifTrue: [ ^ self trapBeforeAfterwith: arg1 ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { arg1 }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" - result := self trapMethodwith: arg1. "Move to the meta level and call the after hooks. + result := self trapBeforeAfterwith: arg1. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." process shiftLevelUp. wasMeta := true. - result := #handler afterExecutionWithReceiver: self arguments: { arg1 } returnValue: result. + result := #handler + afterExecutionWithReceiver: self + arguments: { arg1 } + returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethodwith: arg1 with: arg2 [ +MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -274,24 +1308,33 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 [ + | deactivator complete result process wasMeta | - ENABLED ifFalse: [ ^ self trapMethodwith: arg1 with: arg2 ]. + ENABLED ifFalse: [ ^ self trapBeforeAfterwith: arg1 with: arg2 ]. process := Processor activeProcess. - process isMeta ifTrue: [ ^ self trapMethodwith: arg1 with: arg2 ]. "Set the deactivator literal for the slow path. + process isMeta ifTrue: [ ^ self trapBeforeAfterwith: arg1 with: arg2 ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { arg1. arg2 }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" - result := self trapMethodwith: arg1 with: arg2. "Move to the meta level and call the after hooks. + result := self trapBeforeAfterwith: arg1 with: arg2. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." @@ -304,13 +1347,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 [ arg2 } returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 [ +MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -319,12 +1364,19 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 [ + | deactivator complete result process wasMeta | - ENABLED ifFalse: [ ^ self trapMethodwith: arg1 with: arg2 with: arg3 ]. + ENABLED ifFalse: [ + ^ self trapBeforeAfterwith: arg1 with: arg2 with: arg3 ]. process := Processor activeProcess. - process isMeta ifTrue: [ ^ self trapMethodwith: arg1 with: arg2 with: arg3 ]. "Set the deactivator literal for the slow path. + process isMeta ifTrue: [ + ^ self trapBeforeAfterwith: arg1 with: arg2 with: arg3 ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { @@ -332,12 +1384,16 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 [ arg2. arg3 }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" - result := self trapMethodwith: arg1 with: arg2 with: arg3. "Move to the meta level and call the after hooks. + result := self trapBeforeAfterwith: arg1 with: arg2 with: arg3. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." @@ -351,13 +1407,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 [ arg3 } returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 [ +MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -366,22 +1424,27 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 [ + | deactivator complete result process wasMeta | ENABLED ifFalse: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 ]. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 ]. process := Processor activeProcess. process isMeta ifTrue: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 ]. "Set the deactivator literal for the slow path. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { @@ -390,16 +1453,20 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 [ arg3. arg4 }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapMethodwith: arg1 + trapBeforeAfterwith: arg1 with: arg2 with: arg3 - with: arg4. "Move to the meta level and call the after hooks. + with: arg4. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." @@ -414,13 +1481,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 [ arg4 } returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 [ +MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -429,24 +1498,29 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit + | deactivator complete result process wasMeta | ENABLED ifFalse: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 ]. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 ]. process := Processor activeProcess. process isMeta ifTrue: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 ]. "Set the deactivator literal for the slow path. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { @@ -456,17 +1530,21 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg4. arg5 }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapMethodwith: arg1 + trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 - with: arg5. "Move to the meta level and call the after hooks. + with: arg5. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." @@ -482,13 +1560,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg5 } returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 [ +MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -497,26 +1577,31 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit + | deactivator complete result process wasMeta | ENABLED ifFalse: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 ]. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 ]. process := Processor activeProcess. process isMeta ifTrue: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 ]. "Set the deactivator literal for the slow path. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { @@ -527,18 +1612,22 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg5. arg6 }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapMethodwith: arg1 + trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 - with: arg6. "Move to the meta level and call the after hooks. + with: arg6. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." @@ -555,13 +1644,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg6 } returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 [ +MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -570,28 +1661,33 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit + | deactivator complete result process wasMeta | ENABLED ifFalse: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 ]. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 ]. process := Processor activeProcess. process isMeta ifTrue: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 ]. "Set the deactivator literal for the slow path. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { @@ -603,19 +1699,23 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg6. arg7 }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapMethodwith: arg1 + trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 - with: arg7. "Move to the meta level and call the after hooks. + with: arg7. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." @@ -633,13 +1733,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg7 } returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 [ +MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -648,30 +1750,35 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit + | deactivator complete result process wasMeta | ENABLED ifFalse: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 ]. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 ]. process := Processor activeProcess. process isMeta ifTrue: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 ]. "Set the deactivator literal for the slow path. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { @@ -684,20 +1791,24 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg7. arg8 }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapMethodwith: arg1 + trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 - with: arg8. "Move to the meta level and call the after hooks. + with: arg8. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." @@ -716,13 +1827,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg8 } returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 [ +MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -731,32 +1844,37 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit + | deactivator complete result process wasMeta | ENABLED ifFalse: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 - with: arg9 ]. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 ]. process := Processor activeProcess. process isMeta ifTrue: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 - with: arg9 ]. "Set the deactivator literal for the slow path. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { @@ -770,13 +1888,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg8. arg9 }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapMethodwith: arg1 + trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 @@ -784,7 +1904,9 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit with: arg6 with: arg7 with: arg8 - with: arg9. "Move to the meta level and call the after hooks. + with: arg9. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." @@ -804,13 +1926,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg9 } returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 [ +MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -819,34 +1943,39 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit + | deactivator complete result process wasMeta | ENABLED ifFalse: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 - with: arg9 - with: arg10 ]. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 ]. process := Processor activeProcess. process isMeta ifTrue: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 - with: arg9 - with: arg10 ]. "Set the deactivator literal for the slow path. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { @@ -861,13 +1990,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg9. arg10 }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapMethodwith: arg1 + trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 @@ -876,7 +2007,9 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit with: arg7 with: arg8 with: arg9 - with: arg10. "Move to the meta level and call the after hooks. + with: arg10. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." @@ -897,13 +2030,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg10 } returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 [ +MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -912,36 +2047,41 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit + | deactivator complete result process wasMeta | ENABLED ifFalse: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 - with: arg9 - with: arg10 - with: arg11 ]. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 ]. process := Processor activeProcess. process isMeta ifTrue: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 - with: arg9 - with: arg10 - with: arg11 ]. "Set the deactivator literal for the slow path. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { @@ -957,13 +2097,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg10. arg11 }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapMethodwith: arg1 + trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 @@ -973,7 +2115,9 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit with: arg8 with: arg9 with: arg10 - with: arg11. "Move to the meta level and call the after hooks. + with: arg11. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." @@ -995,13 +2139,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg11 } returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 [ +MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -1010,38 +2156,43 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit + | deactivator complete result process wasMeta | ENABLED ifFalse: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 - with: arg9 - with: arg10 - with: arg11 - with: arg12 ]. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 ]. process := Processor activeProcess. process isMeta ifTrue: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 - with: arg9 - with: arg10 - with: arg11 - with: arg12 ]. "Set the deactivator literal for the slow path. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { @@ -1058,13 +2209,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg11. arg12 }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapMethodwith: arg1 + trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 @@ -1075,7 +2228,9 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit with: arg9 with: arg10 with: arg11 - with: arg12. "Move to the meta level and call the after hooks. + with: arg12. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." @@ -1098,13 +2253,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg12 } returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 [ +MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -1113,40 +2270,45 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit + | deactivator complete result process wasMeta | ENABLED ifFalse: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 - with: arg9 - with: arg10 - with: arg11 - with: arg12 - with: arg13 ]. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 ]. process := Processor activeProcess. process isMeta ifTrue: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 - with: arg9 - with: arg10 - with: arg11 - with: arg12 - with: arg13 ]. "Set the deactivator literal for the slow path. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { @@ -1164,13 +2326,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg12. arg13 }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapMethodwith: arg1 + trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 @@ -1182,7 +2346,9 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit with: arg10 with: arg11 with: arg12 - with: arg13. "Move to the meta level and call the after hooks. + with: arg13. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." @@ -1206,13 +2372,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg13 } returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 [ +MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -1221,42 +2389,47 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit + | deactivator complete result process wasMeta | ENABLED ifFalse: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 - with: arg9 - with: arg10 - with: arg11 - with: arg12 - with: arg13 - with: arg14 ]. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 + with: arg14 ]. process := Processor activeProcess. process isMeta ifTrue: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 - with: arg9 - with: arg10 - with: arg11 - with: arg12 - with: arg13 - with: arg14 ]. "Set the deactivator literal for the slow path. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 + with: arg14 ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { @@ -1275,13 +2448,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg13. arg14 }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapMethodwith: arg1 + trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 @@ -1294,7 +2469,9 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit with: arg11 with: arg12 with: arg13 - with: arg14. "Move to the meta level and call the after hooks. + with: arg14. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." @@ -1319,13 +2496,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg14 } returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 with: arg15 [ +MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 with: arg15 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -1334,44 +2513,49 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit + | deactivator complete result process wasMeta | ENABLED ifFalse: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 - with: arg9 - with: arg10 - with: arg11 - with: arg12 - with: arg13 - with: arg14 - with: arg15 ]. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 + with: arg14 + with: arg15 ]. process := Processor activeProcess. process isMeta ifTrue: [ - ^ self - trapMethodwith: arg1 - with: arg2 - with: arg3 - with: arg4 - with: arg5 - with: arg6 - with: arg7 - with: arg8 - with: arg9 - with: arg10 - with: arg11 - with: arg12 - with: arg13 - with: arg14 - with: arg15 ]. "Set the deactivator literal for the slow path. + ^ self + trapBeforeAfterwith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 + with: arg14 + with: arg15 ]. + + "Set the deactivator literal for the slow path. It will be patched to an exception handler" - deactivator := #slowdeactivator. "Move to the meta level and call the before hook" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. #handler beforeExecutionWithReceiver: self arguments: { @@ -1391,13 +2575,15 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg14. arg15 }. process shiftLevelDown. - wasMeta := false. "Back in the base-level forward the original message. + wasMeta := false. + + "Back in the base-level forward the original message. This is a message to self that will be monomorphically linked by the VM. The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapMethodwith: arg1 + trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg4 @@ -1411,7 +2597,9 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit with: arg12 with: arg13 with: arg14 - with: arg15. "Move to the meta level and call the after hooks. + with: arg15. + + "Move to the meta level and call the after hooks. Two after hooks are required. One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns The other indicates we are returning normally with a value." @@ -1437,7 +2625,9 @@ MpMethodProxy class >> trapMethodwith: arg1 with: arg2 with: arg3 with: arg4 wit arg15 } returnValue: result. process shiftLevelDown. - wasMeta := false. "Mark the execution as complete to avoid double execution of the unwind handler" + wasMeta := false. + + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] @@ -1531,8 +2721,15 @@ MpMethodProxy >> methodClass [ { #category : 'installation' } MpMethodProxy >> prototypeTrapMethod [ - ^ self class class methods detect: [ :m | - m numArgs = proxifiedMethod numArgs and: [ m selector beginsWith: 'trapMethod' ] ] + | trapSelector | + "What kind of trap method do we want?" + trapSelector := handler overridesBeforeMethod + ifTrue: [ #trapBeforeAfter ] + ifFalse: [ #trapAfter ]. + + ^ self class class methods detect: [ :m | + m numArgs = proxifiedMethod numArgs and: [ + m selector beginsWith: trapSelector ] ] ] { #category : 'accessing' } diff --git a/src/MethodProxiesExamples/MpEmptyBeforeHandler.class.st b/src/MethodProxiesExamples/MpEmptyBeforeHandler.class.st new file mode 100644 index 0000000..befa2f0 --- /dev/null +++ b/src/MethodProxiesExamples/MpEmptyBeforeHandler.class.st @@ -0,0 +1,16 @@ +" +I'm an example handler that counts all the times a method has been invoked +" +Class { + #name : 'MpEmptyBeforeHandler', + #superclass : 'MpHandler', + #instVars : [ + 'count' + ], + #category : 'MethodProxiesExamples', + #package : 'MethodProxiesExamples' +} + +{ #category : 'as yet unclassified' } +MpEmptyBeforeHandler >> beforeExecutionWithReceiver: anObject arguments: anArrayOfObjects [ +] diff --git a/src/MethodProxiesExamples/MpEmptyHandlerAfter.class.st b/src/MethodProxiesExamples/MpEmptyHandlerAfter.class.st new file mode 100644 index 0000000..1da1b1a --- /dev/null +++ b/src/MethodProxiesExamples/MpEmptyHandlerAfter.class.st @@ -0,0 +1,18 @@ +" +I'm an example handler that counts all the times a method has been invoked +" +Class { + #name : 'MpEmptyHandlerAfter', + #superclass : 'MpHandler', + #instVars : [ + 'count' + ], + #category : 'MethodProxiesExamples', + #package : 'MethodProxiesExamples' +} + +{ #category : 'evaluating' } +MpEmptyHandlerAfter >> afterExecutionWithReceiver: anObject arguments: anArrayOfObjects returnValue: retVal [ + + ^ retVal +] From eab5035193b10bc2fa0ecf463f883f86ff22429a Mon Sep 17 00:00:00 2001 From: Guille Polito Date: Thu, 18 Dec 2025 09:14:29 +0100 Subject: [PATCH 2/6] Avoid wrapping of arguments in array for common messages --- .../MpMethodProxyTest.class.st | 26 +- src/MethodProxies/MpHandler.class.st | 82 + src/MethodProxies/MpMethodProxy.class.st | 1396 +++++++++++++++-- .../MpEmptyBeforeHandler.class.st | 2 +- 4 files changed, 1378 insertions(+), 128 deletions(-) diff --git a/src/MethodProxies-Tests/MpMethodProxyTest.class.st b/src/MethodProxies-Tests/MpMethodProxyTest.class.st index ebcfe2a..b5d68a4 100644 --- a/src/MethodProxies-Tests/MpMethodProxyTest.class.st +++ b/src/MethodProxies-Tests/MpMethodProxyTest.class.st @@ -166,7 +166,7 @@ MpMethodProxyTest >> testCanRunConcurrently [ MpMethodProxyTest >> testCanWrapAboutToReturnThroughWithNonLocalReturn [ | mp handler | - mp := MpMethodProxy onMethod: Context >> #aboutToReturn:through: handler: (handler := MpEmptyBeforeHandler new). + mp := MpMethodProxy onMethod: Context >> #aboutToReturn:through: handler: (handler := MpCountingHandler new). self installMethodProxy: mp. @@ -179,7 +179,7 @@ MpMethodProxyTest >> testCanWrapAboutToReturnThroughWithNonLocalReturn [ MpMethodProxyTest >> testCanWrapBasicNew [ | mp handler | - mp := MpMethodProxy onMethod: Behavior >> #basicNew handler: (handler := MpEmptyBeforeHandler new). + mp := MpMethodProxy onMethod: Behavior >> #basicNew handler: (handler := MpCountingHandler new). self installMethodProxy: mp. @@ -193,7 +193,7 @@ MpMethodProxyTest >> testCanWrapBasicNew [ MpMethodProxyTest >> testCanWrapEnsure [ | mp handler | - mp := MpMethodProxy onMethod: BlockClosure >> #ensure: handler: (handler := MpEmptyBeforeHandler new). + mp := MpMethodProxy onMethod: BlockClosure >> #ensure: handler: (handler := MpCountingHandler new). self installMethodProxy: mp. @@ -206,7 +206,7 @@ MpMethodProxyTest >> testCanWrapEnsure [ MpMethodProxyTest >> testCanWrapEnsureNonLocalReturn [ | mp handler | - mp := MpMethodProxy onMethod: BlockClosure >> #ensure: handler: (handler := MpEmptyBeforeHandler new). + mp := MpMethodProxy onMethod: BlockClosure >> #ensure: handler: (handler := MpCountingHandler new). self installMethodProxy: mp. @@ -219,7 +219,7 @@ MpMethodProxyTest >> testCanWrapEnsureNonLocalReturn [ MpMethodProxyTest >> testCanWrapEnsureWithException [ | mp handler | - mp := MpMethodProxy onMethod: BlockClosure >> #ensure: handler: (handler := MpEmptyBeforeHandler new). + mp := MpMethodProxy onMethod: BlockClosure >> #ensure: handler: (handler := MpCountingHandler new). self installMethodProxy: mp. @@ -233,7 +233,7 @@ MpMethodProxyTest >> testCanWrapValue [ | mp handler | - mp := MpMethodProxy onMethod: (FullBlockClosure lookupSelector: #value) handler: (handler := MpEmptyBeforeHandler new). + mp := MpMethodProxy onMethod: (FullBlockClosure lookupSelector: #value) handler: (handler := MpCountingHandler new). self installMethodProxy: mp. @@ -249,7 +249,7 @@ MpMethodProxyTest >> testCanWrapValueWithException [ | mp handler | mp := MpMethodProxy onMethod: (FullBlockClosure lookupSelector: #value) - handler: (handler := MpEmptyBeforeHandler new). + handler: (handler := MpCountingHandler new). self installMethodProxy: mp. [ [ [ 1 error ] value ] value ] @@ -266,7 +266,7 @@ MpMethodProxyTest >> testCanWrapValueWithException [ MpMethodProxyTest >> testCannotWrapCriticalProxyMethods6 [ | mp handler | - mp := MpMethodProxy onMethod: InstrumentationDeactivator >> #value handler: (handler := MpEmptyBeforeHandler new). + mp := MpMethodProxy onMethod: InstrumentationDeactivator >> #value handler: (handler := MpCountingHandler new). self assertCannotInstall: mp ] @@ -288,7 +288,7 @@ MpMethodProxyTest >> testCreatingAnInstanceDoesNotInstallIt [ MpMethodProxyTest >> testDisableInstrumentationSimple [ | mp handler | - mp := MpMethodProxy onMethod: (MpClassA >> #methodOne) handler: (handler := MpEmptyBeforeHandler new). + mp := MpMethodProxy onMethod: (MpClassA >> #methodOne) handler: (handler := MpCountingHandler new). self installMethodProxy: mp. mp disableInstrumentation. @@ -305,7 +305,7 @@ MpMethodProxyTest >> testDisableInstrumentationValue [ | mp handler | - mp := MpMethodProxy onMethod: (FullBlockClosure lookupSelector: #value) handler: (handler := MpEmptyBeforeHandler new). + mp := MpMethodProxy onMethod: (FullBlockClosure lookupSelector: #value) handler: (handler := MpCountingHandler new). self installMethodProxy: mp. mp disableInstrumentation. @@ -322,7 +322,7 @@ MpMethodProxyTest >> testDisableInstrumentationValueWithException [ | mp handler | mp := MpMethodProxy onMethod: (FullBlockClosure lookupSelector: #value) - handler: (handler := MpEmptyBeforeHandler new). + handler: (handler := MpCountingHandler new). self installMethodProxy: mp. mp disableInstrumentation. @@ -340,7 +340,7 @@ MpMethodProxyTest >> testDisableInstrumentationValueWithException [ MpMethodProxyTest >> testExceptionsAfterInstrumentationDoNotBreakInstrumentation [ | mp handler | - mp := MpMethodProxy onMethod: Object >> #error: handler: (handler := MpEmptyBeforeHandler new). + mp := MpMethodProxy onMethod: Object >> #error: handler: (handler := MpCountingHandler new). self installMethodProxy: mp. @@ -357,7 +357,7 @@ MpMethodProxyTest >> testExceptionsAfterInstrumentationDoNotBreakInstrumentation MpMethodProxyTest >> testExceptionsAfterInstrumentationFlow [ "Managing exceptions in the wrapper" | p | - p := MpMethodProxy onMethod: Object >> #error: handler: MpEmptyBeforeHandler new. + p := MpMethodProxy onMethod: Object >> #error: handler: MpCountingHandler new. self installMethodProxy: p. diff --git a/src/MethodProxies/MpHandler.class.st b/src/MethodProxies/MpHandler.class.st index f9d728c..a800ff7 100644 --- a/src/MethodProxies/MpHandler.class.st +++ b/src/MethodProxies/MpHandler.class.st @@ -36,27 +36,109 @@ MpHandler >> afterExecutionWithReceiver: anObject arguments: anArrayOfObjects re ^ returnValue ] +{ #category : 'evaluating' } +MpHandler >> afterExecutionWithReceiver: anObject returnValue: aValue [ + ^ self afterExecutionWithReceiver: anObject arguments: {} returnValue: aValue +] + +{ #category : 'evaluating' } +MpHandler >> afterExecutionWithReceiver: anObject with: arg1 returnValue: aValue [ + ^ self afterExecutionWithReceiver: anObject arguments: {arg1} returnValue: aValue +] + +{ #category : 'evaluating' } +MpHandler >> afterExecutionWithReceiver: anObject with: arg1 with: arg2 returnValue: aValue [ + ^ self afterExecutionWithReceiver: anObject arguments: {arg1 . arg2} returnValue: aValue +] + +{ #category : 'evaluating' } +MpHandler >> afterExecutionWithReceiver: anObject with: arg1 with: arg2 with: arg3 returnValue: aValue [ + ^ self afterExecutionWithReceiver: anObject arguments: {arg1 . arg2 . arg3} returnValue: aValue +] + +{ #category : 'evaluating' } +MpHandler >> afterExecutionWithReceiver: anObject with: arg1 with: arg2 with: arg3 with: arg4 returnValue: aValue [ + ^ self afterExecutionWithReceiver: anObject arguments: {arg1 . arg2 . arg3 . arg4} returnValue: aValue +] + +{ #category : 'evaluating' } +MpHandler >> afterExecutionWithReceiver: anObject with: arg1 with: arg2 with: arg3 with: arg4 with: arg5 returnValue: aValue [ + ^ self afterExecutionWithReceiver: anObject arguments: {arg1 . arg2 . arg3 . arg4 . arg5} returnValue: aValue +] + { #category : 'evaluating' } MpHandler >> afterMethod [ ] +{ #category : 'evaluating' } +MpHandler >> beforeExecutionWithReceiver: anObject [ + ^ self beforeExecutionWithReceiver: anObject arguments: {} +] + { #category : 'evaluating' } MpHandler >> beforeExecutionWithReceiver: anObject arguments: anArrayOfObjects [ self beforeMethod ] +{ #category : 'evaluating' } +MpHandler >> beforeExecutionWithReceiver: anObject with: arg1 [ + ^ self beforeExecutionWithReceiver: anObject arguments: {arg1} +] + +{ #category : 'evaluating' } +MpHandler >> beforeExecutionWithReceiver: anObject with: arg1 with: arg2 [ + ^ self beforeExecutionWithReceiver: anObject arguments: {arg1 . arg2} +] + +{ #category : 'evaluating' } +MpHandler >> beforeExecutionWithReceiver: anObject with: arg1 with: arg2 with: arg3 [ + ^ self beforeExecutionWithReceiver: anObject arguments: {arg1 . arg2 . arg3} +] + +{ #category : 'evaluating' } +MpHandler >> beforeExecutionWithReceiver: anObject with: arg1 with: arg2 with: arg3 with: arg4 [ + ^ self beforeExecutionWithReceiver: anObject arguments: {arg1 . arg2 . arg3 . arg4} +] + +{ #category : 'evaluating' } +MpHandler >> beforeExecutionWithReceiver: anObject with: arg1 with: arg2 with: arg3 with: arg4 with: arg5 [ + ^ self beforeExecutionWithReceiver: anObject arguments: {arg1 . arg2 . arg3 . arg4 . arg5} +] + { #category : 'evaluating' } MpHandler >> beforeMethod [ ] +{ #category : 'as yet unclassified' } +MpHandler >> overridesAfterMethodFor: anInteger [ + + | argKeywords | + argKeywords := '' join: ((1 to: anInteger) collect: [ :i | 'with:' ]). + + ^ (self class lookupSelector: + (#afterExecutionWithReceiver: , argKeywords, 'returnValue:') asSymbol) + methodClass ~= MpHandler +] + { #category : 'configuring' } MpHandler >> overridesBeforeMethod [ ^(self class lookupSelector: #beforeExecutionWithReceiver:arguments:) methodClass ~= MpHandler ] + +{ #category : 'as yet unclassified' } +MpHandler >> overridesBeforeMethodFor: anInteger [ + + | argKeywords | + argKeywords := '' join: ((1 to: anInteger) collect: [ :i | 'with:' ]). + + ^ (self class lookupSelector: + (#beforeExecutionWithReceiver: , argKeywords) asSymbol) + methodClass ~= MpHandler +] diff --git a/src/MethodProxies/MpMethodProxy.class.st b/src/MethodProxies/MpMethodProxy.class.st index 2cb8813..4e176a4 100644 --- a/src/MethodProxies/MpMethodProxy.class.st +++ b/src/MethodProxies/MpMethodProxy.class.st @@ -76,7 +76,7 @@ MpMethodProxy class >> buildPrototypesUpToArguments: maxNumberOfArguments [ "self buildPrototypesUpToArguments: 15" - | forwarders argumentListNodes prototypeTraps | + | forwarders prototypeTraps argumentListNodes | 0 to: maxNumberOfArguments do: [ :numberOfArguments | "There are different traps, optimized by handler" @@ -96,8 +96,23 @@ MpMethodProxy class >> buildPrototypesUpToArguments: maxNumberOfArguments [ originalAst selector: trapSelector. originalAst arguments: trapArguments. + "If we have less than 6 arguments, just call a method without boxing in an array" argumentListNodes := originalAst allChildren select: [ :e | e value = #argumentList ]. - argumentListNodes do: [ :e | e replaceWith: (RBArrayNode statements: trapArguments) ]. + trapArguments size < 6 ifTrue: [ + argumentListNodes do: [ :e | | newSelectorPart | + newSelectorPart := '' join: ((1 to: trapArguments size) collect: [ :i | 'with:' ]). + e parent selector: (e parent selector copyReplaceAll: 'arguments:' with: newSelectorPart). + (e parent selector beginsWith: #before) ifTrue: [ + "Expand the argument selector into a with:with:with: chain" + e parent arguments: (e parent arguments allButLast copyWithAll: (trapArguments collect: #copy)) + ] ifFalse: [ + "Expand the argument selector into a with:with:with: chain" + e parent arguments: (((e parent arguments allButLast: 2) copyWithAll: (trapArguments collect: #copy)) copyWith: e parent arguments last) + ] + ] + ] ifFalse: [ + argumentListNodes do: [ :e | e replaceWith: (RBArrayNode statements: trapArguments) ] + ]. forwarders := originalAst sendNodes select: [ :e | e selector = #originalMessage ]. forwarders do: [ :e | @@ -180,6 +195,45 @@ MpMethodProxy class >> prototypeTrapAfter [ ^ result ] +{ #category : 'evaluating' } +MpMethodProxy class >> prototypeTrapBefore [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ ^ self originalMessage ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ self originalMessage ]. + + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler beforeExecutionWithReceiver: self arguments: #argumentList. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self originalMessage. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + { #category : 'evaluating' } MpMethodProxy class >> prototypeTrapBeforeAfter [ "The unwind handler should be the first temp. @@ -276,7 +330,6 @@ MpMethodProxy class >> trapAfter [ wasMeta := true. result := #handler afterExecutionWithReceiver: self - arguments: { } returnValue: result. process shiftLevelDown. wasMeta := false. @@ -321,7 +374,7 @@ MpMethodProxy class >> trapAfterwith: arg1 [ wasMeta := true. result := #handler afterExecutionWithReceiver: self - arguments: { arg1 } + with: arg1 returnValue: result. process shiftLevelDown. wasMeta := false. @@ -366,9 +419,8 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 [ wasMeta := true. result := #handler afterExecutionWithReceiver: self - arguments: { - arg1. - arg2 } + with: arg1 + with: arg2 returnValue: result. process shiftLevelDown. wasMeta := false. @@ -413,10 +465,9 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 [ wasMeta := true. result := #handler afterExecutionWithReceiver: self - arguments: { - arg1. - arg2. - arg3 } + with: arg1 + with: arg2 + with: arg3 returnValue: result. process shiftLevelDown. wasMeta := false. @@ -465,11 +516,10 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 [ wasMeta := true. result := #handler afterExecutionWithReceiver: self - arguments: { - arg1. - arg2. - arg3. - arg4 } + with: arg1 + with: arg2 + with: arg3 + with: arg4 returnValue: result. process shiftLevelDown. wasMeta := false. @@ -519,12 +569,11 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with wasMeta := true. result := #handler afterExecutionWithReceiver: self - arguments: { - arg1. - arg2. - arg3. - arg4. - arg5 } + with: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 returnValue: result. process shiftLevelDown. wasMeta := false. @@ -1194,6 +1243,45 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with ^ result ] +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBefore [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ ^ self trapBefore ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ self trapBefore ]. + + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler beforeExecutionWithReceiver: self. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self trapBefore. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + { #category : 'as yet unclassified' } MpMethodProxy class >> trapBeforeAfter [ "The unwind handler should be the first temp. @@ -1217,7 +1305,7 @@ MpMethodProxy class >> trapBeforeAfter [ "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. - #handler beforeExecutionWithReceiver: self arguments: { }. + #handler beforeExecutionWithReceiver: self. process shiftLevelDown. wasMeta := false. @@ -1236,7 +1324,6 @@ MpMethodProxy class >> trapBeforeAfter [ wasMeta := true. result := #handler afterExecutionWithReceiver: self - arguments: { } returnValue: result. process shiftLevelDown. wasMeta := false. @@ -1269,7 +1356,7 @@ MpMethodProxy class >> trapBeforeAfterwith: arg1 [ "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. - #handler beforeExecutionWithReceiver: self arguments: { arg1 }. + #handler beforeExecutionWithReceiver: self with: arg1. process shiftLevelDown. wasMeta := false. @@ -1288,7 +1375,7 @@ MpMethodProxy class >> trapBeforeAfterwith: arg1 [ wasMeta := true. result := #handler afterExecutionWithReceiver: self - arguments: { arg1 } + with: arg1 returnValue: result. process shiftLevelDown. wasMeta := false. @@ -1321,9 +1408,7 @@ MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 [ "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. - #handler beforeExecutionWithReceiver: self arguments: { - arg1. - arg2 }. + #handler beforeExecutionWithReceiver: self with: arg1 with: arg2. process shiftLevelDown. wasMeta := false. @@ -1342,9 +1427,8 @@ MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 [ wasMeta := true. result := #handler afterExecutionWithReceiver: self - arguments: { - arg1. - arg2 } + with: arg1 + with: arg2 returnValue: result. process shiftLevelDown. wasMeta := false. @@ -1379,10 +1463,11 @@ MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 [ "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. - #handler beforeExecutionWithReceiver: self arguments: { - arg1. - arg2. - arg3 }. + #handler + beforeExecutionWithReceiver: self + with: arg1 + with: arg2 + with: arg3. process shiftLevelDown. wasMeta := false. @@ -1401,10 +1486,9 @@ MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 [ wasMeta := true. result := #handler afterExecutionWithReceiver: self - arguments: { - arg1. - arg2. - arg3 } + with: arg1 + with: arg2 + with: arg3 returnValue: result. process shiftLevelDown. wasMeta := false. @@ -1447,11 +1531,12 @@ MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. - #handler beforeExecutionWithReceiver: self arguments: { - arg1. - arg2. - arg3. - arg4 }. + #handler + beforeExecutionWithReceiver: self + with: arg1 + with: arg2 + with: arg3 + with: arg4. process shiftLevelDown. wasMeta := false. @@ -1474,11 +1559,10 @@ MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg wasMeta := true. result := #handler afterExecutionWithReceiver: self - arguments: { - arg1. - arg2. - arg3. - arg4 } + with: arg1 + with: arg2 + with: arg3 + with: arg4 returnValue: result. process shiftLevelDown. wasMeta := false. @@ -1523,12 +1607,13 @@ MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg "Move to the meta level and call the before hook" process shiftLevelUp. wasMeta := true. - #handler beforeExecutionWithReceiver: self arguments: { - arg1. - arg2. - arg3. - arg4. - arg5 }. + #handler + beforeExecutionWithReceiver: self + with: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5. process shiftLevelDown. wasMeta := false. @@ -1552,12 +1637,11 @@ MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg wasMeta := true. result := #handler afterExecutionWithReceiver: self - arguments: { - arg1. - arg2. - arg3. - arg4. - arg5 } + with: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 returnValue: result. process shiftLevelDown. wasMeta := false. @@ -2632,72 +2716,1144 @@ MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg ^ result ] -{ #category : 'installation' } -MpMethodProxy >> disableInstrumentation [ +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforewith: arg1 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" - self class disableInstrumentation -] + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ ^ self trapBeforewith: arg1 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ self trapBeforewith: arg1 ]. -{ #category : 'installation' } -MpMethodProxy >> enableInstrumentation [ + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. - self class enableInstrumentation -] + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler beforeExecutionWithReceiver: self with: arg1. + process shiftLevelDown. + wasMeta := false. -{ #category : 'accessing' } -MpMethodProxy >> handler [ + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self trapBeforewith: arg1. - ^ handler + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result ] -{ #category : 'accessing' } -MpMethodProxy >> handler: anObject [ - - handler := anObject -] +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforewith: arg1 with: arg2 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" -{ #category : 'installation' } -MpMethodProxy >> install [ + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ ^ self trapBeforewith: arg1 with: arg2 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ self trapBeforewith: arg1 with: arg2 ]. - | slowdeactivator newTrap index trapSelector | - - "Disable instrumentation during installation to make it safe. - We don't want to call instrumented methods when installing the instrumentation" - self disableInstrumentation. - - thisProcess runInMetaLevel: [ - (proxifiedMethod hasPragmaNamed: #noInstrumentation) ifTrue: [ - ^ MpCannotInstall signalWith: self ]. + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. - slowdeactivator := MpDeactivator withHandler: handler. + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler beforeExecutionWithReceiver: self with: arg1 with: arg2. + process shiftLevelDown. + wasMeta := false. - newTrap := self prototypeTrapMethod copy. - trapSelector := newTrap selector. - newTrap selector: proxifiedMethod selector. - newTrap methodClass: proxifiedMethod methodClass. + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self trapBeforewith: arg1 with: arg2. - hiddenSelector := MpHiddenSelector new - proxifiedSelector: proxifiedMethod selector; - yourself. + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] - index := newTrap literals indexOf: trapSelector. - newTrap literalAt: index put: hiddenSelector. +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" - index := newTrap literals indexOf: #handler. - newTrap literalAt: index put: handler. + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ ^ self trapBeforewith: arg1 with: arg2 with: arg3 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ + ^ self trapBeforewith: arg1 with: arg2 with: arg3 ]. - index := newTrap literals indexOf: #slowdeactivator. - newTrap literalAt: index put: slowdeactivator. + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. - "It could happen that a proxy wraps a proxy. Remember the object that was installed at this moment. - This is the object to restore during uninstall" - wrappedMethod := proxifiedMethod methodClass - methodDict at: proxifiedMethod selector. + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler + beforeExecutionWithReceiver: self + with: arg1 + with: arg2 + with: arg3. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self trapBeforewith: arg1 with: arg2 with: arg3. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 ]. + + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler + beforeExecutionWithReceiver: self + with: arg1 + with: arg2 + with: arg3 + with: arg4. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 ]. + + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler + beforeExecutionWithReceiver: self + with: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 ]. + + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler beforeExecutionWithReceiver: self arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6 }. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 ]. + + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler beforeExecutionWithReceiver: self arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7 }. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 ]. + + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler beforeExecutionWithReceiver: self arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8 }. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 ]. + + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler beforeExecutionWithReceiver: self arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8. + arg9 }. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 ]. + + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler beforeExecutionWithReceiver: self arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8. + arg9. + arg10 }. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 ]. + + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler beforeExecutionWithReceiver: self arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8. + arg9. + arg10. + arg11 }. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 ]. + + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler beforeExecutionWithReceiver: self arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8. + arg9. + arg10. + arg11. + arg12 }. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 ]. + + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler beforeExecutionWithReceiver: self arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8. + arg9. + arg10. + arg11. + arg12. + arg13 }. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 + with: arg14 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 + with: arg14 ]. + + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler beforeExecutionWithReceiver: self arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8. + arg9. + arg10. + arg11. + arg12. + arg13. + arg14 }. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 + with: arg14. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 with: arg15 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 + with: arg14 + with: arg15 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ + ^ self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 + with: arg14 + with: arg15 ]. + + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler beforeExecutionWithReceiver: self arguments: { + arg1. + arg2. + arg3. + arg4. + arg5. + arg6. + arg7. + arg8. + arg9. + arg10. + arg11. + arg12. + arg13. + arg14. + arg15 }. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self + trapBeforewith: arg1 + with: arg2 + with: arg3 + with: arg4 + with: arg5 + with: arg6 + with: arg7 + with: arg8 + with: arg9 + with: arg10 + with: arg11 + with: arg12 + with: arg13 + with: arg14 + with: arg15. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'installation' } +MpMethodProxy >> disableInstrumentation [ + + self class disableInstrumentation +] + +{ #category : 'installation' } +MpMethodProxy >> enableInstrumentation [ + + self class enableInstrumentation +] + +{ #category : 'accessing' } +MpMethodProxy >> handler [ + + ^ handler +] + +{ #category : 'accessing' } +MpMethodProxy >> handler: anObject [ + + handler := anObject +] + +{ #category : 'installation' } +MpMethodProxy >> install [ + + | slowdeactivator newTrap index trapSelector | + + "Disable instrumentation during installation to make it safe. + We don't want to call instrumented methods when installing the instrumentation" + self disableInstrumentation. + + thisProcess runInMetaLevel: [ + (proxifiedMethod hasPragmaNamed: #noInstrumentation) ifTrue: [ + ^ MpCannotInstall signalWith: self ]. + + slowdeactivator := MpDeactivator withHandler: handler. + + newTrap := self prototypeTrapMethod copy. + trapSelector := newTrap selector. + newTrap selector: proxifiedMethod selector. + newTrap methodClass: proxifiedMethod methodClass. + + hiddenSelector := MpHiddenSelector new + proxifiedSelector: proxifiedMethod selector; + yourself. + + index := newTrap literals indexOf: trapSelector. + newTrap literalAt: index put: hiddenSelector. + + index := newTrap literals indexOf: #handler. + index > 0 ifTrue: [ newTrap literalAt: index put: handler]. + + index := newTrap literals indexOf: #slowdeactivator. + newTrap literalAt: index put: slowdeactivator. + + "It could happen that a proxy wraps a proxy. Remember the object that was installed at this moment. + This is the object to restore during uninstall" + wrappedMethod := proxifiedMethod methodClass + methodDict at: proxifiedMethod selector. proxifiedMethod methodClass methodDict - at: hiddenSelector - put: proxifiedMethod. - proxifiedMethod methodClass methodDict + at: hiddenSelector + put: proxifiedMethod. + proxifiedMethod methodClass methodDict at: proxifiedMethod selector put: newTrap. @@ -2721,11 +3877,23 @@ MpMethodProxy >> methodClass [ { #category : 'installation' } MpMethodProxy >> prototypeTrapMethod [ - | trapSelector | + | trapSelector overridesBefore overridesAfter | "What kind of trap method do we want?" - trapSelector := handler overridesBeforeMethod - ifTrue: [ #trapBeforeAfter ] - ifFalse: [ #trapAfter ]. + overridesBefore := handler overridesBeforeMethodFor: proxifiedMethod numArgs. + overridesAfter := handler overridesAfterMethodFor: proxifiedMethod numArgs. + + trapSelector := overridesBefore + ifTrue: [ + overridesAfter + ifTrue: [ #trapBeforeAfter ] + ifFalse: [ #trapBefore ] ] + ifFalse: [ + overridesAfter + ifTrue: [ #trapAfter ] + ifFalse: [ + "If you override nothing, we instrument everything. + This will degrade performance but not present strange exceptions during installation" + #trapBeforeAfter ]]. ^ self class class methods detect: [ :m | m numArgs = proxifiedMethod numArgs and: [ diff --git a/src/MethodProxiesExamples/MpEmptyBeforeHandler.class.st b/src/MethodProxiesExamples/MpEmptyBeforeHandler.class.st index befa2f0..2c39e3f 100644 --- a/src/MethodProxiesExamples/MpEmptyBeforeHandler.class.st +++ b/src/MethodProxiesExamples/MpEmptyBeforeHandler.class.st @@ -12,5 +12,5 @@ Class { } { #category : 'as yet unclassified' } -MpEmptyBeforeHandler >> beforeExecutionWithReceiver: anObject arguments: anArrayOfObjects [ +MpEmptyBeforeHandler >> beforeExecutionWithReceiver: anObject [ ] From d6fe62e3395f640d7052d329c295e62c36d84560 Mon Sep 17 00:00:00 2001 From: Guille Polito Date: Thu, 18 Dec 2025 09:17:25 +0100 Subject: [PATCH 3/6] Specialize before handler --- src/MethodProxiesExamples/MpCountingHandler.class.st | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/MethodProxiesExamples/MpCountingHandler.class.st b/src/MethodProxiesExamples/MpCountingHandler.class.st index 675dba8..c7167c5 100644 --- a/src/MethodProxiesExamples/MpCountingHandler.class.st +++ b/src/MethodProxiesExamples/MpCountingHandler.class.st @@ -17,6 +17,12 @@ MpCountingHandler >> beforeExecutionWithReceiver: anObject arguments: anArrayOfO self count: self count + 1 ] +{ #category : 'evaluating' } +MpCountingHandler >> beforeExecutionWithReceiver: anObject with: argument [ + + self count: self count + 1 +] + { #category : 'accessing' } MpCountingHandler >> count [ From 236907ce7a387c4f36bd341452f250ac00e0ee4d Mon Sep 17 00:00:00 2001 From: Guille Polito Date: Thu, 18 Dec 2025 09:23:14 +0100 Subject: [PATCH 4/6] Fix trap name ambiguities in --- src/MethodProxies/MpMethodProxy.class.st | 299 ++++++++++++----------- 1 file changed, 150 insertions(+), 149 deletions(-) diff --git a/src/MethodProxies/MpMethodProxy.class.st b/src/MethodProxies/MpMethodProxy.class.st index 4e176a4..b3dc396 100644 --- a/src/MethodProxies/MpMethodProxy.class.st +++ b/src/MethodProxies/MpMethodProxy.class.st @@ -151,7 +151,7 @@ MpMethodProxy class >> onMethod: aMethod handler: aHandler [ ] { #category : 'evaluating' } -MpMethodProxy class >> prototypeTrapAfter [ +MpMethodProxy class >> prototypeTrapAfterOnly [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -196,7 +196,7 @@ MpMethodProxy class >> prototypeTrapAfter [ ] { #category : 'evaluating' } -MpMethodProxy class >> prototypeTrapBefore [ +MpMethodProxy class >> prototypeTrapBeforeAfter [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -229,13 +229,26 @@ MpMethodProxy class >> prototypeTrapBefore [ - this call is patched to use that symbol for the send" result := self originalMessage. + "Move to the meta level and call the after hooks. + Two after hooks are required. + One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns + The other indicates we are returning normally with a value." + process shiftLevelUp. + wasMeta := true. + result := #handler + afterExecutionWithReceiver: self + arguments: #argumentList + returnValue: result. + process shiftLevelDown. + wasMeta := false. + "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result ] { #category : 'evaluating' } -MpMethodProxy class >> prototypeTrapBeforeAfter [ +MpMethodProxy class >> prototypeTrapBeforeOnly [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -268,19 +281,6 @@ MpMethodProxy class >> prototypeTrapBeforeAfter [ - this call is patched to use that symbol for the send" result := self originalMessage. - "Move to the meta level and call the after hooks. - Two after hooks are required. - One indicates the method is returning either because a normal return, or a stack unwind due to exceptions or non-local returns - The other indicates we are returning normally with a value." - process shiftLevelUp. - wasMeta := true. - result := #handler - afterExecutionWithReceiver: self - arguments: #argumentList - returnValue: result. - process shiftLevelDown. - wasMeta := false. - "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. ^ result @@ -296,7 +296,7 @@ MpMethodProxy class >> proxyMethod: method handler: aHandler [ ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfter [ +MpMethodProxy class >> trapAfterOnly [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -316,7 +316,7 @@ MpMethodProxy class >> trapAfter [ The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" - result := self trapAfter. + result := self trapAfterOnly. ENABLED ifFalse: [ ^ result ]. process := Processor activeProcess. @@ -340,7 +340,7 @@ MpMethodProxy class >> trapAfter [ ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfterwith: arg1 [ +MpMethodProxy class >> trapAfterOnlywith: arg1 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -360,7 +360,7 @@ MpMethodProxy class >> trapAfterwith: arg1 [ The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" - result := self trapAfterwith: arg1. + result := self trapAfterOnlywith: arg1. ENABLED ifFalse: [ ^ result ]. process := Processor activeProcess. @@ -385,7 +385,7 @@ MpMethodProxy class >> trapAfterwith: arg1 [ ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfterwith: arg1 with: arg2 [ +MpMethodProxy class >> trapAfterOnlywith: arg1 with: arg2 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -405,7 +405,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 [ The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" - result := self trapAfterwith: arg1 with: arg2. + result := self trapAfterOnlywith: arg1 with: arg2. ENABLED ifFalse: [ ^ result ]. process := Processor activeProcess. @@ -431,7 +431,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 [ ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 [ +MpMethodProxy class >> trapAfterOnlywith: arg1 with: arg2 with: arg3 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -451,7 +451,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 [ The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" - result := self trapAfterwith: arg1 with: arg2 with: arg3. + result := self trapAfterOnlywith: arg1 with: arg2 with: arg3. ENABLED ifFalse: [ ^ result ]. process := Processor activeProcess. @@ -478,7 +478,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 [ ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 [ +MpMethodProxy class >> trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -499,7 +499,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 [ - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapAfterwith: arg1 + trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4. @@ -530,7 +530,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 [ ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 [ +MpMethodProxy class >> trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -551,7 +551,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapAfterwith: arg1 + trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -584,7 +584,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 [ +MpMethodProxy class >> trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -605,7 +605,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapAfterwith: arg1 + trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -641,7 +641,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 [ +MpMethodProxy class >> trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -662,7 +662,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapAfterwith: arg1 + trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -700,7 +700,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 [ +MpMethodProxy class >> trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -721,7 +721,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapAfterwith: arg1 + trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -761,7 +761,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 [ +MpMethodProxy class >> trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -782,7 +782,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapAfterwith: arg1 + trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -824,7 +824,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 [ +MpMethodProxy class >> trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -845,7 +845,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapAfterwith: arg1 + trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -889,7 +889,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 [ +MpMethodProxy class >> trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -910,7 +910,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapAfterwith: arg1 + trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -956,7 +956,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 [ +MpMethodProxy class >> trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -977,7 +977,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapAfterwith: arg1 + trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -1025,7 +1025,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 [ +MpMethodProxy class >> trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -1046,7 +1046,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapAfterwith: arg1 + trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -1096,7 +1096,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 [ +MpMethodProxy class >> trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -1117,7 +1117,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapAfterwith: arg1 + trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -1169,7 +1169,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 with: arg15 [ +MpMethodProxy class >> trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 with: arg15 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -1190,7 +1190,7 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapAfterwith: arg1 + trapAfterOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -1243,45 +1243,6 @@ MpMethodProxy class >> trapAfterwith: arg1 with: arg2 with: arg3 with: arg4 with ^ result ] -{ #category : 'as yet unclassified' } -MpMethodProxy class >> trapBefore [ - "The unwind handler should be the first temp. - The complete flag should be the second temp. - The last temp variable should be the wasMeta flag. - Then this method is free to use as many extra temporaries and arguments as is wants" - - - - - - | deactivator complete result process wasMeta | - ENABLED ifFalse: [ ^ self trapBefore ]. - process := Processor activeProcess. - process isMeta ifTrue: [ ^ self trapBefore ]. - - "Set the deactivator literal for the slow path. - It will be patched to an exception handler" - deactivator := #slowdeactivator. - - "Move to the meta level and call the before hook" - process shiftLevelUp. - wasMeta := true. - #handler beforeExecutionWithReceiver: self. - process shiftLevelDown. - wasMeta := false. - - "Back in the base-level forward the original message. - This is a message to self that will be monomorphically linked by the VM. - The core idea is that - - the original method is installed in the same method dictionary using a unique symbol - - this call is patched to use that symbol for the send" - result := self trapBefore. - - "Mark the execution as complete to avoid double execution of the unwind handler" - complete := true. - ^ result -] - { #category : 'as yet unclassified' } MpMethodProxy class >> trapBeforeAfter [ "The unwind handler should be the first temp. @@ -2717,7 +2678,7 @@ MpMethodProxy class >> trapBeforeAfterwith: arg1 with: arg2 with: arg3 with: arg ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapBeforewith: arg1 [ +MpMethodProxy class >> trapBeforeOnly [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -2728,9 +2689,48 @@ MpMethodProxy class >> trapBeforewith: arg1 [ | deactivator complete result process wasMeta | - ENABLED ifFalse: [ ^ self trapBeforewith: arg1 ]. + ENABLED ifFalse: [ ^ self trapBeforeOnly ]. process := Processor activeProcess. - process isMeta ifTrue: [ ^ self trapBeforewith: arg1 ]. + process isMeta ifTrue: [ ^ self trapBeforeOnly ]. + + "Set the deactivator literal for the slow path. + It will be patched to an exception handler" + deactivator := #slowdeactivator. + + "Move to the meta level and call the before hook" + process shiftLevelUp. + wasMeta := true. + #handler beforeExecutionWithReceiver: self. + process shiftLevelDown. + wasMeta := false. + + "Back in the base-level forward the original message. + This is a message to self that will be monomorphically linked by the VM. + The core idea is that + - the original method is installed in the same method dictionary using a unique symbol + - this call is patched to use that symbol for the send" + result := self trapBeforeOnly. + + "Mark the execution as complete to avoid double execution of the unwind handler" + complete := true. + ^ result +] + +{ #category : 'as yet unclassified' } +MpMethodProxy class >> trapBeforeOnlywith: arg1 [ + "The unwind handler should be the first temp. + The complete flag should be the second temp. + The last temp variable should be the wasMeta flag. + Then this method is free to use as many extra temporaries and arguments as is wants" + + + + + + | deactivator complete result process wasMeta | + ENABLED ifFalse: [ ^ self trapBeforeOnlywith: arg1 ]. + process := Processor activeProcess. + process isMeta ifTrue: [ ^ self trapBeforeOnlywith: arg1 ]. "Set the deactivator literal for the slow path. It will be patched to an exception handler" @@ -2748,7 +2748,7 @@ MpMethodProxy class >> trapBeforewith: arg1 [ The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" - result := self trapBeforewith: arg1. + result := self trapBeforeOnlywith: arg1. "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. @@ -2756,7 +2756,7 @@ MpMethodProxy class >> trapBeforewith: arg1 [ ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapBeforewith: arg1 with: arg2 [ +MpMethodProxy class >> trapBeforeOnlywith: arg1 with: arg2 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -2767,9 +2767,9 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 [ | deactivator complete result process wasMeta | - ENABLED ifFalse: [ ^ self trapBeforewith: arg1 with: arg2 ]. + ENABLED ifFalse: [ ^ self trapBeforeOnlywith: arg1 with: arg2 ]. process := Processor activeProcess. - process isMeta ifTrue: [ ^ self trapBeforewith: arg1 with: arg2 ]. + process isMeta ifTrue: [ ^ self trapBeforeOnlywith: arg1 with: arg2 ]. "Set the deactivator literal for the slow path. It will be patched to an exception handler" @@ -2787,7 +2787,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 [ The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" - result := self trapBeforewith: arg1 with: arg2. + result := self trapBeforeOnlywith: arg1 with: arg2. "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. @@ -2795,7 +2795,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 [ ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 [ +MpMethodProxy class >> trapBeforeOnlywith: arg1 with: arg2 with: arg3 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -2806,10 +2806,11 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 [ | deactivator complete result process wasMeta | - ENABLED ifFalse: [ ^ self trapBeforewith: arg1 with: arg2 with: arg3 ]. + ENABLED ifFalse: [ + ^ self trapBeforeOnlywith: arg1 with: arg2 with: arg3 ]. process := Processor activeProcess. process isMeta ifTrue: [ - ^ self trapBeforewith: arg1 with: arg2 with: arg3 ]. + ^ self trapBeforeOnlywith: arg1 with: arg2 with: arg3 ]. "Set the deactivator literal for the slow path. It will be patched to an exception handler" @@ -2831,7 +2832,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 [ The core idea is that - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" - result := self trapBeforewith: arg1 with: arg2 with: arg3. + result := self trapBeforeOnlywith: arg1 with: arg2 with: arg3. "Mark the execution as complete to avoid double execution of the unwind handler" complete := true. @@ -2839,7 +2840,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 [ ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 [ +MpMethodProxy class >> trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -2852,14 +2853,14 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 [ | deactivator complete result process wasMeta | ENABLED ifFalse: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 ]. process := Processor activeProcess. process isMeta ifTrue: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 ]. @@ -2886,7 +2887,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 [ - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4. @@ -2897,7 +2898,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 [ ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 [ +MpMethodProxy class >> trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -2910,7 +2911,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit | deactivator complete result process wasMeta | ENABLED ifFalse: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -2918,7 +2919,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit process := Processor activeProcess. process isMeta ifTrue: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -2947,7 +2948,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -2959,7 +2960,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 [ +MpMethodProxy class >> trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -2972,7 +2973,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit | deactivator complete result process wasMeta | ENABLED ifFalse: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -2981,7 +2982,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit process := Processor activeProcess. process isMeta ifTrue: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3011,7 +3012,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3024,7 +3025,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 [ +MpMethodProxy class >> trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -3037,7 +3038,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit | deactivator complete result process wasMeta | ENABLED ifFalse: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3047,7 +3048,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit process := Processor activeProcess. process isMeta ifTrue: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3079,7 +3080,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3093,7 +3094,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 [ +MpMethodProxy class >> trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -3106,7 +3107,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit | deactivator complete result process wasMeta | ENABLED ifFalse: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3117,7 +3118,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit process := Processor activeProcess. process isMeta ifTrue: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3151,7 +3152,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3166,7 +3167,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 [ +MpMethodProxy class >> trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -3179,7 +3180,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit | deactivator complete result process wasMeta | ENABLED ifFalse: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3191,7 +3192,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit process := Processor activeProcess. process isMeta ifTrue: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3227,7 +3228,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3243,7 +3244,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 [ +MpMethodProxy class >> trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -3256,7 +3257,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit | deactivator complete result process wasMeta | ENABLED ifFalse: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3269,7 +3270,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit process := Processor activeProcess. process isMeta ifTrue: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3307,7 +3308,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3324,7 +3325,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 [ +MpMethodProxy class >> trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -3337,7 +3338,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit | deactivator complete result process wasMeta | ENABLED ifFalse: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3351,7 +3352,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit process := Processor activeProcess. process isMeta ifTrue: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3391,7 +3392,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3409,7 +3410,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 [ +MpMethodProxy class >> trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -3422,7 +3423,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit | deactivator complete result process wasMeta | ENABLED ifFalse: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3437,7 +3438,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit process := Processor activeProcess. process isMeta ifTrue: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3479,7 +3480,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3498,7 +3499,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 [ +MpMethodProxy class >> trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -3511,7 +3512,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit | deactivator complete result process wasMeta | ENABLED ifFalse: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3527,7 +3528,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit process := Processor activeProcess. process isMeta ifTrue: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3571,7 +3572,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3591,7 +3592,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 [ +MpMethodProxy class >> trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -3604,7 +3605,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit | deactivator complete result process wasMeta | ENABLED ifFalse: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3621,7 +3622,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit process := Processor activeProcess. process isMeta ifTrue: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3667,7 +3668,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3688,7 +3689,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit ] { #category : 'as yet unclassified' } -MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 with: arg15 [ +MpMethodProxy class >> trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 with: arg5 with: arg6 with: arg7 with: arg8 with: arg9 with: arg10 with: arg11 with: arg12 with: arg13 with: arg14 with: arg15 [ "The unwind handler should be the first temp. The complete flag should be the second temp. The last temp variable should be the wasMeta flag. @@ -3701,7 +3702,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit | deactivator complete result process wasMeta | ENABLED ifFalse: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3719,7 +3720,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit process := Processor activeProcess. process isMeta ifTrue: [ ^ self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3767,7 +3768,7 @@ MpMethodProxy class >> trapBeforewith: arg1 with: arg2 with: arg3 with: arg4 wit - the original method is installed in the same method dictionary using a unique symbol - this call is patched to use that symbol for the send" result := self - trapBeforewith: arg1 + trapBeforeOnlywith: arg1 with: arg2 with: arg3 with: arg4 @@ -3886,10 +3887,10 @@ MpMethodProxy >> prototypeTrapMethod [ ifTrue: [ overridesAfter ifTrue: [ #trapBeforeAfter ] - ifFalse: [ #trapBefore ] ] + ifFalse: [ #trapBeforeOnly ] ] ifFalse: [ overridesAfter - ifTrue: [ #trapAfter ] + ifTrue: [ #trapAfterOnly ] ifFalse: [ "If you override nothing, we instrument everything. This will degrade performance but not present strange exceptions during installation" From 22576c509b69180484adb9ccca6f395d31e23258 Mon Sep 17 00:00:00 2001 From: Guille Polito Date: Thu, 18 Dec 2025 09:39:56 +0100 Subject: [PATCH 5/6] Implement optimized hooks --- .../MpCountingHandler.class.st | 6 ++++++ .../MpEmptyHandlerAfter.class.st | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/MethodProxiesExamples/MpCountingHandler.class.st b/src/MethodProxiesExamples/MpCountingHandler.class.st index c7167c5..7bfd051 100644 --- a/src/MethodProxiesExamples/MpCountingHandler.class.st +++ b/src/MethodProxiesExamples/MpCountingHandler.class.st @@ -11,6 +11,12 @@ Class { #package : 'MethodProxiesExamples' } +{ #category : 'evaluating' } +MpCountingHandler >> beforeExecutionWithReceiver: anObject [ + + self count: self count + 1 +] + { #category : 'evaluating' } MpCountingHandler >> beforeExecutionWithReceiver: anObject arguments: anArrayOfObjects [ diff --git a/src/MethodProxiesExamples/MpEmptyHandlerAfter.class.st b/src/MethodProxiesExamples/MpEmptyHandlerAfter.class.st index 1da1b1a..5d90071 100644 --- a/src/MethodProxiesExamples/MpEmptyHandlerAfter.class.st +++ b/src/MethodProxiesExamples/MpEmptyHandlerAfter.class.st @@ -16,3 +16,23 @@ MpEmptyHandlerAfter >> afterExecutionWithReceiver: anObject arguments: anArrayOf ^ retVal ] + +{ #category : 'evaluating' } +MpEmptyHandlerAfter >> afterExecutionWithReceiver: anObject returnValue: retVal [ + + ^ retVal +] + +{ #category : 'evaluating' } +MpEmptyHandlerAfter >> afterExecutionWithReceiver: anObject with: arg returnValue: retVal [ + + ^ retVal +] + +{ #category : 'evaluating' } +MpEmptyHandlerAfter >> beforeExecutionWithReceiver: anObject [ +] + +{ #category : 'evaluating' } +MpEmptyHandlerAfter >> beforeExecutionWithReceiver: anObject with: arg [ +] From d67637aafe2d248a077484431d8d00bbce1a4d69 Mon Sep 17 00:00:00 2001 From: Guille Polito Date: Thu, 18 Dec 2025 10:29:00 +0100 Subject: [PATCH 6/6] Fix detection of last temp index --- src/MethodProxies/MpDeactivator.class.st | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/MethodProxies/MpDeactivator.class.st b/src/MethodProxies/MpDeactivator.class.st index d1cd444..ebe4f07 100644 --- a/src/MethodProxies/MpDeactivator.class.st +++ b/src/MethodProxies/MpDeactivator.class.st @@ -19,8 +19,16 @@ Class { { #category : 'class initialization' } MpDeactivator class >> initialize [ - WasMetaTempVariableIndex := (MpMethodProxy class >> #prototypeTrap) numTemps. "last temp" - CompleteTempVariableIndex := 2 "always the second temp" + | prototypeTraps tempIndexes | + prototypeTraps := MpMethodProxy class methods select: [ :e | + e hasPragmaNamed: #prototypeTrap ]. + + "Consider only the last temp, and verify that they all agree" + tempIndexes := prototypeTraps collect: [ :e | e numTemps ] as: Set. + self assert: tempIndexes size = 1. + + WasMetaTempVariableIndex := tempIndexes anyOne. + CompleteTempVariableIndex := 2 "always the second temp" ] { #category : 'as yet unclassified' }