Eliot Miranda uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-eem.1143.mcz
==================== Summary ====================
Name: Kernel-eem.1143
Author: eem
Time: 11 January 2018, 12:46:50.669083 pm
UUID: 304608ac-b9d3-459b-813b-fd0c960a5911
Ancestors: Kernel-eem.1142
CompiledBlock>>numCopiedValues has utility
=============== Diff against Kernel-eem.1142 ===============
Item was added:
+ ----- Method: CompiledBlock>>numCopiedValues (in category 'accessing') -----
+ numCopiedValues
+ "Answer the number of copied values the receiver expects.
+ This is not fast as it is not expected to be needed from the
+ compiled block itself. It is available cheaply from a block
+ closure for the method."
+
+ | locator scanner pc |
+ locator := BlockStartLocator new.
+ scanner := InstructionStream on: self outerCode.
+ [pc := scanner pc.
+ self == (scanner interpretNextInstructionFor: locator) ifTrue:
+ [^(self outerCode abstractBytecodeMessageAt: pc) arguments second].
+ scanner atEnd] whileFalse.
+ self error: 'cannot find the block creation bytecode for this compiled block in its outer code.'!
Eliot Miranda uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-eem.1142.mcz
==================== Summary ====================
Name: Kernel-eem.1142
Author: eem
Time: 11 January 2018, 10:48:34.716679 am
UUID: 7a417b5f-f076-48e5-804c-cce7235fe71b
Ancestors: Kernel-eem.1141
Provide the full properties and pragmas protocol in CompiledBlock, deferring to outer method. (It would be nice to prune this at some stage).
=============== Diff against Kernel-eem.1141 ===============
Item was added:
+ ----- Method: CompiledBlock>>pragmas (in category 'accessing-pragmas & properties') -----
+ pragmas
+ ^self homeMethod pragmas!
Item was added:
+ ----- Method: CompiledBlock>>propertyKeysAndValuesDo: (in category 'accessing-pragmas & properties') -----
+ propertyKeysAndValuesDo: aBlock
+ "Enumerate the receiver with all the keys and values."
+ ^self homeMethod propertyKeysAndValuesDo: aBlock!
Item was added:
+ ----- Method: CompiledBlock>>propertyValueAt: (in category 'accessing-pragmas & properties') -----
+ propertyValueAt: propName
+ ^self homeMethod propertyValueAt: propName!
Item was added:
+ ----- Method: CompiledBlock>>propertyValueAt:ifAbsent: (in category 'accessing-pragmas & properties') -----
+ propertyValueAt: propName ifAbsent: aBlock
+ ^self homeMethod propertyValueAt: propName ifAbsent: aBlock!
Item was added:
+ ----- Method: CompiledBlock>>propertyValueAt:put: (in category 'accessing-pragmas & properties') -----
+ propertyValueAt: propName put: propValue
+ "Set or add the property with key propName and value propValue.
+ If the receiver does not yet have a method properties create one and replace
+ the selector with it. Otherwise, either relace propValue in the method properties
+ or replace method properties with one containing the new property."
+ ^self homeMethod propertyValueAt: propName put: propValue!
Item was added:
+ ----- Method: CompiledBlock>>removeProperty: (in category 'accessing-pragmas & properties') -----
+ removeProperty: propName
+ "Remove the property propName if it exists.
+ Do _not_ raise an error if the property is missing."
+ ^self homeMethod removeProperty: propName!
Item was added:
+ ----- Method: CompiledBlock>>removeProperty:ifAbsent: (in category 'accessing-pragmas & properties') -----
+ removeProperty: propName ifAbsent: aBlock
+ "Remove the property propName if it exists.
+ Answer the evaluation of aBlock if the property is missing."
+ ^self homeMethod removeProperty: propName ifAbsent: aBlock!
Eliot Miranda uploaded a new version of Compiler to project The Trunk:
http://source.squeak.org/trunk/Compiler-eem.372.mcz
==================== Summary ====================
Name: Compiler-eem.372
Author: eem
Time: 11 January 2018, 9:30:54.229387 am
UUID: 692e5c85-e068-42df-9404-266f9bd3c93f
Ancestors: Compiler-eem.371
Move BlockLocalTempCounter to Kernel. It is used to implement BlockClosure>>numTemps, which is used more broadly than simply the decompiler and debugger.
=============== Diff against Compiler-eem.371 ===============
Item was removed:
- InstructionClient subclass: #BlockLocalTempCounter
- instanceVariableNames: 'stackPointer scanner blockEnd joinOffsets'
- classVariableNames: ''
- poolDictionaries: ''
- category: 'Compiler-Support'!
-
- !BlockLocalTempCounter commentStamp: 'eem 1/11/2018 08:30' prior: 0!
- I am a support class for the decompiler that is used to find the number of local temps in a block by finding out what the stack offset is at the end of a block. I am necessary because in the EncoderForV3PlusClosures bytecode set the only way to initialize block-local temporaries is with pushConstant: nil bytecodes, but such bytecodes are ambiguous with a pushConstant: nil used to pass nil as a parameter or answer it as a result. By scanning through to the end of the block these can be disambiguated by tracking the stack depth.!
Item was removed:
- ----- Method: BlockLocalTempCounter class>>tempCountForBlockAt:in: (in category 'instance creation') -----
- tempCountForBlockAt: pc in: method
- ^self new tempCountForBlockAt: pc in: method!
Item was removed:
- ----- Method: BlockLocalTempCounter class>>tempCountForBlockStartingAt:in: (in category 'instance creation') -----
- tempCountForBlockStartingAt: startpc in: method
- ^self new
- tempCountForBlockAt: (method encoderClass pcOfBlockCreationBytecodeForBlockStartingAt: startpc in: method)
- in: method!
Item was removed:
- ----- Method: BlockLocalTempCounter>>blockReturnConstant: (in category 'instruction decoding') -----
- blockReturnConstant: value
- "Return Constant From Block bytecode."
- scanner pc < blockEnd ifTrue:
- [self doJoin]!
Item was removed:
- ----- Method: BlockLocalTempCounter>>blockReturnTop (in category 'instruction decoding') -----
- blockReturnTop
- "Return Top Of Stack bytecode."
- stackPointer := stackPointer - 1.
- scanner pc < blockEnd ifTrue:
- [self doJoin]!
Item was removed:
- ----- Method: BlockLocalTempCounter>>directedSuperSend:numArgs: (in category 'instruction decoding') -----
- directedSuperSend: selector numArgs: numArgs
- "Send Message Above Specific Class With Selector, selector, bytecode.
- Start the lookup above the class that is the value of the association on
- top of stack. The arguments of the message are found in the top numArgs
- stack locations beneath the association, and the receiver just below them."
-
- stackPointer := stackPointer - (numArgs + 1)!
Item was removed:
- ----- Method: BlockLocalTempCounter>>doDup (in category 'instruction decoding') -----
- doDup
- "Duplicate Top Of Stack bytecode."
- stackPointer := stackPointer + 1!
Item was removed:
- ----- Method: BlockLocalTempCounter>>doJoin (in category 'private') -----
- doJoin
- scanner pc < blockEnd ifTrue:
- [stackPointer := joinOffsets at: scanner pc ifAbsent: [scanner followingPc]]
-
- "the ifAbsent: handles a caseOf:otherwise: where all cases return, which results
- in the branch around the otherwise being unreached. e.g. in the following
- jumpTo: L2
- is unreached.
-
- | t |
- t caseOf: { [nil] -> [^thisContext method abstractSymbolic] }
- otherwise: ['Oh no Mr Bill!!']
-
- pushTemp: 0
- pushConstant: nil
- send: #= (1 arg)
- jumpFalseTo: L1
- pushThisContext:
- send: #method (0 args)
- send: #abstractSymbolic (0 args)
- returnTop
- jumpTo: L2
- L1:
- pushConstant: 'Oh no Mr Bill!!'
- L2:
- returnTop"!
Item was removed:
- ----- Method: BlockLocalTempCounter>>doPop (in category 'instruction decoding') -----
- doPop
- "Remove Top Of Stack bytecode."
- stackPointer := stackPointer - 1!
Item was removed:
- ----- Method: BlockLocalTempCounter>>jump: (in category 'instruction decoding') -----
- jump: offset
- "Unconditional Jump bytecode."
- offset > 0 ifTrue:
- [joinOffsets at: scanner pc + offset put: stackPointer.
- self doJoin]!
Item was removed:
- ----- Method: BlockLocalTempCounter>>jump:if: (in category 'instruction decoding') -----
- jump: offset if: condition
- "Conditional Jump bytecode."
- stackPointer := stackPointer - 1.
- offset > 0 ifTrue:
- [joinOffsets at: scanner pc + offset put: stackPointer]!
Item was removed:
- ----- Method: BlockLocalTempCounter>>methodReturnConstant: (in category 'instruction decoding') -----
- methodReturnConstant: value
- "Return Constant bytecode."
- self doJoin!
Item was removed:
- ----- Method: BlockLocalTempCounter>>methodReturnReceiver (in category 'instruction decoding') -----
- methodReturnReceiver
- "Return Self bytecode."
- self doJoin!
Item was removed:
- ----- Method: BlockLocalTempCounter>>methodReturnTop (in category 'instruction decoding') -----
- methodReturnTop
- "Return Top Of Stack bytecode."
- stackPointer := stackPointer - 1.
- self doJoin!
Item was removed:
- ----- Method: BlockLocalTempCounter>>popIntoLiteralVariable: (in category 'instruction decoding') -----
- popIntoLiteralVariable: anAssociation
- "Remove Top Of Stack And Store Into Literal Variable bytecode."
- stackPointer := stackPointer - 1!
Item was removed:
- ----- Method: BlockLocalTempCounter>>popIntoReceiverVariable: (in category 'instruction decoding') -----
- popIntoReceiverVariable: offset
- "Remove Top Of Stack And Store Into Instance Variable bytecode."
- stackPointer := stackPointer - 1!
Item was removed:
- ----- Method: BlockLocalTempCounter>>popIntoRemoteTemp:inVectorAt: (in category 'instruction decoding') -----
- popIntoRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex
- "Remove Top Of Stack And Store Into Offset of Temp Vector bytecode."
- stackPointer := stackPointer - 1!
Item was removed:
- ----- Method: BlockLocalTempCounter>>popIntoTemporaryVariable: (in category 'instruction decoding') -----
- popIntoTemporaryVariable: offset
- "Remove Top Of Stack And Store Into Temporary Variable bytecode."
- stackPointer := stackPointer - 1!
Item was removed:
- ----- Method: BlockLocalTempCounter>>pushActiveContext (in category 'instruction decoding') -----
- pushActiveContext
- "Push Active Context On Top Of Its Own Stack bytecode."
- stackPointer := stackPointer + 1!
Item was removed:
- ----- Method: BlockLocalTempCounter>>pushClosureCopyNumCopiedValues:numArgs:blockSize: (in category 'instruction decoding') -----
- pushClosureCopyNumCopiedValues: numCopied numArgs: numArgs blockSize: blockSize
- "Push Closure bytecode. Either compute the end of the block if this is
- the block we're analysing, or skip it, adjusting the stack as appropriate."
- blockEnd
- ifNil: [blockEnd := scanner pc + blockSize]
- ifNotNil:
- [stackPointer := stackPointer - numCopied + 1.
- scanner pc: scanner pc + blockSize]!
Item was removed:
- ----- Method: BlockLocalTempCounter>>pushConsArrayWithElements: (in category 'instruction decoding') -----
- pushConsArrayWithElements: numElements
- "Push Cons Array of size numElements popping numElements items from the stack into the array bytecode."
- stackPointer := stackPointer - numElements + 1!
Item was removed:
- ----- Method: BlockLocalTempCounter>>pushConstant: (in category 'instruction decoding') -----
- pushConstant: value
- "Push Constant, value, on Top Of Stack bytecode."
- stackPointer := stackPointer + 1!
Item was removed:
- ----- Method: BlockLocalTempCounter>>pushLiteralVariable: (in category 'instruction decoding') -----
- pushLiteralVariable: anAssociation
- "Push Contents Of anAssociation On Top Of Stack bytecode."
- stackPointer := stackPointer + 1!
Item was removed:
- ----- Method: BlockLocalTempCounter>>pushNewArrayOfSize: (in category 'instruction decoding') -----
- pushNewArrayOfSize: numElements
- "Push New Array of size numElements bytecode."
- stackPointer := stackPointer + 1!
Item was removed:
- ----- Method: BlockLocalTempCounter>>pushReceiver (in category 'instruction decoding') -----
- pushReceiver
- "Push Active Context's Receiver on Top Of Stack bytecode."
- stackPointer := stackPointer + 1!
Item was removed:
- ----- Method: BlockLocalTempCounter>>pushReceiverVariable: (in category 'instruction decoding') -----
- pushReceiverVariable: offset
- "Push Contents Of the Receiver's Instance Variable Whose Index
- is the argument, offset, On Top Of Stack bytecode."
- stackPointer := stackPointer + 1!
Item was removed:
- ----- Method: BlockLocalTempCounter>>pushRemoteTemp:inVectorAt: (in category 'instruction decoding') -----
- pushRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex
- "Push Contents at Offset in Temp Vector bytecode."
- stackPointer := stackPointer + 1!
Item was removed:
- ----- Method: BlockLocalTempCounter>>pushTemporaryVariable: (in category 'instruction decoding') -----
- pushTemporaryVariable: offset
- "Push Contents Of Temporary Variable Whose Index Is the
- argument, offset, On Top Of Stack bytecode."
- stackPointer := stackPointer + 1!
Item was removed:
- ----- Method: BlockLocalTempCounter>>send:super:numArgs: (in category 'instruction decoding') -----
- send: selector super: supered numArgs: numberArguments
- "Send Message With Selector, selector, bytecode. The argument,
- supered, indicates whether the receiver of the message is specified with
- 'super' in the source method. The arguments of the message are found in
- the top numArguments locations on the stack and the receiver just
- below them."
-
- stackPointer := stackPointer - numberArguments!
Item was removed:
- ----- Method: BlockLocalTempCounter>>tempCountForBlockAt:in: (in category 'initialize-release') -----
- tempCountForBlockAt: pc in: method
- "Compute the number of local temporaries in a block.
- If the block begins with a sequence of push: nil bytecodes then some of
- These could be initializing local temps. We can only reliably disambuguate
- them from other uses of nil by parsing the stack and seeing what the offset
- of the stack pointer is at the end of the block.
-
- There are short-cuts. The ones we take here are
- - if there is no sequence of push nils there can be no local temps
- - we follow forward jumps to shorten the amount of scanning"
- stackPointer := 0.
- scanner := InstructionStream new method: method pc: pc.
- scanner interpretNextInstructionFor: self.
- blockEnd ifNil:
- [self error: 'pc is not that of a block'].
- scanner nextByte = method encoderClass pushNilCode ifTrue:
- [joinOffsets := Dictionary new.
- [scanner pc < blockEnd] whileTrue:
- [scanner interpretNextInstructionFor: self]].
- ^stackPointer!
Item was removed:
- ----- Method: BlockLocalTempCounter>>testTempCountForBlockAt:in: (in category 'initialize-release') -----
- testTempCountForBlockAt: startPc in: method
- "Compute the number of local temporaries in a block.
- If the block begins with a sequence of push: nil bytecodes then some of
- These could be initializing local temps. We can only reliably disambuguate
- them from other uses of nil by parsing the stack and seeing what the offset
- of the stack pointer is at the end of the block.There are short-cuts. The only
- one we take here is
- - if there is no sequence of push nils there can be no local temps"
-
- | symbolicLines line prior thePc |
- symbolicLines := Dictionary new.
- method symbolicLinesDo:
- [:pc :lineForPC| symbolicLines at: pc put: lineForPC].
- stackPointer := 0.
- scanner := InstructionStream new method: method pc: startPc.
- scanner interpretNextInstructionFor: self.
- blockEnd ifNil:
- [self error: 'pc is not that of a block'].
- scanner nextByte = method encoderClass pushNilCode ifTrue:
- [joinOffsets := Dictionary new.
- [scanner pc < blockEnd] whileTrue:
- [line := symbolicLines at: scanner pc.
- prior := stackPointer.
- thePc := scanner pc.
- scanner interpretNextInstructionFor: self.
- Transcript cr; print: prior; nextPutAll: '->'; print: stackPointer; tab; print: thePc; tab; nextPutAll: line; flush]].
- ^stackPointer!
Item was removed:
- ----- Method: CompiledBlock>>startpcsToBlockExtents (in category '*Compiler-support') -----
- startpcsToBlockExtents
- ^self outerCode startpcsToBlockExtents!
Item was removed:
- ----- Method: CompiledMethod>>blockExtentsInto:from:to:scanner:numberer: (in category '*Compiler-support') -----
- blockExtentsInto: aDictionary from: initialPC to: endPC scanner: scanner numberer: numbererBlock
- "Support routine for startpcsToBlockExtents"
- | extentStart blockSizeOrLocator |
- extentStart := numbererBlock value.
- [scanner pc <= endPC] whileTrue:
- [blockSizeOrLocator := scanner interpretNextInstructionFor: BlockStartLocator new.
- blockSizeOrLocator isInteger ifTrue:
- [self
- blockExtentsInto: aDictionary
- from: scanner pc
- to: scanner pc + blockSizeOrLocator - 1
- scanner: scanner
- numberer: numbererBlock]].
- aDictionary at: initialPC put: (extentStart to: numbererBlock value).
- ^aDictionary!
Item was removed:
- ----- Method: CompiledMethod>>startpcsToBlockExtents (in category '*Compiler-support') -----
- startpcsToBlockExtents
- "Answer a Dictionary of startpc to Interval of blockExtent, using the
- identical numbering scheme described in and orchestrated by
- BlockNode>>analyseArguments:temporaries:rootNode:. This is used
- to find the temp names for any block in a method, as needed by the
- decompiler and debugger. By indirecting through the blockExtent
- instead of using the startpc directly we decouple access to temp
- names from the exact bytecode; insulating the decompiler and
- debugger from minor changes in the compiler's output. If the
- recompilation doesn't produce exactly the same bytecode at exactly
- the same offset no matter; the blockExtents will be the same."
- | index |
- index := 0.
- ^self
- blockExtentsInto: Dictionary new
- from: self initialPC
- to: self endPC
- scanner: (InstructionStream on: self)
- numberer: [| value | value := index. index := index + 2. value]!
Eliot Miranda uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-eem.1141.mcz
==================== Summary ====================
Name: Kernel-eem.1141
Author: eem
Time: 11 January 2018, 9:22:51.439093 am
UUID: a64a9457-407a-40f0-8d51-111106f0afdf
Ancestors: Kernel-eem.1140
Move BlockLocalTempCounter to Kernel. It is used to implement BlockClosure>>numTemps, which is used more broadly than simply the decompiler and debugger.
=============== Diff against Kernel-eem.1140 ===============
Item was added:
+ InstructionClient subclass: #BlockLocalTempCounter
+ instanceVariableNames: 'stackPointer scanner blockEnd joinOffsets'
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'Kernel-Methods'!
+
+ !BlockLocalTempCounter commentStamp: 'eem 1/11/2018 08:30' prior: 0!
+ I am a support class for the decompiler that is used to find the number of local temps in a block by finding out what the stack offset is at the end of a block. I am necessary because in the EncoderForV3PlusClosures bytecode set the only way to initialize block-local temporaries is with pushConstant: nil bytecodes, but such bytecodes are ambiguous with a pushConstant: nil used to pass nil as a parameter or answer it as a result. By scanning through to the end of the block these can be disambiguated by tracking the stack depth.!
Item was added:
+ ----- Method: BlockLocalTempCounter class>>tempCountForBlockAt:in: (in category 'instance creation') -----
+ tempCountForBlockAt: pc in: method
+ ^self new tempCountForBlockAt: pc in: method!
Item was added:
+ ----- Method: BlockLocalTempCounter class>>tempCountForBlockStartingAt:in: (in category 'instance creation') -----
+ tempCountForBlockStartingAt: startpc in: method
+ ^self new
+ tempCountForBlockAt: (method encoderClass pcOfBlockCreationBytecodeForBlockStartingAt: startpc in: method)
+ in: method!
Item was added:
+ ----- Method: BlockLocalTempCounter>>blockReturnConstant: (in category 'instruction decoding') -----
+ blockReturnConstant: value
+ "Return Constant From Block bytecode."
+ scanner pc < blockEnd ifTrue:
+ [self doJoin]!
Item was added:
+ ----- Method: BlockLocalTempCounter>>blockReturnTop (in category 'instruction decoding') -----
+ blockReturnTop
+ "Return Top Of Stack bytecode."
+ stackPointer := stackPointer - 1.
+ scanner pc < blockEnd ifTrue:
+ [self doJoin]!
Item was added:
+ ----- Method: BlockLocalTempCounter>>directedSuperSend:numArgs: (in category 'instruction decoding') -----
+ directedSuperSend: selector numArgs: numArgs
+ "Send Message Above Specific Class With Selector, selector, bytecode.
+ Start the lookup above the class that is the value of the association on
+ top of stack. The arguments of the message are found in the top numArgs
+ stack locations beneath the association, and the receiver just below them."
+
+ stackPointer := stackPointer - (numArgs + 1)!
Item was added:
+ ----- Method: BlockLocalTempCounter>>doDup (in category 'instruction decoding') -----
+ doDup
+ "Duplicate Top Of Stack bytecode."
+ stackPointer := stackPointer + 1!
Item was added:
+ ----- Method: BlockLocalTempCounter>>doJoin (in category 'private') -----
+ doJoin
+ scanner pc < blockEnd ifTrue:
+ [stackPointer := joinOffsets at: scanner pc ifAbsent: [scanner followingPc]]
+
+ "the ifAbsent: handles a caseOf:otherwise: where all cases return, which results
+ in the branch around the otherwise being unreached. e.g. in the following
+ jumpTo: L2
+ is unreached.
+
+ | t |
+ t caseOf: { [nil] -> [^thisContext method abstractSymbolic] }
+ otherwise: ['Oh no Mr Bill!!']
+
+ pushTemp: 0
+ pushConstant: nil
+ send: #= (1 arg)
+ jumpFalseTo: L1
+ pushThisContext:
+ send: #method (0 args)
+ send: #abstractSymbolic (0 args)
+ returnTop
+ jumpTo: L2
+ L1:
+ pushConstant: 'Oh no Mr Bill!!'
+ L2:
+ returnTop"!
Item was added:
+ ----- Method: BlockLocalTempCounter>>doPop (in category 'instruction decoding') -----
+ doPop
+ "Remove Top Of Stack bytecode."
+ stackPointer := stackPointer - 1!
Item was added:
+ ----- Method: BlockLocalTempCounter>>jump: (in category 'instruction decoding') -----
+ jump: offset
+ "Unconditional Jump bytecode."
+ offset > 0 ifTrue:
+ [joinOffsets at: scanner pc + offset put: stackPointer.
+ self doJoin]!
Item was added:
+ ----- Method: BlockLocalTempCounter>>jump:if: (in category 'instruction decoding') -----
+ jump: offset if: condition
+ "Conditional Jump bytecode."
+ stackPointer := stackPointer - 1.
+ offset > 0 ifTrue:
+ [joinOffsets at: scanner pc + offset put: stackPointer]!
Item was added:
+ ----- Method: BlockLocalTempCounter>>methodReturnConstant: (in category 'instruction decoding') -----
+ methodReturnConstant: value
+ "Return Constant bytecode."
+ self doJoin!
Item was added:
+ ----- Method: BlockLocalTempCounter>>methodReturnReceiver (in category 'instruction decoding') -----
+ methodReturnReceiver
+ "Return Self bytecode."
+ self doJoin!
Item was added:
+ ----- Method: BlockLocalTempCounter>>methodReturnTop (in category 'instruction decoding') -----
+ methodReturnTop
+ "Return Top Of Stack bytecode."
+ stackPointer := stackPointer - 1.
+ self doJoin!
Item was added:
+ ----- Method: BlockLocalTempCounter>>popIntoLiteralVariable: (in category 'instruction decoding') -----
+ popIntoLiteralVariable: anAssociation
+ "Remove Top Of Stack And Store Into Literal Variable bytecode."
+ stackPointer := stackPointer - 1!
Item was added:
+ ----- Method: BlockLocalTempCounter>>popIntoReceiverVariable: (in category 'instruction decoding') -----
+ popIntoReceiverVariable: offset
+ "Remove Top Of Stack And Store Into Instance Variable bytecode."
+ stackPointer := stackPointer - 1!
Item was added:
+ ----- Method: BlockLocalTempCounter>>popIntoRemoteTemp:inVectorAt: (in category 'instruction decoding') -----
+ popIntoRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex
+ "Remove Top Of Stack And Store Into Offset of Temp Vector bytecode."
+ stackPointer := stackPointer - 1!
Item was added:
+ ----- Method: BlockLocalTempCounter>>popIntoTemporaryVariable: (in category 'instruction decoding') -----
+ popIntoTemporaryVariable: offset
+ "Remove Top Of Stack And Store Into Temporary Variable bytecode."
+ stackPointer := stackPointer - 1!
Item was added:
+ ----- Method: BlockLocalTempCounter>>pushActiveContext (in category 'instruction decoding') -----
+ pushActiveContext
+ "Push Active Context On Top Of Its Own Stack bytecode."
+ stackPointer := stackPointer + 1!
Item was added:
+ ----- Method: BlockLocalTempCounter>>pushClosureCopyNumCopiedValues:numArgs:blockSize: (in category 'instruction decoding') -----
+ pushClosureCopyNumCopiedValues: numCopied numArgs: numArgs blockSize: blockSize
+ "Push Closure bytecode. Either compute the end of the block if this is
+ the block we're analysing, or skip it, adjusting the stack as appropriate."
+ blockEnd
+ ifNil: [blockEnd := scanner pc + blockSize]
+ ifNotNil:
+ [stackPointer := stackPointer - numCopied + 1.
+ scanner pc: scanner pc + blockSize]!
Item was added:
+ ----- Method: BlockLocalTempCounter>>pushConsArrayWithElements: (in category 'instruction decoding') -----
+ pushConsArrayWithElements: numElements
+ "Push Cons Array of size numElements popping numElements items from the stack into the array bytecode."
+ stackPointer := stackPointer - numElements + 1!
Item was added:
+ ----- Method: BlockLocalTempCounter>>pushConstant: (in category 'instruction decoding') -----
+ pushConstant: value
+ "Push Constant, value, on Top Of Stack bytecode."
+ stackPointer := stackPointer + 1!
Item was added:
+ ----- Method: BlockLocalTempCounter>>pushFullClosure:numCopied: (in category 'instruction decoding') -----
+ pushFullClosure: aCompiledBlock numCopied: numCopied
+ "Push Full Closure bytecode."
+ self error: 'BlockLocalTempCounter should not be used with full block compiled methods. A full block''s numTemps is accessible directly from its method.'!
Item was added:
+ ----- Method: BlockLocalTempCounter>>pushLiteralVariable: (in category 'instruction decoding') -----
+ pushLiteralVariable: anAssociation
+ "Push Contents Of anAssociation On Top Of Stack bytecode."
+ stackPointer := stackPointer + 1!
Item was added:
+ ----- Method: BlockLocalTempCounter>>pushNewArrayOfSize: (in category 'instruction decoding') -----
+ pushNewArrayOfSize: numElements
+ "Push New Array of size numElements bytecode."
+ stackPointer := stackPointer + 1!
Item was added:
+ ----- Method: BlockLocalTempCounter>>pushReceiver (in category 'instruction decoding') -----
+ pushReceiver
+ "Push Active Context's Receiver on Top Of Stack bytecode."
+ stackPointer := stackPointer + 1!
Item was added:
+ ----- Method: BlockLocalTempCounter>>pushReceiverVariable: (in category 'instruction decoding') -----
+ pushReceiverVariable: offset
+ "Push Contents Of the Receiver's Instance Variable Whose Index
+ is the argument, offset, On Top Of Stack bytecode."
+ stackPointer := stackPointer + 1!
Item was added:
+ ----- Method: BlockLocalTempCounter>>pushRemoteTemp:inVectorAt: (in category 'instruction decoding') -----
+ pushRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex
+ "Push Contents at Offset in Temp Vector bytecode."
+ stackPointer := stackPointer + 1!
Item was added:
+ ----- Method: BlockLocalTempCounter>>pushTemporaryVariable: (in category 'instruction decoding') -----
+ pushTemporaryVariable: offset
+ "Push Contents Of Temporary Variable Whose Index Is the
+ argument, offset, On Top Of Stack bytecode."
+ stackPointer := stackPointer + 1!
Item was added:
+ ----- Method: BlockLocalTempCounter>>send:super:numArgs: (in category 'instruction decoding') -----
+ send: selector super: supered numArgs: numberArguments
+ "Send Message With Selector, selector, bytecode. The argument,
+ supered, indicates whether the receiver of the message is specified with
+ 'super' in the source method. The arguments of the message are found in
+ the top numArguments locations on the stack and the receiver just
+ below them."
+
+ stackPointer := stackPointer - numberArguments!
Item was added:
+ ----- Method: BlockLocalTempCounter>>tempCountForBlockAt:in: (in category 'initialize-release') -----
+ tempCountForBlockAt: pc in: method
+ "Compute the number of local temporaries in a block.
+ If the block begins with a sequence of push: nil bytecodes then some of
+ These could be initializing local temps. We can only reliably disambuguate
+ them from other uses of nil by parsing the stack and seeing what the offset
+ of the stack pointer is at the end of the block.
+
+ There are short-cuts. The ones we take here are
+ - if there is no sequence of push nils there can be no local temps
+ - we follow forward jumps to shorten the amount of scanning"
+ stackPointer := 0.
+ scanner := InstructionStream new method: method pc: pc.
+ scanner interpretNextInstructionFor: self.
+ blockEnd ifNil:
+ [self error: 'pc is not that of a block'].
+ scanner nextByte = method encoderClass pushNilCode ifTrue:
+ [joinOffsets := Dictionary new.
+ [scanner pc < blockEnd] whileTrue:
+ [scanner interpretNextInstructionFor: self]].
+ ^stackPointer!
Item was added:
+ ----- Method: BlockLocalTempCounter>>testTempCountForBlockAt:in: (in category 'initialize-release') -----
+ testTempCountForBlockAt: startPc in: method
+ "Compute the number of local temporaries in a block.
+ If the block begins with a sequence of push: nil bytecodes then some of
+ These could be initializing local temps. We can only reliably disambuguate
+ them from other uses of nil by parsing the stack and seeing what the offset
+ of the stack pointer is at the end of the block.There are short-cuts. The only
+ one we take here is
+ - if there is no sequence of push nils there can be no local temps"
+
+ | symbolicLines line prior thePc |
+ symbolicLines := Dictionary new.
+ method symbolicLinesDo:
+ [:pc :lineForPC| symbolicLines at: pc put: lineForPC].
+ stackPointer := 0.
+ scanner := InstructionStream new method: method pc: startPc.
+ scanner interpretNextInstructionFor: self.
+ blockEnd ifNil:
+ [self error: 'pc is not that of a block'].
+ scanner nextByte = method encoderClass pushNilCode ifTrue:
+ [joinOffsets := Dictionary new.
+ [scanner pc < blockEnd] whileTrue:
+ [line := symbolicLines at: scanner pc.
+ prior := stackPointer.
+ thePc := scanner pc.
+ scanner interpretNextInstructionFor: self.
+ Transcript cr; print: prior; nextPutAll: '->'; print: stackPointer; tab; print: thePc; tab; nextPutAll: line; flush]].
+ ^stackPointer!
Eliot Miranda uploaded a new version of Tools to project The Trunk:
http://source.squeak.org/trunk/Tools-eem.790.mcz
==================== Summary ====================
Name: Tools-eem.790
Author: eem
Time: 11 January 2018, 9:07:29.791856 am
UUID: 24ea3a83-3589-4e8f-8a7f-cdf01eb2b06e
Ancestors: Tools-eem.789
Add source range support for full blocks by adding DebuggerMethodMapForFullBlockCompiledMethods. Shift to using startKeys instead of merely startPcs.
Interface with the debuggerMap via rangeForPC:in:contextIsActiveContext: rather than rangeForPC:contextIsActiveContext: so that if a full block is in use the debuggerMap has the method in hand to choose the right source range map.
=============== Diff against Tools-eem.789 ===============
Item was added:
+ ----- Method: CompiledBlock>>blockExtentsToTempsMap (in category '*Tools-Debugger-support') -----
+ blockExtentsToTempsMap
+ ^self homeMethod blockExtentsToTempsMap!
Item was added:
+ ----- Method: CompiledBlock>>debuggerMap (in category '*Tools-Debugger-support') -----
+ debuggerMap
+ ^self homeMethod debuggerMap!
Item was added:
+ ----- Method: CompiledBlock>>startKey (in category '*Tools-Debugger-support') -----
+ startKey
+ "The startKey is used as a key to identify the active sequence of temporaries for a block or
+ method in a DebuggerMethodMapForClosureCompiledMethod's startKeysToTempRefs map."
+ ^self!
Item was added:
+ ----- Method: CompiledCode>>abstractPCForConcretePC: (in category '*Tools-Debugger-support') -----
+ abstractPCForConcretePC: concretePC
+ "Answer the abstractPC matching concretePC."
+
+ | abstractPC scanner client endPC |
+ self flag: 'belongs in DebuggerMethodMap?'.
+ abstractPC := 1.
+ scanner := InstructionStream on: self.
+ client := InstructionClient new.
+ "cache endPC for methods with embedded source; finding out the endPC is very slow in this case..."
+ endPC := self endPC.
+ [(scanner pc > endPC
+ or: [scanner pc >= concretePC]) ifTrue:
+ [^abstractPC].
+ abstractPC := abstractPC + 1.
+ scanner interpretNextInstructionFor: client] repeat!
Item was removed:
- ----- Method: CompiledMethod>>abstractPCForConcretePC: (in category '*Tools-Debugger-support') -----
- abstractPCForConcretePC: concretePC
- "Answer the abstractPC matching concretePC."
-
- | abstractPC scanner client endPC |
- self flag: 'belongs in DebuggerMethodMap?'.
- abstractPC := 1.
- scanner := InstructionStream on: self.
- client := InstructionClient new.
- "cache endPC for methods with embedded source; finding out the endPC is very slow in this case..."
- endPC := self endPC.
- [(scanner pc > endPC
- or: [scanner pc >= concretePC]) ifTrue:
- [^abstractPC].
- abstractPC := abstractPC + 1.
- scanner interpretNextInstructionFor: client] repeat!
Item was changed:
----- Method: CompiledMethod>>blockExtentsToTempsMap (in category '*Tools-Debugger-support') -----
blockExtentsToTempsMap
"If the receiver has been copied with temp names answer a
map from blockExtent to temps map in the same format as
BytecodeEncoder>>blockExtentsToTempNamesMap. if the
receiver has not been copied with temps answer nil."
^self holdsTempNames ifTrue:
+ [self mapFromBlockKeys: (self startKeysToBlockExtents values sort: [:assocA :assocB| assocA first <= assocB first])
- [self mapFromBlockKeys: ((self startpcsToBlockExtents associations sort:
- [:a1 :a2| a1 key < a2 key]) replace:
- [:assoc| assoc value])
toSchematicTemps: self tempNamesString]!
Item was removed:
- ----- Method: CompiledMethod>>mapFromBlockKeys:toSchematicTemps: (in category '*Tools-Debugger-support') -----
- mapFromBlockKeys: keys toSchematicTemps: schematicTempNamesString
- "Decode a schematicTempNamesString that encodes the layout of temp names
- in a method and any closures/blocks within it, matching keys in keys to
- vectors of temp names."
- | map tempNames |
- map := Dictionary new.
- tempNames := schematicTempNamesString readStream.
- keys do:
- [:key| | tempSequence tempIndex |
- tempSequence := OrderedCollection new.
- tempIndex := 0.
- [(tempNames skipSeparators; peek) ifNil: [true] ifNotNil: [:ch| '[]' includes: ch]] whileFalse:
- [tempNames peek = $(
- ifTrue: [tempSequence addAllLast: ((self tempsSubSequenceFrom: (tempNames next; yourself)) withIndexCollect:
- [:temp :index|
- { temp. { tempIndex + 1. index } }]).
- tempNames peek ~= $) ifTrue: [self error: 'parse error'].
- tempIndex := tempIndex + 1.
- tempNames next]
- ifFalse: [tempSequence addAllLast: ((self tempsSubSequenceFrom: tempNames) withIndexCollect:
- [:temp :index|
- { temp. tempIndex := tempIndex + 1 }])]].
- map at: key put: tempSequence asArray.
- [tempNames peek = $]] whileTrue: [tempNames next].
- tempNames peek = $[ ifTrue:
- [tempNames next]].
- ^map!
Item was added:
+ ----- Method: CompiledMethod>>startKey (in category '*Tools-Debugger-support') -----
+ startKey
+ "The startKey is used as a key to identify the active sequence of temporaries for a block or
+ method in a DebuggerMethodMapForClosureCompiledMethod's startKeysToTempRefs map."
+ ^self initialPC!
Item was added:
+ ----- Method: Context>>startKey (in category '*Tools-debugger access') -----
+ startKey
+ "The startKey is used as a key to identify the active sequence of temporaries for a block or
+ method in a DebuggerMethodMapForClosureCompiledMethod's startKeysToTempRefs map."
+ ^closureOrNil
+ ifNil: [method initialPC]
+ ifNotNil: [closureOrNil isFullBlock
+ ifTrue: [method]
+ ifFalse: [closureOrNil startpc]]!
Item was changed:
----- Method: Debugger>>pcRange (in category 'code pane') -----
pcRange
"Answer the indices in the source code for the method corresponding to
the selected context's program counter value."
+ | ctxt |
(selectingPC and: [contextStackIndex ~= 0]) ifFalse:
[^1 to: 0].
+ (ctxt := self selectedContext) isDead ifTrue:
- self selectedContext isDead ifTrue:
[^1 to: 0].
+ ^ctxt debuggerMap
+ rangeForPC: ctxt pc
+ in: ctxt method
- ^self selectedContext debuggerMap
- rangeForPC: self selectedContext pc
contextIsActiveContext: contextStackIndex = 1!
Item was changed:
----- Method: DebuggerMethodMap class>>forMethod:methodNode: (in category 'instance creation') -----
+ forMethod: aMethod "<CompiledCode>" methodNode: methodNode "<MethodNode>"
- forMethod: aMethod "<CompiledMethod>" methodNode: methodNode "<MethodNode>"
"Uncached instance creation method for private use or for tests.
Please consider using forMethod: instead."
^(aMethod isBlueBookCompiled
ifTrue: [DebuggerMethodMapForBlueBookMethods]
+ ifFalse:
+ [aMethod encoderClass supportsFullBlocks
+ ifTrue: [DebuggerMethodMapForFullBlockCompiledMethods]
+ ifFalse: [DebuggerMethodMapForClosureCompiledMethods]]) new
+ forMethod: aMethod homeMethod
- ifFalse: [DebuggerMethodMapForClosureCompiledMethods]) new
- forMethod: aMethod
methodNode: methodNode!
Item was changed:
+ ----- Method: DebuggerMethodMap>>abstractSourceMap (in category 'private') -----
- ----- Method: DebuggerMethodMap>>abstractSourceMap (in category 'source mapping') -----
abstractSourceMap
"Answer with a Dictionary of abstractPC <Integer> to sourceRange <Interval>."
| theMethodToScan rawSourceRanges concreteSourceRanges abstractPC scanner client |
abstractSourceRanges ifNotNil:
[^abstractSourceRanges].
"If the methodNode hasn't had a method generated it doesn't have pcs set in its
nodes so we must generate a new method and might as well use it for scanning."
methodNode rawSourceRangesAndMethodDo:
[:ranges :method|
rawSourceRanges := ranges.
theMethodToScan := method].
concreteSourceRanges := Dictionary new.
rawSourceRanges keysAndValuesDo:
[:node :range|
node pc ~= 0 ifTrue:
[concreteSourceRanges at: node pc put: range]].
abstractPC := 1.
abstractSourceRanges := Dictionary new.
scanner := InstructionStream on: theMethodToScan.
client := InstructionClient new.
[(concreteSourceRanges includesKey: scanner pc) ifTrue:
[abstractSourceRanges at: abstractPC put: (concreteSourceRanges at: scanner pc)].
abstractPC := abstractPC + 1.
scanner interpretNextInstructionFor: client.
scanner atEnd] whileFalse.
^abstractSourceRanges!
Item was added:
+ ----- Method: DebuggerMethodMap>>abstractSourceMapForMethod: (in category 'source mapping') -----
+ abstractSourceMapForMethod: aCompiledMethod
+ "The default source mapping is for block bytecodes embedded within a
+ single compiled method, as in the BlueBook and EncoderForV3PlusClosures."
+ ^self abstractSourceMap!
Item was changed:
+ ----- Method: DebuggerMethodMap>>rangeForPC:contextIsActiveContext: (in category 'private but obsolete') -----
- ----- Method: DebuggerMethodMap>>rangeForPC:contextIsActiveContext: (in category 'source mapping') -----
rangeForPC: contextsConcretePC contextIsActiveContext: contextIsActiveContext
"Answer the indices in the source code for the supplied pc.
If the context is the actve context (is at the hot end of the stack)
then its pc is the current pc. But if the context isn't, because it is
suspended sending a message, then its current pc is the previous pc."
| pc i end |
pc := self method abstractPCForConcretePC: (contextIsActiveContext
ifTrue: [contextsConcretePC]
ifFalse: [(self method pcPreviousTo: contextsConcretePC)
ifNotNil: [:prevpc| prevpc]
ifNil: [contextsConcretePC]]).
(self abstractSourceMap includesKey: pc) ifTrue:
[^self abstractSourceMap at: pc].
sortedSourceMap ifNil:
[sortedSourceMap := self abstractSourceMap associations
replace: [ :each | each copy ];
sort].
sortedSourceMap isEmpty ifTrue: [^1 to: 0].
i := sortedSourceMap findNearbyBinaryIndex: [:assoc| pc - assoc key].
i < 1 ifTrue: [^1 to: 0].
i > sortedSourceMap size ifTrue:
[end := sortedSourceMap inject: 0 into:
[:prev :this | prev max: this value last].
^end+1 to: end].
^(sortedSourceMap at: i) value
"| method source scanner map |
method := DebuggerMethodMap compiledMethodAt: #rangeForPC:contextIsActiveContext:.
source := method getSourceFromFile asString.
scanner := InstructionStream on: method.
map := method debuggerMap.
Array streamContents:
[:ranges|
[scanner atEnd] whileFalse:
[| range |
range := map rangeForPC: scanner pc contextIsActiveContext: true.
((map abstractSourceMap includesKey: scanner abstractPC)
and: [range first ~= 0]) ifTrue:
[ranges nextPut: (source copyFrom: range first to: range last)].
scanner interpretNextInstructionFor: InstructionClient new]]"!
Item was added:
+ ----- Method: DebuggerMethodMap>>rangeForPC:in:contextIsActiveContext: (in category 'source mapping') -----
+ rangeForPC: contextsConcretePC in: method contextIsActiveContext: contextIsActiveContext
+ "Answer the indices in the source code for the supplied pc.
+ If the context is the actve context (is at the hot end of the stack)
+ then its pc is the current pc. But if the context isn't, because it is
+ suspended sending a message, then its current pc is the previous pc."
+
+ | pc i end |
+ pc := self method abstractPCForConcretePC: (contextIsActiveContext
+ ifTrue: [contextsConcretePC]
+ ifFalse: [(self method pcPreviousTo: contextsConcretePC)
+ ifNotNil: [:prevpc| prevpc]
+ ifNil: [contextsConcretePC]]).
+ (self abstractSourceMap includesKey: pc) ifTrue:
+ [^self abstractSourceMap at: pc].
+ sortedSourceMap ifNil:
+ [sortedSourceMap := self abstractSourceMap associations
+ replace: [ :each | each copy ];
+ sort].
+ sortedSourceMap isEmpty ifTrue: [^1 to: 0].
+ i := sortedSourceMap findNearbyBinaryIndex: [:assoc| pc - assoc key].
+ i < 1 ifTrue: [^1 to: 0].
+ i > sortedSourceMap size ifTrue:
+ [end := sortedSourceMap inject: 0 into:
+ [:prev :this | prev max: this value last].
+ ^end+1 to: end].
+ ^(sortedSourceMap at: i) value
+
+ "| method source scanner map |
+ method := DebuggerMethodMap compiledMethodAt: #rangeForPC:in:contextIsActiveContext:.
+ source := method getSourceFromFile asString.
+ scanner := InstructionStream on: method.
+ map := method debuggerMap.
+ Array streamContents:
+ [:ranges|
+ [scanner atEnd] whileFalse:
+ [| range |
+ range := map rangeForPC: scanner pc in: method contextIsActiveContext: true.
+ ((map abstractSourceMap includesKey: scanner abstractPC)
+ and: [range first ~= 0]) ifTrue:
+ [ranges nextPut: (source copyFrom: range first to: range last)].
+ scanner interpretNextInstructionFor: InstructionClient new]]"!
Item was changed:
DebuggerMethodMap subclass: #DebuggerMethodMapForBlueBookMethods
instanceVariableNames: 'tempNames'
classVariableNames: ''
poolDictionaries: ''
category: 'Tools-Debugger'!
+ !DebuggerMethodMapForBlueBookMethods commentStamp: 'eem 1/6/2018 16:57' prior: 0!
+ I am a place-holder for information needed by the Debugger to inspect method activations. See my superclass's comment. I map methods compiled using BlueBook blocks.!
- !DebuggerMethodMapForBlueBookMethods commentStamp: '<historical>' prior: 0!
- I am a place-holder for information needed by the Debugger to inspect method activations. See my superclass's comment. I map methods compiled using Closures.!
Item was changed:
DebuggerMethodMap subclass: #DebuggerMethodMapForClosureCompiledMethods
+ instanceVariableNames: 'blockExtentsToTempRefs startpcsToTempRefs startKeysToTempRefs'
- instanceVariableNames: 'blockExtentsToTempRefs startpcsToTempRefs'
classVariableNames: 'FirstTime'
poolDictionaries: ''
category: 'Tools-Debugger'!
+ !DebuggerMethodMapForClosureCompiledMethods commentStamp: 'eem 1/8/2018 12:42' prior: 0!
+ I am a place-holder for information needed by the Debugger to inspect method activations. See my superclass's comment. I map methods compiled using closures.
- !DebuggerMethodMapForClosureCompiledMethods commentStamp: '<historical>' prior: 0!
- I am a place-holder for information needed by the Debugger to inspect method activations. See my superclass's comment. I map methods compiled using BlueBook blocks.
Instance variables
blockExtentsToTempsRefs <Dictionary of: Interval -> Array of: (Array with: String with: (Integer | (Array with: Integer with: Integer)))>
maps a block extent to an Array of temp references for that block/method.
Each reference is a pair of temp name and index, where the index can itself be a pair for a remote temp.
+ startKeysToTempRefs <Dictionary of: Integer startpc -> Array of: (Array with: String with: temp reference)> where
- startpcsToTempRefs <Dictionary of: Integer -> Array of: (Array with: String with: temp reference)> where
temp reference ::= Integer
+ | (Array with: Integer with: Integer)
+ | (Array with: #outer with: temp reference)!
- | (Array with: Integer with: Integer)
- | (Array with: #outer with: temp reference)!
Item was removed:
- ----- Method: DebuggerMethodMapForClosureCompiledMethods>>ensureExtentsMapsInitialized (in category 'private') -----
- ensureExtentsMapsInitialized
- | encoderTempRefs "<Dictionary of: Interval -> <Array of: <String | <Array of: String>>>>" |
- blockExtentsToTempRefs ifNotNil: [^self].
- blockExtentsToTempRefs := Dictionary new.
- startpcsToTempRefs := Dictionary new.
- encoderTempRefs := methodNode blockExtentsToTempRefs.
- encoderTempRefs keysAndValuesDo:
- [:blockExtent :tempVector|
- blockExtentsToTempRefs
- at: blockExtent
- put: (Array streamContents:
- [:stream|
- tempVector withIndexDo:
- [:nameOrSequence :index|
- nameOrSequence isString
- ifTrue:
- [stream nextPut: {nameOrSequence. index}]
- ifFalse:
- [nameOrSequence withIndexDo:
- [:name :indirectIndex|
- stream nextPut: { name. { index. indirectIndex }}]]]])]!
Item was changed:
----- Method: DebuggerMethodMapForClosureCompiledMethods>>namedTempAt:in: (in category 'accessing') -----
namedTempAt: index in: aContext
"Answer the value of the temp at index in aContext where index is relative
to the array of temp names answered by tempNamesForContext:"
^self
privateTempAt: index
in: aContext
+ startKeysToBlockExtents: aContext method startKeysToBlockExtents!
- startpcsToBlockExtents: aContext method startpcsToBlockExtents!
Item was changed:
----- Method: DebuggerMethodMapForClosureCompiledMethods>>namedTempAt:put:in: (in category 'accessing') -----
namedTempAt: index put: aValue in: aContext
"Assign the value of the temp at index in aContext where index is relative
to the array of temp names answered by tempNamesForContext:.
If the value is a copied value we also need to set it along the lexical chain."
^self
privateTempAt: index
in: aContext
put: aValue
+ startKeysToBlockExtents: aContext method startKeysToBlockExtents!
- startpcsToBlockExtents: aContext method startpcsToBlockExtents!
Item was added:
+ ----- Method: DebuggerMethodMapForClosureCompiledMethods>>privateTempAt:in:put:startKeysToBlockExtents: (in category 'private') -----
+ privateTempAt: index in: aContext put: aValue startKeysToBlockExtents: theContextsStartKeysToBlockExtents
+ | nameRefPair |
+ nameRefPair := (self privateTempRefsForContext: aContext
+ startKeysToBlockExtents: theContextsStartKeysToBlockExtents)
+ at: index
+ ifAbsent: [aContext errorSubscriptBounds: index].
+ ^self privateDereference: nameRefPair last in: aContext put: aValue!
Item was changed:
+ ----- Method: DebuggerMethodMapForClosureCompiledMethods>>privateTempAt:in:put:startpcsToBlockExtents: (in category 'private but obsolete') -----
- ----- Method: DebuggerMethodMapForClosureCompiledMethods>>privateTempAt:in:put:startpcsToBlockExtents: (in category 'private') -----
privateTempAt: index in: aContext put: aValue startpcsToBlockExtents: theContextsStartpcsToBlockExtents
| nameRefPair |
nameRefPair := (self privateTempRefsForContext: aContext
startpcsToBlockExtents: theContextsStartpcsToBlockExtents)
at: index
ifAbsent: [aContext errorSubscriptBounds: index].
^self privateDereference: nameRefPair last in: aContext put: aValue!
Item was added:
+ ----- Method: DebuggerMethodMapForClosureCompiledMethods>>privateTempAt:in:startKeysToBlockExtents: (in category 'private') -----
+ privateTempAt: index in: aContext startKeysToBlockExtents: theContextsStartKeysToBlockExtents
+ | nameRefPair |
+ nameRefPair := (self privateTempRefsForContext: aContext
+ startKeysToBlockExtents: theContextsStartKeysToBlockExtents)
+ at: index
+ ifAbsent: [aContext errorSubscriptBounds: index].
+ ^self privateDereference: nameRefPair last in: aContext!
Item was changed:
+ ----- Method: DebuggerMethodMapForClosureCompiledMethods>>privateTempAt:in:startpcsToBlockExtents: (in category 'private but obsolete') -----
- ----- Method: DebuggerMethodMapForClosureCompiledMethods>>privateTempAt:in:startpcsToBlockExtents: (in category 'private') -----
privateTempAt: index in: aContext startpcsToBlockExtents: theContextsStartpcsToBlockExtents
| nameRefPair |
nameRefPair := (self privateTempRefsForContext: aContext
startpcsToBlockExtents: theContextsStartpcsToBlockExtents)
at: index
ifAbsent: [aContext errorSubscriptBounds: index].
^self privateDereference: nameRefPair last in: aContext!
Item was added:
+ ----- Method: DebuggerMethodMapForClosureCompiledMethods>>privateTempRefsForContext:startKeysToBlockExtents: (in category 'private') -----
+ privateTempRefsForContext: aContext startKeysToBlockExtents: theContextsStartKeysToBlockExtents
+ "Answer the sequence of temps in scope in aContext in the natural order,
+ outermost arguments and temporaries first, innermost last. Each temp is
+ a pair of the temp's name followed by a reference. The reference can be
+ integer - index of temp in aContext
+ #( indirectionVectorIndex tempIndex ) - remote temp in indirectionVector at index in aContext
+ #( outer. temp reference ) - a temp reference in an outer context."
+ blockExtentsToTempRefs ifNil:
+ [blockExtentsToTempRefs := (aContext method holdsTempNames
+ ifTrue: [aContext method]
+ ifFalse: [methodNode]) blockExtentsToTempsMap.
+ blockExtentsToTempRefs ifNil:
+ ["an empty method. shouldn't be able to step into here but it
+ can happen in weird circumstances (i.e. with MethodWrapper)."
+ blockExtentsToTempRefs := Dictionary new.
+ blockExtentsToTempRefs
+ at: (theContextsStartKeysToBlockExtents at: aContext startKey)
+ put: {}].
+ startKeysToTempRefs := Dictionary new].
+ ^startKeysToTempRefs
+ at: aContext startKey
+ ifAbsentPut:
+ [| localRefs |
+ localRefs := blockExtentsToTempRefs at: (theContextsStartKeysToBlockExtents at: aContext startKey) ifAbsent: [#()].
+ aContext outerContext
+ ifNil: [localRefs]
+ ifNotNil:
+ [:outer| | outerTemps |
+ "Present temps in the order outermost to innermost left-to-right, but replace
+ copied outermost temps with their innermost copies"
+ outerTemps := (self
+ privateTempRefsForContext: outer
+ startKeysToBlockExtents: theContextsStartKeysToBlockExtents) collect:
+ [:outerPair|
+ localRefs
+ detect: [:localPair| outerPair first = localPair first]
+ ifNone: [{ outerPair first. { #outer. outerPair last } }]].
+ outerTemps,
+ (localRefs reject: [:localPair| outerTemps anySatisfy: [:outerPair| localPair first = outerPair first]])]]!
Item was changed:
+ ----- Method: DebuggerMethodMapForClosureCompiledMethods>>privateTempRefsForContext:startpcsToBlockExtents: (in category 'private but obsolete') -----
- ----- Method: DebuggerMethodMapForClosureCompiledMethods>>privateTempRefsForContext:startpcsToBlockExtents: (in category 'private') -----
privateTempRefsForContext: aContext startpcsToBlockExtents: theContextsStartpcsToBlockExtents
"Answer the sequence of temps in scope in aContext in the natural order,
outermost arguments and temporaries first, innermost last. Each temp is
a pair of the temp's name followed by a reference. The reference can be
integer - index of temp in aContext
#( indirectionVectorIndex tempIndex ) - remote temp in indirectionVector at index in aContext
#( outer. temp reference ) - a temp reference in an outer context."
blockExtentsToTempRefs ifNil:
[blockExtentsToTempRefs := (aContext method holdsTempNames
ifTrue: [aContext method]
ifFalse: [methodNode]) blockExtentsToTempsMap.
blockExtentsToTempRefs ifNil:
["an empty method. shouldn't be able to step into here but it
can happen in weird circumstances (i.e. with MethodWrapper)."
blockExtentsToTempRefs := Dictionary new.
blockExtentsToTempRefs
at: (theContextsStartpcsToBlockExtents at: aContext startpc)
put: {}].
startpcsToTempRefs := Dictionary new].
^startpcsToTempRefs
at: aContext startpc
ifAbsentPut:
[| localRefs |
localRefs := blockExtentsToTempRefs at: (theContextsStartpcsToBlockExtents at: aContext startpc).
aContext outerContext
ifNil: [localRefs]
ifNotNil:
[:outer| | outerTemps |
"Present temps in the order outermost to innermost left-to-right, but replace
copied outermost temps with their innermost copies"
outerTemps := (self
privateTempRefsForContext: outer
startpcsToBlockExtents: theContextsStartpcsToBlockExtents) collect:
[:outerPair|
localRefs
detect: [:localPair| outerPair first = localPair first]
ifNone: [{ outerPair first. { #outer. outerPair last } }]].
outerTemps,
(localRefs reject: [:localPair| outerTemps anySatisfy: [:outerPair| localPair first = outerPair first]])]]!
Item was added:
+ ----- Method: DebuggerMethodMapForClosureCompiledMethods>>privateTempRefsForMethod:startKeysToBlockExtents: (in category 'private') -----
+ privateTempRefsForMethod: method startKeysToBlockExtents: startKeysToBlockExtents
+ "Answer the sequence of temps in scope in method in the natural order,
+ outermost arguments and temporaries first, innermost last. Each temp is
+ a pair of the temp's name followed by a reference. The reference can be
+ integer - index of temp in aContext
+ #( indirectionVectorIndex tempIndex ) - remote temp in indirectionVector at index in aContext
+ #( outer. temp reference ) - a temp reference in an outer context."
+ blockExtentsToTempRefs ifNil:
+ [blockExtentsToTempRefs := (method holdsTempNames
+ ifTrue: [method]
+ ifFalse: [methodNode]) blockExtentsToTempsMap.
+ blockExtentsToTempRefs ifNil:
+ ["an empty method. shouldn't be able to step into here but it
+ can happen in weird circumstances (i.e. with MethodWrapper)."
+ blockExtentsToTempRefs := Dictionary new.
+ blockExtentsToTempRefs
+ at: (startKeysToBlockExtents at: method startKey)
+ put: {}].
+ startKeysToTempRefs := Dictionary new].
+ ^startKeysToTempRefs
+ at: method startKey
+ ifAbsentPut:
+ [blockExtentsToTempRefs at: (startKeysToBlockExtents at: method startKey)]!
Item was changed:
+ ----- Method: DebuggerMethodMapForClosureCompiledMethods>>privateTempRefsForMethod:startpcsToBlockExtents: (in category 'private but obsolete') -----
- ----- Method: DebuggerMethodMapForClosureCompiledMethods>>privateTempRefsForMethod:startpcsToBlockExtents: (in category 'private') -----
privateTempRefsForMethod: method startpcsToBlockExtents: startpcsToBlockExtents
"Answer the sequence of temps in scope in method in the natural order,
outermost arguments and temporaries first, innermost last. Each temp is
a pair of the temp's name followed by a reference. The reference can be
integer - index of temp in aContext
#( indirectionVectorIndex tempIndex ) - remote temp in indirectionVector at index in aContext
#( outer. temp reference ) - a temp reference in an outer context."
blockExtentsToTempRefs ifNil:
[blockExtentsToTempRefs := (method holdsTempNames
ifTrue: [method]
ifFalse: [methodNode]) blockExtentsToTempsMap.
blockExtentsToTempRefs ifNil:
["an empty method. shouldn't be able to step into here but it
can happen in weird circumstances (i.e. with MethodWrapper)."
blockExtentsToTempRefs := Dictionary new.
blockExtentsToTempRefs
at: (startpcsToBlockExtents at: method initialPC)
put: {}].
startpcsToTempRefs := Dictionary new].
^startpcsToTempRefs
at: method initialPC
ifAbsentPut:
[blockExtentsToTempRefs at: (startpcsToBlockExtents at: method initialPC)]!
Item was changed:
----- Method: DebuggerMethodMapForClosureCompiledMethods>>tempNamesForContext: (in category 'accessing') -----
tempNamesForContext: aContext
"Answer an Array of all the temp names in scope in aContext starting with
the home's first local (the first argument or first temporary if no arguments)."
^(self
privateTempRefsForContext: aContext
+ startKeysToBlockExtents: aContext method startKeysToBlockExtents) collect:
- startpcsToBlockExtents: aContext method startpcsToBlockExtents) collect:
[:pair| pair first]!
Item was changed:
----- Method: DebuggerMethodMapForClosureCompiledMethods>>tempNamesForMethod: (in category 'accessing') -----
tempNamesForMethod: aMethod
"Answer an Array of all the temp names in scope in aMethod starting with
the home's first local (the first argument or first temporary if no arguments)."
^(self
privateTempRefsForMethod: aMethod
+ startKeysToBlockExtents: aMethod startKeysToBlockExtents) collect:
- startpcsToBlockExtents: aMethod startpcsToBlockExtents) collect:
[:pair| pair first]!
Item was added:
+ DebuggerMethodMapForClosureCompiledMethods subclass: #DebuggerMethodMapForFullBlockCompiledMethods
+ instanceVariableNames: 'sortedSourceMaps'
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'Tools-Debugger'!
+
+ !DebuggerMethodMapForFullBlockCompiledMethods commentStamp: 'eem 1/10/2018 16:28' prior: 0!
+ I am a place-holder for information needed by the Debugger to inspect method activations. See DebuggerMethodMap's comment. I map methods compiled using full block closures.
+
+ Instance variables
+ (inherited)
+ abstractSourceRanges <Dictionary of: CompiledCode -> (Dictionary of: Integer-> Interval)
+ startKeysToTempRefs <Dictionary of: CompiledCode -> Array of: (Array with: String with: temp reference)> where
+ temp reference ::= Integer
+ | (Array with: Integer with: Integer)
+ | (Array with: #outer with: temp reference)
+ (locally defined)
+ sortedSourceMaps <Dictionary of: CompiledCode -> (Dictionary of: Integer-> Interval)!
Item was added:
+ ----- Method: DebuggerMethodMapForFullBlockCompiledMethods>>abstractSourceMap (in category 'source mapping') -----
+ abstractSourceMap
+ self shouldNotImplement!
Item was added:
+ ----- Method: DebuggerMethodMapForFullBlockCompiledMethods>>abstractSourceMapForMethod: (in category 'source mapping') -----
+ abstractSourceMapForMethod: compiledCode
+ "Answer with a Dictionary of abstractPC <Integer> to sourceRange <Interval>
+ for compiledCode which may be either a CompiledMethod or a CompiledBlock."
+ | rawSourceRanges theMethodToScan |
+ abstractSourceRanges ifNotNil:
+ [^abstractSourceRanges at: compiledCode].
+ abstractSourceRanges := IdentityDictionary new.
+ "If the methodNode hasn't had a method generated it doesn't have pcs set in its
+ nodes so we must generate a new method. We use this method for scanning
+ since its rawSourceRanges refer to the block methods within the method, and
+ that means we can use identity comparisons to match nodes with blocks."
+ methodNode rawSourceRangesAndMethodDo:
+ [:ranges :method|
+ rawSourceRanges := ranges.
+ theMethodToScan := method].
+ self scanMethod: theMethodToScan mappingRanges: rawSourceRanges.
+ self mapBlockMethodKeysIn: theMethodToScan toActualBlockMethodsIn: compiledCode homeMethod.
+ ^abstractSourceRanges at: compiledCode!
Item was added:
+ ----- Method: DebuggerMethodMapForFullBlockCompiledMethods>>mapBlockMethodKeysIn:toActualBlockMethodsIn: (in category 'source mapping') -----
+ mapBlockMethodKeysIn: theMethodToScan toActualBlockMethodsIn: actualMethod
+ abstractSourceRanges at: actualMethod put: (abstractSourceRanges removeKey: theMethodToScan).
+ 1 to: theMethodToScan numLiterals - 1 do: "i.e. don't scan the last literal which, in CompiledBlocks is a back pointer"
+ [:i| | lit |
+ (lit := theMethodToScan literalAt: i) isCompiledCode ifTrue:
+ [self mapBlockMethodKeysIn: lit toActualBlockMethodsIn: (actualMethod literalAt: i)]]!
Item was added:
+ ----- Method: DebuggerMethodMapForFullBlockCompiledMethods>>rangeForPC:in:contextIsActiveContext: (in category 'source mapping') -----
+ rangeForPC: contextsConcretePC in: method contextIsActiveContext: contextIsActiveContext
+ "Answer the indices in the source code for the supplied pc.
+ If the context is the actve context (is at the hot end of the stack)
+ then its pc is the current pc. But if the context isn't, because it is
+ suspended sending a message, then its current pc is the previous pc."
+
+ | pc i end mapForMethod sortedMap |
+ pc := self method abstractPCForConcretePC: (contextIsActiveContext
+ ifTrue: [contextsConcretePC]
+ ifFalse: [(self method pcPreviousTo: contextsConcretePC)
+ ifNotNil: [:prevpc| prevpc]
+ ifNil: [contextsConcretePC]]).
+ ((mapForMethod := self abstractSourceMapForMethod: method) includesKey: pc) ifTrue:
+ [^mapForMethod at: pc].
+ sortedSourceMap ifNil:
+ [sortedSourceMap := IdentityDictionary new].
+ sortedMap := sortedSourceMap
+ at: method
+ ifAbsentPut: [mapForMethod associations
+ replace: [ :each | each copy ];
+ sort].
+ sortedMap isEmpty ifTrue: [^1 to: 0].
+ i := sortedMap findNearbyBinaryIndex: [:assoc| pc - assoc key].
+ i < 1 ifTrue: [^1 to: 0].
+ i > sortedMap size ifTrue:
+ [end := sortedMap inject: 0 into:
+ [:prev :this | prev max: this value last].
+ ^end+1 to: end].
+ ^(sortedMap at: i) value
+
+ "| method source scanner map |
+ method := DebuggerMethodMapForFullBlockCompiledMethods compiledMethodAt: #rangeForPC:in:contextIsActiveContext:.
+ source := method getSourceFromFile asString.
+ scanner := InstructionStream on: method.
+ map := method debuggerMap.
+ Array streamContents:
+ [:ranges|
+ [scanner atEnd] whileFalse:
+ [| range |
+ range := map rangeForPC: scanner pc in: method contextIsActiveContext: true.
+ ((map abstractSourceMap includesKey: scanner abstractPC)
+ and: [range first ~= 0]) ifTrue:
+ [ranges nextPut: (source copyFrom: range first to: range last)].
+ scanner interpretNextInstructionFor: InstructionClient new]]"!
Item was added:
+ ----- Method: DebuggerMethodMapForFullBlockCompiledMethods>>scanMethod:mappingRanges: (in category 'source mapping') -----
+ scanMethod: theMethodToScan mappingRanges: rawSourceRanges
+ | abstractPC scanner client maybeBlock concreteSourceRanges rangesForMethod |
+ rangesForMethod := (abstractSourceRanges at: theMethodToScan put: Dictionary new).
+ concreteSourceRanges := Dictionary new.
+ "The rawSourceRanges map node pcs to ranges.
+ When node is one in the home method the node's pc is an integer.
+ When the node is within a block method the node's pc is an association from CompiledBlock to pc.
+ Extract pc -> range for this particular CompiledMethod or CompiledBlock."
+ rawSourceRanges keysAndValuesDo:
+ (theMethodToScan isCompiledMethod
+ ifTrue:
+ [[:node :range|
+ (node pc isVariableBinding
+ or: [node pc = 0]) ifFalse:
+ [concreteSourceRanges at: node pc put: range]]]
+ ifFalse:
+ [[:node :range|
+ (node pc isVariableBinding
+ and: [node pc key == theMethodToScan
+ and: [node pc value ~= 0]]) ifTrue:
+ [concreteSourceRanges at: node pc value put: range]]]).
+ abstractPC := 1.
+ scanner := InstructionStream on: theMethodToScan.
+ client := BlockStartLocator new.
+ [(concreteSourceRanges includesKey: scanner pc) ifTrue:
+ [rangesForMethod at: abstractPC put: (concreteSourceRanges at: scanner pc)].
+ abstractPC := abstractPC + 1.
+ maybeBlock := scanner interpretNextInstructionFor: client.
+ (maybeBlock ~~ client
+ and: [maybeBlock isCompiledCode]) ifTrue:
+ [self assert: maybeBlock isCompiledBlock.
+ self scanMethod: maybeBlock mappingRanges: rawSourceRanges].
+ scanner atEnd] whileFalse!
Item was changed:
----- Method: ProcessBrowser>>pcRange (in category 'stack list') -----
pcRange
"Answer the indices in the source code for the method corresponding to
the selected context's program counter value."
+ (selectedContext isNil or: [methodText isEmptyOrNil]) ifTrue:
+ [^ 1 to: 0].
- (selectedContext isNil or: [methodText isEmptyOrNil])
- ifTrue: [^ 1 to: 0].
^selectedContext debuggerMap
rangeForPC: (selectedContext pc ifNotNil: [:pc| pc] ifNil: [selectedContext method endPC])
+ in: selectedContext method
contextIsActiveContext: stackListIndex = 1!
Eliot Miranda uploaded a new version of Tools to project The Trunk:
http://source.squeak.org/trunk/Tools-eem.789.mcz
==================== Summary ====================
Name: Tools-eem.789
Author: eem
Time: 11 January 2018, 8:46:29.072557 am
UUID: 65359207-9312-4a75-bd18-d59c7f3f0ae2
Ancestors: Tools-eem.788
Move CompiledMethod>>startpcsToBlockExtents and its support machinery to Compiler; it is used both by the Decompiler and the Debugger and so belongs in Compiler, not in Tools.
=============== Diff against Tools-eem.788 ===============
Item was removed:
- ----- Method: CompiledMethod>>blockExtentsInto:from:to:scanner:numberer: (in category '*Tools-Debugger-support') -----
- blockExtentsInto: aDictionary from: initialPC to: endPC scanner: scanner numberer: numbererBlock
- "Support routine for startpcsToBlockExtents"
- | extentStart blockSizeOrLocator |
- self flag: 'belongs in DebuggerMethodMap'.
- extentStart := numbererBlock value.
- [scanner pc <= endPC] whileTrue:
- [blockSizeOrLocator := scanner interpretNextInstructionFor: BlockStartLocator new.
- blockSizeOrLocator isInteger ifTrue:
- [self
- blockExtentsInto: aDictionary
- from: scanner pc
- to: scanner pc + blockSizeOrLocator - 1
- scanner: scanner
- numberer: numbererBlock]].
- aDictionary at: initialPC put: (extentStart to: numbererBlock value).
- ^aDictionary!
Item was removed:
- ----- Method: CompiledMethod>>startpcsToBlockExtents (in category '*Tools-Debugger-support') -----
- startpcsToBlockExtents
- "Answer a Dictionary of startpc to Interval of blockExtent, using the
- identical numbering scheme described in and orchestrated by
- BlockNode>>analyseArguments:temporaries:rootNode:. This is
- used in part to find the temp names for any block in a method, as
- needed by the debugger. The other half is to recompile the method,
- obtaining the temp names for each block extent. By indirecting through
- the blockExtent instead of using the startpc directly we decouple the
- debugger's access to temp names from the exact bytecode; insulating
- debugging from minor changes in the compiler (e.g. changes in literal
- pooling, adding prefix bytecodes, adding inst vars to CompiledMethod
- in literals towards the end of the literal frame, etc). If the recompilation
- doesn't produce exactly the same bytecode at exactly the same offset
- no matter; the blockExtents will be the same."
- | index |
- self flag: 'belongs in DebuggerMethodMap'.
- index := 0.
- ^self
- blockExtentsInto: Dictionary new
- from: self initialPC
- to: self endPC
- scanner: (InstructionStream on: self)
- numberer: [| value | value := index. index := index + 2. value]!
Eliot Miranda uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-eem.1140.mcz
==================== Summary ====================
Name: Kernel-eem.1140
Author: eem
Time: 11 January 2018, 8:44:39.290013 am
UUID: d361ade6-5039-4edf-9782-a6baef35212c
Ancestors: Kernel-eem.1139
Move CompiledMethod>>startpcsToBlockExtents and its support machinery to Compiler; it is used both by the Decompiler and the Debugger and so belongs in Compiler, not in Tools.
=============== Diff against Kernel-eem.1139 ===============
Item was removed:
- InstructionClient subclass: #BlockStartLocator
- instanceVariableNames: ''
- classVariableNames: ''
- poolDictionaries: ''
- category: 'Kernel-Methods'!
Item was removed:
- ----- Method: BlockStartLocator>>pushClosureCopyNumCopiedValues:numArgs:blockSize: (in category 'instruction decoding') -----
- pushClosureCopyNumCopiedValues: numCopied numArgs: numArgs blockSize: blockSize
- "Answer the size of the block"
- ^blockSize!
Item was removed:
- ----- Method: BlockStartLocator>>pushFullClosure:numCopied: (in category 'instruction decoding') -----
- pushFullClosure: aCompiledBlock numCopied: numCopied
- "Answer the block method"
- ^aCompiledBlock!
Eliot Miranda uploaded a new version of Compiler to project The Trunk:
http://source.squeak.org/trunk/Compiler-eem.370.mcz
==================== Summary ====================
Name: Compiler-eem.370
Author: eem
Time: 11 January 2018, 8:41:19.10862 am
UUID: 277f856e-2abf-452c-a5e0-84d00819a04d
Ancestors: Compiler-eem.369
Move CompiledMethod>>startpcsToBlockExtents and its support machinery to Compiler; it is used both by the Decompiler and the Debugger and so belongs in Compiler, not in Tools.
=============== Diff against Compiler-eem.369 ===============
Item was changed:
InstructionClient subclass: #BlockLocalTempCounter
instanceVariableNames: 'stackPointer scanner blockEnd joinOffsets'
classVariableNames: ''
poolDictionaries: ''
category: 'Compiler-Support'!
+ !BlockLocalTempCounter commentStamp: 'eem 1/11/2018 08:30' prior: 0!
+ I am a support class for the decompiler that is used to find the number of local temps in a block by finding out what the stack offset is at the end of a block. I am necessary because in the EncoderForV3PlusClosures bytecode set the only way to initialize block-local temporaries is with pushConstant: nil bytecodes, but such bytecodes are ambiguous with a pushConstant: nil used to pass nil as a parameter or answer it as a result. By scanning through to the end of the block these can be disambiguated by tracking the stack depth.!
- !BlockLocalTempCounter commentStamp: '<historical>' prior: 0!
- I am a support class for the decompiler that is used to find the number of local temps in a block by finding out what the stack offset is at the end of a block.!
Item was added:
+ InstructionClient subclass: #BlockStartLocator
+ instanceVariableNames: ''
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'Compiler-Support'!
+
+ !BlockStartLocator commentStamp: 'eem 1/11/2018 08:32' prior: 0!
+ A BlockStartLocator is a scanner that locates the block creation bytecodes in a method. For block creation bytecodes it answers information salient to the kind of block being created, and for all other bytecodes simply answers itself.
+
+ Instance Variables
+ !
Item was added:
+ ----- Method: BlockStartLocator>>pushClosureCopyNumCopiedValues:numArgs:blockSize: (in category 'instruction decoding') -----
+ pushClosureCopyNumCopiedValues: numCopied numArgs: numArgs blockSize: blockSize
+ "Answer the size of the block"
+ ^blockSize!
Item was added:
+ ----- Method: BlockStartLocator>>pushFullClosure:numCopied: (in category 'instruction decoding') -----
+ pushFullClosure: aCompiledBlock numCopied: numCopied
+ "Answer the block method"
+ ^aCompiledBlock!
Item was added:
+ ----- Method: CompiledMethod>>blockExtentsInto:from:to:scanner:numberer: (in category '*Compiler-support') -----
+ blockExtentsInto: aDictionary from: initialPC to: endPC scanner: scanner numberer: numbererBlock
+ "Support routine for startpcsToBlockExtents"
+ | extentStart blockSizeOrLocator |
+ extentStart := numbererBlock value.
+ [scanner pc <= endPC] whileTrue:
+ [blockSizeOrLocator := scanner interpretNextInstructionFor: BlockStartLocator new.
+ blockSizeOrLocator isInteger ifTrue:
+ [self
+ blockExtentsInto: aDictionary
+ from: scanner pc
+ to: scanner pc + blockSizeOrLocator - 1
+ scanner: scanner
+ numberer: numbererBlock]].
+ aDictionary at: initialPC put: (extentStart to: numbererBlock value).
+ ^aDictionary!
Item was added:
+ ----- Method: CompiledMethod>>startpcsToBlockExtents (in category '*Compiler-support') -----
+ startpcsToBlockExtents
+ "Answer a Dictionary of startpc to Interval of blockExtent, using the
+ identical numbering scheme described in and orchestrated by
+ BlockNode>>analyseArguments:temporaries:rootNode:. This is used
+ to find the temp names for any block in a method, as needed by the
+ decompiler and debugger. By indirecting through the blockExtent
+ instead of using the startpc directly we decouple access to temp
+ names from the exact bytecode; insulating the decompiler and
+ debugger from minor changes in the compiler's output. If the
+ recompilation doesn't produce exactly the same bytecode at exactly
+ the same offset no matter; the blockExtents will be the same."
+ | index |
+ index := 0.
+ ^self
+ blockExtentsInto: Dictionary new
+ from: self initialPC
+ to: self endPC
+ scanner: (InstructionStream on: self)
+ numberer: [| value | value := index. index := index + 2. value]!