diff --git a/Sindarin-Tests/SindarinBytecodeToASTCacheTest.class.st b/Sindarin-Tests/SindarinBytecodeToASTCacheTest.class.st deleted file mode 100644 index de79409..0000000 --- a/Sindarin-Tests/SindarinBytecodeToASTCacheTest.class.st +++ /dev/null @@ -1,80 +0,0 @@ -Class { - #name : #SindarinBytecodeToASTCacheTest, - #superclass : #TestCase, - #instVars : [ - 'cache', - 'compiledMethod' - ], - #category : #'Sindarin-Tests' -} - -{ #category : #running } -SindarinBytecodeToASTCacheTest >> setUp [ - "Hooks that subclasses may override to define the fixture of test." - super setUp. - compiledMethod := SindarinDebuggerTest >> #helperMethod12. - cache := SindarinBytecodeToASTCache generateForCompiledMethod: compiledMethod -] - -{ #category : #helpers } -SindarinBytecodeToASTCacheTest >> testCacheInInterval: interval equalsNode: aNode [ - interval do: [ :i | - self assert: (cache nodeForPC: i) identicalTo: aNode ] -] - -{ #category : #tests } -SindarinBytecodeToASTCacheTest >> testCachedMethodNode [ - self assert: cache methodNode identicalTo: compiledMethod ast -] - -{ #category : #tests } -SindarinBytecodeToASTCacheTest >> testFirstBCOffsetTest [ - self assert: cache firstBcOffset equals: compiledMethod initialPC -] - -{ #category : #tests } -SindarinBytecodeToASTCacheTest >> testHigherThanLastBCOffsetAccessTest [ - | pc | - pc := cache lastBcOffset + 5. - self - assert: (cache nodeForPC: pc) - identicalTo: (compiledMethod sourceNodeForPC: pc) -] - -{ #category : #tests } -SindarinBytecodeToASTCacheTest >> testLastBCOffsetTest [ - self - assert: cache lastBcOffset - equals: - compiledMethod ast ir startSequence withAllSuccessors last last - bytecodeOffset -] - -{ #category : #tests } -SindarinBytecodeToASTCacheTest >> testLowerThanFirstBCOffsetAccessTest [ - self - testCacheInInterval: (0 to: cache firstBcOffset - 1) - equalsNode: compiledMethod ast -] - -{ #category : #tests } -SindarinBytecodeToASTCacheTest >> testNodeForBCOffsetRangeTest [ - "As we associate each node to each possible bytecode offset that can refer to it, - we have to check that associations are consistent between a range and a node" - - | pcRange | - pcRange := 0 to: cache lastBcOffset. - pcRange do: [ :pc | - self - assert: (cache nodeForPC: pc) - identicalTo: (compiledMethod sourceNodeForPC: pc) ] -] - -{ #category : #tests } -SindarinBytecodeToASTCacheTest >> testNodeForBCOffsetTest [ - | pc | - pc := 51. - self - assert: (cache nodeForPC: pc) - identicalTo: (compiledMethod sourceNodeForPC: pc) -] diff --git a/Sindarin/SindarinBytecodeToASTCache.class.st b/Sindarin/SindarinBytecodeToASTCache.class.st deleted file mode 100644 index 6f5cd72..0000000 --- a/Sindarin/SindarinBytecodeToASTCache.class.st +++ /dev/null @@ -1,91 +0,0 @@ -" -I cache a mapping between possible bytecode offsets and the AST nodes they correspond to for a given compiled method. - -Instanciate me using my class method generateForCompiledMethod: and give me as parameter a compiled method. - -Use me through the node access API method nodeForPC: and give me a program counter as parameter. - -I store: -- firstBcOffset: The first bytecode pc. If you try to access a pc below that first pc, I return the method node. -- lastBcOffset: The last bytecode pc. If you try to access a pc after this last pc, I return the node associated with the last pc. -- bcToASTMap: A map associating each possible pc between firstBcOffset and lastBcOffset and the corresponding ast node. -- the methode node. -" -Class { - #name : #SindarinBytecodeToASTCache, - #superclass : #Object, - #instVars : [ - 'firstBcOffset', - 'lastBcOffset', - 'bcToASTMap', - 'methodNode' - ], - #category : #Sindarin -} - -{ #category : #initialization } -SindarinBytecodeToASTCache class >> generateForCompiledMethod: compiledMethod [ - ^self new generateForCompiledMethod: compiledMethod -] - -{ #category : #accessing } -SindarinBytecodeToASTCache >> bcToASTMap [ - ^ bcToASTMap -] - -{ #category : #private } -SindarinBytecodeToASTCache >> fillMissingBCOffsetsWithLastBCOffsetNodes [ - "It happens that different bytecode offsets map to the same AST node. - These cases are detected when there is no node mapped between, for example, bcOffset 46 and bcOffset 50. - In that case, we take every possible bytecode index between 46 and 50 (i.e., 47, 48, 49), - and we map them to the same node as the last mapped bytecode offset, here 46." - - | sortedBCOffsets | - sortedBCOffsets := bcToASTMap keys asSortedCollection. - 1 to: sortedBCOffsets size - 1 do: [ :index | - | bcAtIndex bcAtNextIndex | - bcAtIndex := sortedBCOffsets at: index. - bcAtNextIndex := sortedBCOffsets at: index + 1. - bcAtIndex < bcAtNextIndex ifTrue: [ - bcAtIndex to: bcAtNextIndex - 1 do: [ :i | - bcToASTMap at: i put: (bcToASTMap at: bcAtIndex) ] ] ] -] - -{ #category : #accessing } -SindarinBytecodeToASTCache >> firstBcOffset [ - ^ firstBcOffset -] - -{ #category : #initialization } -SindarinBytecodeToASTCache >> generateForCompiledMethod: compiledMethod [ - | methodIR currentBcOffset | - methodNode := compiledMethod ast. - methodIR := methodNode ir. - bcToASTMap := Dictionary new. - firstBcOffset := compiledMethod initialPC. - currentBcOffset := firstBcOffset. - methodIR startSequence withAllSuccessors do: [ :seq | - seq do: [ :ir | - ir ifNotNil: [ - bcToASTMap at: ir bytecodeOffset ifAbsentPut: [ ir sourceNode ]. - currentBcOffset := ir bytecodeOffset + 1 ] ] ]. - lastBcOffset := currentBcOffset - 1. - self fillMissingBCOffsetsWithLastBCOffsetNodes -] - -{ #category : #accessing } -SindarinBytecodeToASTCache >> lastBcOffset [ - ^ lastBcOffset -] - -{ #category : #accessing } -SindarinBytecodeToASTCache >> methodNode [ - ^ methodNode -] - -{ #category : #'node access' } -SindarinBytecodeToASTCache >> nodeForPC: pc [ - pc < firstBcOffset ifTrue: [ ^ methodNode ]. - pc > lastBcOffset ifTrue: [ ^ bcToASTMap at: lastBcOffset ]. - ^ bcToASTMap at: pc -] diff --git a/Sindarin/SindarinDebugger.class.st b/Sindarin/SindarinDebugger.class.st index fe482a6..45e2bf9 100644 --- a/Sindarin/SindarinDebugger.class.st +++ b/Sindarin/SindarinDebugger.class.st @@ -20,8 +20,6 @@ Class { #instVars : [ 'process', 'stepHooks', - 'nodeMapForMethod', - 'debugStarted', 'sindarinSession', 'blockToDebug' ], @@ -86,8 +84,7 @@ SindarinDebugger >> attachTo: aDebugSession [ sindarinSession := aDebugSession asSindarinDebugSession. process := aDebugSession interruptedProcess. - sindarinSession deactivateEventTriggering. - debugStarted := true + sindarinSession deactivateEventTriggering ] { #category : #astAndAstMapping } @@ -107,7 +104,7 @@ SindarinDebugger >> contextIsAboutToSignalException: aContext [ "Returns whether aContext is about to execute a message-send of selector #signal to an instance of the Exception class (or one of its subclasses)" | node | - node := (self nodeMapForMethod: aContext method) nodeForPC: aContext pc. + node := aContext method methodNode bcToASTCache nodeForPC: aContext pc. node isMessage ifFalse: [ ^ false ]. node selector = #signal @@ -191,7 +188,6 @@ SindarinDebugger >> debug: aBlock [ sindarinSession deactivateEventTriggering. [ self selector = #newProcess ] whileFalse: [ self step ]. "Step the process to get out of the on:do: context added at the bottom of its stack" [ self selector = #newProcess ] whileTrue: [ self step ]. "Step the process so that it leaves BlockClosure>>#newProcess and enters the block for which a process was created" - debugStarted := true ] { #category : #accessing } @@ -209,8 +205,7 @@ SindarinDebugger >> hasSignalledUnhandledException [ { #category : #initialization } SindarinDebugger >> initialize [ - stepHooks := OrderedCollection new. - debugStarted := false + stepHooks := OrderedCollection new ] { #category : #private } @@ -321,13 +316,7 @@ SindarinDebugger >> method [ SindarinDebugger >> node [ "Returns the AST node about to be executed by the top context of the execution" - debugStarted - ifFalse: - [ "Until the debug session is started, node is returned using the unoptimized version" "Sindarin starts by executing controlled steps to exit the caller code (e.g. tests) - before entering the actual debugged code, and we do not want to cache nodes for the - caller code." ^ self context method sourceNodeForPC: self context pc ]. - "Once the hand is given to the tool or user, we start caching nodes for better performance" - ^ self nodeMap nodeForPC: self context pc + ^ self context method sourceNodeForPC: self context pc ] { #category : #astAndAstMapping } @@ -337,22 +326,6 @@ SindarinDebugger >> nodeForContext: aContext [ ^ aContext method sourceNodeForPC: aContext pc ] -{ #category : #astAndAstMapping } -SindarinDebugger >> nodeMap [ - ^ self nodeMapForMethod: self context method -] - -{ #category : #astAndAstMapping } -SindarinDebugger >> nodeMapForMethod: aCompiledMethod [ - nodeMapForMethod ifNil: [ nodeMapForMethod := Dictionary new ]. - ^ (nodeMapForMethod - at: aCompiledMethod methodClass name - ifAbsentPut: [ Dictionary new ]) - at: aCompiledMethod selector - ifAbsentPut: [ SindarinBytecodeToASTCache - generateForCompiledMethod: aCompiledMethod ] -] - { #category : #'graphical debugger' } SindarinDebugger >> openInGraphicalDebugger [ sindarinSession canBeTerminated: false. "Prevents the graphical debugger from terminating the debug session when it's closed."